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