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 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
\r
13 // runs the Buffer translation process for index buffers.
\r
15 #include "IndexDataManager.h"
\r
18 #include "common/debug.h"
\r
21 #include <algorithm>
\r
25 enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
\r
31 IndexDataManager::IndexDataManager()
\r
33 mStreamingBuffer = new StreamingIndexBuffer(INITIAL_INDEX_BUFFER_SIZE);
\r
35 if(!mStreamingBuffer)
\r
37 ERR("Failed to allocate the streaming index buffer.");
\r
41 IndexDataManager::~IndexDataManager()
\r
43 delete mStreamingBuffer;
\r
46 void copyIndices(GLenum type, const void *input, GLsizei count, void *output)
\r
48 if(type == GL_UNSIGNED_BYTE)
\r
50 memcpy(output, input, count * sizeof(GLubyte));
\r
52 else if(type == GL_UNSIGNED_INT)
\r
54 memcpy(output, input, count * sizeof(GLuint));
\r
56 else if(type == GL_UNSIGNED_SHORT)
\r
58 memcpy(output, input, count * sizeof(GLushort));
\r
63 template<class IndexType>
\r
64 void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
\r
66 *minIndex = indices[0];
\r
67 *maxIndex = indices[0];
\r
69 for(GLsizei i = 0; i < count; i++)
\r
71 if(*minIndex > indices[i]) *minIndex = indices[i];
\r
72 if(*maxIndex < indices[i]) *maxIndex = indices[i];
\r
76 void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
\r
78 if(type == GL_UNSIGNED_BYTE)
\r
80 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
\r
82 else if(type == GL_UNSIGNED_INT)
\r
84 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
\r
86 else if(type == GL_UNSIGNED_SHORT)
\r
88 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
\r
93 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
\r
95 if(!mStreamingBuffer)
\r
97 return GL_OUT_OF_MEMORY;
\r
100 intptr_t offset = reinterpret_cast<intptr_t>(indices);
\r
101 bool alignedOffset = false;
\r
107 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
\r
108 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
\r
109 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
\r
110 default: UNREACHABLE(); alignedOffset = false;
\r
113 if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
\r
115 return GL_INVALID_OPERATION;
\r
118 indices = static_cast<const GLubyte*>(buffer->data()) + offset;
\r
121 StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
\r
123 sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
\r
127 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
\r
129 translated->indexBuffer = staticBuffer;
\r
130 translated->indexOffset = offset;
\r
134 unsigned int streamOffset = 0;
\r
135 int convertCount = count;
\r
137 streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
\r
138 void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
\r
142 ERR("Failed to map index buffer.");
\r
143 return GL_OUT_OF_MEMORY;
\r
146 copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
\r
147 streamingBuffer->unmap();
\r
149 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
\r
151 translated->indexBuffer = streamingBuffer->getResource();
\r
152 translated->indexOffset = streamOffset;
\r
155 return GL_NO_ERROR;
\r
158 std::size_t IndexDataManager::typeSize(GLenum type)
\r
162 case GL_UNSIGNED_INT: return sizeof(GLuint);
\r
163 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
\r
164 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
\r
165 default: UNREACHABLE(); return sizeof(GLushort);
\r
169 StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mBufferSize(initialSize), mIndexBuffer(NULL)
\r
171 if(initialSize > 0)
\r
173 mIndexBuffer = new sw::Resource(initialSize + 16);
\r
177 ERR("Out of memory allocating an index buffer of size %lu.", initialSize);
\r
181 mWritePosition = 0;
\r
184 StreamingIndexBuffer::~StreamingIndexBuffer()
\r
188 mIndexBuffer->destruct();
\r
192 void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset)
\r
194 void *mapPtr = NULL;
\r
198 mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;
\r
202 ERR(" Lock failed");
\r
206 *offset = mWritePosition;
\r
207 mWritePosition += requiredSpace;
\r
213 void StreamingIndexBuffer::unmap()
\r
217 mIndexBuffer->unlock();
\r
221 void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type)
\r
223 if(requiredSpace > mBufferSize)
\r
227 mIndexBuffer->destruct();
\r
231 mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
\r
233 mIndexBuffer = new sw::Resource(mBufferSize + 16);
\r
237 ERR("Out of memory allocating an index buffer of size %lu.", mBufferSize);
\r
240 mWritePosition = 0;
\r
242 else if(mWritePosition + requiredSpace > mBufferSize) // Recycle
\r
246 mIndexBuffer->destruct();
\r
247 mIndexBuffer = new sw::Resource(mBufferSize + 16);
\r
250 mWritePosition = 0;
\r
254 sw::Resource *StreamingIndexBuffer::getResource() const
\r
256 return mIndexBuffer;
\r