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