blob: a8227a8f253da28c408af082c783ca95ef03da01 [file] [log] [blame]
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// geometry/IndexDataManager.cpp: Defines the IndexDataManager, a class that
8// runs the Buffer translation process for index buffers.
9
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000010#include "libGLESv2/geometry/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.combbf56f72010-04-20 18:52:13 +000016#include "libGLESv2/geometry/backend.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000017
18namespace
19{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000020 enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000021}
22
23namespace gl
24{
25
26IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend)
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000027 : mContext(context), mBackend(backend), mIntIndicesSupported(backend->supportIntIndices())
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000028{
daniel@transgaming.com81655a72010-05-20 19:18:17 +000029 mCountingBuffer = NULL;
30 mCountingBufferSize = 0;
31
32 mLineLoopBuffer = NULL;
33
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000034 mStreamBufferShort = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
35
36 if (mIntIndicesSupported)
37 {
38 mStreamBufferInt = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
39 }
40 else
41 {
42 mStreamBufferInt = NULL;
43 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000044}
45
46IndexDataManager::~IndexDataManager()
47{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000048 delete mStreamBufferShort;
49 delete mStreamBufferInt;
daniel@transgaming.com81655a72010-05-20 19:18:17 +000050 delete mCountingBuffer;
51 delete mLineLoopBuffer;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000052}
53
54namespace
55{
56
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000057template <class InputIndexType, class OutputIndexType>
58void copyIndices(const InputIndexType *in, GLsizei count, OutputIndexType *out, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000059{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000060 InputIndexType first = *in;
daniel@transgaming.combf2b52a2010-04-20 18:53:03 +000061 GLuint minIndexSoFar = first;
62 GLuint maxIndexSoFar = first;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000063
64 for (GLsizei i = 0; i < count; i++)
65 {
66 if (minIndexSoFar > *in) minIndexSoFar = *in;
67 if (maxIndexSoFar < *in) maxIndexSoFar = *in;
68
69 *out++ = *in++;
70 }
71
daniel@transgaming.combf2b52a2010-04-20 18:53:03 +000072 // It might be a line loop, so copy the loop index.
73 *out = first;
74
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000075 *minIndex = minIndexSoFar;
76 *maxIndex = maxIndexSoFar;
77}
78
79}
80
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000081GLenum IndexDataManager::preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000082{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000083 ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000084 ASSERT(count > 0);
85
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000086 if (arrayElementBuffer != NULL)
87 {
88 GLsizei offset = reinterpret_cast<GLsizei>(indices);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000089
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000090 if (typeSize(type) * count + offset > static_cast<std::size_t>(arrayElementBuffer->size()))
91 {
92 return GL_INVALID_OPERATION;
93 }
94
95 indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + offset;
96 }
97
98 translated->count = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000099
daniel@transgaming.combf2b52a2010-04-20 18:53:03 +0000100 std::size_t requiredSpace = spaceRequired(type, count);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000101
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000102 TranslatedIndexBuffer *streamIb = prepareIndexBuffer(type, requiredSpace);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000103
104 size_t offset;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000105 void *output = streamIb->map(requiredSpace, &offset);
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000106 if (output == NULL)
107 {
108 ERR(" failed to map index buffer.");
109 return GL_OUT_OF_MEMORY;
110 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000111
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000112 translated->buffer = streamIb;
113 translated->offset = offset;
114 translated->indexSize = indexSize(type);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000115
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000116 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000117 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000118 const GLubyte *in = static_cast<const GLubyte*>(indices);
119 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000120
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000121 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000122 }
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000123 else if (type == GL_UNSIGNED_INT)
124 {
125 const GLuint *in = static_cast<const GLuint*>(indices);
126
127 if (mIntIndicesSupported)
128 {
129 GLuint *out = static_cast<GLuint*>(output);
130
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000131 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000132 }
133 else
134 {
135 // When 32-bit indices are unsupported, fake them by truncating to 16-bit.
136
137 GLushort *out = static_cast<GLushort*>(output);
138
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000139 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000140 }
141 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000142 else
143 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000144 const GLushort *in = static_cast<const GLushort*>(indices);
145 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000146
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000147 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000148 }
149
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000150 streamIb->unmap();
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000151
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000152 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000153}
154
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000155std::size_t IndexDataManager::indexSize(GLenum type) const
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000156{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000157 return (type == GL_UNSIGNED_INT && mIntIndicesSupported) ? sizeof(GLuint) : sizeof(GLushort);
158}
159
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000160std::size_t IndexDataManager::typeSize(GLenum type) const
161{
162 switch (type)
163 {
164 case GL_UNSIGNED_INT: return sizeof(GLuint);
165 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
166 default: UNREACHABLE();
167 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
168 }
169}
170
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000171std::size_t IndexDataManager::spaceRequired(GLenum type, GLsizei count) const
172{
173 return (count + 1) * indexSize(type); // +1 because we always leave an extra for line loops
174}
175
176TranslatedIndexBuffer *IndexDataManager::prepareIndexBuffer(GLenum type, std::size_t requiredSpace)
177{
178 bool use32 = (type == GL_UNSIGNED_INT && mIntIndicesSupported);
179
180 TranslatedIndexBuffer *streamIb = use32 ? mStreamBufferInt : mStreamBufferShort;
181
182 if (requiredSpace > streamIb->size())
183 {
184 std::size_t newSize = std::max(requiredSpace, 2 * streamIb->size());
185
186 TranslatedIndexBuffer *newStreamBuffer = mBackend->createIndexBuffer(newSize, use32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT);
187
188 delete streamIb;
189
190 streamIb = newStreamBuffer;
191
192 if (use32)
193 {
194 mStreamBufferInt = streamIb;
195 }
196 else
197 {
198 mStreamBufferShort = streamIb;
199 }
200 }
201
202 streamIb->reserveSpace(requiredSpace);
203
204 return streamIb;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000205}
206
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000207GLenum IndexDataManager::preRenderValidateUnindexed(GLenum mode, GLsizei count, TranslatedIndexData *indexInfo)
208{
209 if (count >= 65535) return GL_OUT_OF_MEMORY;
210
211 if (mode == GL_LINE_LOOP)
212 {
213 // For line loops, create a single-use buffer that runs 0 - count-1, 0.
214 delete mLineLoopBuffer;
215 mLineLoopBuffer = mBackend->createIndexBuffer((count+1) * sizeof(unsigned short), GL_UNSIGNED_SHORT);
216
217 unsigned short *indices = static_cast<unsigned short *>(mLineLoopBuffer->map());
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000218 if (indices == NULL)
219 {
220 ERR(" failed to map index buffer.");
221 return GL_OUT_OF_MEMORY;
222 }
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000223
224 for (int i = 0; i < count; i++)
225 {
226 indices[i] = i;
227 }
228
229 indices[count] = 0;
230
231 mLineLoopBuffer->unmap();
232
233 indexInfo->buffer = mLineLoopBuffer;
234 indexInfo->count = count + 1;
235 indexInfo->maxIndex = count - 1;
236 }
237 else if (mCountingBufferSize < count)
238 {
239 mCountingBufferSize = std::max(static_cast<GLsizei>(ceilPow2(count)), mCountingBufferSize*2);
240
241 delete mCountingBuffer;
242 mCountingBuffer = mBackend->createIndexBuffer(count * sizeof(unsigned short), GL_UNSIGNED_SHORT);
243
244 unsigned short *indices = static_cast<unsigned short *>(mCountingBuffer->map());
apatrick@chromium.orgf99fbb72010-11-16 01:57:05 +0000245 if (indices == NULL)
246 {
247 ERR(" failed to map index buffer.");
248 return GL_OUT_OF_MEMORY;
249 }
daniel@transgaming.com81655a72010-05-20 19:18:17 +0000250
251 for (int i = 0; i < count; i++)
252 {
253 indices[i] = i;
254 }
255
256 mCountingBuffer->unmap();
257
258 indexInfo->buffer = mCountingBuffer;
259 indexInfo->count = count;
260 indexInfo->maxIndex = count - 1;
261 }
262 else
263 {
264 indexInfo->buffer = mCountingBuffer;
265 indexInfo->count = count;
266 indexInfo->maxIndex = count - 1;
267 }
268
269 indexInfo->indexSize = sizeof(unsigned short);
270 indexInfo->minIndex = 0;
271 indexInfo->offset = 0;
272
273 return GL_NO_ERROR;
274}
275
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000276}