1 // SwiftShader Software Renderer
\r
3 // Copyright(c) 2005-2012 TransGaming Inc.
\r
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,
\r
6 // transcribed, stored in a retrieval system, translated into any human or computer
\r
7 // language by any means, or disclosed to third parties without the explicit written
\r
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
\r
9 // or implied, including but not limited to any patent rights, are granted to you.
\r
12 // VertexDataManager.h: Defines the VertexDataManager, a class that
\r
13 // runs the Buffer translation process.
\r
15 #include "VertexDataManager.h"
\r
18 #include "Program.h"
\r
19 #include "IndexDataManager.h"
\r
20 #include "common/debug.h"
\r
24 enum {INITIAL_STREAM_BUFFER_SIZE = 1024 * 1024};
\r
30 VertexDataManager::VertexDataManager(Context *context) : mContext(context)
\r
32 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
\r
34 mDirtyCurrentValue[i] = true;
\r
35 mCurrentValueBuffer[i] = NULL;
\r
38 mStreamingBuffer = new StreamingVertexBuffer(INITIAL_STREAM_BUFFER_SIZE);
\r
40 if(!mStreamingBuffer)
\r
42 ERR("Failed to allocate the streaming vertex buffer.");
\r
46 VertexDataManager::~VertexDataManager()
\r
48 delete mStreamingBuffer;
\r
50 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
\r
52 delete mCurrentValueBuffer[i];
\r
56 unsigned int VertexDataManager::writeAttributeData(StreamingVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
\r
58 Buffer *buffer = attribute.mBoundBuffer.get();
\r
60 int inputStride = attribute.stride();
\r
61 int elementSize = attribute.typeSize();
\r
62 unsigned int streamOffset = 0;
\r
64 char *output = NULL;
\r
68 output = (char*)vertexBuffer->map(attribute, attribute.typeSize() * count, &streamOffset);
\r
73 ERR("Failed to map vertex buffer.");
\r
77 const char *input = NULL;
\r
81 int offset = attribute.mOffset;
\r
83 input = static_cast<const char*>(buffer->data()) + offset;
\r
87 input = static_cast<const char*>(attribute.mPointer);
\r
90 input += inputStride * start;
\r
92 if(inputStride == elementSize)
\r
94 memcpy(output, input, count * inputStride);
\r
98 for(int i = 0; i < count; i++)
\r
100 memcpy(output, input, elementSize);
\r
101 output += elementSize;
\r
102 input += inputStride;
\r
106 vertexBuffer->unmap();
\r
108 return streamOffset;
\r
111 GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
\r
113 if(!mStreamingBuffer)
\r
115 return GL_OUT_OF_MEMORY;
\r
118 const VertexAttributeArray &attribs = mContext->getVertexAttributes();
\r
119 Program *program = mContext->getCurrentProgram();
\r
121 // Determine the required storage size per used buffer
\r
122 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
\r
124 if(program->getAttributeStream(i) != -1 && attribs[i].mArrayEnabled)
\r
126 if(!attribs[i].mBoundBuffer)
\r
128 mStreamingBuffer->addRequiredSpace(attribs[i].typeSize() * count);
\r
133 mStreamingBuffer->reserveRequiredSpace();
\r
135 // Perform the vertex data translations
\r
136 for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
\r
138 if(program->getAttributeStream(i) != -1)
\r
140 if(attribs[i].mArrayEnabled)
\r
142 Buffer *buffer = attribs[i].mBoundBuffer.get();
\r
144 if(!buffer && attribs[i].mPointer == NULL)
\r
146 // This is an application error that would normally result in a crash, but we catch it and return an error
\r
147 ERR("An enabled vertex array has no buffer and no pointer.");
\r
148 return GL_INVALID_OPERATION;
\r
151 sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
\r
155 translated[i].vertexBuffer = staticBuffer;
\r
156 translated[i].offset = start * attribs[i].stride() + attribs[i].mOffset;
\r
157 translated[i].stride = attribs[i].stride();
\r
161 unsigned int streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
\r
163 if(streamOffset == -1)
\r
165 return GL_OUT_OF_MEMORY;
\r
168 translated[i].vertexBuffer = mStreamingBuffer->getResource();
\r
169 translated[i].offset = streamOffset;
\r
170 translated[i].stride = attribs[i].typeSize();
\r
173 switch(attribs[i].mType)
\r
175 case GL_BYTE: translated[i].type = sw::STREAMTYPE_SBYTE; break;
\r
176 case GL_UNSIGNED_BYTE: translated[i].type = sw::STREAMTYPE_BYTE; break;
\r
177 case GL_SHORT: translated[i].type = sw::STREAMTYPE_SHORT; break;
\r
178 case GL_UNSIGNED_SHORT: translated[i].type = sw::STREAMTYPE_USHORT; break;
\r
179 case GL_FIXED: translated[i].type = sw::STREAMTYPE_FIXED; break;
\r
180 case GL_FLOAT: translated[i].type = sw::STREAMTYPE_FLOAT; break;
\r
181 default: UNREACHABLE(); translated[i].type = sw::STREAMTYPE_FLOAT; break;
\r
184 translated[i].count = attribs[i].mSize;
\r
185 translated[i].normalized = attribs[i].mNormalized;
\r
189 if(mDirtyCurrentValue[i])
\r
191 delete mCurrentValueBuffer[i];
\r
192 mCurrentValueBuffer[i] = new ConstantVertexBuffer(attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
\r
193 mDirtyCurrentValue[i] = false;
\r
196 translated[i].vertexBuffer = mCurrentValueBuffer[i]->getResource();
\r
198 translated[i].type = sw::STREAMTYPE_FLOAT;
\r
199 translated[i].count = 4;
\r
200 translated[i].stride = 0;
\r
201 translated[i].offset = 0;
\r
206 return GL_NO_ERROR;
\r
209 VertexBuffer::VertexBuffer(unsigned int size) : mVertexBuffer(NULL)
\r
213 mVertexBuffer = new sw::Resource(size + 1024);
\r
217 ERR("Out of memory allocating a vertex buffer of size %lu.", size);
\r
222 VertexBuffer::~VertexBuffer()
\r
226 mVertexBuffer->destruct();
\r
230 void VertexBuffer::unmap()
\r
234 mVertexBuffer->unlock();
\r
238 sw::Resource *VertexBuffer::getResource() const
\r
240 return mVertexBuffer;
\r
243 ConstantVertexBuffer::ConstantVertexBuffer(float x, float y, float z, float w) : VertexBuffer(4 * sizeof(float))
\r
247 float *vector = (float*)mVertexBuffer->lock(sw::PUBLIC);
\r
254 mVertexBuffer->unlock();
\r
258 ConstantVertexBuffer::~ConstantVertexBuffer()
\r
262 StreamingVertexBuffer::StreamingVertexBuffer(unsigned int size) : VertexBuffer(size)
\r
264 mBufferSize = size;
\r
265 mWritePosition = 0;
\r
266 mRequiredSpace = 0;
\r
269 StreamingVertexBuffer::~StreamingVertexBuffer()
\r
273 void StreamingVertexBuffer::addRequiredSpace(unsigned int requiredSpace)
\r
275 mRequiredSpace += requiredSpace;
\r
278 void *StreamingVertexBuffer::map(const VertexAttribute &attribute, unsigned int requiredSpace, unsigned int *offset)
\r
280 void *mapPtr = NULL;
\r
284 mapPtr = (char*)mVertexBuffer->lock(sw::PUBLIC) + mWritePosition;
\r
288 ERR("Lock failed");
\r
292 *offset = mWritePosition;
\r
293 mWritePosition += requiredSpace;
\r
299 void StreamingVertexBuffer::reserveRequiredSpace()
\r
301 if(mRequiredSpace > mBufferSize)
\r
305 mVertexBuffer->destruct();
\r
309 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.
\r
311 mVertexBuffer = new sw::Resource(mBufferSize);
\r
315 ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
\r
318 mWritePosition = 0;
\r
320 else if(mWritePosition + mRequiredSpace > mBufferSize) // Recycle
\r
324 mVertexBuffer->destruct();
\r
325 mVertexBuffer = new sw::Resource(mBufferSize);
\r
328 mWritePosition = 0;
\r
331 mRequiredSpace = 0;
\r