blob: 1979b76cc5658abb05a9fb4aab2cb88edc92c469 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00002//
daniel@transgaming.comf6549452012-01-27 15:39:08 +00003// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
daniel@transgaming.com8fd34bd2011-02-18 02:52:14 +00008// IndexDataManager.cpp: Defines the IndexDataManager, a class that
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00009// runs the Buffer translation process for index buffers.
10
daniel@transgaming.com50aadb02012-11-28 21:06:11 +000011#include "libGLESv2/renderer/IndexDataManager.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000012#include "libGLESv2/renderer/BufferStorage.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000013
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000014#include "libGLESv2/Buffer.h"
daniel@transgaming.com37b141e2011-01-08 05:46:13 +000015#include "libGLESv2/main.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000016#include "libGLESv2/renderer/IndexBuffer.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000017
daniel@transgaming.com31240482012-11-28 21:06:41 +000018namespace rx
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000019{
20
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000021IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000022{
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000023 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
24 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000025 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000026 delete mStreamingBufferShort;
27 mStreamingBufferShort = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000028 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000029
30 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
31 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000032 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000033 delete mStreamingBufferInt;
daniel@transgaming.com83921382011-01-08 05:46:00 +000034 mStreamingBufferInt = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000035 }
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000036
37 if (!mStreamingBufferShort)
38 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000039 // Make sure both buffers are deleted.
40 delete mStreamingBufferInt;
41 mStreamingBufferInt = NULL;
42
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000043 ERR("Failed to allocate the streaming index buffer(s).");
44 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +000045
46 mCountingBuffer = NULL;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000047}
48
49IndexDataManager::~IndexDataManager()
50{
daniel@transgaming.com83921382011-01-08 05:46:00 +000051 delete mStreamingBufferShort;
52 delete mStreamingBufferInt;
daniel@transgaming.comf6549452012-01-27 15:39:08 +000053 delete mCountingBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000054}
55
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000056static unsigned int indexTypeSize(GLenum type)
57{
58 switch (type)
59 {
60 case GL_UNSIGNED_INT: return sizeof(GLuint);
61 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
62 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
63 default: UNREACHABLE(); return sizeof(GLushort);
64 }
65}
66
67static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000068{
daniel@transgaming.com83921382011-01-08 05:46:00 +000069 if (type == GL_UNSIGNED_BYTE)
70 {
71 const GLubyte *in = static_cast<const GLubyte*>(input);
72 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000073
daniel@transgaming.com83921382011-01-08 05:46:00 +000074 for (GLsizei i = 0; i < count; i++)
75 {
76 out[i] = in[i];
77 }
78 }
79 else if (type == GL_UNSIGNED_INT)
80 {
81 memcpy(output, input, count * sizeof(GLuint));
82 }
83 else if (type == GL_UNSIGNED_SHORT)
84 {
85 memcpy(output, input, count * sizeof(GLushort));
86 }
87 else UNREACHABLE();
88}
89
90template <class IndexType>
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000091static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000092{
daniel@transgaming.com83921382011-01-08 05:46:00 +000093 *minIndex = indices[0];
94 *maxIndex = indices[0];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000095
96 for (GLsizei i = 0; i < count; i++)
97 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000098 if (*minIndex > indices[i]) *minIndex = indices[i];
99 if (*maxIndex < indices[i]) *maxIndex = indices[i];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000100 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000101}
102
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000103static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000104{
daniel@transgaming.com83921382011-01-08 05:46:00 +0000105 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000106 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000107 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
108 }
109 else if (type == GL_UNSIGNED_INT)
110 {
111 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
112 }
113 else if (type == GL_UNSIGNED_SHORT)
114 {
115 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
116 }
117 else UNREACHABLE();
118}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000119
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000120GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000121{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +0000122 if (!mStreamingBufferShort)
123 {
124 return GL_OUT_OF_MEMORY;
125 }
126
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000127 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000128 intptr_t offset = reinterpret_cast<intptr_t>(indices);
129 bool alignedOffset = false;
130
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000131 BufferStorage *storage = NULL;
132
daniel@transgaming.com83921382011-01-08 05:46:00 +0000133 if (buffer != NULL)
134 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000135 storage = buffer->getStorage();
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000136
daniel@transgaming.com83921382011-01-08 05:46:00 +0000137 switch (type)
138 {
139 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
140 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
141 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
142 default: UNREACHABLE(); alignedOffset = false;
143 }
144
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000145 if (indexTypeSize(type) * count + offset > storage->getSize())
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000146 {
147 return GL_INVALID_OPERATION;
148 }
149
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000150 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000151 }
152
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000153 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000154
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000155 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
156 IndexBufferInterface *indexBuffer = streamingBuffer;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000157 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
158 destinationIndexType == type;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000159 UINT streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000160
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000161 if (directStorage)
162 {
163 indexBuffer = streamingBuffer;
164 streamOffset = offset;
165 storage->markBufferUsage();
166 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
167 }
168 else if (staticBuffer && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000169 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000170 indexBuffer = staticBuffer;
171 streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000172
daniel@transgaming.com83921382011-01-08 05:46:00 +0000173 if (streamOffset == -1)
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000174 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000175 streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000176 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
177 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000178 }
179 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000180 else
181 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000182 int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000183
daniel@transgaming.com83921382011-01-08 05:46:00 +0000184 if (staticBuffer)
185 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000186 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000187 {
188 indexBuffer = staticBuffer;
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000189 convertCount = storage->getSize() / indexTypeSize(type);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000190 }
191 else
192 {
193 buffer->invalidateStaticData();
194 staticBuffer = NULL;
195 }
196 }
197
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000198 if (!indexBuffer)
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000199 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000200 ERR("No valid index buffer.");
201 return GL_INVALID_OPERATION;
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000202 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000203
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000204 unsigned int bufferSizeRequired = convertCount * indexTypeSize(destinationIndexType);
205 indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
206
207 void* output = NULL;
208 streamOffset = indexBuffer->mapBuffer(bufferSizeRequired, &output);
209 if (streamOffset == -1 || output == NULL)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000210 {
211 ERR("Failed to map index buffer.");
212 return GL_OUT_OF_MEMORY;
213 }
214
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000215 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000216
217 if (!indexBuffer->unmapBuffer())
218 {
219 ERR("Failed to unmap index buffer.");
220 return GL_OUT_OF_MEMORY;
221 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000222
223 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
224
225 if (staticBuffer)
226 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000227 streamOffset = (offset / indexTypeSize(type)) * indexTypeSize(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000228 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
229 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000230 }
231
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000232 translated->storage = directStorage ? storage : NULL;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000233 translated->indexBuffer = indexBuffer->getIndexBuffer();
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000234 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000235 translated->startIndex = streamOffset / indexTypeSize(destinationIndexType);
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000236 translated->startOffset = streamOffset;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000237
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000238 if (buffer)
239 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000240 buffer->promoteStaticUsage(count * indexTypeSize(type));
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000241 }
242
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000243 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000244}
245
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000246StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000247{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000248 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000249 {
250 const unsigned int spaceNeeded = count * sizeof(unsigned short);
251
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000252 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000253 {
254 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000255 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000256 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000257
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000258 void* mappedMemory = NULL;
259 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000260 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000261 ERR("Failed to map counting buffer.");
262 return NULL;
263 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000264
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000265 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
266 for(int i = 0; i < count; i++)
267 {
268 data[i] = i;
269 }
270
271 if (!mCountingBuffer->unmapBuffer())
272 {
273 ERR("Failed to unmap counting buffer.");
274 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000275 }
276 }
277 }
278 else if (mStreamingBufferInt) // 32-bit indices supported
279 {
280 const unsigned int spaceNeeded = count * sizeof(unsigned int);
281
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000282 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000283 {
284 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000285 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000286 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000287
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000288 void* mappedMemory = NULL;
289 if (mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory) == -1 || mappedMemory == NULL)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000290 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000291 ERR("Failed to map counting buffer.");
292 return NULL;
293 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000294
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000295 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
296 for(int i = 0; i < count; i++)
297 {
298 data[i] = i;
299 }
300
301 if (!mCountingBuffer->unmapBuffer())
302 {
303 ERR("Failed to unmap counting buffer.");
304 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000305 }
306 }
307 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000308 else
309 {
310 return NULL;
311 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000312
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000313 return mCountingBuffer;
314}
315
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000316}