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