blob: ea216cfa206039e686fcfaa470ffef2bc15a912d [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
daniel@transgaming.com838bcea2010-05-20 19:17:42 +000012#include <limits>
13
alokp@chromium.orgea0e1af2010-03-22 19:33:14 +000014#include "common/debug.h"
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000015
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000016#include "libGLESv2/Buffer.h"
17#include "libGLESv2/Program.h"
18
19#include "libGLESv2/geometry/backend.h"
20#include "libGLESv2/geometry/IndexDataManager.h"
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000021
22namespace
23{
24 enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
daniel@transgaming.comc828b142010-05-12 03:42:04 +000025 enum { MAX_CURRENT_VALUE_EXPANSION = 16 };
26 enum { CURRENT_VALUES_REQUIRED_SPACE = 4 * sizeof(float) * gl::MAX_VERTEX_ATTRIBS * MAX_CURRENT_VALUE_EXPANSION };
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000027}
28
29namespace gl
30{
31
32VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
daniel@transgaming.com97bffae2010-05-05 18:49:44 +000033 : mContext(context), mBackend(backend), mDirtyCurrentValues(true), mCurrentValueOffset(0)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000034{
35 mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
36 try
37 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +000038 mCurrentValueBuffer = mBackend->createVertexBufferForStrideZero(4 * sizeof(float) * MAX_VERTEX_ATTRIBS);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000039 }
40 catch (...)
41 {
42 delete mStreamBuffer;
43 throw;
44 }
45}
46
47VertexDataManager::~VertexDataManager()
48{
49 delete mStreamBuffer;
50 delete mCurrentValueBuffer;
51}
52
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000053std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::getActiveAttribs() const
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000054{
55 std::bitset<MAX_VERTEX_ATTRIBS> active;
56
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000057 Program *program = mContext->getCurrentProgram();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000058
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000059 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000060 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000061 active[attributeIndex] = (program->getSemanticIndex(attributeIndex) != -1);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000062 }
63
64 return active;
65}
66
67GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000068 TranslatedAttribute *translated)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000069{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000070 const AttributeState *attribs = mContext->getVertexAttribBlock();
71 const std::bitset<MAX_VERTEX_ATTRIBS> activeAttribs = getActiveAttribs();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000072
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000073 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
74 {
75 if (!activeAttribs[i] && attribs[i].mEnabled && attribs[i].mBoundBuffer != 0 && !mContext->getBuffer(attribs[i].mBoundBuffer))
76 return GL_INVALID_OPERATION;
77 }
78
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000079 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
80 {
81 translated[i].enabled = activeAttribs[i];
82 }
83
daniel@transgaming.comc828b142010-05-12 03:42:04 +000084 bool usesCurrentValues = false;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000085
daniel@transgaming.comc828b142010-05-12 03:42:04 +000086 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
87 {
88 if (activeAttribs[i] && !attribs[i].mEnabled)
89 {
90 usesCurrentValues = true;
91 break;
92 }
93 }
94
95 // Handle the identity-mapped attributes.
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000096 // Process array attributes.
97
98 std::size_t requiredSpace = 0;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000099
100 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
101 {
102 if (activeAttribs[i] && attribs[i].mEnabled)
103 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000104 requiredSpace += spaceRequired(attribs[i], count);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000105 }
106 }
107
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000108 if (usesCurrentValues)
109 {
110 requiredSpace += CURRENT_VALUES_REQUIRED_SPACE;
111 }
112
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000113 if (requiredSpace > mStreamBuffer->size())
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000114 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000115 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 +0000116
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000117 TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);
118
119 delete mStreamBuffer;
120 mStreamBuffer = newStreamBuffer;
121 }
122
123 mStreamBuffer->reserveSpace(requiredSpace);
124
125 for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
126 {
127 if (activeAttribs[i] && attribs[i].mEnabled)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000128 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000129 FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);
130
131 translated[i].type = attribs[i].mType;
132 translated[i].size = attribs[i].mSize;
133 translated[i].normalized = attribs[i].mNormalized;
134 translated[i].stride = formatConverter.outputVertexSize;
135 translated[i].buffer = mStreamBuffer;
136
daniel@transgaming.com838bcea2010-05-20 19:17:42 +0000137 size_t inputStride = interpretGlStride(attribs[i]);
138 size_t elementSize = typeSize(attribs[i].mType) * attribs[i].mSize;
139
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000140 void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);
141
142 const void *input;
143 if (attribs[i].mBoundBuffer)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000144 {
daniel@transgaming.com838bcea2010-05-20 19:17:42 +0000145 Buffer *buffer = mContext->getBuffer(attribs[i].mBoundBuffer);
146
147 size_t offset = reinterpret_cast<size_t>(attribs[i].mPointer);
148
149 // Before we calculate the required size below, make sure it can be computed without integer overflow.
150 if (std::numeric_limits<std::size_t>::max() - start < static_cast<std::size_t>(count)
151 || std::numeric_limits<std::size_t>::max() / inputStride < static_cast<std::size_t>(start + count - 1) // it's a prerequisite that count >= 1, so start+count-1 >= 0.
152 || std::numeric_limits<std::size_t>::max() - offset < inputStride * (start + count - 1)
153 || std::numeric_limits<std::size_t>::max() - elementSize < offset + inputStride * (start + count - 1) + elementSize)
154 {
155 mStreamBuffer->unmap();
156 return GL_INVALID_OPERATION;
157 }
158
159 if (offset + inputStride * (start + count - 1) + elementSize > buffer->size())
160 {
161 mStreamBuffer->unmap();
162 return GL_INVALID_OPERATION;
163 }
164
165 input = static_cast<const char*>(buffer->data()) + offset;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000166 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000167 else
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000168 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000169 input = attribs[i].mPointer;
170 }
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000171
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000172 input = static_cast<const char*>(input) + inputStride * start;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000173
daniel@transgaming.com838bcea2010-05-20 19:17:42 +0000174 if (formatConverter.identity && inputStride == elementSize)
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000175 {
176 memcpy(output, input, count * inputStride);
177 }
178 else
179 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000180 formatConverter.convertArray(input, inputStride, count, output);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000181 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000182
183 mStreamBuffer->unmap();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000184 }
185 }
186
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000187 if (usesCurrentValues)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000188 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000189 processNonArrayAttributes(attribs, activeAttribs, translated, count);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000190 }
daniel@transgaming.com97bffae2010-05-05 18:49:44 +0000191
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000192 return GL_NO_ERROR;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000193}
194
195std::size_t VertexDataManager::typeSize(GLenum type) const
196{
197 switch (type)
198 {
199 case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
200 case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
201 case GL_FIXED: return sizeof(GLfixed);
202 case GL_FLOAT: return sizeof(GLfloat);
daniel@transgaming.com9efa6f62010-03-16 06:23:20 +0000203 default: UNREACHABLE(); return sizeof(GLfloat);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000204 }
205}
206
207std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
208{
209 return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
210}
211
212// Round up x (>=0) to the next multiple of multiple (>0).
213// 0 rounds up to 0.
214std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
215{
216 ASSERT(x >= 0);
217 ASSERT(multiple > 0);
218
219 std::size_t remainder = x % multiple;
220 if (remainder != 0)
221 {
222 return x + multiple - remainder;
223 }
224 else
225 {
226 return x;
227 }
228}
229
230std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
231{
232 std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
233 size *= maxVertex;
234
235 return roundUp(size, 4 * sizeof(GLfloat));
236}
237
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000238void VertexDataManager::processNonArrayAttributes(const AttributeState *attribs, const std::bitset<MAX_VERTEX_ATTRIBS> &activeAttribs, TranslatedAttribute *translated, std::size_t count)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000239{
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000240 if (count <= MAX_CURRENT_VALUE_EXPANSION)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000241 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000242 if (mDirtyCurrentValues || mCurrentValueLoadBuffer != mStreamBuffer)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000243 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000244 float *p = static_cast<float*>(mStreamBuffer->map(CURRENT_VALUES_REQUIRED_SPACE, &mCurrentValueOffset));
245
246 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
247 {
248 float *out = p + MAX_CURRENT_VALUE_EXPANSION * 4 * i;
249 for (unsigned int j = 0; j < MAX_CURRENT_VALUE_EXPANSION; j++)
250 {
251 *out++ = attribs[i].mCurrentValue[0];
252 *out++ = attribs[i].mCurrentValue[1];
253 *out++ = attribs[i].mCurrentValue[2];
254 *out++ = attribs[i].mCurrentValue[3];
255 }
256 }
257
258 mStreamBuffer->unmap();
259
260 mCurrentValueLoadBuffer = mStreamBuffer;
261 mCurrentValueSize = MAX_CURRENT_VALUE_EXPANSION;
262 mCurrentValueStride = 4 * sizeof(float);
263 }
264 }
265 else
266 {
267 if (mDirtyCurrentValues || mCurrentValueLoadBuffer != mCurrentValueBuffer)
268 {
269 std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;
270
271 mCurrentValueBuffer->reserveSpace(totalSize);
272
273 float* p = static_cast<float*>(mCurrentValueBuffer->map(totalSize, &mCurrentValueOffset));
274
275 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
276 {
277 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.
278 }
279
280 mCurrentValueBuffer->unmap();
281
282 mCurrentValueLoadBuffer = mCurrentValueBuffer;
283 mCurrentValueSize = 1;
284 mCurrentValueStride = 0;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000285 }
286 }
287
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000288 for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000289 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000290 if (activeAttribs[i] && !attribs[i].mEnabled)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000291 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000292 translated[i].buffer = mCurrentValueLoadBuffer;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000293
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000294 translated[i].type = GL_FLOAT;
295 translated[i].size = 4;
296 translated[i].normalized = false;
297 translated[i].stride = mCurrentValueStride;
298 translated[i].offset = mCurrentValueOffset + 4 * sizeof(float) * i * mCurrentValueSize;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000299 }
300 }
301}
302
303}