1 //
2 // Copyright 2022 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 // ProgramPipelineObjectPerfTest:
7 // Performance tests switching program stages of a pipeline.
8 //
9
10 #include "ANGLEPerfTest.h"
11
12 #include <array>
13
14 #include "common/vector_utils.h"
15 #include "util/shader_utils.h"
16
17 using namespace angle;
18
19 namespace
20 {
21
22 constexpr unsigned int kIterationsPerStep = 1024;
23
24 struct ProgramPipelineObjectParams final : public RenderTestParams
25 {
ProgramPipelineObjectParams__anon1bcf8de70111::ProgramPipelineObjectParams26 ProgramPipelineObjectParams()
27 {
28 iterationsPerStep = kIterationsPerStep;
29
30 majorVersion = 3;
31 minorVersion = 1;
32 windowWidth = 256;
33 windowHeight = 256;
34 }
35
story__anon1bcf8de70111::ProgramPipelineObjectParams36 std::string story() const override
37 {
38 std::stringstream strstr;
39 strstr << RenderTestParams::story();
40
41 if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
42 {
43 strstr << "_null";
44 }
45
46 return strstr.str();
47 }
48 };
49
operator <<(std::ostream & os,const ProgramPipelineObjectParams & params)50 std::ostream &operator<<(std::ostream &os, const ProgramPipelineObjectParams ¶ms)
51 {
52 os << params.backendAndStory().substr(1);
53 return os;
54 }
55
56 class ProgramPipelineObjectBenchmark
57 : public ANGLERenderTest,
58 public ::testing::WithParamInterface<ProgramPipelineObjectParams>
59 {
60 public:
61 ProgramPipelineObjectBenchmark();
62
63 void initializeBenchmark() override;
64 void destroyBenchmark() override;
65 void drawBenchmark() override;
66
67 protected:
68 GLuint mVertProg1 = 0;
69 GLuint mVertProg2 = 0;
70 GLuint mFragProg1 = 0;
71 GLuint mFragProg2 = 0;
72 GLuint mPpo = 0;
73 };
74
ProgramPipelineObjectBenchmark()75 ProgramPipelineObjectBenchmark::ProgramPipelineObjectBenchmark()
76 : ANGLERenderTest("ProgramPipelineObject", GetParam())
77 {}
78
initializeBenchmark()79 void ProgramPipelineObjectBenchmark::initializeBenchmark()
80 {
81 glGenProgramPipelines(1, &mPpo);
82 glBindProgramPipeline(mPpo);
83
84 // Create 2 separable vertex and fragment program objects from the same source.
85 const GLchar *vertString = essl31_shaders::vs::Simple();
86 const GLchar *fragString = R"(#version 310 es
87 precision highp float;
88 uniform float redColorIn;
89 uniform float greenColorIn;
90 out vec4 my_FragColor;
91 void main()
92 {
93 my_FragColor = vec4(redColorIn, greenColorIn, 0.0, 1.0);
94 })";
95
96 mVertProg1 = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
97 ASSERT_NE(mVertProg1, 0u);
98 mVertProg2 = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertString);
99 ASSERT_NE(mVertProg2, 0u);
100 mFragProg1 = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
101 ASSERT_NE(mFragProg1, 0u);
102 mFragProg2 = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragString);
103 ASSERT_NE(mFragProg2, 0u);
104 }
105
destroyBenchmark()106 void ProgramPipelineObjectBenchmark::destroyBenchmark()
107 {
108
109 glDeleteProgramPipelines(1, &mPpo);
110 glDeleteProgram(mVertProg1);
111 glDeleteProgram(mVertProg2);
112 glDeleteProgram(mFragProg1);
113 glDeleteProgram(mFragProg2);
114 }
115
drawBenchmark()116 void ProgramPipelineObjectBenchmark::drawBenchmark()
117 {
118 glUseProgramStages(mPpo, GL_VERTEX_SHADER_BIT, mVertProg1);
119 glUseProgramStages(mPpo, GL_FRAGMENT_SHADER_BIT, mFragProg1);
120
121 // Set the output color to red
122 GLint location = glGetUniformLocation(mFragProg1, "redColorIn");
123 glActiveShaderProgram(mPpo, mFragProg1);
124 glUniform1f(location, 1.0);
125 location = glGetUniformLocation(mFragProg1, "greenColorIn");
126 glActiveShaderProgram(mPpo, mFragProg1);
127 glUniform1f(location, 0.0);
128
129 // Change vertex and fragment programs of the pipeline before the draw.
130 glUseProgramStages(mPpo, GL_VERTEX_SHADER_BIT, mVertProg2);
131 glUseProgramStages(mPpo, GL_FRAGMENT_SHADER_BIT, mFragProg2);
132
133 // Set the output color to green
134 location = glGetUniformLocation(mFragProg2, "redColorIn");
135 glActiveShaderProgram(mPpo, mFragProg2);
136 glUniform1f(location, 0.0);
137 location = glGetUniformLocation(mFragProg2, "greenColorIn");
138 glActiveShaderProgram(mPpo, mFragProg2);
139 glUniform1f(location, 1.0);
140
141 // Draw
142 const std::array<Vector3, 6> kQuadVertices = {{
143 Vector3(-1.0f, 1.0f, 0.5f),
144 Vector3(-1.0f, -1.0f, 0.5f),
145 Vector3(1.0f, -1.0f, 0.5f),
146 Vector3(-1.0f, 1.0f, 0.5f),
147 }};
148
149 GLint positionLocation = glGetAttribLocation(mVertProg2, "a_position");
150 glBindBuffer(GL_ARRAY_BUFFER, 0);
151 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, kQuadVertices.data());
152 glEnableVertexAttribArray(positionLocation);
153
154 glDrawArrays(GL_TRIANGLES, 0, 6);
155
156 glDisableVertexAttribArray(positionLocation);
157 glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
158 }
159
160 using namespace egl_platform;
161
ProgramPipelineObjectVulkanParams()162 ProgramPipelineObjectParams ProgramPipelineObjectVulkanParams()
163 {
164 ProgramPipelineObjectParams params;
165 params.eglParameters = VULKAN();
166 return params;
167 }
168
ProgramPipelineObjectVulkanNullParams()169 ProgramPipelineObjectParams ProgramPipelineObjectVulkanNullParams()
170 {
171 ProgramPipelineObjectParams params;
172 params.eglParameters = VULKAN_NULL();
173 return params;
174 }
175
176 // Test performance of switching programs before a draw.
TEST_P(ProgramPipelineObjectBenchmark,Run)177 TEST_P(ProgramPipelineObjectBenchmark, Run)
178 {
179 run();
180 }
181
182 ANGLE_INSTANTIATE_TEST(ProgramPipelineObjectBenchmark,
183 ProgramPipelineObjectVulkanParams(),
184 ProgramPipelineObjectVulkanNullParams());
185
186 } // anonymous namespace
187