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 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 50 IndexDataManager::~IndexDataManager() 51 { 52 delete mStreamingBufferShort; 53 delete mStreamingBufferInt; 54 delete mCountingBuffer; 55 } 56 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> 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 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 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 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