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