blob: fd3277e1726a6008dbb59939419f336e7730e859 [file] [log] [blame]
jchen1082af6202018-06-22 10:59:52 +08001//
2// Copyright 2018 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
7// ParallelShaderCompileTest.cpp : Tests of the GL_KHR_parallel_shader_compile extension.
8
9#include "test_utils/ANGLETest.h"
10
jchen107ae70d82018-07-06 13:47:01 +080011#include "random_utils.h"
12
jchen1082af6202018-06-22 10:59:52 +080013using namespace angle;
14
15namespace
16{
17
18class ParallelShaderCompileTest : public ANGLETest
19{
20 protected:
21 ParallelShaderCompileTest()
22 {
23 setWindowWidth(128);
24 setWindowHeight(128);
25 setConfigRedBits(8);
26 setConfigGreenBits(8);
27 setConfigBlueBits(8);
28 setConfigAlphaBits(8);
29 }
30
31 void SetUp() override { ANGLETest::SetUp(); }
32
33 void TearDown() override { ANGLETest::TearDown(); }
34
35 bool ensureParallelShaderCompileExtensionAvailable()
36 {
37 if (extensionRequestable("GL_KHR_parallel_shader_compile"))
38 {
39 glRequestExtensionANGLE("GL_KHR_parallel_shader_compile");
40 }
41
42 if (!extensionEnabled("GL_KHR_parallel_shader_compile"))
43 {
44 return false;
45 }
46 return true;
47 }
jchen107ae70d82018-07-06 13:47:01 +080048
49 class ClearColorWithDraw
50 {
51 public:
52 ClearColorWithDraw(GLubyte color) : mColor(color, color, color, 255) {}
53
jchen10a155bac2018-08-16 15:26:39 +080054 bool compile()
jchen107ae70d82018-07-06 13:47:01 +080055 {
jchen10a155bac2018-08-16 15:26:39 +080056 mVertexShader =
57 compileShader(GL_VERTEX_SHADER, insertRandomString(essl1_shaders::vs::Simple()));
58 mFragmentShader = compileShader(GL_FRAGMENT_SHADER,
59 insertRandomString(essl1_shaders::fs::UniformColor()));
60 return (mVertexShader != 0 && mFragmentShader != 0);
61 }
62
63 bool isCompileCompleted()
64 {
65 GLint status;
66 glGetShaderiv(mVertexShader, GL_COMPLETION_STATUS_KHR, &status);
67 if (status == GL_TRUE)
68 {
69 glGetShaderiv(mFragmentShader, GL_COMPLETION_STATUS_KHR, &status);
70 return (status == GL_TRUE);
71 }
72 return false;
73 }
74
75 bool link()
76 {
77 mProgram = 0;
78 if (checkShader(mVertexShader) && checkShader(mFragmentShader))
79 {
80 mProgram = glCreateProgram();
81 glAttachShader(mProgram, mVertexShader);
82 glAttachShader(mProgram, mFragmentShader);
83 glLinkProgram(mProgram);
84 }
85 glDeleteShader(mVertexShader);
86 glDeleteShader(mFragmentShader);
jchen107ae70d82018-07-06 13:47:01 +080087 return (mProgram != 0);
88 }
89
90 bool isLinkCompleted()
91 {
92 GLint status;
93 glGetProgramiv(mProgram, GL_COMPLETION_STATUS_KHR, &status);
94 return (status == GL_TRUE);
95 }
96
97 void drawAndVerify(ParallelShaderCompileTest *test)
98 {
99 glClearColor(0, 0, 0, 0);
100 glClear(GL_COLOR_BUFFER_BIT);
101 glDisable(GL_DEPTH_TEST);
102 glUseProgram(mProgram);
103 ASSERT_GL_NO_ERROR();
104 GLint colorUniformLocation =
105 glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
106 ASSERT_NE(colorUniformLocation, -1);
107 auto normalizeColor = mColor.toNormalizedVector();
108 glUniform4fv(colorUniformLocation, 1, normalizeColor.data());
109 test->drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f);
110 EXPECT_PIXEL_COLOR_EQ(test->getWindowWidth() / 2, test->getWindowHeight() / 2, mColor);
111 glUseProgram(0);
112 glDeleteProgram(mProgram);
113 ASSERT_GL_NO_ERROR();
114 }
115
116 private:
117 std::string insertRandomString(const std::string &source)
118 {
119 RNG rng;
120 std::ostringstream ostream;
121 ostream << "// Random string to fool program cache: " << rng.randomInt() << "\n"
122 << source;
123 return ostream.str();
124 }
125
jchen10a155bac2018-08-16 15:26:39 +0800126 GLuint compileShader(GLenum type, const std::string &source)
127 {
128 GLuint shader = glCreateShader(type);
129
130 const char *sourceArray[1] = {source.c_str()};
131 glShaderSource(shader, 1, sourceArray, nullptr);
132 glCompileShader(shader);
133 return shader;
134 }
135
136 bool checkShader(GLuint shader)
137 {
138 GLint compileResult;
139 glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
140
141 if (compileResult == 0)
142 {
143 GLint infoLogLength;
144 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
145
146 // Info log length includes the null terminator, so 1 means that the info log is an
147 // empty string.
148 if (infoLogLength > 1)
149 {
150 std::vector<GLchar> infoLog(infoLogLength);
151 glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), nullptr,
152 &infoLog[0]);
153 std::cerr << "shader compilation failed: " << &infoLog[0];
154 }
155 else
156 {
157 std::cerr << "shader compilation failed. <Empty log message>";
158 }
159 std::cerr << std::endl;
160 }
161 return (compileResult == GL_TRUE);
162 }
163
jchen107ae70d82018-07-06 13:47:01 +0800164 GLColor mColor;
jchen10a155bac2018-08-16 15:26:39 +0800165 GLuint mVertexShader;
166 GLuint mFragmentShader;
jchen107ae70d82018-07-06 13:47:01 +0800167 GLuint mProgram;
168 };
jchen1082af6202018-06-22 10:59:52 +0800169};
170
171// Test basic functionality of GL_KHR_parallel_shader_compile
172TEST_P(ParallelShaderCompileTest, Basic)
173{
174 ANGLE_SKIP_TEST_IF(!ensureParallelShaderCompileExtensionAvailable());
175
176 GLint count = 0;
177 glMaxShaderCompilerThreadsKHR(8);
178 EXPECT_GL_NO_ERROR();
179 glGetIntegerv(GL_MAX_SHADER_COMPILER_THREADS_KHR, &count);
180 EXPECT_GL_NO_ERROR();
181 EXPECT_EQ(8, count);
182}
183
jchen107ae70d82018-07-06 13:47:01 +0800184// Test to compile and link many programs in parallel.
185TEST_P(ParallelShaderCompileTest, LinkAndDrawManyPrograms)
186{
187 ANGLE_SKIP_TEST_IF(!ensureParallelShaderCompileExtensionAvailable());
188
jchen10a155bac2018-08-16 15:26:39 +0800189 std::vector<std::unique_ptr<ClearColorWithDraw>> compileTasks;
jchen107ae70d82018-07-06 13:47:01 +0800190 constexpr int kTaskCount = 32;
191 for (int i = 0; i < kTaskCount; ++i)
192 {
193 std::unique_ptr<ClearColorWithDraw> task(new ClearColorWithDraw(i * 255 / kTaskCount));
jchen10a155bac2018-08-16 15:26:39 +0800194 bool isCompiling = task->compile();
195 ASSERT_TRUE(isCompiling);
196 compileTasks.push_back(std::move(task));
jchen107ae70d82018-07-06 13:47:01 +0800197 }
jchen10a155bac2018-08-16 15:26:39 +0800198
jchen107ae70d82018-07-06 13:47:01 +0800199 constexpr unsigned int kPollInterval = 100;
jchen10a155bac2018-08-16 15:26:39 +0800200
201 std::vector<std::unique_ptr<ClearColorWithDraw>> linkTasks;
202 while (!compileTasks.empty())
jchen107ae70d82018-07-06 13:47:01 +0800203 {
jchen10a155bac2018-08-16 15:26:39 +0800204 for (unsigned int i = 0; i < compileTasks.size();)
jchen107ae70d82018-07-06 13:47:01 +0800205 {
jchen10a155bac2018-08-16 15:26:39 +0800206 auto &task = compileTasks[i];
207
208 if (task->isCompileCompleted())
209 {
210 bool isLinking = task->link();
211 ASSERT_TRUE(isLinking);
212 linkTasks.push_back(std::move(task));
213 compileTasks.erase(compileTasks.begin() + i);
214 continue;
215 }
216 ++i;
217 }
218 Sleep(kPollInterval);
219 }
220
221 while (!linkTasks.empty())
222 {
223 for (unsigned int i = 0; i < linkTasks.size();)
224 {
225 auto &task = linkTasks[i];
226
jchen107ae70d82018-07-06 13:47:01 +0800227 if (task->isLinkCompleted())
228 {
229 task->drawAndVerify(this);
jchen10a155bac2018-08-16 15:26:39 +0800230 linkTasks.erase(linkTasks.begin() + i);
jchen107ae70d82018-07-06 13:47:01 +0800231 continue;
232 }
233 ++i;
234 }
235 Sleep(kPollInterval);
236 }
237}
238
jchen1082af6202018-06-22 10:59:52 +0800239ANGLE_INSTANTIATE_TEST(ParallelShaderCompileTest,
240 ES2_D3D9(),
241 ES2_D3D11(),
242 ES2_D3D11_FL9_3(),
243 ES2_OPENGL(),
244 ES2_OPENGLES(),
245 ES2_VULKAN());
246
247} // namespace