1 //
2 // Copyright 2021 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 // VertexArrayPerfTest:
7 // Performance test for glBindVertexArray.
8 //
9
10 #include "ANGLEPerfTest.h"
11 #include "DrawCallPerfParams.h"
12 #include "test_utils/gl_raii.h"
13
14 using namespace angle;
15
16 namespace
17 {
18 enum class TestMode
19 {
20 BufferData,
21 BindBuffer,
22 UpdateBufferData,
23 };
24
25 struct VertexArrayParams final : public RenderTestParams
26 {
VertexArrayParams__anon5ac9623f0111::VertexArrayParams27 VertexArrayParams()
28 {
29 iterationsPerStep = 1;
30
31 // Common default params
32 majorVersion = 3;
33 minorVersion = 0;
34 windowWidth = 720;
35 windowHeight = 720;
36 }
37
38 std::string story() const override;
39
40 int numVertexArrays = 2000;
41 int numBuffers = 5;
42 GLuint bufferSize[5] = {384, 1028, 192, 384, 192};
43 TestMode testMode = TestMode::BufferData;
44 };
45
operator <<(std::ostream & os,const VertexArrayParams & params)46 std::ostream &operator<<(std::ostream &os, const VertexArrayParams ¶ms)
47 {
48 os << params.backendAndStory().substr(1);
49 return os;
50 }
51
story() const52 std::string VertexArrayParams::story() const
53 {
54 std::stringstream strstr;
55
56 strstr << RenderTestParams::story();
57
58 if (testMode == TestMode::BindBuffer)
59 {
60 strstr << "_bindbuffer";
61 }
62 else if (testMode == TestMode::UpdateBufferData)
63 {
64 strstr << "_updatebufferdata";
65 }
66
67 return strstr.str();
68 }
69
70 class VertexArrayBenchmark : public ANGLERenderTest,
71 public ::testing::WithParamInterface<VertexArrayParams>
72 {
73 public:
74 VertexArrayBenchmark();
75
76 void initializeBenchmark() override;
77 void destroyBenchmark() override;
78 void drawBenchmark() override;
79
80 void rebindVertexArray(GLuint vertexArrayID, GLuint bufferID);
81 void updateBufferData(GLuint vertexArrayID, GLuint bufferID, GLuint bufferSize);
82
83 private:
84 std::vector<GLuint> mBuffers;
85 GLuint mProgram = 0;
86 GLint mAttribLocation = 0;
87 std::vector<GLuint> mVertexArrays;
88 };
89
VertexArrayBenchmark()90 VertexArrayBenchmark::VertexArrayBenchmark() : ANGLERenderTest("VertexArrayPerf", GetParam()) {}
91
initializeBenchmark()92 void VertexArrayBenchmark::initializeBenchmark()
93 {
94 constexpr char kVS[] = R"(attribute vec4 position;
95 attribute float in_attrib;
96 varying float v_attrib;
97 void main()
98 {
99 v_attrib = in_attrib;
100 gl_Position = position;
101 })";
102
103 constexpr char kFS[] = R"(precision mediump float;
104 varying float v_attrib;
105 void main()
106 {
107 gl_FragColor = vec4(v_attrib, 0, 0, 1);
108 })";
109
110 mProgram = CompileProgram(kVS, kFS);
111 ASSERT_NE(0u, mProgram);
112
113 mAttribLocation = glGetAttribLocation(mProgram, "in_attrib");
114 ASSERT_NE(mAttribLocation, -1);
115
116 // Generate 5 buffers.
117 int numBuffers = GetParam().numBuffers;
118 mBuffers.resize(numBuffers, 0);
119 glGenBuffers(numBuffers, mBuffers.data());
120
121 int numVertexArrays = GetParam().numVertexArrays;
122 mVertexArrays.resize(numVertexArrays, 0);
123 glGenVertexArrays(numVertexArrays, mVertexArrays.data());
124
125 // Bind one VBO to all VAOs.
126 for (GLuint vertexArray : mVertexArrays)
127 {
128 rebindVertexArray(vertexArray, mBuffers[0]);
129 }
130
131 glBindVertexArray(0);
132 glBindBuffer(GL_ARRAY_BUFFER, mBuffers[0]);
133 }
134
rebindVertexArray(GLuint vertexArrayID,GLuint bufferID)135 void VertexArrayBenchmark::rebindVertexArray(GLuint vertexArrayID, GLuint bufferID)
136 {
137 // Rebind a vertex array object and a generic vertex attribute inside of it.
138 glBindVertexArray(vertexArrayID);
139 glBindBuffer(GL_ARRAY_BUFFER, bufferID);
140 glEnableVertexAttribArray(mAttribLocation);
141 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
142 glVertexAttribDivisor(mAttribLocation, 1);
143 glBindVertexArray(0);
144 glBindBuffer(GL_ARRAY_BUFFER, 0);
145 }
146
updateBufferData(GLuint vertexArrayID,GLuint bufferID,GLuint bufferSize)147 void VertexArrayBenchmark::updateBufferData(GLuint vertexArrayID,
148 GLuint bufferID,
149 GLuint bufferSize)
150 {
151 glBindVertexArray(vertexArrayID);
152 glBindBuffer(GL_ARRAY_BUFFER, bufferID);
153 glEnableVertexAttribArray(mAttribLocation);
154 glVertexAttribPointer(mAttribLocation, 1, GL_FLOAT, GL_FALSE, 4, nullptr);
155 glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW);
156 glBindVertexArray(0);
157 glBindBuffer(GL_ARRAY_BUFFER, 0);
158 }
159
destroyBenchmark()160 void VertexArrayBenchmark::destroyBenchmark()
161 {
162 glDeleteProgram(mProgram);
163 glDeleteVertexArrays(static_cast<GLsizei>(mVertexArrays.size()), mVertexArrays.data());
164 mVertexArrays.clear();
165 glDeleteBuffers(static_cast<GLsizei>(mBuffers.size()), mBuffers.data());
166 mBuffers.clear();
167 }
168
drawBenchmark()169 void VertexArrayBenchmark::drawBenchmark()
170 {
171 const VertexArrayParams ¶ms = GetParam();
172 if (params.testMode == TestMode::BufferData)
173 {
174 glBufferData(GL_ARRAY_BUFFER, 128, nullptr, GL_STATIC_DRAW);
175 }
176 else if (params.testMode == TestMode::UpdateBufferData)
177 {
178 int bufferSizeIndex = 0;
179 for (GLuint vertexArray : mVertexArrays)
180 {
181 bufferSizeIndex = ((bufferSizeIndex + 1) == 5) ? 0 : (bufferSizeIndex + 1);
182 updateBufferData(vertexArray, mBuffers[0], params.bufferSize[bufferSizeIndex]);
183 }
184 }
185 else
186 {
187 int bufferIndex = 0;
188 for (GLuint vertexArray : mVertexArrays)
189 {
190 bufferIndex = ((bufferIndex + 1) == params.numBuffers) ? 0 : (bufferIndex + 1);
191 rebindVertexArray(vertexArray, mBuffers[bufferIndex]);
192 }
193 }
194 }
195
TEST_P(VertexArrayBenchmark,Run)196 TEST_P(VertexArrayBenchmark, Run)
197 {
198 run();
199 }
200
MetalParams()201 VertexArrayParams MetalParams()
202 {
203 VertexArrayParams params;
204 params.eglParameters = egl_platform::METAL();
205 return params;
206 }
207
VulkanParams()208 VertexArrayParams VulkanParams()
209 {
210 VertexArrayParams params;
211 params.eglParameters = egl_platform::VULKAN();
212 return params;
213 }
214
VulkanNullParams(TestMode testMode)215 VertexArrayParams VulkanNullParams(TestMode testMode)
216 {
217 VertexArrayParams params;
218 params.eglParameters = egl_platform::VULKAN_NULL();
219 params.testMode = testMode;
220 return params;
221 }
222
223 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexArrayBenchmark);
224 ANGLE_INSTANTIATE_TEST(VertexArrayBenchmark,
225 MetalParams(),
226 VulkanParams(),
227 VulkanNullParams(TestMode::BindBuffer),
228 VulkanNullParams(TestMode::BufferData),
229 VulkanNullParams(TestMode::UpdateBufferData),
230 params::Native(VertexArrayParams()));
231 } // namespace
232