xref: /aosp_15_r20/external/angle/src/tests/perf_tests/BindingPerf.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2016 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 // BindingPerf:
7 //   Performance test for binding objects
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <iostream>
13 #include <random>
14 #include <sstream>
15 
16 #include "test_utils/angle_test_instantiate.h"
17 #include "util/shader_utils.h"
18 
19 namespace angle
20 {
21 namespace
22 {
23 constexpr unsigned int kIterationsPerStep = 128;
24 
25 enum TestMode
26 {
27     VertexArray,
28     MultipleBindings,
29 };
30 
31 enum AllocationStyle
32 {
33     EVERY_ITERATION,
34     AT_INITIALIZATION
35 };
36 
37 struct BindingsParams final : public RenderTestParams
38 {
BindingsParamsangle::__anon94a4391d0111::BindingsParams39     BindingsParams()
40     {
41         // Common default params
42         majorVersion = 2;
43         minorVersion = 0;
44         windowWidth  = 720;
45         windowHeight = 720;
46 
47         numObjects        = 100;
48         allocationStyle   = EVERY_ITERATION;
49         iterationsPerStep = kIterationsPerStep;
50     }
51 
52     std::string story() const override;
53     TestMode testMode = TestMode::MultipleBindings;
54     size_t numObjects;
55     AllocationStyle allocationStyle;
56 };
57 
operator <<(std::ostream & os,const BindingsParams & params)58 std::ostream &operator<<(std::ostream &os, const BindingsParams &params)
59 {
60     os << params.backendAndStory().substr(1);
61     return os;
62 }
63 
story() const64 std::string BindingsParams::story() const
65 {
66     std::stringstream strstr;
67 
68     strstr << RenderTestParams::story();
69 
70     if (testMode == TestMode::VertexArray)
71     {
72         strstr << "_vertexarray";
73     }
74     else
75     {
76         strstr << "_" << numObjects << "_objects";
77 
78         switch (allocationStyle)
79         {
80             case EVERY_ITERATION:
81                 strstr << "_allocated_every_iteration";
82                 break;
83             case AT_INITIALIZATION:
84                 strstr << "_allocated_at_initialization";
85                 break;
86             default:
87                 strstr << "_err";
88                 break;
89         }
90     }
91 
92     return strstr.str();
93 }
94 
95 class BindingsBenchmark : public ANGLERenderTest,
96                           public ::testing::WithParamInterface<BindingsParams>
97 {
98   public:
99     BindingsBenchmark();
100 
101     void initializeBenchmark() override;
102     void destroyBenchmark() override;
103     void drawBenchmark() override;
104 
105   private:
106     // TODO: Test binding perf of more than just buffers
107     std::vector<GLuint> mBuffers;
108     std::vector<GLenum> mBindingPoints;
109     GLuint mMaxVertexAttribs = 0;
110 };
111 
BindingsBenchmark()112 BindingsBenchmark::BindingsBenchmark() : ANGLERenderTest("Bindings", GetParam())
113 {
114     if (GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
115     {
116         skipTest("http://anglebug.com/42264783 Flaky on OpenGL");
117     }
118 }
119 
initializeBenchmark()120 void BindingsBenchmark::initializeBenchmark()
121 {
122     const BindingsParams &params = GetParam();
123 
124     mBuffers.resize(params.numObjects, 0);
125     if (params.allocationStyle == AT_INITIALIZATION)
126     {
127         glGenBuffers(static_cast<GLsizei>(mBuffers.size()), mBuffers.data());
128         for (size_t bufferIdx = 0; bufferIdx < mBuffers.size(); bufferIdx++)
129         {
130             glBindBuffer(GL_ARRAY_BUFFER, mBuffers[bufferIdx]);
131         }
132         glBindBuffer(GL_ARRAY_BUFFER, 0);
133     }
134 
135     if (params.testMode == TestMode::MultipleBindings)
136     {
137         mBindingPoints.push_back(GL_ARRAY_BUFFER);
138         mBindingPoints.push_back(GL_ELEMENT_ARRAY_BUFFER);
139         if (params.majorVersion >= 3)
140         {
141             mBindingPoints.push_back(GL_PIXEL_PACK_BUFFER);
142             mBindingPoints.push_back(GL_PIXEL_UNPACK_BUFFER);
143             mBindingPoints.push_back(GL_COPY_READ_BUFFER);
144             mBindingPoints.push_back(GL_COPY_WRITE_BUFFER);
145             mBindingPoints.push_back(GL_TRANSFORM_FEEDBACK_BUFFER);
146             mBindingPoints.push_back(GL_UNIFORM_BUFFER);
147         }
148         if (params.majorVersion > 3 || (params.majorVersion == 3 && params.minorVersion >= 1))
149         {
150             mBindingPoints.push_back(GL_ATOMIC_COUNTER_BUFFER);
151             mBindingPoints.push_back(GL_SHADER_STORAGE_BUFFER);
152             mBindingPoints.push_back(GL_DRAW_INDIRECT_BUFFER);
153             mBindingPoints.push_back(GL_DISPATCH_INDIRECT_BUFFER);
154         }
155     }
156     else
157     {
158         mBindingPoints.resize(mBuffers.size(), GL_ARRAY_BUFFER);
159     }
160 
161     glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, reinterpret_cast<GLint *>(&mMaxVertexAttribs));
162 }
163 
destroyBenchmark()164 void BindingsBenchmark::destroyBenchmark()
165 {
166     const BindingsParams &params = GetParam();
167     if (params.allocationStyle == AT_INITIALIZATION)
168     {
169         glDeleteBuffers(static_cast<GLsizei>(mBuffers.size()), mBuffers.data());
170     }
171 }
172 
drawBenchmark()173 void BindingsBenchmark::drawBenchmark()
174 {
175     const BindingsParams &params = GetParam();
176 
177     for (unsigned int it = 0; it < params.iterationsPerStep; ++it)
178     {
179         // Generate a buffer (if needed) and bind it to a "random" binding point
180         if (params.allocationStyle == EVERY_ITERATION)
181         {
182             glGenBuffers(static_cast<GLsizei>(mBuffers.size()), mBuffers.data());
183         }
184 
185         // Fetch a few variables from the underlying data structure to keep them in registers.
186         // Otherwise each loop iteration they'll be fetched again because the compiler cannot
187         // guarantee that those are unchanged when calling glBindBuffer.
188         const GLuint *buffers       = mBuffers.data();
189         const GLenum *bindingPoints = mBindingPoints.data();
190         size_t bindingPointsSize    = mBindingPoints.size();
191         size_t buffersSize          = mBuffers.size();
192         size_t bindingIndex         = it % bindingPointsSize;
193         for (GLuint bufferIdx = 0; bufferIdx < buffersSize; bufferIdx++)
194         {
195             GLenum binding = bindingPoints[bindingIndex];
196             glBindBuffer(binding, buffers[bufferIdx]);
197 
198             // Instead of doing a costly division to get an index in the range [0,bindingPointsSize)
199             // do a bounds-check and reset the index.
200             ++bindingIndex;
201             bindingIndex = (bindingIndex >= bindingPointsSize) ? 0 : bindingIndex;
202 
203             if (params.testMode == TestMode::VertexArray)
204             {
205                 GLuint vertexAttribIndex = bufferIdx % mMaxVertexAttribs;
206                 glVertexAttribPointer(vertexAttribIndex, 1, GL_FLOAT, GL_FALSE, 0, 0);
207             }
208         }
209 
210         // Delete all the buffers
211         if (params.allocationStyle == EVERY_ITERATION)
212         {
213             glDeleteBuffers(static_cast<GLsizei>(mBuffers.size()), mBuffers.data());
214         }
215     }
216 
217     ASSERT_GL_NO_ERROR();
218 }
219 
D3D11Params(AllocationStyle allocationStyle)220 BindingsParams D3D11Params(AllocationStyle allocationStyle)
221 {
222     BindingsParams params;
223     params.eglParameters   = egl_platform::D3D11_NULL();
224     params.allocationStyle = allocationStyle;
225     return params;
226 }
227 
OpenGLOrGLESParams(AllocationStyle allocationStyle)228 BindingsParams OpenGLOrGLESParams(AllocationStyle allocationStyle)
229 {
230     BindingsParams params;
231     params.eglParameters   = egl_platform::OPENGL_OR_GLES_NULL();
232     params.allocationStyle = allocationStyle;
233     return params;
234 }
235 
VulkanParams(AllocationStyle allocationStyle,TestMode testMode)236 BindingsParams VulkanParams(AllocationStyle allocationStyle, TestMode testMode)
237 {
238     BindingsParams params;
239     params.eglParameters   = egl_platform::VULKAN_NULL();
240     params.allocationStyle = allocationStyle;
241     params.testMode        = testMode;
242     return params;
243 }
244 
TEST_P(BindingsBenchmark,Run)245 TEST_P(BindingsBenchmark, Run)
246 {
247     run();
248 }
249 }  // namespace
250 
251 ANGLE_INSTANTIATE_TEST(BindingsBenchmark,
252                        D3D11Params(EVERY_ITERATION),
253                        D3D11Params(AT_INITIALIZATION),
254                        OpenGLOrGLESParams(EVERY_ITERATION),
255                        OpenGLOrGLESParams(AT_INITIALIZATION),
256                        VulkanParams(EVERY_ITERATION, TestMode::MultipleBindings),
257                        VulkanParams(AT_INITIALIZATION, TestMode::MultipleBindings),
258                        VulkanParams(AT_INITIALIZATION, TestMode::VertexArray));
259 
260 }  // namespace angle
261