blob: 6d45f8780f2ba6eed32705b404e9abc0116c9e33 [file] [log] [blame]
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00001//
daniel@transgaming.comf6549452012-01-27 15:39:08 +00002// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
daniel@transgaming.com8fd34bd2011-02-18 02:52:14 +00007// IndexDataManager.cpp: Defines the IndexDataManager, a class that
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00008// runs the Buffer translation process for index buffers.
9
daniel@transgaming.com50aadb02012-11-28 21:06:11 +000010#include "libGLESv2/renderer/IndexDataManager.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000011#include "libGLESv2/renderer/BufferStorage.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000012
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000013#include "libGLESv2/Buffer.h"
daniel@transgaming.com37b141e2011-01-08 05:46:13 +000014#include "libGLESv2/main.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000015#include "libGLESv2/renderer/IndexBuffer.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000016
daniel@transgaming.com31240482012-11-28 21:06:41 +000017namespace rx
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000018{
19
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000020IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000021{
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000022 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
23 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000024 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000025 delete mStreamingBufferShort;
26 mStreamingBufferShort = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000027 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000028
29 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
30 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000031 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000032 delete mStreamingBufferInt;
daniel@transgaming.com83921382011-01-08 05:46:00 +000033 mStreamingBufferInt = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000034 }
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000035
36 if (!mStreamingBufferShort)
37 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000038 // Make sure both buffers are deleted.
39 delete mStreamingBufferInt;
40 mStreamingBufferInt = NULL;
41
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000042 ERR("Failed to allocate the streaming index buffer(s).");
43 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +000044
45 mCountingBuffer = NULL;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000046}
47
48IndexDataManager::~IndexDataManager()
49{
daniel@transgaming.com83921382011-01-08 05:46:00 +000050 delete mStreamingBufferShort;
51 delete mStreamingBufferInt;
daniel@transgaming.comf6549452012-01-27 15:39:08 +000052 delete mCountingBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000053}
54
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000055static unsigned int indexTypeSize(GLenum type)
56{
57 switch (type)
58 {
59 case GL_UNSIGNED_INT: return sizeof(GLuint);
60 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
61 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
62 default: UNREACHABLE(); return sizeof(GLushort);
63 }
64}
65
66static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000067{
daniel@transgaming.com83921382011-01-08 05:46:00 +000068 if (type == GL_UNSIGNED_BYTE)
69 {
70 const GLubyte *in = static_cast<const GLubyte*>(input);
71 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000072
daniel@transgaming.com83921382011-01-08 05:46:00 +000073 for (GLsizei i = 0; i < count; i++)
74 {
75 out[i] = in[i];
76 }
77 }
78 else if (type == GL_UNSIGNED_INT)
79 {
80 memcpy(output, input, count * sizeof(GLuint));
81 }
82 else if (type == GL_UNSIGNED_SHORT)
83 {
84 memcpy(output, input, count * sizeof(GLushort));
85 }
86 else UNREACHABLE();
87}
88
89template <class IndexType>
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000090static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000091{
daniel@transgaming.com83921382011-01-08 05:46:00 +000092 *minIndex = indices[0];
93 *maxIndex = indices[0];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000094
95 for (GLsizei i = 0; i < count; i++)
96 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000097 if (*minIndex > indices[i]) *minIndex = indices[i];
98 if (*maxIndex < indices[i]) *maxIndex = indices[i];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000099 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000100}
101
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000102static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000103{
daniel@transgaming.com83921382011-01-08 05:46:00 +0000104 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000105 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000106 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
107 }
108 else if (type == GL_UNSIGNED_INT)
109 {
110 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
111 }
112 else if (type == GL_UNSIGNED_SHORT)
113 {
114 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
115 }
116 else UNREACHABLE();
117}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000118
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000119GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000120{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +0000121 if (!mStreamingBufferShort)
122 {
123 return GL_OUT_OF_MEMORY;
124 }
125
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000126 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000127 intptr_t offset = reinterpret_cast<intptr_t>(indices);
128 bool alignedOffset = false;
129
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000130 BufferStorage *storage = NULL;
131
daniel@transgaming.com83921382011-01-08 05:46:00 +0000132 if (buffer != NULL)
133 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000134 storage = buffer->getStorage();
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000135
daniel@transgaming.com83921382011-01-08 05:46:00 +0000136 switch (type)
137 {
138 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
139 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
140 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
141 default: UNREACHABLE(); alignedOffset = false;
142 }
143
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000144 if (indexTypeSize(type) * count + offset > storage->getSize())
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000145 {
146 return GL_INVALID_OPERATION;
147 }
148
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000149 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000150 }
151
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000152 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000153
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000154 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
155 IndexBufferInterface *indexBuffer = streamingBuffer;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000156 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
157 destinationIndexType == type;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000158 UINT streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000159
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000160 if (directStorage)
161 {
162 indexBuffer = streamingBuffer;
163 streamOffset = offset;
164 storage->markBufferUsage();
165 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
166 }
167 else if (staticBuffer && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000168 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000169 indexBuffer = staticBuffer;
170 streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000171
daniel@transgaming.com83921382011-01-08 05:46:00 +0000172 if (streamOffset == -1)
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000173 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000174 streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000175 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
176 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000177 }
178 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000179 else
180 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000181 int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000182
daniel@transgaming.com83921382011-01-08 05:46:00 +0000183 if (staticBuffer)
184 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000185 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000186 {
187 indexBuffer = staticBuffer;
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000188 convertCount = storage->getSize() / indexTypeSize(type);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000189 }
190 else
191 {
192 buffer->invalidateStaticData();
193 staticBuffer = NULL;
194 }
195 }
196
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000197 if (!indexBuffer)
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000198 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000199 ERR("No valid index buffer.");
200 return GL_INVALID_OPERATION;
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000201 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000202
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000203 unsigned int bufferSizeRequired = convertCount * indexTypeSize(destinationIndexType);
204 indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
205
206 void* output = NULL;
207 streamOffset = indexBuffer->mapBuffer(bufferSizeRequired, &output);
208 if (streamOffset == -1 || output == NULL)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000209 {
210 ERR("Failed to map index buffer.");
211 return GL_OUT_OF_MEMORY;
212 }
213
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000214 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000215
216 if (!indexBuffer->unmapBuffer())
217 {
218 ERR("Failed to unmap index buffer.");
219 return GL_OUT_OF_MEMORY;
220 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000221
222 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
223
224 if (staticBuffer)
225 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000226 streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000227 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
228 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000229 }
230
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000231 translated->storage = directStorage ? storage : NULL;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000232 translated->indexBuffer = indexBuffer->getIndexBuffer();
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000233 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000234 translated->startIndex = streamOffset / indexTypeSize(destinationIndexType);
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000235 translated->startOffset = streamOffset;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000236
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000237 if (buffer)
238 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000239 buffer->promoteStaticUsage(count * indexTypeSize(type));
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000240 }
241
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000242 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000243}
244
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000245StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000246{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000247 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000248 {
249 const unsigned int spaceNeeded = count * sizeof(unsigned short);
250
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000251 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000252 {
253 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000254 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000255 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000256
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000257 void* mappedMemory = NULL;
258 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000259 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000260 ERR("Failed to map counting buffer.");
261 return NULL;
262 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000263
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000264 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
265 for(int i = 0; i < count; i++)
266 {
267 data[i] = i;
268 }
269
270 if (!mCountingBuffer->unmapBuffer())
271 {
272 ERR("Failed to unmap counting buffer.");
273 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000274 }
275 }
276 }
277 else if (mStreamingBufferInt) // 32-bit indices supported
278 {
279 const unsigned int spaceNeeded = count * sizeof(unsigned int);
280
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000281 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000282 {
283 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000284 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000285 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000286
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000287 void* mappedMemory = NULL;
288 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000289 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000290 ERR("Failed to map counting buffer.");
291 return NULL;
292 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000293
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000294 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
295 for(int i = 0; i < count; i++)
296 {
297 data[i] = i;
298 }
299
300 if (!mCountingBuffer->unmapBuffer())
301 {
302 ERR("Failed to unmap counting buffer.");
303 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000304 }
305 }
306 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000307 else
308 {
309 return NULL;
310 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000311
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000312 return mCountingBuffer;
313}
314
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000315}