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