blob: 25e63a8bc8ce2d6ddf34583f27cefbf98b3ed726 [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)
daniel@transgaming.com97bffae2010-05-05 18:49:44 +000029 : mContext(context), mBackend(backend), mDirtyCurrentValues(true), mCurrentValueOffset(0)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000030{
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
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000049std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::getActiveAttribs() const
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000050{
51 std::bitset<MAX_VERTEX_ATTRIBS> active;
52
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000053 Program *program = mContext->getCurrentProgram();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000054
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000055 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000056 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000057 active[attributeIndex] = (program->getSemanticIndex(attributeIndex) != -1);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000058 }
59
60 return active;
61}
62
63GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000064 TranslatedAttribute *translated)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000065{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000066 const AttributeState *attribs = mContext->getVertexAttribBlock();
67 const std::bitset<MAX_VERTEX_ATTRIBS> activeAttribs = getActiveAttribs();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000068
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000069 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
70 {
71 if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
72 return GL_INVALID_OPERATION;
73 }
74
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000075 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
76 {
77 translated[i].enabled = activeAttribs[i];
78 }
79
80 processNonArrayAttributes(attribs, activeAttribs, translated);
81
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000082 // Process array attributes.
83
84 std::size_t requiredSpace = 0;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000085
86 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
87 {
88 if (activeAttribs[i] && attribs[i].mEnabled)
89 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000090 requiredSpace += spaceRequired(attribs[i], count);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000091 }
92 }
93
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000094 if (requiredSpace > mStreamBuffer->size())
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000095 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000096 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.
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000097
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000098 TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);
99
100 delete mStreamBuffer;
101 mStreamBuffer = newStreamBuffer;
102 }
103
104 mStreamBuffer->reserveSpace(requiredSpace);
105
106 for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
107 {
108 if (activeAttribs[i] && attribs[i].mEnabled)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000109 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000110 FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);
111
112 translated[i].type = attribs[i].mType;
113 translated[i].size = attribs[i].mSize;
114 translated[i].normalized = attribs[i].mNormalized;
115 translated[i].stride = formatConverter.outputVertexSize;
116 translated[i].buffer = mStreamBuffer;
117
118 void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);
119
120 const void *input;
121 if (attribs[i].mBoundBuffer)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000122 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000123 input = mContext->getBuffer(attribs[i].mBoundBuffer)->data();
124 input = static_cast<const char*>(input) + reinterpret_cast<size_t>(attribs[i].mPointer);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000125 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000126 else
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000127 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000128 input = attribs[i].mPointer;
129 }
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000130
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000131 size_t inputStride = interpretGlStride(attribs[i]);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000132
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000133 input = static_cast<const char*>(input) + inputStride * start;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000134
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000135 if (formatConverter.identity && inputStride == typeSize(attribs[i].mType) * attribs[i].mSize)
136 {
137 memcpy(output, input, count * inputStride);
138 }
139 else
140 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000141 formatConverter.convertArray(input, inputStride, count, output);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000142 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000143
144 mStreamBuffer->unmap();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000145 }
146 }
147
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000148 return GL_NO_ERROR;
149}
150
151void VertexDataManager::reloadCurrentValues(const AttributeState *attribs, std::size_t *offset)
152{
153 if (mDirtyCurrentValues)
154 {
155 std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;
156
157 mCurrentValueBuffer->reserveSpace(totalSize);
158
daniel@transgaming.com97bffae2010-05-05 18:49:44 +0000159 float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, &mCurrentValueOffset));
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000160
161 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
162 {
163 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.
164 }
165
166 mCurrentValueBuffer->unmap();
167
168 mDirtyCurrentValues = false;
169 }
daniel@transgaming.com97bffae2010-05-05 18:49:44 +0000170
171 *offset = mCurrentValueOffset;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000172}
173
174std::size_t VertexDataManager::typeSize(GLenum type) const
175{
176 switch (type)
177 {
178 case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
179 case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
180 case GL_FIXED: return sizeof(GLfixed);
181 case GL_FLOAT: return sizeof(GLfloat);
daniel@transgaming.com9efa6f62010-03-16 06:23:20 +0000182 default: UNREACHABLE(); return sizeof(GLfloat);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000183 }
184}
185
186std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
187{
188 return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
189}
190
191// Round up x (>=0) to the next multiple of multiple (>0).
192// 0 rounds up to 0.
193std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
194{
195 ASSERT(x >= 0);
196 ASSERT(multiple > 0);
197
198 std::size_t remainder = x % multiple;
199 if (remainder != 0)
200 {
201 return x + multiple - remainder;
202 }
203 else
204 {
205 return x;
206 }
207}
208
209std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
210{
211 std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
212 size *= maxVertex;
213
214 return roundUp(size, 4 * sizeof(GLfloat));
215}
216
217void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated)
218{
219 bool usesCurrentValues = false;
220
221 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
222 {
223 if (activeAttribs[i] && !attribs[i].mEnabled)
224 {
225 usesCurrentValues = true;
226 break;
227 }
228 }
229
230 if (usesCurrentValues)
231 {
232 std::size_t currentValueOffset;
233
234 reloadCurrentValues(attribs, &currentValueOffset);
235
236 for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
237 {
238 if (activeAttribs[i] && !attribs[i].mEnabled)
239 {
240 translated[i].buffer = mCurrentValueBuffer;
241
242 translated[i].type = GL_FLOAT;
243 translated[i].size = 4;
244 translated[i].normalized = false;
245 translated[i].stride = 0;
246 translated[i].offset = currentValueOffset + 4 * sizeof(float) * i;
247 }
248 }
249 }
250}
251
252}