blob: 5328a03c26d5bd9f5a6e3d26ceda3abed4c7657a [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"
Corentin Wallez2e62a9a2015-07-03 14:13:50 -070011
Geoff Lang2b5420c2014-11-19 14:20:15 -050012#include "libANGLE/renderer/d3d/BufferD3D.h"
13#include "libANGLE/renderer/d3d/IndexBuffer.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050014#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
Corentin Wallez2e62a9a2015-07-03 14:13:50 -070020static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void *input,
21 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
Corentin Wallez2e62a9a2015-07-03 14:13:50 -070060static gl::Error StreamInIndexBuffer(IndexBufferInterface *buffer, const GLvoid *data,
61 unsigned int count, GLenum srcType, GLenum dstType,
62 unsigned int *offset)
63{
64 const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
65
66 if (count > (std::numeric_limits<unsigned int>::max() >> dstTypeInfo.bytesShift))
67 {
68 return gl::Error(GL_OUT_OF_MEMORY,
69 "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
70 count, dstTypeInfo.bytes);
71 }
72
73 unsigned int bufferSizeRequired = count << dstTypeInfo.bytesShift;
74 gl::Error error = buffer->reserveBufferSpace(bufferSizeRequired, dstType);
75 if (error.isError())
76 {
77 return error;
78 }
79
80 void *output = nullptr;
81 error = buffer->mapBuffer(bufferSizeRequired, &output, offset);
82 if (error.isError())
83 {
84 return error;
85 }
86
87 ConvertIndices(srcType, dstType, data, count, output);
88
89 error = buffer->unmapBuffer();
90 if (error.isError())
91 {
92 return error;
93 }
94
95 return gl::Error(GL_NO_ERROR);
96}
97
Jamie Madillfd1bf4e2015-03-31 09:46:02 -040098IndexDataManager::IndexDataManager(BufferFactoryD3D *factory, RendererClass rendererClass)
99 : mFactory(factory),
100 mRendererClass(rendererClass),
101 mStreamingBufferShort(nullptr),
102 mStreamingBufferInt(nullptr)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000103{
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000104}
105
Jamie Madill2b976812014-08-25 15:47:49 -0400106IndexDataManager::~IndexDataManager()
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000107{
Jamie Madill2b976812014-08-25 15:47:49 -0400108 SafeDelete(mStreamingBufferShort);
109 SafeDelete(mStreamingBufferInt);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000110}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000111
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700112// This function translates a GL-style indices into DX-style indices, with their description
113// returned in translated.
114// GL can specify vertex data in immediate mode (pointer to CPU array of indices), which is not
115// possible in DX and requires streaming (Case 1). If the GL indices are specified with a buffer
116// (Case 2), in a format supported by DX (subcase a) then all is good.
117// When we have a buffer with an unsupported format (subcase b) then we need to do some translation:
118// we will start by falling back to streaming, and after a while will start using a static translated
119// copy of the index buffer.
120gl::Error IndexDataManager::prepareIndexData(GLenum srcType, GLsizei count, gl::Buffer *glBuffer,
121 const GLvoid *indices, TranslatedIndexData *translated,
122 SourceIndexData *sourceData)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000123{
Jamie Madillb48e8b02015-04-15 14:26:37 -0400124 // Avoid D3D11's primitive restart index value
125 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
126 bool primitiveRestartWorkaround = mRendererClass == RENDERER_D3D11 &&
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700127 translated->indexRange.end == 0xFFFF &&
128 srcType == GL_UNSIGNED_SHORT;
Jamie Madillb48e8b02015-04-15 14:26:37 -0400129
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700130 const GLenum dstType = (srcType == GL_UNSIGNED_INT || primitiveRestartWorkaround) ?
131 GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
132
133 const gl::Type &srcTypeInfo = gl::GetTypeInfo(srcType);
134 const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
135
Corentin Wallezbc3b5e62015-07-07 10:08:05 -0700136 BufferD3D *buffer = glBuffer ? GetImplAs<BufferD3D>(glBuffer) : nullptr;
137
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700138 translated->indexType = dstType;
139 if (sourceData)
Jamie Madillb48e8b02015-04-15 14:26:37 -0400140 {
Corentin Wallezbc3b5e62015-07-07 10:08:05 -0700141 sourceData->srcBuffer = buffer;
142 sourceData->srcIndices = indices;
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700143 sourceData->srcIndexType = srcType;
144 sourceData->srcCount = count;
Jamie Madillb48e8b02015-04-15 14:26:37 -0400145 }
146
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700147 // Case 1: the indices are passed by pointer, which forces the streaming of index data
148 if (glBuffer == nullptr)
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000149 {
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700150 translated->storage = nullptr;
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700151 return streamIndexData(indices, count, srcType, dstType, translated);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000152 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400153
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700154 // Case 2: the indices are already in a buffer
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700155 unsigned int offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
156 ASSERT(srcTypeInfo.bytes * static_cast<unsigned int>(count) + offset <= buffer->getSize());
157
158 bool offsetAligned;
159 switch (srcType)
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400160 {
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700161 case GL_UNSIGNED_BYTE: offsetAligned = (offset % sizeof(GLubyte) == 0); break;
162 case GL_UNSIGNED_SHORT: offsetAligned = (offset % sizeof(GLushort) == 0); break;
163 case GL_UNSIGNED_INT: offsetAligned = (offset % sizeof(GLuint) == 0); break;
164 default: UNREACHABLE(); offsetAligned = false;
165 }
166
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700167 // Case 2a: the buffer can be used directly
168 if (offsetAligned && buffer->supportsDirectBinding() &&
169 dstType == srcType && !primitiveRestartWorkaround)
170 {
171 translated->storage = buffer;
172 translated->indexBuffer = nullptr;
173 translated->serial = buffer->getSerial();
174 translated->startIndex = (offset >> srcTypeInfo.bytesShift);
175 translated->startOffset = offset;
176 buffer->promoteStaticUsage(count << srcTypeInfo.bytesShift);
177 return gl::Error(GL_NO_ERROR);
178 }
179 else
180 {
181 translated->storage = nullptr;
182 }
183
184 // Case 2b: use a static translated copy or fall back to streaming
185 StaticIndexBufferInterface *staticBuffer = buffer->getStaticIndexBuffer();
186
187 bool staticBufferInitialized = staticBuffer && staticBuffer->getBufferSize() != 0;
188 bool staticBufferUsable = staticBuffer &&
189 offsetAligned && staticBuffer->getIndexType() == dstType;
190
191 if (staticBufferInitialized && !staticBufferUsable)
192 {
193 buffer->invalidateStaticData();
194 staticBuffer = nullptr;
195 }
196
197 if (staticBuffer == nullptr || !offsetAligned)
198 {
Corentin Wallezbc3b5e62015-07-07 10:08:05 -0700199 const uint8_t *bufferData = nullptr;
200 gl::Error error = buffer->getData(&bufferData);
201 if (error.isError())
202 {
203 return error;
204 }
205 ASSERT(bufferData != nullptr);
206
207 error = streamIndexData(bufferData, count, srcType, dstType, translated);
Geoff Langc9e69b12014-09-08 16:06:25 -0400208 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400209 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400210 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400211 }
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700212 }
213 else
214 {
215 if (!staticBufferInitialized)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000216 {
Corentin Wallezbc3b5e62015-07-07 10:08:05 -0700217 const uint8_t *bufferData = nullptr;
218 gl::Error error = buffer->getData(&bufferData);
219 if (error.isError())
220 {
221 return error;
222 }
223 ASSERT(bufferData != nullptr);
224
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700225 unsigned int convertCount = buffer->getSize() >> srcTypeInfo.bytesShift;
Corentin Wallezbc3b5e62015-07-07 10:08:05 -0700226 error = StreamInIndexBuffer(staticBuffer, bufferData, convertCount,
227 srcType, dstType, nullptr);
Geoff Langc8d297a2014-09-19 11:09:08 -0400228 if (error.isError())
229 {
230 return error;
231 }
232 }
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700233 ASSERT(offsetAligned && staticBuffer->getIndexType() == dstType);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000234
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700235 translated->indexBuffer = staticBuffer->getIndexBuffer();
236 translated->serial = staticBuffer->getSerial();
237 translated->startIndex = (offset >> srcTypeInfo.bytesShift);
238 translated->startOffset = (offset >> srcTypeInfo.bytesShift) << dstTypeInfo.bytesShift;
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000239 }
240
Geoff Langc9e69b12014-09-08 16:06:25 -0400241 return gl::Error(GL_NO_ERROR);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000242}
243
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700244gl::Error IndexDataManager::streamIndexData(const GLvoid *data, unsigned int count, GLenum srcType,
245 GLenum dstType, TranslatedIndexData *translated)
246{
247 const gl::Type &dstTypeInfo = gl::GetTypeInfo(dstType);
248
249 IndexBufferInterface *indexBuffer = nullptr;
250 gl::Error error = getStreamingIndexBuffer(dstType, &indexBuffer);
251 if (error.isError())
252 {
253 return error;
254 }
255 ASSERT(indexBuffer != nullptr);
256
257 unsigned int offset;
258 StreamInIndexBuffer(indexBuffer, data, count, srcType, dstType, &offset);
259
260 translated->indexBuffer = indexBuffer->getIndexBuffer();
261 translated->serial = indexBuffer->getSerial();
262 translated->startIndex = (offset >> dstTypeInfo.bytesShift);
263 translated->startOffset = offset;
264
265 return gl::Error(GL_NO_ERROR);
266}
267
268gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType,
269 IndexBufferInterface **outBuffer)
Geoff Lang1c134e62014-09-08 15:32:18 -0400270{
271 ASSERT(outBuffer);
272 if (destinationIndexType == GL_UNSIGNED_INT)
273 {
274 if (!mStreamingBufferInt)
275 {
Jamie Madillfd1bf4e2015-03-31 09:46:02 -0400276 mStreamingBufferInt = new StreamingIndexBufferInterface(mFactory);
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700277 gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE,
278 GL_UNSIGNED_INT);
Geoff Langc9e69b12014-09-08 16:06:25 -0400279 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400280 {
281 SafeDelete(mStreamingBufferInt);
Geoff Langc9e69b12014-09-08 16:06:25 -0400282 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400283 }
284 }
285
286 *outBuffer = mStreamingBufferInt;
Geoff Langc9e69b12014-09-08 16:06:25 -0400287 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400288 }
289 else
290 {
291 ASSERT(destinationIndexType == GL_UNSIGNED_SHORT);
292
293 if (!mStreamingBufferShort)
294 {
Jamie Madillfd1bf4e2015-03-31 09:46:02 -0400295 mStreamingBufferShort = new StreamingIndexBufferInterface(mFactory);
Corentin Wallez2e62a9a2015-07-03 14:13:50 -0700296 gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE,
297 GL_UNSIGNED_SHORT);
Geoff Langc9e69b12014-09-08 16:06:25 -0400298 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400299 {
300 SafeDelete(mStreamingBufferShort);
Geoff Langc9e69b12014-09-08 16:06:25 -0400301 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400302 }
303 }
304
305 *outBuffer = mStreamingBufferShort;
Geoff Langc9e69b12014-09-08 16:06:25 -0400306 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400307 }
308}
309
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000310}