blob: 7c68c1c5dd00128fa385260ebd055072fd095843 [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"
Geoff Lang2b5420c2014-11-19 14:20:15 -050013#include "libANGLE/Buffer.h"
14#include "libANGLE/formatutils.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000015
daniel@transgaming.com31240482012-11-28 21:06:41 +000016namespace rx
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000017{
18
Jamie Madill2b976812014-08-25 15:47:49 -040019static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000020{
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040021 if (sourceType == GL_UNSIGNED_BYTE)
daniel@transgaming.com83921382011-01-08 05:46:00 +000022 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040023 ASSERT(destinationType == GL_UNSIGNED_SHORT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000024 const GLubyte *in = static_cast<const GLubyte*>(input);
25 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000026
daniel@transgaming.com83921382011-01-08 05:46:00 +000027 for (GLsizei i = 0; i < count; i++)
28 {
29 out[i] = in[i];
30 }
31 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040032 else if (sourceType == GL_UNSIGNED_INT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000033 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040034 ASSERT(destinationType == GL_UNSIGNED_INT);
daniel@transgaming.com83921382011-01-08 05:46:00 +000035 memcpy(output, input, count * sizeof(GLuint));
36 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040037 else if (sourceType == GL_UNSIGNED_SHORT)
daniel@transgaming.com83921382011-01-08 05:46:00 +000038 {
Nicolas Capens8d62bcc2014-07-25 15:08:21 -040039 if (destinationType == GL_UNSIGNED_SHORT)
40 {
41 memcpy(output, input, count * sizeof(GLushort));
42 }
43 else if (destinationType == GL_UNSIGNED_INT)
44 {
45 const GLushort *in = static_cast<const GLushort*>(input);
46 GLuint *out = static_cast<GLuint*>(output);
47
48 for (GLsizei i = 0; i < count; i++)
49 {
50 out[i] = in[i];
51 }
52 }
53 else UNREACHABLE();
daniel@transgaming.com83921382011-01-08 05:46:00 +000054 }
55 else UNREACHABLE();
56}
57
Jamie Madillfd1bf4e2015-03-31 09:46:02 -040058IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass)
59 : mFactory(factory),
60 mRendererClass(rendererClass),
61 mStreamingBufferShort(nullptr),
62 mStreamingBufferInt(nullptr)
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
Olli Etuaho11ffe1b2015-03-24 17:28:18 +020089 // We'll trust that the compiler will optimize the % below:
90 // the operands are unsigned and the divisor is a constant.
daniel@transgaming.com83921382011-01-08 05:46:00 +000091 switch (type)
92 {
93 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
94 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
95 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
96 default: UNREACHABLE(); alignedOffset = false;
97 }
98
Jamie Madillae3000b2014-08-25 15:47:51 -040099 ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000100
Geoff Langc8d297a2014-09-19 11:09:08 -0400101 const uint8_t *bufferData = NULL;
102 gl::Error error = storage->getData(&bufferData);
103 if (error.isError())
104 {
105 return error;
106 }
107
108 indices = bufferData + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000109 }
110
Brandon Jonesd38f9262014-06-18 16:26:45 -0700111 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400112 IndexBufferInterface *indexBuffer = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000113 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
114 destinationIndexType == type;
Geoff Langa36ead42013-08-02 11:54:08 -0400115 unsigned int streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000116
Jamie Madillb48e8b02015-04-15 14:26:37 -0400117 // Avoid D3D11's primitive restart index value
118 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
119 bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
120 translated->indexRange.end == 0xFFFF &&
121 type == GL_UNSIGNED_SHORT;
122
123 if (primitiveRestartWorkaround)
124 {
125 destinationIndexType = GL_UNSIGNED_INT;
126 directStorage = false;
127 }
128
129 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
130
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000131 if (directStorage)
132 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000133 streamOffset = offset;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000134 }
Jamie Madillb48e8b02015-04-15 14:26:37 -0400135 else if (staticBuffer &&
136 staticBuffer->getBufferSize() != 0 &&
137 alignedOffset &&
138 staticBuffer->getIndexType() == destinationIndexType)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000139 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000140 indexBuffer = staticBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000141
Olli Etuahoff5e7372015-03-25 16:52:11 +0200142 // Using bit-shift here is faster than using division.
Jamie Madillb48e8b02015-04-15 14:26:37 -0400143 streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000144 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400145
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400146 if (!directStorage && !indexBuffer)
147 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400148 gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
149 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400150 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400151 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400152 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400153
Geoff Langa36ead42013-08-02 11:54:08 -0400154 unsigned int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000155
daniel@transgaming.com83921382011-01-08 05:46:00 +0000156 if (staticBuffer)
157 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000158 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000159 {
160 indexBuffer = staticBuffer;
Olli Etuaho11ffe1b2015-03-24 17:28:18 +0200161 // Using bit-shift here is faster than using division.
162 convertCount = storage->getSize() >> typeInfo.bytesShift;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000163 }
164 else
165 {
Brandon Jonesd38f9262014-06-18 16:26:45 -0700166 storage->invalidateStaticData();
daniel@transgaming.com83921382011-01-08 05:46:00 +0000167 staticBuffer = NULL;
168 }
169 }
170
Jamie Madillae3000b2014-08-25 15:47:51 -0400171 ASSERT(indexBuffer);
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000172
Olli Etuaho11ffe1b2015-03-24 17:28:18 +0200173 // Using bit-shift here is faster than using division.
174 if (convertCount > (std::numeric_limits<unsigned int>::max() >> destTypeInfo.bytesShift))
Geoff Langa36ead42013-08-02 11:54:08 -0400175 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400176 return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
177 convertCount, destTypeInfo.bytes);
Geoff Langa36ead42013-08-02 11:54:08 -0400178 }
179
Olli Etuaho11ffe1b2015-03-24 17:28:18 +0200180 unsigned int bufferSizeRequired = convertCount << destTypeInfo.bytesShift;
Jamie Madillb48e8b02015-04-15 14:26:37 -0400181 error = indexBuffer->reserveBufferSpace(bufferSizeRequired, destinationIndexType);
Geoff Langc9e69b12014-09-08 16:06:25 -0400182 if (error.isError())
Geoff Langa36ead42013-08-02 11:54:08 -0400183 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400184 return error;
Geoff Langa36ead42013-08-02 11:54:08 -0400185 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000186
187 void* output = NULL;
Geoff Langc9e69b12014-09-08 16:06:25 -0400188 error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
189 if (error.isError())
daniel@transgaming.com83921382011-01-08 05:46:00 +0000190 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400191 return error;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000192 }
193
Geoff Langc8d297a2014-09-19 11:09:08 -0400194 const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices);
195 if (staticBuffer)
196 {
197 error = storage->getData(&dataPointer);
198 if (error.isError())
199 {
200 return error;
201 }
202 }
203 ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000204
Geoff Langc9e69b12014-09-08 16:06:25 -0400205 error = indexBuffer->unmapBuffer();
206 if (error.isError())
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000207 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400208 return error;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000209 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000210
daniel@transgaming.com83921382011-01-08 05:46:00 +0000211 if (staticBuffer)
212 {
Olli Etuaho11ffe1b2015-03-24 17:28:18 +0200213 // Using bit-shift here is faster than using division.
214 streamOffset = (offset >> typeInfo.bytesShift) << destTypeInfo.bytesShift;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000215 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000216 }
217
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000218 translated->storage = directStorage ? storage : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400219 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000220 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
Olli Etuaho11ffe1b2015-03-24 17:28:18 +0200221 // Using bit-shift here is faster than using division.
222 translated->startIndex = (streamOffset >> destTypeInfo.bytesShift);
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000223 translated->startOffset = streamOffset;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400224 translated->indexType = destinationIndexType;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000225
Brandon Jonesd38f9262014-06-18 16:26:45 -0700226 if (storage)
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000227 {
Olli Etuaho11ffe1b2015-03-24 17:28:18 +0200228 storage->promoteStaticUsage(count << typeInfo.bytesShift);
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000229 }
230
Geoff Langc9e69b12014-09-08 16:06:25 -0400231 return gl::Error(GL_NO_ERROR);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000232}
233
Geoff Langc9e69b12014-09-08 16:06:25 -0400234gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer)
Geoff Lang1c134e62014-09-08 15:32:18 -0400235{
236 ASSERT(outBuffer);
237 if (destinationIndexType == GL_UNSIGNED_INT)
238 {
239 if (!mStreamingBufferInt)
240 {
Jamie Madillfd1bf4e2015-03-31 09:46:02 -0400241 mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory);
Geoff Langc9e69b12014-09-08 16:06:25 -0400242 gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
243 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400244 {
245 SafeDelete(mStreamingBufferInt);
Geoff Langc9e69b12014-09-08 16:06:25 -0400246 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400247 }
248 }
249
250 *outBuffer = mStreamingBufferInt;
Geoff Langc9e69b12014-09-08 16:06:25 -0400251 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400252 }
253 else
254 {
255 ASSERT(destinationIndexType == GL_UNSIGNED_SHORT);
256
257 if (!mStreamingBufferShort)
258 {
Jamie Madillfd1bf4e2015-03-31 09:46:02 -0400259 mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory);
Geoff Langc9e69b12014-09-08 16:06:25 -0400260 gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
261 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400262 {
263 SafeDelete(mStreamingBufferShort);
Geoff Langc9e69b12014-09-08 16:06:25 -0400264 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400265 }
266 }
267
268 *outBuffer = mStreamingBufferShort;
Geoff Langc9e69b12014-09-08 16:06:25 -0400269 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400270 }
271}
272
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000273}