blob: 4a0291921f48a895be378bbd909fb06eb52d22e3 [file] [log] [blame]
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00001//
daniel@transgaming.comf6549452012-01-27 15:39:08 +00002// Copyright (c) 2002-2012 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
daniel@transgaming.com50aadb02012-11-28 21:06:11 +000010#include "libGLESv2/renderer/IndexDataManager.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000011
12#include "common/debug.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000013
14#include "libGLESv2/Buffer.h"
daniel@transgaming.com81655a72010-05-20 19:18:17 +000015#include "libGLESv2/mathutil.h"
daniel@transgaming.com37b141e2011-01-08 05:46:13 +000016#include "libGLESv2/main.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
daniel@transgaming.com76d3e6e2012-10-31 19:55:33 +000021IndexDataManager::IndexDataManager(rx::Renderer9 *renderer) : mRenderer(renderer)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000022{
daniel@transgaming.com50cc7252012-12-20 21:09:23 +000023 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
daniel@transgaming.com81655a72010-05-20 19:18:17 +000024
daniel@transgaming.com408caa52012-10-31 18:47:01 +000025 if (renderer->get32BitIndexSupport())
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000026 {
daniel@transgaming.com50cc7252012-12-20 21:09:23 +000027 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000028
29 if (!mStreamingBufferInt)
30 {
31 // Don't leave it in a half-initialized state
32 delete mStreamingBufferShort;
33 mStreamingBufferShort = NULL;
34 }
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000035 }
36 else
37 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000038 mStreamingBufferInt = NULL;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000039 }
daniel@transgaming.com72b9e182011-04-13 14:58:33 +000040
41 if (!mStreamingBufferShort)
42 {
43 ERR("Failed to allocate the streaming index buffer(s).");
44 }
daniel@transgaming.comf6549452012-01-27 15:39:08 +000045
46 mCountingBuffer = NULL;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000047}
48
49IndexDataManager::~IndexDataManager()
50{
daniel@transgaming.com83921382011-01-08 05:46:00 +000051 delete mStreamingBufferShort;
52 delete mStreamingBufferInt;
daniel@transgaming.comf6549452012-01-27 15:39:08 +000053 delete mCountingBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000054}
55
daniel@transgaming.com83921382011-01-08 05:46:00 +000056void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000057{
daniel@transgaming.com83921382011-01-08 05:46:00 +000058 if (type == GL_UNSIGNED_BYTE)
59 {
60 const GLubyte *in = static_cast<const GLubyte*>(input);
61 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000062
daniel@transgaming.com83921382011-01-08 05:46:00 +000063 for (GLsizei i = 0; i < count; i++)
64 {
65 out[i] = in[i];
66 }
67 }
68 else if (type == GL_UNSIGNED_INT)
69 {
70 memcpy(output, input, count * sizeof(GLuint));
71 }
72 else if (type == GL_UNSIGNED_SHORT)
73 {
74 memcpy(output, input, count * sizeof(GLushort));
75 }
76 else UNREACHABLE();
77}
78
79template <class IndexType>
80void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000081{
daniel@transgaming.com83921382011-01-08 05:46:00 +000082 *minIndex = indices[0];
83 *maxIndex = indices[0];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000084
85 for (GLsizei i = 0; i < count; i++)
86 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000087 if (*minIndex > indices[i]) *minIndex = indices[i];
88 if (*maxIndex < indices[i]) *maxIndex = indices[i];
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000089 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000090}
91
daniel@transgaming.comd2820bf2012-01-27 15:38:48 +000092void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000093{
daniel@transgaming.com83921382011-01-08 05:46:00 +000094 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000095 {
daniel@transgaming.com83921382011-01-08 05:46:00 +000096 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
97 }
98 else if (type == GL_UNSIGNED_INT)
99 {
100 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
101 }
102 else if (type == GL_UNSIGNED_SHORT)
103 {
104 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
105 }
106 else UNREACHABLE();
107}
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000108
daniel@transgaming.com31240482012-11-28 21:06:41 +0000109GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated, IDirect3DIndexBuffer9 **d3dIndexBuffer, unsigned int *serial)
daniel@transgaming.com83921382011-01-08 05:46:00 +0000110{
daniel@transgaming.com72b9e182011-04-13 14:58:33 +0000111 if (!mStreamingBufferShort)
112 {
113 return GL_OUT_OF_MEMORY;
114 }
115
daniel@transgaming.com83921382011-01-08 05:46:00 +0000116 D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
117 intptr_t offset = reinterpret_cast<intptr_t>(indices);
118 bool alignedOffset = false;
119
120 if (buffer != NULL)
121 {
122 switch (type)
123 {
124 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
125 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
126 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
127 default: UNREACHABLE(); alignedOffset = false;
128 }
129
130 if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000131 {
132 return GL_INVALID_OPERATION;
133 }
134
daniel@transgaming.com83921382011-01-08 05:46:00 +0000135 indices = static_cast<const GLubyte*>(buffer->data()) + offset;
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000136 }
137
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000138 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000139
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000140 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
141 IndexBufferInterface *indexBuffer = streamingBuffer;
daniel@transgaming.com83921382011-01-08 05:46:00 +0000142 UINT streamOffset = 0;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000143
daniel@transgaming.com83921382011-01-08 05:46:00 +0000144 if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000145 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000146 indexBuffer = staticBuffer;
147 streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000148
daniel@transgaming.com83921382011-01-08 05:46:00 +0000149 if (streamOffset == -1)
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000150 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000151 streamOffset = (offset / typeSize(type)) * indexSize(format);
152 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
153 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000154 }
155 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000156 else
157 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000158 int convertCount = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000159
daniel@transgaming.com83921382011-01-08 05:46:00 +0000160 if (staticBuffer)
161 {
162 if (staticBuffer->size() == 0 && alignedOffset)
163 {
164 indexBuffer = staticBuffer;
165 convertCount = buffer->size() / typeSize(type);
166 }
167 else
168 {
169 buffer->invalidateStaticData();
170 staticBuffer = NULL;
171 }
172 }
173
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000174 void *output = NULL;
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000175
daniel@transgaming.com5ee2ad02011-01-08 05:46:20 +0000176 if (indexBuffer)
177 {
178 indexBuffer->reserveSpace(convertCount * indexSize(format), type);
179 output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
180 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000181
daniel@transgaming.com83921382011-01-08 05:46:00 +0000182 if (output == NULL)
183 {
184 ERR("Failed to map index buffer.");
185 return GL_OUT_OF_MEMORY;
186 }
187
188 convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
189 indexBuffer->unmap();
190
191 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
192
193 if (staticBuffer)
194 {
195 streamOffset = (offset / typeSize(type)) * indexSize(format);
196 staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
197 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000198 }
199
daniel@transgaming.com91207b72012-11-28 20:56:43 +0000200 *d3dIndexBuffer = indexBuffer->getBuffer();
201 *serial = indexBuffer->getSerial();
daniel@transgaming.com83921382011-01-08 05:46:00 +0000202 translated->startIndex = streamOffset / indexSize(format);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000203
daniel@transgaming.com78624ca2011-04-22 04:17:57 +0000204 if (buffer)
205 {
206 buffer->promoteStaticUsage(count * typeSize(type));
207 }
208
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000209 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000210}
211
daniel@transgaming.com83921382011-01-08 05:46:00 +0000212std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000213{
daniel@transgaming.com83921382011-01-08 05:46:00 +0000214 return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000215}
216
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000217std::size_t IndexDataManager::typeSize(GLenum type) const
218{
219 switch (type)
220 {
daniel@transgaming.com83921382011-01-08 05:46:00 +0000221 case GL_UNSIGNED_INT: return sizeof(GLuint);
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000222 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
daniel@transgaming.com83921382011-01-08 05:46:00 +0000223 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
224 default: UNREACHABLE(); return sizeof(GLushort);
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000225 }
226}
227
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000228StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000229{
daniel@transgaming.com0f328a72012-03-05 15:07:50 +0000230 if (count <= 65536) // 16-bit indices
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000231 {
232 const unsigned int spaceNeeded = count * sizeof(unsigned short);
233
234 if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
235 {
236 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000237 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000238 mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
239
240 UINT offset;
241 unsigned short *data = static_cast<unsigned short*>(mCountingBuffer->map(spaceNeeded, &offset));
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000242
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000243 if (data)
244 {
245 for(int i = 0; i < count; i++)
246 {
247 data[i] = i;
248 }
249
250 mCountingBuffer->unmap();
251 }
252 }
253 }
254 else if (mStreamingBufferInt) // 32-bit indices supported
255 {
256 const unsigned int spaceNeeded = count * sizeof(unsigned int);
257
258 if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
259 {
260 delete mCountingBuffer;
daniel@transgaming.com50cc7252012-12-20 21:09:23 +0000261 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000262 mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
263
264 UINT offset;
265 unsigned int *data = static_cast<unsigned int*>(mCountingBuffer->map(spaceNeeded, &offset));
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000266
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000267 if (data)
268 {
269 for(int i = 0; i < count; i++)
270 {
271 data[i] = i;
272 }
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000273
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000274 mCountingBuffer->unmap();
275 }
276 }
277 }
278 else return NULL;
daniel@transgaming.com50aadb02012-11-28 21:06:11 +0000279
daniel@transgaming.comf6549452012-01-27 15:39:08 +0000280 return mCountingBuffer;
281}
282
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000283}