blob: ce46b3dfb907eb0ce71ad30e24450711109d9387 [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//
Nicolas Capens8d62bcc2014-07-25 15:08:21 -04003// Copyright (c) 2002-2014 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"
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040018#include "libGLESv2/renderer/Renderer.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000019
daniel@transgaming.com31240482012-11-28 21:06:41 +000020namespace rx
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000021{
22
Jamie Madill2b976812014-08-25 15:47:49 -040023static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000024{
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040025 if (sourceType == GL_UNSIGNED_BYTE)
daniel@transgaming.com83921382011-01-08 05:46:00 +000026 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040027 ASSERT(destinationType == GL_UNSIGNED_SHORT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000028 const GLubyte *in = static_cast<const GLubyte*>(input);
29 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000030
daniel@transgaming.com83921382011-01-08 05:46:00 +000031 for (GLsizei i = 0; i < count; i++)
32 {
33 out[i] = in[i];
34 }
35 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040036 else if (sourceType == GL_UNSIGNED_INT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000037 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040038 ASSERT(destinationType == GL_UNSIGNED_INT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000039 memcpy(output, input, count * sizeof(GLuint));
40 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040041 else if (sourceType == GL_UNSIGNED_SHORT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000042 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040043 if (destinationType == GL_UNSIGNED_SHORT)
44 {
45 memcpy(output, input, count * sizeof(GLushort));
46 }
47 else if (destinationType == GL_UNSIGNED_INT)
48 {
49 const GLushort *in = static_cast<const GLushort*>(input);
50 GLuint *out = static_cast<GLuint*>(output);
51
52 for (GLsizei i = 0; i < count; i++)
53 {
54 out[i] = in[i];
55 }
56 }
57 else UNREACHABLE();
daniel@transgaming.com83921382011-01-08 05:46:00 +000058 }
59 else UNREACHABLE();
60}
61
Jamie Madill2b976812014-08-25 15:47:49 -040062IndexDataManager::IndexDataManager(Renderer *renderer)
63 : mRenderer(renderer)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000064{
Jamie Madill2b976812014-08-25 15:47:49 -040065 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
66 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000067 {
Jamie Madill2b976812014-08-25 15:47:49 -040068 SafeDelete(mStreamingBufferShort);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000069 }
Jamie Madill39b43462014-08-18 16:39:50 -040070
Jamie Madill2b976812014-08-25 15:47:49 -040071 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
72 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
73 {
74 SafeDelete(mStreamingBufferInt);
75 }
76
77 if (!mStreamingBufferShort)
78 {
79 // Make sure both buffers are deleted.
80 SafeDelete(mStreamingBufferInt);
81 ERR("Failed to allocate the streaming index buffer(s).");
82 }
83
84 mCountingBuffer = NULL;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000085}
86
Jamie Madill2b976812014-08-25 15:47:49 -040087IndexDataManager::~IndexDataManager()
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000088{
Jamie Madill2b976812014-08-25 15:47:49 -040089 SafeDelete(mStreamingBufferShort);
90 SafeDelete(mStreamingBufferInt);
91 SafeDelete(mCountingBuffer);
daniel@transgaming.com83921382011-01-08 05:46:00 +000092}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000093
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000094GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +000095{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000096 if (!mStreamingBufferShort)
97 {
98 return GL_OUT_OF_MEMORY;
99 }
100
Geoff Lang5d601382014-07-22 15:14:06 -0400101 const gl::Type &typeInfo = gl::GetTypeInfo(type);
102
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000103 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
Geoff Lang5d601382014-07-22 15:14:06 -0400104
Geoff Langb23fc092013-08-06 10:43:14 -0400105 unsigned int offset = 0;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000106 bool alignedOffset = false;
107
Brandon Jonesd38f9262014-06-18 16:26:45 -0700108 BufferD3D *storage = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000109
daniel@transgaming.com83921382011-01-08 05:46:00 +0000110 if (buffer != NULL)
111 {
Geoff Langb23fc092013-08-06 10:43:14 -0400112 if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
113 {
114 return GL_OUT_OF_MEMORY;
115 }
116 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
117
Brandon Jonesd38f9262014-06-18 16:26:45 -0700118 storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000119
daniel@transgaming.com83921382011-01-08 05:46:00 +0000120 switch (type)
121 {
122 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
123 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
124 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
125 default: UNREACHABLE(); alignedOffset = false;
126 }
127
Geoff Langfdf06942013-08-06 10:41:05 -0400128 // check for integer overflows
Geoff Lang5d601382014-07-22 15:14:06 -0400129 if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeInfo.bytes) ||
130 typeInfo.bytes * static_cast<unsigned int>(count) + offset < offset)
Geoff Langa36ead42013-08-02 11:54:08 -0400131 {
132 return GL_OUT_OF_MEMORY;
133 }
134
Geoff Lang5d601382014-07-22 15:14:06 -0400135 if (typeInfo.bytes * static_cast<unsigned int>(count) + offset > storage->getSize())
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000136 {
137 return GL_INVALID_OPERATION;
138 }
139
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000140 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000141 }
142
Brandon Jonesd38f9262014-06-18 16:26:45 -0700143 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400144 IndexBufferInterface *indexBuffer = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000145 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
146 destinationIndexType == type;
Geoff Langa36ead42013-08-02 11:54:08 -0400147 unsigned int streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000148
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000149 if (directStorage)
150 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000151 streamOffset = offset;
Geoff Langf23eb282013-07-22 10:52:19 -0400152
Jamie Madill2b976812014-08-25 15:47:49 -0400153 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL))
Geoff Langf23eb282013-07-22 10:52:19 -0400154 {
Jamie Madillef9d63e2014-08-04 10:48:02 -0400155 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
Geoff Langf23eb282013-07-22 10:52:19 -0400156 }
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000157 }
shannon.woods@transgaming.com38e87882013-02-28 23:18:32 +0000158 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000159 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000160 indexBuffer = staticBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000161
Jamie Madill2b976812014-08-25 15:47:49 -0400162 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000163 {
Geoff Lang5d601382014-07-22 15:14:06 -0400164 streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400165 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000166 }
167 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400168
169 // Avoid D3D11's primitive restart index value
170 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
Jamie Madill39b43462014-08-18 16:39:50 -0400171 if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400172 {
173 destinationIndexType = GL_UNSIGNED_INT;
174 directStorage = false;
175 indexBuffer = NULL;
176 }
177
Geoff Lang5d601382014-07-22 15:14:06 -0400178 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
179
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400180 if (!directStorage && !indexBuffer)
181 {
182 indexBuffer = (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
183
Geoff Langa36ead42013-08-02 11:54:08 -0400184 unsigned int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000185
daniel@transgaming.com83921382011-01-08 05:46:00 +0000186 if (staticBuffer)
187 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000188 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000189 {
190 indexBuffer = staticBuffer;
Geoff Lang5d601382014-07-22 15:14:06 -0400191 convertCount = storage->getSize() / typeInfo.bytes;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000192 }
193 else
194 {
Brandon Jonesd38f9262014-06-18 16:26:45 -0700195 storage->invalidateStaticData();
daniel@transgaming.com83921382011-01-08 05:46:00 +0000196 staticBuffer = NULL;
197 }
198 }
199
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000200 if (!indexBuffer)
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000201 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000202 ERR("No valid index buffer.");
203 return GL_INVALID_OPERATION;
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000204 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000205
Geoff Lang5d601382014-07-22 15:14:06 -0400206 if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
Geoff Langa36ead42013-08-02 11:54:08 -0400207 {
Geoff Lang5d601382014-07-22 15:14:06 -0400208 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, destTypeInfo.bytes);
Geoff Langa36ead42013-08-02 11:54:08 -0400209 return GL_OUT_OF_MEMORY;
210 }
211
Geoff Lang5d601382014-07-22 15:14:06 -0400212 unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
Geoff Langa36ead42013-08-02 11:54:08 -0400213 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
214 {
215 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
216 return GL_OUT_OF_MEMORY;
217 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000218
219 void* output = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400220 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
daniel@transgaming.com83921382011-01-08 05:46:00 +0000221 {
222 ERR("Failed to map index buffer.");
223 return GL_OUT_OF_MEMORY;
224 }
225
Jamie Madill2b976812014-08-25 15:47:49 -0400226 ConvertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000227
228 if (!indexBuffer->unmapBuffer())
229 {
230 ERR("Failed to unmap index buffer.");
231 return GL_OUT_OF_MEMORY;
232 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000233
daniel@transgaming.com83921382011-01-08 05:46:00 +0000234 if (staticBuffer)
235 {
Geoff Lang5d601382014-07-22 15:14:06 -0400236 streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400237 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000238 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000239 }
240
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000241 translated->storage = directStorage ? storage : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400242 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000243 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
Geoff Lang5d601382014-07-22 15:14:06 -0400244 translated->startIndex = streamOffset / destTypeInfo.bytes;
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000245 translated->startOffset = streamOffset;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400246 translated->indexType = destinationIndexType;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000247
Brandon Jonesd38f9262014-06-18 16:26:45 -0700248 if (storage)
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000249 {
Geoff Lang5d601382014-07-22 15:14:06 -0400250 storage->promoteStaticUsage(count * typeInfo.bytes);
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000251 }
252
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000253 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000254}
255
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000256StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000257{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000258 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000259 {
260 const unsigned int spaceNeeded = count * sizeof(unsigned short);
261
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000262 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000263 {
264 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000265 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000266 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000267
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000268 void* mappedMemory = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400269 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000270 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000271 ERR("Failed to map counting buffer.");
272 return NULL;
273 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000274
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000275 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
276 for(int i = 0; i < count; i++)
277 {
278 data[i] = i;
279 }
280
281 if (!mCountingBuffer->unmapBuffer())
282 {
283 ERR("Failed to unmap counting buffer.");
284 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000285 }
286 }
287 }
288 else if (mStreamingBufferInt) // 32-bit indices supported
289 {
290 const unsigned int spaceNeeded = count * sizeof(unsigned int);
291
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000292 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000293 {
294 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000295 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000296 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000297
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000298 void* mappedMemory = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400299 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000300 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000301 ERR("Failed to map counting buffer.");
302 return NULL;
303 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000304
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000305 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
306 for(int i = 0; i < count; i++)
307 {
308 data[i] = i;
309 }
310
311 if (!mCountingBuffer->unmapBuffer())
312 {
313 ERR("Failed to unmap counting buffer.");
314 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000315 }
316 }
317 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000318 else
319 {
320 return NULL;
321 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000322
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000323 return mCountingBuffer;
324}
325
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000326}