1//
2// Copyright (c) 2014 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#include "BufferSubData.h"
8
9#include <cassert>
10#include <sstream>
11
12#include "shader_utils.h"
13
14namespace
15{
16
17GLfloat *GetFloatData(GLint componentCount)
18{
19    static GLfloat vertices2[] =
20    {
21        1, 2,
22        0, 0,
23        2, 0,
24    };
25
26    static GLfloat vertices3[] =
27    {
28        1, 2, 1,
29        0, 0, 1,
30        2, 0, 1,
31    };
32
33    static GLfloat vertices4[] =
34    {
35        1, 2, 1, 3,
36        0, 0, 1, 3,
37        2, 0, 1, 3,
38    };
39
40    switch (componentCount)
41    {
42      case 2: return vertices2;
43      case 3: return vertices3;
44      case 4: return vertices4;
45      default: return NULL;
46    }
47}
48
49template <class T>
50GLsizeiptr GetNormalizedData(GLsizeiptr numElements, GLfloat *floatData, std::vector<uint8_t> *data)
51{
52    GLsizeiptr triDataSize = sizeof(T) * numElements;
53    data->resize(triDataSize);
54
55    T *destPtr = reinterpret_cast<T*>(data->data());
56
57    for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++)
58    {
59        GLfloat scaled = floatData[dataIndex] * 0.25f;
60        destPtr[dataIndex] = static_cast<T>(scaled * static_cast<GLfloat>(std::numeric_limits<T>::max()));
61    }
62
63    return triDataSize;
64}
65
66template <class T>
67GLsizeiptr GetIntData(GLsizeiptr numElements, GLfloat *floatData, std::vector<uint8_t> *data)
68{
69    GLsizeiptr triDataSize = sizeof(T) * numElements;
70    data->resize(triDataSize);
71
72    T *destPtr = reinterpret_cast<T*>(data->data());
73
74    for (GLsizeiptr dataIndex = 0; dataIndex < numElements; dataIndex++)
75    {
76        destPtr[dataIndex] = static_cast<T>(floatData[dataIndex]);
77    }
78
79    return triDataSize;
80}
81
82GLsizeiptr GetVertexData(GLenum type, GLint componentCount, GLboolean normalized, std::vector<uint8_t> *data)
83{
84    GLsizeiptr triDataSize = 0;
85    GLfloat *floatData = GetFloatData(componentCount);
86
87    if (type == GL_FLOAT)
88    {
89        triDataSize = sizeof(GLfloat) * componentCount * 3;
90        data->resize(triDataSize);
91        memcpy(data->data(), floatData, triDataSize);
92    }
93    else if (normalized == GL_TRUE)
94    {
95        GLsizeiptr numElements = componentCount * 3;
96
97        switch (type)
98        {
99          case GL_BYTE:           triDataSize = GetNormalizedData<GLbyte>(numElements, floatData, data); break;
100          case GL_SHORT:          triDataSize = GetNormalizedData<GLshort>(numElements, floatData, data); break;
101          case GL_INT:            triDataSize = GetNormalizedData<GLint>(numElements, floatData, data); break;
102          case GL_UNSIGNED_BYTE:  triDataSize = GetNormalizedData<GLubyte>(numElements, floatData, data); break;
103          case GL_UNSIGNED_SHORT: triDataSize = GetNormalizedData<GLushort>(numElements, floatData, data); break;
104          case GL_UNSIGNED_INT:   triDataSize = GetNormalizedData<GLuint>(numElements, floatData, data); break;
105          default: assert(0);
106        }
107    }
108    else
109    {
110        GLsizeiptr numElements = componentCount * 3;
111
112        switch (type)
113        {
114          case GL_BYTE:           triDataSize = GetIntData<GLbyte>(numElements, floatData, data); break;
115          case GL_SHORT:          triDataSize = GetIntData<GLshort>(numElements, floatData, data); break;
116          case GL_INT:            triDataSize = GetIntData<GLint>(numElements, floatData, data); break;
117          case GL_UNSIGNED_BYTE:  triDataSize = GetIntData<GLubyte>(numElements, floatData, data); break;
118          case GL_UNSIGNED_SHORT: triDataSize = GetIntData<GLushort>(numElements, floatData, data); break;
119          case GL_UNSIGNED_INT:   triDataSize = GetIntData<GLuint>(numElements, floatData, data); break;
120          default: assert(0);
121        }
122    }
123
124    return triDataSize;
125}
126
127}
128
129std::string BufferSubDataParams::name() const
130{
131    std::stringstream strstr;
132
133    strstr << "BufferSubData - " << BenchmarkParams::name() << " - ";
134
135    if (vertexNormalized)
136    {
137        strstr << "Norm";
138    }
139
140    switch (vertexType)
141    {
142      case GL_FLOAT: strstr << "Float"; break;
143      case GL_INT: strstr << "Int"; break;
144      case GL_BYTE: strstr << "Byte"; break;
145      case GL_SHORT: strstr << "Short"; break;
146      case GL_UNSIGNED_INT: strstr << "UInt"; break;
147      case GL_UNSIGNED_BYTE: strstr << "UByte"; break;
148      case GL_UNSIGNED_SHORT: strstr << "UShort"; break;
149      default: strstr << "UNKNOWN FORMAT (" << vertexType << ")"; break;
150    }
151
152    strstr << vertexComponentCount;
153
154    strstr << " - " << updateSize << "b updates (per " << updatesEveryNFrames << ") - ";
155    strstr << (bufferSize >> 10) << "k buffer - ";
156    strstr << iterations << " updates";
157
158    return strstr.str();
159}
160
161BufferSubDataBenchmark::BufferSubDataBenchmark(const BufferSubDataParams &params)
162    : SimpleBenchmark(params.name(), 1280, 720, 2, params.requestedRenderer),
163      mProgram(0),
164      mBuffer(0),
165      mUpdateData(NULL),
166      mNumTris(0),
167      mParams(params)
168{
169    mDrawIterations = mParams.iterations;
170
171    assert(mParams.vertexComponentCount > 1);
172    assert(mParams.iterations > 0);
173}
174
175bool BufferSubDataBenchmark::initializeBenchmark()
176{
177    const std::string vs = SHADER_SOURCE
178    (
179        attribute vec2 vPosition;
180        uniform float uScale;
181        uniform float uOffset;
182        void main()
183        {
184            gl_Position = vec4(vPosition * vec2(uScale) - vec2(uOffset), 0, 1);
185        }
186    );
187
188    const std::string fs = SHADER_SOURCE
189    (
190        precision mediump float;
191        void main()
192        {
193            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
194        }
195    );
196
197    mProgram = CompileProgram(vs, fs);
198    if (!mProgram)
199    {
200        return false;
201    }
202
203    // Use the program object
204    glUseProgram(mProgram);
205
206    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
207
208
209    std::vector<uint8_t> zeroData(mParams.bufferSize);
210    memset(zeroData.data(), 0, zeroData.size());
211
212    glGenBuffers(1, &mBuffer);
213    glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
214    glBufferData(GL_ARRAY_BUFFER, mParams.bufferSize, zeroData.data(), GL_DYNAMIC_DRAW);
215
216    glVertexAttribPointer(0, mParams.vertexComponentCount, mParams.vertexType,
217                          mParams.vertexNormalized, 0, 0);
218    glEnableVertexAttribArray(0);
219
220    if (mParams.updateSize > 0)
221    {
222        mUpdateData = new uint8_t[mParams.updateSize];
223    }
224
225    std::vector<uint8_t> data;
226    GLsizei triDataSize = GetVertexData(mParams.vertexType,
227                                        mParams.vertexComponentCount,
228                                        mParams.vertexNormalized, &data);
229
230    mNumTris = mParams.updateSize / triDataSize;
231    for (int i = 0, offset = 0; i < mNumTris; ++i)
232    {
233        memcpy(mUpdateData + offset, data.data(), triDataSize);
234        offset += triDataSize;
235    }
236
237    if (mParams.updateSize == 0)
238    {
239        mNumTris = 1;
240        glBufferSubData(GL_ARRAY_BUFFER, 0, data.size(), data.data());
241    }
242
243    // Set the viewport
244    glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
245
246    GLfloat scale = 0.5f;
247    GLfloat offset = 0.5f;
248
249    if (mParams.vertexNormalized == GL_TRUE)
250    {
251        scale = 2.0f;
252        offset = 0.5f;
253    }
254
255    glUniform1f(glGetUniformLocation(mProgram, "uScale"), scale);
256    glUniform1f(glGetUniformLocation(mProgram, "uOffset"), offset);
257
258    GLenum glErr = glGetError();
259    if (glErr != GL_NO_ERROR)
260    {
261        return false;
262    }
263
264    return true;
265}
266
267void BufferSubDataBenchmark::destroyBenchmark()
268{
269    glDeleteProgram(mProgram);
270    glDeleteBuffers(1, &mBuffer);
271    delete[] mUpdateData;
272}
273
274void BufferSubDataBenchmark::beginDrawBenchmark()
275{
276    // Clear the color buffer
277    glClear(GL_COLOR_BUFFER_BIT);
278}
279
280void BufferSubDataBenchmark::drawBenchmark()
281{
282    for (unsigned int it = 0; it < mParams.iterations; it++)
283    {
284        if (mParams.updateSize > 0 && ((mNumFrames % mParams.updatesEveryNFrames) == 0))
285        {
286            glBufferSubData(GL_ARRAY_BUFFER, 0, mParams.updateSize, mUpdateData);
287        }
288
289        glDrawArrays(GL_TRIANGLES, 0, 3 * mNumTris);
290    }
291}
292