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