1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // IndexDataManager.cpp: Defines the IndexDataManager, a class that 16 // runs the Buffer translation process for index buffers. 17 18 #include "IndexDataManager.h" 19 20 #include "Buffer.h" 21 #include "common/debug.h" 22 23 #include <string.h> 24 #include <algorithm> 25 26 namespace 27 { 28 enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) }; 29 } 30 31 namespace es1 32 { 33 34 IndexDataManager::IndexDataManager() 35 { 36 mStreamingBuffer = new StreamingIndexBuffer(INITIAL_INDEX_BUFFER_SIZE); 37 38 if(!mStreamingBuffer) 39 { 40 ERR("Failed to allocate the streaming index buffer."); 41 } 42 } 43 44 IndexDataManager::~IndexDataManager() 45 { 46 delete mStreamingBuffer; 47 } 48 49 void copyIndices(GLenum type, const void *input, GLsizei count, void *output) 50 { 51 if(type == GL_UNSIGNED_BYTE) 52 { 53 memcpy(output, input, count * sizeof(GLubyte)); 54 } 55 else if(type == GL_UNSIGNED_SHORT) 56 { 57 memcpy(output, input, count * sizeof(GLushort)); 58 } 59 else UNREACHABLE(type); 60 } 61 62 template<class IndexType> 63 void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) 64 { 65 *minIndex = indices[0]; 66 *maxIndex = indices[0]; 67 68 for(GLsizei i = 0; i < count; i++) 69 { 70 if(*minIndex > indices[i]) *minIndex = indices[i]; 71 if(*maxIndex < indices[i]) *maxIndex = indices[i]; 72 } 73 } 74 75 void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex) 76 { 77 if(type == GL_UNSIGNED_BYTE) 78 { 79 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex); 80 } 81 else if(type == GL_UNSIGNED_SHORT) 82 { 83 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex); 84 } 85 else UNREACHABLE(type); 86 } 87 88 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated) 89 { 90 if(!mStreamingBuffer) 91 { 92 return GL_OUT_OF_MEMORY; 93 } 94 95 intptr_t offset = reinterpret_cast<intptr_t>(indices); 96 97 if(buffer != NULL) 98 { 99 if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size())) 100 { 101 return GL_INVALID_OPERATION; 102 } 103 104 indices = static_cast<const GLubyte*>(buffer->data()) + offset; 105 } 106 107 StreamingIndexBuffer *streamingBuffer = mStreamingBuffer; 108 109 sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL; 110 111 if(staticBuffer) 112 { 113 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 114 115 translated->indexBuffer = staticBuffer; 116 translated->indexOffset = offset; 117 } 118 else 119 { 120 unsigned int streamOffset = 0; 121 int convertCount = count; 122 123 streamingBuffer->reserveSpace(convertCount * typeSize(type), type); 124 void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset); 125 126 if(output == NULL) 127 { 128 ERR("Failed to map index buffer."); 129 return GL_OUT_OF_MEMORY; 130 } 131 132 copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output); 133 streamingBuffer->unmap(); 134 135 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex); 136 137 translated->indexBuffer = streamingBuffer->getResource(); 138 translated->indexOffset = streamOffset; 139 } 140 141 return GL_NO_ERROR; 142 } 143 144 std::size_t IndexDataManager::typeSize(GLenum type) 145 { 146 switch(type) 147 { 148 case GL_UNSIGNED_SHORT: return sizeof(GLushort); 149 case GL_UNSIGNED_BYTE: return sizeof(GLubyte); 150 default: UNREACHABLE(type); return sizeof(GLushort); 151 } 152 } 153 154 StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mIndexBuffer(nullptr), mBufferSize(initialSize) 155 { 156 if(initialSize > 0) 157 { 158 mIndexBuffer = new sw::Resource(initialSize + 16); 159 160 if(!mIndexBuffer) 161 { 162 ERR("Out of memory allocating an index buffer of size %u.", initialSize); 163 } 164 } 165 166 mWritePosition = 0; 167 } 168 169 StreamingIndexBuffer::~StreamingIndexBuffer() 170 { 171 if(mIndexBuffer) 172 { 173 mIndexBuffer->destruct(); 174 } 175 } 176 177 void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset) 178 { 179 void *mapPtr = NULL; 180 181 if(mIndexBuffer) 182 { 183 mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition; 184 185 if(!mapPtr) 186 { 187 ERR(" Lock failed"); 188 return NULL; 189 } 190 191 *offset = mWritePosition; 192 mWritePosition += requiredSpace; 193 } 194 195 return mapPtr; 196 } 197 198 void StreamingIndexBuffer::unmap() 199 { 200 if(mIndexBuffer) 201 { 202 mIndexBuffer->unlock(); 203 } 204 } 205 206 void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type) 207 { 208 if(requiredSpace > mBufferSize) 209 { 210 if(mIndexBuffer) 211 { 212 mIndexBuffer->destruct(); 213 mIndexBuffer = 0; 214 } 215 216 mBufferSize = std::max(requiredSpace, 2 * mBufferSize); 217 218 mIndexBuffer = new sw::Resource(mBufferSize + 16); 219 220 if(!mIndexBuffer) 221 { 222 ERR("Out of memory allocating an index buffer of size %u.", mBufferSize); 223 } 224 225 mWritePosition = 0; 226 } 227 else if(mWritePosition + requiredSpace > mBufferSize) // Recycle 228 { 229 if(mIndexBuffer) 230 { 231 mIndexBuffer->destruct(); 232 mIndexBuffer = new sw::Resource(mBufferSize + 16); 233 } 234 235 mWritePosition = 0; 236 } 237 } 238 239 sw::Resource *StreamingIndexBuffer::getResource() const 240 { 241 return mIndexBuffer; 242 } 243 244 } 245