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__anon8c249fff0111::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__anon8c249fff0111::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 &params)
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     {
113         glMaxShaderCompilerThreadsKHR(0);
114     }
115 
116     std::array<Vector3, 6> vertices = {{Vector3(-1.0f, 1.0f, 0.5f), Vector3(-1.0f, -1.0f, 0.5f),
117                                         Vector3(1.0f, -1.0f, 0.5f), Vector3(-1.0f, 1.0f, 0.5f),
118                                         Vector3(1.0f, -1.0f, 0.5f), Vector3(1.0f, 1.0f, 0.5f)}};
119 
120     glGenBuffers(1, &mVertexBuffer);
121     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
122     glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vector3), vertices.data(),
123                  GL_STATIC_DRAW);
124 }
125 
destroyBenchmark()126 void LinkProgramBenchmark::destroyBenchmark()
127 {
128     glDeleteBuffers(1, &mVertexBuffer);
129 }
130 
drawBenchmark()131 void LinkProgramBenchmark::drawBenchmark()
132 {
133     static const char *vertexShader =
134         "attribute vec2 position;\n"
135         "void main() {\n"
136         "    gl_Position = vec4(position, 0, 1);\n"
137         "}";
138     static const char *fragmentShader =
139         "precision mediump float;\n"
140         "void main() {\n"
141         "    gl_FragColor = vec4(1, 0, 0, 1);\n"
142         "}";
143     GLuint vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
144     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
145 
146     ASSERT_NE(0u, vs);
147     ASSERT_NE(0u, fs);
148     if (GetParam().taskOption == TaskOption::CompileOnly)
149     {
150         glDeleteShader(vs);
151         glDeleteShader(fs);
152         return;
153     }
154 
155     GLuint program = glCreateProgram();
156     ASSERT_NE(0u, program);
157 
158     glAttachShader(program, vs);
159     glDeleteShader(vs);
160     glAttachShader(program, fs);
161     glDeleteShader(fs);
162     glLinkProgram(program);
163     glUseProgram(program);
164 
165     GLint positionLoc = glGetAttribLocation(program, "position");
166     glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 8, nullptr);
167     glEnableVertexAttribArray(positionLoc);
168 
169     // Draw with the program to ensure the shader gets compiled and used.
170     glDrawArrays(GL_TRIANGLES, 0, 6);
171 
172     glDeleteProgram(program);
173 }
174 
175 using namespace egl_platform;
176 
LinkProgramD3D11Params(TaskOption taskOption,ThreadOption threadOption)177 LinkProgramParams LinkProgramD3D11Params(TaskOption taskOption, ThreadOption threadOption)
178 {
179     LinkProgramParams params(taskOption, threadOption);
180     params.eglParameters = D3D11();
181     return params;
182 }
183 
LinkProgramOpenGLOrGLESParams(TaskOption taskOption,ThreadOption threadOption)184 LinkProgramParams LinkProgramOpenGLOrGLESParams(TaskOption taskOption, ThreadOption threadOption)
185 {
186     LinkProgramParams params(taskOption, threadOption);
187     params.eglParameters = OPENGL_OR_GLES();
188     return params;
189 }
190 
LinkProgramVulkanParams(TaskOption taskOption,ThreadOption threadOption)191 LinkProgramParams LinkProgramVulkanParams(TaskOption taskOption, ThreadOption threadOption)
192 {
193     LinkProgramParams params(taskOption, threadOption);
194     params.eglParameters = VULKAN();
195     return params;
196 }
197 
TEST_P(LinkProgramBenchmark,Run)198 TEST_P(LinkProgramBenchmark, Run)
199 {
200     run();
201 }
202 
203 ANGLE_INSTANTIATE_TEST(
204     LinkProgramBenchmark,
205     LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::MultiThread),
206     LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
207     LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::MultiThread),
208     LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::MultiThread),
209     LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
210     LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::MultiThread),
211     LinkProgramD3D11Params(TaskOption::CompileOnly, ThreadOption::SingleThread),
212     LinkProgramOpenGLOrGLESParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
213     LinkProgramVulkanParams(TaskOption::CompileOnly, ThreadOption::SingleThread),
214     LinkProgramD3D11Params(TaskOption::CompileAndLink, ThreadOption::SingleThread),
215     LinkProgramOpenGLOrGLESParams(TaskOption::CompileAndLink, ThreadOption::SingleThread),
216     LinkProgramVulkanParams(TaskOption::CompileAndLink, ThreadOption::SingleThread));
217 
218 }  // anonymous namespace
219