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 // LinkProgramPerfTest:
7 // Performance tests compiling a lot of shaders.
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 enum class TaskOption
23 {
24 CompileOnly,
25 CompileAndLink,
26
27 Unspecified
28 };
29
30 enum class ThreadOption
31 {
32 SingleThread,
33 MultiThread,
34
35 Unspecified
36 };
37
38 struct LinkProgramParams final : public RenderTestParams
39 {
LinkProgramParams__anonefc827280111::LinkProgramParams40 LinkProgramParams(TaskOption taskOptionIn, ThreadOption threadOptionIn)
41 {
42 iterationsPerStep = 1;
43
44 majorVersion = 2;
45 minorVersion = 0;
46 windowWidth = 256;
47 windowHeight = 256;
48 taskOption = taskOptionIn;
49 threadOption = threadOptionIn;
50 }
51
story__anonefc827280111::LinkProgramParams52 std::string story() const override
53 {
54 std::stringstream strstr;
55 strstr << RenderTestParams::story();
56
57 if (taskOption == TaskOption::CompileOnly)
58 {
59 strstr << "_compile_only";
60 }
61 else if (taskOption == TaskOption::CompileAndLink)
62 {
63 strstr << "_compile_and_link";
64 }
65
66 if (threadOption == ThreadOption::SingleThread)
67 {
68 strstr << "_single_thread";
69 }
70 else if (threadOption == ThreadOption::MultiThread)
71 {
72 strstr << "_multi_thread";
73 }
74
75 if (eglParameters.deviceType == EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE)
76 {
77 strstr << "_null";
78 }
79
80 return strstr.str();
81 }
82
83 TaskOption taskOption;
84 ThreadOption threadOption;
85 };
86
operator <<(std::ostream & os,const LinkProgramParams & params)87 std::ostream &operator<<(std::ostream &os, const LinkProgramParams ¶ms)
88 {
89 os << params.backendAndStory().substr(1);
90 return os;
91 }
92
93 class LinkProgramBenchmark : public ANGLERenderTest,
94 public ::testing::WithParamInterface<LinkProgramParams>
95 {
96 public:
97 LinkProgramBenchmark();
98
99 void initializeBenchmark() override;
100 void destroyBenchmark() override;
101 void drawBenchmark() override;
102
103 protected:
104 GLuint mVertexBuffer = 0;
105 };
106
LinkProgramBenchmark()107 LinkProgramBenchmark::LinkProgramBenchmark() : ANGLERenderTest("LinkProgram", GetParam()) {}
108
initializeBenchmark()109 void LinkProgramBenchmark::initializeBenchmark()
110 {
111 if (GetParam().threadOption != ThreadOption::SingleThread &&
112 !IsGLExtensionEnabled("GL_KHR_parallel_shader_compile"))
113 {
114 skipTest("non-single-thread but missing GL_KHR_parallel_shader_compile");
115 return;
116 }
117
118 if (IsGLExtensionEnabled("GL_KHR_parallel_shader_compile") &&
119 GetParam().threadOption == ThreadOption::SingleThread)
120 {
121 glMaxShaderCompilerThreadsKHR(0);
122 }
123
124 std::array<Vector3, 6> vertices = {{Vector3(-1.0f, 1.0f, 0.5f), Vector3(-1.0f, -1.0f, 0.5f),
125 Vector3(1.0f, -1.0f, 0.5f), Vector3(-1.0f, 1.0f, 0.5f),
126 Vector3(1.0f, -1.0f, 0.5f), Vector3(1.0f, 1.0f, 0.5f)}};
127
128 glGenBuffers(1, &mVertexBuffer);
129 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
130 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vector3), vertices.data(),
131 GL_STATIC_DRAW);
132 }
133
destroyBenchmark()134 void LinkProgramBenchmark::destroyBenchmark()
135 {
136 glDeleteBuffers(1, &mVertexBuffer);
137 }
138
drawBenchmark()139 void LinkProgramBenchmark::drawBenchmark()
140 {
141 static const char *vertexShader =
142 "attribute vec2 position;\n"
143 "void main() {\n"
144 " gl_Position = vec4(position, 0, 1);\n"
145 "}";
146 static const char *fragmentShader =
147 "precision mediump float;\n"
148 "void main() {\n"
149 " gl_FragColor = vec4(1, 0, 0, 1);\n"
150 "}";
151 GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
152 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
153
154 ASSERT_NE(0u, vs);
155 ASSERT_NE(0u, fs);
156 if (GetParam().taskOption == TaskOption::CompileOnly)
157 {
158 glDeleteShader(vs);
159 glDeleteShader(fs);
160 return;
161 }
162
163 GLuint program = glCreateProgram();
164 ASSERT_NE(0u, program);
165
166 glAttachShader(program, vs);
167 glDeleteShader(vs);
168 glAttachShader(program, fs);
169 glDeleteShader(fs);
170 glLinkProgram(program);
171 glUseProgram(program);
172
173 GLint positionLoc = glGetAttribLocation(program, "position");
174 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 8, nullptr);
175 glEnableVertexAttribArray(positionLoc);
176
177 // Draw with the program to ensure the shader gets compiled and used.
178 glDrawArrays(GL_TRIANGLES, 0, 6);
179
180 glDeleteProgram(program);
181 }
182
183 using namespace egl_platform;
184
LinkProgramD3D11Params(TaskOption taskOption,ThreadOption threadOption)185 LinkProgramParams LinkProgramD3D11Params(TaskOption taskOption, ThreadOption threadOption)
186 {
187 LinkProgramParams params(taskOption, threadOption);
188 params.eglParameters = D3D11();
189 return params;
190 }
191
LinkProgramMetalParams(TaskOption taskOption,ThreadOption threadOption)192 LinkProgramParams LinkProgramMetalParams(TaskOption taskOption, ThreadOption threadOption)
193 {
194 LinkProgramParams params(taskOption, threadOption);
195 params.eglParameters = METAL();
196 return params;
197 }
198
LinkProgramOpenGLOrGLESParams(TaskOption taskOption,ThreadOption threadOption)199 LinkProgramParams LinkProgramOpenGLOrGLESParams(TaskOption taskOption, ThreadOption threadOption)
200 {
201 LinkProgramParams params(taskOption, threadOption);
202 params.eglParameters = OPENGL_OR_GLES();
203 return params;
204 }
205
LinkProgramVulkanParams(TaskOption taskOption,ThreadOption threadOption)206 LinkProgramParams LinkProgramVulkanParams(TaskOption taskOption, ThreadOption threadOption)
207 {
208 LinkProgramParams params(taskOption, threadOption);
209 params.eglParameters = VULKAN();
210 return params;
211 }
212
TEST_P(LinkProgramBenchmark,Run)213 TEST_P(LinkProgramBenchmark, Run)
214 {
215 run();
216 }
217
218 ANGLE_INSTANTIATE_TEST(
219 LinkProgramBenchmark,
220 LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
221 LinkProgramMetalParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
222 LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
223 LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
224 LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
225 LinkProgramMetalParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
226 LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
227 LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
228 LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::SingleThread),
229 LinkProgramMetalParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
230 LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
231 LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
232 LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::SingleThread),
233 LinkProgramMetalParams(TaskOption::CompileAndLink, ThreadOption::SingleThread),
234 LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::SingleThread),
235 LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::SingleThread));
236
237 } // anonymous namespace
238