blob: f29a6f269c76a30cb1b17e017e76840f52f2a72a [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
Geoff Lang2b5420c2014-11-19 14:20:15 -050010#include "libANGLE/renderer/d3d/IndexDataManager.h"
11#include "libANGLE/renderer/d3d/BufferD3D.h"
12#include "libANGLE/renderer/d3d/IndexBuffer.h"
13#include "libANGLE/renderer/d3d/RendererD3D.h"
14#include "libANGLE/Buffer.h"
15#include "libANGLE/formatutils.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000016
daniel@transgaming.com31240482012-11-28 21:06:41 +000017namespace rx
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000018{
19
Jamie Madill2b976812014-08-25 15:47:49 -040020static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000021{
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040022 if (sourceType == GL_UNSIGNED_BYTE)
daniel@transgaming.com83921382011-01-08 05:46:00 +000023 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040024 ASSERT(destinationType == GL_UNSIGNED_SHORT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000025 const GLubyte *in = static_cast<const GLubyte*>(input);
26 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000027
daniel@transgaming.com83921382011-01-08 05:46:00 +000028 for (GLsizei i = 0; i < count; i++)
29 {
30 out[i] = in[i];
31 }
32 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040033 else if (sourceType == GL_UNSIGNED_INT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000034 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040035 ASSERT(destinationType == GL_UNSIGNED_INT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000036 memcpy(output, input, count * sizeof(GLuint));
37 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040038 else if (sourceType == GL_UNSIGNED_SHORT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000039 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040040 if (destinationType == GL_UNSIGNED_SHORT)
41 {
42 memcpy(output, input, count * sizeof(GLushort));
43 }
44 else if (destinationType == GL_UNSIGNED_INT)
45 {
46 const GLushort *in = static_cast<const GLushort*>(input);
47 GLuint *out = static_cast<GLuint*>(output);
48
49 for (GLsizei i = 0; i < count; i++)
50 {
51 out[i] = in[i];
52 }
53 }
54 else UNREACHABLE();
daniel@transgaming.com83921382011-01-08 05:46:00 +000055 }
56 else UNREACHABLE();
57}
58
Jamie Madill93e13fb2014-11-06 15:27:25 -050059IndexDataManager::IndexDataManager(RendererD3D *renderer)
Geoff Lang1c134e62014-09-08 15:32:18 -040060 : mRenderer(renderer),
61 mStreamingBufferShort(NULL),
62 mStreamingBufferInt(NULL)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000063{
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000064}
65
Jamie Madill2b976812014-08-25 15:47:49 -040066IndexDataManager::~IndexDataManager()
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000067{
Jamie Madill2b976812014-08-25 15:47:49 -040068 SafeDelete(mStreamingBufferShort);
69 SafeDelete(mStreamingBufferInt);
daniel@transgaming.com83921382011-01-08 05:46:00 +000070}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000071
Geoff Langc9e69b12014-09-08 16:06:25 -040072gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +000073{
Geoff Lang5d601382014-07-22 15:14:06 -040074 const gl::Type &typeInfo = gl::GetTypeInfo(type);
75
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000076 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
Geoff Lang5d601382014-07-22 15:14:06 -040077
Geoff Langb23fc092013-08-06 10:43:14 -040078 unsigned int offset = 0;
daniel@transgaming.com83921382011-01-08 05:46:00 +000079 bool alignedOffset = false;
80
Brandon Jonesd38f9262014-06-18 16:26:45 -070081 BufferD3D *storage = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +000082
daniel@transgaming.com83921382011-01-08 05:46:00 +000083 if (buffer != NULL)
84 {
Geoff Langb23fc092013-08-06 10:43:14 -040085 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
86
Jamie Madill9236b412015-02-02 16:51:52 -050087 storage = GetImplAs<BufferD3D>(buffer);
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +000088
daniel@transgaming.com83921382011-01-08 05:46:00 +000089 switch (type)
90 {
91 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
92 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
93 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
94 default: UNREACHABLE(); alignedOffset = false;
95 }
96
Jamie Madillae3000b2014-08-25 15:47:51 -040097 ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000098
Geoff Langc8d297a2014-09-19 11:09:08 -040099 const uint8_t *bufferData = NULL;
100 gl::Error error = storage->getData(&bufferData);
101 if (error.isError())
102 {
103 return error;
104 }
105
106 indices = bufferData + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000107 }
108
Brandon Jonesd38f9262014-06-18 16:26:45 -0700109 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400110 IndexBufferInterface *indexBuffer = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000111 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
112 destinationIndexType == type;
Geoff Langa36ead42013-08-02 11:54:08 -0400113 unsigned int streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000114
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000115 if (directStorage)
116 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000117 streamOffset = offset;
Geoff Langf23eb282013-07-22 10:52:19 -0400118
Jamie Madill2b976812014-08-25 15:47:49 -0400119 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL))
Geoff Langf23eb282013-07-22 10:52:19 -0400120 {
Jamie Madillef9d63e2014-08-04 10:48:02 -0400121 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
Geoff Langf23eb282013-07-22 10:52:19 -0400122 }
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000123 }
shannon.woods@transgaming.com38e87882013-02-28 23:18:32 +0000124 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000125 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000126 indexBuffer = staticBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000127
Jamie Madill2b976812014-08-25 15:47:49 -0400128 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000129 {
Geoff Lang5d601382014-07-22 15:14:06 -0400130 streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400131 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000132 }
Olli Etuaho8fcd4e02015-03-24 16:19:33 +0200133 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, nullptr, nullptr))
134 {
135 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
136 }
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000137 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400138
139 // Avoid D3D11's primitive restart index value
140 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
Jamie Madill39b43462014-08-18 16:39:50 -0400141 if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400142 {
143 destinationIndexType = GL_UNSIGNED_INT;
144 directStorage = false;
145 indexBuffer = NULL;
146 }
147
Geoff Lang5d601382014-07-22 15:14:06 -0400148 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
149
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400150 if (!directStorage && !indexBuffer)
151 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400152 gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
153 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400154 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400155 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400156 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400157
Geoff Langa36ead42013-08-02 11:54:08 -0400158 unsigned int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000159
daniel@transgaming.com83921382011-01-08 05:46:00 +0000160 if (staticBuffer)
161 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000162 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000163 {
164 indexBuffer = staticBuffer;
Geoff Lang5d601382014-07-22 15:14:06 -0400165 convertCount = storage->getSize() / typeInfo.bytes;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000166 }
167 else
168 {
Brandon Jonesd38f9262014-06-18 16:26:45 -0700169 storage->invalidateStaticData();
daniel@transgaming.com83921382011-01-08 05:46:00 +0000170 staticBuffer = NULL;
171 }
172 }
173
Jamie Madillae3000b2014-08-25 15:47:51 -0400174 ASSERT(indexBuffer);
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000175
Geoff Lang5d601382014-07-22 15:14:06 -0400176 if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
Geoff Langa36ead42013-08-02 11:54:08 -0400177 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400178 return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
179 convertCount, destTypeInfo.bytes);
Geoff Langa36ead42013-08-02 11:54:08 -0400180 }
181
Geoff Lang5d601382014-07-22 15:14:06 -0400182 unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
Geoff Langc9e69b12014-09-08 16:06:25 -0400183 error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
184 if (error.isError())
Geoff Langa36ead42013-08-02 11:54:08 -0400185 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400186 return error;
Geoff Langa36ead42013-08-02 11:54:08 -0400187 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000188
189 void* output = NULL;
Geoff Langc9e69b12014-09-08 16:06:25 -0400190 error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
191 if (error.isError())
daniel@transgaming.com83921382011-01-08 05:46:00 +0000192 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400193 return error;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000194 }
195
Geoff Langc8d297a2014-09-19 11:09:08 -0400196 const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices);
197 if (staticBuffer)
198 {
199 error = storage->getData(&dataPointer);
200 if (error.isError())
201 {
202 return error;
203 }
204 }
205 ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000206
Geoff Langc9e69b12014-09-08 16:06:25 -0400207 error = indexBuffer->unmapBuffer();
208 if (error.isError())
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000209 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400210 return error;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000211 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000212
daniel@transgaming.com83921382011-01-08 05:46:00 +0000213 if (staticBuffer)
214 {
Geoff Lang5d601382014-07-22 15:14:06 -0400215 streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400216 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000217 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000218 }
219
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000220 translated->storage = directStorage ? storage : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400221 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000222 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
Geoff Lang5d601382014-07-22 15:14:06 -0400223 translated->startIndex = streamOffset / destTypeInfo.bytes;
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000224 translated->startOffset = streamOffset;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400225 translated->indexType = destinationIndexType;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000226
Brandon Jonesd38f9262014-06-18 16:26:45 -0700227 if (storage)
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000228 {
Geoff Lang5d601382014-07-22 15:14:06 -0400229 storage->promoteStaticUsage(count * typeInfo.bytes);
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000230 }
231
Geoff Langc9e69b12014-09-08 16:06:25 -0400232 return gl::Error(GL_NO_ERROR);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000233}
234
Geoff Langc9e69b12014-09-08 16:06:25 -0400235gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer)
Geoff Lang1c134e62014-09-08 15:32:18 -0400236{
237 ASSERT(outBuffer);
238 if (destinationIndexType == GL_UNSIGNED_INT)
239 {
240 if (!mStreamingBufferInt)
241 {
242 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
Geoff Langc9e69b12014-09-08 16:06:25 -0400243 gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
244 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400245 {
246 SafeDelete(mStreamingBufferInt);
Geoff Langc9e69b12014-09-08 16:06:25 -0400247 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400248 }
249 }
250
251 *outBuffer = mStreamingBufferInt;
Geoff Langc9e69b12014-09-08 16:06:25 -0400252 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400253 }
254 else
255 {
256 ASSERT(destinationIndexType == GL_UNSIGNED_SHORT);
257
258 if (!mStreamingBufferShort)
259 {
260 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
Geoff Langc9e69b12014-09-08 16:06:25 -0400261 gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
262 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400263 {
264 SafeDelete(mStreamingBufferShort);
Geoff Langc9e69b12014-09-08 16:06:25 -0400265 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400266 }
267 }
268
269 *outBuffer = mStreamingBufferShort;
Geoff Langc9e69b12014-09-08 16:06:25 -0400270 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400271 }
272}
273
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000274}