1 #include "precompiled.h"
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.
8 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
9 // runs the Buffer translation process for index buffers.
11 #include "libGLESv2/renderer/IndexDataManager.h"
12 #include "libGLESv2/renderer/BufferStorage.h"
14 #include "libGLESv2/Buffer.h"
15 #include "libGLESv2/main.h"
16 #include "libGLESv2/utilities.h"
17 #include "libGLESv2/renderer/IndexBuffer.h"
22 IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
24 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
25 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
27 delete mStreamingBufferShort;
28 mStreamingBufferShort = NULL;
31 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
32 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
34 delete mStreamingBufferInt;
35 mStreamingBufferInt = NULL;
38 if (!mStreamingBufferShort)
40 // Make sure both buffers are deleted.
41 delete mStreamingBufferInt;
42 mStreamingBufferInt = NULL;
44 ERR("Failed to allocate the streaming index buffer(s).");
47 mCountingBuffer = NULL;
50 IndexDataManager::~IndexDataManager()
52 delete mStreamingBufferShort;
53 delete mStreamingBufferInt;
54 delete mCountingBuffer;
57 static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
59 if (type == GL_UNSIGNED_BYTE)
61 const GLubyte *in = static_cast<const GLubyte*>(input);
62 GLushort *out = static_cast<GLushort*>(output);
64 for (GLsizei i = 0; i < count; i++)
69 else if (type == GL_UNSIGNED_INT)
71 memcpy(output, input, count * sizeof(GLuint));
73 else if (type == GL_UNSIGNED_SHORT)
75 memcpy(output, input, count * sizeof(GLushort));
80 template <class IndexType>
81 static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
83 *minIndex = indices[0];
84 *maxIndex = indices[0];
86 for (GLsizei i = 0; i < count; i++)
88 if (*minIndex > indices[i]) *minIndex = indices[i];
89 if (*maxIndex < indices[i]) *maxIndex = indices[i];
93 static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
95 if (type == GL_UNSIGNED_BYTE)
97 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
99 else if (type == GL_UNSIGNED_INT)
101 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
103 else if (type == GL_UNSIGNED_SHORT)
105 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
110 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
112 if (!mStreamingBufferShort)
114 return GL_OUT_OF_MEMORY;
117 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
118 unsigned int offset = 0;
119 bool alignedOffset = false;
121 BufferStorage *storage = NULL;
125 if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
127 return GL_OUT_OF_MEMORY;
129 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
131 storage = buffer->getStorage();
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;
141 unsigned int typeSize = gl::ComputeTypeSize(type);
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)
147 return GL_OUT_OF_MEMORY;
150 if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
152 return GL_INVALID_OPERATION;
155 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
158 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
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;
168 indexBuffer = streamingBuffer;
169 streamOffset = offset;
170 storage->markBufferUsage();
172 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
173 &translated->maxIndex, NULL))
175 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
176 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
177 translated->maxIndex, offset);
180 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
182 indexBuffer = staticBuffer;
183 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
184 &translated->maxIndex, &streamOffset))
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);
194 unsigned int convertCount = count;
198 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
200 indexBuffer = staticBuffer;
201 convertCount = storage->getSize() / gl::ComputeTypeSize(type);
205 buffer->invalidateStaticData();
212 ERR("No valid index buffer.");
213 return GL_INVALID_OPERATION;
216 unsigned int indexTypeSize = gl::ComputeTypeSize(destinationIndexType);
217 if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
219 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
220 return GL_OUT_OF_MEMORY;
223 unsigned int bufferSizeRequired = convertCount * indexTypeSize;
224 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
226 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
227 return GL_OUT_OF_MEMORY;
231 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
233 ERR("Failed to map index buffer.");
234 return GL_OUT_OF_MEMORY;
237 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
239 if (!indexBuffer->unmapBuffer())
241 ERR("Failed to unmap index buffer.");
242 return GL_OUT_OF_MEMORY;
245 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
249 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
250 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
251 translated->maxIndex, streamOffset);
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;
263 buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type));
269 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
271 if (count <= 65536) // 16-bit indices
273 const unsigned int spaceNeeded = count * sizeof(unsigned short);
275 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
277 delete mCountingBuffer;
278 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
279 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
281 void* mappedMemory = NULL;
282 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
284 ERR("Failed to map counting buffer.");
288 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
289 for(int i = 0; i < count; i++)
294 if (!mCountingBuffer->unmapBuffer())
296 ERR("Failed to unmap counting buffer.");
301 else if (mStreamingBufferInt) // 32-bit indices supported
303 const unsigned int spaceNeeded = count * sizeof(unsigned int);
305 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
307 delete mCountingBuffer;
308 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
309 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
311 void* mappedMemory = NULL;
312 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
314 ERR("Failed to map counting buffer.");
318 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
319 for(int i = 0; i < count; i++)
324 if (!mCountingBuffer->unmapBuffer())
326 ERR("Failed to unmap counting buffer.");
336 return mCountingBuffer;