blob: 932524c1321a538655fc5e5db18d7fa3d5ffe539 [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
Brandon Jonesc7a41042014-06-23 12:03:25 -070011#include "libGLESv2/renderer/d3d/IndexDataManager.h"
Brandon Jonesd38f9262014-06-18 16:26:45 -070012#include "libGLESv2/renderer/d3d/BufferD3D.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"
Geoff Langf23eb282013-07-22 10:52:19 -040016#include "libGLESv2/formatutils.h"
Brandon Jonesc7a41042014-06-23 12:03:25 -070017#include "libGLESv2/renderer/d3d/IndexBuffer.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 void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000058{
daniel@transgaming.com83921382011-01-08 05:46:00 +000059 if (type == GL_UNSIGNED_BYTE)
60 {
61 const GLubyte *in = static_cast<const GLubyte*>(input);
62 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000063
daniel@transgaming.com83921382011-01-08 05:46:00 +000064 for (GLsizei i = 0; i < count; i++)
65 {
66 out[i] = in[i];
67 }
68 }
69 else if (type == GL_UNSIGNED_INT)
70 {
71 memcpy(output, input, count * sizeof(GLuint));
72 }
73 else if (type == GL_UNSIGNED_SHORT)
74 {
75 memcpy(output, input, count * sizeof(GLushort));
76 }
77 else UNREACHABLE();
78}
79
80template <class IndexType>
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000081static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000082{
daniel@transgaming.com83921382011-01-08 05:46:00 +000083 *minIndex = indices[0];
84 *maxIndex = indices[0];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000085
86 for (GLsizei i = 0; i < count; i++)
87 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000088 if (*minIndex > indices[i]) *minIndex = indices[i];
89 if (*maxIndex < indices[i]) *maxIndex = indices[i];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000090 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000091}
92
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000093static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000094{
daniel@transgaming.com83921382011-01-08 05:46:00 +000095 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000096 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000097 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
98 }
99 else if (type == GL_UNSIGNED_INT)
100 {
101 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
102 }
103 else if (type == GL_UNSIGNED_SHORT)
104 {
105 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
106 }
107 else UNREACHABLE();
108}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000109
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000110GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000111{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +0000112 if (!mStreamingBufferShort)
113 {
114 return GL_OUT_OF_MEMORY;
115 }
116
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000117 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
Geoff Langb23fc092013-08-06 10:43:14 -0400118 unsigned int offset = 0;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000119 bool alignedOffset = false;
120
Brandon Jonesd38f9262014-06-18 16:26:45 -0700121 BufferD3D *storage = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000122
daniel@transgaming.com83921382011-01-08 05:46:00 +0000123 if (buffer != NULL)
124 {
Geoff Langb23fc092013-08-06 10:43:14 -0400125 if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
126 {
127 return GL_OUT_OF_MEMORY;
128 }
129 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
130
Brandon Jonesd38f9262014-06-18 16:26:45 -0700131 storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000132
daniel@transgaming.com83921382011-01-08 05:46:00 +0000133 switch (type)
134 {
135 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
136 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
137 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
138 default: UNREACHABLE(); alignedOffset = false;
139 }
140
Geoff Langa36ead42013-08-02 11:54:08 -0400141 unsigned int typeSize = gl::GetTypeBytes(type);
142
Geoff Langfdf06942013-08-06 10:41:05 -0400143 // check for integer overflows
144 if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
145 typeSize * static_cast<unsigned int>(count) + offset < offset)
Geoff Langa36ead42013-08-02 11:54:08 -0400146 {
147 return GL_OUT_OF_MEMORY;
148 }
149
150 if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000151 {
152 return GL_INVALID_OPERATION;
153 }
154
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000155 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000156 }
157
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000158 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000159
Brandon Jonesd38f9262014-06-18 16:26:45 -0700160 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000161 IndexBufferInterface *indexBuffer = streamingBuffer;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000162 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
163 destinationIndexType == type;
Geoff Langa36ead42013-08-02 11:54:08 -0400164 unsigned int streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000165
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000166 if (directStorage)
167 {
168 indexBuffer = streamingBuffer;
169 streamOffset = offset;
Geoff Langf23eb282013-07-22 10:52:19 -0400170
Brandon Jonesd38f9262014-06-18 16:26:45 -0700171 if (!storage->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
Geoff Langf23eb282013-07-22 10:52:19 -0400172 &translated->maxIndex, NULL))
173 {
174 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700175 storage->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
Geoff Langf23eb282013-07-22 10:52:19 -0400176 translated->maxIndex, offset);
177 }
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000178 }
shannon.woods@transgaming.com38e87882013-02-28 23:18:32 +0000179 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000180 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000181 indexBuffer = staticBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000182
Geoff Langf23eb282013-07-22 10:52:19 -0400183 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
184 &translated->maxIndex, &streamOffset))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000185 {
Geoff Langf23eb282013-07-22 10:52:19 -0400186 streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000187 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
Geoff Langf23eb282013-07-22 10:52:19 -0400188 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
189 translated->maxIndex, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000190 }
191 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000192 else
193 {
Geoff Langa36ead42013-08-02 11:54:08 -0400194 unsigned int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000195
daniel@transgaming.com83921382011-01-08 05:46:00 +0000196 if (staticBuffer)
197 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000198 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000199 {
200 indexBuffer = staticBuffer;
Geoff Langf23eb282013-07-22 10:52:19 -0400201 convertCount = storage->getSize() / gl::GetTypeBytes(type);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000202 }
203 else
204 {
Brandon Jonesd38f9262014-06-18 16:26:45 -0700205 storage->invalidateStaticData();
daniel@transgaming.com83921382011-01-08 05:46:00 +0000206 staticBuffer = NULL;
207 }
208 }
209
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000210 if (!indexBuffer)
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000211 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000212 ERR("No valid index buffer.");
213 return GL_INVALID_OPERATION;
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000214 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000215
Geoff Langa36ead42013-08-02 11:54:08 -0400216 unsigned int indexTypeSize = gl::GetTypeBytes(destinationIndexType);
217 if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
218 {
219 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
220 return GL_OUT_OF_MEMORY;
221 }
222
223 unsigned int bufferSizeRequired = convertCount * indexTypeSize;
224 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
225 {
226 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
227 return GL_OUT_OF_MEMORY;
228 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000229
230 void* output = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400231 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
daniel@transgaming.com83921382011-01-08 05:46:00 +0000232 {
233 ERR("Failed to map index buffer.");
234 return GL_OUT_OF_MEMORY;
235 }
236
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000237 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000238
239 if (!indexBuffer->unmapBuffer())
240 {
241 ERR("Failed to unmap index buffer.");
242 return GL_OUT_OF_MEMORY;
243 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000244
245 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
246
247 if (staticBuffer)
248 {
Geoff Langf23eb282013-07-22 10:52:19 -0400249 streamOffset = (offset / gl::GetTypeBytes(type)) * gl::GetTypeBytes(destinationIndexType);
250 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
251 translated->maxIndex, streamOffset);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000252 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000253 }
254
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000255 translated->storage = directStorage ? storage : NULL;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000256 translated->indexBuffer = indexBuffer->getIndexBuffer();
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000257 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
Geoff Langf23eb282013-07-22 10:52:19 -0400258 translated->startIndex = streamOffset / gl::GetTypeBytes(destinationIndexType);
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000259 translated->startOffset = streamOffset;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000260
Brandon Jonesd38f9262014-06-18 16:26:45 -0700261 if (storage)
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000262 {
Brandon Jonesd38f9262014-06-18 16:26:45 -0700263 storage->promoteStaticUsage(count * gl::GetTypeBytes(type));
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000264 }
265
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000266 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000267}
268
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000269StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000270{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000271 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000272 {
273 const unsigned int spaceNeeded = count * sizeof(unsigned short);
274
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000275 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000276 {
277 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000278 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000279 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000280
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000281 void* mappedMemory = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400282 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000283 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000284 ERR("Failed to map counting buffer.");
285 return NULL;
286 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000287
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000288 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
289 for(int i = 0; i < count; i++)
290 {
291 data[i] = i;
292 }
293
294 if (!mCountingBuffer->unmapBuffer())
295 {
296 ERR("Failed to unmap counting buffer.");
297 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000298 }
299 }
300 }
301 else if (mStreamingBufferInt) // 32-bit indices supported
302 {
303 const unsigned int spaceNeeded = count * sizeof(unsigned int);
304
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000305 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000306 {
307 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000308 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000309 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000310
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000311 void* mappedMemory = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400312 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000313 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000314 ERR("Failed to map counting buffer.");
315 return NULL;
316 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000317
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000318 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
319 for(int i = 0; i < count; i++)
320 {
321 data[i] = i;
322 }
323
324 if (!mCountingBuffer->unmapBuffer())
325 {
326 ERR("Failed to unmap counting buffer.");
327 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000328 }
329 }
330 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000331 else
332 {
333 return NULL;
334 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000335
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000336 return mCountingBuffer;
337}
338
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000339}