~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/3rdparty/angle/src/libGLESv2/IndexDataManager.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Copyright (c) 2002-2012 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
// IndexDataManager.cpp: Defines the IndexDataManager, a class that
 
8
// runs the Buffer translation process for index buffers.
 
9
 
 
10
#include "libGLESv2/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 gl
 
19
{
 
20
unsigned int IndexBuffer::mCurrentSerial = 1;
 
21
 
 
22
IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
 
23
{
 
24
    mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
 
25
 
 
26
    if (context->supports32bitIndices())
 
27
    {
 
28
        mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
 
29
 
 
30
        if (!mStreamingBufferInt)
 
31
        {
 
32
            // Don't leave it in a half-initialized state
 
33
            delete mStreamingBufferShort;
 
34
            mStreamingBufferShort = NULL;
 
35
        }
 
36
    }
 
37
    else
 
38
    {
 
39
        mStreamingBufferInt = NULL;
 
40
    }
 
41
 
 
42
    if (!mStreamingBufferShort)
 
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
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
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
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, Buffer *buffer, const GLvoid *indices, TranslatedIndexData *translated)
 
111
{
 
112
    if (!mStreamingBufferShort)
 
113
    {
 
114
        return GL_OUT_OF_MEMORY;
 
115
    }
 
116
 
 
117
    D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
 
118
    intptr_t offset = reinterpret_cast<intptr_t>(indices);
 
119
    bool alignedOffset = false;
 
120
 
 
121
    if (buffer != NULL)
 
122
    {
 
123
        switch (type)
 
124
        {
 
125
          case GL_UNSIGNED_BYTE:  alignedOffset = (offset % sizeof(GLubyte) == 0);  break;
 
126
          case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
 
127
          case GL_UNSIGNED_INT:   alignedOffset = (offset % sizeof(GLuint) == 0);   break;
 
128
          default: UNREACHABLE(); alignedOffset = false;
 
129
        }
 
130
 
 
131
        if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
 
132
        {
 
133
            return GL_INVALID_OPERATION;
 
134
        }
 
135
 
 
136
        indices = static_cast<const GLubyte*>(buffer->data()) + offset;
 
137
    }
 
138
 
 
139
    StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
 
140
 
 
141
    StaticIndexBuffer *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
 
142
    IndexBuffer *indexBuffer = streamingBuffer;
 
143
    UINT streamOffset = 0;
 
144
 
 
145
    if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
 
146
    {
 
147
        indexBuffer = staticBuffer;
 
148
        streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
 
149
 
 
150
        if (streamOffset == -1)
 
151
        {
 
152
            streamOffset = (offset / typeSize(type)) * indexSize(format);
 
153
            computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
 
154
            staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
 
155
        }
 
156
    }
 
157
    else
 
158
    {
 
159
        int convertCount = count;
 
160
 
 
161
        if (staticBuffer)
 
162
        {
 
163
            if (staticBuffer->size() == 0 && alignedOffset)
 
164
            {
 
165
                indexBuffer = staticBuffer;
 
166
                convertCount = buffer->size() / typeSize(type);
 
167
            }
 
168
            else
 
169
            {
 
170
                buffer->invalidateStaticData();
 
171
                staticBuffer = NULL;
 
172
            }
 
173
        }
 
174
 
 
175
        void *output = NULL;
 
176
        
 
177
        if (indexBuffer)
 
178
        {
 
179
            indexBuffer->reserveSpace(convertCount * indexSize(format), type);
 
180
            output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
 
181
        }
 
182
        
 
183
        if (output == NULL)
 
184
        {
 
185
            ERR("Failed to map index buffer.");
 
186
            return GL_OUT_OF_MEMORY;
 
187
        }
 
188
 
 
189
        convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
 
190
        indexBuffer->unmap();
 
191
 
 
192
        computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
 
193
 
 
194
        if (staticBuffer)
 
195
        {
 
196
            streamOffset = (offset / typeSize(type)) * indexSize(format);
 
197
            staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
 
198
        }
 
199
    }
 
200
 
 
201
    translated->indexBuffer = indexBuffer->getBuffer();
 
202
    translated->serial = indexBuffer->getSerial();
 
203
    translated->startIndex = streamOffset / indexSize(format);
 
204
 
 
205
    if (buffer)
 
206
    {
 
207
        buffer->promoteStaticUsage(count * typeSize(type));
 
208
    }
 
209
 
 
210
    return GL_NO_ERROR;
 
211
}
 
212
 
 
213
std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
 
214
{
 
215
    return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
 
216
}
 
217
 
 
218
std::size_t IndexDataManager::typeSize(GLenum type) const
 
219
{
 
220
    switch (type)
 
221
    {
 
222
      case GL_UNSIGNED_INT:   return sizeof(GLuint);
 
223
      case GL_UNSIGNED_SHORT: return sizeof(GLushort);
 
224
      case GL_UNSIGNED_BYTE:  return sizeof(GLubyte);
 
225
      default: UNREACHABLE(); return sizeof(GLushort);
 
226
    }
 
227
}
 
228
 
 
229
StaticIndexBuffer *IndexDataManager::getCountingIndices(GLsizei count)
 
230
{
 
231
    if (count <= 65536)   // 16-bit indices
 
232
    {
 
233
        const unsigned int spaceNeeded = count * sizeof(unsigned short);
 
234
 
 
235
        if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
 
236
        {
 
237
            delete mCountingBuffer;
 
238
            mCountingBuffer = new StaticIndexBuffer(mDevice);
 
239
            mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
 
240
 
 
241
            UINT offset;
 
242
            unsigned short *data = static_cast<unsigned short*>(mCountingBuffer->map(spaceNeeded, &offset));
 
243
        
 
244
            if (data)
 
245
            {
 
246
                for(int i = 0; i < count; i++)
 
247
                {
 
248
                    data[i] = i;
 
249
                }
 
250
 
 
251
                mCountingBuffer->unmap();
 
252
            }
 
253
        }
 
254
    }
 
255
    else if (mStreamingBufferInt)   // 32-bit indices supported
 
256
    {
 
257
        const unsigned int spaceNeeded = count * sizeof(unsigned int);
 
258
 
 
259
        if (!mCountingBuffer || mCountingBuffer->size() < spaceNeeded)
 
260
        {
 
261
            delete mCountingBuffer;
 
262
            mCountingBuffer = new StaticIndexBuffer(mDevice);
 
263
            mCountingBuffer->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
 
264
 
 
265
            UINT offset;
 
266
            unsigned int *data = static_cast<unsigned int*>(mCountingBuffer->map(spaceNeeded, &offset));
 
267
        
 
268
            if (data)
 
269
            {
 
270
                for(int i = 0; i < count; i++)
 
271
                {
 
272
                    data[i] = i;
 
273
                }
 
274
                
 
275
                mCountingBuffer->unmap();
 
276
            }
 
277
        }
 
278
    }
 
279
    else return NULL;
 
280
    
 
281
    return mCountingBuffer;
 
282
}
 
283
 
 
284
IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL)
 
