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 // IndexConversionPerf:
7 // Performance tests for ANGLE index conversion in D3D11.
8 //
9
10 #include "ANGLEPerfTest.h"
11 #include "tests/test_utils/draw_call_perf_utils.h"
12
13 #include <sstream>
14
15 using namespace angle;
16
17 namespace
18 {
19 struct IndexConversionPerfParams final : public RenderTestParams
20 {
story__anon3739e9af0111::IndexConversionPerfParams21 std::string story() const override
22 {
23 std::stringstream strstr;
24
25 if (indexRangeOffset > 0)
26 {
27 strstr << "_index_range";
28 }
29
30 strstr << RenderTestParams::story();
31
32 return strstr.str();
33 }
34
35 unsigned int numIndexTris;
36
37 // A second test, which covers using index ranges with an offset.
38 unsigned int indexRangeOffset;
39 };
40
41 // Provide a custom gtest parameter name function for IndexConversionPerfParams.
operator <<(std::ostream & stream,const IndexConversionPerfParams & param)42 std::ostream &operator<<(std::ostream &stream, const IndexConversionPerfParams ¶m)
43 {
44 stream << param.backendAndStory().substr(1);
45 return stream;
46 }
47
48 class IndexConversionPerfTest : public ANGLERenderTest,
49 public ::testing::WithParamInterface<IndexConversionPerfParams>
50 {
51 public:
52 IndexConversionPerfTest();
53
54 void initializeBenchmark() override;
55 void destroyBenchmark() override;
56 void drawBenchmark() override;
57
58 private:
59 void updateBufferData();
60 void drawConversion();
61 void drawIndexRange();
62
63 GLuint mProgram;
64 GLuint mVertexBuffer;
65 GLuint mIndexBuffer;
66 std::vector<GLushort> mIndexData;
67 };
68
IndexConversionPerfTest()69 IndexConversionPerfTest::IndexConversionPerfTest()
70 : ANGLERenderTest("IndexConversionPerfTest", GetParam()),
71 mProgram(0),
72 mVertexBuffer(0),
73 mIndexBuffer(0)
74 {}
75
initializeBenchmark()76 void IndexConversionPerfTest::initializeBenchmark()
77 {
78 const auto ¶ms = GetParam();
79
80 ASSERT_LT(0u, params.iterationsPerStep);
81 ASSERT_LT(0u, params.numIndexTris);
82
83 mProgram = SetupSimpleScaleAndOffsetProgram();
84 ASSERT_NE(0u, mProgram);
85
86 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
87
88 // Initialize the vertex data
89 size_t numTris = std::numeric_limits<GLushort>::max() / 3 + 1;
90 mVertexBuffer = Create2DTriangleBuffer(numTris, GL_STATIC_DRAW);
91
92 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
93 glEnableVertexAttribArray(0);
94
95 // Initialize the index buffer
96 for (unsigned int triIndex = 0; triIndex < params.numIndexTris; ++triIndex)
97 {
98 // Handle two different types of tests, one with index conversion triggered by a -1 index.
99 if (params.indexRangeOffset == 0)
100 {
101 mIndexData.push_back(std::numeric_limits<GLushort>::max());
102 }
103 else
104 {
105 mIndexData.push_back(0);
106 }
107
108 mIndexData.push_back(1);
109 mIndexData.push_back(2);
110 }
111
112 glGenBuffers(1, &mIndexBuffer);
113 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
114 updateBufferData();
115
116 // Set the viewport
117 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
118
119 ASSERT_GL_NO_ERROR();
120 }
121
updateBufferData()122 void IndexConversionPerfTest::updateBufferData()
123 {
124 glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndexData.size() * sizeof(mIndexData[0]), &mIndexData[0],
125 GL_STATIC_DRAW);
126 }
127
destroyBenchmark()128 void IndexConversionPerfTest::destroyBenchmark()
129 {
130 glDeleteProgram(mProgram);
131 glDeleteBuffers(1, &mVertexBuffer);
132 glDeleteBuffers(1, &mIndexBuffer);
133 }
134
drawBenchmark()135 void IndexConversionPerfTest::drawBenchmark()
136 {
137 const auto ¶ms = GetParam();
138
139 if (params.indexRangeOffset == 0)
140 {
141 drawConversion();
142 }
143 else
144 {
145 drawIndexRange();
146 }
147 }
148
drawConversion()149 void IndexConversionPerfTest::drawConversion()
150 {
151 const auto ¶ms = GetParam();
152
153 // Trigger an update to ensure we convert once a frame
154 updateBufferData();
155
156 for (unsigned int it = 0; it < params.iterationsPerStep; it++)
157 {
158 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(params.numIndexTris * 3 - 1),
159 GL_UNSIGNED_SHORT, reinterpret_cast<void *>(0));
160 }
161
162 ASSERT_GL_NO_ERROR();
163 }
164
drawIndexRange()165 void IndexConversionPerfTest::drawIndexRange()
166 {
167 const auto ¶ms = GetParam();
168
169 unsigned int indexCount = 3;
170 size_t offset = static_cast<size_t>(indexCount * getNumStepsPerformed());
171
172 offset %= (params.numIndexTris * 3);
173
174 // This test increments an offset each step. Drawing repeatedly may cause the system memory
175 // to release. Then, using a fresh offset will require index range validation, which pages
176 // it back in. The performance should be good even if the data is was used quite a bit.
177 for (unsigned int it = 0; it < params.iterationsPerStep; it++)
178 {
179 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indexCount), GL_UNSIGNED_SHORT,
180 reinterpret_cast<void *>(offset));
181 }
182
183 ASSERT_GL_NO_ERROR();
184 }
185
IndexConversionPerfD3D11Params()186 IndexConversionPerfParams IndexConversionPerfD3D11Params()
187 {
188 IndexConversionPerfParams params;
189 params.eglParameters = egl_platform::D3D11_NULL();
190 params.majorVersion = 2;
191 params.minorVersion = 0;
192 params.windowWidth = 256;
193 params.windowHeight = 256;
194 params.iterationsPerStep = 225;
195 params.numIndexTris = 3000;
196 params.indexRangeOffset = 0;
197 return params;
198 }
199
IndexRangeOffsetPerfD3D11Params()200 IndexConversionPerfParams IndexRangeOffsetPerfD3D11Params()
201 {
202 IndexConversionPerfParams params;
203 params.eglParameters = egl_platform::D3D11_NULL();
204 params.majorVersion = 2;
205 params.minorVersion = 0;
206 params.windowWidth = 256;
207 params.windowHeight = 256;
208 params.iterationsPerStep = 16;
209 params.numIndexTris = 50000;
210 params.indexRangeOffset = 64;
211 return params;
212 }
213
TEST_P(IndexConversionPerfTest,Run)214 TEST_P(IndexConversionPerfTest, Run)
215 {
216 run();
217 }
218
219 ANGLE_INSTANTIATE_TEST(IndexConversionPerfTest,
220 IndexConversionPerfD3D11Params(),
221 IndexRangeOffsetPerfD3D11Params());
222
223 // This test suite is not instantiated on some OSes.
224 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(IndexConversionPerfTest);
225 } // namespace
226