1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 Valve Corporation.
6  * Copyright (c) 2019 The Khronos Group Inc.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief VK_EXT_blend_operation_advanced tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineBlendOperationAdvancedTests.hpp"
28 #include "vktPipelineImageUtil.hpp"
29 #include "vktPipelineReferenceRenderer.hpp"
30 #include "vktTestCaseUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkObjUtil.hpp"
38 
39 #include "tcuTestLog.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuCommandLine.hpp"
42 
43 #include <cmath>
44 
45 namespace vkt
46 {
47 namespace pipeline
48 {
49 
50 using namespace vk;
51 
52 namespace
53 {
54 using tcu::Vec3;
55 using tcu::Vec4;
56 
57 const uint32_t widthArea  = 32u;
58 const uint32_t heightArea = 32u;
59 
60 static const float A1 = 0.750f; // Between 1    and 0.5
61 static const float A2 = 0.375f; // Between 0.5  and 0.25
62 static const float A3 = 0.125f; // Between 0.25 and 0.0
63 
64 const Vec4 srcColors[] = {
65     // Test that pre-multiplied is converted correctly.
66     // Should not test invalid premultiplied colours (1, 1, 1, 0).
67     {1.000f, 0.750f, 0.500f, 1.00f},
68     {0.250f, 0.125f, 0.000f, 1.00f},
69 
70     // Test clamping.
71     {1.000f, 0.750f, 0.500f, 1.00f},
72     {0.250f, 0.125f, 0.000f, 1.00f},
73     {1.000f, 0.750f, 0.500f, 1.00f},
74     {0.250f, 0.125f, 0.000f, 1.00f},
75 
76     // Combinations that test other branches of blend equations.
77     {1.000f, 0.750f, 0.500f, 1.00f},
78     {0.250f, 0.125f, 0.000f, 1.00f},
79     {1.000f, 0.750f, 0.500f, 1.00f},
80     {0.250f, 0.125f, 0.000f, 1.00f},
81     {1.000f, 0.750f, 0.500f, 1.00f},
82     {0.250f, 0.125f, 0.000f, 1.00f},
83     {1.000f, 0.750f, 0.500f, 1.00f},
84     {0.250f, 0.125f, 0.000f, 1.00f},
85     {1.000f, 0.750f, 0.500f, 1.00f},
86     {0.250f, 0.125f, 0.000f, 1.00f},
87 
88     // Above block with few different pre-multiplied alpha values.
89     {1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1},
90     {0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1},
91     {1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1},
92     {0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1},
93     {1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1},
94     {0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1},
95     {1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1},
96     {0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1},
97     {1.000f * A1, 0.750f * A1, 0.500f * A1, 1.00f * A1},
98     {0.250f * A1, 0.125f * A1, 0.000f * A1, 1.00f * A1},
99 
100     {1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2},
101     {0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2},
102     {1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2},
103     {0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2},
104     {1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2},
105     {0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2},
106     {1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2},
107     {0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2},
108     {1.000f * A2, 0.750f * A2, 0.500f * A2, 1.00f * A2},
109     {0.250f * A2, 0.125f * A2, 0.000f * A2, 1.00f * A2},
110 
111     {1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3},
112     {0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3},
113     {1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3},
114     {0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3},
115     {1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3},
116     {0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3},
117     {1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3},
118     {0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3},
119     {1.000f * A3, 0.750f * A3, 0.500f * A3, 1.00f * A3},
120     {0.250f * A3, 0.125f * A3, 0.000f * A3, 1.00f * A3},
121 
122     // Add some source colors with alpha component that is different than the respective destination color
123     {0.750f, 0.750f, 0.500f, 0.750f},
124     {0.250f, 0.500f, 0.500f, 0.750f},
125     {0.250f, 0.125f, 0.000f, 0.500f},
126     {0.250f, 0.250f, 0.500f, 0.500f},
127     {0.250f, 0.125f, 0.000f, 0.250f},
128     {0.125f, 0.125f, 0.125f, 0.250f}};
129 
130 const Vec4 dstColors[] = {
131     // Test that pre-multiplied is converted correctly.
132     // Should not test invalid premultiplied colours (1, 1, 1, 0).
133     {0.000f, 0.000f, 0.000f, 0.00f},
134     {0.000f, 0.000f, 0.000f, 0.00f},
135 
136     // Test clamping.
137     {-0.125f, -0.125f, -0.125f, 1.00f},
138     {-0.125f, -0.125f, -0.125f, 1.00f},
139     {1.125f, 1.125f, 1.125f, 1.00f},
140     {1.125f, 1.125f, 1.125f, 1.00f},
141 
142     // Combinations that test other branches of blend equations.
143     {1.000f, 1.000f, 1.000f, 1.00f},
144     {1.000f, 1.000f, 1.000f, 1.00f},
145     {0.500f, 0.500f, 0.500f, 1.00f},
146     {0.500f, 0.500f, 0.500f, 1.00f},
147     {0.250f, 0.250f, 0.250f, 1.00f},
148     {0.250f, 0.250f, 0.250f, 1.00f},
149     {0.125f, 0.125f, 0.125f, 1.00f},
150     {0.125f, 0.125f, 0.125f, 1.00f},
151     {0.000f, 0.000f, 0.000f, 1.00f},
152     {0.000f, 0.000f, 0.000f, 1.00f},
153 
154     // Above block with few different pre-multiplied alpha values.
155     {1.000f * A1, 1.000f * A1, 1.000f * A1, 1.00f * A1},
156     {1.000f * A1, 1.000f * A1, 1.000f * A1, 1.00f * A1},
157     {0.500f * A1, 0.500f * A1, 0.500f * A1, 1.00f * A1},
158     {0.500f * A1, 0.500f * A1, 0.500f * A1, 1.00f * A1},
159     {0.250f * A1, 0.250f * A1, 0.250f * A1, 1.00f * A1},
160     {0.250f * A1, 0.250f * A1, 0.250f * A1, 1.00f * A1},
161     {0.125f * A1, 0.125f * A1, 0.125f * A1, 1.00f * A1},
162     {0.125f * A1, 0.125f * A1, 0.125f * A1, 1.00f * A1},
163     {0.000f * A1, 0.000f * A1, 0.000f * A1, 1.00f * A1},
164     {0.000f * A1, 0.000f * A1, 0.000f * A1, 1.00f * A1},
165 
166     {1.000f * A2, 1.000f * A2, 1.000f * A2, 1.00f * A2},
167     {1.000f * A2, 1.000f * A2, 1.000f * A2, 1.00f * A2},
168     {0.500f * A2, 0.500f * A2, 0.500f * A2, 1.00f * A2},
169     {0.500f * A2, 0.500f * A2, 0.500f * A2, 1.00f * A2},
170     {0.250f * A2, 0.250f * A2, 0.250f * A2, 1.00f * A2},
171     {0.250f * A2, 0.250f * A2, 0.250f * A2, 1.00f * A2},
172     {0.125f * A2, 0.125f * A2, 0.125f * A2, 1.00f * A2},
173     {0.125f * A2, 0.125f * A2, 0.125f * A2, 1.00f * A2},
174     {0.000f * A2, 0.000f * A2, 0.000f * A2, 1.00f * A2},
175     {0.000f * A2, 0.000f * A2, 0.000f * A2, 1.00f * A2},
176 
177     {1.000f * A3, 1.000f * A3, 1.000f * A3, 1.00f * A3},
178     {1.000f * A3, 1.000f * A3, 1.000f * A3, 1.00f * A3},
179     {0.500f * A3, 0.500f * A3, 0.500f * A3, 1.00f * A3},
180     {0.500f * A3, 0.500f * A3, 0.500f * A3, 1.00f * A3},
181     {0.250f * A3, 0.250f * A3, 0.250f * A3, 1.00f * A3},
182     {0.250f * A3, 0.250f * A3, 0.250f * A3, 1.00f * A3},
183     {0.125f * A3, 0.125f * A3, 0.125f * A3, 1.00f * A3},
184     {0.125f * A3, 0.125f * A3, 0.125f * A3, 1.00f * A3},
185     {0.000f * A3, 0.000f * A3, 0.000f * A3, 1.00f * A3},
186     {0.000f * A3, 0.000f * A3, 0.000f * A3, 1.00f * A3},
187 
188     // Add some source colors with alpha component that is different than the respective source color
189     {1.000f, 1.000f, 1.000f, 1.000f},
190     {0.250f, 0.250f, 0.250f, 0.500f},
191     {0.500f, 0.500f, 0.500f, 0.750f},
192     {0.250f, 0.250f, 0.250f, 0.250f},
193     {0.250f, 0.250f, 0.250f, 0.500f},
194     {0.125f, 0.125f, 0.125f, 0.125f}};
195 
196 const Vec4 clearColorVec4(1.0f, 1.0f, 1.0f, 1.0f);
197 
198 enum TestMode
199 {
200     TEST_MODE_GENERIC  = 0,
201     TEST_MODE_COHERENT = 1,
202 };
203 
204 struct BlendOperationAdvancedParam
205 {
206     PipelineConstructionType pipelineConstructionType;
207     TestMode testMode;
208     uint32_t testNumber;
209     std::vector<VkBlendOp> blendOps;
210     bool coherentOperations;
211     bool independentBlend;
212     uint32_t colorAttachmentsCount;
213     VkBool32 premultipliedSrcColor;
214     VkBool32 premultipliedDstColor;
215     VkBlendOverlapEXT overlap;
216     VkFormat format;
217 };
218 
219 // helper functions
generateTestName(struct BlendOperationAdvancedParam param)220 const std::string generateTestName(struct BlendOperationAdvancedParam param)
221 {
222     std::ostringstream result;
223 
224     result << ((param.testMode == TEST_MODE_COHERENT && !param.coherentOperations) ? "barrier_" : "");
225     result << "color_attachments_" << param.colorAttachmentsCount;
226     result << "_" << de::toLower(getBlendOverlapEXTStr(param.overlap).toString().substr(3));
227     result << (!param.premultipliedSrcColor ? "_nonpremultipliedsrc" : "");
228     result << (!param.premultipliedDstColor ? "_nonpremultiplieddst" : "");
229     result << "_" << param.testNumber;
230     if (param.format == VK_FORMAT_R8G8B8A8_UNORM)
231         result << "_r8g8b8a8_unorm";
232     return result.str();
233 }
234 
calculateWeightingFactors(BlendOperationAdvancedParam param,float alphaSrc,float alphaDst)235 Vec3 calculateWeightingFactors(BlendOperationAdvancedParam param, float alphaSrc, float alphaDst)
236 {
237     Vec3 p = Vec3(0.0f, 0.0f, 0.0f);
238     switch (param.overlap)
239     {
240     case VK_BLEND_OVERLAP_UNCORRELATED_EXT:
241         p.x() = alphaSrc * alphaDst;
242         p.y() = alphaSrc * (1.0f - alphaDst);
243         p.z() = alphaDst * (1.0f - alphaSrc);
244         break;
245     case VK_BLEND_OVERLAP_CONJOINT_EXT:
246         p.x() = deFloatMin(alphaSrc, alphaDst);
247         p.y() = deFloatMax(alphaSrc - alphaDst, 0.0f);
248         p.z() = deFloatMax(alphaDst - alphaSrc, 0.0f);
249         break;
250     case VK_BLEND_OVERLAP_DISJOINT_EXT:
251         p.x() = deFloatMax(alphaSrc + alphaDst - 1.0f, 0.0f);
252         p.y() = deFloatMin(alphaSrc, 1.0f - alphaDst);
253         p.z() = deFloatMin(alphaDst, 1.0f - alphaSrc);
254         break;
255     default:
256         DE_FATAL("Unsupported Advanced Blend Overlap Mode");
257     }
258     return p;
259 }
260 
calculateXYZFactors(VkBlendOp op)261 Vec3 calculateXYZFactors(VkBlendOp op)
262 {
263     Vec3 xyz = Vec3(0.0f, 0.0f, 0.0f);
264     switch (op)
265     {
266     case VK_BLEND_OP_ZERO_EXT:
267         xyz = Vec3(0.0f, 0.0f, 0.0f);
268         break;
269 
270     case VK_BLEND_OP_DST_ATOP_EXT:
271     case VK_BLEND_OP_SRC_EXT:
272         xyz = Vec3(1.0f, 1.0f, 0.0f);
273         break;
274 
275     case VK_BLEND_OP_DST_EXT:
276         xyz = Vec3(1.0f, 0.0f, 1.0f);
277         break;
278 
279     case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
280     case VK_BLEND_OP_HSL_COLOR_EXT:
281     case VK_BLEND_OP_HSL_SATURATION_EXT:
282     case VK_BLEND_OP_HSL_HUE_EXT:
283     case VK_BLEND_OP_HARDMIX_EXT:
284     case VK_BLEND_OP_PINLIGHT_EXT:
285     case VK_BLEND_OP_LINEARLIGHT_EXT:
286     case VK_BLEND_OP_VIVIDLIGHT_EXT:
287     case VK_BLEND_OP_LINEARBURN_EXT:
288     case VK_BLEND_OP_LINEARDODGE_EXT:
289     case VK_BLEND_OP_EXCLUSION_EXT:
290     case VK_BLEND_OP_DIFFERENCE_EXT:
291     case VK_BLEND_OP_SOFTLIGHT_EXT:
292     case VK_BLEND_OP_HARDLIGHT_EXT:
293     case VK_BLEND_OP_COLORBURN_EXT:
294     case VK_BLEND_OP_COLORDODGE_EXT:
295     case VK_BLEND_OP_LIGHTEN_EXT:
296     case VK_BLEND_OP_DARKEN_EXT:
297     case VK_BLEND_OP_OVERLAY_EXT:
298     case VK_BLEND_OP_SCREEN_EXT:
299     case VK_BLEND_OP_MULTIPLY_EXT:
300     case VK_BLEND_OP_SRC_OVER_EXT:
301     case VK_BLEND_OP_DST_OVER_EXT:
302         xyz = Vec3(1.0f, 1.0f, 1.0f);
303         break;
304 
305     case VK_BLEND_OP_SRC_IN_EXT:
306     case VK_BLEND_OP_DST_IN_EXT:
307         xyz = Vec3(1.0f, 0.0f, 0.0f);
308         break;
309 
310     case VK_BLEND_OP_SRC_OUT_EXT:
311         xyz = Vec3(0.0f, 1.0f, 0.0f);
312         break;
313 
314     case VK_BLEND_OP_DST_OUT_EXT:
315         xyz = Vec3(0.0f, 0.0f, 1.0f);
316         break;
317 
318     case VK_BLEND_OP_INVERT_RGB_EXT:
319     case VK_BLEND_OP_INVERT_EXT:
320     case VK_BLEND_OP_SRC_ATOP_EXT:
321         xyz = Vec3(1.0f, 0.0f, 1.0f);
322         break;
323 
324     case VK_BLEND_OP_XOR_EXT:
325         xyz = Vec3(0.0f, 1.0f, 1.0f);
326         break;
327 
328     default:
329         DE_FATAL("Unsupported f/X/Y/Z Advanced Blend Operations Mode");
330     }
331 
332     return xyz;
333 }
334 
blendOpOverlay(float src,float dst)335 float blendOpOverlay(float src, float dst)
336 {
337     if (dst <= 0.5f)
338         return (2.0f * src * dst);
339     else
340         return (1.0f - (2.0f * (1.0f - src) * (1.0f - dst)));
341 }
342 
blendOpColorDodge(float src,float dst)343 float blendOpColorDodge(float src, float dst)
344 {
345     if (dst <= 0.0f)
346         return 0.0f;
347     else if (src < 1.0f)
348         return deFloatMin(1.0f, (dst / (1.0f - src)));
349     else
350         return 1.0f;
351 }
352 
blendOpColorBurn(float src,float dst)353 float blendOpColorBurn(float src, float dst)
354 {
355     if (dst >= 1.0f)
356         return 1.0f;
357     else if (src > 0.0f)
358         return 1.0f - deFloatMin(1.0f, (1.0f - dst) / src);
359     else
360         return 0.0f;
361 }
362 
blendOpHardlight(float src,float dst)363 float blendOpHardlight(float src, float dst)
364 {
365     if (src <= 0.5f)
366         return 2.0f * src * dst;
367     else
368         return 1.0f - (2.0f * (1.0f - src) * (1.0f - dst));
369 }
370 
blendOpSoftlight(float src,float dst)371 float blendOpSoftlight(float src, float dst)
372 {
373     if (src <= 0.5f)
374         return dst - ((1.0f - (2.0f * src)) * dst * (1.0f - dst));
375     else if (dst <= 0.25f)
376         return dst + (((2.0f * src) - 1.0f) * dst * ((((16.0f * dst) - 12.0f) * dst) + 3.0f));
377     else
378         return dst + (((2.0f * src) - 1.0f) * (deFloatSqrt(dst) - dst));
379 }
380 
blendOpLinearDodge(float src,float dst)381 float blendOpLinearDodge(float src, float dst)
382 {
383     if ((src + dst) <= 1.0f)
384         return src + dst;
385     else
386         return 1.0f;
387 }
388 
blendOpLinearBurn(float src,float dst)389 float blendOpLinearBurn(float src, float dst)
390 {
391     if ((src + dst) > 1.0f)
392         return src + dst - 1.0f;
393     else
394         return 0.0f;
395 }
396 
blendOpVividLight(float src,float dst)397 float blendOpVividLight(float src, float dst)
398 {
399     if (src <= 0.0f)
400         return 0.0f;
401     if (src < 0.5f)
402         return 1.0f - (deFloatMin(1.0f, (1.0f - dst) / (2.0f * src)));
403     if (src < 1.0f)
404         return deFloatMin(1.0f, dst / (2.0f * (1.0f - src)));
405     else
406         return 1.0f;
407 }
408 
blendOpLinearLight(float src,float dst)409 float blendOpLinearLight(float src, float dst)
410 {
411     if ((2.0f * src + dst) > 2.0f)
412         return 1.0f;
413     if ((2.0f * src + dst) <= 1.0f)
414         return 0.0f;
415     return (2.0f * src) + dst - 1.0f;
416 }
417 
blendOpPinLight(float src,float dst)418 float blendOpPinLight(float src, float dst)
419 {
420     if (((2.0f * src - 1.0f) > dst) && src < 0.5f)
421         return 0.0f;
422     if (((2.0f * src - 1.0f) > dst) && src >= 0.5f)
423         return 2.0f * src - 1.0f;
424     if (((2.0f * src - 1.0f) <= dst) && src < (0.5f * dst))
425         return 2.0f * src;
426     if (((2.0f * src - 1.0f) <= dst) && src >= (0.5f * dst))
427         return dst;
428     return 0.0f;
429 }
430 
blendOpHardmix(float src,float dst)431 float blendOpHardmix(float src, float dst)
432 {
433     if ((src + dst) < 1.0f)
434         return 0.0f;
435     else
436         return 1.0f;
437 }
438 
minv3(Vec3 c)439 float minv3(Vec3 c)
440 {
441     return deFloatMin(deFloatMin(c.x(), c.y()), c.z());
442 }
443 
maxv3(Vec3 c)444 float maxv3(Vec3 c)
445 {
446     return deFloatMax(deFloatMax(c.x(), c.y()), c.z());
447 }
448 
lumv3(Vec3 c)449 float lumv3(Vec3 c)
450 {
451     return dot(c, Vec3(0.3f, 0.59f, 0.11f));
452 }
453 
satv3(Vec3 c)454 float satv3(Vec3 c)
455 {
456     return maxv3(c) - minv3(c);
457 }
458 
459 // If any color components are outside [0,1], adjust the color to
460 // get the components in range.
clipColor(Vec3 color)461 Vec3 clipColor(Vec3 color)
462 {
463     float lum    = lumv3(color);
464     float mincol = minv3(color);
465     float maxcol = maxv3(color);
466 
467     if (mincol < 0.0)
468     {
469         color = lum + ((color - lum) * lum) / (lum - mincol);
470     }
471     if (maxcol > 1.0)
472     {
473         color = lum + ((color - lum) * (1.0f - lum)) / (maxcol - lum);
474     }
475     return color;
476 }
477 
478 // Take the base RGB color <cbase> and override its luminosity
479 // with that of the RGB color <clum>.
setLum(Vec3 cbase,Vec3 clum)480 Vec3 setLum(Vec3 cbase, Vec3 clum)
481 {
482     float lbase = lumv3(cbase);
483     float llum  = lumv3(clum);
484     float ldiff = llum - lbase;
485 
486     Vec3 color = cbase + Vec3(ldiff);
487     return clipColor(color);
488 }
489 
490 // Take the base RGB color <cbase> and override its saturation with
491 // that of the RGB color <csat>.  The override the luminosity of the
492 // result with that of the RGB color <clum>.
setLumSat(Vec3 cbase,Vec3 csat,Vec3 clum)493 Vec3 setLumSat(Vec3 cbase, Vec3 csat, Vec3 clum)
494 {
495     float minbase = minv3(cbase);
496     float sbase   = satv3(cbase);
497     float ssat    = satv3(csat);
498     Vec3 color;
499 
500     if (sbase > 0)
501     {
502         // Equivalent (modulo rounding errors) to setting the
503         // smallest (R,G,B) component to 0, the largest to <ssat>,
504         // and interpolating the "middle" component based on its
505         // original value relative to the smallest/largest.
506         color = (cbase - minbase) * ssat / sbase;
507     }
508     else
509     {
510         color = Vec3(0.0f);
511     }
512     return setLum(color, clum);
513 }
514 
calculateFFunction(VkBlendOp op,Vec3 src,Vec3 dst)515 Vec3 calculateFFunction(VkBlendOp op, Vec3 src, Vec3 dst)
516 {
517     Vec3 f = Vec3(0.0f, 0.0f, 0.0f);
518 
519     switch (op)
520     {
521     case VK_BLEND_OP_XOR_EXT:
522     case VK_BLEND_OP_SRC_OUT_EXT:
523     case VK_BLEND_OP_DST_OUT_EXT:
524     case VK_BLEND_OP_ZERO_EXT:
525         f = Vec3(0.0f, 0.0f, 0.0f);
526         break;
527 
528     case VK_BLEND_OP_SRC_ATOP_EXT:
529     case VK_BLEND_OP_SRC_IN_EXT:
530     case VK_BLEND_OP_SRC_OVER_EXT:
531     case VK_BLEND_OP_SRC_EXT:
532         f = src;
533         break;
534 
535     case VK_BLEND_OP_DST_ATOP_EXT:
536     case VK_BLEND_OP_DST_IN_EXT:
537     case VK_BLEND_OP_DST_OVER_EXT:
538     case VK_BLEND_OP_DST_EXT:
539         f = dst;
540         break;
541 
542     case VK_BLEND_OP_MULTIPLY_EXT:
543         f = src * dst;
544         break;
545 
546     case VK_BLEND_OP_SCREEN_EXT:
547         f = src + dst - (src * dst);
548         break;
549 
550     case VK_BLEND_OP_OVERLAY_EXT:
551         f.x() = blendOpOverlay(src.x(), dst.x());
552         f.y() = blendOpOverlay(src.y(), dst.y());
553         f.z() = blendOpOverlay(src.z(), dst.z());
554         break;
555 
556     case VK_BLEND_OP_DARKEN_EXT:
557         f.x() = deFloatMin(src.x(), dst.x());
558         f.y() = deFloatMin(src.y(), dst.y());
559         f.z() = deFloatMin(src.z(), dst.z());
560         break;
561 
562     case VK_BLEND_OP_LIGHTEN_EXT:
563         f.x() = deFloatMax(src.x(), dst.x());
564         f.y() = deFloatMax(src.y(), dst.y());
565         f.z() = deFloatMax(src.z(), dst.z());
566         break;
567 
568     case VK_BLEND_OP_COLORDODGE_EXT:
569         f.x() = blendOpColorDodge(src.x(), dst.x());
570         f.y() = blendOpColorDodge(src.y(), dst.y());
571         f.z() = blendOpColorDodge(src.z(), dst.z());
572         break;
573 
574     case VK_BLEND_OP_COLORBURN_EXT:
575         f.x() = blendOpColorBurn(src.x(), dst.x());
576         f.y() = blendOpColorBurn(src.y(), dst.y());
577         f.z() = blendOpColorBurn(src.z(), dst.z());
578         break;
579 
580     case VK_BLEND_OP_HARDLIGHT_EXT:
581         f.x() = blendOpHardlight(src.x(), dst.x());
582         f.y() = blendOpHardlight(src.y(), dst.y());
583         f.z() = blendOpHardlight(src.z(), dst.z());
584         break;
585 
586     case VK_BLEND_OP_SOFTLIGHT_EXT:
587         f.x() = blendOpSoftlight(src.x(), dst.x());
588         f.y() = blendOpSoftlight(src.y(), dst.y());
589         f.z() = blendOpSoftlight(src.z(), dst.z());
590         break;
591 
592     case VK_BLEND_OP_DIFFERENCE_EXT:
593         f.x() = deFloatAbs(dst.x() - src.x());
594         f.y() = deFloatAbs(dst.y() - src.y());
595         f.z() = deFloatAbs(dst.z() - src.z());
596         break;
597 
598     case VK_BLEND_OP_EXCLUSION_EXT:
599         f = src + dst - (2.0f * src * dst);
600         break;
601 
602     case VK_BLEND_OP_INVERT_EXT:
603         f = 1.0f - dst;
604         break;
605 
606     case VK_BLEND_OP_INVERT_RGB_EXT:
607         f = src * (1.0f - dst);
608         break;
609 
610     case VK_BLEND_OP_LINEARDODGE_EXT:
611         f.x() = blendOpLinearDodge(src.x(), dst.x());
612         f.y() = blendOpLinearDodge(src.y(), dst.y());
613         f.z() = blendOpLinearDodge(src.z(), dst.z());
614         break;
615 
616     case VK_BLEND_OP_LINEARBURN_EXT:
617         f.x() = blendOpLinearBurn(src.x(), dst.x());
618         f.y() = blendOpLinearBurn(src.y(), dst.y());
619         f.z() = blendOpLinearBurn(src.z(), dst.z());
620         break;
621 
622     case VK_BLEND_OP_VIVIDLIGHT_EXT:
623         f.x() = blendOpVividLight(src.x(), dst.x());
624         f.y() = blendOpVividLight(src.y(), dst.y());
625         f.z() = blendOpVividLight(src.z(), dst.z());
626         break;
627 
628     case VK_BLEND_OP_LINEARLIGHT_EXT:
629         f.x() = blendOpLinearLight(src.x(), dst.x());
630         f.y() = blendOpLinearLight(src.y(), dst.y());
631         f.z() = blendOpLinearLight(src.z(), dst.z());
632         break;
633 
634     case VK_BLEND_OP_PINLIGHT_EXT:
635         f.x() = blendOpPinLight(src.x(), dst.x());
636         f.y() = blendOpPinLight(src.y(), dst.y());
637         f.z() = blendOpPinLight(src.z(), dst.z());
638         break;
639 
640     case VK_BLEND_OP_HARDMIX_EXT:
641         f.x() = blendOpHardmix(src.x(), dst.x());
642         f.y() = blendOpHardmix(src.y(), dst.y());
643         f.z() = blendOpHardmix(src.z(), dst.z());
644         break;
645 
646     case VK_BLEND_OP_HSL_HUE_EXT:
647         f = setLumSat(src, dst, dst);
648         break;
649 
650     case VK_BLEND_OP_HSL_SATURATION_EXT:
651         f = setLumSat(dst, src, dst);
652         break;
653 
654     case VK_BLEND_OP_HSL_COLOR_EXT:
655         f = setLum(src, dst);
656         break;
657 
658     case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
659         f = setLum(dst, src);
660         break;
661 
662     default:
663         DE_FATAL("Unsupported f/X/Y/Z Advanced Blend Operations Mode");
664     }
665 
666     return f;
667 }
668 
additionalRGBBlendOperations(VkBlendOp op,Vec4 src,Vec4 dst)669 Vec4 additionalRGBBlendOperations(VkBlendOp op, Vec4 src, Vec4 dst)
670 {
671     Vec4 res = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
672 
673     switch (op)
674     {
675     case VK_BLEND_OP_PLUS_EXT:
676         res = src + dst;
677         break;
678 
679     case VK_BLEND_OP_PLUS_CLAMPED_EXT:
680         res.x() = deFloatMin(1.0f, src.x() + dst.x());
681         res.y() = deFloatMin(1.0f, src.y() + dst.y());
682         res.z() = deFloatMin(1.0f, src.z() + dst.z());
683         res.w() = deFloatMin(1.0f, src.w() + dst.w());
684         break;
685 
686     case VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT:
687         res.x() = deFloatMin(deFloatMin(1.0f, src.w() + dst.w()), src.x() + dst.x());
688         res.y() = deFloatMin(deFloatMin(1.0f, src.w() + dst.w()), src.y() + dst.y());
689         res.z() = deFloatMin(deFloatMin(1.0f, src.w() + dst.w()), src.z() + dst.z());
690         res.w() = deFloatMin(1.0f, src.w() + dst.w());
691         break;
692 
693     case VK_BLEND_OP_PLUS_DARKER_EXT:
694         res.x() = deFloatMax(0.0f, deFloatMin(1.0f, src.w() + dst.w()) - ((src.w() - src.x()) + (dst.w() - dst.x())));
695         res.y() = deFloatMax(0.0f, deFloatMin(1.0f, src.w() + dst.w()) - ((src.w() - src.y()) + (dst.w() - dst.y())));
696         res.z() = deFloatMax(0.0f, deFloatMin(1.0f, src.w() + dst.w()) - ((src.w() - src.z()) + (dst.w() - dst.z())));
697         res.w() = deFloatMin(1.0f, src.w() + dst.w());
698         break;
699 
700     case VK_BLEND_OP_MINUS_EXT:
701         res = dst - src;
702         break;
703 
704     case VK_BLEND_OP_MINUS_CLAMPED_EXT:
705         res.x() = deFloatMax(0.0f, dst.x() - src.x());
706         res.y() = deFloatMax(0.0f, dst.y() - src.y());
707         res.z() = deFloatMax(0.0f, dst.z() - src.z());
708         res.w() = deFloatMax(0.0f, dst.w() - src.w());
709         break;
710 
711     case VK_BLEND_OP_CONTRAST_EXT:
712         res.x() = (dst.w() / 2.0f) + 2.0f * (dst.x() - (dst.w() / 2.0f)) * (src.x() - (src.w() / 2.0f));
713         res.y() = (dst.w() / 2.0f) + 2.0f * (dst.y() - (dst.w() / 2.0f)) * (src.y() - (src.w() / 2.0f));
714         res.z() = (dst.w() / 2.0f) + 2.0f * (dst.z() - (dst.w() / 2.0f)) * (src.z() - (src.w() / 2.0f));
715         res.w() = dst.w();
716         break;
717 
718     case VK_BLEND_OP_INVERT_OVG_EXT:
719         res.x() = src.w() * (1.0f - dst.x()) + (1.0f - src.w()) * dst.x();
720         res.y() = src.w() * (1.0f - dst.y()) + (1.0f - src.w()) * dst.y();
721         res.z() = src.w() * (1.0f - dst.z()) + (1.0f - src.w()) * dst.z();
722         res.w() = src.w() + dst.w() - src.w() * dst.w();
723         break;
724 
725     case VK_BLEND_OP_RED_EXT:
726         res     = dst;
727         res.x() = src.x();
728         break;
729 
730     case VK_BLEND_OP_GREEN_EXT:
731         res     = dst;
732         res.y() = src.y();
733         break;
734 
735     case VK_BLEND_OP_BLUE_EXT:
736         res     = dst;
737         res.z() = src.z();
738         break;
739 
740     default:
741         DE_FATAL("Unsupported blend operation");
742     }
743     return res;
744 }
745 
calculateFinalColor(BlendOperationAdvancedParam param,VkBlendOp op,Vec4 source,Vec4 destination)746 Vec4 calculateFinalColor(BlendOperationAdvancedParam param, VkBlendOp op, Vec4 source, Vec4 destination)
747 {
748     Vec4 result   = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
749     Vec3 srcColor = source.xyz();
750     Vec3 dstColor = destination.xyz();
751 
752     // Calculate weighting factors
753     Vec3 p = calculateWeightingFactors(param, source.w(), destination.w());
754 
755     if (op > VK_BLEND_OP_MAX && op < VK_BLEND_OP_PLUS_EXT)
756     {
757         {
758             // If srcPremultiplied is set to VK_TRUE, the fragment color components
759             // are considered to have been premultiplied by the A component prior to
760             // blending. The base source color (Rs',Gs',Bs') is obtained by dividing
761             // through by the A component.
762             if (param.premultipliedSrcColor)
763             {
764                 if (source.w() != 0.0f)
765                     srcColor = srcColor / source.w();
766                 else
767                     srcColor = Vec3(0.0f, 0.0f, 0.0f);
768             }
769             // If dstPremultiplied is set to VK_TRUE, the destination components are
770             // considered to have been premultiplied by the A component prior to
771             // blending. The base destination color (Rd',Gd',Bd') is obtained by dividing
772             // through by the A component.
773             if (param.premultipliedDstColor)
774             {
775                 if (destination.w() != 0.0f)
776                     dstColor = dstColor / destination.w();
777                 else
778                     dstColor = Vec3(0.0f, 0.0f, 0.0f);
779             }
780         }
781 
782         // Calculate X, Y, Z terms of the equation
783         Vec3 xyz     = calculateXYZFactors(op);
784         Vec3 fSrcDst = calculateFFunction(op, srcColor, dstColor);
785 
786         result.x() = fSrcDst.x() * p.x() + xyz.y() * srcColor.x() * p.y() + xyz.z() * dstColor.x() * p.z();
787         result.y() = fSrcDst.y() * p.x() + xyz.y() * srcColor.y() * p.y() + xyz.z() * dstColor.y() * p.z();
788         result.z() = fSrcDst.z() * p.x() + xyz.y() * srcColor.z() * p.y() + xyz.z() * dstColor.z() * p.z();
789         result.w() = xyz.x() * p.x() + xyz.y() * p.y() + xyz.z() * p.z();
790     }
791     else if (op >= VK_BLEND_OP_PLUS_EXT && op < VK_BLEND_OP_MAX_ENUM)
792     {
793         // Premultiply colors for additional RGB blend operations. The formula is different than the rest of operations.
794         {
795             if (!param.premultipliedSrcColor)
796             {
797                 srcColor = srcColor * source.w();
798             }
799 
800             if (!param.premultipliedDstColor)
801             {
802                 dstColor = dstColor * destination.w();
803             }
804         }
805         Vec4 src = Vec4(srcColor.x(), srcColor.y(), srcColor.z(), source.w());
806         Vec4 dst = Vec4(dstColor.x(), dstColor.y(), dstColor.z(), destination.w());
807         result   = additionalRGBBlendOperations(op, src, dst);
808     }
809     else
810     {
811         DE_FATAL("Unsupported Blend Operation");
812     }
813     return result;
814 }
815 
getCoordinates(uint32_t index,int32_t & x,int32_t & y)816 static inline void getCoordinates(uint32_t index, int32_t &x, int32_t &y)
817 {
818     x = index % widthArea;
819     y = index / heightArea;
820 }
821 
createPoints(void)822 static inline std::vector<Vec4> createPoints(void)
823 {
824     std::vector<Vec4> vertices;
825     vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
826     vertices.push_back(Vec4(1.0f, 1.0f, 0.0f, 1.0f));
827     vertices.push_back(Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
828     vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
829     vertices.push_back(Vec4(1.0f, 1.0f, 0.0f, 1.0f));
830     vertices.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
831     return vertices;
832 }
833 
834 template <class Test>
newTestCase(tcu::TestContext & testContext,const BlendOperationAdvancedParam testParam)835 vkt::TestCase *newTestCase(tcu::TestContext &testContext, const BlendOperationAdvancedParam testParam)
836 {
837     return new Test(testContext, generateTestName(testParam).c_str(), testParam);
838 }
839 
makeTestRenderPass(BlendOperationAdvancedParam param,const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,VkAttachmentLoadOp colorLoadOp=VK_ATTACHMENT_LOAD_OP_CLEAR)840 RenderPassWrapper makeTestRenderPass(BlendOperationAdvancedParam param, const DeviceInterface &vk,
841                                      const VkDevice device, const VkFormat colorFormat,
842                                      VkAttachmentLoadOp colorLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR)
843 {
844     const VkAttachmentDescription colorAttachmentDescription = {
845         (VkAttachmentDescriptionFlags)0,  // VkAttachmentDescriptionFlags        flags
846         colorFormat,                      // VkFormat                            format
847         VK_SAMPLE_COUNT_1_BIT,            // VkSampleCountFlagBits            samples
848         colorLoadOp,                      // VkAttachmentLoadOp                loadOp
849         VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp                storeOp
850         VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp                stencilLoadOp
851         VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp                stencilStoreOp
852         (colorLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) ?
853             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL :
854             VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout                    initialLayout
855         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                    finalLayout
856     };
857 
858     std::vector<VkAttachmentDescription> attachmentDescriptions;
859     std::vector<VkAttachmentReference> colorAttachmentRefs;
860 
861     for (uint32_t i = 0; i < param.colorAttachmentsCount; i++)
862     {
863         attachmentDescriptions.push_back(colorAttachmentDescription);
864         const VkAttachmentReference colorAttachmentRef = {
865             i,                                       // uint32_t        attachment
866             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout    layout
867         };
868 
869         colorAttachmentRefs.push_back(colorAttachmentRef);
870     }
871 
872     const VkSubpassDescription subpassDescription = {
873         (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags        flags
874         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint                pipelineBindPoint
875         0u,                              // uint32_t                            inputAttachmentCount
876         DE_NULL,                         // const VkAttachmentReference*        pInputAttachments
877         param.colorAttachmentsCount,     // uint32_t                            colorAttachmentCount
878         colorAttachmentRefs.data(),      // const VkAttachmentReference*        pColorAttachments
879         DE_NULL,                         // const VkAttachmentReference*        pResolveAttachments
880         DE_NULL,                         // const VkAttachmentReference*        pDepthStencilAttachment
881         0u,                              // uint32_t                            preserveAttachmentCount
882         DE_NULL                          // const uint32_t*                    pPreserveAttachments
883     };
884 
885     const VkRenderPassCreateInfo renderPassInfo = {
886         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType                    sType
887         DE_NULL,                                   // const void*                        pNext
888         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags            flags
889         (uint32_t)attachmentDescriptions.size(),   // uint32_t                            attachmentCount
890         attachmentDescriptions.data(),             // const VkAttachmentDescription*    pAttachments
891         1u,                                        // uint32_t                            subpassCount
892         &subpassDescription,                       // const VkSubpassDescription*        pSubpasses
893         0u,                                        // uint32_t                            dependencyCount
894         DE_NULL                                    // const VkSubpassDependency*        pDependencies
895     };
896 
897     return RenderPassWrapper(param.pipelineConstructionType, vk, device, &renderPassInfo);
898 }
899 
createBufferAndBindMemory(Context & context,VkDeviceSize size,VkBufferUsageFlags usage,de::MovePtr<Allocation> * pAlloc)900 Move<VkBuffer> createBufferAndBindMemory(Context &context, VkDeviceSize size, VkBufferUsageFlags usage,
901                                          de::MovePtr<Allocation> *pAlloc)
902 {
903     const DeviceInterface &vk       = context.getDeviceInterface();
904     const VkDevice vkDevice         = context.getDevice();
905     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
906 
907     const VkBufferCreateInfo vertexBufferParams = {
908         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
909         DE_NULL,                              // const void* pNext;
910         0u,                                   // VkBufferCreateFlags flags;
911         size,                                 // VkDeviceSize size;
912         usage,                                // VkBufferUsageFlags usage;
913         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
914         1u,                                   // uint32_t queueFamilyCount;
915         &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
916     };
917 
918     Move<VkBuffer> vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
919 
920     *pAlloc = context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer),
921                                                      MemoryRequirement::HostVisible);
922     VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset()));
923 
924     return vertexBuffer;
925 }
926 
createImage2DAndBindMemory(Context & context,VkFormat format,uint32_t width,uint32_t height,VkImageUsageFlags usage,VkSampleCountFlagBits sampleCount,de::details::MovePtr<Allocation> * pAlloc)927 Move<VkImage> createImage2DAndBindMemory(Context &context, VkFormat format, uint32_t width, uint32_t height,
928                                          VkImageUsageFlags usage, VkSampleCountFlagBits sampleCount,
929                                          de::details::MovePtr<Allocation> *pAlloc)
930 {
931     const DeviceInterface &vk       = context.getDeviceInterface();
932     const VkDevice vkDevice         = context.getDevice();
933     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
934 
935     const VkImageCreateInfo colorImageParams = {
936         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
937         DE_NULL,                             // const void* pNext;
938         0u,                                  // VkImageCreateFlags flags;
939         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
940         format,                              // VkFormat format;
941         {width, height, 1u},                 // VkExtent3D extent;
942         1u,                                  // uint32_t mipLevels;
943         1u,                                  // uint32_t arraySize;
944         sampleCount,                         // uint32_t samples;
945         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
946         usage,                               // VkImageUsageFlags usage;
947         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
948         1u,                                  // uint32_t queueFamilyCount;
949         &queueFamilyIndex,                   // const uint32_t* pQueueFamilyIndices;
950         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
951     };
952 
953     Move<VkImage> image = createImage(vk, vkDevice, &colorImageParams);
954 
955     *pAlloc = context.getDefaultAllocator().allocate(getImageMemoryRequirements(vk, vkDevice, *image),
956                                                      MemoryRequirement::Any);
957     VK_CHECK(vk.bindImageMemory(vkDevice, *image, (*pAlloc)->getMemory(), (*pAlloc)->getOffset()));
958 
959     return image;
960 }
961 
962 // Test Classes
963 class BlendOperationAdvancedTestInstance : public vkt::TestInstance
964 {
965 public:
966     BlendOperationAdvancedTestInstance(Context &context, const BlendOperationAdvancedParam param);
967     virtual ~BlendOperationAdvancedTestInstance(void);
968     virtual tcu::TestStatus iterate(void);
969 
970 protected:
971     void prepareRenderPass(const GraphicsPipelineWrapper &pipeline) const;
972     void prepareCommandBuffer(void) const;
973     void buildPipeline(VkBool32 premultiplySrc, VkBool32 premultiplyDst);
974     bool verifyTestResult(void);
975 
976 protected:
977     const BlendOperationAdvancedParam m_param;
978     const tcu::UVec2 m_renderSize;
979     const VkFormat m_colorFormat;
980     PipelineLayoutWrapper m_pipelineLayout;
981 
982     Move<VkBuffer> m_vertexBuffer;
983     de::MovePtr<Allocation> m_vertexBufferMemory;
984     std::vector<Vec4> m_vertices;
985 
986     RenderPassWrapper m_renderPass;
987     Move<VkCommandPool> m_cmdPool;
988     Move<VkCommandBuffer> m_cmdBuffer;
989     std::vector<Move<VkImage>> m_colorImages;
990     std::vector<Move<VkImageView>> m_colorAttachmentViews;
991     std::vector<de::MovePtr<Allocation>> m_colorImageAllocs;
992     std::vector<VkImageMemoryBarrier> m_imageLayoutBarriers;
993     GraphicsPipelineWrapper m_pipeline;
994 
995     ShaderWrapper m_shaderModules[2];
996 };
997 
buildPipeline(VkBool32 srcPremultiplied,VkBool32 dstPremultiplied)998 void BlendOperationAdvancedTestInstance::buildPipeline(VkBool32 srcPremultiplied, VkBool32 dstPremultiplied)
999 {
1000     const DeviceInterface &vk = m_context.getDeviceInterface();
1001     const VkDevice vkDevice   = m_context.getDevice();
1002 
1003     const std::vector<VkRect2D> scissor{makeRect2D(m_renderSize)};
1004     const std::vector<VkViewport> viewport{makeViewport(m_renderSize)};
1005 
1006     const VkPipelineColorBlendAdvancedStateCreateInfoEXT blendAdvancedStateParams = {
1007         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT, // VkStructureType sType;
1008         DE_NULL,                                                               // const void* pNext;
1009         srcPremultiplied,                                                      // VkBool32 srcPremultiplied;
1010         dstPremultiplied,                                                      // VkBool32 dstPremultiplied;
1011         m_param.overlap,                                                       // VkBlendOverlapEXT blendOverlap;
1012     };
1013 
1014     std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates;
1015 
1016     for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1017     {
1018         const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1019             VK_TRUE,             // VkBool32 blendEnable;
1020             VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
1021             VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor;
1022             m_param.blendOps[i], // VkBlendOp colorBlendOp;
1023             VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
1024             VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor;
1025             m_param.blendOps[i], // VkBlendOp alphaBlendOp;
1026             VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
1027                 VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask;
1028         };
1029         colorBlendAttachmentStates.emplace_back(colorBlendAttachmentState);
1030     }
1031 
1032     const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
1033         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1034         &blendAdvancedStateParams,                                // const void* pNext;
1035         0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
1036         VK_FALSE,                                                 // VkBool32 logicOpEnable;
1037         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
1038         (uint32_t)colorBlendAttachmentStates.size(),              // uint32_t attachmentCount;
1039         colorBlendAttachmentStates.data(), // const VkPipelineColorBlendAttachmentState* pAttachments;
1040         {0.0f, 0.0f, 0.0f, 0.0f},          // float blendConst[4];
1041     };
1042 
1043     const VkPipelineMultisampleStateCreateInfo multisampleStateParams = {
1044         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
1045         DE_NULL,                                                  // const void* pNext;
1046         0u,                                                       // VkPipelineMultisampleStateCreateFlags flags;
1047         VK_SAMPLE_COUNT_1_BIT,                                    // VkSampleCountFlagBits rasterizationSamples;
1048         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
1049         0.0f,                                                     // float minSampleShading;
1050         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
1051         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
1052         VK_FALSE,                                                 // VkBool32 alphaToOneEnable;
1053     };
1054 
1055     VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = {
1056         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
1057         DE_NULL,                                                    // const void* pNext;
1058         0u,                                                         // VkPipelineDepthStencilStateCreateFlags flags;
1059         VK_FALSE,                                                   // VkBool32 depthTestEnable;
1060         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
1061         VK_COMPARE_OP_NEVER,                                        // VkCompareOp depthCompareOp;
1062         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
1063         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
1064         // VkStencilOpState front;
1065         {
1066             VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1067             VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1068             VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1069             VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1070             0u,                  // uint32_t compareMask;
1071             0u,                  // uint32_t writeMask;
1072             0u,                  // uint32_t reference;
1073         },
1074         // VkStencilOpState back;
1075         {
1076             VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1077             VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1078             VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1079             VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1080             0u,                  // uint32_t compareMask;
1081             0u,                  // uint32_t writeMask;
1082             0u,                  // uint32_t reference;
1083         },
1084         0.0f, // float minDepthBounds;
1085         1.0f, // float maxDepthBounds;
1086     };
1087 
1088     const VkDynamicState dynamicState                         = VK_DYNAMIC_STATE_SCISSOR;
1089     const VkPipelineDynamicStateCreateInfo dynamicStateParams = {
1090         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
1091         DE_NULL,                                              // const void* pNext;
1092         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
1093         1u,                                                   // uint32_t dynamicStateCount;
1094         &dynamicState                                         // const VkDynamicState* pDynamicStates;
1095     };
1096 
1097     m_shaderModules[0] = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0);
1098     m_shaderModules[1] = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0);
1099 
1100     m_pipeline.setDynamicState(&dynamicStateParams)
1101         .setDefaultRasterizationState()
1102         .setupVertexInputState()
1103         .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, *m_renderPass, 0u, m_shaderModules[0])
1104         .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, m_shaderModules[1], &depthStencilStateParams,
1105                                   &multisampleStateParams)
1106         .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams, &multisampleStateParams)
1107         .setMonolithicPipelineLayout(m_pipelineLayout)
1108         .buildPipeline();
1109 }
1110 
prepareRenderPass(const GraphicsPipelineWrapper & pipeline) const1111 void BlendOperationAdvancedTestInstance::prepareRenderPass(const GraphicsPipelineWrapper &pipeline) const
1112 {
1113     const DeviceInterface &vk = m_context.getDeviceInterface();
1114 
1115     std::vector<VkClearValue> attachmentClearValues;
1116 
1117     for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1118         attachmentClearValues.emplace_back(makeClearValueColor(clearColorVec4));
1119 
1120     m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()),
1121                        m_param.colorAttachmentsCount, attachmentClearValues.data());
1122     pipeline.bind(*m_cmdBuffer);
1123     VkDeviceSize offsets = 0u;
1124     vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &offsets);
1125 
1126     // Draw all colors
1127     uint32_t skippedColors = 0u;
1128     for (uint32_t color = 0; color < DE_LENGTH_OF_ARRAY(srcColors); color++)
1129     {
1130         // Skip ill-formed colors when we have non-premultiplied destination colors.
1131         if (m_param.premultipliedDstColor == VK_FALSE)
1132         {
1133             bool skipColor = false;
1134             for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1135             {
1136                 Vec4 calculatedColor =
1137                     calculateFinalColor(m_param, m_param.blendOps[i], srcColors[color], dstColors[color]);
1138                 if (calculatedColor.w() <= 0.0f && calculatedColor != Vec4(0.0f))
1139                 {
1140                     // Skip ill-formed colors, because the spec says the result is undefined.
1141                     skippedColors++;
1142                     skipColor = true;
1143                     break;
1144                 }
1145             }
1146             if (skipColor)
1147                 continue;
1148         }
1149 
1150         int32_t x = 0;
1151         int32_t y = 0;
1152         getCoordinates(color, x, y);
1153 
1154         // Set source color as push constant
1155         vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(Vec4),
1156                             &srcColors[color]);
1157 
1158         VkRect2D scissor = makeRect2D(x, y, 1u, 1u);
1159         if (vk::isConstructionTypeShaderObject(m_param.pipelineConstructionType))
1160         {
1161 #ifndef CTS_USES_VULKANSC
1162             vk.cmdSetScissorWithCount(*m_cmdBuffer, 1u, &scissor);
1163 #else
1164             vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, 1u, &scissor);
1165 #endif
1166         }
1167         else
1168         {
1169             vk.cmdSetScissor(*m_cmdBuffer, 0u, 1u, &scissor);
1170         }
1171 
1172         // To set destination color, we do clear attachment restricting the area to the respective pixel of each color attachment.
1173         {
1174             // Set destination color as push constant.
1175             std::vector<VkClearAttachment> attachments;
1176             VkClearValue clearValue = vk::makeClearValueColorVec4(dstColors[color]);
1177 
1178             for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1179             {
1180                 VkClearAttachment attachment = {VK_IMAGE_ASPECT_COLOR_BIT, i, clearValue};
1181                 attachments.emplace_back(attachment);
1182             }
1183 
1184             const VkClearRect rect = {scissor, 0u, 1u};
1185             vk.cmdClearAttachments(*m_cmdBuffer, (uint32_t)attachments.size(), attachments.data(), 1u, &rect);
1186         }
1187 
1188         // Draw
1189         vk.cmdDraw(*m_cmdBuffer, (uint32_t)m_vertices.size(), 1u, 0u, 0u);
1190     }
1191 
1192     // If we break this assert, then we are not testing anything in this test.
1193     DE_ASSERT(skippedColors < DE_LENGTH_OF_ARRAY(srcColors));
1194 
1195     // Log number of skipped colors
1196     if (skippedColors != 0u)
1197     {
1198         tcu::TestLog &log = m_context.getTestContext().getLog();
1199         log << tcu::TestLog::Message << "Skipped " << skippedColors << " out of " << DE_LENGTH_OF_ARRAY(srcColors)
1200             << " color cases due to ill-formed colors" << tcu::TestLog::EndMessage;
1201     }
1202     m_renderPass.end(vk, *m_cmdBuffer);
1203 }
1204 
prepareCommandBuffer() const1205 void BlendOperationAdvancedTestInstance::prepareCommandBuffer() const
1206 {
1207     const DeviceInterface &vk = m_context.getDeviceInterface();
1208 
1209     beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1210 
1211     vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1212                           VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
1213                           (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, (uint32_t)m_imageLayoutBarriers.size(),
1214                           m_imageLayoutBarriers.data());
1215 
1216     prepareRenderPass(m_pipeline);
1217 
1218     endCommandBuffer(vk, *m_cmdBuffer);
1219 }
1220 
BlendOperationAdvancedTestInstance(Context & context,const BlendOperationAdvancedParam param)1221 BlendOperationAdvancedTestInstance::BlendOperationAdvancedTestInstance(Context &context,
1222                                                                        const BlendOperationAdvancedParam param)
1223     : TestInstance(context)
1224     , m_param(param)
1225     , m_renderSize(tcu::UVec2(widthArea, heightArea))
1226     , m_colorFormat(param.format)
1227     , m_pipeline(m_context.getInstanceInterface(), m_context.getDeviceInterface(), m_context.getPhysicalDevice(),
1228                  m_context.getDevice(), m_context.getDeviceExtensions(), param.pipelineConstructionType)
1229 {
1230     const DeviceInterface &vk       = m_context.getDeviceInterface();
1231     const VkDevice vkDevice         = m_context.getDevice();
1232     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1233 
1234     // Create vertex buffer and upload data
1235     {
1236         // Load vertices into vertex buffer
1237         m_vertices = createPoints();
1238         DE_ASSERT((uint32_t)m_vertices.size() == 6);
1239 
1240         m_vertexBuffer = createBufferAndBindMemory(m_context, m_vertices.size() * sizeof(Vec4),
1241                                                    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &m_vertexBufferMemory);
1242         deMemcpy(m_vertexBufferMemory->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vec4));
1243         flushAlloc(vk, vkDevice, *m_vertexBufferMemory);
1244     }
1245 
1246     // Create render pass
1247     m_renderPass = makeTestRenderPass(param, vk, vkDevice, m_colorFormat);
1248 
1249     const VkComponentMapping componentMappingRGBA = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1250                                                      VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
1251 
1252     // Create color images
1253     for (uint32_t i = 0; i < param.colorAttachmentsCount; i++)
1254     {
1255         de::MovePtr<Allocation> colorImageAlloc;
1256         m_colorImageAllocs.emplace_back(colorImageAlloc);
1257 
1258         Move<VkImage> colorImage =
1259             createImage2DAndBindMemory(m_context, m_colorFormat, m_renderSize.x(), m_renderSize.y(),
1260                                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
1261                                        VK_SAMPLE_COUNT_1_BIT, &m_colorImageAllocs.back());
1262         m_colorImages.emplace_back(colorImage);
1263 
1264         // Set up image layout transition barriers
1265         {
1266             VkImageMemoryBarrier colorImageBarrier = {
1267                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1268                 DE_NULL,                                // const void* pNext;
1269                 0u,                                     // VkAccessFlags srcAccessMask;
1270                 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
1271                  VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags dstAccessMask;
1272                 VK_IMAGE_LAYOUT_UNDEFINED,                             // VkImageLayout oldLayout;
1273                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,              // VkImageLayout newLayout;
1274                 VK_QUEUE_FAMILY_IGNORED,                               // uint32_t srcQueueFamilyIndex;
1275                 VK_QUEUE_FAMILY_IGNORED,                               // uint32_t dstQueueFamilyIndex;
1276                 *m_colorImages.back(),                                 // VkImage image;
1277                 {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u},           // VkImageSubresourceRange subresourceRange;
1278             };
1279 
1280             m_imageLayoutBarriers.emplace_back(colorImageBarrier);
1281         }
1282 
1283         // Create color attachment view
1284         {
1285             VkImageViewCreateInfo colorAttachmentViewParams = {
1286                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,    // VkStructureType sType;
1287                 DE_NULL,                                     // const void* pNext;
1288                 0u,                                          // VkImageViewCreateFlags flags;
1289                 *m_colorImages.back(),                       // VkImage image;
1290                 VK_IMAGE_VIEW_TYPE_2D,                       // VkImageViewType viewType;
1291                 m_colorFormat,                               // VkFormat format;
1292                 componentMappingRGBA,                        // VkComponentMapping components;
1293                 {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1294             };
1295 
1296             m_colorAttachmentViews.emplace_back(createImageView(vk, vkDevice, &colorAttachmentViewParams));
1297         }
1298     }
1299 
1300     // Create framebuffer
1301     {
1302         std::vector<VkImage> images;
1303         std::vector<VkImageView> imageViews;
1304 
1305         for (auto &movePtr : m_colorImages)
1306             images.push_back(movePtr.get());
1307 
1308         for (auto &movePtr : m_colorAttachmentViews)
1309             imageViews.push_back(movePtr.get());
1310 
1311         const VkFramebufferCreateInfo framebufferParams = {
1312             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1313             DE_NULL,                                   // const void* pNext;
1314             0u,                                        // VkFramebufferCreateFlags flags;
1315             *m_renderPass,                             // VkRenderPass renderPass;
1316             (uint32_t)imageViews.size(),               // uint32_t attachmentCount;
1317             imageViews.data(),                         // const VkImageView* pAttachments;
1318             (uint32_t)m_renderSize.x(),                // uint32_t width;
1319             (uint32_t)m_renderSize.y(),                // uint32_t height;
1320             1u,                                        // uint32_t layers;
1321         };
1322 
1323         m_renderPass.createFramebuffer(vk, vkDevice, &framebufferParams, images);
1324     }
1325 
1326     // Create pipeline layout
1327     {
1328         const VkPushConstantRange pushConstantRange = {
1329             VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags    stageFlags
1330             0,                            // uint32_t                offset
1331             sizeof(Vec4)                  // uint32_t                size
1332         };
1333 
1334         const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
1335             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1336             DE_NULL,                                       // const void* pNext;
1337             0u,                                            // VkPipelineLayoutCreateFlags flags;
1338             0u,                                            // uint32_t setLayoutCount;
1339             DE_NULL,                                       // const VkDescriptorSetLayout* pSetLayouts;
1340             1u,                                            // uint32_t pushConstantRangeCount;
1341             &pushConstantRange                             // const VkPushConstantRange* pPushConstantRanges;
1342         };
1343 
1344         m_pipelineLayout = PipelineLayoutWrapper(m_param.pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
1345     }
1346 
1347     // Create pipeline
1348     buildPipeline(m_param.premultipliedSrcColor, m_param.premultipliedDstColor);
1349 
1350     // Create command pool
1351     m_cmdPool = createCommandPool(
1352         vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1353         queueFamilyIndex);
1354 
1355     // Create command buffer
1356     m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1357 }
1358 
~BlendOperationAdvancedTestInstance(void)1359 BlendOperationAdvancedTestInstance::~BlendOperationAdvancedTestInstance(void)
1360 {
1361 }
1362 
iterate(void)1363 tcu::TestStatus BlendOperationAdvancedTestInstance::iterate(void)
1364 {
1365     const DeviceInterface &vk = m_context.getDeviceInterface();
1366     const VkDevice vkDevice   = m_context.getDevice();
1367     const VkQueue queue       = m_context.getUniversalQueue();
1368     tcu::TestLog &log         = m_context.getTestContext().getLog();
1369 
1370     // Log the blend operations to test
1371     {
1372         if (m_param.independentBlend)
1373         {
1374             for (uint32_t i = 0; (i < m_param.colorAttachmentsCount); i++)
1375                 log << tcu::TestLog::Message << "Color attachment " << i
1376                     << " uses depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[i]).toString().substr(3))
1377                     << tcu::TestLog::EndMessage;
1378         }
1379         else
1380         {
1381             log << tcu::TestLog::Message << "All color attachments use depth op: "
1382                 << de::toLower(getBlendOpStr(m_param.blendOps[0]).toString().substr(3)) << tcu::TestLog::EndMessage;
1383         }
1384     }
1385     prepareCommandBuffer();
1386     submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
1387 
1388     if (verifyTestResult() == false)
1389         return tcu::TestStatus::fail("Image mismatch");
1390 
1391     return tcu::TestStatus::pass("Result images matches references");
1392 }
1393 
verifyTestResult()1394 bool BlendOperationAdvancedTestInstance::verifyTestResult()
1395 {
1396     bool compareOk                  = true;
1397     const DeviceInterface &vk       = m_context.getDeviceInterface();
1398     const VkDevice vkDevice         = m_context.getDevice();
1399     const VkQueue queue             = m_context.getUniversalQueue();
1400     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1401     Allocator &allocator            = m_context.getDefaultAllocator();
1402     std::vector<tcu::TextureLevel> referenceImages;
1403 
1404     for (uint32_t colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++)
1405     {
1406         tcu::TextureLevel refImage(vk::mapVkFormat(m_colorFormat), 32, 32);
1407         tcu::clear(refImage.getAccess(), clearColorVec4);
1408         referenceImages.emplace_back(refImage);
1409     }
1410 
1411     for (uint32_t color = 0; color < DE_LENGTH_OF_ARRAY(srcColors); color++)
1412     {
1413         bool skipColor = false;
1414 
1415         // Check if any color attachment will generate an ill-formed color. If that's the case, skip that color in the verification.
1416         for (uint32_t colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++)
1417         {
1418             Vec4 rectColor =
1419                 calculateFinalColor(m_param, m_param.blendOps[colorAtt], srcColors[color], dstColors[color]);
1420 
1421             if (m_param.premultipliedDstColor == VK_FALSE)
1422             {
1423                 if (rectColor.w() > 0.0f)
1424                 {
1425                     rectColor.x() = rectColor.x() / rectColor.w();
1426                     rectColor.y() = rectColor.y() / rectColor.w();
1427                     rectColor.z() = rectColor.z() / rectColor.w();
1428                 }
1429                 else
1430                 {
1431                     // Skip the color check if it is ill-formed.
1432                     if (rectColor != Vec4(0.0f))
1433                     {
1434                         skipColor = true;
1435                         break;
1436                     }
1437                 }
1438             }
1439 
1440             // If pixel value is not normal (inf, nan, denorm), skip it
1441             if (!std::isnormal(rectColor.x()) || !std::isnormal(rectColor.y()) || !std::isnormal(rectColor.z()) ||
1442                 !std::isnormal(rectColor.w()))
1443                 skipColor = true;
1444         }
1445 
1446         // Skip ill-formed colors that appears in any color attachment.
1447         if (skipColor)
1448             continue;
1449 
1450         // If we reach this point, the final color for all color attachment is not ill-formed.
1451         for (uint32_t colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++)
1452         {
1453             Vec4 rectColor =
1454                 calculateFinalColor(m_param, m_param.blendOps[colorAtt], srcColors[color], dstColors[color]);
1455             if (m_param.premultipliedDstColor == VK_FALSE)
1456             {
1457                 if (rectColor.w() > 0.0f)
1458                 {
1459                     rectColor.x() = rectColor.x() / rectColor.w();
1460                     rectColor.y() = rectColor.y() / rectColor.w();
1461                     rectColor.z() = rectColor.z() / rectColor.w();
1462                 }
1463                 else
1464                 {
1465                     // Ill-formed colors were already skipped
1466                     DE_ASSERT(rectColor == Vec4(0.0f));
1467                 }
1468             }
1469             int32_t x = 0;
1470             int32_t y = 0;
1471             getCoordinates(color, x, y);
1472             tcu::clear(tcu::getSubregion(referenceImages[colorAtt].getAccess(), x, y, 1u, 1u), rectColor);
1473         }
1474     }
1475 
1476     for (uint32_t colorAtt = 0; colorAtt < m_param.colorAttachmentsCount; colorAtt++)
1477     {
1478         // Compare image
1479         de::MovePtr<tcu::TextureLevel> result = vkt::pipeline::readColorAttachment(
1480             vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImages[colorAtt], m_colorFormat, m_renderSize);
1481         std::ostringstream name;
1482         name << "Image comparison. Color attachment: " << colorAtt
1483              << ". Depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[colorAtt]).toString().substr(3));
1484 
1485         // R8G8B8A8 threshold was derived experimentally.
1486         compareOk =
1487             tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "FloatImageCompare", name.str().c_str(),
1488                                        referenceImages[colorAtt].getAccess(), result->getAccess(), clearColorVec4,
1489                                        m_colorFormat == VK_FORMAT_R8G8B8A8_UNORM ? Vec4(0.15f, 0.15f, 0.15f, 0.13f) :
1490                                                                                    Vec4(0.01f, 0.01f, 0.01f, 0.01f),
1491                                        tcu::COMPARE_LOG_RESULT);
1492 #ifdef CTS_USES_VULKANSC
1493         if (m_context.getTestContext().getCommandLine().isSubProcess())
1494 #endif // CTS_USES_VULKANSC
1495         {
1496             if (!compareOk)
1497                 return false;
1498         }
1499     }
1500     return true;
1501 }
1502 
1503 class BlendOperationAdvancedTest : public vkt::TestCase
1504 {
1505 public:
BlendOperationAdvancedTest(tcu::TestContext & testContext,const std::string & name,const BlendOperationAdvancedParam param)1506     BlendOperationAdvancedTest(tcu::TestContext &testContext, const std::string &name,
1507                                const BlendOperationAdvancedParam param)
1508         : vkt::TestCase(testContext, name)
1509         , m_param(param)
1510     {
1511     }
~BlendOperationAdvancedTest(void)1512     virtual ~BlendOperationAdvancedTest(void)
1513     {
1514     }
1515     virtual void initPrograms(SourceCollections &programCollection) const;
1516     virtual TestInstance *createInstance(Context &context) const;
1517     virtual void checkSupport(Context &context) const;
1518 
1519 protected:
1520     const BlendOperationAdvancedParam m_param;
1521 };
1522 
checkSupport(Context & context) const1523 void BlendOperationAdvancedTest::checkSupport(Context &context) const
1524 {
1525     const InstanceInterface &vki = context.getInstanceInterface();
1526 
1527     context.requireDeviceFunctionality("VK_EXT_blend_operation_advanced");
1528 
1529     VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT blendProperties;
1530     blendProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
1531     blendProperties.pNext = DE_NULL;
1532 
1533     VkPhysicalDeviceProperties2 properties2;
1534     properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1535     properties2.pNext = &blendProperties;
1536     vki.getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties2);
1537 
1538     if (!blendProperties.advancedBlendAllOperations)
1539     {
1540         for (uint32_t index = 0u; index < m_param.blendOps.size(); index++)
1541         {
1542             switch (m_param.blendOps[index])
1543             {
1544             case VK_BLEND_OP_MULTIPLY_EXT:
1545             case VK_BLEND_OP_SCREEN_EXT:
1546             case VK_BLEND_OP_OVERLAY_EXT:
1547             case VK_BLEND_OP_DARKEN_EXT:
1548             case VK_BLEND_OP_LIGHTEN_EXT:
1549             case VK_BLEND_OP_COLORDODGE_EXT:
1550             case VK_BLEND_OP_COLORBURN_EXT:
1551             case VK_BLEND_OP_HARDLIGHT_EXT:
1552             case VK_BLEND_OP_SOFTLIGHT_EXT:
1553             case VK_BLEND_OP_DIFFERENCE_EXT:
1554             case VK_BLEND_OP_EXCLUSION_EXT:
1555             case VK_BLEND_OP_HSL_HUE_EXT:
1556             case VK_BLEND_OP_HSL_SATURATION_EXT:
1557             case VK_BLEND_OP_HSL_COLOR_EXT:
1558             case VK_BLEND_OP_HSL_LUMINOSITY_EXT:
1559                 break;
1560             default:
1561                 throw tcu::NotSupportedError(
1562                     "Unsupported all advanced blend operations and unsupported advanced blend operation");
1563             }
1564         }
1565     }
1566 
1567     if (m_param.colorAttachmentsCount > blendProperties.advancedBlendMaxColorAttachments)
1568     {
1569         std::ostringstream error;
1570         error << "Unsupported number of color attachments (" << blendProperties.advancedBlendMaxColorAttachments
1571               << " < " << m_param.colorAttachmentsCount;
1572         throw tcu::NotSupportedError(error.str().c_str());
1573     }
1574 
1575     if (m_param.overlap != VK_BLEND_OVERLAP_UNCORRELATED_EXT && !blendProperties.advancedBlendCorrelatedOverlap)
1576     {
1577         throw tcu::NotSupportedError("Unsupported blend correlated overlap");
1578     }
1579 
1580     if (m_param.colorAttachmentsCount > 1 && m_param.independentBlend && !blendProperties.advancedBlendIndependentBlend)
1581     {
1582         throw tcu::NotSupportedError("Unsupported independent blend");
1583     }
1584 
1585     if (!m_param.premultipliedSrcColor && !blendProperties.advancedBlendNonPremultipliedSrcColor)
1586     {
1587         throw tcu::NotSupportedError("Unsupported non-premultiplied source color");
1588     }
1589 
1590     if (!m_param.premultipliedDstColor && !blendProperties.advancedBlendNonPremultipliedDstColor)
1591     {
1592         throw tcu::NotSupportedError("Unsupported non-premultiplied destination color");
1593     }
1594 
1595     const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT blendFeatures =
1596         context.getBlendOperationAdvancedFeaturesEXT();
1597     if (m_param.coherentOperations && !blendFeatures.advancedBlendCoherentOperations)
1598     {
1599         throw tcu::NotSupportedError("Unsupported required coherent operations");
1600     }
1601     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1602                                           m_param.pipelineConstructionType);
1603 }
1604 
initPrograms(SourceCollections & programCollection) const1605 void BlendOperationAdvancedTest::initPrograms(SourceCollections &programCollection) const
1606 {
1607     programCollection.glslSources.add("vert") << glu::VertexSource("#version 310 es\n"
1608                                                                    "layout(location = 0) in vec4 position;\n"
1609                                                                    "void main (void)\n"
1610                                                                    "{\n"
1611                                                                    "  gl_Position = position;\n"
1612                                                                    "}\n");
1613 
1614     std::ostringstream fragmentSource;
1615     fragmentSource << "#version 310 es\n";
1616     fragmentSource << "layout(push_constant) uniform Color { highp vec4 color; };\n";
1617     for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1618         fragmentSource << "layout(location = " << i << ") out highp vec4 fragColor" << i << ";\n";
1619     fragmentSource << "void main (void)\n";
1620     fragmentSource << "{\n";
1621     for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1622         fragmentSource << "  fragColor" << i << " = color;\n";
1623     fragmentSource << "}\n";
1624     programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSource.str().c_str());
1625 }
1626 
1627 class BlendOperationAdvancedTestCoherentInstance : public vkt::TestInstance
1628 {
1629 public:
1630     BlendOperationAdvancedTestCoherentInstance(Context &context, const BlendOperationAdvancedParam param);
1631     virtual ~BlendOperationAdvancedTestCoherentInstance(void);
1632     virtual tcu::TestStatus iterate(void);
1633 
1634 protected:
1635     void prepareRenderPass(GraphicsPipelineWrapper &pipeline, RenderPassWrapper &renderpass, bool secondDraw);
1636     virtual void prepareCommandBuffer(void);
1637     virtual void buildPipeline(void);
1638     virtual tcu::TestStatus verifyTestResult(void);
1639 
1640 protected:
1641     const BlendOperationAdvancedParam m_param;
1642     const tcu::UVec2 m_renderSize;
1643     const VkFormat m_colorFormat;
1644     PipelineLayoutWrapper m_pipelineLayout;
1645 
1646     Move<VkBuffer> m_vertexBuffer;
1647     de::MovePtr<Allocation> m_vertexBufferMemory;
1648     std::vector<Vec4> m_vertices;
1649 
1650     std::vector<RenderPassWrapper> m_renderPasses;
1651     Move<VkCommandPool> m_cmdPool;
1652     Move<VkCommandBuffer> m_cmdBuffer;
1653     Move<VkImage> m_colorImage;
1654     Move<VkImageView> m_colorAttachmentView;
1655     de::MovePtr<Allocation> m_colorImageAlloc;
1656     std::vector<VkImageMemoryBarrier> m_imageLayoutBarriers;
1657     std::vector<GraphicsPipelineWrapper> m_pipelines;
1658 
1659     ShaderWrapper m_shaderModules[2];
1660     uint32_t m_shaderStageCount;
1661     VkPipelineShaderStageCreateInfo m_shaderStageInfo[2];
1662 };
1663 
~BlendOperationAdvancedTestCoherentInstance(void)1664 BlendOperationAdvancedTestCoherentInstance::~BlendOperationAdvancedTestCoherentInstance(void)
1665 {
1666 }
1667 
buildPipeline()1668 void BlendOperationAdvancedTestCoherentInstance::buildPipeline()
1669 {
1670     const InstanceInterface &vki          = m_context.getInstanceInterface();
1671     const DeviceInterface &vk             = m_context.getDeviceInterface();
1672     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
1673     const VkDevice vkDevice               = m_context.getDevice();
1674 
1675     const std::vector<VkRect2D> scissor{makeRect2D(m_renderSize)};
1676     const std::vector<VkViewport> viewport{makeViewport(m_renderSize)};
1677 
1678     const VkPipelineColorBlendAdvancedStateCreateInfoEXT blendAdvancedStateParams = {
1679         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT, // VkStructureType sType;
1680         DE_NULL,                                                               // const void* pNext;
1681         VK_TRUE,                                                               // VkBool32 srcPremultiplied;
1682         VK_TRUE,                                                               // VkBool32 dstPremultiplied;
1683         m_param.overlap,                                                       // VkBlendOverlapEXT blendOverlap;
1684     };
1685 
1686     std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates;
1687 
1688     // One VkPipelineColorBlendAttachmentState for each pipeline, we only have one color attachment.
1689     for (uint32_t i = 0; i < 2; i++)
1690     {
1691         const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1692             VK_TRUE,             // VkBool32 blendEnable;
1693             VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
1694             VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor;
1695             m_param.blendOps[i], // VkBlendOp colorBlendOp;
1696             VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
1697             VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor;
1698             m_param.blendOps[i], // VkBlendOp alphaBlendOp;
1699             VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
1700                 VK_COLOR_COMPONENT_A_BIT // VkColorComponentFlags colorWriteMask;
1701         };
1702         colorBlendAttachmentStates.emplace_back(colorBlendAttachmentState);
1703     }
1704 
1705     std::vector<VkPipelineColorBlendStateCreateInfo> colorBlendStateParams;
1706     VkPipelineColorBlendStateCreateInfo colorBlendStateParam = {
1707         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1708         &blendAdvancedStateParams,                                // const void* pNext;
1709         0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
1710         VK_FALSE,                                                 // VkBool32 logicOpEnable;
1711         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
1712         1u,                                                       // uint32_t attachmentCount;
1713         &colorBlendAttachmentStates[0], // const VkPipelineColorBlendAttachmentState* pAttachments;
1714         {0.0f, 0.0f, 0.0f, 0.0f},       // float blendConst[4];
1715     };
1716     colorBlendStateParams.emplace_back(colorBlendStateParam);
1717 
1718     // For the second pipeline, the blendOp changed.
1719     colorBlendStateParam.pAttachments = &colorBlendAttachmentStates[1];
1720     colorBlendStateParams.emplace_back(colorBlendStateParam);
1721 
1722     const VkPipelineMultisampleStateCreateInfo multisampleStateParams = {
1723         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
1724         DE_NULL,                                                  // const void* pNext;
1725         0u,                                                       // VkPipelineMultisampleStateCreateFlags flags;
1726         VK_SAMPLE_COUNT_1_BIT,                                    // VkSampleCountFlagBits rasterizationSamples;
1727         VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
1728         0.0f,                                                     // float minSampleShading;
1729         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
1730         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
1731         VK_FALSE,                                                 // VkBool32 alphaToOneEnable;
1732     };
1733 
1734     VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = {
1735         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
1736         DE_NULL,                                                    // const void* pNext;
1737         0u,                                                         // VkPipelineDepthStencilStateCreateFlags flags;
1738         VK_FALSE,                                                   // VkBool32 depthTestEnable;
1739         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
1740         VK_COMPARE_OP_NEVER,                                        // VkCompareOp depthCompareOp;
1741         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
1742         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
1743         // VkStencilOpState front;
1744         {
1745             VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1746             VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1747             VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1748             VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1749             0u,                  // uint32_t compareMask;
1750             0u,                  // uint32_t writeMask;
1751             0u,                  // uint32_t reference;
1752         },
1753         // VkStencilOpState back;
1754         {
1755             VK_STENCIL_OP_KEEP,  // VkStencilOp failOp;
1756             VK_STENCIL_OP_KEEP,  // VkStencilOp passOp;
1757             VK_STENCIL_OP_KEEP,  // VkStencilOp depthFailOp;
1758             VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
1759             0u,                  // uint32_t compareMask;
1760             0u,                  // uint32_t writeMask;
1761             0u,                  // uint32_t reference;
1762         },
1763         0.0f, // float minDepthBounds;
1764         1.0f, // float maxDepthBounds;
1765     };
1766 
1767     const VkDynamicState dynamicState                         = VK_DYNAMIC_STATE_SCISSOR;
1768     const VkPipelineDynamicStateCreateInfo dynamicStateParams = {
1769         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
1770         DE_NULL,                                              // const void* pNext;
1771         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
1772         1u,                                                   // uint32_t dynamicStateCount;
1773         &dynamicState                                         // const VkDynamicState* pDynamicStates;
1774     };
1775 
1776     m_shaderModules[0] = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0);
1777     m_shaderModules[1] = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0);
1778 
1779     m_pipelines.reserve(2);
1780 
1781     // Create first pipeline
1782     m_pipelines.emplace_back(vki, vk, physicalDevice, vkDevice, m_context.getDeviceExtensions(),
1783                              m_param.pipelineConstructionType);
1784     m_pipelines.back()
1785         .setDynamicState(&dynamicStateParams)
1786         .setDefaultRasterizationState()
1787         .setupVertexInputState()
1788         .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, m_renderPasses[0].get(), 0u,
1789                                           m_shaderModules[0])
1790         .setupFragmentShaderState(m_pipelineLayout, m_renderPasses[0].get(), 0u, m_shaderModules[1],
1791                                   &depthStencilStateParams, &multisampleStateParams)
1792         .setupFragmentOutputState(m_renderPasses[0].get(), 0u, &colorBlendStateParams[0], &multisampleStateParams)
1793         .setMonolithicPipelineLayout(m_pipelineLayout)
1794         .buildPipeline();
1795 
1796     // Create second pipeline
1797     m_pipelines.emplace_back(vki, vk, physicalDevice, vkDevice, m_context.getDeviceExtensions(),
1798                              m_param.pipelineConstructionType);
1799     m_pipelines.back()
1800         .setDynamicState(&dynamicStateParams)
1801         .setDefaultRasterizationState()
1802         .setupVertexInputState()
1803         .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, m_renderPasses[1].get(), 0u,
1804                                           m_shaderModules[0])
1805         .setupFragmentShaderState(m_pipelineLayout, m_renderPasses[1].get(), 0u, m_shaderModules[1],
1806                                   &depthStencilStateParams, &multisampleStateParams)
1807         .setupFragmentOutputState(m_renderPasses[1].get(), 0u, &colorBlendStateParams[1], &multisampleStateParams)
1808         .setMonolithicPipelineLayout(m_pipelineLayout)
1809         .buildPipeline();
1810 }
1811 
prepareRenderPass(GraphicsPipelineWrapper & pipeline,RenderPassWrapper & renderpass,bool secondDraw)1812 void BlendOperationAdvancedTestCoherentInstance::prepareRenderPass(GraphicsPipelineWrapper &pipeline,
1813                                                                    RenderPassWrapper &renderpass, bool secondDraw)
1814 {
1815     const DeviceInterface &vk = m_context.getDeviceInterface();
1816 
1817     VkClearValue attachmentClearValue = makeClearValueColor(clearColorVec4);
1818 
1819     renderpass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), (secondDraw ? 0u : 1u),
1820                      (secondDraw ? DE_NULL : &attachmentClearValue));
1821 
1822     pipeline.bind(*m_cmdBuffer);
1823     VkDeviceSize offsets = 0u;
1824     vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &offsets);
1825 
1826     // There are two different renderpasses, each of them draw
1827     // one half of the colors.
1828     uint32_t skippedColors = 0u;
1829     for (uint32_t color = 0; color < DE_LENGTH_OF_ARRAY(srcColors) / 2; color++)
1830     {
1831         // Skip ill-formed colors when we have non-premultiplied destination colors.
1832         if (m_param.premultipliedDstColor == VK_FALSE)
1833         {
1834             bool skipColor = false;
1835             for (uint32_t i = 0; i < m_param.colorAttachmentsCount; i++)
1836             {
1837                 Vec4 calculatedColor =
1838                     calculateFinalColor(m_param, m_param.blendOps[i], srcColors[color], dstColors[color]);
1839                 if (calculatedColor.w() <= 0.0f && calculatedColor != Vec4(0.0f))
1840                 {
1841                     // Skip ill-formed colors, because the spec says the result is undefined.
1842                     skippedColors++;
1843                     skipColor = true;
1844                     break;
1845                 }
1846             }
1847             if (skipColor)
1848                 continue;
1849         }
1850         int32_t x = 0;
1851         int32_t y = 0;
1852         getCoordinates(color, x, y);
1853 
1854         uint32_t index = secondDraw ? (color + DE_LENGTH_OF_ARRAY(srcColors) / 2) : color;
1855 
1856         // Set source color as push constant
1857         vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(Vec4),
1858                             &srcColors[index]);
1859         VkRect2D scissor = makeRect2D(x, y, 1u, 1u);
1860         if (vk::isConstructionTypeShaderObject(m_param.pipelineConstructionType))
1861         {
1862 #ifndef CTS_USES_VULKANSC
1863             vk.cmdSetScissorWithCount(*m_cmdBuffer, 1u, &scissor);
1864 #else
1865             vk.cmdSetScissorWithCountEXT(*m_cmdBuffer, 1u, &scissor);
1866 #endif
1867         }
1868         else
1869         {
1870             vk.cmdSetScissor(*m_cmdBuffer, 0u, 1u, &scissor);
1871         }
1872 
1873         // To set destination color, we do clear attachment restricting the area to the respective pixel of each color attachment.
1874         // Only clear in the first draw, for the second draw the destination color is the result of the first draw's blend.
1875         if (secondDraw == false)
1876         {
1877             std::vector<VkClearAttachment> attachments;
1878             VkClearValue clearValue = vk::makeClearValueColorVec4(dstColors[index]);
1879 
1880             const VkClearAttachment attachment = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, clearValue};
1881 
1882             const VkClearRect rect = {scissor, 0u, 1u};
1883             vk.cmdClearAttachments(*m_cmdBuffer, 1u, &attachment, 1u, &rect);
1884         }
1885 
1886         // Draw
1887         vk.cmdDraw(*m_cmdBuffer, (uint32_t)m_vertices.size(), 1u, 0u, 0u);
1888     }
1889 
1890     // If we break this assert, then we are not testing anything in this test.
1891     DE_ASSERT(skippedColors < (DE_LENGTH_OF_ARRAY(srcColors) / 2));
1892 
1893     // Log number of skipped colors
1894     if (skippedColors != 0u)
1895     {
1896         tcu::TestLog &log = m_context.getTestContext().getLog();
1897         log << tcu::TestLog::Message << "Skipped " << skippedColors << " out of " << (DE_LENGTH_OF_ARRAY(srcColors) / 2)
1898             << " color cases due to ill-formed colors" << tcu::TestLog::EndMessage;
1899     }
1900     renderpass.end(vk, *m_cmdBuffer);
1901 }
1902 
prepareCommandBuffer()1903 void BlendOperationAdvancedTestCoherentInstance::prepareCommandBuffer()
1904 {
1905     const DeviceInterface &vk = m_context.getDeviceInterface();
1906 
1907     beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1908 
1909     vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1910                           VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
1911                           (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, (uint32_t)m_imageLayoutBarriers.size(),
1912                           m_imageLayoutBarriers.data());
1913 
1914     prepareRenderPass(m_pipelines[0], m_renderPasses[0], false);
1915 
1916     if (m_param.coherentOperations == false)
1917     {
1918         const VkImageMemoryBarrier colorImageBarrier = {
1919             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1920             DE_NULL,                                // const void* pNext;
1921             (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
1922              VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags srcAccessMask;
1923             (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
1924              VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags dstAccessMask;
1925             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,              // VkImageLayout oldLayout;
1926             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,              // VkImageLayout newLayout;
1927             VK_QUEUE_FAMILY_IGNORED,                               // uint32_t srcQueueFamilyIndex;
1928             VK_QUEUE_FAMILY_IGNORED,                               // uint32_t dstQueueFamilyIndex;
1929             *m_colorImage,                                         // VkImage image;
1930             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u},           // VkImageSubresourceRange subresourceRange;
1931         };
1932         vk.cmdPipelineBarrier(*m_cmdBuffer,
1933                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
1934                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
1935                               (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &colorImageBarrier);
1936     }
1937 
1938     prepareRenderPass(m_pipelines[1], m_renderPasses[1], true);
1939 
1940     endCommandBuffer(vk, *m_cmdBuffer);
1941 }
1942 
BlendOperationAdvancedTestCoherentInstance(Context & context,const BlendOperationAdvancedParam param)1943 BlendOperationAdvancedTestCoherentInstance::BlendOperationAdvancedTestCoherentInstance(
1944     Context &context, const BlendOperationAdvancedParam param)
1945     : TestInstance(context)
1946     , m_param(param)
1947     , m_renderSize(tcu::UVec2(widthArea, heightArea))
1948     , m_colorFormat(param.format)
1949     , m_shaderStageCount(0)
1950 {
1951     const DeviceInterface &vk       = m_context.getDeviceInterface();
1952     const VkDevice vkDevice         = m_context.getDevice();
1953     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1954 
1955     // Create vertex buffer
1956     {
1957         m_vertices = createPoints();
1958         DE_ASSERT((uint32_t)m_vertices.size() == 6);
1959 
1960         m_vertexBuffer = createBufferAndBindMemory(m_context, m_vertices.size() * sizeof(Vec4),
1961                                                    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &m_vertexBufferMemory);
1962         // Load vertices into vertex buffer
1963         deMemcpy(m_vertexBufferMemory->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vec4));
1964         flushAlloc(vk, vkDevice, *m_vertexBufferMemory);
1965     }
1966 
1967     // Create render passes
1968     m_renderPasses.emplace_back(makeTestRenderPass(param, vk, vkDevice, m_colorFormat, VK_ATTACHMENT_LOAD_OP_CLEAR));
1969     m_renderPasses.emplace_back(makeTestRenderPass(param, vk, vkDevice, m_colorFormat, VK_ATTACHMENT_LOAD_OP_LOAD));
1970 
1971     const VkComponentMapping componentMappingRGBA = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1972                                                      VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
1973 
1974     // Create color image
1975     m_colorImage = createImage2DAndBindMemory(m_context, m_colorFormat, m_renderSize.x(), m_renderSize.y(),
1976                                               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
1977                                               VK_SAMPLE_COUNT_1_BIT, &m_colorImageAlloc);
1978     // Set up image layout transition barriers
1979     {
1980         VkImageMemoryBarrier colorImageBarrier = {
1981             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1982             DE_NULL,                                // const void* pNext;
1983             0u,                                     // VkAccessFlags srcAccessMask;
1984             (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
1985              VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT), // VkAccessFlags dstAccessMask;
1986             VK_IMAGE_LAYOUT_UNDEFINED,                             // VkImageLayout oldLayout;
1987             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,              // VkImageLayout newLayout;
1988             VK_QUEUE_FAMILY_IGNORED,                               // uint32_t srcQueueFamilyIndex;
1989             VK_QUEUE_FAMILY_IGNORED,                               // uint32_t dstQueueFamilyIndex;
1990             *m_colorImage,                                         // VkImage image;
1991             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u},           // VkImageSubresourceRange subresourceRange;
1992         };
1993 
1994         m_imageLayoutBarriers.emplace_back(colorImageBarrier);
1995     }
1996 
1997     // Create color attachment view
1998     {
1999         VkImageViewCreateInfo colorAttachmentViewParams = {
2000             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,    // VkStructureType sType;
2001             DE_NULL,                                     // const void* pNext;
2002             0u,                                          // VkImageViewCreateFlags flags;
2003             *m_colorImage,                               // VkImage image;
2004             VK_IMAGE_VIEW_TYPE_2D,                       // VkImageViewType viewType;
2005             m_colorFormat,                               // VkFormat format;
2006             componentMappingRGBA,                        // VkComponentMapping components;
2007             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
2008         };
2009 
2010         m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
2011     }
2012 
2013     // Create framebuffers
2014     {
2015         VkFramebufferCreateInfo framebufferParams = {
2016             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
2017             DE_NULL,                                   // const void* pNext;
2018             0u,                                        // VkFramebufferCreateFlags flags;
2019             m_renderPasses[0].get(),                   // VkRenderPass renderPass;
2020             1u,                                        // uint32_t attachmentCount;
2021             &m_colorAttachmentView.get(),              // const VkImageView* pAttachments;
2022             (uint32_t)m_renderSize.x(),                // uint32_t width;
2023             (uint32_t)m_renderSize.y(),                // uint32_t height;
2024             1u,                                        // uint32_t layers;
2025         };
2026 
2027         m_renderPasses[0].createFramebuffer(vk, vkDevice, &framebufferParams, *m_colorImage);
2028         framebufferParams.renderPass = m_renderPasses[1].get();
2029         m_renderPasses[1].createFramebuffer(vk, vkDevice, &framebufferParams, *m_colorImage);
2030     }
2031 
2032     // Create pipeline layout
2033     {
2034         const VkPushConstantRange pushConstantRange = {
2035             VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags    stageFlags
2036             0,                            // uint32_t                offset
2037             sizeof(Vec4)                  // uint32_t                size
2038         };
2039 
2040         const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
2041             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
2042             DE_NULL,                                       // const void* pNext;
2043             0u,                                            // VkPipelineLayoutCreateFlags flags;
2044             0u,                                            // uint32_t setLayoutCount;
2045             DE_NULL,                                       // const VkDescriptorSetLayout* pSetLayouts;
2046             1u,                                            // uint32_t pushConstantRangeCount;
2047             &pushConstantRange                             // const VkPushConstantRange* pPushConstantRanges;
2048         };
2049 
2050         m_pipelineLayout = PipelineLayoutWrapper(m_param.pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
2051     }
2052 
2053     // Create pipeline
2054     buildPipeline();
2055 
2056     // Create command pool
2057     m_cmdPool = createCommandPool(
2058         vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
2059         queueFamilyIndex);
2060 
2061     // Create command buffer
2062     m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2063 }
2064 
iterate(void)2065 tcu::TestStatus BlendOperationAdvancedTestCoherentInstance::iterate(void)
2066 {
2067     const DeviceInterface &vk = m_context.getDeviceInterface();
2068     const VkDevice vkDevice   = m_context.getDevice();
2069     const VkQueue queue       = m_context.getUniversalQueue();
2070     tcu::TestLog &log         = m_context.getTestContext().getLog();
2071 
2072     // Log the blend operations to test
2073     {
2074         DE_ASSERT(m_param.blendOps.size() == 2u);
2075         log << tcu::TestLog::Message
2076             << "First depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[0]).toString().substr(3))
2077             << tcu::TestLog::EndMessage;
2078         log << tcu::TestLog::Message
2079             << "Second depth op: " << de::toLower(getBlendOpStr(m_param.blendOps[1]).toString().substr(3))
2080             << tcu::TestLog::EndMessage;
2081     }
2082 
2083     prepareCommandBuffer();
2084 
2085     submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
2086     return verifyTestResult();
2087 }
2088 
verifyTestResult(void)2089 tcu::TestStatus BlendOperationAdvancedTestCoherentInstance::verifyTestResult(void)
2090 {
2091     bool compareOk                  = true;
2092     const DeviceInterface &vk       = m_context.getDeviceInterface();
2093     const VkDevice vkDevice         = m_context.getDevice();
2094     const VkQueue queue             = m_context.getUniversalQueue();
2095     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
2096     Allocator &allocator            = m_context.getDefaultAllocator();
2097     tcu::TextureLevel refImage(vk::mapVkFormat(m_colorFormat), 32, 32);
2098 
2099     tcu::clear(refImage.getAccess(), clearColorVec4);
2100 
2101     // Generate reference image
2102     for (uint32_t color = 0; color < DE_LENGTH_OF_ARRAY(srcColors) / 2; color++)
2103     {
2104         uint32_t secondDrawColorIndex = color + DE_LENGTH_OF_ARRAY(srcColors) / 2;
2105         // Calculate first draw final color
2106         Vec4 rectColorTmp = calculateFinalColor(m_param, m_param.blendOps[0], srcColors[color], dstColors[color]);
2107 
2108         if (m_param.premultipliedDstColor == VK_FALSE)
2109         {
2110             if (rectColorTmp.w() > 0.0f)
2111             {
2112                 rectColorTmp.x() = rectColorTmp.x() / rectColorTmp.w();
2113                 rectColorTmp.y() = rectColorTmp.y() / rectColorTmp.w();
2114                 rectColorTmp.z() = rectColorTmp.z() / rectColorTmp.w();
2115             }
2116             else
2117             {
2118                 // Skip the color check if it is ill-formed.
2119                 if (rectColorTmp != Vec4(0.0f))
2120                     continue;
2121             }
2122         }
2123         // Calculate second draw final color
2124         Vec4 rectColor =
2125             calculateFinalColor(m_param, m_param.blendOps[1], srcColors[secondDrawColorIndex], rectColorTmp);
2126         if (m_param.premultipliedDstColor == VK_FALSE)
2127         {
2128             if (rectColor.w() > 0.0f)
2129             {
2130                 rectColor.x() = rectColor.x() / rectColor.w();
2131                 rectColor.y() = rectColor.y() / rectColor.w();
2132                 rectColor.z() = rectColor.z() / rectColor.w();
2133             }
2134             else
2135             {
2136                 // Skip the color check if it is ill-formed.
2137                 if (rectColor != Vec4(0.0f))
2138                     continue;
2139             }
2140         }
2141 
2142         int32_t x = 0;
2143         int32_t y = 0;
2144         getCoordinates(color, x, y);
2145         tcu::clear(tcu::getSubregion(refImage.getAccess(), x, y, 1u, 1u), rectColor);
2146     }
2147 
2148     de::MovePtr<tcu::TextureLevel> result = vkt::pipeline::readColorAttachment(
2149         vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize);
2150     std::ostringstream name;
2151     name << "Image comparison. Depth ops: " << de::toLower(getBlendOpStr(m_param.blendOps[0]).toString().substr(3))
2152          << " and " << de::toLower(getBlendOpStr(m_param.blendOps[1]).toString().substr(3));
2153 
2154     // R8G8B8A8 threshold was derived experimentally.
2155     compareOk = tcu::floatThresholdCompare(
2156         m_context.getTestContext().getLog(), "FloatImageCompare", name.str().c_str(), refImage.getAccess(),
2157         result->getAccess(), clearColorVec4,
2158         m_colorFormat == VK_FORMAT_R8G8B8A8_UNORM ? Vec4(0.13f, 0.13f, 0.13f, 0.13f) : Vec4(0.01f, 0.01f, 0.01f, 0.01f),
2159         tcu::COMPARE_LOG_RESULT);
2160     if (!compareOk)
2161         return tcu::TestStatus::fail("Image mismatch");
2162 
2163     return tcu::TestStatus::pass("Result images matches references");
2164 }
2165 
createInstance(Context & context) const2166 TestInstance *BlendOperationAdvancedTest::createInstance(Context &context) const
2167 {
2168     if (m_param.testMode == TEST_MODE_GENERIC)
2169         return new BlendOperationAdvancedTestInstance(context, m_param);
2170     else
2171         return new BlendOperationAdvancedTestCoherentInstance(context, m_param);
2172 }
2173 
2174 } // namespace
2175 
createBlendOperationAdvancedTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)2176 tcu::TestCaseGroup *createBlendOperationAdvancedTests(tcu::TestContext &testCtx,
2177                                                       PipelineConstructionType pipelineConstructionType)
2178 {
2179     enum nonpremultiplyEnum
2180     {
2181         PREMULTIPLY_SRC = 1u,
2182         PREMULTIPLY_DST = 2u
2183     };
2184     uint32_t premultiplyModes[]      = {0u, PREMULTIPLY_SRC, PREMULTIPLY_DST, PREMULTIPLY_SRC | PREMULTIPLY_DST};
2185     uint32_t colorAttachmentCounts[] = {1u, 2u, 4u, 8u, 16u};
2186     bool coherentOps[]               = {false, true};
2187     VkBlendOp blendOps[]             = {
2188         VK_BLEND_OP_ZERO_EXT,
2189         VK_BLEND_OP_SRC_EXT,
2190         VK_BLEND_OP_DST_EXT,
2191         VK_BLEND_OP_SRC_OVER_EXT,
2192         VK_BLEND_OP_DST_OVER_EXT,
2193         VK_BLEND_OP_SRC_IN_EXT,
2194         VK_BLEND_OP_DST_IN_EXT,
2195         VK_BLEND_OP_SRC_OUT_EXT,
2196         VK_BLEND_OP_DST_OUT_EXT,
2197         VK_BLEND_OP_SRC_ATOP_EXT,
2198         VK_BLEND_OP_DST_ATOP_EXT,
2199         VK_BLEND_OP_XOR_EXT,
2200         VK_BLEND_OP_MULTIPLY_EXT,
2201         VK_BLEND_OP_SCREEN_EXT,
2202         VK_BLEND_OP_OVERLAY_EXT,
2203         VK_BLEND_OP_DARKEN_EXT,
2204         VK_BLEND_OP_LIGHTEN_EXT,
2205         VK_BLEND_OP_COLORDODGE_EXT,
2206         VK_BLEND_OP_COLORBURN_EXT,
2207         VK_BLEND_OP_HARDLIGHT_EXT,
2208         VK_BLEND_OP_SOFTLIGHT_EXT,
2209         VK_BLEND_OP_DIFFERENCE_EXT,
2210         VK_BLEND_OP_EXCLUSION_EXT,
2211         VK_BLEND_OP_INVERT_EXT,
2212         VK_BLEND_OP_INVERT_RGB_EXT,
2213         VK_BLEND_OP_LINEARDODGE_EXT,
2214         VK_BLEND_OP_LINEARBURN_EXT,
2215         VK_BLEND_OP_VIVIDLIGHT_EXT,
2216         VK_BLEND_OP_LINEARLIGHT_EXT,
2217         VK_BLEND_OP_PINLIGHT_EXT,
2218         VK_BLEND_OP_HARDMIX_EXT,
2219         VK_BLEND_OP_HSL_HUE_EXT,
2220         VK_BLEND_OP_HSL_SATURATION_EXT,
2221         VK_BLEND_OP_HSL_COLOR_EXT,
2222         VK_BLEND_OP_HSL_LUMINOSITY_EXT,
2223         VK_BLEND_OP_PLUS_EXT,
2224         VK_BLEND_OP_PLUS_CLAMPED_EXT,
2225         VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT,
2226         VK_BLEND_OP_PLUS_DARKER_EXT,
2227         VK_BLEND_OP_MINUS_EXT,
2228         VK_BLEND_OP_MINUS_CLAMPED_EXT,
2229         VK_BLEND_OP_CONTRAST_EXT,
2230         VK_BLEND_OP_INVERT_OVG_EXT,
2231         VK_BLEND_OP_RED_EXT,
2232         VK_BLEND_OP_GREEN_EXT,
2233         VK_BLEND_OP_BLUE_EXT,
2234     };
2235 
2236     // VK_EXT_blend_operation_advanced tests
2237     de::MovePtr<tcu::TestCaseGroup> tests(new tcu::TestCaseGroup(testCtx, "blend_operation_advanced"));
2238     de::Random rnd(deStringHash(tests->getName()));
2239 
2240     // Test each blend operation advance op
2241     de::MovePtr<tcu::TestCaseGroup> opsTests(new tcu::TestCaseGroup(testCtx, "ops"));
2242 
2243     for (uint32_t colorAttachmentCount = 0u; colorAttachmentCount < DE_LENGTH_OF_ARRAY(colorAttachmentCounts);
2244          colorAttachmentCount++)
2245     {
2246         for (uint32_t overlap = 0; overlap <= VK_BLEND_OVERLAP_CONJOINT_EXT; overlap++)
2247         {
2248             for (uint32_t premultiply = 0u; premultiply < DE_LENGTH_OF_ARRAY(premultiplyModes); premultiply++)
2249             {
2250                 uint32_t testNumber = 0u;
2251                 for (uint64_t blendOp = 0u; blendOp < DE_LENGTH_OF_ARRAY(blendOps); blendOp++)
2252                 {
2253                     bool isAdditionalRGBBlendOp =
2254                         blendOps[blendOp] >= VK_BLEND_OP_PLUS_EXT && blendOps[blendOp] < VK_BLEND_OP_MAX_ENUM;
2255 
2256                     // Additional RGB Blend operations are not affected by the blend overlap modes
2257                     if (isAdditionalRGBBlendOp && overlap != VK_BLEND_OVERLAP_UNCORRELATED_EXT)
2258                         continue;
2259 
2260                     BlendOperationAdvancedParam testParams;
2261                     testParams.pipelineConstructionType = pipelineConstructionType;
2262                     testParams.testMode                 = TEST_MODE_GENERIC;
2263                     testParams.overlap                  = (VkBlendOverlapEXT)overlap;
2264                     testParams.coherentOperations       = false;
2265                     testParams.colorAttachmentsCount    = colorAttachmentCounts[colorAttachmentCount];
2266                     testParams.independentBlend         = false;
2267                     testParams.premultipliedSrcColor =
2268                         (premultiplyModes[premultiply] & PREMULTIPLY_SRC) ? VK_TRUE : VK_FALSE;
2269                     testParams.premultipliedDstColor =
2270                         (premultiplyModes[premultiply] & PREMULTIPLY_DST) ? VK_TRUE : VK_FALSE;
2271                     testParams.testNumber = testNumber++;
2272                     testParams.format     = VK_FORMAT_R16G16B16A16_SFLOAT;
2273 
2274                     for (uint32_t numColorAtt = 0; numColorAtt < colorAttachmentCounts[colorAttachmentCount];
2275                          numColorAtt++)
2276                         testParams.blendOps.push_back(blendOps[blendOp]);
2277                     opsTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams));
2278 
2279                     testParams.format = VK_FORMAT_R8G8B8A8_UNORM;
2280                     opsTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams));
2281                 }
2282             }
2283         }
2284     }
2285     tests->addChild(opsTests.release());
2286 
2287     // Independent Blend Tests: test more than one color attachment.
2288     de::MovePtr<tcu::TestCaseGroup> independentTests(new tcu::TestCaseGroup(testCtx, "independent"));
2289     uint32_t testNumber = 0u;
2290 
2291     for (uint32_t colorAttachmentCount = 1u; colorAttachmentCount < DE_LENGTH_OF_ARRAY(colorAttachmentCounts);
2292          colorAttachmentCount++)
2293     {
2294         BlendOperationAdvancedParam testParams;
2295         testParams.pipelineConstructionType = pipelineConstructionType;
2296         testParams.testMode                 = TEST_MODE_GENERIC;
2297         testParams.overlap                  = VK_BLEND_OVERLAP_UNCORRELATED_EXT;
2298         testParams.coherentOperations       = false;
2299         testParams.colorAttachmentsCount    = colorAttachmentCounts[colorAttachmentCount];
2300         testParams.independentBlend         = true;
2301         testParams.premultipliedSrcColor    = VK_TRUE;
2302         testParams.premultipliedDstColor    = VK_TRUE;
2303         testParams.testNumber               = testNumber++;
2304         testParams.format                   = VK_FORMAT_R16G16B16A16_SFLOAT;
2305 
2306         for (uint32_t numColorAtt = 0; numColorAtt < colorAttachmentCounts[colorAttachmentCount]; numColorAtt++)
2307         {
2308             uint32_t i = de::randomScalar<uint32_t>(rnd, 0, DE_LENGTH_OF_ARRAY(blendOps) - 1);
2309             testParams.blendOps.push_back(blendOps[i]);
2310         }
2311         independentTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams));
2312 
2313         testParams.format = VK_FORMAT_R8G8B8A8_UNORM;
2314         independentTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams));
2315     }
2316 
2317     tests->addChild(independentTests.release());
2318 
2319     // Coherent tests, do two consecutive advanced blending operations on the same color attachment.
2320     de::MovePtr<tcu::TestCaseGroup> coherentTests(new tcu::TestCaseGroup(testCtx, "coherent"));
2321     testNumber = 0u;
2322 
2323     for (uint32_t coherent = 0u; coherent < DE_LENGTH_OF_ARRAY(coherentOps); coherent++)
2324     {
2325         BlendOperationAdvancedParam testParams;
2326         testParams.pipelineConstructionType = pipelineConstructionType;
2327         testParams.testMode                 = TEST_MODE_COHERENT;
2328         testParams.overlap                  = VK_BLEND_OVERLAP_UNCORRELATED_EXT;
2329         testParams.coherentOperations       = coherentOps[coherent];
2330         testParams.colorAttachmentsCount    = 1u;
2331         testParams.independentBlend         = false;
2332         testParams.premultipliedSrcColor    = VK_TRUE;
2333         testParams.premultipliedDstColor    = VK_TRUE;
2334         testParams.testNumber               = testNumber++;
2335         testParams.format                   = VK_FORMAT_R16G16B16A16_SFLOAT;
2336 
2337         // We do two consecutive advanced blending operations
2338         uint32_t i = de::randomScalar<uint32_t>(rnd, 0, DE_LENGTH_OF_ARRAY(blendOps) - 1);
2339         testParams.blendOps.push_back(blendOps[i]);
2340         i = de::randomScalar<uint32_t>(rnd, 0, DE_LENGTH_OF_ARRAY(blendOps) - 1);
2341         testParams.blendOps.push_back(blendOps[i]);
2342 
2343         coherentTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams));
2344 
2345         testParams.format = VK_FORMAT_R8G8B8A8_UNORM;
2346         coherentTests->addChild(newTestCase<BlendOperationAdvancedTest>(testCtx, testParams));
2347     }
2348     tests->addChild(coherentTests.release());
2349 
2350     return tests.release();
2351 }
2352 
2353 } // namespace pipeline
2354 
2355 } // namespace vkt
2356