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