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 // VertexDataManager.h: Defines the VertexDataManager, a class that 16 // runs the Buffer translation process. 17 18 #include "VertexDataManager.h" 19 20 #include "Buffer.h" 21 #include "Program.h" 22 #include "IndexDataManager.h" 23 #include "common/debug.h" 24 25 namespace 26 { 27 enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024}; 28 } 29 30 namespace es2 31 { 32 33 VertexDataManager::VertexDataManager(Context *context) : mContext(context) 34 { 35 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 36 { 37 mDirtyCurrentValue[i] = true; 38 mCurrentValueBuffer[i] = nullptr; 39 } 40 41 mStreamingBuffer = new StreamingVertexBuffer(INITIAL_STREAM_BUFFER_SIZE); 42 43 if(!mStreamingBuffer) 44 { 45 ERR("Failed to allocate the streaming vertex buffer."); 46 } 47 } 48 49 VertexDataManager::~VertexDataManager() 50 { 51 delete mStreamingBuffer; 52 53 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 54 { 55 delete mCurrentValueBuffer[i]; 56 } 57 } 58 59 unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute) 60 { 61 Buffer *buffer = attribute.mBoundBuffer; 62 63 int inputStride = attribute.stride(); 64 int elementSize = attribute.typeSize(); 65 unsigned int streamOffset = 0; 66 67 char *output = nullptr; 68 69 if(vertexBuffer) 70 { 71 output = (char*)vertexBuffer->map(attribute, attribute.typeSize() * count, &streamOffset); 72 } 73 74 if(!output) 75 { 76 ERR("Failed to map vertex buffer."); 77 return ~0u; 78 } 79 80 const char *input = nullptr; 81 82 if(buffer) 83 { 84 input = static_cast<const char*>(buffer->data()) + attribute.mOffset; 85 } 86 else 87 { 88 input = static_cast<const char*>(attribute.mPointer); 89 } 90 91 input += inputStride * start; 92 93 if(inputStride == elementSize) 94 { 95 memcpy(output, input, count * inputStride); 96 } 97 else 98 { 99 for(int i = 0; i < count; i++) 100 { 101 memcpy(output, input, elementSize); 102 output += elementSize; 103 input += inputStride; 104 } 105 } 106 107 vertexBuffer->unmap(); 108 109 return streamOffset; 110 } 111 112 GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instanceId) 113 { 114 if(!mStreamingBuffer) 115 { 116 return GL_OUT_OF_MEMORY; 117 } 118 119 const VertexAttributeArray &attribs = mContext->getVertexArrayAttributes(); 120 const VertexAttributeArray ¤tAttribs = mContext->getCurrentVertexAttributes(); 121 Program *program = mContext->getCurrentProgram(); 122 123 // Determine the required storage size per used buffer 124 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 125 { 126 const VertexAttribute &attrib = attribs[i].mArrayEnabled ? attribs[i] : currentAttribs[i]; 127 128 if(program->getAttributeStream(i) != -1 && attrib.mArrayEnabled) 129 { 130 if(!attrib.mBoundBuffer) 131 { 132 const bool isInstanced = attrib.mDivisor > 0; 133 mStreamingBuffer->addRequiredSpace(attrib.typeSize() * (isInstanced ? 1 : count)); 134 } 135 } 136 } 137 138 mStreamingBuffer->reserveRequiredSpace(); 139 140 // Perform the vertex data translations 141 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 142 { 143 if(program->getAttributeStream(i) != -1) 144 { 145 const VertexAttribute &attrib = attribs[i].mArrayEnabled ? attribs[i] : currentAttribs[i]; 146 147 if(attrib.mArrayEnabled) 148 { 149 const bool isInstanced = attrib.mDivisor > 0; 150 151 // Instanced vertices do not apply the 'start' offset 152 GLint firstVertexIndex = isInstanced ? instanceId / attrib.mDivisor : start; 153 154 Buffer *buffer = attrib.mBoundBuffer; 155 156 if((!buffer && attrib.mPointer == nullptr) || (buffer && !buffer->data())) 157 { 158 // This is an application error that would normally result in a crash, but we catch it and return an error 159 ERR("An enabled vertex array has no buffer and no pointer."); 160 return GL_INVALID_OPERATION; 161 } 162 163 sw::Resource *staticBuffer = buffer ? buffer->getResource() : nullptr; 164 165 if(staticBuffer) 166 { 167 translated[i].vertexBuffer = staticBuffer; 168 translated[i].offset = firstVertexIndex * attrib.stride() + static_cast<int>(attrib.mOffset); 169 translated[i].stride = isInstanced ? 0 : attrib.stride(); 170 } 171 else 172 { 173 unsigned int streamOffset = writeAttributeData(mStreamingBuffer, firstVertexIndex, isInstanced ? 1 : count, attrib); 174 175 if(streamOffset == ~0u) 176 { 177 return GL_OUT_OF_MEMORY; 178 } 179 180 translated[i].vertexBuffer = mStreamingBuffer->getResource(); 181 translated[i].offset = streamOffset; 182 translated[i].stride = isInstanced ? 0 : attrib.typeSize(); 183 } 184 185 switch(attrib.mType) 186 { 187 case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break; 188 case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break; 189 case GL_SHORT: translated[i].type = sw::STREAMTYPE_SHORT; break; 190 case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break; 191 case GL_INT: translated[i].type = sw::STREAMTYPE_INT; break; 192 case GL_UNSIGNED_INT: translated[i].type = sw::STREAMTYPE_UINT; break; 193 case GL_FIXED: translated[i].type = sw::STREAMTYPE_FIXED; break; 194 case GL_FLOAT: translated[i].type = sw::STREAMTYPE_FLOAT; break; 195 case GL_HALF_FLOAT: translated[i].type = sw::STREAMTYPE_HALF; break; 196 case GL_HALF_FLOAT_OES: translated[i].type = sw::STREAMTYPE_HALF; break; 197 case GL_INT_2_10_10_10_REV: translated[i].type = sw::STREAMTYPE_2_10_10_10_INT; break; 198 case GL_UNSIGNED_INT_2_10_10_10_REV: translated[i].type = sw::STREAMTYPE_2_10_10_10_UINT; break; 199 default: UNREACHABLE(attrib.mType); translated[i].type = sw::STREAMTYPE_FLOAT; break; 200 } 201 202 translated[i].count = attrib.mSize; 203 translated[i].normalized = attrib.mNormalized; 204 } 205 else 206 { 207 if(mDirtyCurrentValue[i]) 208 { 209 delete mCurrentValueBuffer[i]; 210 mCurrentValueBuffer[i] = new ConstantVertexBuffer(attrib.getCurrentValueBitsAsFloat(0), attrib.getCurrentValueBitsAsFloat(1), attrib.getCurrentValueBitsAsFloat(2), attrib.getCurrentValueBitsAsFloat(3)); 211 mDirtyCurrentValue[i] = false; 212 } 213 214 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource(); 215 216 switch(attrib.currentValueType()) 217 { 218 case GL_INT: 219 translated[i].type = sw::STREAMTYPE_INT; 220 break; 221 case GL_UNSIGNED_INT: 222 translated[i].type = sw::STREAMTYPE_UINT; 223 break; 224 default: 225 translated[i].type = sw::STREAMTYPE_FLOAT; 226 break; 227 } 228 translated[i].count = 4; 229 translated[i].stride = 0; 230 translated[i].offset = 0; 231 translated[i].normalized = false; 232 } 233 } 234 } 235 236 return GL_NO_ERROR; 237 } 238 239 VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(nullptr) 240 { 241 if(size > 0) 242 { 243 mVertexBuffer = new sw::Resource(size + 1024); 244 245 if(!mVertexBuffer) 246 { 247 ERR("Out of memory allocating a vertex buffer of size %u.", size); 248 } 249 } 250 } 251 252 VertexBuffer::~VertexBuffer() 253 { 254 if(mVertexBuffer) 255 { 256 mVertexBuffer->destruct(); 257 } 258 } 259 260 void VertexBuffer::unmap() 261 { 262 if(mVertexBuffer) 263 { 264 mVertexBuffer->unlock(); 265 } 266 } 267 268 sw::Resource *VertexBuffer::getResource() const 269 { 270 return mVertexBuffer; 271 } 272 273 ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float)) 274 { 275 if(mVertexBuffer) 276 { 277 float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC); 278 279 vector[0] = x; 280 vector[1] = y; 281 vector[2] = z; 282 vector[3] = w; 283 284 mVertexBuffer->unlock(); 285 } 286 } 287 288 ConstantVertexBuffer::~ConstantVertexBuffer() 289 { 290 } 291 292 StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size) 293 { 294 mBufferSize = size; 295 mWritePosition = 0; 296 mRequiredSpace = 0; 297 } 298 299 StreamingVertexBuffer::~StreamingVertexBuffer() 300 { 301 } 302 303 void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace) 304 { 305 mRequiredSpace += requiredSpace; 306 } 307 308 void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset) 309 { 310 void *mapPtr = nullptr; 311 312 if(mVertexBuffer) 313 { 314 // We can use a private lock because we never overwrite the content 315 mapPtr = (char*)mVertexBuffer->lock(sw::PRIVATE) + mWritePosition; 316 317 *offset = mWritePosition; 318 mWritePosition += requiredSpace; 319 } 320 321 return mapPtr; 322 } 323 324 void StreamingVertexBuffer::reserveRequiredSpace() 325 { 326 if(mRequiredSpace > mBufferSize) 327 { 328 if(mVertexBuffer) 329 { 330 mVertexBuffer->destruct(); 331 mVertexBuffer = 0; 332 } 333 334 mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations. 335 336 mVertexBuffer = new sw::Resource(mBufferSize); 337 338 if(!mVertexBuffer) 339 { 340 ERR("Out of memory allocating a vertex buffer of size %u.", mBufferSize); 341 } 342 343 mWritePosition = 0; 344 } 345 else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle 346 { 347 if(mVertexBuffer) 348 { 349 mVertexBuffer->destruct(); 350 mVertexBuffer = new sw::Resource(mBufferSize); 351 } 352 353 mWritePosition = 0; 354 } 355 356 mRequiredSpace = 0; 357 } 358 359 } 360