• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 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 // InstancingPerf:
7 //   Performance tests for ANGLE instanced draw calls.
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <cmath>
13 #include <sstream>
14 
15 #include "util/Matrix.h"
16 #include "util/random_utils.h"
17 #include "util/shader_utils.h"
18 
19 using namespace angle;
20 using namespace egl_platform;
21 
22 namespace
23 {
24 
AnimationSignal(float t)25 float AnimationSignal(float t)
26 {
27     float l = t / 2.0f;
28     float f = l - std::floor(l);
29     return (f > 0.5f ? 1.0f - f : f) * 4.0f - 1.0f;
30 }
31 
32 template <typename T>
VectorSizeBytes(const std::vector<T> & vec)33 size_t VectorSizeBytes(const std::vector<T> &vec)
34 {
35     return sizeof(T) * vec.size();
36 }
37 
RandomVector3(RNG * rng)38 Vector3 RandomVector3(RNG *rng)
39 {
40     return Vector3(rng->randomNegativeOneToOne(), rng->randomNegativeOneToOne(),
41                    rng->randomNegativeOneToOne());
42 }
43 
44 struct InstancingPerfParams final : public RenderTestParams
45 {
46     // Common default options
InstancingPerfParams__anon5ac92ae50111::InstancingPerfParams47     InstancingPerfParams()
48     {
49         majorVersion      = 2;
50         minorVersion      = 0;
51         windowWidth       = 256;
52         windowHeight      = 256;
53         iterationsPerStep = 1;
54         runTimeSeconds    = 10.0;
55         animationEnabled  = false;
56         instancingEnabled = true;
57     }
58 
story__anon5ac92ae50111::InstancingPerfParams59     std::string story() const override
60     {
61         std::stringstream strstr;
62 
63         strstr << RenderTestParams::story();
64 
65         if (!instancingEnabled)
66         {
67             strstr << "_billboards";
68         }
69 
70         return strstr.str();
71     }
72 
73     double runTimeSeconds;
74     bool animationEnabled;
75     bool instancingEnabled;
76 };
77 
operator <<(std::ostream & os,const InstancingPerfParams & params)78 std::ostream &operator<<(std::ostream &os, const InstancingPerfParams &params)
79 {
80     os << params.backendAndStory().substr(1);
81     return os;
82 }
83 
84 class InstancingPerfBenchmark : public ANGLERenderTest,
85                                 public ::testing::WithParamInterface<InstancingPerfParams>
86 {
87   public:
88     InstancingPerfBenchmark();
89 
90     void initializeBenchmark() override;
91     void destroyBenchmark() override;
92     void drawBenchmark() override;
93 
94   private:
95     GLuint mProgram;
96     std::vector<GLuint> mBuffers;
97     GLuint mNumPoints;
98     std::vector<Vector3> mTranslateData;
99     std::vector<float> mSizeData;
100     std::vector<Vector3> mColorData;
101     angle::RNG mRNG;
102 };
103 
InstancingPerfBenchmark()104 InstancingPerfBenchmark::InstancingPerfBenchmark()
105     : ANGLERenderTest("InstancingPerf", GetParam()), mProgram(0), mNumPoints(75000)
106 {}
107 
initializeBenchmark()108 void InstancingPerfBenchmark::initializeBenchmark()
109 {
110     const auto &params = GetParam();
111 
112     const char kVS[] =
113         "attribute vec2 aPosition;\n"
114         "attribute vec3 aTranslate;\n"
115         "attribute float aScale;\n"
116         "attribute vec3 aColor;\n"
117         "uniform mat4 uWorldMatrix;\n"
118         "uniform mat4 uProjectionMatrix;\n"
119         "varying vec3 vColor;\n"
120         "void main()\n"
121         "{\n"
122         "    vec4 position = uWorldMatrix * vec4(aTranslate, 1.0);\n"
123         "    position.xy += aPosition * aScale;\n"
124         "    gl_Position = uProjectionMatrix * position;\n"
125         "    vColor = aColor;\n"
126         "}\n";
127 
128     constexpr char kFS[] =
129         "precision mediump float;\n"
130         "varying vec3 vColor;\n"
131         "void main()\n"
132         "{\n"
133         "    gl_FragColor = vec4(vColor, 1.0);\n"
134         "}\n";
135 
136     mProgram = CompileProgram(kVS, kFS);
137     ASSERT_NE(0u, mProgram);
138 
139     glUseProgram(mProgram);
140 
141     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
142 
143     GLuint baseIndexData[6]     = {0, 1, 2, 1, 3, 2};
144     Vector2 basePositionData[4] = {Vector2(-1.0f, 1.0f), Vector2(1.0f, 1.0f), Vector2(-1.0f, -1.0f),
145                                    Vector2(1.0f, -1.0f)};
146 
147     std::vector<GLuint> indexData;
148     std::vector<Vector2> positionData;
149 
150     if (!params.instancingEnabled)
151     {
152         GLuint pointVertexStride = 4;
153         for (GLuint pointIndex = 0; pointIndex < mNumPoints; ++pointIndex)
154         {
155             for (GLuint indexIndex = 0; indexIndex < 6; ++indexIndex)
156             {
157                 indexData.push_back(baseIndexData[indexIndex] + pointIndex * pointVertexStride);
158             }
159 
160             Vector3 randVec = RandomVector3(&mRNG);
161             for (GLuint vertexIndex = 0; vertexIndex < 4; ++vertexIndex)
162             {
163                 positionData.push_back(basePositionData[vertexIndex]);
164                 mTranslateData.push_back(randVec);
165             }
166         }
167 
168         mSizeData.resize(mNumPoints * 4, 0.012f);
169         mColorData.resize(mNumPoints * 4, Vector3(1.0f, 0.0f, 0.0f));
170     }
171     else
172     {
173         for (GLuint index : baseIndexData)
174         {
175             indexData.push_back(index);
176         }
177 
178         for (const Vector2 &position : basePositionData)
179         {
180             positionData.push_back(position);
181         }
182 
183         for (GLuint pointIndex = 0; pointIndex < mNumPoints; ++pointIndex)
184         {
185             Vector3 randVec = RandomVector3(&mRNG);
186             mTranslateData.push_back(randVec);
187         }
188 
189         mSizeData.resize(mNumPoints, 0.012f);
190         mColorData.resize(mNumPoints, Vector3(1.0f, 0.0f, 0.0f));
191     }
192 
193     mBuffers.resize(5, 0);
194     glGenBuffers(static_cast<GLsizei>(mBuffers.size()), &mBuffers[0]);
195 
196     // Index Data
197     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffers[0]);
198     glBufferData(GL_ELEMENT_ARRAY_BUFFER, VectorSizeBytes(indexData), &indexData[0],
199                  GL_STATIC_DRAW);
200 
201     // Position Data
202     glBindBuffer(GL_ARRAY_BUFFER, mBuffers[1]);
203     glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(positionData), &positionData[0], GL_STATIC_DRAW);
204     GLint positionLocation = glGetAttribLocation(mProgram, "aPosition");
205     ASSERT_NE(-1, positionLocation);
206     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 8, nullptr);
207     glEnableVertexAttribArray(positionLocation);
208 
209     // Translate Data
210     glBindBuffer(GL_ARRAY_BUFFER, mBuffers[2]);
211     glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mTranslateData), &mTranslateData[0],
212                  GL_STATIC_DRAW);
213     GLint translateLocation = glGetAttribLocation(mProgram, "aTranslate");
214     ASSERT_NE(-1, translateLocation);
215     glVertexAttribPointer(translateLocation, 3, GL_FLOAT, GL_FALSE, 12, nullptr);
216     glEnableVertexAttribArray(translateLocation);
217     glVertexAttribDivisorANGLE(translateLocation, 1);
218 
219     // Scale Data
220     glBindBuffer(GL_ARRAY_BUFFER, mBuffers[3]);
221     glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mSizeData), nullptr, GL_DYNAMIC_DRAW);
222     GLint scaleLocation = glGetAttribLocation(mProgram, "aScale");
223     ASSERT_NE(-1, scaleLocation);
224     glVertexAttribPointer(scaleLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
225     glEnableVertexAttribArray(scaleLocation);
226     glVertexAttribDivisorANGLE(scaleLocation, 1);
227 
228     // Color Data
229     glBindBuffer(GL_ARRAY_BUFFER, mBuffers[4]);
230     glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mColorData), nullptr, GL_DYNAMIC_DRAW);
231     GLint colorLocation = glGetAttribLocation(mProgram, "aColor");
232     ASSERT_NE(-1, colorLocation);
233     glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 12, nullptr);
234     glEnableVertexAttribArray(colorLocation);
235     glVertexAttribDivisorANGLE(colorLocation, 1);
236 
237     // Set the viewport
238     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
239 
240     // Init matrices
241     GLint worldMatrixLocation = glGetUniformLocation(mProgram, "uWorldMatrix");
242     ASSERT_NE(-1, worldMatrixLocation);
243     Matrix4 worldMatrix = Matrix4::translate(Vector3(0, 0, -3.0f));
244     worldMatrix *= Matrix4::rotate(25.0f, Vector3(0.6f, 1.0f, 0.0f));
245     glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, &worldMatrix.data[0]);
246 
247     GLint projectionMatrixLocation = glGetUniformLocation(mProgram, "uProjectionMatrix");
248     ASSERT_NE(-1, projectionMatrixLocation);
249     float fov =
250         static_cast<float>(getWindow()->getWidth()) / static_cast<float>(getWindow()->getHeight());
251     Matrix4 projectionMatrix = Matrix4::perspective(60.0f, fov, 1.0f, 300.0f);
252     glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix.data[0]);
253 
254     getWindow()->setVisible(true);
255 
256     ASSERT_GL_NO_ERROR();
257 }
258 
destroyBenchmark()259 void InstancingPerfBenchmark::destroyBenchmark()
260 {
261     glDeleteProgram(mProgram);
262 
263     if (!mBuffers.empty())
264     {
265         glDeleteBuffers(static_cast<GLsizei>(mBuffers.size()), &mBuffers[0]);
266         mBuffers.clear();
267     }
268 }
269 
drawBenchmark()270 void InstancingPerfBenchmark::drawBenchmark()
271 {
272     glClear(GL_COLOR_BUFFER_BIT);
273 
274     const auto &params = GetParam();
275 
276     // Animatino makes the test more interesting visually, but also eats up many CPU cycles.
277     if (params.animationEnabled)
278     {
279         float time = static_cast<float>(mTimer.getElapsedTime());
280 
281         for (size_t pointIndex = 0; pointIndex < mTranslateData.size(); ++pointIndex)
282         {
283             const Vector3 &translate = mTranslateData[pointIndex];
284 
285             float tx = translate.x() + time;
286             float ty = translate.y() + time;
287             float tz = translate.z() + time;
288 
289             float scale           = AnimationSignal(tx) * 0.01f + 0.01f;
290             mSizeData[pointIndex] = scale;
291 
292             Vector3 color =
293                 Vector3(AnimationSignal(tx), AnimationSignal(ty), AnimationSignal(tz)) * 0.5f +
294                 Vector3(0.5f);
295 
296             mColorData[pointIndex] = color;
297         }
298     }
299 
300     // Update scales and colors.
301     glBindBuffer(GL_ARRAY_BUFFER, mBuffers[3]);
302     glBufferSubData(GL_ARRAY_BUFFER, 0, VectorSizeBytes(mSizeData), &mSizeData[0]);
303 
304     glBindBuffer(GL_ARRAY_BUFFER, mBuffers[4]);
305     glBufferSubData(GL_ARRAY_BUFFER, 0, VectorSizeBytes(mColorData), &mColorData[0]);
306 
307     // Render the instances/billboards.
308     if (params.instancingEnabled)
309     {
310         for (unsigned int it = 0; it < params.iterationsPerStep; it++)
311         {
312             glDrawElementsInstancedANGLE(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr, mNumPoints);
313         }
314     }
315     else
316     {
317         for (unsigned int it = 0; it < params.iterationsPerStep; it++)
318         {
319             glDrawElements(GL_TRIANGLES, 6 * mNumPoints, GL_UNSIGNED_INT, nullptr);
320         }
321     }
322 
323     ASSERT_GL_NO_ERROR();
324 }
325 
InstancingPerfD3D11Params()326 InstancingPerfParams InstancingPerfD3D11Params()
327 {
328     InstancingPerfParams params;
329     params.eglParameters = D3D11();
330     return params;
331 }
332 
InstancingPerfD3D9Params()333 InstancingPerfParams InstancingPerfD3D9Params()
334 {
335     InstancingPerfParams params;
336     params.eglParameters = D3D9();
337     return params;
338 }
339 
InstancingPerfOpenGLOrGLESParams()340 InstancingPerfParams InstancingPerfOpenGLOrGLESParams()
341 {
342     InstancingPerfParams params;
343     params.eglParameters = OPENGL_OR_GLES();
344     return params;
345 }
346 
TEST_P(InstancingPerfBenchmark,Run)347 TEST_P(InstancingPerfBenchmark, Run)
348 {
349     run();
350 }
351 
352 ANGLE_INSTANTIATE_TEST(InstancingPerfBenchmark,
353                        InstancingPerfD3D11Params(),
354                        InstancingPerfD3D9Params(),
355                        InstancingPerfOpenGLOrGLESParams());
356 
357 }  // anonymous namespace
358