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 intptr_t offset = reinterpret_cast<intptr_t>(indices); 119 bool alignedOffset = false; 120 121 BufferStorage *storage = NULL; 122 123 if (buffer != NULL) 124 { 125 storage = buffer->getStorage(); 126 127 switch (type) 128 { 129 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; 130 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; 131 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; 132 default: UNREACHABLE(); alignedOffset = false; 133 } 134 135 if (gl::ComputeTypeSize(type) * count + offset > static_cast<GLsizei>(storage->getSize())) 136 { 137 return GL_INVALID_OPERATION; 138 } 139 140 indices = static_cast<const GLubyte*>(storage->getData()) + offset; 141 } 142 143 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; 144 145 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL; 146 IndexBufferInterface *indexBuffer = streamingBuffer; 147 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && 148 destinationIndexType == type; 149 UINT streamOffset = 0; 150 151 if (directStorage) 152 { 153 indexBuffer = streamingBuffer; 154 streamOffset = offset; 155 storage->markBufferUsage(); 156 157 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, 158 &translated->maxIndex, NULL)) 159 { 160 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 161 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, 162 translated->maxIndex, offset); 163 } 164 } 165 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) 166 { 167 indexBuffer = staticBuffer; 168 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, 169 &translated->maxIndex, &streamOffset)) 170 { 171 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType); 172 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 173 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, 174 translated->maxIndex, streamOffset); 175 } 176 } 177 else 178 { 179 int convertCount = count; 180 181 if (staticBuffer) 182 { 183 if (staticBuffer->getBufferSize() == 0 && alignedOffset) 184 { 185 indexBuffer = staticBuffer; 186 convertCount = storage->getSize() / gl::ComputeTypeSize(type); 187 } 188 else 189 { 190 buffer->invalidateStaticData(); 191 staticBuffer = NULL; 192 } 193 } 194 195 if (!indexBuffer) 196 { 197 ERR("No valid index buffer."); 198 return GL_INVALID_OPERATION; 199 } 200 201 unsigned int bufferSizeRequired = convertCount * gl::ComputeTypeSize(destinationIndexType); 202 indexBuffer->reserveBufferSpace(bufferSizeRequired, type); 203 204 void* output = NULL; 205 streamOffset = indexBuffer->mapBuffer(bufferSizeRequired, &output); 206 if (streamOffset == -1 || output == NULL) 207 { 208 ERR("Failed to map index buffer."); 209 return GL_OUT_OF_MEMORY; 210 } 211 212 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output); 213 214 if (!indexBuffer->unmapBuffer()) 215 { 216 ERR("Failed to unmap index buffer."); 217 return GL_OUT_OF_MEMORY; 218 } 219 220 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 221 222 if (staticBuffer) 223 { 224 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType); 225 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, 226 translated->maxIndex, streamOffset); 227 } 228 } 229 230 translated->storage = directStorage ? storage : NULL; 231 translated->indexBuffer = indexBuffer->getIndexBuffer(); 232 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); 233 translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType); 234 translated->startOffset = streamOffset; 235 236 if (buffer) 237 { 238 buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type)); 239 } 240 241 return GL_NO_ERROR; 242 } 243 244 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count) 245 { 246 if (count <= 65536) // 16-bit indices 247 { 248 const unsigned int spaceNeeded = count * sizeof(unsigned short); 249 250 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded) 251 { 252 delete mCountingBuffer; 253 mCountingBuffer = new StaticIndexBufferInterface(mRenderer); 254 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); 255 256 void* mappedMemory = NULL; 257 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL) 258 { 259 ERR("Failed to map counting buffer."); 260 return NULL; 261 } 262 263 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory); 264 for(int i = 0; i < count; i++) 265 { 266 data[i] = i; 267 } 268 269 if (!mCountingBuffer->unmapBuffer()) 270 { 271 ERR("Failed to unmap counting buffer."); 272 return NULL; 273 } 274 } 275 } 276 else if (mStreamingBufferInt) // 32-bit indices supported 277 { 278 const unsigned int spaceNeeded = count * sizeof(unsigned int); 279 280 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded) 281 { 282 delete mCountingBuffer; 283 mCountingBuffer = new StaticIndexBufferInterface(mRenderer); 284 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); 285 286 void* mappedMemory = NULL; 287 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL) 288 { 289 ERR("Failed to map counting buffer."); 290 return NULL; 291 } 292 293 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); 294 for(int i = 0; i < count; i++) 295 { 296 data[i] = i; 297 } 298 299 if (!mCountingBuffer->unmapBuffer()) 300 { 301 ERR("Failed to unmap counting buffer."); 302 return NULL; 303 } 304 } 305 } 306 else 307 { 308 return NULL; 309 } 310 311 return mCountingBuffer; 312 } 313 314 } 315