Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / renderer / d3d / IndexDataManager.cpp
1 #include "precompiled.h"
2 //
3 // Copyright (c) 2002-2014 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/d3d/IndexDataManager.h"
12 #include "libGLESv2/renderer/d3d/BufferD3D.h"
13
14 #include "libGLESv2/Buffer.h"
15 #include "libGLESv2/main.h"
16 #include "libGLESv2/formatutils.h"
17 #include "libGLESv2/renderer/d3d/IndexBuffer.h"
18 #include "libGLESv2/renderer/Renderer.h"
19
20 namespace rx
21 {
22
23 IndexDataManager::IndexDataManager(Renderer *renderer) : mRenderer(renderer)
24 {
25     mStreamingBufferShort = new StreamingIndexBufferInterface(mRenderer);
26     if (!mStreamingBufferShort->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_SHORT))
27     {
28         delete mStreamingBufferShort;
29         mStreamingBufferShort = NULL;
30     }
31
32     mStreamingBufferInt = new StreamingIndexBufferInterface(mRenderer);
33     if (!mStreamingBufferInt->reserveBufferSpace(INITIAL_INDEX_BUFFER_SIZE, GL_UNSIGNED_INT))
34     {
35         delete mStreamingBufferInt;
36         mStreamingBufferInt = NULL;
37     }
38
39     if (!mStreamingBufferShort)
40     {
41         // Make sure both buffers are deleted.
42         delete mStreamingBufferInt;
43         mStreamingBufferInt = NULL;
44
45         ERR("Failed to allocate the streaming index buffer(s).");
46     }
47
48     mCountingBuffer = NULL;
49 }
50
51 IndexDataManager::~IndexDataManager()
52 {
53     delete mStreamingBufferShort;
54     delete mStreamingBufferInt;
55     delete mCountingBuffer;
56 }
57
58 static void convertIndices(GLenum sourceType, GLenum destinationType, const void *input, GLsizei count, void *output)
59 {
60     if (sourceType == GL_UNSIGNED_BYTE)
61     {
62         ASSERT(destinationType == GL_UNSIGNED_SHORT);
63         const GLubyte *in = static_cast<const GLubyte*>(input);
64         GLushort *out = static_cast<GLushort*>(output);
65
66         for (GLsizei i = 0; i < count; i++)
67         {
68             out[i] = in[i];
69         }
70     }
71     else if (sourceType == GL_UNSIGNED_INT)
72     {
73         ASSERT(destinationType == GL_UNSIGNED_INT);
74         memcpy(output, input, count * sizeof(GLuint));
75     }
76     else if (sourceType == GL_UNSIGNED_SHORT)
77     {
78         if (destinationType == GL_UNSIGNED_SHORT)
79         {
80             memcpy(output, input, count * sizeof(GLushort));
81         }
82         else if (destinationType == GL_UNSIGNED_INT)
83         {
84             const GLushort *in = static_cast<const GLushort*>(input);
85             GLuint *out = static_cast<GLuint*>(output);
86
87             for (GLsizei i = 0; i < count; i++)
88             {
89                 out[i] = in[i];
90             }
91         }
92         else UNREACHABLE();
93     }
94     else UNREACHABLE();
95 }
96
97 template <class IndexType>
98 static void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
99 {
100     *minIndex = indices[0];
101     *maxIndex = indices[0];
102
103     for (GLsizei i = 0; i < count; i++)
104     {
105         if (*minIndex > indices[i]) *minIndex = indices[i];
106         if (*maxIndex < indices[i]) *maxIndex = indices[i];
107     }
108 }
109
110 static void computeRange(GLenum type, const GLvoid *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
111 {
112     if (type == GL_UNSIGNED_BYTE)
113     {
114         computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
115     }
116     else if (type == GL_UNSIGNED_INT)
117     {
118         computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
119     }
120     else if (type == GL_UNSIGNED_SHORT)
121     {
122         computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
123     }
124     else UNREACHABLE();
125 }
126
127 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
128 {
129     if (!mStreamingBufferShort)
130     {
131         return GL_OUT_OF_MEMORY;
132     }
133
134     const gl::Type &typeInfo = gl::GetTypeInfo(type);
135
136     GLenum destinationIndexType = (type == GL_UNSIGNED_INT) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
137
138     unsigned int offset = 0;
139     bool alignedOffset = false;
140
141     BufferD3D *storage = NULL;
142
143     if (buffer != NULL)
144     {
145         if (reinterpret_cast<uintptr_t>(indices) > std::numeric_limits<unsigned int>::max())
146         {
147             return GL_OUT_OF_MEMORY;
148         }
149         offset = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(indices));
150
151         storage = BufferD3D::makeBufferD3D(buffer->getImplementation());
152
153         switch (type)
154         {
155           case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
156           case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
157           case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
158           default: UNREACHABLE(); alignedOffset = false;
159         }
160
161         // check for integer overflows
162         if (static_cast<unsigned int>(count) > (std::numeric_limits<unsigned int>::max() / typeInfo.bytes) ||
163             typeInfo.bytes * static_cast<unsigned int>(count) + offset < offset)
164         {
165             return GL_OUT_OF_MEMORY;
166         }
167
168         if (typeInfo.bytes * static_cast<unsigned int>(count) + offset > storage->getSize())
169         {
170             return GL_INVALID_OPERATION;
171         }
172
173         indices = static_cast<const GLubyte*>(storage->getData()) + offset;
174     }
175
176     StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL;
177     IndexBufferInterface *indexBuffer = NULL;
178     bool directStorage = alignedOffset && storage && storage->supportsDirectBinding() &&
179                          destinationIndexType == type;
180     unsigned int streamOffset = 0;
181
182     if (directStorage)
183     {
184         streamOffset = offset;
185
186         if (!storage->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
187                                                      &translated->maxIndex, NULL))
188         {
189             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
190             storage->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
191                                                    translated->maxIndex, offset);
192         }
193     }
194     else if (staticBuffer && staticBuffer->getBufferSize() != 0 && staticBuffer->getIndexType() == type && alignedOffset)
195     {
196         indexBuffer = staticBuffer;
197
198         if (!staticBuffer->getIndexRangeCache()->findRange(type, offset, count, &translated->minIndex,
199                                                            &translated->maxIndex, &streamOffset))
200         {
201             streamOffset = (offset / typeInfo.bytes) * gl::GetTypeInfo(destinationIndexType).bytes;
202             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
203             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
204                                                          translated->maxIndex, streamOffset);
205         }
206     }
207     else
208     {
209         computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
210     }
211
212     // Avoid D3D11's primitive restart index value
213     // see http://msdn.microsoft.com/en-us/library/windows/desktop/bb205124(v=vs.85).aspx
214     if (translated->maxIndex == 0xFFFF && type == GL_UNSIGNED_SHORT && mRenderer->getMajorShaderModel() > 3)
215     {
216         destinationIndexType = GL_UNSIGNED_INT;
217         directStorage = false;
218         indexBuffer = NULL;
219     }
220
221     const gl::Type &destTypeInfo = gl::GetTypeInfo(destinationIndexType);
222
223     if (!directStorage && !indexBuffer)
224     {
225         indexBuffer = (destinationIndexType == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
226
227         unsigned int convertCount = count;
228
229         if (staticBuffer)
230         {
231             if (staticBuffer->getBufferSize() == 0 && alignedOffset)
232             {
233                 indexBuffer = staticBuffer;
234                 convertCount = storage->getSize() / typeInfo.bytes;
235             }
236             else
237             {
238                 storage->invalidateStaticData();
239                 staticBuffer = NULL;
240             }
241         }
242
243         if (!indexBuffer)
244         {
245             ERR("No valid index buffer.");
246             return GL_INVALID_OPERATION;
247         }
248
249         if (convertCount > std::numeric_limits<unsigned int>::max() / destTypeInfo.bytes)
250         {
251             ERR("Reserving %u indicies of %u bytes each exceeds the maximum buffer size.", convertCount, destTypeInfo.bytes);
252             return GL_OUT_OF_MEMORY;
253         }
254
255         unsigned int bufferSizeRequired = convertCount * destTypeInfo.bytes;
256         if (!indexBuffer->reserveBufferSpace(bufferSizeRequired, type))
257         {
258             ERR("Failed to reserve %u bytes in an index buffer.", bufferSizeRequired);
259             return GL_OUT_OF_MEMORY;
260         }
261
262         void* output = NULL;
263         if (!indexBuffer->mapBuffer(bufferSizeRequired, &output, &streamOffset))
264         {
265             ERR("Failed to map index buffer.");
266             return GL_OUT_OF_MEMORY;
267         }
268
269         convertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output);
270
271         if (!indexBuffer->unmapBuffer())
272         {
273             ERR("Failed to unmap index buffer.");
274             return GL_OUT_OF_MEMORY;
275         }
276
277         if (staticBuffer)
278         {
279             streamOffset = (offset / typeInfo.bytes) * destTypeInfo.bytes;
280             staticBuffer->getIndexRangeCache()->addRange(type, offset, count, translated->minIndex,
281                                                          translated->maxIndex, streamOffset);
282         }
283     }
284
285     translated->storage = directStorage ? storage : NULL;
286     translated->indexBuffer = indexBuffer ? indexBuffer->getIndexBuffer() : NULL;
287     translated->serial = directStorage ? storage->getSerial() : indexBuffer->getSerial();
288     translated->startIndex = streamOffset / destTypeInfo.bytes;
289     translated->startOffset = streamOffset;
290     translated->indexType = destinationIndexType;
291
292     if (storage)
293     {
294         storage->promoteStaticUsage(count * typeInfo.bytes);
295     }
296
297     return GL_NO_ERROR;
298 }
299
300 StaticIndexBufferInterface *IndexDataManager::getCountingIndices(GLsizei count)
301 {
302     if (count <= 65536)   // 16-bit indices
303     {
304         const unsigned int spaceNeeded = count * sizeof(unsigned short);
305
306         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
307         {
308             delete mCountingBuffer;
309             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
310             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_SHORT);
311
312             void* mappedMemory = NULL;
313             if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
314             {
315                 ERR("Failed to map counting buffer.");
316                 return NULL;
317             }
318
319             unsigned short *data = reinterpret_cast<unsigned short*>(mappedMemory);
320             for(int i = 0; i < count; i++)
321             {
322                 data[i] = i;
323             }
324
325             if (!mCountingBuffer->unmapBuffer())
326             {
327                 ERR("Failed to unmap counting buffer.");
328                 return NULL;
329             }
330         }
331     }
332     else if (mStreamingBufferInt)   // 32-bit indices supported
333     {
334         const unsigned int spaceNeeded = count * sizeof(unsigned int);
335
336         if (!mCountingBuffer || mCountingBuffer->getBufferSize() < spaceNeeded)
337         {
338             delete mCountingBuffer;
339             mCountingBuffer = new StaticIndexBufferInterface(mRenderer);
340             mCountingBuffer->reserveBufferSpace(spaceNeeded, GL_UNSIGNED_INT);
341
342             void* mappedMemory = NULL;
343             if (!mCountingBuffer->mapBuffer(spaceNeeded, &mappedMemory, NULL))
344             {
345                 ERR("Failed to map counting buffer.");
346                 return NULL;
347             }
348
349             unsigned int *data = reinterpret_cast<unsigned int*>(mappedMemory);
350             for(int i = 0; i < count; i++)
351             {
352                 data[i] = i;
353             }
354
355             if (!mCountingBuffer->unmapBuffer())
356             {
357                 ERR("Failed to unmap counting buffer.");
358                 return NULL;
359             }
360         }
361     }
362     else
363     {
364         return NULL;
365     }
366
367     return mCountingBuffer;
368 }
369
370 }