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 gl 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 int offset = attribute.mOffset; 85 86 input = static_cast<const char*>(buffer->data()) + offset; 87 } 88 else 89 { 90 input = static_cast<const char*>(attribute.mPointer); 91 } 92 93 input += inputStride * start; 94 95 if(inputStride == elementSize) 96 { 97 memcpy(output, input, count * inputStride); 98 } 99 else 100 { 101 for(int i = 0; i < count; i++) 102 { 103 memcpy(output, input, elementSize); 104 output += elementSize; 105 input += inputStride; 106 } 107 } 108 109 vertexBuffer->unmap(); 110 111 return streamOffset; 112 } 113 114 GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated) 115 { 116 if(!mStreamingBuffer) 117 { 118 return GL_OUT_OF_MEMORY; 119 } 120 121 const VertexAttributeArray &attribs = mContext->getVertexAttributes(); 122 Program *program = mContext->getCurrentProgram(); 123 124 // Determine the required storage size per used buffer 125 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 126 { 127 if(!program || program->getAttributeStream(i) != -1) 128 { 129 if(attribs[i].mArrayEnabled) 130 { 131 if(!attribs[i].mBoundBuffer) 132 { 133 mStreamingBuffer->addRequiredSpace(attribs[i].typeSize() * count); 134 } 135 } 136 } 137 } 138 139 mStreamingBuffer->reserveRequiredSpace(); 140 141 // Perform the vertex data translations 142 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 143 { 144 if(!program || program->getAttributeStream(i) != -1) 145 { 146 if(attribs[i].mArrayEnabled) 147 { 148 Buffer *buffer = attribs[i].mBoundBuffer; 149 150 if(!buffer && attribs[i].mPointer == nullptr) 151 { 152 // This is an application error that would normally result in a crash, but we catch it and return an error 153 ERR("An enabled vertex array has no buffer and no pointer."); 154 return GL_INVALID_OPERATION; 155 } 156 157 sw::Resource *staticBuffer = buffer ? buffer->getResource() : nullptr; 158 159 if(staticBuffer) 160 { 161 translated[i].vertexBuffer = staticBuffer; 162 translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset; 163 translated[i].stride = attribs[i].stride(); 164 } 165 else 166 { 167 unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]); 168 169 if(streamOffset == ~0u) 170 { 171 return GL_OUT_OF_MEMORY; 172 } 173 174 translated[i].vertexBuffer = mStreamingBuffer->getResource(); 175 translated[i].offset = streamOffset; 176 translated[i].stride = attribs[i].typeSize(); 177 } 178 179 switch(attribs[i].mType) 180 { 181 case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break; 182 case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break; 183 case GL_SHORT: translated[i].type = sw::STREAMTYPE_SHORT; break; 184 case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break; 185 case GL_INT: translated[i].type = sw::STREAMTYPE_INT; break; 186 case GL_UNSIGNED_INT: translated[i].type = sw::STREAMTYPE_UINT; break; 187 case GL_FIXED: translated[i].type = sw::STREAMTYPE_FIXED; break; 188 case GL_FLOAT: translated[i].type = sw::STREAMTYPE_FLOAT; break; 189 default: UNREACHABLE(attribs[i].mType); translated[i].type = sw::STREAMTYPE_FLOAT; break; 190 } 191 192 translated[i].count = attribs[i].mSize; 193 translated[i].normalized = attribs[i].mNormalized; 194 } 195 else 196 { 197 if(mDirtyCurrentValue[i]) 198 { 199 delete mCurrentValueBuffer[i]; 200 mCurrentValueBuffer[i] = new ConstantVertexBuffer(attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]); 201 mDirtyCurrentValue[i] = false; 202 } 203 204 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource(); 205 206 translated[i].type = sw::STREAMTYPE_FLOAT; 207 translated[i].count = 4; 208 translated[i].stride = 0; 209 translated[i].offset = 0; 210 } 211 } 212 } 213 214 return GL_NO_ERROR; 215 } 216 217 VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(nullptr) 218 { 219 if(size > 0) 220 { 221 mVertexBuffer = new sw::Resource(size + 1024); 222 223 if(!mVertexBuffer) 224 { 225 ERR("Out of memory allocating a vertex buffer of size %u.", size); 226 } 227 } 228 } 229 230 VertexBuffer::~VertexBuffer() 231 { 232 if(mVertexBuffer) 233 { 234 mVertexBuffer->destruct(); 235 } 236 } 237 238 void VertexBuffer::unmap() 239 { 240 if(mVertexBuffer) 241 { 242 mVertexBuffer->unlock(); 243 } 244 } 245 246 sw::Resource *VertexBuffer::getResource() const 247 { 248 return mVertexBuffer; 249 } 250 251 ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float)) 252 { 253 if(mVertexBuffer) 254 { 255 float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC); 256 257 vector[0] = x; 258 vector[1] = y; 259 vector[2] = z; 260 vector[3] = w; 261 262 mVertexBuffer->unlock(); 263 } 264 } 265 266 ConstantVertexBuffer::~ConstantVertexBuffer() 267 { 268 } 269 270 StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size) 271 { 272 mBufferSize = size; 273 mWritePosition = 0; 274 mRequiredSpace = 0; 275 } 276 277 StreamingVertexBuffer::~StreamingVertexBuffer() 278 { 279 } 280 281 void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace) 282 { 283 mRequiredSpace += requiredSpace; 284 } 285 286 void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset) 287 { 288 void *mapPtr = nullptr; 289 290 if(mVertexBuffer) 291 { 292 // We can use a private lock because we never overwrite the content 293 mapPtr = (char*)mVertexBuffer->lock(sw::PRIVATE) + mWritePosition; 294 295 *offset = mWritePosition; 296 mWritePosition += requiredSpace; 297 } 298 299 return mapPtr; 300 } 301 302 void StreamingVertexBuffer::reserveRequiredSpace() 303 { 304 if(mRequiredSpace > mBufferSize) 305 { 306 if(mVertexBuffer) 307 { 308 mVertexBuffer->destruct(); 309 mVertexBuffer = 0; 310 } 311 312 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. 313 314 mVertexBuffer = new sw::Resource(mBufferSize); 315 316 if(!mVertexBuffer) 317 { 318 ERR("Out of memory allocating a vertex buffer of size %u.", mBufferSize); 319 } 320 321 mWritePosition = 0; 322 } 323 else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle 324 { 325 if(mVertexBuffer) 326 { 327 mVertexBuffer->destruct(); 328 mVertexBuffer = new sw::Resource(mBufferSize); 329 } 330 331 mWritePosition = 0; 332 } 333 334 mRequiredSpace = 0; 335 } 336 337 } 338