diff options
Diffstat (limited to 'gfx/angle/src/tests/perf_tests/InstancingPerf.cpp')
-rwxr-xr-x | gfx/angle/src/tests/perf_tests/InstancingPerf.cpp | 366 |
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 ¶ms) +{ + 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 ¶ms = 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 ¶ms = 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 |