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