xref: /aosp_15_r20/external/angle/src/tests/perf_tests/ProgramPipelineObjectPerfTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 &params)
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