blob: 202c9c044e2c12e71d500cc2b837f5b49118c49f [file] [log] [blame]
//
// 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 <sstream>
#include "ANGLEPerfTest.h"
#include "tests/test_utils/draw_call_perf_utils.h"
using namespace angle;
namespace
{
struct IndexConversionPerfParams final : public RenderTestParams
{
std::string suffix() const override
{
std::stringstream strstr;
if (indexRangeOffset > 0)
{
strstr << "_index_range";
}
strstr << RenderTestParams::suffix();
return strstr.str();
}
unsigned int iterations;
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 &param)
{
stream << param.suffix().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)
{
mRunTimeSeconds = 3.0;
}
void IndexConversionPerfTest::initializeBenchmark()
{
const auto &params = GetParam();
ASSERT_LT(0u, params.iterations);
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 &params = GetParam();
if (params.indexRangeOffset == 0)
{
drawConversion();
}
else
{
drawIndexRange();
}
}
void IndexConversionPerfTest::drawConversion()
{
const auto &params = GetParam();
// Trigger an update to ensure we convert once a frame
updateBufferData();
for (unsigned int it = 0; it < params.iterations; 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 &params = 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.iterations; 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.iterations = 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.iterations = 16;
params.numIndexTris = 50000;
params.indexRangeOffset = 64;
return params;
}
TEST_P(IndexConversionPerfTest, Run)
{
run();
}
ANGLE_INSTANTIATE_TEST(IndexConversionPerfTest,
IndexConversionPerfD3D11Params(),
IndexRangeOffsetPerfD3D11Params());
} // namespace