blob: 8f077c28c798e03d1525319e27a5ccaac5d866ed [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
13#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014
15#include "libGLESv2/Buffer.h"
daniel@transgaming.com81655a72010-05-20 19:18:17 +000016#include "libGLESv2/mathutil.h"
daniel@transgaming.com37b141e2011-01-08 05:46:13 +000017#include "libGLESv2/main.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000018
daniel@transgaming.com31240482012-11-28 21:06:41 +000019namespace rx
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000020{
21
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000022IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000023{
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000024 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
25 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000026 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000027 delete mStreamingBufferShort;
28 mStreamingBufferShort = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000029 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000030
31 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
32 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000033 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000034 delete mStreamingBufferInt;
daniel@transgaming.com83921382011-01-08 05:46:00 +000035 mStreamingBufferInt = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000036 }
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000037
38 if (!mStreamingBufferShort)
39 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000040 // Make sure both buffers are deleted.
41 delete mStreamingBufferInt;
42 mStreamingBufferInt = NULL;
43
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000044 ERR("Failed to allocate the streaming index buffer(s).");
45 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +000046
47 mCountingBuffer = NULL;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000048}
49
50IndexDataManager::~IndexDataManager()
51{
daniel@transgaming.com83921382011-01-08 05:46:00 +000052 delete mStreamingBufferShort;
53 delete mStreamingBufferInt;
daniel@transgaming.comf6549452012-01-27 15:39:08 +000054 delete mCountingBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000055}
56
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000057static unsigned int indexTypeSize(GLenum type)
58{
59 switch (type)
60 {
61 case GL_UNSIGNED_INT: return sizeof(GLuint);
62 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
63 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
64 default: UNREACHABLE(); return sizeof(GLushort);
65 }
66}
67
68static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000069{
daniel@transgaming.com83921382011-01-08 05:46:00 +000070 if (type == GL_UNSIGNED_BYTE)
71 {
72 const GLubyte *in = static_cast<const GLubyte*>(input);
73 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000074
daniel@transgaming.com83921382011-01-08 05:46:00 +000075 for (GLsizei i = 0; i < count; i++)
76 {
77 out[i] = in[i];
78 }
79 }
80 else if (type == GL_UNSIGNED_INT)
81 {
82 memcpy(output, input, count * sizeof(GLuint));
83 }
84 else if (type == GL_UNSIGNED_SHORT)
85 {
86 memcpy(output, input, count * sizeof(GLushort));
87 }
88 else UNREACHABLE();
89}
90
91template <class IndexType>
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000092static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000093{
daniel@transgaming.com83921382011-01-08 05:46:00 +000094 *minIndex = indices[0];
95 *maxIndex = indices[0];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000096
97 for (GLsizei i = 0; i < count; i++)
98 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000099 if (*minIndex > indices[i]) *minIndex = indices[i];
100 if (*maxIndex < indices[i]) *maxIndex = indices[i];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000101 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000102}
103
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000104static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000105{
daniel@transgaming.com83921382011-01-08 05:46:00 +0000106 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000107 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000108 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
109 }
110 else if (type == GL_UNSIGNED_INT)
111 {
112 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
113 }
114 else if (type == GL_UNSIGNED_SHORT)
115 {
116 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
117 }
118 else UNREACHABLE();
119}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000120
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000121GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000122{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +0000123 if (!mStreamingBufferShort)
124 {
125 return GL_OUT_OF_MEMORY;
126 }
127
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000128 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000129 intptr_t offset = reinterpret_cast<intptr_t>(indices);
130 bool alignedOffset = false;
131
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000132 BufferStorage *storage = NULL;
133
daniel@transgaming.com83921382011-01-08 05:46:00 +0000134 if (buffer != NULL)
135 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000136 storage = buffer->getStorage();
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000137
daniel@transgaming.com83921382011-01-08 05:46:00 +0000138 switch (type)
139 {
140 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
141 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
142 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
143 default: UNREACHABLE(); alignedOffset = false;
144 }
145
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000146 if (indexTypeSize(type) * count + offset > storage->getSize())
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000147 {
148 return GL_INVALID_OPERATION;
149 }
150
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000151 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000152 }
153
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000154 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000155
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000156 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
157 IndexBufferInterface *indexBuffer = streamingBuffer;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000158 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
159 destinationIndexType == type;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000160 UINT streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000161
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000162 if (directStorage)
163 {
164 indexBuffer = streamingBuffer;
165 streamOffset = offset;
166 storage->markBufferUsage();
167 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
168 }
169 else if (staticBuffer && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000170 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000171 indexBuffer = staticBuffer;
172 streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000173
daniel@transgaming.com83921382011-01-08 05:46:00 +0000174 if (streamOffset == -1)
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000175 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000176 streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000177 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
178 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000179 }
180 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000181 else
182 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000183 int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000184
daniel@transgaming.com83921382011-01-08 05:46:00 +0000185 if (staticBuffer)
186 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000187 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000188 {
189 indexBuffer = staticBuffer;
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000190 convertCount = storage->getSize() / indexTypeSize(type);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000191 }
192 else
193 {
194 buffer->invalidateStaticData();
195 staticBuffer = NULL;
196 }
197 }
198
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000199 if (!indexBuffer)
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000200 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000201 ERR("No valid index buffer.");
202 return GL_INVALID_OPERATION;
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000203 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000204
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000205 unsigned int bufferSizeRequired = convertCount * indexTypeSize(destinationIndexType);
206 indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
207
208 void* output = NULL;
209 streamOffset = indexBuffer->mapBuffer(bufferSizeRequired, &output);
210 if (streamOffset == -1 || output == NULL)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000211 {
212 ERR("Failed to map index buffer.");
213 return GL_OUT_OF_MEMORY;
214 }
215
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000216 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000217
218 if (!indexBuffer->unmapBuffer())
219 {
220 ERR("Failed to unmap index buffer.");
221 return GL_OUT_OF_MEMORY;
222 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000223
224 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
225
226 if (staticBuffer)
227 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000228 streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000229 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
230 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000231 }
232
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000233 translated->storage = directStorage ? storage : NULL;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000234 translated->indexBuffer = indexBuffer->getIndexBuffer();
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000235 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000236 translated->startIndex = streamOffset / indexTypeSize(destinationIndexType);
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000237 translated->startOffset = streamOffset;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000238
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000239 if (buffer)
240 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000241 buffer->promoteStaticUsage(count * indexTypeSize(type));
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000242 }
243
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000244 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000245}
246
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000247StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000248{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000249 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000250 {
251 const unsigned int spaceNeeded = count * sizeof(unsigned short);
252
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000253 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000254 {
255 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000256 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000257 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000258
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000259 void* mappedMemory = NULL;
260 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000261 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000262 ERR("Failed to map counting buffer.");
263 return NULL;
264 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000265
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000266 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
267 for(int i = 0; i < count; i++)
268 {
269 data[i] = i;
270 }
271
272 if (!mCountingBuffer->unmapBuffer())
273 {
274 ERR("Failed to unmap counting buffer.");
275 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000276 }
277 }
278 }
279 else if (mStreamingBufferInt) // 32-bit indices supported
280 {
281 const unsigned int spaceNeeded = count * sizeof(unsigned int);
282
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000283 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000284 {
285 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000286 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000287 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000288
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000289 void* mappedMemory = NULL;
290 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000291 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000292 ERR("Failed to map counting buffer.");
293 return NULL;
294 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000295
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000296 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
297 for(int i = 0; i < count; i++)
298 {
299 data[i] = i;
300 }
301
302 if (!mCountingBuffer->unmapBuffer())
303 {
304 ERR("Failed to unmap counting buffer.");
305 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000306 }
307 }
308 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000309 else
310 {
311 return NULL;
312 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000313
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000314 return mCountingBuffer;
315}
316
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000317}