gfx/angle/src/libGLESv2/renderer/IndexDataManager.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:0cbbfa1cfd30
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 //
7
8 // IndexDataManager.cpp: Defines the IndexDataManager, a class that
9 // runs the Buffer translation process for index buffers.
10
11 #include "libGLESv2/renderer/IndexDataManager.h"
12 #include "libGLESv2/renderer/BufferStorage.h"
13
14 #include "libGLESv2/Buffer.h"
15 #include "libGLESv2/main.h"
16 #include "libGLESv2/utilities.h"
17 #include "libGLESv2/renderer/IndexBuffer.h"
18
19 namespace rx
20 {
21
22 IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
23 {
24 mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
25 if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
26 {
27 delete mStreamingBufferShort;
28 mStreamingBufferShort = NULL;
29 }
30
31 mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
32 if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
33 {
34 delete mStreamingBufferInt;
35 mStreamingBufferInt = NULL;
36 }
37
38 if (!mStreamingBufferShort)
39 {
40 // Make sure both buffers are deleted.
41 delete mStreamingBufferInt;
42 mStreamingBufferInt = NULL;
43
44 ERR("Failed to allocate the streaming index buffer(s).");
45 }
46
47 mCountingBuffer = NULL;
48 }
49
50 IndexDataManager::~IndexDataManager()
51 {
52 delete mStreamingBufferShort;
53 delete mStreamingBufferInt;
54 delete mCountingBuffer;
55 }
56
57 static void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
58 {
59 if (type == GL_UNSIGNED_BYTE)
60 {
61 const GLubyte *in = static_cast<const GLubyte*>(input);
62 GLushort *out = static_cast<GLushort*>(output);
63
64 for (GLsizei i = 0; i < count; i++)
65 {
66 out[i] = in[i];
67 }
68 }
69 else if (type == GL_UNSIGNED_INT)
70 {
71 memcpy(output, input, count * sizeof(GLuint));
72 }
73 else if (type == GL_UNSIGNED_SHORT)
74 {
75 memcpy(output, input, count * sizeof(GLushort));
76 }
77 else UNREACHABLE();
78 }
79
80 template <class IndexType>
81 static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
82 {
83 *minIndex = indices[0];
84 *maxIndex = indices[0];
85
86 for (GLsizei i = 0; i < count; i++)
87 {
88 if (*minIndex > indices[i]) *minIndex = indices[i];
89 if (*maxIndex < indices[i]) *maxIndex = indices[i];
90 }
91 }
92
93 static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
94 {
95 if (type == GL_UNSIGNED_BYTE)
96 {
97 computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
98 }
99 else if (type == GL_UNSIGNED_INT)
100 {
101 computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
102 }
103 else if (type == GL_UNSIGNED_SHORT)
104 {
105 computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
106 }
107 else UNREACHABLE();
108 }
109
110 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
111 {
112 if (!mStreamingBufferShort)
113 {
114 return GL_OUT_OF_MEMORY;
115 }
116
117 GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
118 intptr_t offset = reinterpret_cast<intptr_t>(indices);
119 bool alignedOffset = false;
120
121 BufferStorage *storage = NULL;
122
123 if (buffer != NULL)
124 {
125 storage = buffer->getStorage();
126
127 switch (type)
128 {
129 case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
130 case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
131 case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
132 default: UNREACHABLE(); alignedOffset = false;
133 }
134
135 unsigned int typeSize = gl::ComputeTypeSize(type);
136
137 // check for integer overflows and underflows
138 if (static_cast<unsigned int>(offset) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
139 static_cast<unsigned int>(count) > ((std::numeric_limits<unsigned int>::max() / typeSize) - offset))
140 {
141 return GL_OUT_OF_MEMORY;
142 }
143
144 if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
145 {
146 return GL_INVALID_OPERATION;
147 }
148
149 indices = static_cast<const GLubyte*>(storage->getData()) + offset;
150 }
151
152 StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
153
154 StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
155 IndexBufferInterface *indexBuffer = streamingBuffer;
156 bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
157 destinationIndexType == type;
158 unsigned int streamOffset = 0;
159
160 if (directStorage)
161 {
162 indexBuffer = streamingBuffer;
163 streamOffset = offset;
164 storage->markBufferUsage();
165
166 if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
167 &translated->maxIndex, NULL))
168 {
169 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
170 buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
171 translated->maxIndex, offset);
172 }
173 }
174 else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
175 {
176 indexBuffer = staticBuffer;
177 if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
178 &translated->maxIndex, &streamOffset))
179 {
180 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
181 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
182 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
183 translated->maxIndex, streamOffset);
184 }
185 }
186 else
187 {
188 unsigned int convertCount = count;
189
190 if (staticBuffer)
191 {
192 if (staticBuffer->getBufferSize() == 0 && alignedOffset)
193 {
194 indexBuffer = staticBuffer;
195 convertCount = storage->getSize() / gl::ComputeTypeSize(type);
196 }
197 else
198 {
199 buffer->invalidateStaticData();
200 staticBuffer = NULL;
201 }
202 }
203
204 if (!indexBuffer)
205 {
206 ERR("No valid index buffer.");
207 return GL_INVALID_OPERATION;
208 }
209
210 unsigned int indexTypeSize = gl::ComputeTypeSize(destinationIndexType);
211 if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
212 {
213 ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
214 return GL_OUT_OF_MEMORY;
215 }
216
217 unsigned int bufferSizeRequired = convertCount * indexTypeSize;
218 if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
219 {
220 ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
221 return GL_OUT_OF_MEMORY;
222 }
223
224 void* output = NULL;
225 if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
226 {
227 ERR("Failed to map index buffer.");
228 return GL_OUT_OF_MEMORY;
229 }
230
231 convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
232
233 if (!indexBuffer->unmapBuffer())
234 {
235 ERR("Failed to unmap index buffer.");
236 return GL_OUT_OF_MEMORY;
237 }
238
239 computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
240
241 if (staticBuffer)
242 {
243 streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
244 staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
245 translated->maxIndex, streamOffset);
246 }
247 }
248
249 translated->storage = directStorage ? storage : NULL;
250 translated->indexBuffer = indexBuffer->getIndexBuffer();
251 translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
252 translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType);
253 translated->startOffset = streamOffset;
254
255 if (buffer)
256 {
257 buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type));
258 }
259
260 return GL_NO_ERROR;
261 }
262
263 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
264 {
265 if (count <= 65536) // 16-bit indices
266 {
267 const unsigned int spaceNeeded = count * sizeof(unsigned short);
268
269 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
270 {
271 delete mCountingBuffer;
272 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
273 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
274
275 void* mappedMemory = NULL;
276 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
277 {
278 ERR("Failed to map counting buffer.");
279 return NULL;
280 }
281
282 unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
283 for(int i = 0; i < count; i++)
284 {
285 data[i] = i;
286 }
287
288 if (!mCountingBuffer->unmapBuffer())
289 {
290 ERR("Failed to unmap counting buffer.");
291 return NULL;
292 }
293 }
294 }
295 else if (mStreamingBufferInt) // 32-bit indices supported
296 {
297 const unsigned int spaceNeeded = count * sizeof(unsigned int);
298
299 if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
300 {
301 delete mCountingBuffer;
302 mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
303 mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
304
305 void* mappedMemory = NULL;
306 if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
307 {
308 ERR("Failed to map counting buffer.");
309 return NULL;
310 }
311
312 unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
313 for(int i = 0; i < count; i++)
314 {
315 data[i] = i;
316 }
317
318 if (!mCountingBuffer->unmapBuffer())
319 {
320 ERR("Failed to unmap counting buffer.");
321 return NULL;
322 }
323 }
324 }
325 else
326 {
327 return NULL;
328 }
329
330 return mCountingBuffer;
331 }
332
333 }

mercurial