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