285
{
 
286
    if (size > 0)
 
287
    {
 
288
        D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
 
289
        HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL);
 
290
        mSerial = issueSerial();
 
291
 
 
292
        if (FAILED(result))
 
293
        {
 
294
            ERR("Out of memory allocating an index buffer of size %lu.", size);
 
295
        }
 
296
    }
 
297
}
 
298
 
 
299
IndexBuffer::~IndexBuffer()
 
300
{
 
301
    if (mIndexBuffer)
 
302
    {
 
303
        mIndexBuffer->Release();
 
304
    }
 
305
}
 
306
 
 
307
IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
 
308
{
 
309
    return mIndexBuffer;
 
310
}
 
311
 
 
312
unsigned int IndexBuffer::getSerial() const
 
313
{
 
314
    return mSerial;
 
315
}
 
316
 
 
317
unsigned int IndexBuffer::issueSerial()
 
318
{
 
319
    return mCurrentSerial++;
 
320
}
 
321
 
 
322
void IndexBuffer::unmap()
 
323
{
 
324
    if (mIndexBuffer)
 
325
    {
 
326
        mIndexBuffer->Unlock();
 
327
    }
 
328
}
 
329
 
 
330
StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format)
 
331
{
 
332
    mWritePosition = 0;
 
333
}
 
