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 ¶ms);
~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 ¶ms)
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