xref: /aosp_15_r20/external/angle/src/tests/gl_tests/BlendFuncExtendedTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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