1 //
2 // Copyright 2021 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 // RobustFragmentShaderOutputTest: Tests for the custom ANGLE extension.
7
8 #include "test_utils/ANGLETest.h"
9 #include "test_utils/gl_raii.h"
10
11 #include "util/random_utils.h"
12
13 #include <stdint.h>
14
15 using namespace angle;
16
17 namespace
18 {
ExtEnabled()19 bool ExtEnabled()
20 {
21 return IsGLExtensionEnabled("GL_ANGLE_robust_fragment_shader_output");
22 }
23 } // namespace
24
25 class RobustFragmentShaderOutputTest : public ANGLETest<>
26 {
27 public:
RobustFragmentShaderOutputTest()28 RobustFragmentShaderOutputTest() {}
29 };
30
31 // Basic behaviour from the extension.
TEST_P(RobustFragmentShaderOutputTest,Basic)32 TEST_P(RobustFragmentShaderOutputTest, Basic)
33 {
34 ANGLE_SKIP_TEST_IF(!ExtEnabled());
35
36 const char kFS[] = R"(#version 300 es
37 precision mediump float;
38 out vec4 outvar;
39 void main() {
40 outvar = vec4(0.0, 1.0, 0.0, 1.0);
41 })";
42 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
43
44 GLFramebuffer framebuffer;
45 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
46
47 constexpr GLsizei kSize = 2;
48 std::vector<GLColor> bluePixels(kSize * kSize, GLColor::blue);
49
50 GLTexture texA;
51 glBindTexture(GL_TEXTURE_2D, texA);
52 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
53 bluePixels.data());
54 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texA, 0);
55
56 GLTexture texB;
57 glBindTexture(GL_TEXTURE_2D, texB);
58 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
59 bluePixels.data());
60 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, texB, 0);
61
62 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
63
64 // Verify initial attachment colors (blue).
65 glReadBuffer(GL_COLOR_ATTACHMENT0);
66 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
67
68 glReadBuffer(GL_COLOR_ATTACHMENT1);
69 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
70
71 constexpr std::array<GLenum, 2> kDrawBuffers = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
72 glDrawBuffers(2, kDrawBuffers.data());
73 glViewport(0, 0, kSize, kSize);
74 glUseProgram(program);
75 ASSERT_GL_NO_ERROR();
76
77 // Draw, verify first attachment is updated (green) and second is unchanged (blue).
78 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
79 ASSERT_GL_NO_ERROR();
80
81 glReadBuffer(GL_COLOR_ATTACHMENT0);
82 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
83
84 glReadBuffer(GL_COLOR_ATTACHMENT1);
85 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
86 }
87
88 // Test that changing framebuffer attachments work
TEST_P(RobustFragmentShaderOutputTest,ChangingFramebufferAttachments)89 TEST_P(RobustFragmentShaderOutputTest, ChangingFramebufferAttachments)
90 {
91 ANGLE_SKIP_TEST_IF(!ExtEnabled());
92
93 const char kFS[] = R"(#version 300 es
94 precision mediump float;
95 layout(location = 1) out vec4 color1;
96 layout(location = 3) out vec4 color2;
97
98 uniform vec4 color1In;
99 uniform vec4 color2In;
100
101 void main() {
102 color1 = color1In;
103 color2 = color2In;
104 })";
105 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
106 glUseProgram(program);
107
108 GLint color1Loc = glGetUniformLocation(program, "color1In");
109 ASSERT_NE(color1Loc, -1);
110 GLint color2Loc = glGetUniformLocation(program, "color2In");
111 ASSERT_NE(color2Loc, -1);
112
113 constexpr GLsizei kSize = 2;
114 const std::vector<GLColor> initColor(kSize * kSize, GLColor::transparentBlack);
115
116 GLTexture color1;
117 glBindTexture(GL_TEXTURE_2D, color1);
118 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
119 initColor.data());
120
121 GLTexture color2;
122 glBindTexture(GL_TEXTURE_2D, color2);
123 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
124 initColor.data());
125
126 GLTexture color3;
127 glBindTexture(GL_TEXTURE_2D, color3);
128 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
129 initColor.data());
130
131 // Draw with matching framebuffer attachments
132 GLFramebuffer framebuffer;
133 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
134 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color1, 0);
135 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color2, 0);
136 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
137
138 std::array<GLenum, 4> drawBuffers = {GL_NONE, GL_COLOR_ATTACHMENT1, GL_NONE,
139 GL_COLOR_ATTACHMENT3};
140 glDrawBuffers(4, drawBuffers.data());
141 glViewport(0, 0, kSize, kSize);
142 ASSERT_GL_NO_ERROR();
143
144 glEnable(GL_BLEND);
145 glBlendFunc(GL_ONE, GL_ONE);
146
147 // Draw once, should update color1 and color2
148 glUniform4f(color1Loc, 1, 0, 0, 0);
149 glUniform4f(color2Loc, 0, 1, 0, 0);
150 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
151
152 // Change the framebuffer attachments, this time adding an attachment that's not written to.
153 // This attachment should be unmodified.
154 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color3, 0);
155 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
156 drawBuffers[0] = GL_COLOR_ATTACHMENT0;
157 glDrawBuffers(4, drawBuffers.data());
158
159 glUniform4f(color1Loc, 0, 0, 1, 1);
160 glUniform4f(color2Loc, 0, 0, 0, 1);
161 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
162
163 // Shuffle attachments.
164 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color1, 0);
165 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color2, 0);
166 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color3, 0);
167 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
168
169 glUniform4f(color1Loc, 0, 0, 1, 0);
170 glUniform4f(color2Loc, 1, 0, 0, 1);
171 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
172
173 // Switch back to matching attachment count
174 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
175 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
176 drawBuffers[0] = GL_NONE;
177 glDrawBuffers(4, drawBuffers.data());
178
179 glUniform4f(color1Loc, 1, 0, 0, 0);
180 glUniform4f(color2Loc, 0, 1, 0, 0);
181 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
182
183 // Verify results
184 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color1, 0);
185 glReadBuffer(GL_COLOR_ATTACHMENT0);
186 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::magenta);
187
188 glReadBuffer(GL_COLOR_ATTACHMENT1);
189 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::white);
190
191 glReadBuffer(GL_COLOR_ATTACHMENT3);
192 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::yellow);
193
194 ASSERT_GL_NO_ERROR();
195 }
196
197 // Test that changing framebuffers work
TEST_P(RobustFragmentShaderOutputTest,ChangingFramebuffers)198 TEST_P(RobustFragmentShaderOutputTest, ChangingFramebuffers)
199 {
200 ANGLE_SKIP_TEST_IF(!ExtEnabled());
201
202 const char kFS[] = R"(#version 300 es
203 precision mediump float;
204 layout(location = 1) out vec4 color1;
205 layout(location = 3) out vec4 color2;
206
207 uniform vec4 color1In;
208 uniform vec4 color2In;
209
210 void main() {
211 color1 = color1In;
212 color2 = color2In;
213 })";
214 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
215 glUseProgram(program);
216
217 GLint color1Loc = glGetUniformLocation(program, "color1In");
218 ASSERT_NE(color1Loc, -1);
219 GLint color2Loc = glGetUniformLocation(program, "color2In");
220 ASSERT_NE(color2Loc, -1);
221
222 constexpr GLsizei kSize = 2;
223 const std::vector<GLColor> initColor(kSize * kSize, GLColor::transparentBlack);
224
225 GLTexture color1;
226 glBindTexture(GL_TEXTURE_2D, color1);
227 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
228 initColor.data());
229
230 GLTexture color2;
231 glBindTexture(GL_TEXTURE_2D, color2);
232 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
233 initColor.data());
234
235 GLTexture color3;
236 glBindTexture(GL_TEXTURE_2D, color3);
237 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
238 initColor.data());
239
240 GLFramebuffer framebuffer1;
241 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
242 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color1, 0);
243 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color2, 0);
244 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
245
246 GLFramebuffer framebuffer2;
247 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
248 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color1, 0);
249 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color2, 0);
250 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color3, 0);
251 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
252
253 GLFramebuffer framebuffer3;
254 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
255 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color1, 0);
256 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color2, 0);
257 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color3, 0);
258 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
259
260 GLFramebuffer framebuffer4;
261 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer4);
262 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color2, 0);
263 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color3, 0);
264 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
265
266 // Draw with matching framebuffer attachments
267 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
268
269 std::array<GLenum, 4> drawBuffers = {GL_NONE, GL_COLOR_ATTACHMENT1, GL_NONE,
270 GL_COLOR_ATTACHMENT3};
271 glDrawBuffers(4, drawBuffers.data());
272 glViewport(0, 0, kSize, kSize);
273 ASSERT_GL_NO_ERROR();
274
275 glEnable(GL_BLEND);
276 glBlendFunc(GL_ONE, GL_ONE);
277
278 // Draw once, should update color1 and color2
279 glUniform4f(color1Loc, 1, 0, 0, 0);
280 glUniform4f(color2Loc, 0, 1, 0, 0);
281 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
282
283 // Change the framebuffer attachments, this time adding an attachment that's not written to.
284 // This attachment should be unmodified.
285 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
286
287 drawBuffers[0] = GL_COLOR_ATTACHMENT0;
288 glDrawBuffers(4, drawBuffers.data());
289
290 glUniform4f(color1Loc, 0, 0, 1, 1);
291 glUniform4f(color2Loc, 0, 0, 0, 1);
292 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
293
294 // Shuffle attachments.
295 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
296 glDrawBuffers(4, drawBuffers.data());
297
298 glUniform4f(color1Loc, 0, 0, 1, 0);
299 glUniform4f(color2Loc, 1, 0, 0, 1);
300 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
301
302 // Switch back to matching attachment count
303 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer4);
304
305 drawBuffers[0] = GL_NONE;
306 glDrawBuffers(4, drawBuffers.data());
307
308 glUniform4f(color1Loc, 1, 0, 0, 0);
309 glUniform4f(color2Loc, 0, 1, 0, 0);
310 drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f);
311
312 // Verify results
313 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer3);
314 glReadBuffer(GL_COLOR_ATTACHMENT0);
315 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::magenta);
316
317 glReadBuffer(GL_COLOR_ATTACHMENT1);
318 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::white);
319
320 glReadBuffer(GL_COLOR_ATTACHMENT3);
321 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::yellow);
322
323 ASSERT_GL_NO_ERROR();
324 }
325
326 // Test that changing program outputs work
TEST_P(RobustFragmentShaderOutputTest,ChangingProgramOutputs)327 TEST_P(RobustFragmentShaderOutputTest, ChangingProgramOutputs)
328 {
329 ANGLE_SKIP_TEST_IF(!ExtEnabled());
330
331 const char kFS1[] = R"(#version 300 es
332 precision mediump float;
333 layout(location = 1) out vec4 color1;
334
335 uniform vec4 color1In;
336
337 void main() {
338 color1 = color1In;
339 })";
340
341 const char kFS2[] = R"(#version 300 es
342 precision mediump float;
343 layout(location = 1) out vec4 color1;
344 layout(location = 3) out vec4 color2;
345
346 uniform vec4 color1In;
347 uniform vec4 color2In;
348
349 void main() {
350 color1 = color1In;
351 color2 = color2In;
352 })";
353
354 const char kFS3[] = R"(#version 300 es
355 precision mediump float;
356 layout(location = 0) out vec4 color1;
357 layout(location = 1) out vec4 color2;
358 layout(location = 3) out vec4 color3;
359
360 uniform vec4 color1In;
361 uniform vec4 color2In;
362 uniform vec4 color3In;
363
364 void main() {
365 color1 = color1In;
366 color2 = color2In;
367 color3 = color3In;
368 })";
369
370 ANGLE_GL_PROGRAM(program1, essl3_shaders::vs::Simple(), kFS1);
371 glUseProgram(program1);
372 GLint program1Color1Loc = glGetUniformLocation(program1, "color1In");
373 ASSERT_NE(program1Color1Loc, -1);
374
375 ANGLE_GL_PROGRAM(program2, essl3_shaders::vs::Simple(), kFS2);
376 glUseProgram(program2);
377 GLint program2Color1Loc = glGetUniformLocation(program2, "color1In");
378 ASSERT_NE(program2Color1Loc, -1);
379 GLint program2Color2Loc = glGetUniformLocation(program2, "color2In");
380 ASSERT_NE(program2Color2Loc, -1);
381
382 ANGLE_GL_PROGRAM(program3, essl3_shaders::vs::Simple(), kFS3);
383 glUseProgram(program3);
384 GLint program3Color1Loc = glGetUniformLocation(program3, "color1In");
385 ASSERT_NE(program2Color1Loc, -1);
386 GLint program3Color2Loc = glGetUniformLocation(program3, "color2In");
387 ASSERT_NE(program2Color2Loc, -1);
388 GLint program3Color3Loc = glGetUniformLocation(program3, "color3In");
389 ASSERT_NE(program3Color3Loc, -1);
390
391 constexpr GLsizei kSize = 2;
392 const std::vector<GLColor> initColor(kSize * kSize, GLColor::transparentBlack);
393
394 GLTexture color1;
395 glBindTexture(GL_TEXTURE_2D, color1);
396 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
397 initColor.data());
398
399 GLTexture color2;
400 glBindTexture(GL_TEXTURE_2D, color2);
401 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
402 initColor.data());
403
404 GLTexture color3;
405 glBindTexture(GL_TEXTURE_2D, color3);
406 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
407 initColor.data());
408
409 // Draw with matching framebuffer attachments
410 GLFramebuffer framebuffer;
411 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
412 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color1, 0);
413 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, color2, 0);
414 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, color3, 0);
415 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
416
417 std::array<GLenum, 4> drawBuffers = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_NONE,
418 GL_COLOR_ATTACHMENT3};
419 glDrawBuffers(4, drawBuffers.data());
420 glViewport(0, 0, kSize, kSize);
421 ASSERT_GL_NO_ERROR();
422
423 glEnable(GL_BLEND);
424 glBlendFunc(GL_ONE, GL_ONE);
425
426 // Draw with 2 outputs, should update color2 and color3
427 glUseProgram(program2);
428 glUniform4f(program2Color1Loc, 0.6, 0, 0, 0);
429 glUniform4f(program2Color2Loc, 0, 0.7, 0, 0);
430 drawQuad(program2, essl3_shaders::PositionAttrib(), 0.5f);
431
432 // Draw with 1 output, should update color2
433 glUseProgram(program1);
434 glUniform4f(program1Color1Loc, 0.5, 0, 0, 0);
435 drawQuad(program1, essl3_shaders::PositionAttrib(), 0.5f);
436
437 // Draw with 3 outputs, should update all
438 glUseProgram(program3);
439 glUniform4f(program3Color1Loc, 0, 0, 1, 1);
440 glUniform4f(program3Color2Loc, 0, 1, 0, 0);
441 glUniform4f(program3Color3Loc, 0, 0.4, 0, 0);
442 drawQuad(program3, essl3_shaders::PositionAttrib(), 0.5f);
443
444 // Draw with 2 outputs again, should update color2 and color3
445 glUseProgram(program2);
446 glUniform4f(program2Color1Loc, 0, 0, 0, 1);
447 glUniform4f(program2Color2Loc, 0, 0, 0, 1);
448 drawQuad(program2, essl3_shaders::PositionAttrib(), 0.5f);
449
450 // Verify results
451 glReadBuffer(GL_COLOR_ATTACHMENT0);
452 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::blue);
453
454 glReadBuffer(GL_COLOR_ATTACHMENT1);
455 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::yellow);
456
457 glReadBuffer(GL_COLOR_ATTACHMENT3);
458 EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::green);
459
460 ASSERT_GL_NO_ERROR();
461 }
462
463 ANGLE_INSTANTIATE_TEST_ES3(RobustFragmentShaderOutputTest);
464