| // |
| // 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. |
| // |
| // IndexConversionPerf: |
| // Performance tests for ANGLE index conversion in D3D11. |
| // |
| |
| #include "ANGLEPerfTest.h" |
| #include "tests/test_utils/draw_call_perf_utils.h" |
| |
| #include <sstream> |
| |
| using namespace angle; |
| |
| namespace |
| { |
| struct IndexConversionPerfParams final : public RenderTestParams |
| { |
| std::string story() const override |
| { |
| std::stringstream strstr; |
| |
| if (indexRangeOffset > 0) |
| { |
| strstr << "_index_range"; |
| } |
| |
| strstr << RenderTestParams::story(); |
| |
| return strstr.str(); |
| } |
| |
| unsigned int numIndexTris; |
| |
| // A second test, which covers using index ranges with an offset. |
| unsigned int indexRangeOffset; |
| }; |
| |
| // Provide a custom gtest parameter name function for IndexConversionPerfParams. |
| std::ostream &operator<<(std::ostream &stream, const IndexConversionPerfParams ¶m) |
| { |
| stream << param.backendAndStory().substr(1); |
| return stream; |
| } |
| |
| class IndexConversionPerfTest : public ANGLERenderTest, |
| public ::testing::WithParamInterface<IndexConversionPerfParams> |
| { |
| public: |
| IndexConversionPerfTest(); |
| |
| void initializeBenchmark() override; |
| void destroyBenchmark() override; |
| void drawBenchmark() override; |
| |
| private: |
| void updateBufferData(); |
| void drawConversion(); |
| void drawIndexRange(); |
| |
| GLuint mProgram; |
| GLuint mVertexBuffer; |
| GLuint mIndexBuffer; |
| std::vector<GLushort> mIndexData; |
| }; |
| |
| IndexConversionPerfTest::IndexConversionPerfTest() |
| : ANGLERenderTest("IndexConversionPerfTest", GetParam()), |
| mProgram(0), |
| mVertexBuffer(0), |
| mIndexBuffer(0) |
| {} |
| |
| void IndexConversionPerfTest::initializeBenchmark() |
| { |
| const auto ¶ms = GetParam(); |
| |
| ASSERT_LT(0u, params.iterationsPerStep); |
| ASSERT_LT(0u, params.numIndexTris); |
| |
| mProgram = SetupSimpleScaleAndOffsetProgram(); |
| ASSERT_NE(0u, mProgram); |
| |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| |
| // Initialize the vertex data |
| size_t numTris = std::numeric_limits<GLushort>::max() / 3 + 1; |
| mVertexBuffer = Create2DTriangleBuffer(numTris, GL_STATIC_DRAW); |
| |
| glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| glEnableVertexAttribArray(0); |
| |
| // Initialize the index buffer |
| for (unsigned int triIndex = 0; triIndex < params.numIndexTris; ++triIndex) |
| { |
| // Handle two different types of tests, one with index conversion triggered by a -1 index. |
| if (params.indexRangeOffset == 0) |
| { |
| mIndexData.push_back(std::numeric_limits<GLushort>::max()); |
| } |
| else |
| { |
| mIndexData.push_back(0); |
| } |
| |
| mIndexData.push_back(1); |
| mIndexData.push_back(2); |
| } |
| |
| glGenBuffers(1, &mIndexBuffer); |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); |
| updateBufferData(); |
| |
| // Set the viewport |
| glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void IndexConversionPerfTest::updateBufferData() |
| { |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexData.size() * sizeof(mIndexData[0]), &mIndexData[0], |
| GL_STATIC_DRAW); |
| } |
| |
| void IndexConversionPerfTest::destroyBenchmark() |
| { |
| glDeleteProgram(mProgram); |
| glDeleteBuffers(1, &mVertexBuffer); |
| glDeleteBuffers(1, &mIndexBuffer); |
| } |
| |
| void IndexConversionPerfTest::drawBenchmark() |
| { |
| const auto ¶ms = GetParam(); |
| |
| if (params.indexRangeOffset == 0) |
| { |
| drawConversion(); |
| } |
| else |
| { |
| drawIndexRange(); |
| } |
| } |
| |
| void IndexConversionPerfTest::drawConversion() |
| { |
| const auto ¶ms = GetParam(); |
| |
| // Trigger an update to ensure we convert once a frame |
| updateBufferData(); |
| |
| for (unsigned int it = 0; it < params.iterationsPerStep; it++) |
| { |
| glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(params.numIndexTris * 3 - 1), |
| GL_UNSIGNED_SHORT, reinterpret_cast<void *>(0)); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| void IndexConversionPerfTest::drawIndexRange() |
| { |
| const auto ¶ms = GetParam(); |
| |
| unsigned int indexCount = 3; |
| size_t offset = static_cast<size_t>(indexCount * getNumStepsPerformed()); |
| |
| offset %= (params.numIndexTris * 3); |
| |
| // This test increments an offset each step. Drawing repeatedly may cause the system memory |
| // to release. Then, using a fresh offset will require index range validation, which pages |
| // it back in. The performance should be good even if the data is was used quite a bit. |
| for (unsigned int it = 0; it < params.iterationsPerStep; it++) |
| { |
| glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indexCount), GL_UNSIGNED_SHORT, |
| reinterpret_cast<void *>(offset)); |
| } |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| IndexConversionPerfParams IndexConversionPerfD3D11Params() |
| { |
| IndexConversionPerfParams params; |
| params.eglParameters = egl_platform::D3D11_NULL(); |
| params.majorVersion = 2; |
| params.minorVersion = 0; |
| params.windowWidth = 256; |
| params.windowHeight = 256; |
| params.iterationsPerStep = 225; |
| params.numIndexTris = 3000; |
| params.indexRangeOffset = 0; |
| return params; |
| } |
| |
| IndexConversionPerfParams IndexRangeOffsetPerfD3D11Params() |
| { |
| IndexConversionPerfParams params; |
| params.eglParameters = egl_platform::D3D11_NULL(); |
| params.majorVersion = 2; |
| params.minorVersion = 0; |
| params.windowWidth = 256; |
| params.windowHeight = 256; |
| params.iterationsPerStep = 16; |
| params.numIndexTris = 50000; |
| params.indexRangeOffset = 64; |
| return params; |
| } |
| |
| TEST_P(IndexConversionPerfTest, Run) |
| { |
| run(); |
| } |
| |
| ANGLE_INSTANTIATE_TEST(IndexConversionPerfTest, |
| IndexConversionPerfD3D11Params(), |
| IndexRangeOffsetPerfD3D11Params()); |
| } // namespace |