1 // 2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // IndexDataManager.cpp: Defines the IndexDataManager, a class that 8 // runs the Buffer translation process for index buffers. 9 10 #include "libGLESv2/renderer/d3d/IndexDataManager.h" 11 #include "libGLESv2/renderer/d3d/BufferD3D.h" 12 #include "libGLESv2/renderer/d3d/IndexBuffer.h" 13 #include "libGLESv2/renderer/Renderer.h" 14 #include "libGLESv2/Buffer.h" 15 #include "libGLESv2/main.h" 16 #include "libGLESv2/formatutils.h" 17 18 namespace rx 19 { 20 21 static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output) 22 { 23 if (sourceType == GL_UNSIGNED_BYTE) 24 { 25 ASSERT(destinationType == GL_UNSIGNED_SHORT); 26 const GLubyte *in = static_cast<const GLubyte*>(input); 27 GLushort *out = static_cast<GLushort*>(output); 28 29 for (GLsizei i = 0; i < count; i++) 30 { 31 out[i] = in[i]; 32 } 33 } 34 else if (sourceType == GL_UNSIGNED_INT) 35 { 36 ASSERT(destinationType == GL_UNSIGNED_INT); 37 memcpy(output, input, count * sizeof(GLuint)); 38 } 39 else if (sourceType == GL_UNSIGNED_SHORT) 40 { 41 if (destinationType == GL_UNSIGNED_SHORT) 42 { 43 memcpy(output, input, count * sizeof(GLushort)); 44 } 45 else if (destinationType == GL_UNSIGNED_INT) 46 { 47 const GLushort *in = static_cast<const GLushort*>(input); 48 GLuint *out = static_cast<GLuint*>(output); 49 50 for (GLsizei i = 0; i < count; i++) 51 { 52 out[i] = in[i]; 53 } 54 } 55 else UNREACHABLE(); 56 } 57 else UNREACHABLE(); 58 } 59 60 IndexDataManager::IndexDataManager(Renderer *renderer) 61 : mRenderer(renderer), 62 mStreamingBufferShort(NULL), 63 mStreamingBufferInt(NULL) 64 { 65 } 66 67 IndexDataManager::~IndexDataManager() 68 { 69 SafeDelete(mStreamingBufferShort); 70 SafeDelete(mStreamingBufferInt); 71 } 72 73 gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated) 74 { 75 const gl::Type &typeInfo = gl::GetTypeInfo(type); 76 77 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; 78 79 unsigned int offset = 0; 80 bool alignedOffset = false; 81 82 BufferD3D *storage = NULL; 83 84 if (buffer != NULL) 85 { 86 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices)); 87 88 storage = BufferD3D::makeBufferD3D(buffer->getImplementation()); 89 90 switch (type) 91 { 92 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break; 93 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break; 94 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break; 95 default: UNREACHABLE(); alignedOffset = false; 96 } 97 98 ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize()); 99 100 indices = static_cast<const GLubyte*>(storage->getData()) + offset; 101 } 102 103 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; 104 IndexBufferInterface *indexBuffer = NULL; 105 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() && 106 destinationIndexType == type; 107 unsigned int streamOffset = 0; 108 109 if (directStorage) 110 { 111 streamOffset = offset; 112 113 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL)) 114 { 115 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset); 116 } 117 } 118 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset) 119 { 120 indexBuffer = staticBuffer; 121 122 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset)) 123 { 124 streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes; 125 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset); 126 } 127 } 128 129 // Avoid D3D11's primitive restart index value 130 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx 131 if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3) 132 { 133 destinationIndexType = GL_UNSIGNED_INT; 134 directStorage = false; 135 indexBuffer = NULL; 136 } 137 138 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType); 139 140 if (!directStorage && !indexBuffer) 141 { 142 gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer); 143 if (error.isError()) 144 { 145 return error; 146 } 147 148 unsigned int convertCount = count; 149 150 if (staticBuffer) 151 { 152 if (staticBuffer->getBufferSize() == 0 && alignedOffset) 153 { 154 indexBuffer = staticBuffer; 155 convertCount = storage->getSize() / typeInfo.bytes; 156 } 157 else 158 { 159 storage->invalidateStaticData(); 160 staticBuffer = NULL; 161 } 162 } 163 164 ASSERT(indexBuffer); 165 166 if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes) 167 { 168 return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.", 169 convertCount, destTypeInfo.bytes); 170 } 171 172 unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes; 173 error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type); 174 if (error.isError()) 175 { 176 return error; 177 } 178 179 void* output = NULL; 180 error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset); 181 if (error.isError()) 182 { 183 return error; 184 } 185 186 ConvertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output); 187 188 error = indexBuffer->unmapBuffer(); 189 if (error.isError()) 190 { 191 return error; 192 } 193 194 if (staticBuffer) 195 { 196 streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes; 197 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset); 198 } 199 } 200 201 translated->storage = directStorage ? storage : NULL; 202 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL; 203 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial(); 204 translated->startIndex = streamOffset / destTypeInfo.bytes; 205 translated->startOffset = streamOffset; 206 translated->indexType = destinationIndexType; 207 208 if (storage) 209 { 210 storage->promoteStaticUsage(count * typeInfo.bytes); 211 } 212 213 return gl::Error(GL_NO_ERROR); 214 } 215 216 gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer) 217 { 218 ASSERT(outBuffer); 219 if (destinationIndexType == GL_UNSIGNED_INT) 220 { 221 if (!mStreamingBufferInt) 222 { 223 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer); 224 gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT); 225 if (error.isError()) 226 { 227 SafeDelete(mStreamingBufferInt); 228 return error; 229 } 230 } 231 232 *outBuffer = mStreamingBufferInt; 233 return gl::Error(GL_NO_ERROR); 234 } 235 else 236 { 237 ASSERT(destinationIndexType == GL_UNSIGNED_SHORT); 238 239 if (!mStreamingBufferShort) 240 { 241 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer); 242 gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT); 243 if (error.isError()) 244 { 245 SafeDelete(mStreamingBufferShort); 246 return error; 247 } 248 } 249 250 *outBuffer = mStreamingBufferShort; 251 return gl::Error(GL_NO_ERROR); 252 } 253 } 254 255 } 256