• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
11 #include "util/shader_utils.h"
12 
13 #include <algorithm>
14 #include <cmath>
15 #include <fstream>
16 
17 using namespace angle;
18 
19 namespace
20 {
21 
22 // Partial implementation of weight function for GLES 2 blend equation that
23 // is dual-source aware.
24 template <int factor, int index>
Weight(const float[4],const float src[4],const float src1[4])25 float Weight(const float /*dst*/[4], const float src[4], const float src1[4])
26 {
27     if (factor == GL_SRC_COLOR)
28         return src[index];
29     if (factor == GL_SRC_ALPHA)
30         return src[3];
31     if (factor == GL_SRC1_COLOR_EXT)
32         return src1[index];
33     if (factor == GL_SRC1_ALPHA_EXT)
34         return src1[3];
35     if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT)
36         return 1.0f - src1[index];
37     if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT)
38         return 1.0f - src1[3];
39     return 0.0f;
40 }
41 
ScaleChannel(float weight)42 GLubyte ScaleChannel(float weight)
43 {
44     return static_cast<GLubyte>(std::floor(std::max(0.0f, std::min(1.0f, weight)) * 255.0f));
45 }
46 
47 // Implementation of GLES 2 blend equation that is dual-source aware.
48 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)49 void BlendEquationFuncAdd(const float dst[4],
50                           const float src[4],
51                           const float src1[4],
52                           angle::GLColor *result)
53 {
54     float r[4];
55     r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) + dst[0] * Weight<RGBd, 0>(dst, src, src1);
56     r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) + dst[1] * Weight<RGBd, 1>(dst, src, src1);
57     r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) + dst[2] * Weight<RGBd, 2>(dst, src, src1);
58     r[3] = src[3] * Weight<As, 3>(dst, src, src1) + dst[3] * Weight<Ad, 3>(dst, src, src1);
59 
60     result->R = ScaleChannel(r[0]);
61     result->G = ScaleChannel(r[1]);
62     result->B = ScaleChannel(r[2]);
63     result->A = ScaleChannel(r[3]);
64 }
65 
CheckPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLint tolerance,const angle::GLColor & color)66 void CheckPixels(GLint x,
67                  GLint y,
68                  GLsizei width,
69                  GLsizei height,
70                  GLint tolerance,
71                  const angle::GLColor &color)
72 {
73     for (GLint yy = 0; yy < height; ++yy)
74     {
75         for (GLint xx = 0; xx < width; ++xx)
76         {
77             const auto px = x + xx;
78             const auto py = y + yy;
79             EXPECT_PIXEL_COLOR_NEAR(px, py, color, 1);
80         }
81     }
82 }
83 
84 const GLuint kWidth  = 100;
85 const GLuint kHeight = 100;
86 
87 class EXTBlendFuncExtendedTest : public ANGLETest
88 {};
89 
90 class EXTBlendFuncExtendedTestES3 : public ANGLETest
91 {};
92 
93 class EXTBlendFuncExtendedDrawTest : public ANGLETest
94 {
95   protected:
EXTBlendFuncExtendedDrawTest()96     EXTBlendFuncExtendedDrawTest() : mProgram(0)
97     {
98         setWindowWidth(kWidth);
99         setWindowHeight(kHeight);
100         setConfigRedBits(8);
101         setConfigGreenBits(8);
102         setConfigBlueBits(8);
103         setConfigAlphaBits(8);
104     }
105 
testSetUp()106     void testSetUp() override
107     {
108         glGenBuffers(1, &mVBO);
109         glBindBuffer(GL_ARRAY_BUFFER, mVBO);
110 
111         static const float vertices[] = {
112             1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
113         };
114         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
115 
116         ASSERT_GL_NO_ERROR();
117     }
118 
testTearDown()119     void testTearDown() override
120     {
121         glDeleteBuffers(1, &mVBO);
122         if (mProgram)
123         {
124             glDeleteProgram(mProgram);
125         }
126 
127         ASSERT_GL_NO_ERROR();
128     }
129 
makeProgram(const char * vertSource,const char * fragSource)130     void makeProgram(const char *vertSource, const char *fragSource)
131     {
132         mProgram = CompileProgram(vertSource, fragSource);
133 
134         ASSERT_NE(0u, mProgram);
135     }
136 
drawTest()137     void drawTest()
138     {
139         glUseProgram(mProgram);
140 
141         GLint position = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
142         GLint src0     = glGetUniformLocation(mProgram, "src0");
143         GLint src1     = glGetUniformLocation(mProgram, "src1");
144         ASSERT_GL_NO_ERROR();
145 
146         glBindBuffer(GL_ARRAY_BUFFER, mVBO);
147         glEnableVertexAttribArray(position);
148         glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);
149         ASSERT_GL_NO_ERROR();
150 
151         static const float kDst[4]  = {0.5f, 0.5f, 0.5f, 0.5f};
152         static const float kSrc0[4] = {1.0f, 1.0f, 1.0f, 1.0f};
153         static const float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f};
154 
155         glUniform4f(src0, kSrc0[0], kSrc0[1], kSrc0[2], kSrc0[3]);
156         glUniform4f(src1, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]);
157         ASSERT_GL_NO_ERROR();
158 
159         glEnable(GL_BLEND);
160         glBlendEquation(GL_FUNC_ADD);
161         glViewport(0, 0, kWidth, kHeight);
162         glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]);
163         ASSERT_GL_NO_ERROR();
164 
165         {
166             glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_COLOR_EXT,
167                                 GL_ONE_MINUS_SRC1_ALPHA_EXT);
168 
169             glClear(GL_COLOR_BUFFER_BIT);
170             glDrawArrays(GL_TRIANGLES, 0, 6);
171             ASSERT_GL_NO_ERROR();
172 
173             // verify
174             angle::GLColor color;
175             BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_COLOR_EXT,
176                                  GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc0, kSrc1, &color);
177 
178             CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, 1, color);
179             CheckPixels(kWidth - 1, 0, 1, 1, 1, color);
180         }
181 
182         {
183             glBlendFuncSeparate(GL_ONE_MINUS_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC_ALPHA,
184                                 GL_ONE_MINUS_SRC_COLOR, GL_SRC1_ALPHA_EXT);
185 
186             glClear(GL_COLOR_BUFFER_BIT);
187             glDrawArrays(GL_TRIANGLES, 0, 6);
188             ASSERT_GL_NO_ERROR();
189 
190             // verify
191             angle::GLColor color;
192             BlendEquationFuncAdd<GL_ONE_MINUS_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC_ALPHA,
193                                  GL_ONE_MINUS_SRC_COLOR, GL_SRC1_ALPHA_EXT>(kDst, kSrc0, kSrc1,
194                                                                             &color);
195 
196             CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, 1, color);
197             CheckPixels(kWidth - 1, 0, 1, 1, 1, color);
198         }
199     }
200 
201     GLuint mVBO;
202     GLuint mProgram;
203 };
204 
205 class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest
206 {
207   protected:
EXTBlendFuncExtendedDrawTestES3()208     EXTBlendFuncExtendedDrawTestES3() : EXTBlendFuncExtendedDrawTest(), mIsES31OrNewer(false) {}
209 
testSetUp()210     void testSetUp() override
211     {
212         EXTBlendFuncExtendedDrawTest::testSetUp();
213         if (getClientMajorVersion() > 3 ||
214             (getClientMajorVersion() == 3 && getClientMinorVersion() >= 1))
215         {
216             mIsES31OrNewer = true;
217         }
218     }
checkOutputIndexQuery(const char * name,GLint expectedIndex)219     void checkOutputIndexQuery(const char *name, GLint expectedIndex)
220     {
221         GLint index = glGetFragDataIndexEXT(mProgram, name);
222         EXPECT_EQ(expectedIndex, index);
223         if (mIsES31OrNewer)
224         {
225             index = glGetProgramResourceLocationIndexEXT(mProgram, GL_PROGRAM_OUTPUT, name);
226             EXPECT_EQ(expectedIndex, index);
227         }
228         else
229         {
230             glGetProgramResourceLocationIndexEXT(mProgram, GL_PROGRAM_OUTPUT, name);
231             EXPECT_GL_ERROR(GL_INVALID_OPERATION);
232         }
233     }
234 
LinkProgram()235     void LinkProgram()
236     {
237         glLinkProgram(mProgram);
238         GLint linked = 0;
239         glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);
240         EXPECT_NE(0, linked);
241         glUseProgram(mProgram);
242         return;
243     }
244 
245   private:
246     bool mIsES31OrNewer;
247 };
248 
249 }  // namespace
250 
251 // Test EXT_blend_func_extended related gets.
TEST_P(EXTBlendFuncExtendedTest,TestMaxDualSourceDrawBuffers)252 TEST_P(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers)
253 {
254     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
255 
256     GLint maxDualSourceDrawBuffers = 0;
257     glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers);
258     EXPECT_GT(maxDualSourceDrawBuffers, 0);
259 
260     ASSERT_GL_NO_ERROR();
261 }
262 
263 // Test a shader with EXT_blend_func_extended and gl_SecondaryFragColorEXT.
264 // Outputs to primary color buffer using primary and secondary colors.
TEST_P(EXTBlendFuncExtendedDrawTest,FragColor)265 TEST_P(EXTBlendFuncExtendedDrawTest, FragColor)
266 {
267     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
268 
269     const char *kFragColorShader =
270         "#extension GL_EXT_blend_func_extended : require\n"
271         "precision mediump float;\n"
272         "uniform vec4 src0;\n"
273         "uniform vec4 src1;\n"
274         "void main() {\n"
275         "  gl_FragColor = src0;\n"
276         "  gl_SecondaryFragColorEXT = src1;\n"
277         "}\n";
278 
279     makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
280 
281     drawTest();
282 }
283 
284 // Test a shader with EXT_blend_func_extended and gl_FragData.
285 // Outputs to a color buffer using primary and secondary frag data.
TEST_P(EXTBlendFuncExtendedDrawTest,FragData)286 TEST_P(EXTBlendFuncExtendedDrawTest, FragData)
287 {
288     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
289 
290     const char *kFragColorShader =
291         "#extension GL_EXT_blend_func_extended : require\n"
292         "precision mediump float;\n"
293         "uniform vec4 src0;\n"
294         "uniform vec4 src1;\n"
295         "void main() {\n"
296         "  gl_FragData[0] = src0;\n"
297         "  gl_SecondaryFragDataEXT[0] = src1;\n"
298         "}\n";
299 
300     makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
301 
302     drawTest();
303 }
304 
305 // Test an ESSL 3.00 shader that uses two fragment outputs with locations specified in the shader.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsInShader)306 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsInShader)
307 {
308     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
309 
310     const char *kFragColorShader = R"(#version 300 es
311 #extension GL_EXT_blend_func_extended : require
312 precision mediump float;
313 uniform vec4 src0;
314 uniform vec4 src1;
315 layout(location = 0, index = 1) out vec4 outSrc1;
316 layout(location = 0, index = 0) out vec4 outSrc0;
317 void main() {
318     outSrc0 = src0;
319     outSrc1 = src1;
320 })";
321 
322     makeProgram(essl3_shaders::vs::Simple(), kFragColorShader);
323 
324     checkOutputIndexQuery("outSrc0", 0);
325     checkOutputIndexQuery("outSrc1", 1);
326 
327     drawTest();
328 }
329 
330 // Test an ESSL 3.00 shader that uses two fragment outputs with locations specified through the API.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationAPI)331 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationAPI)
332 {
333     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
334 
335     constexpr char kFS[] = R"(#version 300 es
336 #extension GL_EXT_blend_func_extended : require
337 precision mediump float;
338 uniform vec4 src0;
339 uniform vec4 src1;
340 out vec4 outSrc1;
341 out vec4 outSrc0;
342 void main() {
343     outSrc0 = src0;
344     outSrc1 = src1;
345 })";
346 
347     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
348         glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0");
349         glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
350     });
351 
352     ASSERT_NE(0u, mProgram);
353 
354     checkOutputIndexQuery("outSrc0", 0);
355     checkOutputIndexQuery("outSrc1", 1);
356 
357     drawTest();
358 }
359 
360 // Test an ESSL 3.00 shader that uses two fragment outputs, with location for one specified through
361 // the API and location for another being set automatically.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsAPIAndAutomatic)362 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsAPIAndAutomatic)
363 {
364     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
365 
366     constexpr char kFS[] = R"(#version 300 es
367 #extension GL_EXT_blend_func_extended : require
368 precision mediump float;
369 uniform vec4 src0;
370 uniform vec4 src1;
371 out vec4 outSrc1;
372 out vec4 outSrc0;
373 void main() {
374     outSrc0 = src0;
375     outSrc1 = src1;
376 })";
377 
378     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
379         glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
380     });
381 
382     ASSERT_NE(0u, mProgram);
383 
384     checkOutputIndexQuery("outSrc0", 0);
385     checkOutputIndexQuery("outSrc1", 1);
386 
387     drawTest();
388 }
389 
390 // Test an ESSL 3.00 shader that uses two array fragment outputs with locations specified through
391 // the API.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentArrayOutputLocationsAPI)392 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsAPI)
393 {
394     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
395 
396     // TODO: Investigate this mac-only failure.  http://angleproject.com/1085
397     ANGLE_SKIP_TEST_IF(IsOSX());
398 
399     constexpr char kFS[] = R"(#version 300 es
400 #extension GL_EXT_blend_func_extended : require
401 precision mediump float;
402 uniform vec4 src0;
403 uniform vec4 src1;
404 out vec4 outSrc1[1];
405 out vec4 outSrc0[1];
406 void main() {
407     outSrc0[0] = src0;
408     outSrc1[0] = src1;
409 })";
410 
411     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
412         // Specs aren't very clear on what kind of name should be used when binding location for
413         // array variables. We only allow names that do include the "[0]" suffix.
414         glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0[0]");
415         glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1[0]");
416     });
417 
418     ASSERT_NE(0u, mProgram);
419 
420     // The extension spec is not very clear on what name can be used for the queries for array
421     // variables. We're checking that the queries work in the same way as specified in OpenGL 4.4
422     // page 107.
423     checkOutputIndexQuery("outSrc0[0]", 0);
424     checkOutputIndexQuery("outSrc1[0]", 1);
425     checkOutputIndexQuery("outSrc0", 0);
426     checkOutputIndexQuery("outSrc1", 1);
427 
428     // These queries use an out of range array index so they should return -1.
429     checkOutputIndexQuery("outSrc0[1]", -1);
430     checkOutputIndexQuery("outSrc1[1]", -1);
431 
432     drawTest();
433 }
434 
435 // Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
436 // Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT,
437 // glGetFragDataLocation, glGetFragDataIndexEXT work correctly with
438 // GLSL array output variables. The output variable can be bound by
439 // referring to the variable name with or without the first element array
440 // accessor. The getters can query location of the individual elements in
441 // the array. The test does not actually use the base test drawing,
442 // since the drivers at the time of writing do not support multiple
443 // buffers and dual source blending.
TEST_P(EXTBlendFuncExtendedDrawTestES3,ES3GettersArray)444 TEST_P(EXTBlendFuncExtendedDrawTestES3, ES3GettersArray)
445 {
446     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
447 
448     // TODO(zmo): Figure out why this fails on AMD. crbug.com/585132.
449     // Also fails on the Intel Mesa driver, see
450     // https://bugs.freedesktop.org/show_bug.cgi?id=96765
451     ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD());
452     ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel());
453 
454     const GLint kTestArraySize     = 2;
455     const GLint kFragData0Location = 2;
456     const GLint kFragData1Location = 1;
457     const GLint kUnusedLocation    = 5;
458 
459     // The test binds kTestArraySize -sized array to location 1 for test purposes.
460     // The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an
461     // array will be bound to continuous locations, starting from the first
462     // location.
463     GLint maxDrawBuffers = 0;
464     glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
465     EXPECT_LT(kTestArraySize, maxDrawBuffers);
466 
467     constexpr char kFragColorShader[] = R"(#version 300 es
468 #extension GL_EXT_blend_func_extended : require
469 precision mediump float;
470 uniform vec4 src;
471 uniform vec4 src1;
472 out vec4 FragData[2];
473 void main() {
474     FragData[0] = src;
475     FragData[1] = src1;
476 })";
477 
478     struct testCase
479     {
480         std::string unusedLocationName;
481         std::string fragData0LocationName;
482         std::string fragData1LocationName;
483     };
484 
485     testCase testCases[4]{{"FragData[0]", "FragData", "FragData[1]"},
486                           {"FragData", "FragData[0]", "FragData[1]"},
487                           {"FragData[0]", "FragData", "FragData[1]"},
488                           {"FragData", "FragData[0]", "FragData[1]"}};
489 
490     for (const testCase &test : testCases)
491     {
492         mProgram =
493             CompileProgram(essl3_shaders::vs::Simple(), kFragColorShader, [&](GLuint program) {
494                 glBindFragDataLocationEXT(program, kUnusedLocation,
495                                           test.unusedLocationName.c_str());
496                 glBindFragDataLocationEXT(program, kFragData0Location,
497                                           test.fragData0LocationName.c_str());
498                 glBindFragDataLocationEXT(program, kFragData1Location,
499                                           test.fragData1LocationName.c_str());
500             });
501 
502         EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
503         LinkProgram();
504         EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData"));
505         EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData"));
506         EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData[0]"));
507         EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[0]"));
508         EXPECT_EQ(kFragData1Location, glGetFragDataLocation(mProgram, "FragData[1]"));
509         EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[1]"));
510         // Index bigger than the GLSL variable array length does not find anything.
511         EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[3]"));
512     }
513 }
514 
515 // Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
TEST_P(EXTBlendFuncExtendedDrawTestES3,ESSL3BindSimpleVarAsArrayNoBind)516 TEST_P(EXTBlendFuncExtendedDrawTestES3, ESSL3BindSimpleVarAsArrayNoBind)
517 {
518     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
519 
520     constexpr char kFragDataShader[] = R"(#version 300 es
521 #extension GL_EXT_blend_func_extended : require
522 precision mediump float;
523 uniform vec4 src;
524 uniform vec4 src1;
525 out vec4 FragData;
526 out vec4 SecondaryFragData;
527 void main() {
528     FragData = src;
529     SecondaryFragData = src1;
530 })";
531 
532     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFragDataShader, [](GLuint program) {
533         glBindFragDataLocationEXT(program, 0, "FragData[0]");
534         glBindFragDataLocationIndexedEXT(program, 0, 1, "SecondaryFragData[0]");
535     });
536 
537     LinkProgram();
538 
539     EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[0]"));
540     EXPECT_EQ(0, glGetFragDataLocation(mProgram, "FragData"));
541     EXPECT_EQ(1, glGetFragDataLocation(mProgram, "SecondaryFragData"));
542     // Did not bind index.
543     EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "SecondaryFragData"));
544 
545     glBindFragDataLocationEXT(mProgram, 0, "FragData");
546     glBindFragDataLocationIndexedEXT(mProgram, 0, 1, "SecondaryFragData");
547     LinkProgram();
548 }
549 
550 // Test an ESSL 3.00 program with a link-time fragment output location conflict.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationConflict)551 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationConflict)
552 {
553     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
554 
555     constexpr char kFS[] = R"(#version 300 es
556 #extension GL_EXT_blend_func_extended : require
557 precision mediump float;
558 uniform vec4 src0;
559 uniform vec4 src1;
560 out vec4 out0;
561 out vec4 out1;
562 void main() {
563     out0 = src0;
564     out1 = src1;
565 })";
566 
567     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
568     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
569     ASSERT_NE(0u, vs);
570     ASSERT_NE(0u, fs);
571 
572     GLuint program = glCreateProgram();
573     glAttachShader(program, vs);
574     glDeleteShader(vs);
575     glAttachShader(program, fs);
576     glDeleteShader(fs);
577 
578     glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");
579     glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");
580 
581     // The program should fail to link.
582     glLinkProgram(program);
583     GLint linkStatus;
584     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
585     EXPECT_EQ(0, linkStatus);
586 
587     glDeleteProgram(program);
588 }
589 
590 // Test an ESSL 3.00 program with some bindings set for nonexistent variables. These should not
591 // create link-time conflicts.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationForNonexistentOutput)592 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationForNonexistentOutput)
593 {
594     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
595 
596     constexpr char kFS[] = R"(#version 300 es
597 #extension GL_EXT_blend_func_extended : require
598 precision mediump float;
599 uniform vec4 src0;
600 out vec4 out0;
601 void main() {
602     out0 = src0;
603 })";
604 
605     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
606     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
607     ASSERT_NE(0u, vs);
608     ASSERT_NE(0u, fs);
609 
610     GLuint program = glCreateProgram();
611     glAttachShader(program, vs);
612     glDeleteShader(vs);
613     glAttachShader(program, fs);
614     glDeleteShader(fs);
615 
616     glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");
617     glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");
618     glBindFragDataLocationIndexedEXT(program, 0, 0, "out2[0]");
619 
620     // The program should link successfully - conflicting location for nonexistent variables out1 or
621     // out2 should not be an issue.
622     glLinkProgram(program);
623     GLint linkStatus;
624     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
625     EXPECT_NE(0, linkStatus);
626 
627     glDeleteProgram(program);
628 }
629 
630 // Test mixing shader-assigned and automatic output locations.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationsPartiallyAutomatic)631 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationsPartiallyAutomatic)
632 {
633     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
634 
635     GLint maxDrawBuffers;
636     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
637     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
638 
639     constexpr char kFS[] = R"(#version 300 es
640 #extension GL_EXT_blend_func_extended : require
641 precision mediump float;
642 uniform vec4 src0;
643 uniform vec4 src1;
644 uniform vec4 src2;
645 uniform vec4 src3;
646 layout(location=0) out vec4 out0;
647 layout(location=3) out vec4 out3;
648 out vec4 out12[2];
649 void main() {
650     out0 = src0;
651     out12[0] = src1;
652     out12[1] = src2;
653     out3 = src3;
654 })";
655 
656     GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFS);
657     ASSERT_NE(0u, program);
658 
659     GLint location = glGetFragDataLocation(program, "out0");
660     EXPECT_EQ(0, location);
661     location = glGetFragDataLocation(program, "out12");
662     EXPECT_EQ(1, location);
663     location = glGetFragDataLocation(program, "out3");
664     EXPECT_EQ(3, location);
665 
666     glDeleteProgram(program);
667 }
668 
669 // Test a fragment output array that doesn't fit because contiguous locations are not available.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputArrayDoesntFit)670 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputArrayDoesntFit)
671 {
672     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
673 
674     GLint maxDrawBuffers;
675     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
676     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
677 
678     std::stringstream fragShader;
679     fragShader << R"(#version 300 es
680 #extension GL_EXT_blend_func_extended : require
681 precision mediump float;
682 layout(location=2) out vec4 out0;
683 out vec4 outArray[)"
684                << (maxDrawBuffers - 1) << R"(];
685 void main() {
686     out0 = vec4(1.0);
687     outArray[0] = vec4(1.0);
688 })";
689 
690     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
691     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragShader.str().c_str());
692     ASSERT_NE(0u, vs);
693     ASSERT_NE(0u, fs);
694 
695     GLuint program = glCreateProgram();
696     glAttachShader(program, vs);
697     glDeleteShader(vs);
698     glAttachShader(program, fs);
699     glDeleteShader(fs);
700 
701     // The program should not link - there's no way to fit "outArray" into available output
702     // locations.
703     glLinkProgram(program);
704     GLint linkStatus;
705     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
706     EXPECT_EQ(0, linkStatus);
707 
708     glDeleteProgram(program);
709 }
710 
711 ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedTest);
712 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedTestES3);
713 
714 ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedDrawTest);
715 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedDrawTestES3);
716