Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / IndexDataManager.cpp
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     unsigned int offset = 0;
119     bool alignedOffset = false;
120
121     BufferStorage *storage = NULL;
122
123     if (buffer != NULL)
124     {
125         if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
126         {
127             return GL_OUT_OF_MEMORY;
128         }
129         offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
130
131         storage = buffer->getStorage();
132
133         switch (type)
134         {
135           case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
136           case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
137           case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
138           default: UNREACHABLE(); alignedOffset = false;
139         }
140
141         unsigned int typeSize = gl::ComputeTypeSize(type);
142
143         // check for integer overflows
144         if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeSize) ||
145             typeSize * static_cast<unsigned int>(count) + offset < offset)
146         {
147             return GL_OUT_OF_MEMORY;
148         }
149
150         if (typeSize * static_cast<unsigned int>(count) + offset > storage->getSize())
151         {
152             return GL_INVALID_OPERATION;
153         }
154
155         indices = static_cast<const GLubyte*>(storage->getData()) + offset;
156     }
157
158     StreamingIndexBufferInterface *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
159
160     StaticIndexBufferInterface *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
161     IndexBufferInterface *indexBuffer = streamingBuffer;
162     bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
163                          destinationIndexType == type;
164     unsigned int streamOffset = 0;
165
166     if (directStorage)
167     {
168         indexBuffer = streamingBuffer;
169         streamOffset = offset;
170         storage->markBufferUsage();
171
172         if (!buffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
173                                                      &translated->maxIndex, NULL))
174         {
175             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
176             buffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
177                                                    translated->maxIndex, offset);
178         }
179     }
180     else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
181     {
182         indexBuffer = staticBuffer;
183         if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
184                                                            &translated->maxIndex, &streamOffset))
185         {
186             streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
187             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
188             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
189                                                          translated->maxIndex, streamOffset);
190         }
191     }
192     else
193     {
194         unsigned int convertCount = count;
195
196         if (staticBuffer)
197         {
198             if (staticBuffer->getBufferSize() == 0 && alignedOffset)
199             {
200                 indexBuffer = staticBuffer;
201                 convertCount = storage->getSize() / gl::ComputeTypeSize(type);
202             }
203             else
204             {
205                 buffer->invalidateStaticData();
206                 staticBuffer = NULL;
207             }
208         }
209
210         if (!indexBuffer)
211         {
212             ERR("No valid index buffer.");
213             return GL_INVALID_OPERATION;
214         }
215
216         unsigned int indexTypeSize = gl::ComputeTypeSize(destinationIndexType);
217         if (convertCount > std::numeric_limits<unsigned int>::max() / indexTypeSize)
218         {
219             ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, indexTypeSize);
220             return GL_OUT_OF_MEMORY;
221         }
222
223         unsigned int bufferSizeRequired = convertCount * indexTypeSize;
224         if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
225         {
226             ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
227             return GL_OUT_OF_MEMORY;
228         }
229
230         void* output = NULL;
231         if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
232         {
233             ERR("Failed to map index buffer.");
234             return GL_OUT_OF_MEMORY;
235         }
236
237         convertIndices(type, staticBuffer ? storage->getData() : indices, convertCount, output);
238
239         if (!indexBuffer->unmapBuffer())
240         {
241             ERR("Failed to unmap index buffer.");
242             return GL_OUT_OF_MEMORY;
243         }
244
245         computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
246
247         if (staticBuffer)
248         {
249             streamOffset = (offset / gl::ComputeTypeSize(type)) * gl::ComputeTypeSize(destinationIndexType);
250             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
251                                                          translated->maxIndex, streamOffset);
252         }
253     }
254
255     translated->storage = directStorage ? storage : NULL;
256     translated->indexBuffer = indexBuffer->getIndexBuffer();
257     translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
258     translated->startIndex = streamOffset / gl::ComputeTypeSize(destinationIndexType);
259     translated->startOffset = streamOffset;
260
261     if (buffer)
262     {
263         buffer->promoteStaticUsage(count * gl::ComputeTypeSize(type));
264     }
265
266     return GL_NO_ERROR;
267 }
268
269 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
270 {
271     if (count <= 65536)   // 16-bit indices
272     {
273         const unsigned int spaceNeeded = count * sizeof(unsigned short);
274
275         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
276         {
277             delete mCountingBuffer;
278             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
279             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
280
281             void* mappedMemory = NULL;
282             if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
283             {
284                 ERR("Failed to map counting buffer.");
285                 return NULL;
286             }
287
288             unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
289             for(int i = 0; i < count; i++)
290             {
291                 data[i] = i;
292             }
293
294             if (!mCountingBuffer->unmapBuffer())
295             {
296                 ERR("Failed to unmap counting buffer.");
297                 return NULL;
298             }
299         }
300     }
301     else if (mStreamingBufferInt)   // 32-bit indices supported
302     {
303         const unsigned int spaceNeeded = count * sizeof(unsigned int);
304
305         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
306         {
307             delete mCountingBuffer;
308             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
309             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
310
311             void* mappedMemory = NULL;
312             if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
313             {
314                 ERR("Failed to map counting buffer.");
315                 return NULL;
316             }
317
318             unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
319             for(int i = 0; i < count; i++)
320             {
321                 data[i] = i;
322             }
323
324             if (!mCountingBuffer->unmapBuffer())
325             {
326                 ERR("Failed to unmap counting buffer.");
327                 return NULL;
328             }
329         }
330     }
331     else
332     {
333         return NULL;
334     }
335
336     return mCountingBuffer;
337 }
338
339 }