1 //
2 // Copyright 2017 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 // LinkAndRelinkFailureTest:
7 // Link and relink failure tests for rendering pipeline and compute pipeline.
8
9 #include <vector>
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
18 class LinkAndRelinkTest : public ANGLETest
19 {
20 protected:
LinkAndRelinkTest()21 LinkAndRelinkTest() {}
22 };
23
24 class LinkAndRelinkTestES31 : public ANGLETest
25 {
26 protected:
LinkAndRelinkTestES31()27 LinkAndRelinkTestES31() {}
28 };
29
30 // When a program link or relink fails, if you try to install the unsuccessfully
31 // linked program (via UseProgram) and start rendering or dispatch compute,
32 // We can not always report INVALID_OPERATION for rendering/compute pipeline.
33 // The result depends on the previous state: Whether a valid program is
34 // installed in current GL state before the link.
35 // If a program successfully relinks when it is in use, the program might
36 // change from a rendering program to a compute program in theory,
37 // or vice versa.
38
39 // When program link fails and no valid rendering program is installed in the GL
40 // state before the link, it should report an error for UseProgram
TEST_P(LinkAndRelinkTest,RenderingProgramFailsWithoutProgramInstalled)41 TEST_P(LinkAndRelinkTest, RenderingProgramFailsWithoutProgramInstalled)
42 {
43 glUseProgram(0);
44 GLuint program = glCreateProgram();
45
46 glLinkProgram(program);
47 GLint linkStatus;
48 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
49 EXPECT_GL_FALSE(linkStatus);
50
51 glUseProgram(program);
52 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
53
54 glDrawArrays(GL_POINTS, 0, 1);
55 EXPECT_GL_NO_ERROR();
56 }
57
58 // When program link or relink fails and a valid rendering program is installed
59 // in the GL state before the link, using the failed program via UseProgram
60 // should report an error, but starting rendering should succeed.
61 // However, dispatching compute always fails.
TEST_P(LinkAndRelinkTest,RenderingProgramFailsWithProgramInstalled)62 TEST_P(LinkAndRelinkTest, RenderingProgramFailsWithProgramInstalled)
63 {
64 // Install a render program in current GL state via UseProgram, then render.
65 // It should succeed.
66 constexpr char kVS[] = "void main() {}";
67 constexpr char kFS[] = "void main() {}";
68
69 GLuint program = glCreateProgram();
70
71 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
72 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
73
74 EXPECT_NE(0u, vs);
75 EXPECT_NE(0u, fs);
76
77 glAttachShader(program, vs);
78 glDeleteShader(vs);
79
80 glAttachShader(program, fs);
81 glDeleteShader(fs);
82
83 glLinkProgram(program);
84
85 GLint linkStatus;
86 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
87 EXPECT_GL_TRUE(linkStatus);
88
89 EXPECT_GL_NO_ERROR();
90
91 glUseProgram(program);
92 EXPECT_GL_NO_ERROR();
93 glDrawArrays(GL_POINTS, 0, 1);
94 EXPECT_GL_NO_ERROR();
95
96 glDispatchCompute(8, 4, 2);
97 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
98
99 // Link failure, and a valid program has been installed in the GL state.
100 GLuint programNull = glCreateProgram();
101
102 glLinkProgram(programNull);
103 glGetProgramiv(programNull, GL_LINK_STATUS, &linkStatus);
104 EXPECT_GL_FALSE(linkStatus);
105
106 // Starting rendering should succeed.
107 glDrawArrays(GL_POINTS, 0, 1);
108 EXPECT_GL_NO_ERROR();
109
110 glDispatchCompute(8, 4, 2);
111 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
112
113 // Using the unsuccessfully linked program should report an error.
114 glUseProgram(programNull);
115 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
116
117 // Using the unsuccessfully linked program, that program should not
118 // replace the program binary residing in the GL state. It will not make
119 // the installed program invalid either, like what UseProgram(0) can do.
120 // So, starting rendering should succeed.
121 glDrawArrays(GL_POINTS, 0, 1);
122 EXPECT_GL_NO_ERROR();
123
124 glDispatchCompute(8, 4, 2);
125 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
126
127 // We try to relink the installed program, but make it fail.
128
129 // No vertex shader, relink fails.
130 glDetachShader(program, vs);
131 glLinkProgram(program);
132 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
133 EXPECT_GL_FALSE(linkStatus);
134 EXPECT_GL_NO_ERROR();
135
136 // Starting rendering should succeed.
137 glDrawArrays(GL_POINTS, 0, 1);
138 EXPECT_GL_NO_ERROR();
139
140 glDispatchCompute(8, 4, 2);
141 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
142
143 // Using the unsuccessfully relinked program should report an error.
144 glUseProgram(program);
145 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
146
147 // Using the unsuccessfully relinked program, that program should not
148 // replace the program binary residing in the GL state. It will not make
149 // the installed program invalid either, like what UseProgram(0) can do.
150 // So, starting rendering should succeed.
151 glDrawArrays(GL_POINTS, 0, 1);
152 EXPECT_GL_NO_ERROR();
153
154 glDispatchCompute(8, 4, 2);
155 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
156 }
157
158 // Tests uniform default values.
TEST_P(LinkAndRelinkTest,UniformDefaultValues)159 TEST_P(LinkAndRelinkTest, UniformDefaultValues)
160 {
161 // TODO(anglebug.com/3969): Understand why rectangle texture CLs made this fail.
162 ANGLE_SKIP_TEST_IF(IsOzone() && IsIntel());
163 constexpr char kFS[] = R"(precision mediump float;
164 uniform vec4 u_uniform;
165
166 bool isZero(vec4 value) {
167 return value == vec4(0,0,0,0);
168 }
169
170 void main()
171 {
172 gl_FragColor = isZero(u_uniform) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
173 })";
174
175 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
176 glUseProgram(program);
177
178 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
179 ASSERT_GL_NO_ERROR();
180 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
181
182 GLint loc = glGetUniformLocation(program, "u_uniform");
183 ASSERT_NE(-1, loc);
184 glUniform4f(loc, 0.1f, 0.2f, 0.3f, 0.4f);
185
186 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
187 ASSERT_GL_NO_ERROR();
188 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
189
190 glLinkProgram(program);
191 ASSERT_GL_NO_ERROR();
192
193 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
194 ASSERT_GL_NO_ERROR();
195 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
196 }
197
198 // When program link fails and no valid compute program is installed in the GL
199 // state before the link, it should report an error for UseProgram and
200 // DispatchCompute.
TEST_P(LinkAndRelinkTestES31,ComputeProgramFailsWithoutProgramInstalled)201 TEST_P(LinkAndRelinkTestES31, ComputeProgramFailsWithoutProgramInstalled)
202 {
203 glUseProgram(0);
204 GLuint program = glCreateProgram();
205
206 glLinkProgram(program);
207 GLint linkStatus;
208 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
209 EXPECT_GL_FALSE(linkStatus);
210
211 glUseProgram(program);
212 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
213
214 glDispatchCompute(8, 4, 2);
215 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
216 }
217
218 // When program link or relink fails and a valid compute program is installed in
219 // the GL state before the link, using the failed program via UseProgram should
220 // report an error, but dispatching compute should succeed.
TEST_P(LinkAndRelinkTestES31,ComputeProgramFailsWithProgramInstalled)221 TEST_P(LinkAndRelinkTestES31, ComputeProgramFailsWithProgramInstalled)
222 {
223 // Install a compute program in the GL state via UseProgram, then dispatch
224 // compute. It should succeed.
225 constexpr char kCS[] =
226 R"(#version 310 es
227 layout(local_size_x=1) in;
228 void main()
229 {
230 })";
231
232 GLuint program = glCreateProgram();
233
234 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
235 EXPECT_NE(0u, cs);
236
237 glAttachShader(program, cs);
238 glDeleteShader(cs);
239
240 glLinkProgram(program);
241 GLint linkStatus;
242 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
243 EXPECT_GL_TRUE(linkStatus);
244
245 EXPECT_GL_NO_ERROR();
246
247 glUseProgram(program);
248 EXPECT_GL_NO_ERROR();
249 glDispatchCompute(8, 4, 2);
250 EXPECT_GL_NO_ERROR();
251
252 glDrawArrays(GL_POINTS, 0, 1);
253 EXPECT_GL_NO_ERROR();
254
255 // Link failure, and a valid program has been installed in the GL state.
256 GLuint programNull = glCreateProgram();
257
258 glLinkProgram(programNull);
259 glGetProgramiv(programNull, GL_LINK_STATUS, &linkStatus);
260 EXPECT_GL_FALSE(linkStatus);
261
262 // Dispatching compute should succeed.
263 glDispatchCompute(8, 4, 2);
264 EXPECT_GL_NO_ERROR();
265
266 glDrawArrays(GL_POINTS, 0, 1);
267 EXPECT_GL_NO_ERROR();
268
269 // Using the unsuccessfully linked program should report an error.
270 glUseProgram(programNull);
271 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
272
273 // Using the unsuccessfully linked program, that program should not
274 // replace the program binary residing in the GL state. It will not make
275 // the installed program invalid either, like what UseProgram(0) can do.
276 // So, dispatching compute should succeed.
277 glDispatchCompute(8, 4, 2);
278 EXPECT_GL_NO_ERROR();
279
280 glDrawArrays(GL_POINTS, 0, 1);
281 EXPECT_GL_NO_ERROR();
282
283 // We try to relink the installed program, but make it fail.
284
285 // No compute shader, relink fails.
286 glDetachShader(program, cs);
287 glLinkProgram(program);
288 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
289 EXPECT_GL_FALSE(linkStatus);
290 EXPECT_GL_NO_ERROR();
291
292 // Dispatching compute should succeed.
293 glDispatchCompute(8, 4, 2);
294 EXPECT_GL_NO_ERROR();
295
296 glDrawArrays(GL_POINTS, 0, 1);
297 EXPECT_GL_NO_ERROR();
298
299 // Using the unsuccessfully relinked program should report an error.
300 glUseProgram(program);
301 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
302
303 // Using the unsuccessfully relinked program, that program should not
304 // replace the program binary residing in the GL state. It will not make
305 // the installed program invalid either, like what UseProgram(0) can do.
306 // So, dispatching compute should succeed.
307 glDispatchCompute(8, 4, 2);
308 EXPECT_GL_NO_ERROR();
309
310 glDrawArrays(GL_POINTS, 0, 1);
311 EXPECT_GL_NO_ERROR();
312 }
313
314 // If you compile and link a compute program successfully and use the program,
315 // then dispatching compute and rendering can succeed (with undefined behavior).
316 // If you relink the compute program to a rendering program when it is in use,
317 // then dispatching compute will fail, but starting rendering can succeed.
TEST_P(LinkAndRelinkTestES31,RelinkProgramSucceedsFromComputeToRendering)318 TEST_P(LinkAndRelinkTestES31, RelinkProgramSucceedsFromComputeToRendering)
319 {
320 constexpr char kCS[] = R"(#version 310 es
321 layout(local_size_x=1) in;
322 void main()
323 {
324 })";
325
326 GLuint program = glCreateProgram();
327
328 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
329 EXPECT_NE(0u, cs);
330
331 glAttachShader(program, cs);
332 glDeleteShader(cs);
333
334 glLinkProgram(program);
335 glDetachShader(program, cs);
336 GLint linkStatus;
337 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
338 EXPECT_GL_TRUE(linkStatus);
339
340 EXPECT_GL_NO_ERROR();
341
342 glUseProgram(program);
343 EXPECT_GL_NO_ERROR();
344 glDispatchCompute(8, 4, 2);
345 EXPECT_GL_NO_ERROR();
346
347 glDrawArrays(GL_POINTS, 0, 1);
348 EXPECT_GL_NO_ERROR();
349
350 constexpr char kVS[] = "void main() {}";
351 constexpr char kFS[] = "void main() {}";
352
353 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
354 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
355 EXPECT_NE(0u, vs);
356 EXPECT_NE(0u, fs);
357
358 glAttachShader(program, vs);
359 glDeleteShader(vs);
360
361 glAttachShader(program, fs);
362 glDeleteShader(fs);
363
364 glLinkProgram(program);
365 glDetachShader(program, vs);
366 glDetachShader(program, fs);
367 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
368 EXPECT_GL_TRUE(linkStatus);
369
370 EXPECT_GL_NO_ERROR();
371
372 glDrawArrays(GL_POINTS, 0, 1);
373 EXPECT_GL_NO_ERROR();
374
375 glDispatchCompute(8, 4, 2);
376 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
377 }
378
379 // If you compile and link a rendering program successfully and use the program,
380 // then starting rendering can succeed, while dispatching compute will fail.
381 // If you relink the rendering program to a compute program when it is in use,
382 // then starting rendering will fail, but dispatching compute can succeed.
TEST_P(LinkAndRelinkTestES31,RelinkProgramSucceedsFromRenderingToCompute)383 TEST_P(LinkAndRelinkTestES31, RelinkProgramSucceedsFromRenderingToCompute)
384 {
385 constexpr char kVS[] = "void main() {}";
386 constexpr char kFS[] = "void main() {}";
387
388 GLuint program = glCreateProgram();
389
390 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
391 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
392
393 EXPECT_NE(0u, vs);
394 EXPECT_NE(0u, fs);
395
396 glAttachShader(program, vs);
397 glDeleteShader(vs);
398
399 glAttachShader(program, fs);
400 glDeleteShader(fs);
401
402 glLinkProgram(program);
403 glDetachShader(program, vs);
404 glDetachShader(program, fs);
405 GLint linkStatus;
406 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
407 EXPECT_GL_TRUE(linkStatus);
408
409 EXPECT_GL_NO_ERROR();
410
411 glUseProgram(program);
412 EXPECT_GL_NO_ERROR();
413 glDrawArrays(GL_POINTS, 0, 1);
414 EXPECT_GL_NO_ERROR();
415
416 glDispatchCompute(8, 4, 2);
417 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
418
419 constexpr char kCS[] = R"(#version 310 es
420 layout(local_size_x=1) in;
421 void main()
422 {
423 })";
424
425 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
426 EXPECT_NE(0u, cs);
427
428 glAttachShader(program, cs);
429 glDeleteShader(cs);
430
431 glLinkProgram(program);
432 glDetachShader(program, cs);
433 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
434 EXPECT_GL_TRUE(linkStatus);
435
436 EXPECT_GL_NO_ERROR();
437
438 glDispatchCompute(8, 4, 2);
439 EXPECT_GL_NO_ERROR();
440
441 glDrawArrays(GL_POINTS, 0, 1);
442 EXPECT_GL_NO_ERROR();
443 }
444
445 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(LinkAndRelinkTest);
446 ANGLE_INSTANTIATE_TEST_ES31(LinkAndRelinkTestES31);
447
448 } // namespace
449