• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 Valve Corporation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Border color swizzle tests
23  *//*--------------------------------------------------------------------*/
24 #include "vktPipelineSamplerBorderSwizzleTests.hpp"
25 #include "vktPipelineImageUtil.hpp"
26 
27 #include "vkImageUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkImageWithMemory.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 
36 #include "tcuMaybe.hpp"
37 #include "tcuTextureUtil.hpp"
38 #include "tcuVectorUtil.hpp"
39 #include "tcuFloat.hpp"
40 
41 #include "deRandom.hpp"
42 
43 #include <string>
44 #include <sstream>
45 #include <array>
46 #include <cstring>
47 #include <algorithm>
48 
49 namespace vkt
50 {
51 namespace pipeline
52 {
53 
54 namespace
55 {
56 
57 using namespace vk;
58 
59 // Returns true if the mapping doesn't alter each component.
isIdentitySwizzle(const VkComponentMapping & mapping)60 bool isIdentitySwizzle (const VkComponentMapping& mapping)
61 {
62 	return (
63 		(mapping.r == VK_COMPONENT_SWIZZLE_R || mapping.r == VK_COMPONENT_SWIZZLE_IDENTITY) &&
64 		(mapping.g == VK_COMPONENT_SWIZZLE_G || mapping.g == VK_COMPONENT_SWIZZLE_IDENTITY) &&
65 		(mapping.b == VK_COMPONENT_SWIZZLE_B || mapping.b == VK_COMPONENT_SWIZZLE_IDENTITY) &&
66 		(mapping.a == VK_COMPONENT_SWIZZLE_A || mapping.a == VK_COMPONENT_SWIZZLE_IDENTITY)
67 	);
68 }
69 
70 struct TestParams
71 {
72 	VkFormat						textureFormat;
73 	VkClearColorValue				textureColor;
74 	VkComponentMapping				componentMapping;
75 	VkBorderColor					borderColor;
76 	tcu::Maybe<int>					componentGather;
77 	bool							useSamplerSwizzleHint;
78 
79 	// Pseudorandom elements.
80 	tcu::Vec2						textureCoordinates;
81 	tcu::Maybe<VkClearColorValue>	customBorderColor;
82 
isCustomvkt::pipeline::__anon698e512d0111::TestParams83 	bool isCustom (void) const
84 	{
85 		return (borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT || borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT);
86 	}
87 
isOpaqueBlackvkt::pipeline::__anon698e512d0111::TestParams88 	bool isOpaqueBlack (void) const
89 	{
90 		return (borderColor == VK_BORDER_COLOR_INT_OPAQUE_BLACK || borderColor == VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK);
91 	}
92 
isIdentityvkt::pipeline::__anon698e512d0111::TestParams93 	bool isIdentity (void) const
94 	{
95 		return isIdentitySwizzle(componentMapping);
96 	}
97 };
98 
99 struct SpecConstants
100 {
101 	float	u;
102 	float	v;
103 	deInt32	gatherFlag;
104 	//deInt32	gatherComp;
105 };
106 
107 class BorderSwizzleCase : public vkt::TestCase
108 {
109 public:
110 							BorderSwizzleCase		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~BorderSwizzleCase(void)111 	virtual					~BorderSwizzleCase		(void) {}
112 
113 	virtual void			initPrograms			(vk::SourceCollections& programCollection) const;
114 	virtual TestInstance*	createInstance			(Context& context) const;
115 	virtual void			checkSupport			(Context& context) const;
116 
117 protected:
118 	TestParams				m_params;
119 };
120 
121 class BorderSwizzleInstance : public vkt::TestInstance
122 {
123 public:
124 								BorderSwizzleInstance	(Context& context, const TestParams &params);
~BorderSwizzleInstance(void)125 	virtual						~BorderSwizzleInstance	(void) {}
126 
127 	VkExtent3D					getImageExtent			(void) const;
128 	virtual tcu::TestStatus		iterate					(void);
129 
130 protected:
131 	TestParams				m_params;
132 };
133 
BorderSwizzleCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)134 BorderSwizzleCase::BorderSwizzleCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
135 	: vkt::TestCase	(testCtx, name, description)
136 	, m_params		(params)
137 {
138 }
139 
checkSupport(Context & context) const140 void BorderSwizzleCase::checkSupport (Context& context) const
141 {
142 	const auto&				vki					= context.getInstanceInterface();
143 	const auto				physicalDevice		= context.getPhysicalDevice();
144 	VkImageFormatProperties	formatProperties;
145 
146 	const auto result = vki.getPhysicalDeviceImageFormatProperties(
147 		physicalDevice, m_params.textureFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), 0u, &formatProperties);
148 
149 	if (result != VK_SUCCESS)
150 	{
151 		if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
152 			TCU_THROW(NotSupportedError, "Format not supported for sampling");
153 		TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned " + de::toString(result));
154 	}
155 
156 	const auto&	borderColorFeatures		= context.getCustomBorderColorFeaturesEXT();
157 	const auto&	borderSwizzleFeatures	= context.getBorderColorSwizzleFeaturesEXT();
158 	const bool	identity				= m_params.isIdentity();
159 
160 	if (m_params.useSamplerSwizzleHint)
161 		context.requireDeviceFunctionality("VK_EXT_border_color_swizzle");
162 
163 	if (m_params.isCustom())
164 	{
165 		if (!borderColorFeatures.customBorderColors)
166 			TCU_THROW(NotSupportedError, "Custom border colors not supported");
167 
168 		if (!identity)
169 		{
170 			if (!borderSwizzleFeatures.borderColorSwizzle)
171 				TCU_THROW(NotSupportedError, "Custom border color with non-identity swizzle not supported");
172 
173 			if (!m_params.useSamplerSwizzleHint && !borderSwizzleFeatures.borderColorSwizzleFromImage)
174 				TCU_THROW(NotSupportedError, "Custom border color with non-identity swizzle not supported without specifying sampler border mapping");
175 		}
176 	}
177 	else if (m_params.isOpaqueBlack())
178 	{
179 		if (!identity)
180 		{
181 			if (!borderSwizzleFeatures.borderColorSwizzle)
182 				TCU_THROW(NotSupportedError, "Opaque black with non-identity swizzle not supported");
183 
184 			if (!m_params.useSamplerSwizzleHint && !borderSwizzleFeatures.borderColorSwizzleFromImage)
185 				TCU_THROW(NotSupportedError, "Opaque black with non-identity swizzle not supported without specifying sampler border mapping");
186 		}
187 	}
188 }
189 
190 enum class FormatType
191 {
192 	SIGNED_INT = 0,
193 	UNSIGNED_INT,
194 	FLOAT,
195 };
196 
getFormatType(VkFormat format)197 FormatType getFormatType (VkFormat format)
198 {
199 	if (isIntFormat(format))
200 		return FormatType::SIGNED_INT;
201 
202 	if (isUintFormat(format))
203 		return FormatType::UNSIGNED_INT;
204 
205 	return FormatType::FLOAT;
206 }
207 
208 // Output color attachment format will vary slightly with the chosen texture format to accomodate different clear colors.
getColorAttachmentFormat(VkFormat textureFormat)209 VkFormat getColorAttachmentFormat (VkFormat textureFormat)
210 {
211 	const auto formatType = getFormatType(textureFormat);
212 
213 	if (formatType == FormatType::SIGNED_INT)
214 		return VK_FORMAT_R32G32B32A32_SINT;
215 
216 	if (formatType == FormatType::UNSIGNED_INT)
217 		return VK_FORMAT_R32G32B32A32_UINT;
218 
219 	return VK_FORMAT_R32G32B32A32_SFLOAT;
220 }
221 
initPrograms(vk::SourceCollections & programCollection) const222 void BorderSwizzleCase::initPrograms (vk::SourceCollections& programCollection) const
223 {
224 	std::ostringstream vert;
225 	vert
226 		<< "#version 450\n"
227 		<< "\n"
228 		<< "void main()\n"
229 		<< "{\n"
230 		// Full-screen clockwise triangle strip with 4 vertices.
231 		<< "	const float x = (-1.0+2.0*((gl_VertexIndex & 2)>>1));\n"
232 		<< "	const float y = ( 1.0-2.0* (gl_VertexIndex % 2));\n"
233 		<< "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
234 		<< "}\n"
235 		;
236 
237 	const auto formatType = getFormatType(m_params.textureFormat);
238 
239 	std::string	prefix;
240 	if (formatType == FormatType::SIGNED_INT)
241 		prefix = "i";
242 	else if (formatType == FormatType::UNSIGNED_INT)
243 		prefix = "u";
244 
245 	const std::string	samplerType		= prefix + "sampler2D";
246 	const std::string	outColorType	= prefix + "vec4";
247 	// Note: glslang will complain if the gather component is not a compile-time constant.
248 	const int			gatherComp		= (m_params.componentGather ? m_params.componentGather.get() : 0);
249 
250 	// Note the spec constants here should match the SpecConstants structure.
251 	std::ostringstream frag;
252 	frag
253 		<< "#version 450\n"
254 		<< "\n"
255 		<< "layout (constant_id=0) const float u = 0.0f;\n"
256 		<< "layout (constant_id=1) const float v = 0.0f;\n"
257 		<< "layout (constant_id=2) const int gatherFlag = 0;\n"
258 		//<< "layout (constant_id=3) const int gatherComp = 0;\n"
259 		<< "\n"
260 		<< "layout (set=0, binding=0) uniform " << samplerType << " texSampler;\n"
261 		<< "\n"
262 		<< "layout (location=0) out " << outColorType << " colorOut;\n"
263 		<< "\n"
264 		<< "void main()\n"
265 		<< "{\n"
266 		<< "	const vec2 coords = vec2(u, v);\n"
267 		<< "\n"
268 		<< "	if (gatherFlag != 0)\n"
269 		<< "	{\n"
270 		<< "		colorOut = textureGather(texSampler, coords, " << gatherComp << ");\n"
271 		<< "	}\n"
272 		<< "	else\n"
273 		<< "	{\n"
274 		<< "		colorOut = texture(texSampler, coords);\n"
275 		<< "	}\n"
276 		<< "}\n"
277 		;
278 
279 	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
280 	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
281 }
282 
createInstance(Context & context) const283 TestInstance* BorderSwizzleCase::createInstance (Context& context) const
284 {
285 	return new BorderSwizzleInstance(context, m_params);
286 }
287 
BorderSwizzleInstance(Context & context,const TestParams & params)288 BorderSwizzleInstance::BorderSwizzleInstance (Context& context, const TestParams &params)
289 	: vkt::TestInstance	(context)
290 	, m_params			(params)
291 {}
292 
getImageExtent(void) const293 VkExtent3D BorderSwizzleInstance::getImageExtent (void) const
294 {
295 	return makeExtent3D(16u, 16u, 1u);
296 }
297 
298 // Reinterprets the exponent and mantissa in the floating point number as an integer.
299 // Function copied from vktApiImageClearingTests.cpp but changed return type to deUint64.
calcFloatDiff(float a,float b)300 deUint64 calcFloatDiff (float a, float b)
301 {
302 	const int		asign	= tcu::Float32(a).sign();
303 	const int		bsign	= tcu::Float32(a).sign();
304 
305 	const deUint32	avalue	= (tcu::Float32(a).bits() & ((0x1u << 31u) - 1u));
306 	const deUint32	bvalue	= (tcu::Float32(b).bits() & ((0x1u << 31u) - 1u));
307 
308 	if (asign != bsign)
309 		return avalue + bvalue + 1u;
310 	else if (avalue < bvalue)
311 		return bvalue - avalue;
312 	else
313 		return avalue - bvalue;
314 }
315 
316 // Convert VkComponentMapping to an array of 4 VkComponentSwizzle elements.
makeComponentSwizzleVec(const VkComponentMapping & mapping)317 tcu::Vector<VkComponentSwizzle, 4> makeComponentSwizzleVec(const VkComponentMapping& mapping)
318 {
319 	const tcu::Vector<VkComponentSwizzle, 4> result = {{ mapping.r, mapping.g, mapping.b, mapping.a }};
320 	return result;
321 }
322 
323 // Apply swizzling to an array of 4 elements.
324 template <typename T>
applySwizzle(const tcu::Vector<T,4> & orig,const VkComponentMapping & mapping)325 tcu::Vector<T, 4> applySwizzle (const tcu::Vector<T, 4>& orig, const VkComponentMapping& mapping)
326 {
327 	const auto			swizzles	= makeComponentSwizzleVec(mapping);
328 	tcu::Vector<T, 4>	result;
329 
330 	for (int i = 0; i < decltype(swizzles)::SIZE; ++i)
331 	{
332 		const auto cs = swizzles[i];
333 		DE_ASSERT(cs >= VK_COMPONENT_SWIZZLE_IDENTITY && cs <= VK_COMPONENT_SWIZZLE_A);
334 
335 		if (cs == VK_COMPONENT_SWIZZLE_IDENTITY)
336 			result[i] = orig[i];
337 		else if (cs == VK_COMPONENT_SWIZZLE_ZERO)
338 			result[i] = static_cast<T>(0);
339 		else if (cs == VK_COMPONENT_SWIZZLE_ONE)
340 			result[i] = static_cast<T>(1);
341 		else
342 			result[i] = orig[cs - VK_COMPONENT_SWIZZLE_R];
343 	}
344 
345 	return result;
346 }
347 
348 // Apply gathering to an array of 4 elements.
349 template <typename T>
applyGather(const tcu::Vector<T,4> & orig,int compNum)350 tcu::Vector<T, 4> applyGather (const tcu::Vector<T, 4>& orig, int compNum)
351 {
352 	tcu::Vector<T, 4> result;
353 
354 	for (int i = 0; i < decltype(result)::SIZE; ++i)
355 		result[i] = orig[compNum];
356 
357 	return result;
358 }
359 
360 // Transforms an input border color, once expanded, to the expected output color.
361 template <typename T>
getExpectedColor(const tcu::Vector<T,4> & color,const TestParams & params)362 tcu::Vector<T, 4> getExpectedColor (const tcu::Vector<T, 4>& color, const TestParams& params)
363 {
364 	tcu::Vector<T, 4> result = color;
365 
366 	result = applySwizzle(result, params.componentMapping);
367 
368 	if (params.componentGather)
369 		result = applyGather(result, *params.componentGather);
370 
371 	return result;
372 }
373 
374 // Transforms an input border color to the expected output color.
375 // Uses the proper union member depending on the test parameters and takes into account "Conversion to RGBA" from the spec.
getExpectedColor(const VkClearColorValue & color,const TestParams & params)376 VkClearColorValue getExpectedColor (const VkClearColorValue& color, const TestParams& params)
377 {
378 	const auto			numComp		= tcu::getNumUsedChannels(mapVkFormat(params.textureFormat).order);
379 	const auto			formatType	= getFormatType(params.textureFormat);
380 	VkClearColorValue	result;
381 
382 	DE_ASSERT(numComp >= 0 && numComp <= 4);
383 
384 	if (formatType == FormatType::UNSIGNED_INT)
385 	{
386 		tcu::UVec4 borderColor (0u, 0u, 0u, 0u);
387 
388 		for (int i = 0; i < numComp; ++i)
389 			borderColor[i] = color.uint32[i];
390 
391 		if (numComp < 4)
392 			borderColor[3] = 1u;
393 
394 		const auto expected = getExpectedColor(borderColor, params);
395 
396 		for (int i = 0; i < decltype(expected)::SIZE; ++i)
397 			result.uint32[i] = expected[i];
398 	}
399 	else if (formatType == FormatType::SIGNED_INT)
400 	{
401 		tcu::IVec4 borderColor (0, 0, 0, 0);
402 
403 		for (int i = 0; i < numComp; ++i)
404 			borderColor[i] = color.int32[i];
405 
406 		if (numComp < 4)
407 			borderColor[3] = 1;
408 
409 		const auto expected = getExpectedColor(borderColor, params);
410 
411 		for (int i = 0; i < decltype(expected)::SIZE; ++i)
412 			result.int32[i] = expected[i];
413 	}
414 	else
415 	{
416 		DE_ASSERT(formatType == FormatType::FLOAT);
417 
418 		tcu::Vec4 borderColor (.0f, .0f, .0f, .0f);
419 
420 		for (int i = 0; i < numComp; ++i)
421 			borderColor[i] = color.float32[i];
422 
423 		if (numComp < 4)
424 			borderColor[3] = 1.0f;
425 
426 		const auto expected = getExpectedColor(borderColor, params);
427 
428 		for (int i = 0; i < decltype(expected)::SIZE; ++i)
429 			result.float32[i] = expected[i];
430 	}
431 
432 	return result;
433 }
434 
435 // Compare color buffer to the expected border color.
436 //
437 // This method was copied from vktApiImageClearingTests.cpp and adapted to this use case:
438 //
439 // * Taking into account the texture format instead of the color buffer format when calculating acceptable thresholds.
440 // * Applying swizzles and gathering to said thresholds.
441 // * Making thresholds more strict for components that do not come from custom borders.
442 // * Checking the full image in a single pass.
443 //
444 // The color buffer format is supposed to be at least as precise as the texture format.
comparePixelToColorClearValue(const TestParams & params,const tcu::ConstPixelBufferAccess & access,const tcu::TextureFormat & textureFormat,const VkClearColorValue & ref,std::string & stringResult)445 bool comparePixelToColorClearValue (const TestParams&					params,
446 									const tcu::ConstPixelBufferAccess&	access,
447 									const tcu::TextureFormat&			textureFormat,
448 									const VkClearColorValue&			ref,
449 									std::string&						stringResult)
450 {
451 	const auto	bufferFormat	= access.getFormat();
452 	const auto	channelClass	= getTextureChannelClass(textureFormat.type);
453 	// We must compare all available channels in the color buffer to check RGBA conversion.
454 	const auto	channelMask		= getTextureFormatChannelMask(bufferFormat);
455 
456 	switch (channelClass)
457 	{
458 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
459 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
460 		{
461 			tcu::Vec4			refColor	(ref.float32[0],
462 											 ref.float32[1],
463 											 ref.float32[2],
464 											 ref.float32[3]);
465 			tcu::Vec4			threshold	(0.0f);
466 
467 			if (params.isCustom())
468 			{
469 				// Relax thresholds for custom color components.
470 				const tcu::IVec4	bitDepth	(getTextureFormatBitDepth(textureFormat));
471 				const int			modifier	= (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) ? 0 : 1;
472 
473 				threshold = tcu::Vec4 (bitDepth[0] > 0 ? 1.0f / ((float)(1 << (bitDepth[0] - modifier)) - 1.0f) : 0.0f,
474 									   bitDepth[1] > 0 ? 1.0f / ((float)(1 << (bitDepth[1] - modifier)) - 1.0f) : 0.0f,
475 									   bitDepth[2] > 0 ? 1.0f / ((float)(1 << (bitDepth[2] - modifier)) - 1.0f) : 0.0f,
476 									   bitDepth[3] > 0 ? 1.0f / ((float)(1 << (bitDepth[3] - modifier)) - 1.0f) : 0.0f);
477 
478 				if (isSRGB(textureFormat))
479 				{
480 					// Widen thresholds a bit due to possible low-precision sRGB conversions.
481 					for (int i = 0; i < decltype(threshold)::SIZE; ++i)
482 						threshold[i] *= 2.0f;
483 				}
484 			}
485 
486 			// Apply swizzle and gather to thresholds.
487 			threshold = applySwizzle(threshold, params.componentMapping);
488 
489 			if (params.componentGather)
490 				threshold = applyGather(threshold, *params.componentGather);
491 
492 			for (int z = 0; z < access.getDepth(); ++z)
493 			for (int y = 0; y < access.getHeight(); ++y)
494 			for (int x = 0; x < access.getWidth(); ++x)
495 			{
496 				const tcu::Vec4	resColor	(access.getPixel(x, y, z));
497 				const bool		result		= !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask));
498 
499 				if (!result || (x == 0 && y == 0 && z == 0))
500 				{
501 					std::stringstream s;
502 					s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor;
503 					stringResult = s.str();
504 				}
505 
506 				if (!result)
507 					return false;
508 			}
509 
510 			return true;
511 		}
512 
513 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
514 		{
515 			const tcu::UVec4	refColor	(ref.uint32[0],
516 											 ref.uint32[1],
517 											 ref.uint32[2],
518 											 ref.uint32[3]);
519 			tcu::UVec4			threshold	(0u);
520 
521 			if (params.isCustom())
522 			{
523 				// Relax thresholds for custom color components.
524 				const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat));
525 
526 				threshold = tcu::UVec4 ((bitDepth[0] > 0) ? 1 : 0,
527 										(bitDepth[1] > 0) ? 1 : 0,
528 										(bitDepth[2] > 0) ? 1 : 0,
529 										(bitDepth[3] > 0) ? 1 : 0);
530 			}
531 
532 			// Apply swizzle and gather to thresholds.
533 			threshold = applySwizzle(threshold, params.componentMapping);
534 
535 			if (params.componentGather)
536 				threshold = applyGather(threshold, *params.componentGather);
537 
538 			for (int z = 0; z < access.getDepth(); ++z)
539 			for (int y = 0; y < access.getHeight(); ++y)
540 			for (int x = 0; x < access.getWidth(); ++x)
541 			{
542 				const tcu::UVec4	resColor	(access.getPixelUint(x, y, z));
543 				const bool			result		= !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask));
544 
545 				if (!result || (x == 0 && y == 0 && z == 0))
546 				{
547 					std::stringstream s;
548 					s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor;
549 					stringResult = s.str();
550 				}
551 
552 				if (!result)
553 					return false;
554 			}
555 
556 			return true;
557 		}
558 
559 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
560 		{
561 			const tcu::IVec4	refColor	(ref.int32[0],
562 											 ref.int32[1],
563 											 ref.int32[2],
564 											 ref.int32[3]);
565 			tcu::IVec4			threshold	(0);
566 
567 			if (params.isCustom())
568 			{
569 				// Relax thresholds for custom color components.
570 				const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat));
571 
572 				threshold = tcu::IVec4 ((bitDepth[0] > 0) ? 1 : 0,
573 										(bitDepth[1] > 0) ? 1 : 0,
574 										(bitDepth[2] > 0) ? 1 : 0,
575 										(bitDepth[3] > 0) ? 1 : 0);
576 			}
577 
578 			// Apply swizzle and gather to thresholds.
579 			threshold = applySwizzle(threshold, params.componentMapping);
580 
581 			if (params.componentGather)
582 				threshold = applyGather(threshold, *params.componentGather);
583 
584 			for (int z = 0; z < access.getDepth(); ++z)
585 			for (int y = 0; y < access.getHeight(); ++y)
586 			for (int x = 0; x < access.getWidth(); ++x)
587 			{
588 				const tcu::IVec4	resColor	(access.getPixelInt(x, y, z));
589 				const bool			result		= !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask));
590 
591 				if (!result || (x == 0 && y == 0 && z == 0))
592 				{
593 					std::stringstream s;
594 					s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor;
595 					stringResult = s.str();
596 				}
597 
598 				if (!result)
599 					return false;
600 			}
601 
602 			return true;
603 		}
604 
605 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
606 		{
607 			using u64v4 = tcu::Vector<deUint64, 4>;
608 
609 			const tcu::Vec4		refColor		(ref.float32[0],
610 												 ref.float32[1],
611 												 ref.float32[2],
612 												 ref.float32[3]);
613 			u64v4				threshold		(0ull);
614 
615 			if (params.isCustom())
616 			{
617 				// Relax thresholds for custom color components.
618 				const tcu::IVec4	mantissaBitsI	(getTextureFormatMantissaBitDepth(textureFormat));
619 				const u64v4			mantissaBits	(mantissaBitsI.x(), mantissaBitsI.y(), mantissaBitsI.z(), mantissaBitsI.w());
620 
621 				threshold = u64v4 ((mantissaBits[0] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[0])) : 0ull,
622 								   (mantissaBits[1] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[1])) : 0ull,
623 								   (mantissaBits[2] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[2])) : 0ull,
624 								   (mantissaBits[3] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[3])) : 0ull);
625 			}
626 
627 			// Apply swizzle and gather to thresholds.
628 			threshold = applySwizzle(threshold, params.componentMapping);
629 
630 			if (params.componentGather)
631 				threshold = applyGather(threshold, *params.componentGather);
632 
633 			DE_ASSERT(allEqual(greaterThanEqual(threshold, u64v4(0u)), tcu::BVec4(true)));
634 
635 			for (int z = 0; z < access.getDepth(); ++z)
636 			for (int y = 0; y < access.getHeight(); ++y)
637 			for (int x = 0; x < access.getWidth(); ++x)
638 			{
639 				const tcu::Vec4	resColor (access.getPixel(x, y, z));
640 
641 				for (int ndx = 0; ndx < decltype(resColor)::SIZE; ndx++)
642 				{
643 					const bool result = !(calcFloatDiff(resColor[ndx], refColor[ndx]) > threshold[ndx] && channelMask[ndx]);
644 
645 					if (!result || (x == 0 && y == 0 && z == 0))
646 					{
647 						float				floatThreshold	= tcu::Float32((deUint32)(threshold)[0]).asFloat();
648 						tcu::Vec4			thresholdVec4	(floatThreshold,
649 															 floatThreshold,
650 															 floatThreshold,
651 															 floatThreshold);
652 						std::stringstream	s;
653 
654 						s << "Ref:" << refColor << " Threshold:" << thresholdVec4 << " Color:" << resColor;
655 						stringResult = s.str();
656 					}
657 
658 					if (!result)
659 						return false;
660 				}
661 			}
662 
663 			return true;
664 		}
665 
666 		default:
667 			DE_FATAL("Invalid channel class");
668 			return false;
669 	}
670 }
671 
672 // Gets the clear color value from the border color. See "Texel Replacement" in the spec.
getBorderClearColorValue(const TestParams & params)673 VkClearColorValue getBorderClearColorValue (const TestParams& params)
674 {
675 	VkClearColorValue result;
676 	deMemset(&result, 0, sizeof(result));
677 
678 	switch (params.borderColor)
679 	{
680 	case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:	/* memset works. */															break;
681 	case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:		/* memset works. */															break;
682 	case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:		result.float32[3] = 1.0f;													break;
683 	case VK_BORDER_COLOR_INT_OPAQUE_BLACK:			result.int32[3] = 1;														break;
684 	case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:		for (size_t i = 0; i < 4; ++i) result.float32[i] = 1.0f;					break;
685 	case VK_BORDER_COLOR_INT_OPAQUE_WHITE:			for (size_t i = 0; i < 4; ++i) result.int32[i] = 1;							break;
686 	case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:			// fallthrough.
687 	case VK_BORDER_COLOR_INT_CUSTOM_EXT:			DE_ASSERT(params.customBorderColor); result = *params.customBorderColor;	break;
688 	default:										DE_ASSERT(false);															break;
689 	}
690 
691 	return result;
692 }
693 
iterate(void)694 tcu::TestStatus BorderSwizzleInstance::iterate (void)
695 {
696 	const auto&	vkd						= m_context.getDeviceInterface();
697 	const auto	device					= m_context.getDevice();
698 	auto&		alloc					= m_context.getDefaultAllocator();
699 	const auto	queue					= m_context.getUniversalQueue();
700 	const auto	qIndex					= m_context.getUniversalQueueFamilyIndex();
701 	const auto	extent					= getImageExtent();
702 	const auto	custom					= m_params.isCustom();
703 	const auto	colorAttachmentFormat	= getColorAttachmentFormat(m_params.textureFormat);
704 	const auto	colorSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
705 
706 	// Texture.
707 	const VkImageCreateInfo textureCreateInfo =
708 	{
709 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
710 		nullptr,								//	const void*				pNext;
711 		0u,										//	VkImageCreateFlags		flags;
712 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
713 		m_params.textureFormat,					//	VkFormat				format;
714 		extent,									//	VkExtent3D				extent;
715 		1u,										//	deUint32				mipLevels;
716 		1u,										//	deUint32				arrayLayers;
717 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
718 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
719 		(VK_IMAGE_USAGE_SAMPLED_BIT				//	VkImageUsageFlags		usage;
720 		|VK_IMAGE_USAGE_TRANSFER_DST_BIT),
721 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
722 		0u,										//	deUint32				queueFamilyIndexCount;
723 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
724 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
725 	};
726 
727 	ImageWithMemory texture (vkd, device, alloc, textureCreateInfo, MemoryRequirement::Any);
728 
729 	const VkImageViewCreateInfo textureViewCreateInfo =
730 	{
731 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	//	VkStructureType			sType;
732 		nullptr,									//	const void*				pNext;
733 		0u,											//	VkImageViewCreateFlags	flags;
734 		texture.get(),								//	VkImage					image;
735 		VK_IMAGE_VIEW_TYPE_2D,						//	VkImageViewType			viewType;
736 		m_params.textureFormat,						//	VkFormat				format;
737 		m_params.componentMapping,					//	VkComponentMapping		components;
738 		colorSubresourceRange,						//	VkImageSubresourceRange	subresourceRange;
739 	};
740 
741 	const auto textureView = createImageView(vkd, device, &textureViewCreateInfo);
742 
743 	// Color attachment.
744 	const VkImageCreateInfo colorAttachmentInfo =
745 	{
746 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
747 		nullptr,								//	const void*				pNext;
748 		0u,										//	VkImageCreateFlags		flags;
749 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
750 		colorAttachmentFormat,					//	VkFormat				format;
751 		extent,									//	VkExtent3D				extent;
752 		1u,										//	deUint32				mipLevels;
753 		1u,										//	deUint32				arrayLayers;
754 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
755 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
756 		(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
757 		| VK_IMAGE_USAGE_TRANSFER_SRC_BIT),		//	VkImageUsageFlags		usage;
758 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
759 		0u,										//	deUint32				queueFamilyIndexCount;
760 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
761 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
762 	};
763 
764 	ImageWithMemory colorAttachment (vkd, device, alloc, colorAttachmentInfo, MemoryRequirement::Any);
765 
766 	const auto colorAttachmentView = makeImageView(vkd, device, colorAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, colorAttachmentInfo.format, colorSubresourceRange);
767 
768 	// Texure sampler.
769 	de::MovePtr<VkSamplerCustomBorderColorCreateInfoEXT> customBorderColorInfo;
770 
771 	const VkSamplerBorderColorComponentMappingCreateInfoEXT borderColorMappingInfo =
772 	{
773 		VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT,
774 		nullptr,
775 		m_params.componentMapping,
776 		isSrgbFormat(m_params.textureFormat),
777 	};
778 
779 	const void* pNext = nullptr;
780 
781 	if (custom)
782 	{
783 		customBorderColorInfo	= de::MovePtr<VkSamplerCustomBorderColorCreateInfoEXT>(new VkSamplerCustomBorderColorCreateInfoEXT);
784 		*customBorderColorInfo	= initVulkanStructure();
785 
786 		DE_ASSERT(m_params.customBorderColor);
787 		VkClearColorValue colorValue = m_params.customBorderColor.get();
788 
789 		if (m_params.useSamplerSwizzleHint)
790 			customBorderColorInfo->pNext = &borderColorMappingInfo;
791 
792 		// TODO: try combinations with customBorderColorWithoutFormat if supported?
793 		customBorderColorInfo->format				= m_params.textureFormat;
794 		customBorderColorInfo->customBorderColor	= colorValue;
795 
796 		pNext = customBorderColorInfo.get();
797 	}
798 	else
799 	{
800 		if (m_params.useSamplerSwizzleHint)
801 			pNext = &borderColorMappingInfo;
802 	}
803 
804 	const VkSamplerCreateInfo samplerCreateInfo =
805 	{
806 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,				//	VkStructureType			sType;
807 		pNext,												//	const void*				pNext;
808 		0u,													//	VkSamplerCreateFlags	flags;
809 		VK_FILTER_NEAREST,									//	VkFilter				magFilter;
810 		VK_FILTER_NEAREST,									//	VkFilter				minFilter;
811 		VK_SAMPLER_MIPMAP_MODE_NEAREST,						//	VkSamplerMipmapMode		mipmapMode;
812 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,			//	VkSamplerAddressMode	addressModeU;
813 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,			//	VkSamplerAddressMode	addressModeV;
814 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,			//	VkSamplerAddressMode	addressModeW;
815 		0u,													//	float					mipLodBias;
816 		VK_FALSE,											//	VkBool32				anisotropyEnable;
817 		0.0f,												//	float					maxAnisotropy;
818 		VK_FALSE,											//	VkBool32				compareEnable;
819 		VK_COMPARE_OP_NEVER,								//	VkCompareOp				compareOp;
820 		0.0f,												//	float					minLod;
821 		1.0f,												//	float					maxLod;
822 		m_params.borderColor,								//	VkBorderColor			borderColor;
823 		VK_FALSE,											//	VkBool32				unnormalizedCoordinates;
824 	};
825 
826 	const auto sampler = createSampler(vkd, device, &samplerCreateInfo);
827 
828 	// Descriptor set layout.
829 	DescriptorSetLayoutBuilder dsLayoutBuilder;
830 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
831 	const auto dsLayout = dsLayoutBuilder.build(vkd, device);
832 
833 	// Pipeline layout.
834 	const auto pipelineLayout = makePipelineLayout(vkd, device, dsLayout.get());
835 
836 	// Descriptor pool.
837 	DescriptorPoolBuilder poolBuilder;
838 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
839 	const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
840 
841 	// Descriptor set.
842 	const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), dsLayout.get());
843 
844 	// Update descriptor set.
845 	{
846 		DescriptorSetUpdateBuilder updateBuilder;
847 		VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(sampler.get(), textureView.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
848 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descriptorImageInfo);
849 		updateBuilder.update(vkd, device);
850 	}
851 
852 	// Render pass.
853 	const auto renderPass = makeRenderPass(vkd, device, colorAttachmentFormat);
854 
855 	// Shader modules.
856 	const auto vertShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
857 	const auto fragShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
858 
859 	// Pipeline.
860 	const VkPipelineShaderStageCreateInfo vertStageInfo =
861 	{
862 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
863 		nullptr,												//	const void*							pNext;
864 		0u,														//	VkPipelineShaderStageCreateFlags	flags;
865 		VK_SHADER_STAGE_VERTEX_BIT,								//	VkShaderStageFlagBits				stage;
866 		vertShader.get(),										//	VkShaderModule						module;
867 		"main",													//	const char*							pName;
868 		nullptr,												//	const VkSpecializationInfo*			pSpecializationInfo;
869 	};
870 
871 	const SpecConstants specConstantData =
872 	{
873 		m_params.textureCoordinates.x(),
874 		m_params.textureCoordinates.y(),
875 		(m_params.componentGather ? 1 : 0),
876 		//(m_params.componentGather ? *m_params.componentGather : -1),
877 	};
878 
879 	const VkSpecializationMapEntry specializationMap[] =
880 	{
881 		{	0u, offsetof(SpecConstants, u),				sizeof(specConstantData.u)			},
882 		{	1u, offsetof(SpecConstants, v),				sizeof(specConstantData.v)			},
883 		{	2u, offsetof(SpecConstants, gatherFlag),	sizeof(specConstantData.gatherFlag)	},
884 		//{	3u, offsetof(SpecConstants, gatherComp),	sizeof(specConstantData.gatherComp)	},
885 	};
886 
887 	const VkSpecializationInfo specializationInfo =
888 	{
889 		static_cast<deUint32>(DE_LENGTH_OF_ARRAY(specializationMap)),	//	deUint32						mapEntryCount;
890 		specializationMap,												//	const VkSpecializationMapEntry*	pMapEntries;
891 		static_cast<deUintptr>(sizeof(specConstantData)),				//	deUintptr						dataSize;
892 		&specConstantData,												//	const void*						pData;
893 	};
894 
895 	const VkPipelineShaderStageCreateInfo fragStageInfo =
896 	{
897 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
898 		nullptr,												//	const void*							pNext;
899 		0u,														//	VkPipelineShaderStageCreateFlags	flags;
900 		VK_SHADER_STAGE_FRAGMENT_BIT,							//	VkShaderStageFlagBits				stage;
901 		fragShader.get(),										//	VkShaderModule						module;
902 		"main",													//	const char*							pName;
903 		&specializationInfo,									//	const VkSpecializationInfo*			pSpecializationInfo;
904 	};
905 
906 	const VkPipelineShaderStageCreateInfo shaderStagesInfo[] = { vertStageInfo, fragStageInfo };
907 
908 	const VkPipelineVertexInputStateCreateInfo vertexInputInfo = initVulkanStructure();
909 
910 	VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = initVulkanStructure();
911 	inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
912 
913 	const auto viewport	= makeViewport(extent);
914 	const auto scissor	= makeRect2D(extent);
915 
916 	const VkPipelineViewportStateCreateInfo viewportInfo =
917 	{
918 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	//	VkStructureType						sType;
919 		nullptr,												//	const void*							pNext;
920 		0u,														//	VkPipelineViewportStateCreateFlags	flags;
921 		1u,														//	deUint32							viewportCount;
922 		&viewport,												//	const VkViewport*					pViewports;
923 		1u,														//	deUint32							scissorCount;
924 		&scissor,												//	const VkRect2D*						pScissors;
925 	};
926 
927 	const VkPipelineTessellationStateCreateInfo tessInfo = initVulkanStructure();
928 
929 	const VkPipelineRasterizationStateCreateInfo rasterizationInfo =
930 	{
931 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
932 		nullptr,													//	const void*								pNext;
933 		0u,															//	VkPipelineRasterizationStateCreateFlags	flags;
934 		VK_FALSE,													//	VkBool32								depthClampEnable;
935 		VK_FALSE,													//	VkBool32								rasterizerDiscardEnable;
936 		VK_POLYGON_MODE_FILL,										//	VkPolygonMode							polygonMode;
937 		VK_CULL_MODE_NONE,											//	VkCullModeFlags							cullMode;
938 		VK_FRONT_FACE_CLOCKWISE,									//	VkFrontFace								frontFace;
939 		VK_FALSE,													//	VkBool32								depthBiasEnable;
940 		0.0f,														//	float									depthBiasConstantFactor;
941 		0.0f,														//	float									depthBiasClamp;
942 		0.0f,														//	float									depthBiasSlopeFactor;
943 		1.0f,														//	float									lineWidth;
944 	};
945 
946 	const VkPipelineMultisampleStateCreateInfo multisampleInfo =
947 	{
948 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType							sType;
949 		nullptr,													//	const void*								pNext;
950 		0u,															//	VkPipelineMultisampleStateCreateFlags	flags;
951 		VK_SAMPLE_COUNT_1_BIT,										//	VkSampleCountFlagBits					rasterizationSamples;
952 		VK_FALSE,													//	VkBool32								sampleShadingEnable;
953 		1.0f,														//	float									minSampleShading;
954 		nullptr,													//	const VkSampleMask*						pSampleMask;
955 		VK_FALSE,													//	VkBool32								alphaToCoverageEnable;
956 		VK_FALSE,													//	VkBool32								alphaToOneEnable;
957 	};
958 
959 	const VkPipelineDepthStencilStateCreateInfo depthStencilInfo = initVulkanStructure();
960 
961 	VkPipelineColorBlendAttachmentState colorBlendAttachmentState;
962 	deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState));
963 	colorBlendAttachmentState.colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
964 
965 	const VkPipelineColorBlendStateCreateInfo colorBlendInfo =
966 	{
967 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
968 		nullptr,													//	const void*									pNext;
969 		0u,															//	VkPipelineColorBlendStateCreateFlags		flags;
970 		VK_FALSE,													//	VkBool32									logicOpEnable;
971 		VK_LOGIC_OP_CLEAR,											//	VkLogicOp									logicOp;
972 		1u,															//	deUint32									attachmentCount;
973 		&colorBlendAttachmentState,									//	const VkPipelineColorBlendAttachmentState*	pAttachments;
974 		{ .0f, .0f, .0f, .0f },										//	float										blendConstants[4];
975 	};
976 
977 	const VkGraphicsPipelineCreateInfo pipelineCreateInfo =
978 	{
979 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,				//	VkStructureType									sType;
980 		nullptr,														//	const void*										pNext;
981 		0u,																//	VkPipelineCreateFlags							flags;
982 		static_cast<deUint32>(DE_LENGTH_OF_ARRAY(shaderStagesInfo)),	//	deUint32										stageCount;
983 		shaderStagesInfo,												//	const VkPipelineShaderStageCreateInfo*			pStages;
984 		&vertexInputInfo,												//	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
985 		&inputAssemblyInfo,												//	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
986 		&tessInfo,														//	const VkPipelineTessellationStateCreateInfo*	pTessellationState;
987 		&viewportInfo,													//	const VkPipelineViewportStateCreateInfo*		pViewportState;
988 		&rasterizationInfo,												//	const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
989 		&multisampleInfo,												//	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
990 		&depthStencilInfo,												//	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
991 		&colorBlendInfo,												//	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
992 		nullptr,														//	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
993 		pipelineLayout.get(),											//	VkPipelineLayout								layout;
994 		renderPass.get(),												//	VkRenderPass									renderPass;
995 		0u,																//	deUint32										subpass;
996 		DE_NULL,														//	VkPipeline										basePipelineHandle;
997 		0,																//	deInt32											basePipelineIndex;
998 	};
999 
1000 	const auto graphicsPipeline = createGraphicsPipeline(vkd, device, DE_NULL, &pipelineCreateInfo);
1001 
1002 	// Framebuffer.
1003 	const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), extent.width, extent.height);
1004 
1005 	// Command pool and buffer.
1006 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
1007 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1008 	const auto cmdBuffer	= cmdBufferPtr.get();
1009 
1010 	// Empty clear color for the framebuffer.
1011 	VkClearValue zeroClearColor;
1012 	deMemset(&zeroClearColor, 0, sizeof(zeroClearColor));
1013 
1014 	// Texture barriers to fill it before using it.
1015 	const auto preClearBarrier = makeImageMemoryBarrier(
1016 		0u,
1017 		VK_ACCESS_TRANSFER_WRITE_BIT,
1018 		VK_IMAGE_LAYOUT_UNDEFINED,
1019 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1020 		texture.get(),
1021 		colorSubresourceRange);
1022 
1023 	const auto postClearBarrier = makeImageMemoryBarrier(
1024 		VK_ACCESS_TRANSFER_WRITE_BIT,
1025 		VK_ACCESS_SHADER_READ_BIT,
1026 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1027 		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1028 		texture.get(),
1029 		colorSubresourceRange);
1030 
1031 	// Record and submit.
1032 	beginCommandBuffer(vkd, cmdBuffer);
1033 
1034 	// Prepare texture.
1035 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preClearBarrier);
1036 	vkd.cmdClearColorImage(cmdBuffer, texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_params.textureColor, 1u, &colorSubresourceRange);
1037 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &postClearBarrier);
1038 
1039 	// Read from the texture to render a full-screen quad to the color buffer.
1040 	beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, zeroClearColor);
1041 	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
1042 	vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
1043 	vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u);
1044 	endRenderPass(vkd, cmdBuffer);
1045 
1046 	endCommandBuffer(vkd, cmdBuffer);
1047 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1048 
1049 	// Verify color buffer.
1050 	const auto	renderSize				= tcu::UVec2(extent.width, extent.height);
1051 	const auto	colorAttachmentLevel	= readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment.get(), colorAttachmentFormat, renderSize);
1052 	const auto	colorPixels				= colorAttachmentLevel->getAccess();
1053 	const auto	tcuTextureFormat		= mapVkFormat(m_params.textureFormat);
1054 	const auto	borderColor				= getBorderClearColorValue(m_params);
1055 	const auto	expectedColor			= getExpectedColor(borderColor, m_params);
1056 	std::string	resultMsg;
1057 
1058 	if (!comparePixelToColorClearValue(m_params, colorPixels, tcuTextureFormat, expectedColor, resultMsg))
1059 		TCU_FAIL(resultMsg);
1060 
1061 	return tcu::TestStatus::pass(resultMsg);
1062 }
1063 
1064 using ComponentSwizzleArray = std::array<VkComponentSwizzle, 4>;
1065 
1066 // Convert the component swizzle array to a component mapping structure.
makeComponentMapping(VkComponentMapping & mapping,const ComponentSwizzleArray & array)1067 void makeComponentMapping(VkComponentMapping& mapping, const ComponentSwizzleArray& array)
1068 {
1069 	mapping.r = array[0];
1070 	mapping.g = array[1];
1071 	mapping.b = array[2];
1072 	mapping.a = array[3];
1073 }
1074 
swizzleArrayToString(const ComponentSwizzleArray & swizzles)1075 std::string swizzleArrayToString(const ComponentSwizzleArray& swizzles)
1076 {
1077 	std::ostringstream stream;
1078 
1079 	for (const auto& s : swizzles)
1080 	{
1081 		switch (s)
1082 		{
1083 		case VK_COMPONENT_SWIZZLE_IDENTITY:	stream << "i"; break;
1084 		case VK_COMPONENT_SWIZZLE_ZERO:		stream << "0"; break;
1085 		case VK_COMPONENT_SWIZZLE_ONE:		stream << "1"; break;
1086 		case VK_COMPONENT_SWIZZLE_R:		stream << "r"; break;
1087 		case VK_COMPONENT_SWIZZLE_G:		stream << "g"; break;
1088 		case VK_COMPONENT_SWIZZLE_B:		stream << "b"; break;
1089 		case VK_COMPONENT_SWIZZLE_A:		stream << "a"; break;
1090 		default:
1091 			DE_ASSERT(false); break;
1092 		}
1093 	}
1094 
1095 	return stream.str();
1096 }
1097 
1098 // Generate mapping permutations for the swizzle components.
1099 // Note: using every permutation for component swizzle values results in 7^4=2401 combinations, which are too many.
genMappingPermutations()1100 std::vector<ComponentSwizzleArray> genMappingPermutations ()
1101 {
1102 	std::vector<ComponentSwizzleArray>	result;
1103 	const ComponentSwizzleArray			standardSwizzle	= {{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }};
1104 
1105 	// Standard normal swizzle.
1106 	result.push_back(standardSwizzle);
1107 
1108 	// Add a few combinations with rotated swizzles.
1109 	for (size_t rotations = 1u; rotations < standardSwizzle.size(); ++rotations)
1110 	{
1111 		ComponentSwizzleArray rotatedSwizzle = standardSwizzle;
1112 		std::rotate(rotatedSwizzle.begin(), rotatedSwizzle.begin() + rotations, rotatedSwizzle.end());
1113 		result.push_back(rotatedSwizzle);
1114 	}
1115 
1116 	// Try placing each special value in each of the positions.
1117 	VkComponentSwizzle specialSwizzles[] = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ZERO };
1118 	for (const auto& special : specialSwizzles)
1119 	{
1120 		for (size_t pos = 0; pos < standardSwizzle.size(); ++pos)
1121 		{
1122 			ComponentSwizzleArray newArray = standardSwizzle;
1123 			newArray[pos] = special;
1124 			result.push_back(newArray);
1125 		}
1126 	}
1127 
1128 	return result;
1129 }
1130 
gatherIndexToString(int gatherIndex)1131 std::string gatherIndexToString(int gatherIndex)
1132 {
1133 	if (gatherIndex < 0)
1134 		return "no_gather";
1135 	return "gather_" + std::to_string(gatherIndex);
1136 }
1137 
isIntegerBorder(VkBorderColor borderType)1138 bool isIntegerBorder (VkBorderColor borderType)
1139 {
1140 	bool isInt = false;
1141 	switch (borderType)
1142 	{
1143 	case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
1144 	case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
1145 	case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
1146 	case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
1147 		isInt = false; break;
1148 	case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
1149 	case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
1150 	case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
1151 	case VK_BORDER_COLOR_INT_CUSTOM_EXT:
1152 		isInt = true; break;
1153 	default:
1154 		DE_ASSERT(false); break;
1155 	}
1156 
1157 	return isInt;
1158 }
1159 
getRandomBorderCoordinates(de::Random & rnd)1160 tcu::Vec2 getRandomBorderCoordinates (de::Random& rnd)
1161 {
1162 	tcu::Vec2 coords;
1163 
1164 	// Two bits to decide which coordinates will be out of range (at least one).
1165 	const deUint32 outOfRangeMask = static_cast<deUint32>(rnd.getInt(1, 3));
1166 
1167 	for (int i = 0; i < 2; ++i)
1168 	{
1169 		// Each coord will be in the [0.0, 0.9] range if in range, [1.1, 5.0] or [-5.0, -1.1] if out of range.
1170 		bool	outOfRange	= (outOfRangeMask & (1<<i));
1171 		bool	negative	= (outOfRange && rnd.getBool());
1172 		float	minCoord	= (outOfRange ? 1.1f : 0.0f);
1173 		float	maxCoord	= (outOfRange ? 5.0f : 0.9f);
1174 		float	value		= (negative ? -1.0f : 1.0f) * rnd.getFloat(minCoord, maxCoord);
1175 
1176 		coords[i] = value;
1177 	}
1178 
1179 	return coords;
1180 }
1181 
1182 // Generate a random clear color usable for the given format.
getRandomClearColor(VkFormat format,de::Random & rnd)1183 VkClearColorValue getRandomClearColor (VkFormat format, de::Random& rnd)
1184 {
1185 	VkClearColorValue color;
1186 	deMemset(&color, 0, sizeof(color));
1187 
1188 	const auto		tcuFormat		= mapVkFormat(format);
1189 	const auto		numComponents	= tcu::getNumUsedChannels(tcuFormat.order);
1190 	const auto		formatType		= getFormatType(format);
1191 
1192 	for (int i = 0; i < numComponents; ++i)
1193 	{
1194 		if (formatType == FormatType::SIGNED_INT || formatType == FormatType::UNSIGNED_INT)
1195 		{
1196 			const auto		componentSize	= tcu::getChannelSize(tcuFormat.type);
1197 
1198 			DE_ASSERT(componentSize > 0);
1199 
1200 			const deUint64	mask			= (1ull << (componentSize*8)) - 1ull;
1201 			const deUint64	signBit			= (1ull << (componentSize*8-1));
1202 			const deUint64	signMask		= (~mask); // Used to extend the sign bit.
1203 			const auto value = rnd.getUint64();
1204 
1205 			if (formatType == FormatType::SIGNED_INT)
1206 			{
1207 				// Extend sign bit for negative values.
1208 				auto finalValue = (value & mask);
1209 				if (finalValue & signBit)
1210 					finalValue |= signMask;
1211 				color.int32[i] = static_cast<deInt32>(finalValue);
1212 			}
1213 			else
1214 				color.uint32[i] = static_cast<deUint32>(value & mask);
1215 		}
1216 		else
1217 			color.float32[i] = rnd.getFloat();
1218 	}
1219 
1220 	return color;
1221 }
1222 
1223 } // anonymous
1224 
createSamplerBorderSwizzleTests(tcu::TestContext & testCtx)1225 tcu::TestCaseGroup* createSamplerBorderSwizzleTests (tcu::TestContext& testCtx)
1226 {
1227 	const deUint32 baseSeed = 1610707317u;
1228 
1229 	const VkFormat textureFormats[] =
1230 	{
1231 		//VK_FORMAT_UNDEFINED,
1232 		VK_FORMAT_R4G4_UNORM_PACK8,
1233 		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1234 		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1235 		VK_FORMAT_R5G6B5_UNORM_PACK16,
1236 		VK_FORMAT_B5G6R5_UNORM_PACK16,
1237 		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1238 		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1239 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1240 		VK_FORMAT_R8_UNORM,
1241 		VK_FORMAT_R8_SNORM,
1242 		//VK_FORMAT_R8_USCALED,
1243 		//VK_FORMAT_R8_SSCALED,
1244 		VK_FORMAT_R8_UINT,
1245 		VK_FORMAT_R8_SINT,
1246 		VK_FORMAT_R8_SRGB,
1247 		VK_FORMAT_R8G8_UNORM,
1248 		VK_FORMAT_R8G8_SNORM,
1249 		//VK_FORMAT_R8G8_USCALED,
1250 		//VK_FORMAT_R8G8_SSCALED,
1251 		VK_FORMAT_R8G8_UINT,
1252 		VK_FORMAT_R8G8_SINT,
1253 		VK_FORMAT_R8G8_SRGB,
1254 		VK_FORMAT_R8G8B8_UNORM,
1255 		VK_FORMAT_R8G8B8_SNORM,
1256 		//VK_FORMAT_R8G8B8_USCALED,
1257 		//VK_FORMAT_R8G8B8_SSCALED,
1258 		VK_FORMAT_R8G8B8_UINT,
1259 		VK_FORMAT_R8G8B8_SINT,
1260 		VK_FORMAT_R8G8B8_SRGB,
1261 		VK_FORMAT_B8G8R8_UNORM,
1262 		VK_FORMAT_B8G8R8_SNORM,
1263 		//VK_FORMAT_B8G8R8_USCALED,
1264 		//VK_FORMAT_B8G8R8_SSCALED,
1265 		VK_FORMAT_B8G8R8_UINT,
1266 		VK_FORMAT_B8G8R8_SINT,
1267 		VK_FORMAT_B8G8R8_SRGB,
1268 		VK_FORMAT_R8G8B8A8_UNORM,
1269 		VK_FORMAT_R8G8B8A8_SNORM,
1270 		//VK_FORMAT_R8G8B8A8_USCALED,
1271 		//VK_FORMAT_R8G8B8A8_SSCALED,
1272 		VK_FORMAT_R8G8B8A8_UINT,
1273 		VK_FORMAT_R8G8B8A8_SINT,
1274 		VK_FORMAT_R8G8B8A8_SRGB,
1275 		VK_FORMAT_B8G8R8A8_UNORM,
1276 		VK_FORMAT_B8G8R8A8_SNORM,
1277 		//VK_FORMAT_B8G8R8A8_USCALED,
1278 		//VK_FORMAT_B8G8R8A8_SSCALED,
1279 		VK_FORMAT_B8G8R8A8_UINT,
1280 		VK_FORMAT_B8G8R8A8_SINT,
1281 		VK_FORMAT_B8G8R8A8_SRGB,
1282 		 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1283 		 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1284 		// VK_FORMAT_A8B8G8R8_USCALED_PACK32,
1285 		// VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
1286 		// VK_FORMAT_A8B8G8R8_UINT_PACK32,
1287 		// VK_FORMAT_A8B8G8R8_SINT_PACK32,
1288 		// VK_FORMAT_A8B8G8R8_SRGB_PACK32,
1289 		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1290 		VK_FORMAT_A2R10G10B10_SNORM_PACK32,
1291 		// VK_FORMAT_A2R10G10B10_USCALED_PACK32,
1292 		// VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
1293 		// VK_FORMAT_A2R10G10B10_UINT_PACK32,
1294 		// VK_FORMAT_A2R10G10B10_SINT_PACK32,
1295 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1296 		VK_FORMAT_A2B10G10R10_SNORM_PACK32,
1297 		// VK_FORMAT_A2B10G10R10_USCALED_PACK32,
1298 		// VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
1299 		// VK_FORMAT_A2B10G10R10_UINT_PACK32,
1300 		// VK_FORMAT_A2B10G10R10_SINT_PACK32,
1301 		VK_FORMAT_R16_UNORM,
1302 		VK_FORMAT_R16_SNORM,
1303 		//VK_FORMAT_R16_USCALED,
1304 		//VK_FORMAT_R16_SSCALED,
1305 		VK_FORMAT_R16_UINT,
1306 		VK_FORMAT_R16_SINT,
1307 		VK_FORMAT_R16_SFLOAT,
1308 		VK_FORMAT_R16G16_UNORM,
1309 		VK_FORMAT_R16G16_SNORM,
1310 		//VK_FORMAT_R16G16_USCALED,
1311 		//VK_FORMAT_R16G16_SSCALED,
1312 		VK_FORMAT_R16G16_UINT,
1313 		VK_FORMAT_R16G16_SINT,
1314 		VK_FORMAT_R16G16_SFLOAT,
1315 		VK_FORMAT_R16G16B16_UNORM,
1316 		VK_FORMAT_R16G16B16_SNORM,
1317 		//VK_FORMAT_R16G16B16_USCALED,
1318 		//VK_FORMAT_R16G16B16_SSCALED,
1319 		VK_FORMAT_R16G16B16_UINT,
1320 		VK_FORMAT_R16G16B16_SINT,
1321 		VK_FORMAT_R16G16B16_SFLOAT,
1322 		VK_FORMAT_R16G16B16A16_UNORM,
1323 		VK_FORMAT_R16G16B16A16_SNORM,
1324 		//VK_FORMAT_R16G16B16A16_USCALED,
1325 		//VK_FORMAT_R16G16B16A16_SSCALED,
1326 		VK_FORMAT_R16G16B16A16_UINT,
1327 		VK_FORMAT_R16G16B16A16_SINT,
1328 		VK_FORMAT_R16G16B16A16_SFLOAT,
1329 		VK_FORMAT_R32_UINT,
1330 		VK_FORMAT_R32_SINT,
1331 		VK_FORMAT_R32_SFLOAT,
1332 		VK_FORMAT_R32G32_UINT,
1333 		VK_FORMAT_R32G32_SINT,
1334 		VK_FORMAT_R32G32_SFLOAT,
1335 		VK_FORMAT_R32G32B32_UINT,
1336 		VK_FORMAT_R32G32B32_SINT,
1337 		VK_FORMAT_R32G32B32_SFLOAT,
1338 		VK_FORMAT_R32G32B32A32_UINT,
1339 		VK_FORMAT_R32G32B32A32_SINT,
1340 		VK_FORMAT_R32G32B32A32_SFLOAT,
1341 	};
1342 
1343 	const auto mappingPermutations = genMappingPermutations();
1344 
1345 	const struct
1346 	{
1347 		VkBorderColor	borderType;
1348 		const char*		borderTypeName;
1349 	}
1350 	borderColors[] =
1351 	{
1352 		{	VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	"transparent_black"	},
1353 		{	VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,		"transparent_black"	},
1354 		{	VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,			"opaque_black"		},
1355 		{	VK_BORDER_COLOR_INT_OPAQUE_BLACK,			"opaque_black"		},
1356 		{	VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,			"opaque_white"		},
1357 		{	VK_BORDER_COLOR_INT_OPAQUE_WHITE,			"opaque_white"		},
1358 		{	VK_BORDER_COLOR_FLOAT_CUSTOM_EXT,			"custom"			},
1359 		{	VK_BORDER_COLOR_INT_CUSTOM_EXT,				"custom"			},
1360 	};
1361 
1362 	const struct
1363 	{
1364 		bool		useSwizzleHint;
1365 		const char*	name;
1366 	} swizzleHintCases[] =
1367 	{
1368 		{ false,	"no_swizzle_hint"	},
1369 		{ true,		"with_swizzle_hint"	},
1370 	};
1371 
1372 	de::MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, "border_swizzle", "Border color swizzle tests"));
1373 
1374 	for (const auto& format : textureFormats)
1375 	{
1376 		const auto						skip		= std::strlen("VK_FORMAT_");
1377 		const std::string				formatName	= de::toLower(std::string(getFormatName(format)).substr(skip));
1378 		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatName.c_str(), ""));
1379 
1380 		for (size_t mappingIdx = 0u; mappingIdx < mappingPermutations.size(); ++mappingIdx)
1381 		{
1382 			const auto&						mapping			= mappingPermutations[mappingIdx];
1383 			de::MovePtr<tcu::TestCaseGroup>	mappingGroup	(new tcu::TestCaseGroup(testCtx, swizzleArrayToString(mapping).c_str(), ""));
1384 
1385 			for (int borderColorIdx = 0; borderColorIdx < DE_LENGTH_OF_ARRAY(borderColors); ++borderColorIdx)
1386 			{
1387 				const auto&						borderColor		= borderColors[borderColorIdx];
1388 				de::MovePtr<tcu::TestCaseGroup>	borderTypeGroup	(new tcu::TestCaseGroup(testCtx, borderColor.borderTypeName, ""));
1389 
1390 				const auto formatType	= getFormatType(format);
1391 				const auto isIntBorder	= isIntegerBorder(borderColor.borderType);
1392 
1393 				// Skip cases that do not make sense for the format and border type combination.
1394 				if (isIntBorder && formatType == FormatType::FLOAT)
1395 					continue;
1396 				else if (!isIntBorder && formatType != FormatType::FLOAT)
1397 					continue;
1398 
1399 				for (int gatherIdx = -1; gatherIdx <= 3; ++gatherIdx)
1400 				{
1401 					const auto						componentGather	= gatherIndexToString(gatherIdx);
1402 					de::MovePtr<tcu::TestCaseGroup>	gatherGroup		(new tcu::TestCaseGroup(testCtx, componentGather.c_str(), ""));
1403 
1404 					for (const auto& swizzleHint : swizzleHintCases)
1405 					{
1406 						TestParams params;
1407 
1408 						const deUint32	seed	= baseSeed + static_cast<deUint32>(format) + static_cast<deUint32>(mappingIdx) + static_cast<deUint32>(borderColorIdx) + static_cast<deUint32>(gatherIdx);
1409 						de::Random		rnd		(seed);
1410 
1411 						params.textureFormat	= format;
1412 						params.textureColor		= getRandomClearColor(format, rnd);
1413 
1414 						makeComponentMapping(params.componentMapping, mapping);
1415 						params.borderColor			= borderColor.borderType;
1416 						params.componentGather		= ((gatherIdx < 0) ? tcu::nothing<int>() : tcu::just(gatherIdx));
1417 						params.textureCoordinates	= getRandomBorderCoordinates(rnd);
1418 
1419 						if (params.isCustom())
1420 							params.customBorderColor = tcu::just(getRandomClearColor(format, rnd));
1421 						else
1422 							params.customBorderColor = tcu::nothing<VkClearColorValue>();
1423 
1424 						params.useSamplerSwizzleHint = swizzleHint.useSwizzleHint;
1425 
1426 						gatherGroup->addChild(new BorderSwizzleCase(testCtx, swizzleHint.name, "", params));
1427 					}
1428 
1429 					borderTypeGroup->addChild(gatherGroup.release());
1430 				}
1431 
1432 				mappingGroup->addChild(borderTypeGroup.release());
1433 			}
1434 
1435 			formatGroup->addChild(mappingGroup.release());
1436 		}
1437 
1438 		mainGroup->addChild(formatGroup.release());
1439 	}
1440 
1441 	return mainGroup.release();
1442 }
1443 
1444 } // pipeline
1445 } // vkt
1446 
1447 
1448 
1449