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// VertexDataManager.h: Defines the VertexDataManager, a class that
9// runs the Buffer translation process.
10
11#include "libGLESv2/renderer/VertexDataManager.h"
12#include "libGLESv2/renderer/BufferStorage.h"
13
14#include "libGLESv2/Buffer.h"
15#include "libGLESv2/ProgramBinary.h"
16#include "libGLESv2/Context.h"
17#include "libGLESv2/renderer/VertexBuffer.h"
18
19namespace
20{
21    enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
22    // This has to be at least 4k or else it fails on ATI cards.
23    enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 };
24}
25
26namespace rx
27{
28
29static int elementsInBuffer(const gl::VertexAttribute &attribute, unsigned int size)
30{
31    // Size cannot be larger than a GLsizei
32    if (size > static_cast<unsigned int>(std::numeric_limits<int>::max()))
33    {
34        size = static_cast<unsigned int>(std::numeric_limits<int>::max());
35    }
36
37    GLsizei stride = attribute.stride();
38    return (size - attribute.mOffset % stride + (stride - attribute.typeSize())) / stride;
39}
40
41static int StreamingBufferElementCount(const gl::VertexAttribute &attribute, int vertexDrawCount, int instanceDrawCount)
42{
43    // For instanced rendering, we draw "instanceDrawCount" sets of "vertexDrawCount" vertices.
44    //
45    // A vertex attribute with a positive divisor loads one instanced vertex for every set of
46    // non-instanced vertices, and the instanced vertex index advances once every "mDivisor" instances.
47    if (instanceDrawCount > 0 && attribute.mDivisor > 0)
48    {
49        return instanceDrawCount / attribute.mDivisor;
50    }
51
52    return vertexDrawCount;
53}
54
55VertexDataManager::VertexDataManager(Renderer *renderer) : mRenderer(renderer)
56{
57    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
58    {
59        mCurrentValue[i][0] = std::numeric_limits<float>::quiet_NaN();
60        mCurrentValue[i][1] = std::numeric_limits<float>::quiet_NaN();
61        mCurrentValue[i][2] = std::numeric_limits<float>::quiet_NaN();
62        mCurrentValue[i][3] = std::numeric_limits<float>::quiet_NaN();
63        mCurrentValueBuffer[i] = NULL;
64        mCurrentValueOffsets[i] = 0;
65    }
66
67    mStreamingBuffer = new StreamingVertexBufferInterface(renderer, INITIAL_STREAM_BUFFER_SIZE);
68
69    if (!mStreamingBuffer)
70    {
71        ERR("Failed to allocate the streaming vertex buffer.");
72    }
73}
74
75VertexDataManager::~VertexDataManager()
76{
77    delete mStreamingBuffer;
78
79    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
80    {
81        delete mCurrentValueBuffer[i];
82    }
83}
84
85static bool directStoragePossible(VertexBufferInterface* vb, const gl::VertexAttribute& attrib)
86{
87    gl::Buffer *buffer = attrib.mBoundBuffer.get();
88    BufferStorage *storage = buffer ? buffer->getStorage() : NULL;
89
90    const bool isAligned = (attrib.stride() % 4 == 0) && (attrib.mOffset % 4 == 0);
91
92    return storage && storage->supportsDirectBinding() && !vb->getVertexBuffer()->requiresConversion(attrib) && isAligned;
93}
94
95GLenum VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances)
96{
97    if (!mStreamingBuffer)
98    {
99        return GL_OUT_OF_MEMORY;
100    }
101
102    for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
103    {
104        translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1);
105    }
106
107    // Invalidate static buffers that don't contain matching attributes
108    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
109    {
110        if (translated[i].active && attribs[i].mArrayEnabled)
111        {
112            gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
113            StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
114
115            if (staticBuffer && staticBuffer->getBufferSize() > 0 && !staticBuffer->lookupAttribute(attribs[i], NULL) &&
116                !directStoragePossible(staticBuffer, attribs[i]))
117            {
118                buffer->invalidateStaticData();
119            }
120        }
121    }
122
123    // Reserve the required space in the buffers
124    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
125    {
126        if (translated[i].active && attribs[i].mArrayEnabled)
127        {
128            gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
129            StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
130            VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
131
132            if (!directStoragePossible(vertexBuffer, attribs[i]))
133            {
134                if (staticBuffer)
135                {
136                    if (staticBuffer->getBufferSize() == 0)
137                    {
138                        int totalCount = elementsInBuffer(attribs[i], buffer->size());
139                        if (!staticBuffer->reserveVertexSpace(attribs[i], totalCount, 0))
140                        {
141                            return GL_OUT_OF_MEMORY;
142                        }
143                    }
144                }
145                else
146                {
147                    int totalCount = StreamingBufferElementCount(attribs[i], count, instances);
148
149                    // Undefined behaviour:
150                    // We can return INVALID_OPERATION if our vertex attribute does not have enough backing data.
151                    if (buffer && elementsInBuffer(attribs[i], buffer->size()) < totalCount)
152                    {
153                        return GL_INVALID_OPERATION;
154                    }
155
156                    if (!mStreamingBuffer->reserveVertexSpace(attribs[i], totalCount, instances))
157                    {
158                        return GL_OUT_OF_MEMORY;
159                    }
160                }
161            }
162        }
163    }
164
165    // Perform the vertex data translations
166    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
167    {
168        if (translated[i].active)
169        {
170            if (attribs[i].mArrayEnabled)
171            {
172                gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
173
174                if (!buffer && attribs[i].mPointer == NULL)
175                {
176                    // This is an application error that would normally result in a crash, but we catch it and return an error
177                    ERR("An enabled vertex array has no buffer and no pointer.");
178                    return GL_INVALID_OPERATION;
179                }
180
181                StaticVertexBufferInterface *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
182                VertexBufferInterface *vertexBuffer = staticBuffer ? staticBuffer : static_cast<VertexBufferInterface*>(mStreamingBuffer);
183
184                BufferStorage *storage = buffer ? buffer->getStorage() : NULL;
185                bool directStorage = directStoragePossible(vertexBuffer, attribs[i]);
186
187                unsigned int streamOffset = 0;
188                unsigned int outputElementSize = 0;
189
190                if (directStorage)
191                {
192                    outputElementSize = attribs[i].stride();
193                    streamOffset = attribs[i].mOffset + outputElementSize * start;
194                    storage->markBufferUsage();
195                }
196                else if (staticBuffer)
197                {
198                    if (!staticBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize))
199                    {
200                        return GL_OUT_OF_MEMORY;
201                    }
202
203                    if (!staticBuffer->lookupAttribute(attribs[i], &streamOffset))
204                    {
205                        // Convert the entire buffer
206                        int totalCount = elementsInBuffer(attribs[i], storage->getSize());
207                        int startIndex = attribs[i].mOffset / attribs[i].stride();
208
209                        if (!staticBuffer->storeVertexAttributes(attribs[i], -startIndex, totalCount, 0, &streamOffset))
210                        {
211                            return GL_OUT_OF_MEMORY;
212                        }
213                    }
214
215                    unsigned int firstElementOffset = (attribs[i].mOffset / attribs[i].stride()) * outputElementSize;
216                    unsigned int startOffset = (instances == 0 || attribs[i].mDivisor == 0) ? start * outputElementSize : 0;
217                    if (streamOffset + firstElementOffset + startOffset < streamOffset)
218                    {
219                        return GL_OUT_OF_MEMORY;
220                    }
221
222                    streamOffset += firstElementOffset + startOffset;
223                }
224                else
225                {
226                    int totalCount = StreamingBufferElementCount(attribs[i], count, instances);
227                    if (!mStreamingBuffer->getVertexBuffer()->getSpaceRequired(attribs[i], 1, 0, &outputElementSize) ||
228                        !mStreamingBuffer->storeVertexAttributes(attribs[i], start, totalCount, instances, &streamOffset))
229                    {
230                        return GL_OUT_OF_MEMORY;
231                    }
232                }
233
234                translated[i].storage = directStorage ? storage : NULL;
235                translated[i].vertexBuffer = vertexBuffer->getVertexBuffer();
236                translated[i].serial = directStorage ? storage->getSerial() : vertexBuffer->getSerial();
237                translated[i].divisor = attribs[i].mDivisor;
238
239                translated[i].attribute = &attribs[i];
240                translated[i].stride = outputElementSize;
241                translated[i].offset = streamOffset;
242            }
243            else
244            {
245                if (!mCurrentValueBuffer[i])
246                {
247                    mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE);
248                }
249
250                StreamingVertexBufferInterface *buffer = mCurrentValueBuffer[i];
251
252                if (mCurrentValue[i][0] != attribs[i].mCurrentValue[0] ||
253                    mCurrentValue[i][1] != attribs[i].mCurrentValue[1] ||
254                    mCurrentValue[i][2] != attribs[i].mCurrentValue[2] ||
255                    mCurrentValue[i][3] != attribs[i].mCurrentValue[3])
256                {
257                    unsigned int requiredSpace = sizeof(float) * 4;
258                    if (!buffer->reserveRawDataSpace(requiredSpace))
259                    {
260                        return GL_OUT_OF_MEMORY;
261                    }
262
263                    unsigned int streamOffset;
264                    if (!buffer->storeRawData(attribs[i].mCurrentValue, requiredSpace, &streamOffset))
265                    {
266                        return GL_OUT_OF_MEMORY;
267                    }
268
269                    mCurrentValue[i][0] = attribs[i].mCurrentValue[0];
270                    mCurrentValue[i][1] = attribs[i].mCurrentValue[1];
271                    mCurrentValue[i][2] = attribs[i].mCurrentValue[2];
272                    mCurrentValue[i][3] = attribs[i].mCurrentValue[3];
273                    mCurrentValueOffsets[i] = streamOffset;
274                }
275
276                translated[i].storage = NULL;
277                translated[i].vertexBuffer = mCurrentValueBuffer[i]->getVertexBuffer();
278                translated[i].serial = mCurrentValueBuffer[i]->getSerial();
279                translated[i].divisor = 0;
280
281                translated[i].attribute = &attribs[i];
282                translated[i].stride = 0;
283                translated[i].offset = mCurrentValueOffsets[i];
284            }
285        }
286    }
287
288    for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
289    {
290        if (translated[i].active && attribs[i].mArrayEnabled)
291        {
292            gl::Buffer *buffer = attribs[i].mBoundBuffer.get();
293
294            if (buffer)
295            {
296                buffer->promoteStaticUsage(count * attribs[i].typeSize());
297            }
298        }
299    }
300
301    return GL_NO_ERROR;
302}
303
304}
305