blob: 7c2abace961a0a1e85e22c3879b2020a25616d7d [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
10#include "geometry/VertexDataManager.h"
11
12#include "debug.h"
13#include "Program.h"
14
15#include "Buffer.h"
16#include "geometry/backend.h"
17
18namespace
19{
20 enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
21}
22
23namespace gl
24{
25
26VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
27 : mContext(context), mBackend(backend), mDirtyCurrentValues(true)
28{
29 mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
30 try
31 {
32 mCurrentValueBuffer = mBackend->createVertexBuffer(4*sizeof(float)*MAX_VERTEX_ATTRIBS);
33 }
34 catch (...)
35 {
36 delete mStreamBuffer;
37 throw;
38 }
39}
40
41VertexDataManager::~VertexDataManager()
42{
43 delete mStreamBuffer;
44 delete mCurrentValueBuffer;
45}
46
47VertexDataManager::ArrayTranslationHelper::ArrayTranslationHelper(GLint first, GLsizei count)
48 : mFirst(first), mCount(count)
49{
50}
51
52void VertexDataManager::ArrayTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
53{
54 converter.convertArray(source, stride, mCount, dest);
55}
56
57VertexDataManager::IndexedTranslationHelper::IndexedTranslationHelper(const Index *indices, GLsizei count)
58 : mIndices(indices), mCount(count)
59{
60}
61
62void VertexDataManager::IndexedTranslationHelper::translate(const FormatConverter &converter, GLsizei stride, const void *source, void *dest)
63{
64 converter.convertIndexed(source, stride, mCount, mIndices, dest);
65}
66
67std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::activeAttribs()
68{
69 std::bitset<MAX_VERTEX_ATTRIBS> active;
70
71 Program *p = mContext->getCurrentProgram();
72
73 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
74 {
75 if (p->isActiveAttribute(i))
76 active[i] = true;
77 }
78
79 return active;
80}
81
82GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
83 TranslatedAttribute *outAttribs)
84
85{
86 ArrayTranslationHelper translationHelper(start, count);
87
88 return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), start, start+count, &translationHelper, outAttribs);
89}
90
91namespace
92{
93
94void indexRange(const Index *indices, std::size_t count, Index *minOut, Index *maxOut)
95{
96 ASSERT(count > 0);
97
98 Index minSoFar = indices[0];
99 Index maxSoFar = indices[0];
100
101 for (std::size_t i = 1; i < count; i++)
102 {
103 if (indices[i] > maxSoFar) maxSoFar = indices[i];
104 if (indices[i] < minSoFar) minSoFar = indices[i];
105 }
106
107 *minOut = minSoFar;
108 *maxOut = maxSoFar;
109}
110
111}
112
113GLenum VertexDataManager::preRenderValidate(const Index *indices, GLsizei count,
114 TranslatedAttribute *outAttribs)
115
116{
117 Index minIndex;
118 Index maxIndex;
119
120 indexRange(indices, count, &minIndex, &maxIndex);
121
122 IndexedTranslationHelper translationHelper(indices, count);
123
124 return internalPreRenderValidate(mContext->vertexAttribute, activeAttribs(), minIndex, maxIndex, &translationHelper, outAttribs);
125}
126
127GLenum VertexDataManager::internalPreRenderValidate(const AttributeState *attribs,
128 const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs,
129 Index minIndex,
130 Index maxIndex,
131 TranslationHelper *translator,
132 TranslatedAttribute *outAttribs)
133{
134 std::bitset<MAX_VERTEX_ATTRIBS> translateOrLift;
135
136 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
137 {
138 if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
139 return GL_INVALID_OPERATION;
140 }
141
142 TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
143
144 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
145 {
146 translated[i].enabled = activeAttribs[i];
147 }
148
149 processNonArrayAttributes(attribs, activeAttribs, translated);
150
151 // Handle the identity-mapped attributes.
152
153 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
154 {
155 if (activeAttribs[i] && attribs[i].mEnabled)
156 {
157 if (attribs[i].mBoundBuffer != 0 && mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized).identity)
158 {
159 translated[i].type = attribs[i].mType;
160 translated[i].size = attribs[i].mSize;
161 translated[i].normalized = attribs[i].mNormalized;
162 translated[i].offset = static_cast<std::size_t>(static_cast<const char*>(attribs[i].mPointer) - static_cast<const char*>(NULL));
163 translated[i].stride = interpretGlStride(attribs[i]);
164 translated[i].buffer = mContext->getBuffer(attribs[i].mBoundBuffer)->identityBuffer();
165 }
166 else
167 {
168 translateOrLift[i] = true;
169 }
170 }
171 }
172
173 // Handle any attributes needing translation or lifting.
174 if (translateOrLift.any())
175 {
daniel@transgaming.comc21c2272010-03-11 19:44:45 +0000176 std::size_t count = maxIndex + 1;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000177
178 std::size_t requiredSpace = 0;
179
180 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
181 {
182 if (translateOrLift[i])
183 {
184 requiredSpace += spaceRequired(attribs[i], count);
185 }
186 }
187
188 if (requiredSpace > mStreamBuffer->size())
189 {
190 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.
191
192 TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);
193
194 delete mStreamBuffer;
195 mStreamBuffer = newStreamBuffer;
196 }
197
198 mStreamBuffer->reserveSpace(requiredSpace);
199
200 for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
201 {
202 if (translateOrLift[i])
203 {
204 FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);
205
206 translated[i].type = attribs[i].mType;
207 translated[i].size = attribs[i].mSize;
208 translated[i].normalized = attribs[i].mNormalized;
209 translated[i].stride = formatConverter.outputVertexSize;
210 translated[i].buffer = mStreamBuffer;
211
212 void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);
213
214 const void *input;
215 if (attribs[i].mBoundBuffer)
216 {
217 input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
218 input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
219 }
220 else
221 {
222 input = attribs[i].mPointer;
223 }
224
225 translator->translate(formatConverter, interpretGlStride(attribs[i]), input, output);
226
227 mStreamBuffer->unmap();
228 }
229 }
230 }
231
232 std::copy(translated, translated + MAX_VERTEX_ATTRIBS, outAttribs);
233
234 return GL_NO_ERROR;
235}
236
237void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
238{
239 if (mDirtyCurrentValues)
240 {
241 std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;
242
243 mCurrentValueBuffer->reserveSpace(totalSize);
244
245 float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, offset));
246
247 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
248 {
249 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.
250 }
251
252 mCurrentValueBuffer->unmap();
253
254 mDirtyCurrentValues = false;
255 }
256}
257
258std::size_t VertexDataManager::typeSize(GLenum type) const
259{
260 switch (type)
261 {
262 case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
263 case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
264 case GL_FIXED: return sizeof(GLfixed);
265 case GL_FLOAT: return sizeof(GLfloat);
266 default: UNREACHABLE();
267 }
268}
269
270std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
271{
272 return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
273}
274
275// Round up x (>=0) to the next multiple of multiple (>0).
276// 0 rounds up to 0.
277std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
278{
279 ASSERT(x >= 0);
280 ASSERT(multiple > 0);
281
282 std::size_t remainder = x % multiple;
283 if (remainder != 0)
284 {
285 return x + multiple - remainder;
286 }
287 else
288 {
289 return x;
290 }
291}
292
293std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
294{
295 std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
296 size *= maxVertex;
297
298 return roundUp(size, 4 * sizeof(GLfloat));
299}
300
301void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
302{
303 bool usesCurrentValues = false;
304
305 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
306 {
307 if (activeAttribs[i] && !attribs[i].mEnabled)
308 {
309 usesCurrentValues = true;
310 break;
311 }
312 }
313
314 if (usesCurrentValues)
315 {
316 std::size_t currentValueOffset;
317
318 reloadCurrentValues(attribs, &currentValueOffset);
319
320 for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
321 {
322 if (activeAttribs[i] && !attribs[i].mEnabled)
323 {
324 translated[i].buffer = mCurrentValueBuffer;
325
326 translated[i].type = GL_FLOAT;
327 translated[i].size = 4;
328 translated[i].normalized = false;
329 translated[i].stride = 0;
330 translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
331 }
332 }
333 }
334}
335
336}