blob: ea05dd9b62a4fbab6b4c242fd7fb230be3fb141e [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 };
25}
26
27namespace gl
28{
29
30VertexDataManager::VertexDataManager(Context *context, BufferBackEnd *backend)
daniel@transgaming.com97bffae2010-05-05 18:49:44 +000031 : mContext(context), mBackend(backend), mDirtyCurrentValues(true), mCurrentValueOffset(0)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000032{
33 mStreamBuffer = mBackend->createVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
34 try
35 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +000036 mCurrentValueBuffer = mBackend->createVertexBufferForStrideZero(4 * sizeof(float) * MAX_VERTEX_ATTRIBS);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000037 }
38 catch (...)
39 {
40 delete mStreamBuffer;
41 throw;
42 }
43}
44
45VertexDataManager::~VertexDataManager()
46{
47 delete mStreamBuffer;
48 delete mCurrentValueBuffer;
49}
50
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000051std::bitset<MAX_VERTEX_ATTRIBS> VertexDataManager::getActiveAttribs() const
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000052{
53 std::bitset<MAX_VERTEX_ATTRIBS> active;
54
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000055 Program *program = mContext->getCurrentProgram();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000056
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000057 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000058 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +000059 active[attributeIndex] = (program->getSemanticIndex(attributeIndex) != -1);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000060 }
61
62 return active;
63}
64
65GLenum VertexDataManager::preRenderValidate(GLint start, GLsizei count,
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000066 TranslatedAttribute *translated)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000067{
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +000068 GLenum error = GL_NO_ERROR;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000069 const AttributeState *attribs = mContext->getVertexAttribBlock();
70 const std::bitset<MAX_VERTEX_ATTRIBS> activeAttribs = getActiveAttribs();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000071
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000072 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
73 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000074 translated[i].enabled = activeAttribs[i];
75 }
76
daniel@transgaming.comc828b142010-05-12 03:42:04 +000077 bool usesCurrentValues = false;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000078
daniel@transgaming.comc828b142010-05-12 03:42:04 +000079 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
80 {
81 if (activeAttribs[i] && !attribs[i].mEnabled)
82 {
83 usesCurrentValues = true;
84 break;
85 }
86 }
87
88 // Handle the identity-mapped attributes.
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000089 // Process array attributes.
90
91 std::size_t requiredSpace = 0;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000092
93 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
94 {
95 if (activeAttribs[i] && attribs[i].mEnabled)
96 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +000097 requiredSpace += spaceRequired(attribs[i], count);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +000098 }
99 }
100
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000101 if (requiredSpace > mStreamBuffer->size())
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000102 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000103 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 +0000104
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000105 TranslatedVertexBuffer *newStreamBuffer = mBackend->createVertexBuffer(newSize);
106
107 delete mStreamBuffer;
108 mStreamBuffer = newStreamBuffer;
109 }
110
111 mStreamBuffer->reserveSpace(requiredSpace);
112
113 for (size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
114 {
115 if (activeAttribs[i] && attribs[i].mEnabled)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000116 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000117 FormatConverter formatConverter = mBackend->getFormatConverter(attribs[i].mType, attribs[i].mSize, attribs[i].mNormalized);
118
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000119 translated[i].nonArray = false;
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000120 translated[i].type = attribs[i].mType;
121 translated[i].size = attribs[i].mSize;
122 translated[i].normalized = attribs[i].mNormalized;
123 translated[i].stride = formatConverter.outputVertexSize;
124 translated[i].buffer = mStreamBuffer;
125
daniel@transgaming.com838bcea2010-05-20 19:17:42 +0000126 size_t inputStride = interpretGlStride(attribs[i]);
127 size_t elementSize = typeSize(attribs[i].mType) * attribs[i].mSize;
128
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000129 void *output = mStreamBuffer->map(spaceRequired(attribs[i], count), &translated[i].offset);
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000130 if (output == NULL)
131 {
132 ERR(" failed to map vertex buffer.");
133 return GL_OUT_OF_MEMORY;
134 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000135
136 const void *input;
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000137 if (attribs[i].mBoundBuffer.get())
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000138 {
daniel@transgaming.com9ecb9f92010-07-28 19:21:12 +0000139 Buffer *buffer = attribs[i].mBoundBuffer.get();
daniel@transgaming.com838bcea2010-05-20 19:17:42 +0000140
141 size_t offset = reinterpret_cast<size_t>(attribs[i].mPointer);
142
143 // Before we calculate the required size below, make sure it can be computed without integer overflow.
144 if (std::numeric_limits<std::size_t>::max() - start < static_cast<std::size_t>(count)
145 || 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.
146 || std::numeric_limits<std::size_t>::max() - offset < inputStride * (start + count - 1)
147 || std::numeric_limits<std::size_t>::max() - elementSize < offset + inputStride * (start + count - 1) + elementSize)
148 {
149 mStreamBuffer->unmap();
150 return GL_INVALID_OPERATION;
151 }
152
153 if (offset + inputStride * (start + count - 1) + elementSize > buffer->size())
154 {
155 mStreamBuffer->unmap();
156 return GL_INVALID_OPERATION;
157 }
158
159 input = static_cast<const char*>(buffer->data()) + offset;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000160 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000161 else
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000162 {
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000163 input = attribs[i].mPointer;
164 }
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000165
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000166 input = static_cast<const char*>(input) + inputStride * start;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000167
daniel@transgaming.com838bcea2010-05-20 19:17:42 +0000168 if (formatConverter.identity && inputStride == elementSize)
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000169 {
170 memcpy(output, input, count * inputStride);
171 }
172 else
173 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000174 formatConverter.convertArray(input, inputStride, count, output);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000175 }
daniel@transgaming.com9a0606c2010-05-12 03:42:00 +0000176
177 mStreamBuffer->unmap();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000178 }
179 }
180
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000181 if (usesCurrentValues)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000182 {
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000183 error = processNonArrayAttributes(attribs, activeAttribs, translated, count);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000184 }
daniel@transgaming.com97bffae2010-05-05 18:49:44 +0000185
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000186 return error;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000187}
188
189std::size_t VertexDataManager::typeSize(GLenum type) const
190{
191 switch (type)
192 {
193 case GL_BYTE: case GL_UNSIGNED_BYTE: return sizeof(GLbyte);
194 case GL_SHORT: case GL_UNSIGNED_SHORT: return sizeof(GLshort);
195 case GL_FIXED: return sizeof(GLfixed);
196 case GL_FLOAT: return sizeof(GLfloat);
daniel@transgaming.com9efa6f62010-03-16 06:23:20 +0000197 default: UNREACHABLE(); return sizeof(GLfloat);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000198 }
199}
200
201std::size_t VertexDataManager::interpretGlStride(const AttributeState &attrib) const
202{
203 return attrib.mStride ? attrib.mStride : typeSize(attrib.mType) * attrib.mSize;
204}
205
206// Round up x (>=0) to the next multiple of multiple (>0).
207// 0 rounds up to 0.
208std::size_t VertexDataManager::roundUp(std::size_t x, std::size_t multiple) const
209{
210 ASSERT(x >= 0);
211 ASSERT(multiple > 0);
212
213 std::size_t remainder = x % multiple;
214 if (remainder != 0)
215 {
216 return x + multiple - remainder;
217 }
218 else
219 {
220 return x;
221 }
222}
223
224std::size_t VertexDataManager::spaceRequired(const AttributeState &attrib, std::size_t maxVertex) const
225{
226 std::size_t size = mBackend->getFormatConverter(attrib.mType, attrib.mSize, attrib.mNormalized).outputVertexSize;
227 size *= maxVertex;
228
229 return roundUp(size, 4 * sizeof(GLfloat));
230}
231
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000232GLenum 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 +0000233{
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000234 if (mDirtyCurrentValues)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000235 {
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000236 std::size_t totalSize = 4 * sizeof(float) * MAX_VERTEX_ATTRIBS;
237
238 mCurrentValueBuffer->reserveSpace(totalSize);
239
240 float* currentValues = static_cast<float*>(mCurrentValueBuffer->map(totalSize, &mCurrentValueOffset));
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000241 if (currentValues == NULL)
242 {
243 ERR(" failed to map vertex buffer.");
244 return GL_OUT_OF_MEMORY;
245 }
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000246
247 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000248 {
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000249 // This assumes that the GL_FLOATx4 is supported by the back-end. (For D3D9, it is a mandatory format.)
250 currentValues[i*4+0] = attribs[i].mCurrentValue[0];
251 currentValues[i*4+1] = attribs[i].mCurrentValue[1];
252 currentValues[i*4+2] = attribs[i].mCurrentValue[2];
253 currentValues[i*4+3] = attribs[i].mCurrentValue[3];
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000254 }
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000255
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000256 mCurrentValueBuffer->unmap();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000257 }
258
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000259 for (std::size_t i = 0; i < MAX_VERTEX_ATTRIBS; i++)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000260 {
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000261 if (activeAttribs[i] && !attribs[i].mEnabled)
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000262 {
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000263 translated[i].nonArray = true;
264
265 translated[i].buffer = mCurrentValueBuffer;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000266
daniel@transgaming.comc828b142010-05-12 03:42:04 +0000267 translated[i].type = GL_FLOAT;
268 translated[i].size = 4;
269 translated[i].normalized = false;
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000270 translated[i].stride = 0;
271 translated[i].offset = mCurrentValueOffset + 4 * sizeof(float) * i;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000272 }
273 }
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000274
275 return GL_NO_ERROR;
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000276}
277
278}