• 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 #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, 1);
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.get())
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 a shader with EXT_blend_func_extended and gl_SecondaryFragColorEXT.
384 // Outputs to primary color buffer using primary and secondary colors.
TEST_P(EXTBlendFuncExtendedDrawTest,FragColor)385 TEST_P(EXTBlendFuncExtendedDrawTest, FragColor)
386 {
387     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
388 
389     const char *kFragColorShader =
390         "#extension GL_EXT_blend_func_extended : require\n"
391         "precision mediump float;\n"
392         "uniform vec4 src0;\n"
393         "uniform vec4 src1;\n"
394         "void main() {\n"
395         "  gl_FragColor = src0;\n"
396         "  gl_SecondaryFragColorEXT = src1;\n"
397         "}\n";
398 
399     makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
400 
401     drawTest();
402 }
403 
404 // Test a shader with EXT_blend_func_extended and gl_FragData.
405 // Outputs to a color buffer using primary and secondary frag data.
TEST_P(EXTBlendFuncExtendedDrawTest,FragData)406 TEST_P(EXTBlendFuncExtendedDrawTest, FragData)
407 {
408     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
409 
410     // Suspected VK driver bug http://anglebug.com/5523
411     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsNVIDIA() || IsPixel2()));
412 
413     // Suspected AMD VK driver bug http://anglebug.com/5537
414     ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && IsAMD());
415 
416     const char *kFragColorShader =
417         "#extension GL_EXT_blend_func_extended : require\n"
418         "precision mediump float;\n"
419         "uniform vec4 src0;\n"
420         "uniform vec4 src1;\n"
421         "void main() {\n"
422         "  gl_FragData[0] = src0;\n"
423         "  gl_SecondaryFragDataEXT[0] = src1;\n"
424         "}\n";
425 
426     makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);
427 
428     drawTest();
429 }
430 
431 // Test an ESSL 3.00 shader that uses two fragment outputs with locations specified in the shader.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsInShader)432 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsInShader)
433 {
434     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
435 
436     const char *kFragColorShader = R"(#version 300 es
437 #extension GL_EXT_blend_func_extended : require
438 precision mediump float;
439 uniform vec4 src0;
440 uniform vec4 src1;
441 layout(location = 0, index = 1) out vec4 outSrc1;
442 layout(location = 0, index = 0) out vec4 outSrc0;
443 void main() {
444     outSrc0 = src0;
445     outSrc1 = src1;
446 })";
447 
448     makeProgram(essl3_shaders::vs::Simple(), kFragColorShader);
449 
450     checkOutputIndexQuery("outSrc0", 0);
451     checkOutputIndexQuery("outSrc1", 1);
452 
453     drawTest();
454 }
455 
456 // Test an ESSL 3.00 shader that uses two fragment outputs with locations specified through the API.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationAPI)457 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationAPI)
458 {
459     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
460 
461     constexpr char kFS[] = R"(#version 300 es
462 #extension GL_EXT_blend_func_extended : require
463 precision mediump float;
464 uniform vec4 src0;
465 uniform vec4 src1;
466 out vec4 outSrc1;
467 out vec4 outSrc0;
468 void main() {
469     outSrc0 = src0;
470     outSrc1 = src1;
471 })";
472 
473     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
474         glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0");
475         glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
476     });
477 
478     ASSERT_NE(0u, mProgram);
479 
480     checkOutputIndexQuery("outSrc0", 0);
481     checkOutputIndexQuery("outSrc1", 1);
482 
483     drawTest();
484 }
485 
486 // Test an ESSL 3.00 shader that uses two fragment outputs, with location for one specified through
487 // the API and location for another being set automatically.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentOutputLocationsAPIAndAutomatic)488 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsAPIAndAutomatic)
489 {
490     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
491 
492     constexpr char kFS[] = R"(#version 300 es
493 #extension GL_EXT_blend_func_extended : require
494 precision mediump float;
495 uniform vec4 src0;
496 uniform vec4 src1;
497 out vec4 outSrc1;
498 out vec4 outSrc0;
499 void main() {
500     outSrc0 = src0;
501     outSrc1 = src1;
502 })";
503 
504     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
505         glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");
506     });
507 
508     ASSERT_NE(0u, mProgram);
509 
510     checkOutputIndexQuery("outSrc0", 0);
511     checkOutputIndexQuery("outSrc1", 1);
512 
513     drawTest();
514 }
515 
516 // Test an ESSL 3.00 shader that uses two array fragment outputs with locations specified through
517 // the API.
TEST_P(EXTBlendFuncExtendedDrawTestES3,FragmentArrayOutputLocationsAPI)518 TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsAPI)
519 {
520     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
521 
522     // TODO: Investigate this mac-only failure.  http://angleproject.com/1085
523     ANGLE_SKIP_TEST_IF(IsOSX());
524 
525     // Suspected VK driver bug http://anglebug.com/5523
526     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsNVIDIA() || IsPixel2()));
527 
528     constexpr char kFS[] = R"(#version 300 es
529 #extension GL_EXT_blend_func_extended : require
530 precision mediump float;
531 uniform vec4 src0;
532 uniform vec4 src1;
533 out vec4 outSrc1[1];
534 out vec4 outSrc0[1];
535 void main() {
536     outSrc0[0] = src0;
537     outSrc1[0] = src1;
538 })";
539 
540     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {
541         // Specs aren't very clear on what kind of name should be used when binding location for
542         // array variables. We only allow names that do include the "[0]" suffix.
543         glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0[0]");
544         glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1[0]");
545     });
546 
547     ASSERT_NE(0u, mProgram);
548 
549     // The extension spec is not very clear on what name can be used for the queries for array
550     // variables. We're checking that the queries work in the same way as specified in OpenGL 4.4
551     // page 107.
552     checkOutputIndexQuery("outSrc0[0]", 0);
553     checkOutputIndexQuery("outSrc1[0]", 1);
554     checkOutputIndexQuery("outSrc0", 0);
555     checkOutputIndexQuery("outSrc1", 1);
556 
557     // These queries use an out of range array index so they should return -1.
558     checkOutputIndexQuery("outSrc0[1]", -1);
559     checkOutputIndexQuery("outSrc1[1]", -1);
560 
561     drawTest();
562 }
563 
564 // Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
565 // Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT,
566 // glGetFragDataLocation, glGetFragDataIndexEXT work correctly with
567 // GLSL array output variables. The output variable can be bound by
568 // referring to the variable name with or without the first element array
569 // accessor. The getters can query location of the individual elements in
570 // the array. The test does not actually use the base test drawing,
571 // since the drivers at the time of writing do not support multiple
572 // buffers and dual source blending.
TEST_P(EXTBlendFuncExtendedDrawTestES3,ES3GettersArray)573 TEST_P(EXTBlendFuncExtendedDrawTestES3, ES3GettersArray)
574 {
575     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
576 
577     // TODO(zmo): Figure out why this fails on AMD. crbug.com/585132.
578     // Also fails on the Intel Mesa driver, see
579     // https://bugs.freedesktop.org/show_bug.cgi?id=96765
580     ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD());
581     ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel());
582 
583     const GLint kTestArraySize     = 2;
584     const GLint kFragData0Location = 2;
585     const GLint kFragData1Location = 1;
586     const GLint kUnusedLocation    = 5;
587 
588     // The test binds kTestArraySize -sized array to location 1 for test purposes.
589     // The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an
590     // array will be bound to continuous locations, starting from the first
591     // location.
592     GLint maxDrawBuffers = 0;
593     glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
594     EXPECT_LT(kTestArraySize, maxDrawBuffers);
595 
596     constexpr char kFragColorShader[] = R"(#version 300 es
597 #extension GL_EXT_blend_func_extended : require
598 precision mediump float;
599 uniform vec4 src;
600 uniform vec4 src1;
601 out vec4 FragData[2];
602 void main() {
603     FragData[0] = src;
604     FragData[1] = src1;
605 })";
606 
607     struct testCase
608     {
609         std::string unusedLocationName;
610         std::string fragData0LocationName;
611         std::string fragData1LocationName;
612     };
613 
614     testCase testCases[4]{{"FragData[0]", "FragData", "FragData[1]"},
615                           {"FragData", "FragData[0]", "FragData[1]"},
616                           {"FragData[0]", "FragData", "FragData[1]"},
617                           {"FragData", "FragData[0]", "FragData[1]"}};
618 
619     for (const testCase &test : testCases)
620     {
621         mProgram =
622             CompileProgram(essl3_shaders::vs::Simple(), kFragColorShader, [&](GLuint program) {
623                 glBindFragDataLocationEXT(program, kUnusedLocation,
624                                           test.unusedLocationName.c_str());
625                 glBindFragDataLocationEXT(program, kFragData0Location,
626                                           test.fragData0LocationName.c_str());
627                 glBindFragDataLocationEXT(program, kFragData1Location,
628                                           test.fragData1LocationName.c_str());
629             });
630 
631         EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
632         LinkProgram();
633         EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData"));
634         EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData"));
635         EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData[0]"));
636         EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[0]"));
637         EXPECT_EQ(kFragData1Location, glGetFragDataLocation(mProgram, "FragData[1]"));
638         EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[1]"));
639         // Index bigger than the GLSL variable array length does not find anything.
640         EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[3]"));
641     }
642 }
643 
644 // Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest
TEST_P(EXTBlendFuncExtendedDrawTestES3,ESSL3BindSimpleVarAsArrayNoBind)645 TEST_P(EXTBlendFuncExtendedDrawTestES3, ESSL3BindSimpleVarAsArrayNoBind)
646 {
647     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
648 
649     constexpr char kFragDataShader[] = R"(#version 300 es
650 #extension GL_EXT_blend_func_extended : require
651 precision mediump float;
652 uniform vec4 src;
653 uniform vec4 src1;
654 out vec4 FragData;
655 out vec4 SecondaryFragData;
656 void main() {
657     FragData = src;
658     SecondaryFragData = src1;
659 })";
660 
661     mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFragDataShader, [](GLuint program) {
662         glBindFragDataLocationEXT(program, 0, "FragData[0]");
663         glBindFragDataLocationIndexedEXT(program, 0, 1, "SecondaryFragData[0]");
664     });
665 
666     LinkProgram();
667 
668     EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[0]"));
669     EXPECT_EQ(0, glGetFragDataLocation(mProgram, "FragData"));
670     EXPECT_EQ(1, glGetFragDataLocation(mProgram, "SecondaryFragData"));
671     // Did not bind index.
672     EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "SecondaryFragData"));
673 
674     glBindFragDataLocationEXT(mProgram, 0, "FragData");
675     glBindFragDataLocationIndexedEXT(mProgram, 0, 1, "SecondaryFragData");
676     LinkProgram();
677 }
678 
679 // Test an ESSL 3.00 program with a link-time fragment output location conflict.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationConflict)680 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationConflict)
681 {
682     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
683 
684     constexpr char kFS[] = R"(#version 300 es
685 #extension GL_EXT_blend_func_extended : require
686 precision mediump float;
687 uniform vec4 src0;
688 uniform vec4 src1;
689 out vec4 out0;
690 out vec4 out1;
691 void main() {
692     out0 = src0;
693     out1 = src1;
694 })";
695 
696     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
697     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
698     ASSERT_NE(0u, vs);
699     ASSERT_NE(0u, fs);
700 
701     GLuint program = glCreateProgram();
702     glAttachShader(program, vs);
703     glDeleteShader(vs);
704     glAttachShader(program, fs);
705     glDeleteShader(fs);
706 
707     glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");
708     glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");
709 
710     // The program should fail to link.
711     glLinkProgram(program);
712     GLint linkStatus;
713     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
714     EXPECT_EQ(0, linkStatus);
715 
716     glDeleteProgram(program);
717 }
718 
719 // Test an ESSL 3.00 program with some bindings set for nonexistent variables. These should not
720 // create link-time conflicts.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationForNonexistentOutput)721 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationForNonexistentOutput)
722 {
723     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
724 
725     constexpr char kFS[] = R"(#version 300 es
726 #extension GL_EXT_blend_func_extended : require
727 precision mediump float;
728 uniform vec4 src0;
729 out vec4 out0;
730 void main() {
731     out0 = src0;
732 })";
733 
734     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
735     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
736     ASSERT_NE(0u, vs);
737     ASSERT_NE(0u, fs);
738 
739     GLuint program = glCreateProgram();
740     glAttachShader(program, vs);
741     glDeleteShader(vs);
742     glAttachShader(program, fs);
743     glDeleteShader(fs);
744 
745     glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");
746     glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");
747     glBindFragDataLocationIndexedEXT(program, 0, 0, "out2[0]");
748 
749     // The program should link successfully - conflicting location for nonexistent variables out1 or
750     // out2 should not be an issue.
751     glLinkProgram(program);
752     GLint linkStatus;
753     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
754     EXPECT_NE(0, linkStatus);
755 
756     glDeleteProgram(program);
757 }
758 
759 // Test mixing shader-assigned and automatic output locations.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputLocationsPartiallyAutomatic)760 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationsPartiallyAutomatic)
761 {
762     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
763 
764     GLint maxDrawBuffers;
765     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
766     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
767 
768     constexpr char kFS[] = R"(#version 300 es
769 #extension GL_EXT_blend_func_extended : require
770 precision mediump float;
771 uniform vec4 src0;
772 uniform vec4 src1;
773 uniform vec4 src2;
774 uniform vec4 src3;
775 layout(location=0) out vec4 out0;
776 layout(location=3) out vec4 out3;
777 out vec4 out12[2];
778 void main() {
779     out0 = src0;
780     out12[0] = src1;
781     out12[1] = src2;
782     out3 = src3;
783 })";
784 
785     GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFS);
786     ASSERT_NE(0u, program);
787 
788     GLint location = glGetFragDataLocation(program, "out0");
789     EXPECT_EQ(0, location);
790     location = glGetFragDataLocation(program, "out12");
791     EXPECT_EQ(1, location);
792     location = glGetFragDataLocation(program, "out3");
793     EXPECT_EQ(3, location);
794 
795     glDeleteProgram(program);
796 }
797 
798 // Test a fragment output array that doesn't fit because contiguous locations are not available.
TEST_P(EXTBlendFuncExtendedTestES3,FragmentOutputArrayDoesntFit)799 TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputArrayDoesntFit)
800 {
801     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
802 
803     GLint maxDrawBuffers;
804     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
805     ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);
806 
807     std::stringstream fragShader;
808     fragShader << R"(#version 300 es
809 #extension GL_EXT_blend_func_extended : require
810 precision mediump float;
811 layout(location=2) out vec4 out0;
812 out vec4 outArray[)"
813                << (maxDrawBuffers - 1) << R"(];
814 void main() {
815     out0 = vec4(1.0);
816     outArray[0] = vec4(1.0);
817 })";
818 
819     GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
820     GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragShader.str().c_str());
821     ASSERT_NE(0u, vs);
822     ASSERT_NE(0u, fs);
823 
824     GLuint program = glCreateProgram();
825     glAttachShader(program, vs);
826     glDeleteShader(vs);
827     glAttachShader(program, fs);
828     glDeleteShader(fs);
829 
830     // The program should not link - there's no way to fit "outArray" into available output
831     // locations.
832     glLinkProgram(program);
833     GLint linkStatus;
834     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
835     EXPECT_EQ(0, linkStatus);
836 
837     glDeleteProgram(program);
838 }
839 
840 // Use a program pipeline with EXT_blend_func_extended
TEST_P(EXTBlendFuncExtendedDrawTestES31,UseProgramPipeline)841 TEST_P(EXTBlendFuncExtendedDrawTestES31, UseProgramPipeline)
842 {
843     // Only the Vulkan backend supports PPO
844     ANGLE_SKIP_TEST_IF(!IsVulkan());
845 
846     // Create two separable program objects from a
847     // single source string respectively (vertSrc and fragSrc)
848     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
849 
850     const char *kFragColorShader = R"(#version 300 es
851 #extension GL_EXT_blend_func_extended : require
852 precision mediump float;
853 uniform vec4 src0;
854 uniform vec4 src1;
855 layout(location = 0, index = 1) out vec4 outSrc1;
856 layout(location = 0, index = 0) out vec4 outSrc0;
857 void main() {
858     outSrc0 = src0;
859     outSrc1 = src1;
860 })";
861 
862     setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShader);
863 
864     checkOutputIndexQuery("outSrc0", 0);
865     checkOutputIndexQuery("outSrc1", 1);
866 
867     ASSERT_EQ(mProgram, 0u);
868     drawTest();
869 
870     ASSERT_GL_NO_ERROR();
871 }
872 
873 // Use program pipeline where the fragment program is changed
TEST_P(EXTBlendFuncExtendedDrawTestES31,UseTwoProgramStages)874 TEST_P(EXTBlendFuncExtendedDrawTestES31, UseTwoProgramStages)
875 {
876     // Only the Vulkan backend supports PPO
877     ANGLE_SKIP_TEST_IF(!IsVulkan());
878 
879     // Create two separable program objects from a
880     // single source string respectively (vertSrc and fragSrc)
881     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));
882 
883     const char *kFragColorShaderFlipped = R"(#version 300 es
884 #extension GL_EXT_blend_func_extended : require
885 precision mediump float;
886 uniform vec4 src0;
887 uniform vec4 src1;
888 layout(location = 0, index = 0) out vec4 outSrc1;
889 layout(location = 0, index = 1) out vec4 outSrc0;
890 void main() {
891     outSrc0 = src0;
892     outSrc1 = src1;
893 })";
894 
895     const char *kFragColorShader = R"(#version 300 es
896 #extension GL_EXT_blend_func_extended : require
897 precision mediump float;
898 uniform vec4 src0;
899 uniform vec4 src1;
900 layout(location = 0, index = 1) out vec4 outSrc1;
901 layout(location = 0, index = 0) out vec4 outSrc0;
902 void main() {
903     outSrc0 = src0;
904     outSrc1 = src1;
905 })";
906 
907     setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShaderFlipped);
908 
909     // Check index values frag shader with the "flipped" index values
910     checkOutputIndexQuery("outSrc0", 1);
911     checkOutputIndexQuery("outSrc1", 0);
912 
913     GLuint previousProgram = mFragProgram;
914     mFragProgram           = createShaderProgram(GL_FRAGMENT_SHADER, kFragColorShader);
915     ASSERT_NE(mFragProgram, 0u);
916 
917     // Change the Fragment program of the pipeline
918     glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);
919     EXPECT_GL_NO_ERROR();
920 
921     checkOutputIndexQuery("outSrc0", 0);
922     checkOutputIndexQuery("outSrc1", 1);
923 
924     ASSERT_EQ(mProgram, 0u);
925     drawTest();
926 
927     if (previousProgram)
928     {
929         glDeleteProgram(previousProgram);
930     }
931     ASSERT_GL_NO_ERROR();
932 }
933 
934 ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedTest);
935 
936 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedTestES3);
937 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedTestES3);
938 
939 ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedDrawTest);
940 
941 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedDrawTestES3);
942 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedDrawTestES3);
943 
944 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedDrawTestES31);
945 ANGLE_INSTANTIATE_TEST_ES31(EXTBlendFuncExtendedDrawTestES31);
946