1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/libGLESv2/renderer/IndexDataManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,333 @@ 1.4 +#include "precompiled.h" 1.5 +// 1.6 +// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved. 1.7 +// Use of this source code is governed by a BSD-style license that can be 1.8 +// found in the LICENSE file. 1.9 +// 1.10 + 1.11 +// IndexDataManager.cpp: Defines the IndexDataManager, a class that 1.12 +// runs the Buffer translation process for index buffers. 1.13 + 1.14 +#include "libGLESv2/renderer/IndexDataManager.h" 1.15 +#include "libGLESv2/renderer/BufferStorage.h" 1.16 + 1.17 +#include "libGLESv2/Buffer.h" 1.18 +#include "libGLESv2/main.h" 1.19 +#include "libGLESv2/utilities.h" 1.20 +#include "libGLESv2/renderer/IndexBuffer.h" 1.21 + 1.22 +namespace rx 1.23 +{ 1.24 + 1.25 +IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer) 1.26 +{ 1.27 + mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer); 1.28 + if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT)) 1.29 + { 1.30 + delete mStreamingBufferShort; 1.31 + mStreamingBufferShort = NULL; 1.32 + } 1.33 + 1.34 + mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer); 1.35 + if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT)) 1.36 + { 1.37 + delete mStreamingBufferInt; 1.38 + mStreamingBufferInt = NULL; 1.39 + } 1.40 + 1.41 + if (!mStreamingBufferShort) 1.42 + { 1.43 + // Make sure both buffers are deleted. 1.44 + delete mStreamingBufferInt; 1.45 + mStreamingBufferInt = NULL; 1.46 + 1.47 + ERR("Failed to allocate the streaming index buffer(s)."); 1.48 + } 1.49 + 1.50 + mCountingBuffer = NULL; 1.51 +} 1.52 + 1.53 +IndexDataManager::~IndexDataManager() 1.54 +{ 1.55 + delete mStreamingBufferShort; 1.56 + delete mStreamingBufferInt; 1.57 + delete mCountingBuffer; 1.58 +} 1.59 + 1.60 +static void convertIndices(GLenum type, const void *input, GLsizei count, void *output) 1.61 +{ 1.62 + if (type == GL_UNSIGNED_BYTE) 1.63 + { 1.64 + const GLubyte *in = static_cast<const GLubyte*>(input); 1.65 + GLushort *out = static_cast<GLushort*>(output); 1.66 + 1.67 + for (GLsizei i = 0; i < count; i++) 1.68 + { 1.69 + out[i] = in[i]; 1.70 + } 1.71 + } 1.72 + else if (type == GL_UNSIGNED_INT) 1.73 + { 1.74 + memcpy(output, input, count * sizeof(GLuint)); 1.75 + } 1.76 + else if (type == GL_UNSIGNED_SHORT) 1.77 + { 1.78 + memcpy(output, input, count * sizeof(GLushort)); 1.79 + } 1.80 + else UNREACHABLE(); 1.81 +} 1.82 + 1.83 +template <class IndexType> 1.84 +static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) 1.85 +{ 1.86 + *minIndex = indices[0]; 1.87 + *maxIndex = indices[0]; 1.88 + 1.89 + for (GLsizei i = 0; i < count; i++) 1.90 + { 1.91 + if (*minIndex > indices[i]) *minIndex = indices[i]; 1.92 + if (*maxIndex < indices[i]) *maxIndex = indices[i]; 1.93 + } 1.94 +} 1.95 + 1.96 +static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) 1.97 +{ 1.98 + if (type == GL_UNSIGNED_BYTE) 1.99 + { 1.100 + computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex); 1.101 + } 1.102 + else if (type == GL_UNSIGNED_INT) 1.103 + { 1.104 + computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex); 1.105 + } 1.106 + else if (type == GL_UNSIGNED_SHORT) 1.107 + { 1.108 + computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex); 1.109 + } 1.110 + else UNREACHABLE(); 1.111 +} 1.112 + 1.113 +GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) 1.114 +{ 1.115 + if (!mStreamingBufferShort) 1.116 + { 1.117 + return GL_OUT_OF_MEMORY; 1.118 + } 1.119 + 1.120 + GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; 1.121 + intptr_t offset = reinterpret_cast<intptr_t>(indices); 1.122 + bool alignedOffset = false; 1.123 + 1.124 + BufferStorage *storage = NULL; 1.125 + 1.126 + if (buffer != NULL) 1.127 + { 1.128 + storage = buffer->getStorage(); 1.129 + 1.130 + switch (type) 1.131 + { 1.132 + case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; 1.133 + case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; 1.134 + case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; 1.135 + default: UNREACHABLE(); alignedOffset = false; 1.136 + } 1.137 + 1.138 + unsigned int typeSize = gl::ComputeTypeSize(type); 1.139 + 1.140 + // check for integer overflows and underflows 1.141 + if (static_cast<unsigned int>(offset) > (std::numeric_limits<unsigned int>::max() / typeSize) || 1.142 + static_cast<unsigned int>(count) > ((std::numeric_limits<unsigned int>::max() / typeSize) - offset)) 1.143 + { 1.144 + return GL_OUT_OF_MEMORY; 1.145 + } 1.146 + 1.147 + if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize()) 1.148 + { 1.149 + return GL_INVALID_OPERATION; 1.150 + } 1.151 + 1.152 + indices = static_cast<const GLubyte*>(storage->getData()) + offset; 1.153 + } 1.154 + 1.155 + StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort; 1.156 + 1.157 + StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL; 1.158 + IndexBufferInterface *indexBuffer = streamingBuffer; 1.159 + bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && 1.160 + destinationIndexType == type; 1.161 + unsigned int streamOffset = 0; 1.162 + 1.163 + if (directStorage) 1.164 + { 1.165 + indexBuffer = streamingBuffer; 1.166 + streamOffset = offset; 1.167 + storage->markBufferUsage(); 1.168 + 1.169 + if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, 1.170 + &translated->maxIndex, NULL)) 1.171 + { 1.172 + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 1.173 + buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, 1.174 + translated->maxIndex, offset); 1.175 + } 1.176 + } 1.177 + else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) 1.178 + { 1.179 + indexBuffer = staticBuffer; 1.180 + if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex, 1.181 + &translated->maxIndex, &streamOffset)) 1.182 + { 1.183 + streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType); 1.184 + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 1.185 + staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, 1.186 + translated->maxIndex, streamOffset); 1.187 + } 1.188 + } 1.189 + else 1.190 + { 1.191 + unsigned int convertCount = count; 1.192 + 1.193 + if (staticBuffer) 1.194 + { 1.195 + if (staticBuffer->getBufferSize() == 0 && alignedOffset) 1.196 + { 1.197 + indexBuffer = staticBuffer; 1.198 + convertCount = storage->getSize() / gl::ComputeTypeSize(type); 1.199 + } 1.200 + else 1.201 + { 1.202 + buffer->invalidateStaticData(); 1.203 + staticBuffer = NULL; 1.204 + } 1.205 + } 1.206 + 1.207 + if (!indexBuffer) 1.208 + { 1.209 + ERR("No valid index buffer."); 1.210 + return GL_INVALID_OPERATION; 1.211 + } 1.212 + 1.213 + unsigned int indexTypeSize = gl::ComputeTypeSize(destinationIndexType); 1.214 + if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize) 1.215 + { 1.216 + ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize); 1.217 + return GL_OUT_OF_MEMORY; 1.218 + } 1.219 + 1.220 + unsigned int bufferSizeRequired = convertCount * indexTypeSize; 1.221 + if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type)) 1.222 + { 1.223 + ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired); 1.224 + return GL_OUT_OF_MEMORY; 1.225 + } 1.226 + 1.227 + void* output = NULL; 1.228 + if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset)) 1.229 + { 1.230 + ERR("Failed to map index buffer."); 1.231 + return GL_OUT_OF_MEMORY; 1.232 + } 1.233 + 1.234 + convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output); 1.235 + 1.236 + if (!indexBuffer->unmapBuffer()) 1.237 + { 1.238 + ERR("Failed to unmap index buffer."); 1.239 + return GL_OUT_OF_MEMORY; 1.240 + } 1.241 + 1.242 + computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 1.243 + 1.244 + if (staticBuffer) 1.245 + { 1.246 + streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType); 1.247 + staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex, 1.248 + translated->maxIndex, streamOffset); 1.249 + } 1.250 + } 1.251 + 1.252 + translated->storage = directStorage ? storage : NULL; 1.253 + translated->indexBuffer = indexBuffer->getIndexBuffer(); 1.254 + translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); 1.255 + translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType); 1.256 + translated->startOffset = streamOffset; 1.257 + 1.258 + if (buffer) 1.259 + { 1.260 + buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type)); 1.261 + } 1.262 + 1.263 + return GL_NO_ERROR; 1.264 +} 1.265 + 1.266 +StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count) 1.267 +{ 1.268 + if (count <= 65536) // 16-bit indices 1.269 + { 1.270 + const unsigned int spaceNeeded = count * sizeof(unsigned short); 1.271 + 1.272 + if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded) 1.273 + { 1.274 + delete mCountingBuffer; 1.275 + mCountingBuffer = new StaticIndexBufferInterface(mRenderer); 1.276 + mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT); 1.277 + 1.278 + void* mappedMemory = NULL; 1.279 + if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL)) 1.280 + { 1.281 + ERR("Failed to map counting buffer."); 1.282 + return NULL; 1.283 + } 1.284 + 1.285 + unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory); 1.286 + for(int i = 0; i < count; i++) 1.287 + { 1.288 + data[i] = i; 1.289 + } 1.290 + 1.291 + if (!mCountingBuffer->unmapBuffer()) 1.292 + { 1.293 + ERR("Failed to unmap counting buffer."); 1.294 + return NULL; 1.295 + } 1.296 + } 1.297 + } 1.298 + else if (mStreamingBufferInt) // 32-bit indices supported 1.299 + { 1.300 + const unsigned int spaceNeeded = count * sizeof(unsigned int); 1.301 + 1.302 + if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded) 1.303 + { 1.304 + delete mCountingBuffer; 1.305 + mCountingBuffer = new StaticIndexBufferInterface(mRenderer); 1.306 + mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT); 1.307 + 1.308 + void* mappedMemory = NULL; 1.309 + if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL)) 1.310 + { 1.311 + ERR("Failed to map counting buffer."); 1.312 + return NULL; 1.313 + } 1.314 + 1.315 + unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory); 1.316 + for(int i = 0; i < count; i++) 1.317 + { 1.318 + data[i] = i; 1.319 + } 1.320 + 1.321 + if (!mCountingBuffer->unmapBuffer()) 1.322 + { 1.323 + ERR("Failed to unmap counting buffer."); 1.324 + return NULL; 1.325 + } 1.326 + } 1.327 + } 1.328 + else 1.329 + { 1.330 + return NULL; 1.331 + } 1.332 + 1.333 + return mCountingBuffer; 1.334 +} 1.335 + 1.336 +}