1 //
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 // BlendFuncExtendedTest
7 // Test EXT_blend_func_extended
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 #include "util/shader_utils.h"
13
14 #include <algorithm>
15 #include <cmath>
16 #include <fstream>
17
18 using namespace angle;
19
20 namespace
21 {
22
23 // Partial implementation of weight function for GLES 2 blend equation that
24 // is dual-source aware.
25 template <int factor, int index>
Weight(const float[4],const float src[4],const float src1[4])26 float Weight(const float /*dst*/[4], const float src[4], const float src1[4])
27 {
28 if (factor == GL_SRC_COLOR)
29 return src[index];
30 if (factor == GL_SRC_ALPHA)
31 return src[3];
32 if (factor == GL_SRC1_COLOR_EXT)
33 return src1[index];
34 if (factor == GL_SRC1_ALPHA_EXT)
35 return src1[3];
36 if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT)
37 return 1.0f - src1[index];
38 if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT)
39 return 1.0f - src1[3];
40 return 0.0f;
41 }
42
ScaleChannel(float weight)43 GLubyte ScaleChannel(float weight)
44 {
45 return static_cast<GLubyte>(std::floor(std::max(0.0f, std::min(1.0f, weight)) * 255.0f));
46 }
47
48 // Implementation of GLES 2 blend equation that is dual-source aware.
49 template <int RGBs, int RGBd, int As, int Ad>
BlendEquationFuncAdd(const float dst[4],const float src[4],const float src1[4],angle::GLColor * result)50 void BlendEquationFuncAdd(const float dst[4],
51 const float src[4],
52 const float src1[4],
53 angle::GLColor *result)
54 {
55 float r[4];
56 r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) + dst[0] * Weight<RGBd, 0>(dst, src, src1);
57 r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) + dst[1] * Weight<RGBd, 1>(dst, src, src1);
58 r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) + dst[2] * Weight<RGBd, 2>(dst, src, src1);
59 r[3] = src[3] * Weight<As, 3>(dst, src, src1) + dst[3] * Weight<Ad, 3>(dst, src, src1);
60
61 result->R = ScaleChannel(r[0]);
62 result->G = ScaleChannel(r[1]);
63 result->B = ScaleChannel(r[2]);
64 result->A = ScaleChannel(r[3]);
65 }
66
CheckPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLint tolerance,const angle::GLColor & color)67 void CheckPixels(GLint x,
68 GLint y,
69 GLsizei width,
70 GLsizei height,
71 GLint tolerance,
72 const angle::GLColor &color)
73 {
74 for (GLint yy = 0; yy < height; ++yy)
75 {
76 for (GLint xx = 0; xx < width; ++xx)
77 {
78 const auto px = x + xx;
79 const auto py = y + yy;
80 EXPECT_PIXEL_COLOR_NEAR(px, py, color, 2);
81 }
82 }
83 }
84
85 const GLuint kWidth = 100;
86 const GLuint kHeight = 100;
87
88 class EXTBlendFuncExtendedTest : public ANGLETest<>
89 {};
90
91 class EXTBlendFuncExtendedTestES3 : public ANGLETest<>
92 {};
93
94 class EXTBlendFuncExtendedDrawTest : public ANGLETest<>
95 {
96 protected:
EXTBlendFuncExtendedDrawTest()97 EXTBlendFuncExtendedDrawTest() : mProgram(0)
98 {
99 setWindowWidth(kWidth);
100 setWindowHeight(kHeight);
101 setConfigRedBits(8);
102 setConfigGreenBits(8);
103 setConfigBlueBits(8);
104 setConfigAlphaBits(8);
105 }
106
testSetUp()107 void testSetUp() override
108 {
109 glGenBuffers(1, &mVBO);
110 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
111
112 static const float vertices[] = {
113 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
114 };
115 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
116
117 ASSERT_GL_NO_ERROR();
118 }
119
testTearDown()120 void testTearDown() override
121 {
122 glDeleteBuffers(1, &mVBO);
123 if (mProgram)
124 {
125 glDeleteProgram(mProgram);
126 }
127
128 ASSERT_GL_NO_ERROR();
129 }
130
makeProgram(const char * vertSource,const char * fragSource)131 void makeProgram(const char *vertSource, const char *fragSource)
132 {
133 mProgram = CompileProgram(vertSource, fragSource);
134
135 ASSERT_NE(0u, mProgram);
136 }
137
getVertexAttribLocation(const char * name)138 virtual GLint getVertexAttribLocation(const char *name)
139 {
140 return glGetAttribLocation(mProgram, name);
141 }
142
getFragmentUniformLocation(const char * name)143 virtual GLint getFragmentUniformLocation(const char *name)
144 {
145 return glGetUniformLocation(mProgram, name);
146 }
147
setUniform4f(GLint location,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3)148 virtual void setUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
149 {
150 glUniform4f(location, v0, v1, v2, v3);
151 }
152
drawTest()153 void drawTest()
154 {
155 glUseProgram(mProgram);
156
157 GLint position = getVertexAttribLocation(essl1_shaders::PositionAttrib());
158 GLint src0 = getFragmentUniformLocation("src0");
159 GLint src1 = getFragmentUniformLocation("src1");
160 ASSERT_GL_NO_ERROR();
161
162 glBindBuffer(GL_ARRAY_BUFFER, mVBO);
163 glEnableVertexAttribArray(position);
164 glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);
165 ASSERT_GL_NO_ERROR();
166
167 static const float kDst[4] = {0.5f, 0.5f, 0.5f, 0.5f};
168 static const float kSrc0[4] = {1.0f, 1.0f, 1.0f, 1.0f};
169 static const float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f};
170
171 setUniform4f(src0, kSrc0[0], kSrc0[1], kSrc0[2], kSrc0[3]);
172 setUniform4f(src1, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]);
173 ASSERT_GL_NO_ERROR();
174
175 glEnable(GL_BLEND);
176 glBlendEquation(GL_FUNC_ADD);
177 glViewport(0, 0, kWidth, kHeight);
178 glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]);
179 ASSERT_GL_NO_ERROR();
180
181 {
182 glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_COLOR_EXT,
183 GL_ONE_MINUS_SRC1_ALPHA_EXT);
184
185 glClear(GL_COLOR_BUFFER_BIT);
186 glDrawArrays(GL_TRIANGLES, 0, 6);
187 ASSERT_GL_NO_ERROR();
188
189 // verify
190 angle::GLColor color;
191 BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_COLOR_EXT,
192 GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc0, kSrc1, &color);
193
194 CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, 1, color);
195 CheckPixels(kWidth - 1, 0, 1, 1, 1, color);
196 }
197
198 {
199 glBlendFuncSeparate(GL_ONE_MINUS_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC_ALPHA,
200 GL_ONE_MINUS_SRC_COLOR, GL_SRC1_ALPHA_EXT);
201
202 glClear(GL_COLOR_BUFFER_BIT);
203 glDrawArrays(GL_TRIANGLES, 0, 6);
204 ASSERT_GL_NO_ERROR();
205
206 // verify
207 angle::GLColor color;
208 BlendEquationFuncAdd<GL_ONE_MINUS_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC_ALPHA,
209 GL_ONE_MINUS_SRC_COLOR, GL_SRC1_ALPHA_EXT>(kDst, kSrc0, kSrc1,
210 &color);
211
212 CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, 1, color);
213 CheckPixels(kWidth - 1, 0, 1, 1, 1, color);
214 }
215 }
216
217 GLuint mVBO;
218 GLuint mProgram;
219 };
220
221 class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest
222 {
223 protected:
EXTBlendFuncExtendedDrawTestES3()224 EXTBlendFuncExtendedDrawTestES3() : EXTBlendFuncExtendedDrawTest(), mIsES31OrNewer(false) {}
225
testSetUp()226 void testSetUp() override
227 {
228 EXTBlendFuncExtendedDrawTest::testSetUp();
229 if (getClientMajorVersion() > 3 ||
230 (getClientMajorVersion() == 3 && getClientMinorVersion() >= 1))
231 {
232 mIsES31OrNewer = true;
233 }
234 }
235
checkOutputIndexQuery(const char * name,GLint expectedIndex)236 virtual void checkOutputIndexQuery(const char *name, GLint expectedIndex)
237 {
238 GLint index = glGetFragDataIndexEXT(mProgram, name);
239 EXPECT_EQ(expectedIndex, index);
240 if (mIsES31OrNewer)
241 {
242 index = glGetProgramResourceLocationIndexEXT(mProgram, GL_PROGRAM_OUTPUT, name);
243 EXPECT_EQ(expectedIndex, index);
244 }
245 else
246 {
247 glGetProgramResourceLocationIndexEXT(mProgram, GL_PROGRAM_OUTPUT, name);
248 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
249 }
250 }
251
LinkProgram()252 void LinkProgram()
253 {
254 glLinkProgram(mProgram);
255 GLint linked = 0;
256 glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
257 EXPECT_NE(0, linked);
258 glUseProgram(mProgram);
259 return;
260 }
261
262 private:
263 bool mIsES31OrNewer;
264 };
265
266 class EXTBlendFuncExtendedDrawTestES31 : public EXTBlendFuncExtendedDrawTestES3
267 {
268 protected:
EXTBlendFuncExtendedDrawTestES31()269 EXTBlendFuncExtendedDrawTestES31()
270 : EXTBlendFuncExtendedDrawTestES3(), mPipeline(0), mVertexProgram(0), mFragProgram(0)
271 {}
272
getVertexAttribLocation(const char * name)273 GLint getVertexAttribLocation(const char *name) override
274 {
275 return glGetAttribLocation(mVertexProgram, name);
276 }
277
getFragmentUniformLocation(const char * name)278 GLint getFragmentUniformLocation(const char *name) override
279 {
280 return glGetUniformLocation(mFragProgram, name);
281 }
282
setUniform4f(GLint location,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3)283 void setUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) override
284 {
285 glActiveShaderProgram(mPipeline, mFragProgram);
286 EXTBlendFuncExtendedDrawTest::setUniform4f(location, v0, v1, v2, v3);
287 }
288
checkOutputIndexQuery(const char * name,GLint expectedIndex)289 void checkOutputIndexQuery(const char *name, GLint expectedIndex) override
290 {
291 GLint index = glGetFragDataIndexEXT(mFragProgram, name);
292 EXPECT_EQ(expectedIndex, index);
293 index = glGetProgramResourceLocationIndexEXT(mFragProgram, GL_PROGRAM_OUTPUT, name);
294 EXPECT_EQ(expectedIndex, index);
295 }
296
setupProgramPipeline(const char * vertexSource,const char * fragmentSource)297 void setupProgramPipeline(const char *vertexSource, const char *fragmentSource)
298 {
299 mVertexProgram = createShaderProgram(GL_VERTEX_SHADER, vertexSource);
300 ASSERT_NE(mVertexProgram, 0u);
301 mFragProgram = createShaderProgram(GL_FRAGMENT_SHADER, fragmentSource);
302 ASSERT_NE(mFragProgram, 0u);
303
304 // Generate a program pipeline and attach the programs to their respective stages
305 glGenProgramPipelines(1, &mPipeline);
306 EXPECT_GL_NO_ERROR();
307 glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertexProgram);
308 EXPECT_GL_NO_ERROR();
309 glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);
310 EXPECT_GL_NO_ERROR();
311 glBindProgramPipeline(mPipeline);
312 EXPECT_GL_NO_ERROR();
313 }
314
createShaderProgram(GLenum type,const GLchar * shaderString)315 GLuint createShaderProgram(GLenum type, const GLchar *shaderString)
316 {
317 GLShader shader(type);
318 if (!shader)
319 {
320 return 0;
321 }
322
323 glShaderSource(shader, 1, &shaderString, nullptr);
324 glCompileShader(shader);
325
326 GLuint program = glCreateProgram();
327
328 if (program)
329 {
330 GLint compiled;
331 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
332 glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
333 if (compiled)
334 {
335 glAttachShader(program, shader);
336 glLinkProgram(program);
337 glDetachShader(program, shader);
338 }
339 }
340
341 EXPECT_GL_NO_ERROR();
342
343 return program;
344 }
345
testTearDown()346 void testTearDown() override
347 {
348 EXTBlendFuncExtendedDrawTest::testTearDown();
349 if (mVertexProgram)
350 {
351 glDeleteProgram(mVertexProgram);
352 }
353 if (mFragProgram)
354 {
355 glDeleteProgram(mFragProgram);
356 }
357 if (mPipeline)
358 {
359 glDeleteProgramPipelines(1, &mPipeline);
360 }
361
362 ASSERT_GL_NO_ERROR();
363 }
364
365 GLuint mPipeline;
366 GLuint mVertexProgram;
367 GLuint mFragProgram;
368 };
369 } // namespace
370
371 // Test EXT_blend_func_extended related gets.
TEST_P(EXTBlendFuncExtendedTest,TestMaxDualSourceDrawBuffers)372 TEST_P(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers)
373 {
374 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
375
376 GLint maxDualSourceDrawBuffers = 0;
377 glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers);
378 EXPECT_GT(maxDualSourceDrawBuffers, 0);
379
380 ASSERT_GL_NO_ERROR();
381 }
382
383 // Test that SRC1 factors limit the number of allowed draw buffers.
TEST_P(EXTBlendFuncExtendedTest,MaxDualSourceDrawBuffersError)384 TEST_P(EXTBlendFuncExtendedTest, MaxDualSourceDrawBuffersError)
385 {
386 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
387 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
388 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8"));
389
390 GLint maxDualSourceDrawBuffers = 0;
391 glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers);
392 ANGLE_SKIP_TEST_IF(maxDualSourceDrawBuffers != 1);
393
394 ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
395
396 GLFramebuffer fbo;
397 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
398
399 GLRenderbuffer rb0;
400 glBindRenderbuffer(GL_RENDERBUFFER, rb0);
401 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
402 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, rb0);
403
404 GLRenderbuffer rb1;
405 glBindRenderbuffer(GL_RENDERBUFFER, rb1);
406 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, 1, 1);
407 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER, rb1);
408
409 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
410
411 const GLenum bufs[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
412 glDrawBuffersEXT(2, bufs);
413 ASSERT_GL_NO_ERROR();
414
415 for (const GLenum func : {GL_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC1_COLOR_EXT, GL_SRC1_ALPHA_EXT,
416 GL_ONE_MINUS_SRC1_ALPHA_EXT})
417 {
418 for (size_t slot = 0; slot < 4; slot++)
419 {
420 switch (slot)
421 {
422 case 0:
423 glBlendFuncSeparate(func, GL_ONE, GL_ONE, GL_ONE);
424 break;
425 case 1:
426 glBlendFuncSeparate(GL_ONE, func, GL_ONE, GL_ONE);
427 break;
428 case 2:
429 glBlendFuncSeparate(GL_ONE, GL_ONE, func, GL_ONE);
430 break;
431 case 3:
432 glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, func);
433 break;
434 }
435 // Limit must be applied even with blending disabled
436 glDisable(GL_BLEND);
437 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.0);
438 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
439
440 glEnable(GL_BLEND);
441 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.0);
442 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
443
444 // Limit must be applied even when an attachment is missing
445 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER, 0);
446 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.0);
447 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
448
449 // Restore the attachment for the next iteration
450 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER,
451 rb1);
452
453 // Limit is not applied when non-SRC1 funcs are used
454 glBlendFunc(GL_ONE, GL_ONE);
455 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.0);
456 EXPECT_GL_NO_ERROR();
457 }
458 }
459 }
460
461 // Test a shader with EXT_blend_func_extended and gl_SecondaryFragColorEXT.
462 // Outputs to primary color buffer using primary and secondary colors.
TEST_P(EXTBlendFuncExtendedDrawTest,FragColor)463 TEST_P(EXTBlendFuncExtendedDrawTest, FragColor)
464 {
465 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
466
467 const char *kFragColorShader =
468 "#extension GL_EXT_blend_func_extended : require\n"
469 "precision mediump float;\n"
470 "uniform vec4 src0;\n"
471 "uniform vec4 src1;\n"
472 "void main() {\n"
473 " gl_FragColor = src0;\n"
474 " gl_SecondaryFragColorEXT = src1;\n"
475 "}\n";
476
477 makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
478
479 drawTest();
480 }
481
482 // Test a shader with EXT_blend_func_extended and EXT_draw_buffers enabled at the same time.
TEST_P(EXTBlendFuncExtendedDrawTest,FragColorBroadcast)483 TEST_P(EXTBlendFuncExtendedDrawTest, FragColorBroadcast)
484 {
485 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
486 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_draw_buffers"));
487
488 const char *kFragColorShader =
489 "#extension GL_EXT_blend_func_extended : require\n"
490 "#extension GL_EXT_draw_buffers : require\n"
491 "precision mediump float;\n"
492 "uniform vec4 src0;\n"
493 "uniform vec4 src1;\n"
494 "void main() {\n"
495 " gl_FragColor = src0;\n"
496 " gl_SecondaryFragColorEXT = src1;\n"
497 "}\n";
498
499 makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
500
501 drawTest();
502 }
503
504 // Test a shader with EXT_blend_func_extended and gl_FragData.
505 // Outputs to a color buffer using primary and secondary frag data.
TEST_P(EXTBlendFuncExtendedDrawTest,FragData)506 TEST_P(EXTBlendFuncExtendedDrawTest, FragData)
507 {
508 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
509
510 const char *kFragColorShader =
511 "#extension GL_EXT_blend_func_extended : require\n"
512 "precision mediump float;\n"
513 "uniform vec4 src0;\n"
514 "uniform vec4 src1;\n"
515 "void main() {\n"
516 " gl_FragData[0] = src0;\n"
517 " gl_SecondaryFragDataEXT[0] = src1;\n"
518 "}\n";
519
520 makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
521
522 drawTest();
523 }
524
525 // Test that min/max blending works correctly with SRC1 factors.
TEST_P(EXTBlendFuncExtendedDrawTest,MinMax)526 TEST_P(EXTBlendFuncExtendedDrawTest, MinMax)
527 {
528 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
529 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_minmax"));
530
531 const char *kFragColorShader = R"(#extension GL_EXT_blend_func_extended : require
532 precision mediump float;
533 void main() {
534 gl_FragColor = vec4(0.125, 0.25, 0.75, 0.875);
535 gl_SecondaryFragColorEXT = vec4(0.0, 0.0, 0.0, 0.0);
536 })";
537 makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
538
539 glEnable(GL_BLEND);
540 glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC1_COLOR_EXT, GL_SRC1_ALPHA_EXT,
541 GL_ONE_MINUS_SRC1_ALPHA_EXT);
542 glClearColor(0.5, 0.5, 0.5, 0.5);
543
544 auto test = [&](GLenum colorOp, GLenum alphaOp, GLColor color) {
545 glBlendEquationSeparate(colorOp, alphaOp);
546 glClear(GL_COLOR_BUFFER_BIT);
547 drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.0);
548 EXPECT_PIXEL_COLOR_NEAR(0, 0, color, 2);
549 };
550 test(GL_MIN_EXT, GL_MIN_EXT, GLColor(32, 64, 128, 128));
551 test(GL_MIN_EXT, GL_MAX_EXT, GLColor(32, 64, 128, 224));
552 test(GL_MAX_EXT, GL_MIN_EXT, GLColor(128, 128, 192, 128));
553 test(GL_MAX_EXT, GL_MAX_EXT, GLColor(128, 128, 192, 224));
554 }
555
556 // Test an ESSL 3.00 shader that uses two fragment outputs with locations specified in the shader.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsInShader)557 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsInShader)
558 {
559 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
560
561 const char *kFragColorShader = R"(#version 300 es
562 #extension GL_EXT_blend_func_extended : require
563 precision mediump float;
564 uniform vec4 src0;
565 uniform vec4 src1;
566 layout(location = 0, index = 1) out vec4 outSrc1;
567 layout(location = 0, index = 0) out vec4 outSrc0;
568 void main() {
569 outSrc0 = src0;
570 outSrc1 = src1;
571 })";
572
573 makeProgram(essl3_shaders::vs::Simple(), kFragColorShader);
574
575 checkOutputIndexQuery("outSrc0", 0);
576 checkOutputIndexQuery("outSrc1", 1);
577
578 drawTest();
579 }
580
581 // Test an ESSL 3.00 shader that uses two fragment outputs with locations specified through the API.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsAPI)582 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsAPI)
583 {
584 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
585
586 constexpr char kFS[] = R"(#version 300 es
587 #extension GL_EXT_blend_func_extended : require
588 precision mediump float;
589 uniform vec4 src0;
590 uniform vec4 src1;
591 out vec4 outSrc1;
592 out vec4 outSrc0;
593 void main() {
594 outSrc0 = src0;
595 outSrc1 = src1;
596 })";
597
598 mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
599 glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0");
600 glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
601 });
602
603 ASSERT_NE(0u, mProgram);
604
605 checkOutputIndexQuery("outSrc0", 0);
606 checkOutputIndexQuery("outSrc1", 1);
607
608 drawTest();
609 }
610
611 // Test an ESSL 3.00 shader that uses two fragment outputs, with location for one specified through
612 // the API and location for another being set automatically.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsAPIAndAutomatic)613 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsAPIAndAutomatic)
614 {
615 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
616
617 constexpr char kFS[] = R"(#version 300 es
618 #extension GL_EXT_blend_func_extended : require
619 precision mediump float;
620 uniform vec4 src0;
621 uniform vec4 src1;
622 out vec4 outSrc1;
623 out vec4 outSrc0;
624 void main() {
625 outSrc0 = src0;
626 outSrc1 = src1;
627 })";
628
629 mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
630 glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
631 });
632
633 ASSERT_NE(0u, mProgram);
634
635 checkOutputIndexQuery("outSrc0", 0);
636 checkOutputIndexQuery("outSrc1", 1);
637
638 drawTest();
639 }
640
641 // Test an ESSL 3.00 shader that uses two array fragment outputs with locations
642 // specified in the shader.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentArrayOutputLocationsInShader)643 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsInShader)
644 {
645 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
646
647 const char *kFragColorShader = R"(#version 300 es
648 #extension GL_EXT_blend_func_extended : require
649 precision mediump float;
650 uniform vec4 src0;
651 uniform vec4 src1;
652 layout(location = 0, index = 1) out vec4 outSrc1[1];
653 layout(location = 0, index = 0) out vec4 outSrc0[1];
654 void main() {
655 outSrc0[0] = src0;
656 outSrc1[0] = src1;
657 })";
658
659 makeProgram(essl3_shaders::vs::Simple(), kFragColorShader);
660
661 checkOutputIndexQuery("outSrc0[0]", 0);
662 checkOutputIndexQuery("outSrc1[0]", 1);
663 checkOutputIndexQuery("outSrc0", 0);
664 checkOutputIndexQuery("outSrc1", 1);
665
666 // These queries use an out of range array index so they should return -1.
667 checkOutputIndexQuery("outSrc0[1]", -1);
668 checkOutputIndexQuery("outSrc1[1]", -1);
669
670 drawTest();
671 }
672
673 // Test an ESSL 3.00 shader that uses two array fragment outputs with locations specified through
674 // the API.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentArrayOutputLocationsAPI)675 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsAPI)
676 {
677 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
678
679 constexpr char kFS[] = R"(#version 300 es
680 #extension GL_EXT_blend_func_extended : require
681 precision mediump float;
682 uniform vec4 src0;
683 uniform vec4 src1;
684 out vec4 outSrc1[1];
685 out vec4 outSrc0[1];
686 void main() {
687 outSrc0[0] = src0;
688 outSrc1[0] = src1;
689 })";
690
691 mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
692 // Specs aren't very clear on what kind of name should be used when binding location for
693 // array variables. We only allow names that do include the "[0]" suffix.
694 glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0[0]");
695 glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1[0]");
696 });
697
698 ASSERT_NE(0u, mProgram);
699
700 // The extension spec is not very clear on what name can be used for the queries for array
701 // variables. We're checking that the queries work in the same way as specified in OpenGL 4.4
702 // page 107.
703 checkOutputIndexQuery("outSrc0[0]", 0);
704 checkOutputIndexQuery("outSrc1[0]", 1);
705 checkOutputIndexQuery("outSrc0", 0);
706 checkOutputIndexQuery("outSrc1", 1);
707
708 // These queries use an out of range array index so they should return -1.
709 checkOutputIndexQuery("outSrc0[1]", -1);
710 checkOutputIndexQuery("outSrc1[1]", -1);
711
712 drawTest();
713 }
714
715 // Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
716 // Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT,
717 // glGetFragDataLocation, glGetFragDataIndexEXT work correctly with
718 // GLSL array output variables. The output variable can be bound by
719 // referring to the variable name with or without the first element array
720 // accessor. The getters can query location of the individual elements in
721 // the array. The test does not actually use the base test drawing,
722 // since the drivers at the time of writing do not support multiple
723 // buffers and dual source blending.
TEST_P(EXTBlendFuncExtendedDrawTestES3,ES3GettersArray)724 TEST_P(EXTBlendFuncExtendedDrawTestES3, ES3GettersArray)
725 {
726 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
727
728 const GLint kTestArraySize = 2;
729 const GLint kFragData0Location = 2;
730 const GLint kFragData1Location = 1;
731 const GLint kUnusedLocation = 5;
732
733 // The test binds kTestArraySize -sized array to location 1 for test purposes.
734 // The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an
735 // array will be bound to continuous locations, starting from the first
736 // location.
737 GLint maxDrawBuffers = 0;
738 glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
739 EXPECT_LT(kTestArraySize, maxDrawBuffers);
740
741 constexpr char kFragColorShader[] = R"(#version 300 es
742 #extension GL_EXT_blend_func_extended : require
743 precision mediump float;
744 uniform vec4 src;
745 uniform vec4 src1;
746 out vec4 FragData[2];
747 void main() {
748 FragData[0] = src;
749 FragData[1] = src1;
750 })";
751
752 struct testCase
753 {
754 std::string unusedLocationName;
755 std::string fragData0LocationName;
756 std::string fragData1LocationName;
757 };
758
759 testCase testCases[4]{{"FragData[0]", "FragData", "FragData[1]"},
760 {"FragData", "FragData[0]", "FragData[1]"},
761 {"FragData[0]", "FragData", "FragData[1]"},
762 {"FragData", "FragData[0]", "FragData[1]"}};
763
764 for (const testCase &test : testCases)
765 {
766 mProgram =
767 CompileProgram(essl3_shaders::vs::Simple(), kFragColorShader, [&](GLuint program) {
768 glBindFragDataLocationEXT(program, kUnusedLocation,
769 test.unusedLocationName.c_str());
770 glBindFragDataLocationEXT(program, kFragData0Location,
771 test.fragData0LocationName.c_str());
772 glBindFragDataLocationEXT(program, kFragData1Location,
773 test.fragData1LocationName.c_str());
774 });
775
776 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
777 LinkProgram();
778 EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData"));
779 EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData"));
780 EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData[0]"));
781 EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[0]"));
782 EXPECT_EQ(kFragData1Location, glGetFragDataLocation(mProgram, "FragData[1]"));
783 EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[1]"));
784 // Index bigger than the GLSL variable array length does not find anything.
785 EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[3]"));
786 }
787 }
788
789 // Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
TEST_P(EXTBlendFuncExtendedDrawTestES3,ESSL3BindSimpleVarAsArrayNoBind)790 TEST_P(EXTBlendFuncExtendedDrawTestES3, ESSL3BindSimpleVarAsArrayNoBind)
791 {
792 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
793
794 constexpr char kFragDataShader[] = R"(#version 300 es
795 #extension GL_EXT_blend_func_extended : require
796 precision mediump float;
797 uniform vec4 src;
798 uniform vec4 src1;
799 out vec4 FragData;
800 out vec4 SecondaryFragData;
801 void main() {
802 FragData = src;
803 SecondaryFragData = src1;
804 })";
805
806 mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFragDataShader, [](GLuint program) {
807 glBindFragDataLocationEXT(program, 0, "FragData[0]");
808 glBindFragDataLocationIndexedEXT(program, 0, 1, "SecondaryFragData[0]");
809 });
810
811 LinkProgram();
812
813 EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[0]"));
814 EXPECT_EQ(0, glGetFragDataLocation(mProgram, "FragData"));
815 EXPECT_EQ(1, glGetFragDataLocation(mProgram, "SecondaryFragData"));
816 // Did not bind index.
817 EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "SecondaryFragData"));
818
819 glBindFragDataLocationEXT(mProgram, 0, "FragData");
820 glBindFragDataLocationIndexedEXT(mProgram, 0, 1, "SecondaryFragData");
821 LinkProgram();
822 }
823
824 // Test an ESSL 3.00 program with a link-time fragment output location conflict.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationConflict)825 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationConflict)
826 {
827 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
828
829 constexpr char kFS[] = R"(#version 300 es
830 #extension GL_EXT_blend_func_extended : require
831 precision mediump float;
832 uniform vec4 src0;
833 uniform vec4 src1;
834 out vec4 out0;
835 out vec4 out1;
836 void main() {
837 out0 = src0;
838 out1 = src1;
839 })";
840
841 GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
842 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
843 ASSERT_NE(0u, vs);
844 ASSERT_NE(0u, fs);
845
846 GLuint program = glCreateProgram();
847 glAttachShader(program, vs);
848 glDeleteShader(vs);
849 glAttachShader(program, fs);
850 glDeleteShader(fs);
851
852 glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");
853 glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");
854
855 // The program should fail to link.
856 glLinkProgram(program);
857 GLint linkStatus;
858 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
859 EXPECT_EQ(0, linkStatus);
860
861 glDeleteProgram(program);
862 }
863
864 // Test an ESSL 3.00 program with some bindings set for nonexistent variables. These should not
865 // create link-time conflicts.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationForNonexistentOutput)866 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationForNonexistentOutput)
867 {
868 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
869
870 constexpr char kFS[] = R"(#version 300 es
871 #extension GL_EXT_blend_func_extended : require
872 precision mediump float;
873 uniform vec4 src0;
874 out vec4 out0;
875 void main() {
876 out0 = src0;
877 })";
878
879 GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
880 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
881 ASSERT_NE(0u, vs);
882 ASSERT_NE(0u, fs);
883
884 GLuint program = glCreateProgram();
885 glAttachShader(program, vs);
886 glDeleteShader(vs);
887 glAttachShader(program, fs);
888 glDeleteShader(fs);
889
890 glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");
891 glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");
892 glBindFragDataLocationIndexedEXT(program, 0, 0, "out2[0]");
893
894 // The program should link successfully - conflicting location for nonexistent variables out1 or
895 // out2 should not be an issue.
896 glLinkProgram(program);
897 GLint linkStatus;
898 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
899 EXPECT_NE(0, linkStatus);
900
901 glDeleteProgram(program);
902 }
903
904 // Test mixing shader-assigned and automatic output locations.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationsPartiallyAutomatic)905 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationsPartiallyAutomatic)
906 {
907 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
908
909 GLint maxDrawBuffers;
910 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
911 ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
912
913 constexpr char kFS[] = R"(#version 300 es
914 #extension GL_EXT_blend_func_extended : require
915 precision mediump float;
916 uniform vec4 src0;
917 uniform vec4 src1;
918 uniform vec4 src2;
919 uniform vec4 src3;
920 layout(location=0) out vec4 out0;
921 layout(location=3) out vec4 out3;
922 out vec4 out12[2];
923 void main() {
924 out0 = src0;
925 out12[0] = src1;
926 out12[1] = src2;
927 out3 = src3;
928 })";
929
930 GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFS);
931 ASSERT_NE(0u, program);
932
933 GLint location = glGetFragDataLocation(program, "out0");
934 EXPECT_EQ(0, location);
935 location = glGetFragDataLocation(program, "out12");
936 EXPECT_EQ(1, location);
937 location = glGetFragDataLocation(program, "out3");
938 EXPECT_EQ(3, location);
939
940 glDeleteProgram(program);
941 }
942
943 // Test a fragment output array that doesn't fit because contiguous locations are not available.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputArrayDoesntFit)944 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputArrayDoesntFit)
945 {
946 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
947
948 GLint maxDrawBuffers;
949 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
950 ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
951
952 std::stringstream fragShader;
953 fragShader << R"(#version 300 es
954 #extension GL_EXT_blend_func_extended : require
955 precision mediump float;
956 layout(location=2) out vec4 out0;
957 out vec4 outArray[)"
958 << (maxDrawBuffers - 1) << R"(];
959 void main() {
960 out0 = vec4(1.0);
961 outArray[0] = vec4(1.0);
962 })";
963
964 GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
965 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragShader.str().c_str());
966 ASSERT_NE(0u, vs);
967 ASSERT_NE(0u, fs);
968
969 GLuint program = glCreateProgram();
970 glAttachShader(program, vs);
971 glDeleteShader(vs);
972 glAttachShader(program, fs);
973 glDeleteShader(fs);
974
975 // The program should not link - there's no way to fit "outArray" into available output
976 // locations.
977 glLinkProgram(program);
978 GLint linkStatus;
979 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
980 EXPECT_EQ(0, linkStatus);
981
982 glDeleteProgram(program);
983 }
984
985 // Test that a secondary blending source limits the number of primary outputs.
TEST_P(EXTBlendFuncExtendedTestES3,TooManyFragmentOutputsForDualSourceBlending)986 TEST_P(EXTBlendFuncExtendedTestES3, TooManyFragmentOutputsForDualSourceBlending)
987 {
988 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
989
990 GLint maxDualSourceDrawBuffers;
991 glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers);
992 ASSERT_GE(maxDualSourceDrawBuffers, 1);
993
994 constexpr char kFS[] = R"(#version 300 es
995 #extension GL_EXT_blend_func_extended : require
996 precision mediump float;
997 out vec4 outSrc0;
998 out vec4 outSrc1;
999 void main() {
1000 outSrc0 = vec4(0.5);
1001 outSrc1 = vec4(1.0);
1002 })";
1003
1004 GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
1005 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
1006 ASSERT_NE(0u, vs);
1007 ASSERT_NE(0u, fs);
1008
1009 GLuint program = glCreateProgram();
1010 glAttachShader(program, vs);
1011 glDeleteShader(vs);
1012 glAttachShader(program, fs);
1013 glDeleteShader(fs);
1014
1015 glBindFragDataLocationIndexedEXT(program, maxDualSourceDrawBuffers, 0, "outSrc0");
1016 glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
1017 ASSERT_GL_NO_ERROR();
1018
1019 GLint linkStatus;
1020 glLinkProgram(program);
1021 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
1022 EXPECT_EQ(0, linkStatus);
1023
1024 glDeleteProgram(program);
1025 }
1026
1027 // Test that fragment outputs bound to the same location must have the same type.
TEST_P(EXTBlendFuncExtendedTestES3,InconsistentTypesForLocationAPI)1028 TEST_P(EXTBlendFuncExtendedTestES3, InconsistentTypesForLocationAPI)
1029 {
1030 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
1031
1032 constexpr char kFS[] = R"(#version 300 es
1033 #extension GL_EXT_blend_func_extended : require
1034 precision mediump float;
1035 out vec4 outSrc0;
1036 out ivec4 outSrc1;
1037 void main() {
1038 outSrc0 = vec4(0.5);
1039 outSrc1 = ivec4(1.0);
1040 })";
1041
1042 GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
1043 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
1044 ASSERT_NE(0u, vs);
1045 ASSERT_NE(0u, fs);
1046
1047 GLuint program = glCreateProgram();
1048 glAttachShader(program, vs);
1049 glDeleteShader(vs);
1050 glAttachShader(program, fs);
1051 glDeleteShader(fs);
1052
1053 glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0");
1054 glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
1055 ASSERT_GL_NO_ERROR();
1056
1057 GLint linkStatus;
1058 glLinkProgram(program);
1059 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
1060 EXPECT_EQ(0, linkStatus);
1061
1062 glDeleteProgram(program);
1063 }
1064
1065 // Test that rendering to multiple fragment outputs bound via API works.
TEST_P(EXTBlendFuncExtendedDrawTestES3,MultipleDrawBuffersAPI)1066 TEST_P(EXTBlendFuncExtendedDrawTestES3, MultipleDrawBuffersAPI)
1067 {
1068 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
1069
1070 constexpr char kFS[] = R"(#version 300 es
1071 #extension GL_EXT_blend_func_extended : require
1072 precision mediump float;
1073 out vec4 outSrc0;
1074 out ivec4 outSrc1;
1075 void main() {
1076 outSrc0 = vec4(0.0, 1.0, 0.0, 1.0);
1077 outSrc1 = ivec4(1, 2, 3, 4);
1078 })";
1079
1080 mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
1081 glBindFragDataLocationEXT(program, 0, "outSrc0");
1082 glBindFragDataLocationEXT(program, 1, "outSrc1");
1083 });
1084
1085 ASSERT_NE(0u, mProgram);
1086
1087 GLRenderbuffer rb0;
1088 glBindRenderbuffer(GL_RENDERBUFFER, rb0);
1089 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
1090
1091 GLRenderbuffer rb1;
1092 glBindRenderbuffer(GL_RENDERBUFFER, rb1);
1093 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8I, 1, 1);
1094
1095 GLFramebuffer fbo;
1096 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1097
1098 const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
1099 glDrawBuffers(2, bufs);
1100
1101 GLfloat clearF[] = {0.0, 0.0, 0.0, 0.0};
1102 GLint clearI[] = {0, 0, 0, 0};
1103
1104 // FBO: rb0 (rgba8), rb1 (rgba8i)
1105 glBindRenderbuffer(GL_RENDERBUFFER, rb0);
1106 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb0);
1107 glBindRenderbuffer(GL_RENDERBUFFER, rb1);
1108 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rb1);
1109 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1110
1111 glClearBufferfv(GL_COLOR, 0, clearF);
1112 glClearBufferiv(GL_COLOR, 1, clearI);
1113 ASSERT_GL_NO_ERROR();
1114
1115 glReadBuffer(GL_COLOR_ATTACHMENT0);
1116 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
1117 glReadBuffer(GL_COLOR_ATTACHMENT1);
1118 EXPECT_PIXEL_8I(0, 0, 0, 0, 0, 0);
1119
1120 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.0);
1121 ASSERT_GL_NO_ERROR();
1122
1123 glReadBuffer(GL_COLOR_ATTACHMENT0);
1124 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1125 glReadBuffer(GL_COLOR_ATTACHMENT1);
1126 EXPECT_PIXEL_8I(0, 0, 1, 2, 3, 4);
1127
1128 // FBO: rb1 (rgba8i), rb0 (rgba8)
1129 glBindRenderbuffer(GL_RENDERBUFFER, rb0);
1130 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rb0);
1131 glBindRenderbuffer(GL_RENDERBUFFER, rb1);
1132 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb1);
1133 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1134
1135 // Rebind fragment outputs
1136 glBindFragDataLocationEXT(mProgram, 0, "outSrc1");
1137 glBindFragDataLocationEXT(mProgram, 1, "outSrc0");
1138 glLinkProgram(mProgram);
1139
1140 glClearBufferfv(GL_COLOR, 1, clearF);
1141 glClearBufferiv(GL_COLOR, 0, clearI);
1142 ASSERT_GL_NO_ERROR();
1143
1144 glReadBuffer(GL_COLOR_ATTACHMENT1);
1145 EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
1146 glReadBuffer(GL_COLOR_ATTACHMENT0);
1147 EXPECT_PIXEL_8I(0, 0, 0, 0, 0, 0);
1148
1149 drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.0);
1150 ASSERT_GL_NO_ERROR();
1151
1152 glReadBuffer(GL_COLOR_ATTACHMENT1);
1153 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
1154 glReadBuffer(GL_COLOR_ATTACHMENT0);
1155 EXPECT_PIXEL_8I(0, 0, 1, 2, 3, 4);
1156 }
1157
1158 // Use a program pipeline with EXT_blend_func_extended
TEST_P(EXTBlendFuncExtendedDrawTestES31,UseProgramPipeline)1159 TEST_P(EXTBlendFuncExtendedDrawTestES31, UseProgramPipeline)
1160 {
1161 // Only the Vulkan backend supports PPO
1162 ANGLE_SKIP_TEST_IF(!IsVulkan());
1163
1164 // Create two separable program objects from a
1165 // single source string respectively (vertSrc and fragSrc)
1166 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
1167
1168 const char *kFragColorShader = R"(#version 300 es
1169 #extension GL_EXT_blend_func_extended : require
1170 precision mediump float;
1171 uniform vec4 src0;
1172 uniform vec4 src1;
1173 layout(location = 0, index = 1) out vec4 outSrc1;
1174 layout(location = 0, index = 0) out vec4 outSrc0;
1175 void main() {
1176 outSrc0 = src0;
1177 outSrc1 = src1;
1178 })";
1179
1180 setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShader);
1181
1182 checkOutputIndexQuery("outSrc0", 0);
1183 checkOutputIndexQuery("outSrc1", 1);
1184
1185 ASSERT_EQ(mProgram, 0u);
1186 drawTest();
1187
1188 ASSERT_GL_NO_ERROR();
1189 }
1190
1191 // Use program pipeline where the fragment program is changed
TEST_P(EXTBlendFuncExtendedDrawTestES31,UseTwoProgramStages)1192 TEST_P(EXTBlendFuncExtendedDrawTestES31, UseTwoProgramStages)
1193 {
1194 // Only the Vulkan backend supports PPO
1195 ANGLE_SKIP_TEST_IF(!IsVulkan());
1196
1197 // Create two separable program objects from a
1198 // single source string respectively (vertSrc and fragSrc)
1199 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
1200
1201 const char *kFragColorShaderFlipped = R"(#version 300 es
1202 #extension GL_EXT_blend_func_extended : require
1203 precision mediump float;
1204 uniform vec4 src0;
1205 uniform vec4 src1;
1206 layout(location = 0, index = 0) out vec4 outSrc1;
1207 layout(location = 0, index = 1) out vec4 outSrc0;
1208 void main() {
1209 outSrc0 = src0;
1210 outSrc1 = src1;
1211 })";
1212
1213 const char *kFragColorShader = R"(#version 300 es
1214 #extension GL_EXT_blend_func_extended : require
1215 precision mediump float;
1216 uniform vec4 src0;
1217 uniform vec4 src1;
1218 layout(location = 0, index = 1) out vec4 outSrc1;
1219 layout(location = 0, index = 0) out vec4 outSrc0;
1220 void main() {
1221 outSrc0 = src0;
1222 outSrc1 = src1;
1223 })";
1224
1225 setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShaderFlipped);
1226
1227 // Check index values frag shader with the "flipped" index values
1228 checkOutputIndexQuery("outSrc0", 1);
1229 checkOutputIndexQuery("outSrc1", 0);
1230
1231 GLuint previousProgram = mFragProgram;
1232 mFragProgram = createShaderProgram(GL_FRAGMENT_SHADER, kFragColorShader);
1233 ASSERT_NE(mFragProgram, 0u);
1234
1235 // Change the Fragment program of the pipeline
1236 glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);
1237 EXPECT_GL_NO_ERROR();
1238
1239 checkOutputIndexQuery("outSrc0", 0);
1240 checkOutputIndexQuery("outSrc1", 1);
1241
1242 ASSERT_EQ(mProgram, 0u);
1243 drawTest();
1244
1245 if (previousProgram)
1246 {
1247 glDeleteProgram(previousProgram);
1248 }
1249 ASSERT_GL_NO_ERROR();
1250 }
1251
1252 ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedTest);
1253
1254 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedTestES3);
1255 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedTestES3);
1256
1257 ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedDrawTest);
1258
1259 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedDrawTestES3);
1260 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedDrawTestES3);
1261
1262 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedDrawTestES31);
1263 ANGLE_INSTANTIATE_TEST_ES31(EXTBlendFuncExtendedDrawTestES31);
1264