• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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