1 #include "precompiled.h"
3 // Copyright (c) 2002-2014 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/d3d/IndexDataManager.h"
12 #include "libGLESv2/renderer/d3d/BufferD3D.h"
14 #include "libGLESv2/Buffer.h"
15 #include "libGLESv2/main.h"
16 #include "libGLESv2/formatutils.h"
17 #include "libGLESv2/renderer/d3d/IndexBuffer.h"
18 #include "libGLESv2/renderer/Renderer.h"
23 IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
25 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
26 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
28 delete mStreamingBufferShort;
29 mStreamingBufferShort = NULL;
32 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
33 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
35 delete mStreamingBufferInt;
36 mStreamingBufferInt = NULL;
39 if (!mStreamingBufferShort)
41 // Make sure both buffers are deleted.
42 delete mStreamingBufferInt;
43 mStreamingBufferInt = NULL;
45 ERR("Failed to allocate the streaming index buffer(s).");
48 mCountingBuffer = NULL;
51 IndexDataManager::~IndexDataManager()
53 delete mStreamingBufferShort;
54 delete mStreamingBufferInt;
55 delete mCountingBuffer;
58 static void convertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
60 if (sourceType == GL_UNSIGNED_BYTE)
62 ASSERT(destinationType == GL_UNSIGNED_SHORT);
63 const GLubyte *in = static_cast<const GLubyte*>(input);
64 GLushort *out = static_cast<GLushort*>(output);
66 for (GLsizei i = 0; i < count; i++)
71 else if (sourceType == GL_UNSIGNED_INT)
73 ASSERT(destinationType == GL_UNSIGNED_INT);
74 memcpy(output, input, count * sizeof(GLuint));
76 else if (sourceType == GL_UNSIGNED_SHORT)
78 if (destinationType == GL_UNSIGNED_SHORT)
80 memcpy(output, input, count * sizeof(GLushort));
82 else if (destinationType == GL_UNSIGNED_INT)
84 const GLushort *in = static_cast<const GLushort*>(input);
85 GLuint *out = static_cast<GLuint*>(output);
87 for (GLsizei i = 0; i < count; i++)
97 template <class IndexType>
98 static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
100 *minIndex = indices[0];
101 *maxIndex = indices[0];
103 for (GLsizei i = 0; i < count; i++)
105 if (*minIndex > indices[i]) *minIndex = indices[i];
106 if (*maxIndex < indices[i]) *maxIndex = indices[i];
110 static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
112 if (type == GL_UNSIGNED_BYTE)
114 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
116 else if (type == GL_UNSIGNED_INT)
118 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
120 else if (type == GL_UNSIGNED_SHORT)
122 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
127 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
129 if (!mStreamingBufferShort)
131 return GL_OUT_OF_MEMORY;
134 const gl::Type &typeInfo = gl::GetTypeInfo(type);
136 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
138 unsigned int offset = 0;
139 bool alignedOffset = false;
141 BufferD3D *storage = NULL;
145 if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
147 return GL_OUT_OF_MEMORY;
149 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
151 storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
155 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
156 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
157 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
158 default: UNREACHABLE(); alignedOffset = false;
161 // check for integer overflows
162 if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeInfo.bytes) ||
163 typeInfo.bytes * static_cast<unsigned int>(count) + offset < offset)
165 return GL_OUT_OF_MEMORY;
168 if (typeInfo.bytes * static_cast<unsigned int>(count) + offset > storage->getSize())
170 return GL_INVALID_OPERATION;
173 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
176 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
177 IndexBufferInterface *indexBuffer = NULL;
178 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
179 destinationIndexType == type;
180 unsigned int streamOffset = 0;
184 streamOffset = offset;
186 if (!storage->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
187 &translated->maxIndex, NULL))
189 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
190 storage->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
191 translated->maxIndex, offset);
194 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
196 indexBuffer = staticBuffer;
198 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
199 &translated->maxIndex, &streamOffset))
201 streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
202 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
203 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
204 translated->maxIndex, streamOffset);
209 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
212 // Avoid D3D11's primitive restart index value
213 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
214 if (translated->maxIndex == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
216 destinationIndexType = GL_UNSIGNED_INT;
217 directStorage = false;
221 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
223 if (!directStorage && !indexBuffer)
225 indexBuffer = (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
227 unsigned int convertCount = count;
231 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
233 indexBuffer = staticBuffer;
234 convertCount = storage->getSize() / typeInfo.bytes;
238 storage->invalidateStaticData();
245 ERR("No valid index buffer.");
246 return GL_INVALID_OPERATION;
249 if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
251 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, destTypeInfo.bytes);
252 return GL_OUT_OF_MEMORY;
255 unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
256 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
258 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
259 return GL_OUT_OF_MEMORY;
263 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
265 ERR("Failed to map index buffer.");
266 return GL_OUT_OF_MEMORY;
269 convertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output);
271 if (!indexBuffer->unmapBuffer())
273 ERR("Failed to unmap index buffer.");
274 return GL_OUT_OF_MEMORY;
279 streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
280 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
281 translated->maxIndex, streamOffset);
285 translated->storage = directStorage ? storage : NULL;
286 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
287 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
288 translated->startIndex = streamOffset / destTypeInfo.bytes;
289 translated->startOffset = streamOffset;
290 translated->indexType = destinationIndexType;
294 storage->promoteStaticUsage(count * typeInfo.bytes);
300 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
302 if (count <= 65536) // 16-bit indices
304 const unsigned int spaceNeeded = count * sizeof(unsigned short);
306 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
308 delete mCountingBuffer;
309 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
310 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
312 void* mappedMemory = NULL;
313 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
315 ERR("Failed to map counting buffer.");
319 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
320 for(int i = 0; i < count; i++)
325 if (!mCountingBuffer->unmapBuffer())
327 ERR("Failed to unmap counting buffer.");
332 else if (mStreamingBufferInt) // 32-bit indices supported
334 const unsigned int spaceNeeded = count * sizeof(unsigned int);
336 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
338 delete mCountingBuffer;
339 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
340 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
342 void* mappedMemory = NULL;
343 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
345 ERR("Failed to map counting buffer.");
349 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
350 for(int i = 0; i < count; i++)
355 if (!mCountingBuffer->unmapBuffer())
357 ERR("Failed to unmap counting buffer.");
367 return mCountingBuffer;