• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param)
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 &params = 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 &params = 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 &params = 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 &params = 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