• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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 
10 #include "libGLESv2/geometry/IndexDataManager.h"
11 
12 #include "common/debug.h"
13 
14 #include "libGLESv2/Buffer.h"
15 #include "libGLESv2/mathutil.h"
16 #include "libGLESv2/main.h"
17 
18 namespace
19 {
20     enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
21 }
22 
23 namespace gl
24 {
25 
IndexDataManager(Context * context,IDirect3DDevice9 * device)26 IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
27 {
28     mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
29 
30     if (context->supports32bitIndices())
31     {
32         mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
33     }
34     else
35     {
36         mStreamingBufferInt = NULL;
37     }
38 }
39 
~IndexDataManager()40 IndexDataManager::~IndexDataManager()
41 {
42     delete mStreamingBufferShort;
43     delete mStreamingBufferInt;
44 }
45 
convertIndices(GLenum type,const void * input,GLsizei count,void * output)46 void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
47 {
48     if (type == GL_UNSIGNED_BYTE)
49     {
50         const GLubyte *in = static_cast<const GLubyte*>(input);
51         GLushort *out = static_cast<GLushort*>(output);
52 
53         for (GLsizei i = 0; i < count; i++)
54         {
55             out[i] = in[i];
56         }
57     }
58     else if (type == GL_UNSIGNED_INT)
59     {
60         memcpy(output, input, count * sizeof(GLuint));
61     }
62     else if (type == GL_UNSIGNED_SHORT)
63     {
64         memcpy(output, input, count * sizeof(GLushort));
65     }
66     else UNREACHABLE();
67 }
68 
69 template <class IndexType>
computeRange(const IndexType * indices,GLsizei count,GLuint * minIndex,GLuint * maxIndex)70 void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
71 {
72     *minIndex = indices[0];
73     *maxIndex = indices[0];
74 
75     for (GLsizei i = 0; i < count; i++)
76     {
77         if (*minIndex > indices[i]) *minIndex = indices[i];
78         if (*maxIndex < indices[i]) *maxIndex = indices[i];
79     }
80 }
81 
computeRange(GLenum type,const void * indices,GLsizei count,GLuint * minIndex,GLuint * maxIndex)82 void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
83 {
84     if (type == GL_UNSIGNED_BYTE)
85     {
86         computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
87     }
88     else if (type == GL_UNSIGNED_INT)
89     {
90         computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
91     }
92     else if (type == GL_UNSIGNED_SHORT)
93     {
94         computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
95     }
96     else UNREACHABLE();
97 }
98 
prepareIndexData(GLenum type,GLsizei count,Buffer * buffer,const void * indices,TranslatedIndexData * translated)99 GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
100 {
101     D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
102     intptr_t offset = reinterpret_cast<intptr_t>(indices);
103     bool alignedOffset = false;
104 
105     if (buffer != NULL)
106     {
107         switch (type)
108         {
109           case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
110           case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
111           case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
112           default: UNREACHABLE(); alignedOffset = false;
113         }
114 
115         if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
116         {
117             return GL_INVALID_OPERATION;
118         }
119 
120         indices = static_cast<const GLubyte*>(buffer->data()) + offset;
121     }
122 
123     StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
124 
125     StaticIndexBuffer *staticBuffer = buffer ? buffer->getIndexBuffer() : NULL;
126     IndexBuffer *indexBuffer = streamingBuffer;
127     UINT streamOffset = 0;
128 
129     if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
130     {
131         indexBuffer = staticBuffer;
132         streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
133 
134         if (streamOffset == -1)
135         {
136             streamOffset = (offset / typeSize(type)) * indexSize(format);
137             computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
138             staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
139         }
140     }
141     else
142     {
143         int convertCount = count;
144 
145         if (staticBuffer)
146         {
147             if (staticBuffer->size() == 0 && alignedOffset)
148             {
149                 indexBuffer = staticBuffer;
150                 convertCount = buffer->size() / typeSize(type);
151             }
152             else
153             {
154                 buffer->invalidateStaticData();
155                 staticBuffer = NULL;
156             }
157         }
158 
159         void *output = NULL;
160 
161         if (indexBuffer)
162         {
163             indexBuffer->reserveSpace(convertCount * indexSize(format), type);
164             output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
165         }
166 
167         if (output == NULL)
168         {
169             ERR("Failed to map index buffer.");
170             return GL_OUT_OF_MEMORY;
171         }
172 
173         convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
174         indexBuffer->unmap();
175 
176         computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
177 
178         if (staticBuffer)
179         {
180             streamOffset = (offset / typeSize(type)) * indexSize(format);
181             staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
182         }
183     }
184 
185     translated->indexBuffer = indexBuffer->getBuffer();
186     translated->startIndex = streamOffset / indexSize(format);
187 
188     return GL_NO_ERROR;
189 }
190 
indexSize(D3DFORMAT format) const191 std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
192 {
193     return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
194 }
195 
typeSize(GLenum type) const196 std::size_t IndexDataManager::typeSize(GLenum type) const
197 {
198     switch (type)
199     {
200       case GL_UNSIGNED_INT:   return sizeof(GLuint);
201       case GL_UNSIGNED_SHORT: return sizeof(GLushort);
202       case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
203       default: UNREACHABLE(); return sizeof(GLushort);
204     }
205 }
206 
IndexBuffer(IDirect3DDevice9 * device,UINT size,D3DFORMAT format)207 IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL)
208 {
209     if (size > 0)
210     {
211         D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
212         HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL);
213 
214         if (FAILED(result))
215         {
216             ERR("Out of memory allocating an index buffer of size %lu.", size);
217         }
218     }
219 }
220 
~IndexBuffer()221 IndexBuffer::~IndexBuffer()
222 {
223     if (mIndexBuffer)
224     {
225         mIndexBuffer->Release();
226     }
227 }
228 
getBuffer() const229 IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
230 {
231     return mIndexBuffer;
232 }
233 
unmap()234 void IndexBuffer::unmap()
235 {
236     if (mIndexBuffer)
237     {
238         mIndexBuffer->Unlock();
239     }
240 }
241 
StreamingIndexBuffer(IDirect3DDevice9 * device,UINT initialSize,D3DFORMAT format)242 StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format)
243 {
244     mWritePosition = 0;
245 }
246 
~StreamingIndexBuffer()247 StreamingIndexBuffer::~StreamingIndexBuffer()
248 {
249 }
250 
map(UINT requiredSpace,UINT * offset)251 void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
252 {
253     void *mapPtr = NULL;
254 
255     if (mIndexBuffer)
256     {
257         HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
258 
259         if (FAILED(result))
260         {
261             ERR(" Lock failed with error 0x%08x", result);
262             return NULL;
263         }
264 
265         *offset = mWritePosition;
266         mWritePosition += requiredSpace;
267     }
268 
269     return mapPtr;
270 }
271 
reserveSpace(UINT requiredSpace,GLenum type)272 void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
273 {
274     if (requiredSpace > mBufferSize)
275     {
276         if (mIndexBuffer)
277         {
278             mIndexBuffer->Release();
279             mIndexBuffer = NULL;
280         }
281 
282         mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
283 
284         D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
285         HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
286 
287         if (FAILED(result))
288         {
289             ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
290         }
291 
292         mWritePosition = 0;
293     }
294     else if (mWritePosition + requiredSpace > mBufferSize)   // Recycle
295     {
296         void *dummy;
297         mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
298         mIndexBuffer->Unlock();
299 
300         mWritePosition = 0;
301     }
302 }
303 
StaticIndexBuffer(IDirect3DDevice9 * device)304 StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN)
305 {
306     mCacheType = GL_NONE;
307 }
308 
~StaticIndexBuffer()309 StaticIndexBuffer::~StaticIndexBuffer()
310 {
311 }
312 
map(UINT requiredSpace,UINT * offset)313 void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
314 {
315     void *mapPtr = NULL;
316 
317     if (mIndexBuffer)
318     {
319         HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
320 
321         if (FAILED(result))
322         {
323             ERR(" Lock failed with error 0x%08x", result);
324             return NULL;
325         }
326 
327         *offset = 0;
328     }
329 
330     return mapPtr;
331 }
332 
reserveSpace(UINT requiredSpace,GLenum type)333 void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
334 {
335     if (!mIndexBuffer && mBufferSize == 0)
336     {
337         D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
338         HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
339 
340         if (FAILED(result))
341         {
342             ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
343         }
344 
345         mBufferSize = requiredSpace;
346         mCacheType = type;
347     }
348     else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
349     {
350         // Already allocated
351     }
352     else UNREACHABLE();   // Static index buffers can't be resized
353 }
354 
lookupType(GLenum type)355 bool StaticIndexBuffer::lookupType(GLenum type)
356 {
357     return mCacheType == type;
358 }
359 
lookupRange(intptr_t offset,GLsizei count,UINT * minIndex,UINT * maxIndex)360 UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
361 {
362     for (unsigned int range = 0; range < mCache.size(); range++)
363     {
364         if (mCache[range].offset == offset && mCache[range].count == count)
365         {
366             *minIndex = mCache[range].minIndex;
367             *maxIndex = mCache[range].maxIndex;
368 
369             return mCache[range].streamOffset;
370         }
371     }
372 
373     return -1;
374 }
375 
addRange(intptr_t offset,GLsizei count,UINT minIndex,UINT maxIndex,UINT streamOffset)376 void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
377 {
378     IndexRange indexRange = {offset, count, minIndex, maxIndex, streamOffset};
379     mCache.push_back(indexRange);
380 }
381 
382 }
383