blob: 206ef39442658cee5a30d3bbefa0e9dd02f24f97 [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)
Geoff Lang1c134e62014-09-08 15:32:18 -040061 : mRenderer(renderer),
62 mStreamingBufferShort(NULL),
63 mStreamingBufferInt(NULL)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000064{
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000065}
66
Jamie Madill2b976812014-08-25 15:47:49 -040067IndexDataManager::~IndexDataManager()
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000068{
Jamie Madill2b976812014-08-25 15:47:49 -040069 SafeDelete(mStreamingBufferShort);
70 SafeDelete(mStreamingBufferInt);
daniel@transgaming.com83921382011-01-08 05:46:00 +000071}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000072
Geoff Langc9e69b12014-09-08 16:06:25 -040073gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
daniel@transgaming.com83921382011-01-08 05:46:00 +000074{
Geoff Lang5d601382014-07-22 15:14:06 -040075 const gl::Type &typeInfo = gl::GetTypeInfo(type);
76
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +000077 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
Geoff Lang5d601382014-07-22 15:14:06 -040078
Geoff Langb23fc092013-08-06 10:43:14 -040079 unsigned int offset = 0;
daniel@transgaming.com83921382011-01-08 05:46:00 +000080 bool alignedOffset = false;
81
Brandon Jonesd38f9262014-06-18 16:26:45 -070082 BufferD3D *storage = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +000083
daniel@transgaming.com83921382011-01-08 05:46:00 +000084 if (buffer != NULL)
85 {
Geoff Langb23fc092013-08-06 10:43:14 -040086 offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
87
Brandon Jonesd38f9262014-06-18 16:26:45 -070088 storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
shannon.woods@transgaming.com76655412013-02-28 23:08:09 +000089
daniel@transgaming.com83921382011-01-08 05:46:00 +000090 switch (type)
91 {
92 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
93 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
94 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
95 default: UNREACHABLE(); alignedOffset = false;
96 }
97
Jamie Madillae3000b2014-08-25 15:47:51 -040098 ASSERT(typeInfo.bytes * static_cast<unsigned int>(count) + offset <= storage->getSize());
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000099
Geoff Langc8d297a2014-09-19 11:09:08 -0400100 const uint8_t *bufferData = NULL;
101 gl::Error error = storage->getData(&bufferData);
102 if (error.isError())
103 {
104 return error;
105 }
106
107 indices = bufferData + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000108 }
109
Brandon Jonesd38f9262014-06-18 16:26:45 -0700110 StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400111 IndexBufferInterface *indexBuffer = NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000112 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
113 destinationIndexType == type;
Geoff Langa36ead42013-08-02 11:54:08 -0400114 unsigned int streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000115
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000116 if (directStorage)
117 {
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000118 streamOffset = offset;
Geoff Langf23eb282013-07-22 10:52:19 -0400119
Jamie Madill2b976812014-08-25 15:47:49 -0400120 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, NULL, NULL))
Geoff Langf23eb282013-07-22 10:52:19 -0400121 {
Jamie Madillef9d63e2014-08-04 10:48:02 -0400122 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, offset);
Geoff Langf23eb282013-07-22 10:52:19 -0400123 }
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000124 }
shannon.woods@transgaming.com38e87882013-02-28 23:18:32 +0000125 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000126 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000127 indexBuffer = staticBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000128
Jamie Madill2b976812014-08-25 15:47:49 -0400129 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, NULL, &streamOffset))
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000130 {
Geoff Lang5d601382014-07-22 15:14:06 -0400131 streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400132 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000133 }
134 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400135
136 // Avoid D3D11's primitive restart index value
137 // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
Jamie Madill39b43462014-08-18 16:39:50 -0400138 if (translated->indexRange.end == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400139 {
140 destinationIndexType = GL_UNSIGNED_INT;
141 directStorage = false;
142 indexBuffer = NULL;
143 }
144
Geoff Lang5d601382014-07-22 15:14:06 -0400145 const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
146
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400147 if (!directStorage && !indexBuffer)
148 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400149 gl::Error error = getStreamingIndexBuffer(destinationIndexType, &indexBuffer);
150 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400151 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400152 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400153 }
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400154
Geoff Langa36ead42013-08-02 11:54:08 -0400155 unsigned int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000156
daniel@transgaming.com83921382011-01-08 05:46:00 +0000157 if (staticBuffer)
158 {
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000159 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000160 {
161 indexBuffer = staticBuffer;
Geoff Lang5d601382014-07-22 15:14:06 -0400162 convertCount = storage->getSize() / typeInfo.bytes;
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
Geoff Lang5d601382014-07-22 15:14:06 -0400173 if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
Geoff Langa36ead42013-08-02 11:54:08 -0400174 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400175 return gl::Error(GL_OUT_OF_MEMORY, "Reserving %u indices of %u bytes each exceeds the maximum buffer size.",
176 convertCount, destTypeInfo.bytes);
Geoff Langa36ead42013-08-02 11:54:08 -0400177 }
178
Geoff Lang5d601382014-07-22 15:14:06 -0400179 unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
Geoff Langc9e69b12014-09-08 16:06:25 -0400180 error = indexBuffer->reserveBufferSpace(bufferSizeRequired, type);
181 if (error.isError())
Geoff Langa36ead42013-08-02 11:54:08 -0400182 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400183 return error;
Geoff Langa36ead42013-08-02 11:54:08 -0400184 }
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000185
186 void* output = NULL;
Geoff Langc9e69b12014-09-08 16:06:25 -0400187 error = indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset);
188 if (error.isError())
daniel@transgaming.com83921382011-01-08 05:46:00 +0000189 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400190 return error;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000191 }
192
Geoff Langc8d297a2014-09-19 11:09:08 -0400193 const uint8_t *dataPointer = reinterpret_cast<const uint8_t*>(indices);
194 if (staticBuffer)
195 {
196 error = storage->getData(&dataPointer);
197 if (error.isError())
198 {
199 return error;
200 }
201 }
202 ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output);
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000203
Geoff Langc9e69b12014-09-08 16:06:25 -0400204 error = indexBuffer->unmapBuffer();
205 if (error.isError())
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000206 {
Geoff Langc9e69b12014-09-08 16:06:25 -0400207 return error;
daniel@transgaming.com1e3a8042012-12-20 21:09:55 +0000208 }
daniel@transgaming.com83921382011-01-08 05:46:00 +0000209
daniel@transgaming.com83921382011-01-08 05:46:00 +0000210 if (staticBuffer)
211 {
Geoff Lang5d601382014-07-22 15:14:06 -0400212 streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
Jamie Madill39b43462014-08-18 16:39:50 -0400213 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->indexRange, streamOffset);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000214 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000215 }
216
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000217 translated->storage = directStorage ? storage : NULL;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400218 translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
shannon.woods@transgaming.coma1229a32013-02-28 23:08:40 +0000219 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
Geoff Lang5d601382014-07-22 15:14:06 -0400220 translated->startIndex = streamOffset / destTypeInfo.bytes;
daniel@transgaming.com22ada2c2013-01-11 04:07:12 +0000221 translated->startOffset = streamOffset;
Nicolas Capens8d62bcc2014-07-25 15:08:21 -0400222 translated->indexType = destinationIndexType;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000223
Brandon Jonesd38f9262014-06-18 16:26:45 -0700224 if (storage)
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000225 {
Geoff Lang5d601382014-07-22 15:14:06 -0400226 storage->promoteStaticUsage(count * typeInfo.bytes);
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000227 }
228
Geoff Langc9e69b12014-09-08 16:06:25 -0400229 return gl::Error(GL_NO_ERROR);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000230}
231
Geoff Langc9e69b12014-09-08 16:06:25 -0400232gl::Error IndexDataManager::getStreamingIndexBuffer(GLenum destinationIndexType, IndexBufferInterface **outBuffer)
Geoff Lang1c134e62014-09-08 15:32:18 -0400233{
234 ASSERT(outBuffer);
235 if (destinationIndexType == GL_UNSIGNED_INT)
236 {
237 if (!mStreamingBufferInt)
238 {
239 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
Geoff Langc9e69b12014-09-08 16:06:25 -0400240 gl::Error error = mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
241 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400242 {
243 SafeDelete(mStreamingBufferInt);
Geoff Langc9e69b12014-09-08 16:06:25 -0400244 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400245 }
246 }
247
248 *outBuffer = mStreamingBufferInt;
Geoff Langc9e69b12014-09-08 16:06:25 -0400249 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400250 }
251 else
252 {
253 ASSERT(destinationIndexType == GL_UNSIGNED_SHORT);
254
255 if (!mStreamingBufferShort)
256 {
257 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
Geoff Langc9e69b12014-09-08 16:06:25 -0400258 gl::Error error = mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
259 if (error.isError())
Geoff Lang1c134e62014-09-08 15:32:18 -0400260 {
261 SafeDelete(mStreamingBufferShort);
Geoff Langc9e69b12014-09-08 16:06:25 -0400262 return error;
Geoff Lang1c134e62014-09-08 15:32:18 -0400263 }
264 }
265
266 *outBuffer = mStreamingBufferShort;
Geoff Langc9e69b12014-09-08 16:06:25 -0400267 return gl::Error(GL_NO_ERROR);
Geoff Lang1c134e62014-09-08 15:32:18 -0400268 }
269}
270
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000271}