1 //
2 // Copyright 2021 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 // KHR_blend_equation_advanced_test.cpp:
7 // Test for KHR_blend_equation_advanced and KHR_blend_equation_advanced_coherent
8 //
9
10 #include "tests/test_utils/ShaderExtensionTest.h"
11
12 #include "common/PackedEnums.h"
13
14 namespace
15 {
16 const char EXTPragma[] =
17 "#extension GL_KHR_blend_equation_advanced : require\n"
18 "#extension GL_EXT_shader_framebuffer_fetch_non_coherent : require\n";
19
20 // Use the multiply equation for blending
21 const char ESSL310_Simple[] =
22 R"(
23 precision highp float;
24
25 layout (blend_support_multiply) out;
26 layout (location = 0) out vec4 oCol;
27
28 uniform vec4 uSrcCol;
29
30 void main (void)
31 {
32 oCol = uSrcCol;
33 })";
34
35 const char ESSL310_DeclaredMultiplyScreenSeparately[] =
36 R"(
37 precision highp float;
38
39 layout (blend_support_multiply) out;
40 layout (blend_support_screen) out;
41 layout (location = 0) out vec4 oCol;
42
43 uniform vec4 uSrcCol;
44
45 void main (void)
46 {
47 oCol = uSrcCol;
48 })";
49
50 const char ESSL310_DeclaredMultiplyScreenSuccessively[] =
51 R"(
52 precision highp float;
53
54 layout (blend_support_multiply, blend_support_screen) out;
55 layout (location = 0) out vec4 oCol;
56
57 uniform vec4 uSrcCol;
58
59 void main (void)
60 {
61 oCol = uSrcCol;
62 })";
63
64 const char ESSL310_With_FramebufferFetch[] =
65 R"(
66 precision highp float;
67
68 layout (blend_support_multiply) out;
69 layout (location = 0, noncoherent) inout vec4 oCol;
70
71 uniform vec4 uSrcCol;
72
73 void main (void)
74 {
75 oCol = mix(oCol, uSrcCol, 0.5f);
76 })";
77
78 const char ESSL310_With_FramebufferFetchVec3[] =
79 R"(
80 precision highp float;
81
82 layout (blend_support_multiply) out;
83 layout (location = 0, noncoherent) inout vec3 oCol;
84
85 uniform vec3 uSrcCol;
86
87 void main (void)
88 {
89 oCol = mix(oCol, uSrcCol, 0.5f);
90 })";
91
92 class KHRBlendEquationAdvancedTest : public sh::ShaderExtensionTest
93 {
94 public:
SetUp()95 void SetUp() override
96 {
97 std::map<ShShaderOutput, std::string> shaderOutputList = {
98 {SH_GLSL_450_CORE_OUTPUT, "SH_GLSL_450_CORE_OUTPUT"},
99 #if defined(ANGLE_ENABLE_VULKAN)
100 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}
101 #endif
102 };
103
104 Initialize(shaderOutputList);
105 }
106
TearDown()107 void TearDown() override
108 {
109 for (auto shaderOutputType : mShaderOutputList)
110 {
111 DestroyCompiler(shaderOutputType.first);
112 }
113 }
114
Initialize(std::map<ShShaderOutput,std::string> & shaderOutputList)115 void Initialize(std::map<ShShaderOutput, std::string> &shaderOutputList)
116 {
117 mShaderOutputList = std::move(shaderOutputList);
118
119 for (auto shaderOutputType : mShaderOutputList)
120 {
121 sh::InitBuiltInResources(&mResourceList[shaderOutputType.first]);
122 mCompilerList[shaderOutputType.first] = nullptr;
123 }
124 }
125
DestroyCompiler(ShShaderOutput shaderOutputType)126 void DestroyCompiler(ShShaderOutput shaderOutputType)
127 {
128 if (mCompilerList[shaderOutputType])
129 {
130 sh::Destruct(mCompilerList[shaderOutputType]);
131 mCompilerList[shaderOutputType] = nullptr;
132 }
133 }
134
InitializeCompiler()135 void InitializeCompiler()
136 {
137 for (auto shaderOutputType : mShaderOutputList)
138 {
139 InitializeCompiler(shaderOutputType.first);
140 }
141 }
142
InitializeCompiler(ShShaderOutput shaderOutputType)143 void InitializeCompiler(ShShaderOutput shaderOutputType)
144 {
145 DestroyCompiler(shaderOutputType);
146
147 mCompilerList[shaderOutputType] =
148 sh::ConstructCompiler(GL_FRAGMENT_SHADER, testing::get<0>(GetParam()), shaderOutputType,
149 &mResourceList[shaderOutputType]);
150 ASSERT_TRUE(mCompilerList[shaderOutputType] != nullptr)
151 << "Compiler for " << mShaderOutputList[shaderOutputType]
152 << " could not be constructed.";
153 }
154
155 enum class Emulation
156 {
157 Disabled,
158 Enabled
159 };
160
TestShaderCompile(ShShaderOutput shaderOutputType,const char * pragma,Emulation emulate)161 testing::AssertionResult TestShaderCompile(ShShaderOutput shaderOutputType,
162 const char *pragma,
163 Emulation emulate)
164 {
165 const char *shaderStrings[] = {testing::get<1>(GetParam()), pragma,
166 testing::get<2>(GetParam())};
167
168 ShCompileOptions compileFlags = {};
169 compileFlags.objectCode = true;
170 if (emulate == Emulation::Enabled)
171 {
172 compileFlags.addAdvancedBlendEquationsEmulation = true;
173 }
174
175 bool success = sh::Compile(mCompilerList[shaderOutputType], shaderStrings, 3, compileFlags);
176 if (success)
177 {
178 return ::testing::AssertionSuccess()
179 << "Compilation success(" << mShaderOutputList[shaderOutputType] << ")";
180 }
181 return ::testing::AssertionFailure() << sh::GetInfoLog(mCompilerList[shaderOutputType]);
182 }
183
TestShaderCompile(bool expectation,const char * pragma,Emulation emulate)184 void TestShaderCompile(bool expectation, const char *pragma, Emulation emulate)
185 {
186 for (auto shaderOutputType : mShaderOutputList)
187 {
188 if (expectation)
189 {
190 EXPECT_TRUE(TestShaderCompile(shaderOutputType.first, pragma, emulate));
191 }
192 else
193 {
194 EXPECT_FALSE(TestShaderCompile(shaderOutputType.first, pragma, emulate));
195 }
196 }
197 }
198
SetExtensionEnable(bool enable)199 void SetExtensionEnable(bool enable)
200 {
201 for (auto shaderOutputType : mShaderOutputList)
202 {
203 mResourceList[shaderOutputType.first].KHR_blend_equation_advanced = enable;
204 mResourceList[shaderOutputType.first].EXT_shader_framebuffer_fetch_non_coherent =
205 enable;
206 }
207 }
208
209 protected:
210 std::map<ShShaderOutput, std::string> mShaderOutputList;
211 std::map<ShShaderOutput, ShHandle> mCompilerList;
212 std::map<ShShaderOutput, ShBuiltInResources> mResourceList;
213 };
214
215 class KHRBlendEquationAdvancedES310Test : public KHRBlendEquationAdvancedTest
216 {};
217
218 // Extension flag is required to compile properly. Expect failure when it is not present.
TEST_P(KHRBlendEquationAdvancedES310Test,CompileFailsWithoutExtension)219 TEST_P(KHRBlendEquationAdvancedES310Test, CompileFailsWithoutExtension)
220 {
221 SetExtensionEnable(false);
222 InitializeCompiler();
223 TestShaderCompile(false, EXTPragma, Emulation::Disabled);
224 }
225
226 // Extension directive is required to compile properly. Expect failure when it is not present.
TEST_P(KHRBlendEquationAdvancedES310Test,CompileFailsWithExtensionWithoutPragma)227 TEST_P(KHRBlendEquationAdvancedES310Test, CompileFailsWithExtensionWithoutPragma)
228 {
229 SetExtensionEnable(true);
230 InitializeCompiler();
231 TestShaderCompile(false, "", Emulation::Disabled);
232 }
233
234 INSTANTIATE_TEST_SUITE_P(CorrectESSL310Shaders,
235 KHRBlendEquationAdvancedES310Test,
236 Combine(Values(SH_GLES3_1_SPEC),
237 Values(sh::ESSLVersion310),
238 Values(ESSL310_Simple,
239 ESSL310_With_FramebufferFetch,
240 ESSL310_With_FramebufferFetchVec3,
241 ESSL310_DeclaredMultiplyScreenSeparately,
242 ESSL310_DeclaredMultiplyScreenSuccessively)));
243
244 #if defined(ANGLE_ENABLE_VULKAN)
245
246 class KHRBlendEquationAdvancedSuccessTest : public KHRBlendEquationAdvancedTest
247 {
248 public:
SetUp()249 void SetUp() override
250 {
251 std::map<ShShaderOutput, std::string> shaderOutputList = {
252 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}};
253
254 Initialize(shaderOutputList);
255 }
256 };
257
258 class KHRBlendEquationAdvancedES310SuccessTest : public KHRBlendEquationAdvancedSuccessTest
259 {};
260
261 // With extension flag and extension directive, compiling succeeds. Also test that the extension
262 // directive state is reset correctly.
TEST_P(KHRBlendEquationAdvancedES310SuccessTest,CompileSucceedsWithExtensionAndPragma)263 TEST_P(KHRBlendEquationAdvancedES310SuccessTest, CompileSucceedsWithExtensionAndPragma)
264 {
265 SetExtensionEnable(true);
266 InitializeCompiler();
267 TestShaderCompile(true, EXTPragma, Emulation::Disabled);
268 // Test reset functionality.
269 TestShaderCompile(false, "", Emulation::Disabled);
270 TestShaderCompile(true, EXTPragma, Emulation::Disabled);
271 }
272
273 // Same as CompileSucceedsWithExtensionAndPragma but with emulation.
TEST_P(KHRBlendEquationAdvancedES310SuccessTest,CompileSucceedsWithExtensionAndPragmaWithEmulation)274 TEST_P(KHRBlendEquationAdvancedES310SuccessTest, CompileSucceedsWithExtensionAndPragmaWithEmulation)
275 {
276 SetExtensionEnable(true);
277 InitializeCompiler();
278 TestShaderCompile(true, EXTPragma, Emulation::Enabled);
279 }
280
281 // The SL #version 100 shaders that are correct work similarly
282 // in both GL2 and GL3, with and without the version string.
283 INSTANTIATE_TEST_SUITE_P(CorrectESSL310Shaders,
284 KHRBlendEquationAdvancedES310SuccessTest,
285 Combine(Values(SH_GLES3_1_SPEC),
286 Values(sh::ESSLVersion310),
287 Values(ESSL310_Simple,
288 ESSL310_With_FramebufferFetch,
289 ESSL310_With_FramebufferFetchVec3,
290 ESSL310_DeclaredMultiplyScreenSeparately,
291 ESSL310_DeclaredMultiplyScreenSuccessively)));
292
293 class KHRBlendEquationAdvancedEnabledListCheckTest : public KHRBlendEquationAdvancedTest
294 {
295 public:
SetUp()296 void SetUp() override
297 {
298 std::map<ShShaderOutput, std::string> shaderOutputList = {
299 {SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}};
300
301 Initialize(shaderOutputList);
302 }
303
GetCompilerHandle(const ShShaderOutput outputType) const304 const ShHandle &GetCompilerHandle(const ShShaderOutput outputType) const
305 {
306 return mCompilerList.at(outputType);
307 }
308 };
309
310 class KHRBlendEquationAdvancedEnabledSeparatelyTest
311 : public KHRBlendEquationAdvancedEnabledListCheckTest
312 {};
313
314 // Test for declaring different blend equations in separate layout declarations
TEST_P(KHRBlendEquationAdvancedEnabledSeparatelyTest,DeclaredEquationSeparately)315 TEST_P(KHRBlendEquationAdvancedEnabledSeparatelyTest, DeclaredEquationSeparately)
316 {
317 SetExtensionEnable(true);
318 InitializeCompiler();
319 TestShaderCompile(true, EXTPragma, Emulation::Disabled);
320
321 const ShHandle compilerHandle = GetCompilerHandle(SH_SPIRV_VULKAN_OUTPUT);
322 gl::BlendEquationBitSet enabledBlendEquation(sh::GetAdvancedBlendEquations(compilerHandle));
323 EXPECT_TRUE(enabledBlendEquation.test(gl::BlendEquationType::Multiply));
324 EXPECT_TRUE(enabledBlendEquation.test(gl::BlendEquationType::Screen));
325 }
326
327 // Same as DeclaredEquationSeparately but with emulation.
TEST_P(KHRBlendEquationAdvancedEnabledSeparatelyTest,DeclaredEquationSeparatelyWithEmulation)328 TEST_P(KHRBlendEquationAdvancedEnabledSeparatelyTest, DeclaredEquationSeparatelyWithEmulation)
329 {
330 SetExtensionEnable(true);
331 InitializeCompiler();
332 TestShaderCompile(true, EXTPragma, Emulation::Enabled);
333 }
334
335 INSTANTIATE_TEST_SUITE_P(CorrectESSL310Shaders,
336 KHRBlendEquationAdvancedEnabledSeparatelyTest,
337 Combine(Values(SH_GLES3_1_SPEC),
338 Values(sh::ESSLVersion310),
339 Values(ESSL310_DeclaredMultiplyScreenSeparately)));
340
341 class KHRBlendEquationAdvancedEnabledSuccessivelyTest
342 : public KHRBlendEquationAdvancedEnabledListCheckTest
343 {};
344
345 // Test for declaring different blend equations in the same layout declaration
TEST_P(KHRBlendEquationAdvancedEnabledSuccessivelyTest,DeclaredEquationSuccessively)346 TEST_P(KHRBlendEquationAdvancedEnabledSuccessivelyTest, DeclaredEquationSuccessively)
347 {
348 SetExtensionEnable(true);
349 InitializeCompiler();
350 TestShaderCompile(true, EXTPragma, Emulation::Disabled);
351
352 const ShHandle compilerHandle = GetCompilerHandle(SH_SPIRV_VULKAN_OUTPUT);
353 gl::BlendEquationBitSet enabledBlendEquation(sh::GetAdvancedBlendEquations(compilerHandle));
354 EXPECT_TRUE(enabledBlendEquation.test(gl::BlendEquationType::Multiply));
355 EXPECT_TRUE(enabledBlendEquation.test(gl::BlendEquationType::Screen));
356 }
357
358 INSTANTIATE_TEST_SUITE_P(CorrectESSL310Shaders,
359 KHRBlendEquationAdvancedEnabledSuccessivelyTest,
360 Combine(Values(SH_GLES3_1_SPEC),
361 Values(sh::ESSLVersion310),
362 Values(ESSL310_DeclaredMultiplyScreenSuccessively)));
363
364 #endif
365
366 } // anonymous namespace
367