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 25namespace 26{ 27 enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024}; 28} 29 30namespace gl 31{ 32 33VertexDataManager::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 49VertexDataManager::~VertexDataManager() 50{ 51 delete mStreamingBuffer; 52 53 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 54 { 55 delete mCurrentValueBuffer[i]; 56 } 57} 58 59unsigned 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 114GLenum 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 217VertexBuffer::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 230VertexBuffer::~VertexBuffer() 231{ 232 if(mVertexBuffer) 233 { 234 mVertexBuffer->destruct(); 235 } 236} 237 238void VertexBuffer::unmap() 239{ 240 if(mVertexBuffer) 241 { 242 mVertexBuffer->unlock(); 243 } 244} 245 246sw::Resource *VertexBuffer::getResource() const 247{ 248 return mVertexBuffer; 249} 250 251ConstantVertexBuffer::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 266ConstantVertexBuffer::~ConstantVertexBuffer() 267{ 268} 269 270StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size) 271{ 272 mBufferSize = size; 273 mWritePosition = 0; 274 mRequiredSpace = 0; 275} 276 277StreamingVertexBuffer::~StreamingVertexBuffer() 278{ 279} 280 281void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace) 282{ 283 mRequiredSpace += requiredSpace; 284} 285 286void *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 302void 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