blob: 29be00a1742a6bc678dfdeadc872e7d7b08597aa [file] [log] [blame]
Nicolas Capensdbf6fc82014-10-23 13:33:20 -04001// SwiftShader Software Renderer
2//
3// Copyright(c) 2005-2012 TransGaming Inc.
4//
5// All rights reserved. No part of this software may be copied, distributed, transmitted,
6// transcribed, stored in a retrieval system, translated into any human or computer
7// language by any means, or disclosed to third parties without the explicit written
8// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9// or implied, including but not limited to any patent rights, are granted to you.
10//
11
12// IndexDataManager.cpp: Defines the IndexDataManager, a class that
13// runs the Buffer translation process for index buffers.
14
15#include "IndexDataManager.h"
16
17#include "Buffer.h"
18#include "common/debug.h"
19
20#include <string.h>
21#include <algorithm>
22
23namespace
24{
25 enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
26}
27
Nicolas Capens14ee7622014-10-28 23:48:41 -040028namespace es1
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040029{
30
31IndexDataManager::IndexDataManager()
32{
33 mStreamingBuffer = new StreamingIndexBuffer(INITIAL_INDEX_BUFFER_SIZE);
34
35 if(!mStreamingBuffer)
36 {
37 ERR("Failed to allocate the streaming index buffer.");
38 }
39}
40
41IndexDataManager::~IndexDataManager()
42{
43 delete mStreamingBuffer;
44}
45
46void copyIndices(GLenum type, const void *input, GLsizei count, void *output)
47{
48 if(type == GL_UNSIGNED_BYTE)
49 {
50 memcpy(output, input, count * sizeof(GLubyte));
51 }
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040052 else if(type == GL_UNSIGNED_SHORT)
53 {
54 memcpy(output, input, count * sizeof(GLushort));
55 }
Nicolas Capens3713cd42015-06-22 10:41:54 -040056 else UNREACHABLE(type);
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040057}
58
59template<class IndexType>
60void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
61{
62 *minIndex = indices[0];
63 *maxIndex = indices[0];
64
65 for(GLsizei i = 0; i < count; i++)
66 {
67 if(*minIndex > indices[i]) *minIndex = indices[i];
68 if(*maxIndex < indices[i]) *maxIndex = indices[i];
69 }
70}
71
72void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
73{
74 if(type == GL_UNSIGNED_BYTE)
75 {
76 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
77 }
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040078 else if(type == GL_UNSIGNED_SHORT)
79 {
80 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
81 }
Nicolas Capens3713cd42015-06-22 10:41:54 -040082 else UNREACHABLE(type);
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040083}
84
85GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
86{
87 if(!mStreamingBuffer)
88 {
89 return GL_OUT_OF_MEMORY;
90 }
91
92 intptr_t offset = reinterpret_cast<intptr_t>(indices);
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040093
94 if(buffer != NULL)
95 {
Nicolas Capensdbf6fc82014-10-23 13:33:20 -040096 if(typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
97 {
98 return GL_INVALID_OPERATION;
99 }
100
101 indices = static_cast<const GLubyte*>(buffer->data()) + offset;
102 }
103
104 StreamingIndexBuffer *streamingBuffer = mStreamingBuffer;
105
106 sw::Resource *staticBuffer = buffer ? buffer->getResource() : NULL;
107
108 if(staticBuffer)
109 {
110 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
111
112 translated->indexBuffer = staticBuffer;
113 translated->indexOffset = offset;
114 }
115 else
116 {
117 unsigned int streamOffset = 0;
118 int convertCount = count;
119
120 streamingBuffer->reserveSpace(convertCount * typeSize(type), type);
121 void *output = streamingBuffer->map(typeSize(type) * convertCount, &streamOffset);
122
123 if(output == NULL)
124 {
125 ERR("Failed to map index buffer.");
126 return GL_OUT_OF_MEMORY;
127 }
128
129 copyIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
130 streamingBuffer->unmap();
131
132 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
133
134 translated->indexBuffer = streamingBuffer->getResource();
135 translated->indexOffset = streamOffset;
136 }
137
138 return GL_NO_ERROR;
139}
140
141std::size_t IndexDataManager::typeSize(GLenum type)
142{
143 switch(type)
144 {
Nicolas Capensdbf6fc82014-10-23 13:33:20 -0400145 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
146 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
Nicolas Capens3713cd42015-06-22 10:41:54 -0400147 default: UNREACHABLE(type); return sizeof(GLushort);
Nicolas Capensdbf6fc82014-10-23 13:33:20 -0400148 }
149}
150
151StreamingIndexBuffer::StreamingIndexBuffer(unsigned int initialSize) : mBufferSize(initialSize), mIndexBuffer(NULL)
152{
153 if(initialSize > 0)
154 {
155 mIndexBuffer = new sw::Resource(initialSize + 16);
156
157 if(!mIndexBuffer)
158 {
Nicolas Capens8e8be7c2016-01-01 22:47:44 -0500159 ERR("Out of memory allocating an index buffer of size %u.", initialSize);
Nicolas Capensdbf6fc82014-10-23 13:33:20 -0400160 }
161 }
162
163 mWritePosition = 0;
164}
165
166StreamingIndexBuffer::~StreamingIndexBuffer()
167{
168 if(mIndexBuffer)
169 {
170 mIndexBuffer->destruct();
171 }
172}
173
174void *StreamingIndexBuffer::map(unsigned int requiredSpace, unsigned int *offset)
175{
176 void *mapPtr = NULL;
177
178 if(mIndexBuffer)
179 {
180 mapPtr = (char*)mIndexBuffer->lock(sw::PUBLIC) + mWritePosition;
181
182 if(!mapPtr)
183 {
184 ERR(" Lock failed");
185 return NULL;
186 }
187
188 *offset = mWritePosition;
189 mWritePosition += requiredSpace;
190 }
191
192 return mapPtr;
193}
194
195void StreamingIndexBuffer::unmap()
196{
197 if(mIndexBuffer)
198 {
199 mIndexBuffer->unlock();
200 }
201}
202
203void StreamingIndexBuffer::reserveSpace(unsigned int requiredSpace, GLenum type)
204{
205 if(requiredSpace > mBufferSize)
206 {
207 if(mIndexBuffer)
208 {
209 mIndexBuffer->destruct();
210 mIndexBuffer = 0;
211 }
212
213 mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
214
215 mIndexBuffer = new sw::Resource(mBufferSize + 16);
Nicolas Capens8e8be7c2016-01-01 22:47:44 -0500216
Nicolas Capensdbf6fc82014-10-23 13:33:20 -0400217 if(!mIndexBuffer)
218 {
Nicolas Capens8e8be7c2016-01-01 22:47:44 -0500219 ERR("Out of memory allocating an index buffer of size %u.", mBufferSize);
Nicolas Capensdbf6fc82014-10-23 13:33:20 -0400220 }
221
222 mWritePosition = 0;
223 }
224 else if(mWritePosition + requiredSpace > mBufferSize) // Recycle
225 {
226 if(mIndexBuffer)
227 {
228 mIndexBuffer->destruct();
229 mIndexBuffer = new sw::Resource(mBufferSize + 16);
230 }
231
232 mWritePosition = 0;
233 }
234}
235
236sw::Resource *StreamingIndexBuffer::getResource() const
237{
238 return mIndexBuffer;
239}
240
241}