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