blob: 10725d4f1844ffbca85b01c3edfa03532c8ac6d4 [file] [log] [blame]
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00001//
Nicolas Capens8d62bcc2014-07-25 15:08:21 -04002// Copyright (c) 2002-2014 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
Brandon Jonesc7a41042014-06-23 12:03:25 -070010#include "libGLESv2/renderer/d3d/IndexDataManager.h"
Brandon Jonesd38f9262014-06-18 16:26:45 -070011#include "libGLESv2/renderer/d3d/BufferD3D.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040012#include "libGLESv2/renderer/d3d/IndexBuffer.h"
13#include "libGLESv2/renderer/Renderer.h"
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"
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
Jamie Madill2b976812014-08-25 15:47:49 -040021static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000022{
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040023 if (sourceType == GL_UNSIGNED_BYTE)
daniel@transgaming.com83921382011-01-08 05:46:00 +000024 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040025 ASSERT(destinationType == GL_UNSIGNED_SHORT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000026 const GLubyte *in = static_cast<const GLubyte*>(input);
27 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000028
daniel@transgaming.com83921382011-01-08 05:46:00 +000029 for (GLsizei i = 0; i < count; i++)
30 {
31 out[i] = in[i];
32 }
33 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040034 else if (sourceType == GL_UNSIGNED_INT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000035 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040036 ASSERT(destinationType == GL_UNSIGNED_INT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000037 memcpy(output, input, count * sizeof(GLuint));
38 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040039 else if (sourceType == GL_UNSIGNED_SHORT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000040 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040041 if (destinationType == GL_UNSIGNED_SHORT)
42 {
43 memcpy(output, input, count * sizeof(GLushort));
44 }
45 else if (destinationType == GL_UNSIGNED_INT)
46 {
47 const GLushort *in = static_cast<const GLushort*>(input);
48 GLuint *out = static_cast<GLuint*>(output);
49
50 for (GLsizei i = 0; i < count; i++)
51 {
52 out[i] = in[i];
53 }
54 }
55 else UNREACHABLE();
daniel@transgaming.com83921382011-01-08 05:46:00 +000056 }
57 else UNREACHABLE();
58}
59
Jamie Madill2b976812014-08-25 15:47:49 -040060IndexDataManager::IndexDataManager(Renderer *renderer)
61 : mRenderer(renderer)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000062{
Jamie Madill2b976812014-08-25 15:47:49 -040063 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
64 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000065 {
Jamie Madill2b976812014-08-25 15:47:49 -040066 SafeDelete(mStreamingBufferShort);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000067 }
Jamie Madill39b43462014-08-18 16:39:50 -040068
Jamie Madill2b976812014-08-25 15:47:49 -040069 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
70 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
71 {
72 SafeDelete(mStreamingBufferInt);
73 }
74
75 if (!mStreamingBufferShort)
76 {
77 // Make sure both buffers are deleted.
78 SafeDelete(mStreamingBufferInt);
79 ERR("Failed to allocate the streaming index buffer(s).");
80 }
81
82 mCountingBuffer = NULL;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000083}
84
Jamie Madill2b976812014-08-25 15:47:49 -040085IndexDataManager::~IndexDataManager()
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000086{
Jamie Madill2b976812014-08-25 15:47:49 -040087 SafeDelete(mStreamingBufferShort);
88 SafeDelete(mStreamingBufferInt);
89 SafeDelete(mCountingBuffer);
daniel@transgaming.com83921382011-01-08 05:46:00 +000090}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000091
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000092GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +000093{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000094 if (!mStreamingBufferShort)
95 {
96 return GL_OUT_OF_MEMORY;
97 }
98
Geoff Lang5d601382014-07-22 15:14:06 -040099 const gl::Type &typeInfo = gl::GetTypeInfo(type);
100
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000101 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
Geoff Lang5d601382014-07-22 15:14:06 -0400102
Geoff Langb23fc092013-08-06 10:43:14 -0400103 unsigned int offset = 0;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000104 bool alignedOffset = false;
105
Brandon Jonesd38f9262014-06-18 16:26:45 -0700106 BufferD3D *storage = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000107
daniel@transgaming.com83921382011-01-08 05:46:00 +0000108 if (buffer != NULL)
109 {
Geoff Langb23fc092013-08-06 10:43:14 -0400110 if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
111 {
112 return GL_OUT_OF_MEMORY;
113 }
114 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
115
Brandon Jonesd38f9262014-06-18 16:26:45 -0700116 storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000117
daniel@transgaming.com83921382011-01-08 05:46:00 +0000118 switch (type)
119 {
120 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
121 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
122 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
123 default: UNREACHABLE(); alignedOffset = false;
124 }
125
Jamie Madillae3000b2014-08-25 15:47:51 -0400126 ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000127
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +0000128 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000129 }
130
Brandon Jonesd38f9262014-06-18 16:26:45 -0700131 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400132 IndexBufferInterface *indexBuffer = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000133 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
134 destinationIndexType == type;
Geoff Langa36ead42013-08-02 11:54:08 -0400135 unsigned int streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000136
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000137 if (directStorage)
138 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000139 streamOffset = offset;
Geoff Langf23eb282013-07-22 10:52:19 -0400140
Jamie Madill2b976812014-08-25 15:47:49 -0400141 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL))
Geoff Langf23eb282013-07-22 10:52:19 -0400142 {
Jamie Madillef9d63e2014-08-04 10:48:02 -0400143 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
Geoff Langf23eb282013-07-22 10:52:19 -0400144 }
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000145 }
shannon.woods@transgaming.com38e87882013-02-28 23:18:32 +0000146 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000147 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000148 indexBuffer = staticBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000149
Jamie Madill2b976812014-08-25 15:47:49 -0400150 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000151 {
Geoff Lang5d601382014-07-22 15:14:06 -0400152 streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400153 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000154 }
155 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400156
157 // Avoid D3D11's primitive restart index value
158 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
Jamie Madill39b43462014-08-18 16:39:50 -0400159 if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400160 {
161 destinationIndexType = GL_UNSIGNED_INT;
162 directStorage = false;
163 indexBuffer = NULL;
164 }
165
Geoff Lang5d601382014-07-22 15:14:06 -0400166 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
167
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400168 if (!directStorage && !indexBuffer)
169 {
170 indexBuffer = (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
171
Geoff Langa36ead42013-08-02 11:54:08 -0400172 unsigned int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000173
daniel@transgaming.com83921382011-01-08 05:46:00 +0000174 if (staticBuffer)
175 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000176 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000177 {
178 indexBuffer = staticBuffer;
Geoff Lang5d601382014-07-22 15:14:06 -0400179 convertCount = storage->getSize() / typeInfo.bytes;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000180 }
181 else
182 {
Brandon Jonesd38f9262014-06-18 16:26:45 -0700183 storage->invalidateStaticData();
daniel@transgaming.com83921382011-01-08 05:46:00 +0000184 staticBuffer = NULL;
185 }
186 }
187
Jamie Madillae3000b2014-08-25 15:47:51 -0400188 ASSERT(indexBuffer);
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000189
Geoff Lang5d601382014-07-22 15:14:06 -0400190 if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
Geoff Langa36ead42013-08-02 11:54:08 -0400191 {
Geoff Lang5d601382014-07-22 15:14:06 -0400192 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, destTypeInfo.bytes);
Geoff Langa36ead42013-08-02 11:54:08 -0400193 return GL_OUT_OF_MEMORY;
194 }
195
Geoff Lang5d601382014-07-22 15:14:06 -0400196 unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
Geoff Langa36ead42013-08-02 11:54:08 -0400197 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
198 {
199 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
200 return GL_OUT_OF_MEMORY;
201 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000202
203 void* output = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400204 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
daniel@transgaming.com83921382011-01-08 05:46:00 +0000205 {
206 ERR("Failed to map index buffer.");
207 return GL_OUT_OF_MEMORY;
208 }
209
Jamie Madill2b976812014-08-25 15:47:49 -0400210 ConvertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000211
212 if (!indexBuffer->unmapBuffer())
213 {
214 ERR("Failed to unmap index buffer.");
215 return GL_OUT_OF_MEMORY;
216 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000217
daniel@transgaming.com83921382011-01-08 05:46:00 +0000218 if (staticBuffer)
219 {
Geoff Lang5d601382014-07-22 15:14:06 -0400220 streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400221 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000222 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000223 }
224
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000225 translated->storage = directStorage ? storage : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400226 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000227 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
Geoff Lang5d601382014-07-22 15:14:06 -0400228 translated->startIndex = streamOffset / destTypeInfo.bytes;
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000229 translated->startOffset = streamOffset;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400230 translated->indexType = destinationIndexType;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000231
Brandon Jonesd38f9262014-06-18 16:26:45 -0700232 if (storage)
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000233 {
Geoff Lang5d601382014-07-22 15:14:06 -0400234 storage->promoteStaticUsage(count * typeInfo.bytes);
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000235 }
236
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000237 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000238}
239
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000240StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000241{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000242 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000243 {
244 const unsigned int spaceNeeded = count * sizeof(unsigned short);
245
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000246 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000247 {
248 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000249 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000250 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000251
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000252 void* mappedMemory = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400253 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000254 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000255 ERR("Failed to map counting buffer.");
256 return NULL;
257 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000258
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000259 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
260 for(int i = 0; i < count; i++)
261 {
262 data[i] = i;
263 }
264
265 if (!mCountingBuffer->unmapBuffer())
266 {
267 ERR("Failed to unmap counting buffer.");
268 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000269 }
270 }
271 }
272 else if (mStreamingBufferInt) // 32-bit indices supported
273 {
274 const unsigned int spaceNeeded = count * sizeof(unsigned int);
275
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000276 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000277 {
278 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000279 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000280 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000281
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000282 void* mappedMemory = NULL;
Geoff Langa36ead42013-08-02 11:54:08 -0400283 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000284 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000285 ERR("Failed to map counting buffer.");
286 return NULL;
287 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000288
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000289 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
290 for(int i = 0; i < count; i++)
291 {
292 data[i] = i;
293 }
294
295 if (!mCountingBuffer->unmapBuffer())
296 {
297 ERR("Failed to unmap counting buffer.");
298 return NULL;
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000299 }
300 }
301 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000302 else
303 {
304 return NULL;
305 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000306
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000307 return mCountingBuffer;
308}
309
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000310}