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