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