• 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::__anon84764cf10111::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::__anon84764cf10111::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::__anon84764cf10111::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 	// If the component mapping contains a SWIZZLE_ONE, overwrite this with a SWIZZLE_ZERO to ensure
459 	// a strict tolerance when applying a swizzle of SWIZZLE_ONE to the threshold.
460 	const VkComponentMapping thresholdComponentMapping =
461 	{
462 		(params.componentMapping.r == VK_COMPONENT_SWIZZLE_ONE ? VK_COMPONENT_SWIZZLE_ZERO : params.componentMapping.r),
463 		(params.componentMapping.g == VK_COMPONENT_SWIZZLE_ONE ? VK_COMPONENT_SWIZZLE_ZERO : params.componentMapping.g),
464 		(params.componentMapping.b == VK_COMPONENT_SWIZZLE_ONE ? VK_COMPONENT_SWIZZLE_ZERO : params.componentMapping.b),
465 		(params.componentMapping.a == VK_COMPONENT_SWIZZLE_ONE ? VK_COMPONENT_SWIZZLE_ZERO : params.componentMapping.a),
466 	};
467 
468 	switch (channelClass)
469 	{
470 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
471 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
472 		{
473 			tcu::Vec4			refColor	(ref.float32[0],
474 											 ref.float32[1],
475 											 ref.float32[2],
476 											 ref.float32[3]);
477 			tcu::Vec4			threshold	(0.0f);
478 
479 			if (params.isCustom())
480 			{
481 				// Relax thresholds for custom color components.
482 				const tcu::IVec4	bitDepth	(getTextureFormatBitDepth(textureFormat));
483 				const int			modifier	= (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) ? 0 : 1;
484 
485 				threshold = tcu::Vec4 (bitDepth[0] > 0 ? 1.0f / ((float)(1 << (bitDepth[0] - modifier)) - 1.0f) : 0.0f,
486 									   bitDepth[1] > 0 ? 1.0f / ((float)(1 << (bitDepth[1] - modifier)) - 1.0f) : 0.0f,
487 									   bitDepth[2] > 0 ? 1.0f / ((float)(1 << (bitDepth[2] - modifier)) - 1.0f) : 0.0f,
488 									   bitDepth[3] > 0 ? 1.0f / ((float)(1 << (bitDepth[3] - modifier)) - 1.0f) : 0.0f);
489 
490 				if (isSRGB(textureFormat))
491 				{
492 					// Widen thresholds a bit due to possible low-precision sRGB conversions.
493 					for (int i = 0; i < decltype(threshold)::SIZE; ++i)
494 						threshold[i] *= 2.0f;
495 				}
496 			}
497 
498 			// Apply swizzle and gather to thresholds.
499 			threshold = applySwizzle(threshold, thresholdComponentMapping);
500 
501 			if (params.componentGather)
502 				threshold = applyGather(threshold, *params.componentGather);
503 
504 			for (int z = 0; z < access.getDepth(); ++z)
505 			for (int y = 0; y < access.getHeight(); ++y)
506 			for (int x = 0; x < access.getWidth(); ++x)
507 			{
508 				const tcu::Vec4	resColor	(access.getPixel(x, y, z));
509 				const bool		result		= !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask));
510 
511 				if (!result || (x == 0 && y == 0 && z == 0))
512 				{
513 					std::stringstream s;
514 					s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor;
515 					stringResult = s.str();
516 				}
517 
518 				if (!result)
519 					return false;
520 			}
521 
522 			return true;
523 		}
524 
525 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
526 		{
527 			const tcu::UVec4	refColor	(ref.uint32[0],
528 											 ref.uint32[1],
529 											 ref.uint32[2],
530 											 ref.uint32[3]);
531 			tcu::UVec4			threshold	(0u);
532 
533 			if (params.isCustom())
534 			{
535 				// Relax thresholds for custom color components.
536 				const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat));
537 
538 				threshold = tcu::UVec4 ((bitDepth[0] > 0) ? 1 : 0,
539 										(bitDepth[1] > 0) ? 1 : 0,
540 										(bitDepth[2] > 0) ? 1 : 0,
541 										(bitDepth[3] > 0) ? 1 : 0);
542 			}
543 
544 			// Apply swizzle and gather to thresholds.
545 			threshold = applySwizzle(threshold, thresholdComponentMapping);
546 
547 			if (params.componentGather)
548 				threshold = applyGather(threshold, *params.componentGather);
549 
550 			for (int z = 0; z < access.getDepth(); ++z)
551 			for (int y = 0; y < access.getHeight(); ++y)
552 			for (int x = 0; x < access.getWidth(); ++x)
553 			{
554 				const tcu::UVec4	resColor	(access.getPixelUint(x, y, z));
555 				const bool			result		= !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask));
556 
557 				if (!result || (x == 0 && y == 0 && z == 0))
558 				{
559 					std::stringstream s;
560 					s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor;
561 					stringResult = s.str();
562 				}
563 
564 				if (!result)
565 					return false;
566 			}
567 
568 			return true;
569 		}
570 
571 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
572 		{
573 			const tcu::IVec4	refColor	(ref.int32[0],
574 											 ref.int32[1],
575 											 ref.int32[2],
576 											 ref.int32[3]);
577 			tcu::IVec4			threshold	(0);
578 
579 			if (params.isCustom())
580 			{
581 				// Relax thresholds for custom color components.
582 				const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat));
583 
584 				threshold = tcu::IVec4 ((bitDepth[0] > 0) ? 1 : 0,
585 										(bitDepth[1] > 0) ? 1 : 0,
586 										(bitDepth[2] > 0) ? 1 : 0,
587 										(bitDepth[3] > 0) ? 1 : 0);
588 			}
589 
590 			// Apply swizzle and gather to thresholds.
591 			threshold = applySwizzle(threshold, thresholdComponentMapping);
592 
593 			if (params.componentGather)
594 				threshold = applyGather(threshold, *params.componentGather);
595 
596 			for (int z = 0; z < access.getDepth(); ++z)
597 			for (int y = 0; y < access.getHeight(); ++y)
598 			for (int x = 0; x < access.getWidth(); ++x)
599 			{
600 				const tcu::IVec4	resColor	(access.getPixelInt(x, y, z));
601 				const bool			result		= !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask));
602 
603 				if (!result || (x == 0 && y == 0 && z == 0))
604 				{
605 					std::stringstream s;
606 					s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor;
607 					stringResult = s.str();
608 				}
609 
610 				if (!result)
611 					return false;
612 			}
613 
614 			return true;
615 		}
616 
617 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
618 		{
619 			using u64v4 = tcu::Vector<deUint64, 4>;
620 
621 			const tcu::Vec4		refColor		(ref.float32[0],
622 												 ref.float32[1],
623 												 ref.float32[2],
624 												 ref.float32[3]);
625 			u64v4				threshold		(0ull);
626 
627 			if (params.isCustom())
628 			{
629 				// Relax thresholds for custom color components.
630 				const tcu::IVec4	mantissaBitsI	(getTextureFormatMantissaBitDepth(textureFormat));
631 				const u64v4			mantissaBits	(mantissaBitsI.x(), mantissaBitsI.y(), mantissaBitsI.z(), mantissaBitsI.w());
632 
633 				threshold = u64v4 ((mantissaBits[0] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[0])) : 0ull,
634 								   (mantissaBits[1] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[1])) : 0ull,
635 								   (mantissaBits[2] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[2])) : 0ull,
636 								   (mantissaBits[3] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[3])) : 0ull);
637 			}
638 
639 			// Apply swizzle and gather to thresholds.
640 			threshold = applySwizzle(threshold, thresholdComponentMapping);
641 
642 			if (params.componentGather)
643 				threshold = applyGather(threshold, *params.componentGather);
644 
645 			DE_ASSERT(allEqual(greaterThanEqual(threshold, u64v4(0u)), tcu::BVec4(true)));
646 
647 			for (int z = 0; z < access.getDepth(); ++z)
648 			for (int y = 0; y < access.getHeight(); ++y)
649 			for (int x = 0; x < access.getWidth(); ++x)
650 			{
651 				const tcu::Vec4	resColor (access.getPixel(x, y, z));
652 
653 				for (int ndx = 0; ndx < decltype(resColor)::SIZE; ndx++)
654 				{
655 					const bool result = !(calcFloatDiff(resColor[ndx], refColor[ndx]) > threshold[ndx] && channelMask[ndx]);
656 
657 					if (!result || (x == 0 && y == 0 && z == 0))
658 					{
659 						float				floatThreshold	= tcu::Float32((deUint32)(threshold)[0]).asFloat();
660 						tcu::Vec4			thresholdVec4	(floatThreshold,
661 															 floatThreshold,
662 															 floatThreshold,
663 															 floatThreshold);
664 						std::stringstream	s;
665 
666 						s << "Ref:" << refColor << " Threshold:" << thresholdVec4 << " Color:" << resColor;
667 						stringResult = s.str();
668 					}
669 
670 					if (!result)
671 						return false;
672 				}
673 			}
674 
675 			return true;
676 		}
677 
678 		default:
679 			DE_FATAL("Invalid channel class");
680 			return false;
681 	}
682 }
683 
684 // Gets the clear color value from the border color. See "Texel Replacement" in the spec.
getBorderClearColorValue(const TestParams & params)685 VkClearColorValue getBorderClearColorValue (const TestParams& params)
686 {
687 	VkClearColorValue result;
688 	deMemset(&result, 0, sizeof(result));
689 
690 	switch (params.borderColor)
691 	{
692 	case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:	/* memset works. */															break;
693 	case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:		/* memset works. */															break;
694 	case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:		result.float32[3] = 1.0f;													break;
695 	case VK_BORDER_COLOR_INT_OPAQUE_BLACK:			result.int32[3] = 1;														break;
696 	case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:		for (size_t i = 0; i < 4; ++i) result.float32[i] = 1.0f;					break;
697 	case VK_BORDER_COLOR_INT_OPAQUE_WHITE:			for (size_t i = 0; i < 4; ++i) result.int32[i] = 1;							break;
698 	case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:			// fallthrough.
699 	case VK_BORDER_COLOR_INT_CUSTOM_EXT:			DE_ASSERT(params.customBorderColor); result = *params.customBorderColor;	break;
700 	default:										DE_ASSERT(false);															break;
701 	}
702 
703 	return result;
704 }
705 
iterate(void)706 tcu::TestStatus BorderSwizzleInstance::iterate (void)
707 {
708 	const auto&	vkd						= m_context.getDeviceInterface();
709 	const auto	device					= m_context.getDevice();
710 	auto&		alloc					= m_context.getDefaultAllocator();
711 	const auto	queue					= m_context.getUniversalQueue();
712 	const auto	qIndex					= m_context.getUniversalQueueFamilyIndex();
713 	const auto	extent					= getImageExtent();
714 	const auto	custom					= m_params.isCustom();
715 	const auto	colorAttachmentFormat	= getColorAttachmentFormat(m_params.textureFormat);
716 	const auto	colorSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
717 
718 	// Texture.
719 	const VkImageCreateInfo textureCreateInfo =
720 	{
721 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
722 		nullptr,								//	const void*				pNext;
723 		0u,										//	VkImageCreateFlags		flags;
724 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
725 		m_params.textureFormat,					//	VkFormat				format;
726 		extent,									//	VkExtent3D				extent;
727 		1u,										//	deUint32				mipLevels;
728 		1u,										//	deUint32				arrayLayers;
729 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
730 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
731 		(VK_IMAGE_USAGE_SAMPLED_BIT				//	VkImageUsageFlags		usage;
732 		|VK_IMAGE_USAGE_TRANSFER_DST_BIT),
733 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
734 		0u,										//	deUint32				queueFamilyIndexCount;
735 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
736 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
737 	};
738 
739 	ImageWithMemory texture (vkd, device, alloc, textureCreateInfo, MemoryRequirement::Any);
740 
741 	const VkImageViewCreateInfo textureViewCreateInfo =
742 	{
743 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	//	VkStructureType			sType;
744 		nullptr,									//	const void*				pNext;
745 		0u,											//	VkImageViewCreateFlags	flags;
746 		texture.get(),								//	VkImage					image;
747 		VK_IMAGE_VIEW_TYPE_2D,						//	VkImageViewType			viewType;
748 		m_params.textureFormat,						//	VkFormat				format;
749 		m_params.componentMapping,					//	VkComponentMapping		components;
750 		colorSubresourceRange,						//	VkImageSubresourceRange	subresourceRange;
751 	};
752 
753 	const auto textureView = createImageView(vkd, device, &textureViewCreateInfo);
754 
755 	// Color attachment.
756 	const VkImageCreateInfo colorAttachmentInfo =
757 	{
758 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
759 		nullptr,								//	const void*				pNext;
760 		0u,										//	VkImageCreateFlags		flags;
761 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
762 		colorAttachmentFormat,					//	VkFormat				format;
763 		extent,									//	VkExtent3D				extent;
764 		1u,										//	deUint32				mipLevels;
765 		1u,										//	deUint32				arrayLayers;
766 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
767 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
768 		(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
769 		| VK_IMAGE_USAGE_TRANSFER_SRC_BIT),		//	VkImageUsageFlags		usage;
770 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
771 		0u,										//	deUint32				queueFamilyIndexCount;
772 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
773 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
774 	};
775 
776 	ImageWithMemory colorAttachment (vkd, device, alloc, colorAttachmentInfo, MemoryRequirement::Any);
777 
778 	const auto colorAttachmentView = makeImageView(vkd, device, colorAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, colorAttachmentInfo.format, colorSubresourceRange);
779 
780 	// Texure sampler.
781 	de::MovePtr<VkSamplerCustomBorderColorCreateInfoEXT> customBorderColorInfo;
782 
783 	const VkSamplerBorderColorComponentMappingCreateInfoEXT borderColorMappingInfo =
784 	{
785 		VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT,
786 		nullptr,
787 		m_params.componentMapping,
788 		isSrgbFormat(m_params.textureFormat),
789 	};
790 
791 	const void* pNext = nullptr;
792 
793 	if (custom)
794 	{
795 		customBorderColorInfo	= de::MovePtr<VkSamplerCustomBorderColorCreateInfoEXT>(new VkSamplerCustomBorderColorCreateInfoEXT);
796 		*customBorderColorInfo	= initVulkanStructure();
797 
798 		DE_ASSERT(m_params.customBorderColor);
799 		VkClearColorValue colorValue = m_params.customBorderColor.get();
800 
801 		if (m_params.useSamplerSwizzleHint)
802 			customBorderColorInfo->pNext = &borderColorMappingInfo;
803 
804 		// TODO: try combinations with customBorderColorWithoutFormat if supported?
805 		customBorderColorInfo->format				= m_params.textureFormat;
806 		customBorderColorInfo->customBorderColor	= colorValue;
807 
808 		pNext = customBorderColorInfo.get();
809 	}
810 	else
811 	{
812 		if (m_params.useSamplerSwizzleHint)
813 			pNext = &borderColorMappingInfo;
814 	}
815 
816 	const VkSamplerCreateInfo samplerCreateInfo =
817 	{
818 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,				//	VkStructureType			sType;
819 		pNext,												//	const void*				pNext;
820 		0u,													//	VkSamplerCreateFlags	flags;
821 		VK_FILTER_NEAREST,									//	VkFilter				magFilter;
822 		VK_FILTER_NEAREST,									//	VkFilter				minFilter;
823 		VK_SAMPLER_MIPMAP_MODE_NEAREST,						//	VkSamplerMipmapMode		mipmapMode;
824 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,			//	VkSamplerAddressMode	addressModeU;
825 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,			//	VkSamplerAddressMode	addressModeV;
826 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,			//	VkSamplerAddressMode	addressModeW;
827 		0u,													//	float					mipLodBias;
828 		VK_FALSE,											//	VkBool32				anisotropyEnable;
829 		0.0f,												//	float					maxAnisotropy;
830 		VK_FALSE,											//	VkBool32				compareEnable;
831 		VK_COMPARE_OP_NEVER,								//	VkCompareOp				compareOp;
832 		0.0f,												//	float					minLod;
833 		1.0f,												//	float					maxLod;
834 		m_params.borderColor,								//	VkBorderColor			borderColor;
835 		VK_FALSE,											//	VkBool32				unnormalizedCoordinates;
836 	};
837 
838 	const auto sampler = createSampler(vkd, device, &samplerCreateInfo);
839 
840 	// Descriptor set layout.
841 	DescriptorSetLayoutBuilder dsLayoutBuilder;
842 	dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT);
843 	const auto dsLayout = dsLayoutBuilder.build(vkd, device);
844 
845 	// Pipeline layout.
846 	const auto pipelineLayout = makePipelineLayout(vkd, device, dsLayout.get());
847 
848 	// Descriptor pool.
849 	DescriptorPoolBuilder poolBuilder;
850 	poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
851 	const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
852 
853 	// Descriptor set.
854 	const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), dsLayout.get());
855 
856 	// Update descriptor set.
857 	{
858 		DescriptorSetUpdateBuilder updateBuilder;
859 		VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(sampler.get(), textureView.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
860 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descriptorImageInfo);
861 		updateBuilder.update(vkd, device);
862 	}
863 
864 	// Render pass.
865 	const auto renderPass = makeRenderPass(vkd, device, colorAttachmentFormat);
866 
867 	// Shader modules.
868 	const auto vertShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
869 	const auto fragShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
870 
871 	const SpecConstants specConstantData =
872 	{
873 		m_params.textureCoordinates.x(),
874 		m_params.textureCoordinates.y(),
875 		(m_params.componentGather ? 1 : 0),
876 		//(m_params.componentGather ? *m_params.componentGather : -1),
877 	};
878 
879 	const VkSpecializationMapEntry specializationMap[] =
880 	{
881 		{	0u, offsetof(SpecConstants, u),				sizeof(specConstantData.u)			},
882 		{	1u, offsetof(SpecConstants, v),				sizeof(specConstantData.v)			},
883 		{	2u, offsetof(SpecConstants, gatherFlag),	sizeof(specConstantData.gatherFlag)	},
884 		//{	3u, offsetof(SpecConstants, gatherComp),	sizeof(specConstantData.gatherComp)	},
885 	};
886 
887 	const VkSpecializationInfo specializationInfo =
888 	{
889 		static_cast<deUint32>(DE_LENGTH_OF_ARRAY(specializationMap)),	//	deUint32						mapEntryCount;
890 		specializationMap,												//	const VkSpecializationMapEntry*	pMapEntries;
891 		static_cast<deUintptr>(sizeof(specConstantData)),				//	deUintptr						dataSize;
892 		&specConstantData,												//	const void*						pData;
893 	};
894 
895 	const VkPipelineVertexInputStateCreateInfo vertexInputInfo = initVulkanStructure();
896 
897 	const std::vector<VkViewport>	viewport	{ makeViewport(extent) };
898 	const std::vector<VkRect2D>		scissor		{ makeRect2D(extent) };
899 
900 	VkPipelineColorBlendAttachmentState colorBlendAttachmentState;
901 	deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState));
902 	colorBlendAttachmentState.colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
903 
904 	const VkPipelineColorBlendStateCreateInfo colorBlendInfo
905 	{
906 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
907 		nullptr,													//	const void*									pNext;
908 		0u,															//	VkPipelineColorBlendStateCreateFlags		flags;
909 		VK_FALSE,													//	VkBool32									logicOpEnable;
910 		VK_LOGIC_OP_CLEAR,											//	VkLogicOp									logicOp;
911 		1u,															//	deUint32									attachmentCount;
912 		&colorBlendAttachmentState,									//	const VkPipelineColorBlendAttachmentState*	pAttachments;
913 		{ .0f, .0f, .0f, .0f },										//	float										blendConstants[4];
914 	};
915 
916 	GraphicsPipelineWrapper graphicsPipeline(vkd, device, m_params.pipelineConstructionType);
917 	graphicsPipeline.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
918 					.setDefaultDepthStencilState()
919 					.setDefaultRasterizationState()
920 					.setDefaultMultisampleState()
921 					.setupVertexInputState(&vertexInputInfo)
922 					.setupPreRasterizationShaderState(viewport,
923 									scissor,
924 									*pipelineLayout,
925 									*renderPass,
926 									0u,
927 									*vertShader)
928 					.setupFragmentShaderState(*pipelineLayout,
929 									*renderPass,
930 									0u,
931 									*fragShader,
932 									DE_NULL,
933 									DE_NULL,
934 									&specializationInfo)
935 					.setupFragmentOutputState(*renderPass, 0u, &colorBlendInfo)
936 					.setMonolithicPipelineLayout(*pipelineLayout)
937 					.buildPipeline();
938 
939 	// Framebuffer.
940 	const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), extent.width, extent.height);
941 
942 	// Command pool and buffer.
943 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
944 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
945 	const auto cmdBuffer	= cmdBufferPtr.get();
946 
947 	// Empty clear color for the framebuffer.
948 	VkClearValue zeroClearColor;
949 	deMemset(&zeroClearColor, 0, sizeof(zeroClearColor));
950 
951 	// Texture barriers to fill it before using it.
952 	const auto preClearBarrier = makeImageMemoryBarrier(
953 		0u,
954 		VK_ACCESS_TRANSFER_WRITE_BIT,
955 		VK_IMAGE_LAYOUT_UNDEFINED,
956 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
957 		texture.get(),
958 		colorSubresourceRange);
959 
960 	const auto postClearBarrier = makeImageMemoryBarrier(
961 		VK_ACCESS_TRANSFER_WRITE_BIT,
962 		VK_ACCESS_SHADER_READ_BIT,
963 		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
964 		VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
965 		texture.get(),
966 		colorSubresourceRange);
967 
968 	// Record and submit.
969 	beginCommandBuffer(vkd, cmdBuffer);
970 
971 	// Prepare texture.
972 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preClearBarrier);
973 	vkd.cmdClearColorImage(cmdBuffer, texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_params.textureColor, 1u, &colorSubresourceRange);
974 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &postClearBarrier);
975 
976 	// Read from the texture to render a full-screen quad to the color buffer.
977 	beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor[0], zeroClearColor);
978 	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.getPipeline());
979 	vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
980 	vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u);
981 	endRenderPass(vkd, cmdBuffer);
982 
983 	endCommandBuffer(vkd, cmdBuffer);
984 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
985 
986 	// Verify color buffer.
987 	const auto	renderSize				= tcu::UVec2(extent.width, extent.height);
988 	const auto	colorAttachmentLevel	= readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment.get(), colorAttachmentFormat, renderSize);
989 	const auto	colorPixels				= colorAttachmentLevel->getAccess();
990 	const auto	tcuTextureFormat		= mapVkFormat(m_params.textureFormat);
991 	const auto	borderColor				= getBorderClearColorValue(m_params);
992 	const auto	expectedColor			= getExpectedColor(borderColor, m_params);
993 	std::string	resultMsg;
994 
995 	if (!comparePixelToColorClearValue(m_params, colorPixels, tcuTextureFormat, expectedColor, resultMsg))
996 		TCU_FAIL(resultMsg);
997 
998 	return tcu::TestStatus::pass(resultMsg);
999 }
1000 
1001 using ComponentSwizzleArray = std::array<VkComponentSwizzle, 4>;
1002 
1003 // Convert the component swizzle array to a component mapping structure.
makeComponentMapping(VkComponentMapping & mapping,const ComponentSwizzleArray & array)1004 void makeComponentMapping(VkComponentMapping& mapping, const ComponentSwizzleArray& array)
1005 {
1006 	mapping.r = array[0];
1007 	mapping.g = array[1];
1008 	mapping.b = array[2];
1009 	mapping.a = array[3];
1010 }
1011 
swizzleArrayToString(const ComponentSwizzleArray & swizzles)1012 std::string swizzleArrayToString(const ComponentSwizzleArray& swizzles)
1013 {
1014 	std::ostringstream stream;
1015 
1016 	for (const auto& s : swizzles)
1017 	{
1018 		switch (s)
1019 		{
1020 		case VK_COMPONENT_SWIZZLE_IDENTITY:	stream << "i"; break;
1021 		case VK_COMPONENT_SWIZZLE_ZERO:		stream << "0"; break;
1022 		case VK_COMPONENT_SWIZZLE_ONE:		stream << "1"; break;
1023 		case VK_COMPONENT_SWIZZLE_R:		stream << "r"; break;
1024 		case VK_COMPONENT_SWIZZLE_G:		stream << "g"; break;
1025 		case VK_COMPONENT_SWIZZLE_B:		stream << "b"; break;
1026 		case VK_COMPONENT_SWIZZLE_A:		stream << "a"; break;
1027 		default:
1028 			DE_ASSERT(false); break;
1029 		}
1030 	}
1031 
1032 	return stream.str();
1033 }
1034 
1035 // Generate mapping permutations for the swizzle components.
1036 // Note: using every permutation for component swizzle values results in 7^4=2401 combinations, which are too many.
genMappingPermutations()1037 std::vector<ComponentSwizzleArray> genMappingPermutations ()
1038 {
1039 	std::vector<ComponentSwizzleArray>	result;
1040 	const ComponentSwizzleArray			standardSwizzle	= {{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }};
1041 
1042 	// Standard normal swizzle.
1043 	result.push_back(standardSwizzle);
1044 
1045 	// Add a few combinations with rotated swizzles.
1046 	for (size_t rotations = 1u; rotations < standardSwizzle.size(); ++rotations)
1047 	{
1048 		ComponentSwizzleArray rotatedSwizzle = standardSwizzle;
1049 		std::rotate(rotatedSwizzle.begin(), rotatedSwizzle.begin() + rotations, rotatedSwizzle.end());
1050 		result.push_back(rotatedSwizzle);
1051 	}
1052 
1053 	// Try placing each special value in each of the positions.
1054 	VkComponentSwizzle specialSwizzles[] = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ZERO };
1055 	for (const auto& special : specialSwizzles)
1056 	{
1057 		for (size_t pos = 0; pos < standardSwizzle.size(); ++pos)
1058 		{
1059 			ComponentSwizzleArray newArray = standardSwizzle;
1060 			newArray[pos] = special;
1061 			result.push_back(newArray);
1062 		}
1063 	}
1064 
1065 	return result;
1066 }
1067 
gatherIndexToString(int gatherIndex)1068 std::string gatherIndexToString(int gatherIndex)
1069 {
1070 	if (gatherIndex < 0)
1071 		return "no_gather";
1072 	return "gather_" + std::to_string(gatherIndex);
1073 }
1074 
isIntegerBorder(VkBorderColor borderType)1075 bool isIntegerBorder (VkBorderColor borderType)
1076 {
1077 	bool isInt = false;
1078 	switch (borderType)
1079 	{
1080 	case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
1081 	case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
1082 	case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
1083 	case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
1084 		isInt = false; break;
1085 	case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
1086 	case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
1087 	case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
1088 	case VK_BORDER_COLOR_INT_CUSTOM_EXT:
1089 		isInt = true; break;
1090 	default:
1091 		DE_ASSERT(false); break;
1092 	}
1093 
1094 	return isInt;
1095 }
1096 
getRandomBorderCoordinates(de::Random & rnd)1097 tcu::Vec2 getRandomBorderCoordinates (de::Random& rnd)
1098 {
1099 	tcu::Vec2 coords;
1100 
1101 	// Two bits to decide which coordinates will be out of range (at least one).
1102 	const deUint32 outOfRangeMask = static_cast<deUint32>(rnd.getInt(1, 3));
1103 
1104 	for (int i = 0; i < 2; ++i)
1105 	{
1106 		// 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.
1107 		bool	outOfRange	= (outOfRangeMask & (1<<i));
1108 		bool	negative	= (outOfRange && rnd.getBool());
1109 		float	minCoord	= (outOfRange ? 1.1f : 0.0f);
1110 		float	maxCoord	= (outOfRange ? 5.0f : 0.9f);
1111 		float	value		= (negative ? -1.0f : 1.0f) * rnd.getFloat(minCoord, maxCoord);
1112 
1113 		coords[i] = value;
1114 	}
1115 
1116 	return coords;
1117 }
1118 
1119 // Generate a random clear color usable for the given format.
getRandomClearColor(VkFormat format,de::Random & rnd)1120 VkClearColorValue getRandomClearColor (VkFormat format, de::Random& rnd)
1121 {
1122 	VkClearColorValue color;
1123 	deMemset(&color, 0, sizeof(color));
1124 
1125 	const auto		tcuFormat		= mapVkFormat(format);
1126 	const auto		numComponents	= tcu::getNumUsedChannels(tcuFormat.order);
1127 	const auto		formatType		= getFormatType(format);
1128 
1129 	for (int i = 0; i < numComponents; ++i)
1130 	{
1131 		if (formatType == FormatType::SIGNED_INT || formatType == FormatType::UNSIGNED_INT)
1132 		{
1133 			const auto		componentSize	= tcu::getChannelSize(tcuFormat.type);
1134 
1135 			DE_ASSERT(componentSize > 0);
1136 
1137 			const deUint64	mask			= (1ull << (componentSize*8)) - 1ull;
1138 			const deUint64	signBit			= (1ull << (componentSize*8-1));
1139 			const deUint64	signMask		= (~mask); // Used to extend the sign bit.
1140 			const auto value = rnd.getUint64();
1141 
1142 			if (formatType == FormatType::SIGNED_INT)
1143 			{
1144 				// Extend sign bit for negative values.
1145 				auto finalValue = (value & mask);
1146 				if (finalValue & signBit)
1147 					finalValue |= signMask;
1148 				color.int32[i] = static_cast<deInt32>(finalValue);
1149 			}
1150 			else
1151 				color.uint32[i] = static_cast<deUint32>(value & mask);
1152 		}
1153 		else
1154 			color.float32[i] = rnd.getFloat();
1155 	}
1156 
1157 	return color;
1158 }
1159 
1160 } // anonymous
1161 
createSamplerBorderSwizzleTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1162 tcu::TestCaseGroup* createSamplerBorderSwizzleTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1163 {
1164 	const deUint32 baseSeed = 1610707317u;
1165 
1166 	const VkFormat textureFormats[] =
1167 	{
1168 		//VK_FORMAT_UNDEFINED,
1169 		VK_FORMAT_R4G4_UNORM_PACK8,
1170 		VK_FORMAT_R4G4B4A4_UNORM_PACK16,
1171 		VK_FORMAT_B4G4R4A4_UNORM_PACK16,
1172 		VK_FORMAT_R5G6B5_UNORM_PACK16,
1173 		VK_FORMAT_B5G6R5_UNORM_PACK16,
1174 		VK_FORMAT_R5G5B5A1_UNORM_PACK16,
1175 		VK_FORMAT_B5G5R5A1_UNORM_PACK16,
1176 		VK_FORMAT_A1R5G5B5_UNORM_PACK16,
1177 		VK_FORMAT_R8_UNORM,
1178 		VK_FORMAT_R8_SNORM,
1179 		//VK_FORMAT_R8_USCALED,
1180 		//VK_FORMAT_R8_SSCALED,
1181 		VK_FORMAT_R8_UINT,
1182 		VK_FORMAT_R8_SINT,
1183 		VK_FORMAT_R8_SRGB,
1184 		VK_FORMAT_R8G8_UNORM,
1185 		VK_FORMAT_R8G8_SNORM,
1186 		//VK_FORMAT_R8G8_USCALED,
1187 		//VK_FORMAT_R8G8_SSCALED,
1188 		VK_FORMAT_R8G8_UINT,
1189 		VK_FORMAT_R8G8_SINT,
1190 		VK_FORMAT_R8G8_SRGB,
1191 		VK_FORMAT_R8G8B8_UNORM,
1192 		VK_FORMAT_R8G8B8_SNORM,
1193 		//VK_FORMAT_R8G8B8_USCALED,
1194 		//VK_FORMAT_R8G8B8_SSCALED,
1195 		VK_FORMAT_R8G8B8_UINT,
1196 		VK_FORMAT_R8G8B8_SINT,
1197 		VK_FORMAT_R8G8B8_SRGB,
1198 		VK_FORMAT_B8G8R8_UNORM,
1199 		VK_FORMAT_B8G8R8_SNORM,
1200 		//VK_FORMAT_B8G8R8_USCALED,
1201 		//VK_FORMAT_B8G8R8_SSCALED,
1202 		VK_FORMAT_B8G8R8_UINT,
1203 		VK_FORMAT_B8G8R8_SINT,
1204 		VK_FORMAT_B8G8R8_SRGB,
1205 		VK_FORMAT_R8G8B8A8_UNORM,
1206 		VK_FORMAT_R8G8B8A8_SNORM,
1207 		//VK_FORMAT_R8G8B8A8_USCALED,
1208 		//VK_FORMAT_R8G8B8A8_SSCALED,
1209 		VK_FORMAT_R8G8B8A8_UINT,
1210 		VK_FORMAT_R8G8B8A8_SINT,
1211 		VK_FORMAT_R8G8B8A8_SRGB,
1212 		VK_FORMAT_B8G8R8A8_UNORM,
1213 		VK_FORMAT_B8G8R8A8_SNORM,
1214 		//VK_FORMAT_B8G8R8A8_USCALED,
1215 		//VK_FORMAT_B8G8R8A8_SSCALED,
1216 		VK_FORMAT_B8G8R8A8_UINT,
1217 		VK_FORMAT_B8G8R8A8_SINT,
1218 		VK_FORMAT_B8G8R8A8_SRGB,
1219 		 VK_FORMAT_A8B8G8R8_UNORM_PACK32,
1220 		 VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1221 		// VK_FORMAT_A8B8G8R8_USCALED_PACK32,
1222 		// VK_FORMAT_A8B8G8R8_SSCALED_PACK32,
1223 		// VK_FORMAT_A8B8G8R8_UINT_PACK32,
1224 		// VK_FORMAT_A8B8G8R8_SINT_PACK32,
1225 		// VK_FORMAT_A8B8G8R8_SRGB_PACK32,
1226 		VK_FORMAT_A2R10G10B10_UNORM_PACK32,
1227 		VK_FORMAT_A2R10G10B10_SNORM_PACK32,
1228 		// VK_FORMAT_A2R10G10B10_USCALED_PACK32,
1229 		// VK_FORMAT_A2R10G10B10_SSCALED_PACK32,
1230 		// VK_FORMAT_A2R10G10B10_UINT_PACK32,
1231 		// VK_FORMAT_A2R10G10B10_SINT_PACK32,
1232 		VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1233 		VK_FORMAT_A2B10G10R10_SNORM_PACK32,
1234 		// VK_FORMAT_A2B10G10R10_USCALED_PACK32,
1235 		// VK_FORMAT_A2B10G10R10_SSCALED_PACK32,
1236 		// VK_FORMAT_A2B10G10R10_UINT_PACK32,
1237 		// VK_FORMAT_A2B10G10R10_SINT_PACK32,
1238 		VK_FORMAT_R16_UNORM,
1239 		VK_FORMAT_R16_SNORM,
1240 		//VK_FORMAT_R16_USCALED,
1241 		//VK_FORMAT_R16_SSCALED,
1242 		VK_FORMAT_R16_UINT,
1243 		VK_FORMAT_R16_SINT,
1244 		VK_FORMAT_R16_SFLOAT,
1245 		VK_FORMAT_R16G16_UNORM,
1246 		VK_FORMAT_R16G16_SNORM,
1247 		//VK_FORMAT_R16G16_USCALED,
1248 		//VK_FORMAT_R16G16_SSCALED,
1249 		VK_FORMAT_R16G16_UINT,
1250 		VK_FORMAT_R16G16_SINT,
1251 		VK_FORMAT_R16G16_SFLOAT,
1252 		VK_FORMAT_R16G16B16_UNORM,
1253 		VK_FORMAT_R16G16B16_SNORM,
1254 		//VK_FORMAT_R16G16B16_USCALED,
1255 		//VK_FORMAT_R16G16B16_SSCALED,
1256 		VK_FORMAT_R16G16B16_UINT,
1257 		VK_FORMAT_R16G16B16_SINT,
1258 		VK_FORMAT_R16G16B16_SFLOAT,
1259 		VK_FORMAT_R16G16B16A16_UNORM,
1260 		VK_FORMAT_R16G16B16A16_SNORM,
1261 		//VK_FORMAT_R16G16B16A16_USCALED,
1262 		//VK_FORMAT_R16G16B16A16_SSCALED,
1263 		VK_FORMAT_R16G16B16A16_UINT,
1264 		VK_FORMAT_R16G16B16A16_SINT,
1265 		VK_FORMAT_R16G16B16A16_SFLOAT,
1266 		VK_FORMAT_R32_UINT,
1267 		VK_FORMAT_R32_SINT,
1268 		VK_FORMAT_R32_SFLOAT,
1269 		VK_FORMAT_R32G32_UINT,
1270 		VK_FORMAT_R32G32_SINT,
1271 		VK_FORMAT_R32G32_SFLOAT,
1272 		VK_FORMAT_R32G32B32_UINT,
1273 		VK_FORMAT_R32G32B32_SINT,
1274 		VK_FORMAT_R32G32B32_SFLOAT,
1275 		VK_FORMAT_R32G32B32A32_UINT,
1276 		VK_FORMAT_R32G32B32A32_SINT,
1277 		VK_FORMAT_R32G32B32A32_SFLOAT,
1278 	};
1279 
1280 	const auto mappingPermutations = genMappingPermutations();
1281 
1282 	const struct
1283 	{
1284 		VkBorderColor	borderType;
1285 		const char*		borderTypeName;
1286 	}
1287 	borderColors[] =
1288 	{
1289 		{	VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,	"transparent_black"	},
1290 		{	VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,		"transparent_black"	},
1291 		{	VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK,			"opaque_black"		},
1292 		{	VK_BORDER_COLOR_INT_OPAQUE_BLACK,			"opaque_black"		},
1293 		{	VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,			"opaque_white"		},
1294 		{	VK_BORDER_COLOR_INT_OPAQUE_WHITE,			"opaque_white"		},
1295 		{	VK_BORDER_COLOR_FLOAT_CUSTOM_EXT,			"custom"			},
1296 		{	VK_BORDER_COLOR_INT_CUSTOM_EXT,				"custom"			},
1297 	};
1298 
1299 	const struct
1300 	{
1301 		bool		useSwizzleHint;
1302 		const char*	name;
1303 	} swizzleHintCases[] =
1304 	{
1305 		{ false,	"no_swizzle_hint"	},
1306 		{ true,		"with_swizzle_hint"	},
1307 	};
1308 
1309 	de::MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, "border_swizzle", "Border color swizzle tests"));
1310 
1311 	for (const auto& format : textureFormats)
1312 	{
1313 		const auto						skip		= std::strlen("VK_FORMAT_");
1314 		const std::string				formatName	= de::toLower(std::string(getFormatName(format)).substr(skip));
1315 		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, formatName.c_str(), ""));
1316 
1317 		for (size_t mappingIdx = 0u; mappingIdx < mappingPermutations.size(); ++mappingIdx)
1318 		{
1319 			const auto&						mapping			= mappingPermutations[mappingIdx];
1320 			de::MovePtr<tcu::TestCaseGroup>	mappingGroup	(new tcu::TestCaseGroup(testCtx, swizzleArrayToString(mapping).c_str(), ""));
1321 
1322 			for (int borderColorIdx = 0; borderColorIdx < DE_LENGTH_OF_ARRAY(borderColors); ++borderColorIdx)
1323 			{
1324 				const auto&						borderColor		= borderColors[borderColorIdx];
1325 				de::MovePtr<tcu::TestCaseGroup>	borderTypeGroup	(new tcu::TestCaseGroup(testCtx, borderColor.borderTypeName, ""));
1326 
1327 				const auto formatType	= getFormatType(format);
1328 				const auto isIntBorder	= isIntegerBorder(borderColor.borderType);
1329 
1330 				// Skip cases that do not make sense for the format and border type combination.
1331 				if (isIntBorder && formatType == FormatType::FLOAT)
1332 					continue;
1333 				else if (!isIntBorder && formatType != FormatType::FLOAT)
1334 					continue;
1335 
1336 				for (int gatherIdx = -1; gatherIdx <= 3; ++gatherIdx)
1337 				{
1338 					const auto						componentGather	= gatherIndexToString(gatherIdx);
1339 					de::MovePtr<tcu::TestCaseGroup>	gatherGroup		(new tcu::TestCaseGroup(testCtx, componentGather.c_str(), ""));
1340 
1341 					for (const auto& swizzleHint : swizzleHintCases)
1342 					{
1343 						TestParams params;
1344 
1345 						const deUint32	seed	= baseSeed + static_cast<deUint32>(format) + static_cast<deUint32>(mappingIdx) + static_cast<deUint32>(borderColorIdx) + static_cast<deUint32>(gatherIdx);
1346 						de::Random		rnd		(seed);
1347 
1348 						params.pipelineConstructionType	= pipelineConstructionType;
1349 						params.textureFormat			= format;
1350 						params.textureColor				= getRandomClearColor(format, rnd);
1351 
1352 						makeComponentMapping(params.componentMapping, mapping);
1353 						params.borderColor			= borderColor.borderType;
1354 						params.componentGather		= ((gatherIdx < 0) ? tcu::nothing<int>() : tcu::just(gatherIdx));
1355 						params.textureCoordinates	= getRandomBorderCoordinates(rnd);
1356 
1357 						if (params.isCustom())
1358 							params.customBorderColor = tcu::just(getRandomClearColor(format, rnd));
1359 						else
1360 							params.customBorderColor = tcu::nothing<VkClearColorValue>();
1361 
1362 						params.useSamplerSwizzleHint = swizzleHint.useSwizzleHint;
1363 
1364 						gatherGroup->addChild(new BorderSwizzleCase(testCtx, swizzleHint.name, "", params));
1365 					}
1366 
1367 					borderTypeGroup->addChild(gatherGroup.release());
1368 				}
1369 
1370 				mappingGroup->addChild(borderTypeGroup.release());
1371 			}
1372 
1373 			formatGroup->addChild(mappingGroup.release());
1374 		}
1375 
1376 		mainGroup->addChild(formatGroup.release());
1377 	}
1378 
1379 	return mainGroup.release();
1380 }
1381 
1382 } // pipeline
1383 } // vkt
1384 
1385 
1386 
1387