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