1 //
2 // Copyright 2024 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
7 #include "test_utils/ANGLETest.h"
8 #include "test_utils/gl_raii.h"
9
10 using namespace angle;
11
12 constexpr int kPixelColorThreshhold = 8;
13
14 class AdvancedBlendTest : public ANGLETest<>
15 {
16 protected:
AdvancedBlendTest()17 AdvancedBlendTest()
18 {
19 setWindowWidth(128);
20 setWindowHeight(128);
21 setConfigRedBits(8);
22 setConfigGreenBits(8);
23 setConfigBlueBits(8);
24 setConfigAlphaBits(8);
25 }
26
27 void callBlendBarrier(APIExtensionVersion usedExtension);
28 void testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion usedExtension);
29 void testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion usedExtension);
30 void testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion usedExtension);
31 };
32
33 class AdvancedBlendTestES32 : public AdvancedBlendTest
34 {};
35
callBlendBarrier(APIExtensionVersion usedExtension)36 void AdvancedBlendTest::callBlendBarrier(APIExtensionVersion usedExtension)
37 {
38 ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);
39 if (usedExtension == APIExtensionVersion::KHR)
40 {
41 glBlendBarrierKHR();
42 }
43 else
44 {
45 glBlendBarrier();
46 }
47 }
48
testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion usedExtension)49 void AdvancedBlendTest::testAdvancedBlendNotAppliedWhenBlendIsDisabled(
50 APIExtensionVersion usedExtension)
51 {
52 ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);
53
54 constexpr char kGLSLVersion31[] = R"(#version 310 es
55 )";
56 constexpr char kGLSLVersion32[] = R"(#version 320 es
57 )";
58 constexpr char kBlendKHR[] = R"(#extension GL_KHR_blend_equation_advanced : require
59 )";
60
61 std::string vertSrc;
62 std::string fragSrc;
63
64 if (usedExtension == APIExtensionVersion::KHR)
65 {
66 vertSrc.append(kGLSLVersion31);
67 fragSrc.append(kGLSLVersion31);
68 fragSrc.append(kBlendKHR);
69 }
70 else
71 {
72 vertSrc.append(kGLSLVersion32);
73 fragSrc.append(kGLSLVersion32);
74 }
75
76 constexpr char kVertSrcBody[] = R"(
77 in highp vec4 a_position;
78 in mediump vec4 a_color;
79 out mediump vec4 v_color;
80 void main()
81 {
82 gl_Position = a_position;
83 v_color = a_color;
84 }
85 )";
86 vertSrc.append(kVertSrcBody);
87
88 constexpr char kFragSrcBody[] = R"(
89 in mediump vec4 v_color;
90 layout(blend_support_colorburn) out;
91 layout(location = 0) out mediump vec4 o_color;
92 void main()
93 {
94 o_color = v_color;
95 }
96 )";
97 fragSrc.append(kFragSrcBody);
98
99 ANGLE_GL_PROGRAM(program, vertSrc.c_str(), fragSrc.c_str());
100 glUseProgram(program);
101
102 std::array<GLfloat, 16> attribPosData = {1, 1, 0.5, 1, -1, 1, 0.5, 1,
103 1, -1, 0.5, 1, -1, -1, 0.5, 1};
104
105 GLint attribPosLoc = glGetAttribLocation(1, "a_position");
106 ASSERT(attribPosLoc >= 0);
107 glEnableVertexAttribArray(attribPosLoc);
108 glVertexAttribPointer(attribPosLoc, 4, GL_FLOAT, GL_FALSE, 0, attribPosData.data());
109
110 std::array<GLfloat, 16> attribColorData1 = {1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1,
111 1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1};
112 GLint attribColorLoc = glGetAttribLocation(1, "a_color");
113 ASSERT(attribColorLoc >= 0);
114 glEnableVertexAttribArray(attribColorLoc);
115 glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData1.data());
116
117 glBlendEquation(GL_COLORBURN);
118
119 const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
120 glClearColor(0.5, 0.5, 0.5, 1.0);
121 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
122
123 // Disable the blend. The next glDrawElements() should not blend the a_color with clear color
124 glDisable(GL_BLEND);
125 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);
126 EXPECT_PIXEL_COLOR_NEAR(64, 64, GLColor(255, 51, 128, 255), kPixelColorThreshhold);
127 }
128
129 // Test that when blending is disabled, advanced blend is not applied.
130 // Regression test for a bug in the emulation path in the Vulkan backend.
TEST_P(AdvancedBlendTest,AdvancedBlendNotAppliedWhenBlendIsDisabledKHR)131 TEST_P(AdvancedBlendTest, AdvancedBlendNotAppliedWhenBlendIsDisabledKHR)
132 {
133 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
134 testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion::KHR);
135 }
136
137 // Test that when blending is disabled, advanced blend is not applied (using ES 3.2).
TEST_P(AdvancedBlendTestES32,AdvancedBlendNotAppliedWhenBlendIsDisabled)138 TEST_P(AdvancedBlendTestES32, AdvancedBlendNotAppliedWhenBlendIsDisabled)
139 {
140 testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion::Core);
141 }
142
testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion usedExtension)143 void AdvancedBlendTest::testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion usedExtension)
144 {
145 ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);
146
147 constexpr char kGLSLVersion31[] = R"(#version 310 es
148 )";
149 constexpr char kGLSLVersion32[] = R"(#version 320 es
150 )";
151 constexpr char kBlendKHR[] = R"(#extension GL_KHR_blend_equation_advanced : require
152 )";
153
154 std::string vertSrc;
155 std::string fragSrc;
156
157 if (usedExtension == APIExtensionVersion::KHR)
158 {
159 vertSrc.append(kGLSLVersion31);
160 fragSrc.append(kGLSLVersion31);
161 fragSrc.append(kBlendKHR);
162 }
163 else
164 {
165 vertSrc.append(kGLSLVersion32);
166 fragSrc.append(kGLSLVersion32);
167 }
168
169 constexpr char kVertSrcBody[] = R"(
170 in highp vec4 a_position;
171 in mediump vec4 a_color;
172 out mediump vec4 v_color;
173 void main()
174 {
175 gl_Position = a_position;
176 v_color = a_color;
177 }
178 )";
179 vertSrc.append(kVertSrcBody);
180
181 constexpr char kFragSrcBody[] = R"(
182 in mediump vec4 v_color;
183 layout(blend_support_colorburn) out;
184 layout(location = 0) out mediump vec4 o_color;
185 void main()
186 {
187 o_color = v_color;
188 }
189 )";
190 fragSrc.append(kFragSrcBody);
191
192 ANGLE_GL_PROGRAM(program, vertSrc.c_str(), fragSrc.c_str());
193 glUseProgram(program);
194
195 std::array<GLfloat, 16> attribPosData = {1, 1, 0.5, 1, -1, 1, 0.5, 1,
196 1, -1, 0.5, 1, -1, -1, 0.5, 1};
197
198 GLint attribPosLoc = glGetAttribLocation(1, "a_position");
199 ASSERT(attribPosLoc >= 0);
200 glEnableVertexAttribArray(attribPosLoc);
201 glVertexAttribPointer(attribPosLoc, 4, GL_FLOAT, GL_FALSE, 0, attribPosData.data());
202
203 std::array<GLfloat, 16> attribColorData1 = {1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1,
204 1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1};
205 GLint attribColorLoc = glGetAttribLocation(1, "a_color");
206 ASSERT(attribColorLoc >= 0);
207 glEnableVertexAttribArray(attribColorLoc);
208 glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData1.data());
209
210 glBlendEquation(GL_COLORBURN);
211
212 const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
213 glClearColor(0.5, 0.5, 0.5, 1.0);
214 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
215
216 // Disable the blend. The next glDrawElements() should not blend the a_color with clear color
217 glDisable(GL_BLEND);
218 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);
219
220 // Enable the blend. The next glDrawElements() should blend a_color
221 // with the the existing framebuffer output with GL_COLORBURN blend mode
222 glEnable(GL_BLEND);
223 // Test the blend with coherent blend disabled. This make the test cover both devices that
224 // support / do not support GL_KHR_blend_equation_advanced_coherent
225 if (IsGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"))
226 {
227 glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
228 }
229 callBlendBarrier(usedExtension);
230 std::array<GLfloat, 16> attribColorData2 = {0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1,
231 0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1};
232 glEnableVertexAttribArray(attribColorLoc);
233 glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData2.data());
234 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);
235
236 EXPECT_PIXEL_COLOR_NEAR(64, 64, GLColor(255, 0, 0, 255), kPixelColorThreshhold);
237 }
238
239 // Test that when blending is disabled, advanced blend is not applied, but is applied after
240 // it is enabled.
241 // Regression test for a bug in the emulation path in the Vulkan backend.
TEST_P(AdvancedBlendTest,AdvancedBlendDisabledAndThenEnabledKHR)242 TEST_P(AdvancedBlendTest, AdvancedBlendDisabledAndThenEnabledKHR)
243 {
244 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
245 testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion::KHR);
246 }
247
248 // Test that when blending is disabled, advanced blend is not applied, but is applied after
249 // it is enabled (using ES 3.2).
TEST_P(AdvancedBlendTestES32,AdvancedBlendDisabledAndThenEnabled)250 TEST_P(AdvancedBlendTestES32, AdvancedBlendDisabledAndThenEnabled)
251 {
252 testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion::Core);
253 }
254
testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion usedExtension)255 void AdvancedBlendTest::testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion usedExtension)
256 {
257 ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);
258
259 constexpr char kGLSLVersion31[] = R"(#version 310 es
260 )";
261 constexpr char kGLSLVersion32[] = R"(#version 320 es
262 )";
263 constexpr char kBlendKHR[] = R"(#extension GL_KHR_blend_equation_advanced : require
264 )";
265
266 std::string vertSrc;
267 std::string fragSrc;
268
269 if (usedExtension == APIExtensionVersion::KHR)
270 {
271 vertSrc.append(kGLSLVersion31);
272 fragSrc.append(kGLSLVersion31);
273 fragSrc.append(kBlendKHR);
274 }
275 else
276 {
277 vertSrc.append(kGLSLVersion32);
278 fragSrc.append(kGLSLVersion32);
279 }
280
281 constexpr char kVertSrcBody[] = R"(
282 in highp vec4 a_position;
283 in mediump vec4 a_color;
284 out mediump vec4 v_color;
285 void main()
286 {
287 gl_Position = a_position;
288 v_color = a_color;
289 }
290 )";
291 vertSrc.append(kVertSrcBody);
292
293 constexpr char kFragSrcBody[] = R"(
294 in mediump vec4 v_color;
295 layout(blend_support_colorburn) out;
296 layout(location = 0) out mediump vec4 o_color;
297 void main()
298 {
299 o_color = v_color;
300 }
301 )";
302 fragSrc.append(kFragSrcBody);
303
304 ANGLE_GL_PROGRAM(program, vertSrc.c_str(), fragSrc.c_str());
305 glUseProgram(program);
306
307 std::array<GLfloat, 16> attribPosData = {1, 1, 0.5, 1, -1, 1, 0.5, 1,
308 1, -1, 0.5, 1, -1, -1, 0.5, 1};
309
310 GLint attribPosLoc = glGetAttribLocation(1, "a_position");
311 ASSERT(attribPosLoc >= 0);
312 glEnableVertexAttribArray(attribPosLoc);
313 glVertexAttribPointer(attribPosLoc, 4, GL_FLOAT, GL_FALSE, 0, attribPosData.data());
314
315 std::array<GLfloat, 16> attribColorData1 = {1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1,
316 1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1};
317 GLint attribColorLoc = glGetAttribLocation(1, "a_color");
318 ASSERT(attribColorLoc >= 0);
319 glEnableVertexAttribArray(attribColorLoc);
320 glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData1.data());
321
322 glBlendEquation(GL_COLORBURN);
323
324 const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
325 glClearColor(0.5, 0.5, 0.5, 1.0);
326 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
327
328 // Enable the blend. The next glDrawElements() should blend the a_color with clear color
329 // using the GL_COLORBURN blend mode
330 glEnable(GL_BLEND);
331 // Test the blend with coherent blend disabled. This make the test cover both devices that
332 // support / do not support GL_KHR_blend_equation_advanced_coherent
333 if (IsGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"))
334 {
335 glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
336 }
337 callBlendBarrier(usedExtension);
338 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);
339
340 // Disable the blend. The next glDrawElements() should not blend the a_color with
341 // the existing framebuffer output with GL_COLORBURN blend mode
342 glDisable(GL_BLEND);
343 std::array<GLfloat, 16> attribColorData2 = {0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1,
344 0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1};
345 glEnableVertexAttribArray(attribColorLoc);
346 glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData2.data());
347 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);
348
349 EXPECT_PIXEL_COLOR_NEAR(64, 64, GLColor(128, 128, 0, 255), kPixelColorThreshhold);
350 }
351
352 // Test that when blending is enabled, advanced blend is applied, but is not applied after
353 // it is disabled.
354 // Regression test for a bug in the emulation path in the Vulkan backend.
TEST_P(AdvancedBlendTest,AdvancedBlendEnabledAndThenDisabledKHR)355 TEST_P(AdvancedBlendTest, AdvancedBlendEnabledAndThenDisabledKHR)
356 {
357 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
358 testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion::KHR);
359 }
360
361 // Test that when blending is enabled, advanced blend is applied, but is not applied after
362 // it is disabled (using ES 3.2).
TEST_P(AdvancedBlendTestES32,AdvancedBlendEnabledAndThenDisabled)363 TEST_P(AdvancedBlendTestES32, AdvancedBlendEnabledAndThenDisabled)
364 {
365 testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion::Core);
366 }
367
368 // Test querying advanced blend equation coherent on supported devices (enabled by default).
TEST_P(AdvancedBlendTest,AdvancedBlendCoherentQuery)369 TEST_P(AdvancedBlendTest, AdvancedBlendCoherentQuery)
370 {
371 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"));
372
373 GLint status = -1;
374 glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
375 EXPECT_GL_NO_ERROR();
376 EXPECT_EQ(status, 1);
377
378 glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
379 glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
380 EXPECT_GL_NO_ERROR();
381 EXPECT_EQ(status, 0);
382
383 glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
384 glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
385 EXPECT_GL_NO_ERROR();
386 EXPECT_EQ(status, 1);
387 }
388
389 // Test that querying advanced blend equation coherent results in an error as if this enum does not
390 // exist.
TEST_P(AdvancedBlendTest,AdvancedBlendCoherentQueryFailsIfNotSupported)391 TEST_P(AdvancedBlendTest, AdvancedBlendCoherentQueryFailsIfNotSupported)
392 {
393 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"));
394
395 GLint status = -1;
396 glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
397 EXPECT_GL_ERROR(GL_INVALID_ENUM);
398 }
399
400 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AdvancedBlendTest);
401 ANGLE_INSTANTIATE_TEST_ES31(AdvancedBlendTest);
402
403 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AdvancedBlendTestES32);
404 ANGLE_INSTANTIATE_TEST_ES32(AdvancedBlendTestES32);
405