334
 
 
335
StreamingIndexBuffer::~StreamingIndexBuffer()
 
336
{
 
337
}
 
338
 
 
339
void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
 
340
{
 
341
    void *mapPtr = NULL;
 
342
 
 
343
    if (mIndexBuffer)
 
344
    {
 
345
        HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
 
346
     
 
347
        if (FAILED(result))
 
348
        {
 
349
            ERR(" Lock failed with error 0x%08x", result);
 
350
            return NULL;
 
351
        }
 
352
 
 
353
        *offset = mWritePosition;
 
354
        mWritePosition += requiredSpace;
 
355
    }
 
356
 
 
357
    return mapPtr;
 
358
}
 
359
 
 
360
void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
 
361
{
 
362
    if (requiredSpace > mBufferSize)
 
363
    {
 
364
        if (mIndexBuffer)
 
365
        {
 
366
            mIndexBuffer->Release();
 
367
            mIndexBuffer = NULL;
 
368
        }
 
369
 
 
370
        mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
 
371
 
 
372
        D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
 
373
        HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
 
374
        mSerial = issueSerial();
 
375
    
 
376
        if (FAILED(result))
 
377
        {
 
378
            ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
 
379
        }
 
380
 
 
381
        mWritePosition = 0;
 
382
    }
 
383
    else if (mWritePosition + requiredSpace > mBufferSize)   // Recycle
 
384
    {
 
385
        void *dummy;
 
386
        mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
 
387
        mIndexBuffer->Unlock();
 
388
 
 
389
        mWritePosition = 0;
 
390
    }
 
391
}
 
392
 
 
393
StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN)
 
394
{
 
395
    mCacheType = GL_NONE;
 
396
}
 
397
 
 
398
StaticIndexBuffer::~StaticIndexBuffer()
 
399
{
 
400
}
 
401
 
 
402
void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
 
403
{
 
404
    void *mapPtr = NULL;
 
405
 
 
406
    if (mIndexBuffer)
 
407
    {
 
408
        HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
 
409
     
 
410
        if (FAILED(result))
 
411
        {
 
412
            ERR(" Lock failed with error 0x%08x", result);
 
413
            return NULL;
 
414
        }
 
415
 
 
416
        *offset = 0;
 
417
    }
 
418
 
 
419
    return mapPtr;
 
420
}
 
421
 
 
422
void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
 
423
{
 
424
    if (!mIndexBuffer && mBufferSize == 0)
 
425
    {
 
426
        D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
 
427
        HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
 
428
        mSerial = issueSerial();
 
429
    
 
430
        if (FAILED(result))
 
431
        {
 
432
            ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
 
433
        }
 
434
 
 
435
        mBufferSize = requiredSpace;
 
436
        mCacheType = type;
 
437
    }
 
438
    else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
 
439
    {
 
440
        // Already allocated
 
441
    }
 
442
    else UNREACHABLE();   // Static index buffers can't be resized
 
443
}
 
444
 
 
445
bool StaticIndexBuffer::lookupType(GLenum type)
 
446
{
 
447
    return mCacheType == type;
 
448
}
 
449
 
 
450
UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
 
451
{
 
452
    IndexRange range = {offset, count};
 
453
 
 
454
    std::map<IndexRange, IndexResult>::iterator res = mCache.find(range);
 
455
    
 
456
    if (res == mCache.end())
 
457
    {
 
458
        return -1;
 
459
    }
 
460
 
 
461
    *minIndex = res->second.minIndex;
 
462
    *maxIndex = res->second.maxIndex;
 
463
    return res->second.streamOffset;
 
464
}
 
465
 
 
466
void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
 
467
{
 
468
    IndexRange indexRange = {offset, count};
 
469
    IndexResult indexResult = {minIndex, maxIndex, streamOffset};
 
470
    mCache[indexRange] = indexResult;
 
471
}
 
472
 
 
473
}