1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7
8 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
9 // runs the Buffer translation process for index buffers.
10
11 #include "libGLESv2/renderer/IndexDataManager.h"
12 #include "libGLESv2/renderer/BufferStorage.h"
13
14 #include "libGLESv2/Buffer.h"
15 #include "libGLESv2/main.h"
16 #include "libGLESv2/utilities.h"
17 #include "libGLESv2/renderer/IndexBuffer.h"
18
19 namespace rx
20 {
21
IndexDataManager(Renderer * renderer)22 IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
23 {
24 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
25 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
26 {
27 delete mStreamingBufferShort;
28 mStreamingBufferShort = NULL;
29 }
30
31 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
32 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
33 {
34 delete mStreamingBufferInt;
35 mStreamingBufferInt = NULL;
36 }
37
38 if (!mStreamingBufferShort)
39 {
40 // Make sure both buffers are deleted.
41 delete mStreamingBufferInt;
42 mStreamingBufferInt = NULL;
43
44 ERR("Failed to allocate the streaming index buffer(s).");
45 }
46
47 mCountingBuffer = NULL;
48 }
49
~IndexDataManager()50 IndexDataManager::~IndexDataManager()
51 {
52 delete mStreamingBufferShort;
53 delete mStreamingBufferInt;
54 delete mCountingBuffer;
55 }
56
convertIndices(GLenum type,const void * input,GLsizei count,void * output)57 static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
58 {
59 if (type == GL_UNSIGNED_BYTE)
60 {
61 const GLubyte *in = static_cast<const GLubyte*>(input);
62 GLushort *out = static_cast<GLushort*>(output);
63
64 for (GLsizei i = 0; i < count; i++)
65 {
66 out[i] = in[i];
67 }
68 }
69 else if (type == GL_UNSIGNED_INT)
70 {
71 memcpy(output, input, count * sizeof(GLuint));
72 }
73 else if (type == GL_UNSIGNED_SHORT)
74 {
75 memcpy(output, input, count * sizeof(GLushort));
76 }
77 else UNREACHABLE();
78 }
79
80 template <class IndexType>
computeRange(const IndexType * indices,GLsizei count,GLuint * minIndex,GLuint * maxIndex)81 static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
82 {
83 *minIndex = indices[0];
84 *maxIndex = indices[0];
85
86 for (GLsizei i = 0; i < count; i++)
87 {
88 if (*minIndex > indices[i]) *minIndex = indices[i];
89 if (*maxIndex < indices[i]) *maxIndex = indices[i];
90 }
91 }
92
computeRange(GLenum type,const GLvoid * indices,GLsizei count,GLuint * minIndex,GLuint * maxIndex)93 static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
94 {
95 if (type == GL_UNSIGNED_BYTE)
96 {
97 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
98 }
99 else if (type == GL_UNSIGNED_INT)
100 {
101 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
102 }
103 else if (type == GL_UNSIGNED_SHORT)
104 {
105 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
106 }
107 else UNREACHABLE();
108 }
109
prepareIndexData(GLenum type,GLsizei count,gl::Buffer * buffer,const GLvoid * indices,TranslatedIndexData * translated)110 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
111 {
112 if (!mStreamingBufferShort)
113 {
114 return GL_OUT_OF_MEMORY;
115 }
116
117 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
118 unsigned int offset = 0;
119 bool alignedOffset = false;
120
121 BufferStorage *storage = NULL;
122
123 if (buffer != NULL)
124 {
125 if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
126 {
127 return GL_OUT_OF_MEMORY;
128 }
129 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
130
131 storage = buffer->getStorage();
132
133 switch (type)
134 {
135 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
136 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
137 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
138 default: UNREACHABLE(); alignedOffset = false;
139 }
140
141 unsigned int typeSize = gl::ComputeTypeSize(type);
142
143 // check for integer overflows
144 if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
145 typeSize * static_cast<unsigned int>(count) + offset < offset)
146 {
147 return GL_OUT_OF_MEMORY;
148 }
149
150 if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
151 {
152 return GL_INVALID_OPERATION;
153 }
154
155 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
156 }
157
158 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
159
160 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
161 IndexBufferInterface *indexBuffer = streamingBuffer;
162 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
163 destinationIndexType == type;
164 unsigned int streamOffset = 0;
165
166 if (directStorage)
167 {
168 indexBuffer = streamingBuffer;
169 streamOffset = offset;
170 storage->markBufferUsage();
171
172 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
173 &translated->maxIndex, NULL))
174 {
175 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
176 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
177 translated->maxIndex, offset);
178 }
179 }
180 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
181 {
182 indexBuffer = staticBuffer;
183 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
184 &translated->maxIndex, &streamOffset))
185 {
186 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
187 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
188 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
189 translated->maxIndex, streamOffset);
190 }
191 }
192 else
193 {
194 unsigned int convertCount = count;
195
196 if (staticBuffer)
197 {
198 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
199 {
200 indexBuffer = staticBuffer;
201 convertCount = storage->getSize() / gl::ComputeTypeSize(type);
202 }
203 else
204 {
205 buffer->invalidateStaticData();
206 staticBuffer = NULL;
207 }
208 }
209
210 if (!indexBuffer)
211 {
212 ERR("No valid index buffer.");
213 return GL_INVALID_OPERATION;
214 }
215
216 unsigned int indexTypeSize = gl::ComputeTypeSize(destinationIndexType);
217 if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
218 {
219 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
220 return GL_OUT_OF_MEMORY;
221 }
222
223 unsigned int bufferSizeRequired = convertCount * indexTypeSize;
224 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
225 {
226 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
227 return GL_OUT_OF_MEMORY;
228 }
229
230 void* output = NULL;
231 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
232 {
233 ERR("Failed to map index buffer.");
234 return GL_OUT_OF_MEMORY;
235 }
236
237 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
238
239 if (!indexBuffer->unmapBuffer())
240 {
241 ERR("Failed to unmap index buffer.");
242 return GL_OUT_OF_MEMORY;
243 }
244
245 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
246
247 if (staticBuffer)
248 {
249 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
250 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
251 translated->maxIndex, streamOffset);
252 }
253 }
254
255 translated->storage = directStorage ? storage : NULL;
256 translated->indexBuffer = indexBuffer->getIndexBuffer();
257 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
258 translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType);
259 translated->startOffset = streamOffset;
260
261 if (buffer)
262 {
263 buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type));
264 }
265
266 return GL_NO_ERROR;
267 }
268
getCountingIndices(GLsizei count)269 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
270 {
271 if (count <= 65536) // 16-bit indices
272 {
273 const unsigned int spaceNeeded = count * sizeof(unsigned short);
274
275 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
276 {
277 delete mCountingBuffer;
278 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
279 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
280
281 void* mappedMemory = NULL;
282 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
283 {
284 ERR("Failed to map counting buffer.");
285 return NULL;
286 }
287
288 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
289 for(int i = 0; i < count; i++)
290 {
291 data[i] = i;
292 }
293
294 if (!mCountingBuffer->unmapBuffer())
295 {
296 ERR("Failed to unmap counting buffer.");
297 return NULL;
298 }
299 }
300 }
301 else if (mStreamingBufferInt) // 32-bit indices supported
302 {
303 const unsigned int spaceNeeded = count * sizeof(unsigned int);
304
305 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
306 {
307 delete mCountingBuffer;
308 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
309 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
310
311 void* mappedMemory = NULL;
312 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
313 {
314 ERR("Failed to map counting buffer.");
315 return NULL;
316 }
317
318 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
319 for(int i = 0; i < count; i++)
320 {
321 data[i] = i;
322 }
323
324 if (!mCountingBuffer->unmapBuffer())
325 {
326 ERR("Failed to unmap counting buffer.");
327 return NULL;
328 }
329 }
330 }
331 else
332 {
333 return NULL;
334 }
335
336 return mCountingBuffer;
337 }
338
339 }
340