blob: 1f646d12eb82db33a3076379d153daee65c8ff4c [file] [log] [blame]
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
8// runs the Buffer translation process.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/geometry/VertexDataManager.h"
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000011
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000012#include "common/debug.h"
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "libGLESv2/Buffer.h"
15#include "libGLESv2/Program.h"
16
17#include "libGLESv2/geometry/backend.h"
18#include "libGLESv2/geometry/IndexDataManager.h"
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000019
20namespace
21{
22 enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
23}
24
25namespace gl
26{
27
28VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
29 : mContext(context), mBackend(backend), mDirtyCurrentValues(true)
30{
31 mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
32 try
33 {
daniel@transgaming.come4b08c82010-04-20 18:53:06 +000034 mCurrentValueBuffer = mBackend->createVertexBufferForStrideZero(4*sizeof(float)*MAX_VERTEX_ATTRIBS);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000035 }
36 catch (...)
37 {
38 delete mStreamBuffer;
39 throw;
40 }
41}
42
43VertexDataManager::~VertexDataManager()
44{
45 delete mStreamBuffer;
46 delete mCurrentValueBuffer;
47}
48
49VertexDataManager::ArrayTranslationHelper::ArrayTranslationHelper(GLint first, GLsizei count)
50 : mFirst(first), mCount(count)
51{
52}
53
54void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
55{
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000056 converter.convertArray(source, stride, mCount, dest);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000057}
58
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000059VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, Index minIndex, GLsizei count)
60 : mIndices(indices), mMinIndex(minIndex), mCount(count)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000061{
62}
63
64void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
65{
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000066 converter.convertIndexed(source, stride, mMinIndex, mCount, mIndices, dest);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000067}
68
69std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
70{
71 std::bitset<MAX_VERTEX_ATTRIBS> active;
72
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000073 Program *program = mContext->getCurrentProgram();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000074
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000075 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000076 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000077 active[attributeIndex] = (program->getSemanticIndex(attributeIndex) != -1);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000078 }
79
80 return active;
81}
82
83GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
84 TranslatedAttribute *outAttribs)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000085{
86 ArrayTranslationHelper translationHelper(start, count);
87
daniel@transgaming.com428d1582010-05-04 03:35:25 +000088 return internalPreRenderValidate(mContext->getVertexAttribBlock(), activeAttribs(), start, start+count-1, &translationHelper, outAttribs);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000089}
90
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000091GLenum VertexDataManager::preRenderValidate(const TranslatedIndexData &indexInfo,
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000092 TranslatedAttribute *outAttribs)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000093{
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000094 IndexedTranslationHelper translationHelper(indexInfo.indices, indexInfo.minIndex, indexInfo.count);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000095
daniel@transgaming.com428d1582010-05-04 03:35:25 +000096 return internalPreRenderValidate(mContext->getVertexAttribBlock(), activeAttribs(), indexInfo.minIndex, indexInfo.maxIndex, &translationHelper, outAttribs);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000097}
98
99GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
100 const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs,
101 Index minIndex,
102 Index maxIndex,
103 TranslationHelper *translator,
daniel@transgaming.com5e417102010-03-26 04:08:53 +0000104 TranslatedAttribute *translated)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000105{
106 std::bitset<MAX_VERTEX_ATTRIBS> translateOrLift;
107
108 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
109 {
110 if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
111 return GL_INVALID_OPERATION;
112 }
113
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000114 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
115 {
116 translated[i].enabled = activeAttribs[i];
117 }
118
119 processNonArrayAttributes(attribs, activeAttribs, translated);
120
121 // Handle the identity-mapped attributes.
122
123 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
124 {
125 if (activeAttribs[i] && attribs[i].mEnabled)
126 {
127 if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
128 {
daniel@transgaming.comaa1ff872010-04-15 20:44:58 +0000129 std::size_t stride = interpretGlStride(attribs[i]);
daniel@transgaming.com743d7732010-04-15 20:45:32 +0000130 std::size_t offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL)) + stride * minIndex;
daniel@transgaming.comaa1ff872010-04-15 20:44:58 +0000131
132 if (mBackend->validateStream(attribs[i].mType, attribs[i].mSize, stride, offset))
133 {
134 translated[i].type = attribs[i].mType;
135 translated[i].size = attribs[i].mSize;
136 translated[i].normalized = attribs[i].mNormalized;
137 translated[i].stride = stride;
138 translated[i].offset = offset;
139 translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
140 }
141 else
142 {
143 translateOrLift[i] = true;
144 }
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000145 }
146 else
147 {
148 translateOrLift[i] = true;
149 }
150 }
151 }
152
153 // Handle any attributes needing translation or lifting.
154 if (translateOrLift.any())
155 {
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000156 std::size_t count = maxIndex - minIndex + 1;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000157
158 std::size_t requiredSpace = 0;
159
160 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
161 {
162 if (translateOrLift[i])
163 {
164 requiredSpace += spaceRequired(attribs[i], count);
165 }
166 }
167
168 if (requiredSpace > mStreamBuffer->size())
169 {
170 std::size_t newSize = std::max(requiredSpace, 3 * mStreamBuffer->size() / 2); // 1.5 x mStreamBuffer->size() is arbitrary and should be checked to see we don't have too many reallocations.
171
172 TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);
173
174 delete mStreamBuffer;
175 mStreamBuffer = newStreamBuffer;
176 }
177
178 mStreamBuffer->reserveSpace(requiredSpace);
179
180 for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
181 {
182 if (translateOrLift[i])
183 {
184 FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);
185
186 translated[i].type = attribs[i].mType;
187 translated[i].size = attribs[i].mSize;
188 translated[i].normalized = attribs[i].mNormalized;
189 translated[i].stride = formatConverter.outputVertexSize;
190 translated[i].buffer = mStreamBuffer;
191
192 void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);
193
194 const void *input;
195 if (attribs[i].mBoundBuffer)
196 {
197 input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
198 input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
199 }
200 else
201 {
202 input = attribs[i].mPointer;
203 }
204
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000205 size_t inputStride = interpretGlStride(attribs[i]);
206
207 input = static_cast<const char*>(input) + inputStride * minIndex;
208
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000209 translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);
210
211 mStreamBuffer->unmap();
212 }
213 }
214 }
215
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000216 return GL_NO_ERROR;
217}
218
219void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
220{
221 if (mDirtyCurrentValues)
222 {
223 std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;
224
225 mCurrentValueBuffer->reserveSpace(totalSize);
226
227 float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, offset));
228
229 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
230 {
231 memcpy(&p[i*4], attribs[i].mCurrentValue, sizeof(attribs[i].mCurrentValue)); // FIXME: this should be doing a translation. This assumes that GL_FLOATx4 is supported.
232 }
233
234 mCurrentValueBuffer->unmap();
235
236 mDirtyCurrentValues = false;
237 }
238}
239
240std::size_t VertexDataManager::typeSize(GLenum type) const
241{
242 switch (type)
243 {
244 case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
245 case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
246 case GL_FIXED: return sizeof(GLfixed);
247 case GL_FLOAT: return sizeof(GLfloat);
daniel@transgaming.com9efa6f62010-03-16 06:23:20 +0000248 default: UNREACHABLE(); return sizeof(GLfloat);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000249 }
250}
251
252std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
253{
254 return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
255}
256
257// Round up x (>=0) to the next multiple of multiple (>0).
258// 0 rounds up to 0.
259std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
260{
261 ASSERT(x >= 0);
262 ASSERT(multiple > 0);
263
264 std::size_t remainder = x % multiple;
265 if (remainder != 0)
266 {
267 return x + multiple - remainder;
268 }
269 else
270 {
271 return x;
272 }
273}
274
275std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
276{
277 std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
278 size *= maxVertex;
279
280 return roundUp(size, 4 * sizeof(GLfloat));
281}
282
283void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
284{
285 bool usesCurrentValues = false;
286
287 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
288 {
289 if (activeAttribs[i] && !attribs[i].mEnabled)
290 {
291 usesCurrentValues = true;
292 break;
293 }
294 }
295
296 if (usesCurrentValues)
297 {
298 std::size_t currentValueOffset;
299
300 reloadCurrentValues(attribs, &currentValueOffset);
301
302 for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
303 {
304 if (activeAttribs[i] && !attribs[i].mEnabled)
305 {
306 translated[i].buffer = mCurrentValueBuffer;
307
308 translated[i].type = GL_FLOAT;
309 translated[i].size = 4;
310 translated[i].normalized = false;
311 translated[i].stride = 0;
312 translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
313 }
314 }
315 }
316}
317
318}