blob: 1645f0b972be88a082413a9e5d7ebb296618446a [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"
15#include "libGLESv2/geometry/backend.h"
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000016
17namespace
18{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000019 enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000020}
21
22namespace gl
23{
24
25IndexDataManager::IndexDataManager(Context *context, BufferBackEnd *backend)
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000026 : mContext(context), mBackend(backend), mIntIndicesSupported(backend->supportIntIndices())
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000027{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000028 mStreamBufferShort = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT);
29
30 if (mIntIndicesSupported)
31 {
32 mStreamBufferInt = mBackend->createIndexBuffer(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT);
33 }
34 else
35 {
36 mStreamBufferInt = NULL;
37 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000038}
39
40IndexDataManager::~IndexDataManager()
41{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000042 delete mStreamBufferShort;
43 delete mStreamBufferInt;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000044}
45
46namespace
47{
48
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000049template <class InputIndexType, class OutputIndexType>
50void copyIndices(const InputIndexType *in, GLsizei count, OutputIndexType *out, GLuint *minIndex, GLuint *maxIndex)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000051{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000052 InputIndexType first = *in;
daniel@transgaming.combf2b52a2010-04-20 18:53:03 +000053 GLuint minIndexSoFar = first;
54 GLuint maxIndexSoFar = first;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000055
56 for (GLsizei i = 0; i < count; i++)
57 {
58 if (minIndexSoFar > *in) minIndexSoFar = *in;
59 if (maxIndexSoFar < *in) maxIndexSoFar = *in;
60
61 *out++ = *in++;
62 }
63
daniel@transgaming.combf2b52a2010-04-20 18:53:03 +000064 // It might be a line loop, so copy the loop index.
65 *out = first;
66
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000067 *minIndex = minIndexSoFar;
68 *maxIndex = maxIndexSoFar;
69}
70
71}
72
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000073GLenum IndexDataManager::preRenderValidate(GLenum mode, GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000074{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000075 ASSERT(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_INT);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000076 ASSERT(count > 0);
77
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000078 if (arrayElementBuffer != NULL)
79 {
80 GLsizei offset = reinterpret_cast<GLsizei>(indices);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000081
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000082 if (typeSize(type) * count + offset > static_cast<std::size_t>(arrayElementBuffer->size()))
83 {
84 return GL_INVALID_OPERATION;
85 }
86
87 indices = static_cast<const GLubyte*>(arrayElementBuffer->data()) + offset;
88 }
89
90 translated->count = count;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000091
daniel@transgaming.combf2b52a2010-04-20 18:53:03 +000092 std::size_t requiredSpace = spaceRequired(type, count);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000093
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000094 TranslatedIndexBuffer *streamIb = prepareIndexBuffer(type, requiredSpace);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000095
96 size_t offset;
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +000097 void *output = streamIb->map(requiredSpace, &offset);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +000098
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +000099 translated->buffer = streamIb;
100 translated->offset = offset;
101 translated->indexSize = indexSize(type);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000102
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000103 translated->indices = output;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000104
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000105 if (type == GL_UNSIGNED_BYTE)
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000106 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000107 const GLubyte *in = static_cast<const GLubyte*>(indices);
108 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000109
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000110 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000111 }
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000112 else if (type == GL_UNSIGNED_INT)
113 {
114 const GLuint *in = static_cast<const GLuint*>(indices);
115
116 if (mIntIndicesSupported)
117 {
118 GLuint *out = static_cast<GLuint*>(output);
119
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000120 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000121 }
122 else
123 {
124 // When 32-bit indices are unsupported, fake them by truncating to 16-bit.
125
126 GLushort *out = static_cast<GLushort*>(output);
127
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000128 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000129 }
130 }
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000131 else
132 {
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000133 const GLushort *in = static_cast<const GLushort*>(indices);
134 GLushort *out = static_cast<GLushort*>(output);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000135
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000136 copyIndices(in, count, out, &translated->minIndex, &translated->maxIndex);
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000137 }
138
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000139 streamIb->unmap();
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000140
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000141 return GL_NO_ERROR;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000142}
143
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000144std::size_t IndexDataManager::indexSize(GLenum type) const
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000145{
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000146 return (type == GL_UNSIGNED_INT && mIntIndicesSupported) ? sizeof(GLuint) : sizeof(GLushort);
147}
148
daniel@transgaming.com41d8dd82010-05-12 03:45:03 +0000149std::size_t IndexDataManager::typeSize(GLenum type) const
150{
151 switch (type)
152 {
153 case GL_UNSIGNED_INT: return sizeof(GLuint);
154 case GL_UNSIGNED_SHORT: return sizeof(GLushort);
155 default: UNREACHABLE();
156 case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
157 }
158}
159
daniel@transgaming.com3e4c6002010-05-05 18:50:13 +0000160std::size_t IndexDataManager::spaceRequired(GLenum type, GLsizei count) const
161{
162 return (count + 1) * indexSize(type); // +1 because we always leave an extra for line loops
163}
164
165TranslatedIndexBuffer *IndexDataManager::prepareIndexBuffer(GLenum type, std::size_t requiredSpace)
166{
167 bool use32 = (type == GL_UNSIGNED_INT && mIntIndicesSupported);
168
169 TranslatedIndexBuffer *streamIb = use32 ? mStreamBufferInt : mStreamBufferShort;
170
171 if (requiredSpace > streamIb->size())
172 {
173 std::size_t newSize = std::max(requiredSpace, 2 * streamIb->size());
174
175 TranslatedIndexBuffer *newStreamBuffer = mBackend->createIndexBuffer(newSize, use32 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT);
176
177 delete streamIb;
178
179 streamIb = newStreamBuffer;
180
181 if (use32)
182 {
183 mStreamBufferInt = streamIb;
184 }
185 else
186 {
187 mStreamBufferShort = streamIb;
188 }
189 }
190
191 streamIb->reserveSpace(requiredSpace);
192
193 return streamIb;
daniel@transgaming.comf8b58a02010-03-26 04:08:45 +0000194}
195
196}