summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/tests/perf_tests/InstancingPerf.cpp')
-rwxr-xr-xgfx/angle/src/tests/perf_tests/InstancingPerf.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp b/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp
new file mode 100755
index 000000000..eb02c10e9
--- /dev/null
+++ b/gfx/angle/src/tests/perf_tests/InstancingPerf.cpp
@@ -0,0 +1,366 @@
+//
+// Copyright 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// InstancingPerf:
+// Performance tests for ANGLE instanced draw calls.
+//
+
+#include <cmath>
+#include <sstream>
+
+#include "ANGLEPerfTest.h"
+#include "Matrix.h"
+#include "random_utils.h"
+#include "shader_utils.h"
+#include "Vector.h"
+
+using namespace angle;
+using namespace egl_platform;
+
+namespace
+{
+
+float AnimationSignal(float t)
+{
+ float l = t / 2.0f;
+ float f = l - std::floor(l);
+ return (f > 0.5f ? 1.0f - f : f) * 4.0f - 1.0f;
+}
+
+template <typename T>
+size_t VectorSizeBytes(const std::vector<T> &vec)
+{
+ return sizeof(T) * vec.size();
+}
+
+Vector3 RandomVector3(RNG *rng)
+{
+ return Vector3(rng->randomNegativeOneToOne(), rng->randomNegativeOneToOne(),
+ rng->randomNegativeOneToOne());
+}
+
+struct InstancingPerfParams final : public RenderTestParams
+{
+ // Common default options
+ InstancingPerfParams()
+ {
+ majorVersion = 2;
+ minorVersion = 0;
+ windowWidth = 256;
+ windowHeight = 256;
+ iterations = 1;
+ runTimeSeconds = 10.0;
+ animationEnabled = false;
+ instancingEnabled = true;
+ }
+
+ std::string suffix() const override
+ {
+ std::stringstream strstr;
+
+ strstr << RenderTestParams::suffix();
+
+ if (!instancingEnabled)
+ {
+ strstr << "_billboards";
+ }
+
+ return strstr.str();
+ }
+
+ unsigned int iterations;
+ double runTimeSeconds;
+ bool animationEnabled;
+ bool instancingEnabled;
+};
+
+std::ostream &operator<<(std::ostream &os, const InstancingPerfParams &params)
+{
+ os << params.suffix().substr(1);
+ return os;
+}
+
+class InstancingPerfBenchmark : public ANGLERenderTest,
+ public ::testing::WithParamInterface<InstancingPerfParams>
+{
+ public:
+ InstancingPerfBenchmark();
+
+ void initializeBenchmark() override;
+ void destroyBenchmark() override;
+ void drawBenchmark() override;
+
+ private:
+ GLuint mProgram;
+ std::vector<GLuint> mBuffers;
+ GLuint mNumPoints;
+ std::vector<Vector3> mTranslateData;
+ std::vector<float> mSizeData;
+ std::vector<Vector3> mColorData;
+ angle::RNG mRNG;
+};
+
+InstancingPerfBenchmark::InstancingPerfBenchmark()
+ : ANGLERenderTest("InstancingPerf", GetParam()), mProgram(0), mNumPoints(75000)
+{
+ mRunTimeSeconds = GetParam().runTimeSeconds;
+}
+
+void InstancingPerfBenchmark::initializeBenchmark()
+{
+ const auto &params = GetParam();
+
+ ASSERT_LT(0u, params.iterations);
+
+ const std::string vs =
+ "attribute vec2 aPosition;\n"
+ "attribute vec3 aTranslate;\n"
+ "attribute float aScale;\n"
+ "attribute vec3 aColor;\n"
+ "uniform mat4 uWorldMatrix;\n"
+ "uniform mat4 uProjectionMatrix;\n"
+ "varying vec3 vColor;\n"
+ "void main()\n"
+ "{\n"
+ " vec4 position = uWorldMatrix * vec4(aTranslate, 1.0);\n"
+ " position.xy += aPosition * aScale;\n"
+ " gl_Position = uProjectionMatrix * position;\n"
+ " vColor = aColor;\n"
+ "}\n";
+
+ const std::string fs =
+ "precision mediump float;\n"
+ "varying vec3 vColor;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(vColor, 1.0);\n"
+ "}\n";
+
+ mProgram = CompileProgram(vs, fs);
+ ASSERT_NE(0u, mProgram);
+
+ glUseProgram(mProgram);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ GLuint baseIndexData[6] = {0, 1, 2, 1, 3, 2};
+ Vector2 basePositionData[4] = {Vector2(-1.0f, 1.0f), Vector2(1.0f, 1.0f), Vector2(-1.0f, -1.0f),
+ Vector2(1.0f, -1.0f)};
+
+ std::vector<GLuint> indexData;
+ std::vector<Vector2> positionData;
+
+ if (!params.instancingEnabled)
+ {
+ GLuint pointVertexStride = 4;
+ for (GLuint pointIndex = 0; pointIndex < mNumPoints; ++pointIndex)
+ {
+ for (GLuint indexIndex = 0; indexIndex < 6; ++indexIndex)
+ {
+ indexData.push_back(baseIndexData[indexIndex] + pointIndex * pointVertexStride);
+ }
+
+ Vector3 randVec = RandomVector3(&mRNG);
+ for (GLuint vertexIndex = 0; vertexIndex < 4; ++vertexIndex)
+ {
+ positionData.push_back(basePositionData[vertexIndex]);
+ mTranslateData.push_back(randVec);
+ }
+ }
+
+ mSizeData.resize(mNumPoints * 4, 0.012f);
+ mColorData.resize(mNumPoints * 4, Vector3(1.0f, 0.0f, 0.0f));
+ }
+ else
+ {
+ for (GLuint index : baseIndexData)
+ {
+ indexData.push_back(index);
+ }
+
+ for (const Vector2 &position : basePositionData)
+ {
+ positionData.push_back(position);
+ }
+
+ for (GLuint pointIndex = 0; pointIndex < mNumPoints; ++pointIndex)
+ {
+ Vector3 randVec = RandomVector3(&mRNG);
+ mTranslateData.push_back(randVec);
+ }
+
+ mSizeData.resize(mNumPoints, 0.012f);
+ mColorData.resize(mNumPoints, Vector3(1.0f, 0.0f, 0.0f));
+ }
+
+ mBuffers.resize(5, 0);
+ glGenBuffers(static_cast<GLsizei>(mBuffers.size()), &mBuffers[0]);
+
+ // Index Data
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBuffers[0]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, VectorSizeBytes(indexData), &indexData[0],
+ GL_STATIC_DRAW);
+
+ // Position Data
+ glBindBuffer(GL_ARRAY_BUFFER, mBuffers[1]);
+ glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(positionData), &positionData[0], GL_STATIC_DRAW);
+ GLint positionLocation = glGetAttribLocation(mProgram, "aPosition");
+ ASSERT_NE(-1, positionLocation);
+ glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 8, nullptr);
+ glEnableVertexAttribArray(positionLocation);
+
+ // Translate Data
+ glBindBuffer(GL_ARRAY_BUFFER, mBuffers[2]);
+ glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mTranslateData), &mTranslateData[0],
+ GL_STATIC_DRAW);
+ GLint translateLocation = glGetAttribLocation(mProgram, "aTranslate");
+ ASSERT_NE(-1, translateLocation);
+ glVertexAttribPointer(translateLocation, 3, GL_FLOAT, GL_FALSE, 12, nullptr);
+ glEnableVertexAttribArray(translateLocation);
+ glVertexAttribDivisorANGLE(translateLocation, 1);
+
+ // Scale Data
+ glBindBuffer(GL_ARRAY_BUFFER, mBuffers[3]);
+ glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mSizeData), nullptr, GL_DYNAMIC_DRAW);
+ GLint scaleLocation = glGetAttribLocation(mProgram, "aScale");
+ ASSERT_NE(-1, scaleLocation);
+ glVertexAttribPointer(scaleLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
+ glEnableVertexAttribArray(scaleLocation);
+ glVertexAttribDivisorANGLE(scaleLocation, 1);
+
+ // Color Data
+ glBindBuffer(GL_ARRAY_BUFFER, mBuffers[4]);
+ glBufferData(GL_ARRAY_BUFFER, VectorSizeBytes(mColorData), nullptr, GL_DYNAMIC_DRAW);
+ GLint colorLocation = glGetAttribLocation(mProgram, "aColor");
+ ASSERT_NE(-1, colorLocation);
+ glVertexAttribPointer(colorLocation, 3, GL_FLOAT, GL_FALSE, 12, nullptr);
+ glEnableVertexAttribArray(colorLocation);
+ glVertexAttribDivisorANGLE(colorLocation, 1);
+
+ // Set the viewport
+ glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
+
+ // Init matrices
+ GLint worldMatrixLocation = glGetUniformLocation(mProgram, "uWorldMatrix");
+ ASSERT_NE(-1, worldMatrixLocation);
+ Matrix4 worldMatrix = Matrix4::translate(Vector3(0, 0, -3.0f));
+ worldMatrix *= Matrix4::rotate(25.0f, Vector3(0.6f, 1.0f, 0.0f));
+ glUniformMatrix4fv(worldMatrixLocation, 1, GL_FALSE, &worldMatrix.data[0]);
+
+ GLint projectionMatrixLocation = glGetUniformLocation(mProgram, "uProjectionMatrix");
+ ASSERT_NE(-1, projectionMatrixLocation);
+ float fov =
+ static_cast<float>(getWindow()->getWidth()) / static_cast<float>(getWindow()->getHeight());
+ Matrix4 projectionMatrix = Matrix4::perspective(60.0f, fov, 1.0f, 300.0f);
+ glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix.data[0]);
+
+ getWindow()->setVisible(true);
+
+ ASSERT_GL_NO_ERROR();
+}
+
+void InstancingPerfBenchmark::destroyBenchmark()
+{
+ glDeleteProgram(mProgram);
+
+ if (!mBuffers.empty())
+ {
+ glDeleteBuffers(static_cast<GLsizei>(mBuffers.size()), &mBuffers[0]);
+ mBuffers.clear();
+ }
+}
+
+void InstancingPerfBenchmark::drawBenchmark()
+{
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ const auto &params = GetParam();
+
+ // Animatino makes the test more interesting visually, but also eats up many CPU cycles.
+ if (params.animationEnabled)
+ {
+ // Not implemented for billboards.
+ ASSERT(params.instancingEnabled);
+
+ float time = static_cast<float>(mTimer->getElapsedTime());
+
+ for (size_t pointIndex = 0; pointIndex < mTranslateData.size(); ++pointIndex)
+ {
+ const Vector3 &translate = mTranslateData[pointIndex];
+
+ float tx = translate.x + time;
+ float ty = translate.y + time;
+ float tz = translate.z + time;
+
+ float scale = AnimationSignal(tx) * 0.01f + 0.01f;
+ mSizeData[pointIndex] = scale;
+
+ Vector3 color;
+ color.x = AnimationSignal(tx) * 0.5f + 0.5f;
+ color.y = AnimationSignal(ty) * 0.5f + 0.5f;
+ color.z = AnimationSignal(tz) * 0.5f + 0.5f;
+
+ mColorData[pointIndex] = color;
+ }
+ }
+
+ // Update scales and colors.
+ glBindBuffer(GL_ARRAY_BUFFER, mBuffers[3]);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, VectorSizeBytes(mSizeData), &mSizeData[0]);
+
+ glBindBuffer(GL_ARRAY_BUFFER, mBuffers[4]);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, VectorSizeBytes(mColorData), &mColorData[0]);
+
+ // Render the instances/billboards.
+ if (params.instancingEnabled)
+ {
+ for (unsigned int it = 0; it < params.iterations; it++)
+ {
+ glDrawElementsInstancedANGLE(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr, mNumPoints);
+ }
+ }
+ else
+ {
+ for (unsigned int it = 0; it < params.iterations; it++)
+ {
+ glDrawElements(GL_TRIANGLES, 6 * mNumPoints, GL_UNSIGNED_INT, nullptr);
+ }
+ }
+
+ ASSERT_GL_NO_ERROR();
+}
+
+InstancingPerfParams InstancingPerfD3D11Params()
+{
+ InstancingPerfParams params;
+ params.eglParameters = D3D11();
+ return params;
+}
+
+InstancingPerfParams InstancingPerfD3D9Params()
+{
+ InstancingPerfParams params;
+ params.eglParameters = D3D9();
+ return params;
+}
+
+InstancingPerfParams InstancingPerfOpenGLParams()
+{
+ InstancingPerfParams params;
+ params.eglParameters = OPENGL();
+ return params;
+}
+
+TEST_P(InstancingPerfBenchmark, Run)
+{
+ run();
+}
+
+ANGLE_INSTANTIATE_TEST(InstancingPerfBenchmark,
+ InstancingPerfD3D11Params(),
+ InstancingPerfD3D9Params(),
+ InstancingPerfOpenGLParams());
+
+} // anonymous namespace