| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2021 The Khronos Group Inc. |
| * Copyright (c) 2021 Valve Corporation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Border color swizzle tests |
| *//*--------------------------------------------------------------------*/ |
| #include "vktPipelineSamplerBorderSwizzleTests.hpp" |
| #include "vktPipelineImageUtil.hpp" |
| |
| #include "vkImageUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkImageWithMemory.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkBarrierUtil.hpp" |
| |
| #include "tcuMaybe.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuFloat.hpp" |
| |
| #include "deRandom.hpp" |
| |
| #include <string> |
| #include <sstream> |
| #include <array> |
| #include <cstring> |
| #include <algorithm> |
| |
| namespace vkt |
| { |
| namespace pipeline |
| { |
| |
| namespace |
| { |
| |
| using namespace vk; |
| |
| // Returns true if the mapping doesn't alter each component. |
| bool isIdentitySwizzle (const VkComponentMapping& mapping) |
| { |
| return ( |
| (mapping.r == VK_COMPONENT_SWIZZLE_R || mapping.r == VK_COMPONENT_SWIZZLE_IDENTITY) && |
| (mapping.g == VK_COMPONENT_SWIZZLE_G || mapping.g == VK_COMPONENT_SWIZZLE_IDENTITY) && |
| (mapping.b == VK_COMPONENT_SWIZZLE_B || mapping.b == VK_COMPONENT_SWIZZLE_IDENTITY) && |
| (mapping.a == VK_COMPONENT_SWIZZLE_A || mapping.a == VK_COMPONENT_SWIZZLE_IDENTITY) |
| ); |
| } |
| |
| struct TestParams |
| { |
| VkFormat textureFormat; |
| VkClearColorValue textureColor; |
| VkComponentMapping componentMapping; |
| VkBorderColor borderColor; |
| tcu::Maybe<int> componentGather; |
| bool useSamplerSwizzleHint; |
| |
| // Pseudorandom elements. |
| tcu::Vec2 textureCoordinates; |
| tcu::Maybe<VkClearColorValue> customBorderColor; |
| |
| bool isCustom (void) const |
| { |
| return (borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT || borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT); |
| } |
| |
| bool isOpaqueBlack (void) const |
| { |
| return (borderColor == VK_BORDER_COLOR_INT_OPAQUE_BLACK || borderColor == VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK); |
| } |
| |
| bool isIdentity (void) const |
| { |
| return isIdentitySwizzle(componentMapping); |
| } |
| }; |
| |
| struct SpecConstants |
| { |
| float u; |
| float v; |
| deInt32 gatherFlag; |
| //deInt32 gatherComp; |
| }; |
| |
| class BorderSwizzleCase : public vkt::TestCase |
| { |
| public: |
| BorderSwizzleCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params); |
| virtual ~BorderSwizzleCase (void) {} |
| |
| virtual void initPrograms (vk::SourceCollections& programCollection) const; |
| virtual TestInstance* createInstance (Context& context) const; |
| virtual void checkSupport (Context& context) const; |
| |
| protected: |
| TestParams m_params; |
| }; |
| |
| class BorderSwizzleInstance : public vkt::TestInstance |
| { |
| public: |
| BorderSwizzleInstance (Context& context, const TestParams ¶ms); |
| virtual ~BorderSwizzleInstance (void) {} |
| |
| VkExtent3D getImageExtent (void) const; |
| virtual tcu::TestStatus iterate (void); |
| |
| protected: |
| TestParams m_params; |
| }; |
| |
| BorderSwizzleCase::BorderSwizzleCase(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params) |
| : vkt::TestCase (testCtx, name, description) |
| , m_params (params) |
| { |
| } |
| |
| void BorderSwizzleCase::checkSupport (Context& context) const |
| { |
| const auto& vki = context.getInstanceInterface(); |
| const auto physicalDevice = context.getPhysicalDevice(); |
| VkImageFormatProperties formatProperties; |
| |
| const auto result = vki.getPhysicalDeviceImageFormatProperties( |
| 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); |
| |
| if (result != VK_SUCCESS) |
| { |
| if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| TCU_THROW(NotSupportedError, "Format not supported for sampling"); |
| TCU_FAIL("vkGetPhysicalDeviceImageFormatProperties returned " + de::toString(result)); |
| } |
| |
| const auto& borderColorFeatures = context.getCustomBorderColorFeaturesEXT(); |
| const auto& borderSwizzleFeatures = context.getBorderColorSwizzleFeaturesEXT(); |
| const bool identity = m_params.isIdentity(); |
| |
| if (m_params.useSamplerSwizzleHint) |
| context.requireDeviceFunctionality("VK_EXT_border_color_swizzle"); |
| |
| if (m_params.isCustom()) |
| { |
| if (!borderColorFeatures.customBorderColors) |
| TCU_THROW(NotSupportedError, "Custom border colors not supported"); |
| |
| if (!identity) |
| { |
| if (!borderSwizzleFeatures.borderColorSwizzle) |
| TCU_THROW(NotSupportedError, "Custom border color with non-identity swizzle not supported"); |
| |
| if (!m_params.useSamplerSwizzleHint && !borderSwizzleFeatures.borderColorSwizzleFromImage) |
| TCU_THROW(NotSupportedError, "Custom border color with non-identity swizzle not supported without specifying sampler border mapping"); |
| } |
| } |
| else if (m_params.isOpaqueBlack()) |
| { |
| if (!identity) |
| { |
| if (!borderSwizzleFeatures.borderColorSwizzle) |
| TCU_THROW(NotSupportedError, "Opaque black with non-identity swizzle not supported"); |
| |
| if (!m_params.useSamplerSwizzleHint && !borderSwizzleFeatures.borderColorSwizzleFromImage) |
| TCU_THROW(NotSupportedError, "Opaque black with non-identity swizzle not supported without specifying sampler border mapping"); |
| } |
| } |
| } |
| |
| enum class FormatType |
| { |
| SIGNED_INT = 0, |
| UNSIGNED_INT, |
| FLOAT, |
| }; |
| |
| FormatType getFormatType (VkFormat format) |
| { |
| if (isIntFormat(format)) |
| return FormatType::SIGNED_INT; |
| |
| if (isUintFormat(format)) |
| return FormatType::UNSIGNED_INT; |
| |
| return FormatType::FLOAT; |
| } |
| |
| // Output color attachment format will vary slightly with the chosen texture format to accomodate different clear colors. |
| VkFormat getColorAttachmentFormat (VkFormat textureFormat) |
| { |
| const auto formatType = getFormatType(textureFormat); |
| |
| if (formatType == FormatType::SIGNED_INT) |
| return VK_FORMAT_R32G32B32A32_SINT; |
| |
| if (formatType == FormatType::UNSIGNED_INT) |
| return VK_FORMAT_R32G32B32A32_UINT; |
| |
| return VK_FORMAT_R32G32B32A32_SFLOAT; |
| } |
| |
| void BorderSwizzleCase::initPrograms (vk::SourceCollections& programCollection) const |
| { |
| std::ostringstream vert; |
| vert |
| << "#version 450\n" |
| << "\n" |
| << "void main()\n" |
| << "{\n" |
| // Full-screen clockwise triangle fan with 4 vertices. |
| << " const float x = (-1.0+2.0*(((gl_VertexIndex+1)&2)>>1));\n" |
| << " const float y = (-1.0+2.0*(( gl_VertexIndex &2)>>1));\n" |
| << " gl_Position = vec4(x, y, 0.0, 1.0);\n" |
| << "}\n" |
| ; |
| |
| const auto formatType = getFormatType(m_params.textureFormat); |
| |
| std::string prefix; |
| if (formatType == FormatType::SIGNED_INT) |
| prefix = "i"; |
| else if (formatType == FormatType::UNSIGNED_INT) |
| prefix = "u"; |
| |
| const std::string samplerType = prefix + "sampler2D"; |
| const std::string outColorType = prefix + "vec4"; |
| // Note: glslang will complain if the gather component is not a compile-time constant. |
| const int gatherComp = (m_params.componentGather ? m_params.componentGather.get() : 0); |
| |
| // Note the spec constants here should match the SpecConstants structure. |
| std::ostringstream frag; |
| frag |
| << "#version 450\n" |
| << "\n" |
| << "layout (constant_id=0) const float u = 0.0f;\n" |
| << "layout (constant_id=1) const float v = 0.0f;\n" |
| << "layout (constant_id=2) const int gatherFlag = 0;\n" |
| //<< "layout (constant_id=3) const int gatherComp = 0;\n" |
| << "\n" |
| << "layout (set=0, binding=0) uniform " << samplerType << " texSampler;\n" |
| << "\n" |
| << "layout (location=0) out " << outColorType << " colorOut;\n" |
| << "\n" |
| << "void main()\n" |
| << "{\n" |
| << " const vec2 coords = vec2(u, v);\n" |
| << "\n" |
| << " if (gatherFlag != 0)\n" |
| << " {\n" |
| << " colorOut = textureGather(texSampler, coords, " << gatherComp << ");\n" |
| << " }\n" |
| << " else\n" |
| << " {\n" |
| << " colorOut = texture(texSampler, coords);\n" |
| << " }\n" |
| << "}\n" |
| ; |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()); |
| programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); |
| } |
| |
| TestInstance* BorderSwizzleCase::createInstance (Context& context) const |
| { |
| return new BorderSwizzleInstance(context, m_params); |
| } |
| |
| BorderSwizzleInstance::BorderSwizzleInstance (Context& context, const TestParams ¶ms) |
| : vkt::TestInstance (context) |
| , m_params (params) |
| {} |
| |
| VkExtent3D BorderSwizzleInstance::getImageExtent (void) const |
| { |
| return makeExtent3D(16u, 16u, 1u); |
| } |
| |
| // Reinterprets the exponent and mantissa in the floating point number as an integer. |
| // Function copied from vktApiImageClearingTests.cpp but changed return type to deUint64. |
| deUint64 calcFloatDiff (float a, float b) |
| { |
| const int asign = tcu::Float32(a).sign(); |
| const int bsign = tcu::Float32(a).sign(); |
| |
| const deUint32 avalue = (tcu::Float32(a).bits() & ((0x1u << 31u) - 1u)); |
| const deUint32 bvalue = (tcu::Float32(b).bits() & ((0x1u << 31u) - 1u)); |
| |
| if (asign != bsign) |
| return avalue + bvalue + 1u; |
| else if (avalue < bvalue) |
| return bvalue - avalue; |
| else |
| return avalue - bvalue; |
| } |
| |
| // Convert VkComponentMapping to an array of 4 VkComponentSwizzle elements. |
| tcu::Vector<VkComponentSwizzle, 4> makeComponentSwizzleVec(const VkComponentMapping& mapping) |
| { |
| const tcu::Vector<VkComponentSwizzle, 4> result = {{ mapping.r, mapping.g, mapping.b, mapping.a }}; |
| return result; |
| } |
| |
| // Apply swizzling to an array of 4 elements. |
| template <typename T> |
| tcu::Vector<T, 4> applySwizzle (const tcu::Vector<T, 4>& orig, const VkComponentMapping& mapping) |
| { |
| const auto swizzles = makeComponentSwizzleVec(mapping); |
| tcu::Vector<T, 4> result; |
| |
| for (int i = 0; i < decltype(swizzles)::SIZE; ++i) |
| { |
| const auto cs = swizzles[i]; |
| DE_ASSERT(cs >= VK_COMPONENT_SWIZZLE_IDENTITY && cs <= VK_COMPONENT_SWIZZLE_A); |
| |
| if (cs == VK_COMPONENT_SWIZZLE_IDENTITY) |
| result[i] = orig[i]; |
| else if (cs == VK_COMPONENT_SWIZZLE_ZERO) |
| result[i] = static_cast<T>(0); |
| else if (cs == VK_COMPONENT_SWIZZLE_ONE) |
| result[i] = static_cast<T>(1); |
| else |
| result[i] = orig[cs - VK_COMPONENT_SWIZZLE_R]; |
| } |
| |
| return result; |
| } |
| |
| // Apply gathering to an array of 4 elements. |
| template <typename T> |
| tcu::Vector<T, 4> applyGather (const tcu::Vector<T, 4>& orig, int compNum) |
| { |
| tcu::Vector<T, 4> result; |
| |
| for (int i = 0; i < decltype(result)::SIZE; ++i) |
| result[i] = orig[compNum]; |
| |
| return result; |
| } |
| |
| // Transforms an input border color, once expanded, to the expected output color. |
| template <typename T> |
| tcu::Vector<T, 4> getExpectedColor (const tcu::Vector<T, 4>& color, const TestParams& params) |
| { |
| tcu::Vector<T, 4> result = color; |
| |
| result = applySwizzle(result, params.componentMapping); |
| |
| if (params.componentGather) |
| result = applyGather(result, *params.componentGather); |
| |
| return result; |
| } |
| |
| // Transforms an input border color to the expected output color. |
| // Uses the proper union member depending on the test parameters and takes into account "Conversion to RGBA" from the spec. |
| VkClearColorValue getExpectedColor (const VkClearColorValue& color, const TestParams& params) |
| { |
| const auto numComp = tcu::getNumUsedChannels(mapVkFormat(params.textureFormat).order); |
| const auto formatType = getFormatType(params.textureFormat); |
| VkClearColorValue result; |
| |
| DE_ASSERT(numComp >= 0 && numComp <= 4); |
| |
| if (formatType == FormatType::UNSIGNED_INT) |
| { |
| tcu::UVec4 borderColor (0u, 0u, 0u, 0u); |
| |
| for (int i = 0; i < numComp; ++i) |
| borderColor[i] = color.uint32[i]; |
| |
| if (numComp < 4) |
| borderColor[3] = 1u; |
| |
| const auto expected = getExpectedColor(borderColor, params); |
| |
| for (int i = 0; i < decltype(expected)::SIZE; ++i) |
| result.uint32[i] = expected[i]; |
| } |
| else if (formatType == FormatType::SIGNED_INT) |
| { |
| tcu::IVec4 borderColor (0, 0, 0, 0); |
| |
| for (int i = 0; i < numComp; ++i) |
| borderColor[i] = color.int32[i]; |
| |
| if (numComp < 4) |
| borderColor[3] = 1; |
| |
| const auto expected = getExpectedColor(borderColor, params); |
| |
| for (int i = 0; i < decltype(expected)::SIZE; ++i) |
| result.int32[i] = expected[i]; |
| } |
| else |
| { |
| DE_ASSERT(formatType == FormatType::FLOAT); |
| |
| tcu::Vec4 borderColor (.0f, .0f, .0f, .0f); |
| |
| for (int i = 0; i < numComp; ++i) |
| borderColor[i] = color.float32[i]; |
| |
| if (numComp < 4) |
| borderColor[3] = 1.0f; |
| |
| const auto expected = getExpectedColor(borderColor, params); |
| |
| for (int i = 0; i < decltype(expected)::SIZE; ++i) |
| result.float32[i] = expected[i]; |
| } |
| |
| return result; |
| } |
| |
| // Compare color buffer to the expected border color. |
| // |
| // This method was copied from vktApiImageClearingTests.cpp and adapted to this use case: |
| // |
| // * Taking into account the texture format instead of the color buffer format when calculating acceptable thresholds. |
| // * Applying swizzles and gathering to said thresholds. |
| // * Making thresholds more strict for components that do not come from custom borders. |
| // * Checking the full image in a single pass. |
| // |
| // The color buffer format is supposed to be at least as precise as the texture format. |
| bool comparePixelToColorClearValue (const TestParams& params, |
| const tcu::ConstPixelBufferAccess& access, |
| const tcu::TextureFormat& textureFormat, |
| const VkClearColorValue& ref, |
| std::string& stringResult) |
| { |
| const auto bufferFormat = access.getFormat(); |
| const auto channelClass = getTextureChannelClass(textureFormat.type); |
| // We must compare all available channels in the color buffer to check RGBA conversion. |
| const auto channelMask = getTextureFormatChannelMask(bufferFormat); |
| |
| switch (channelClass) |
| { |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: |
| case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: |
| { |
| tcu::Vec4 refColor (ref.float32[0], |
| ref.float32[1], |
| ref.float32[2], |
| ref.float32[3]); |
| tcu::Vec4 threshold (0.0f); |
| |
| if (params.isCustom()) |
| { |
| // Relax thresholds for custom color components. |
| const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat)); |
| const int modifier = (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) ? 0 : 1; |
| |
| threshold = tcu::Vec4 (bitDepth[0] > 0 ? 1.0f / ((float)(1 << (bitDepth[0] - modifier)) - 1.0f) : 0.0f, |
| bitDepth[1] > 0 ? 1.0f / ((float)(1 << (bitDepth[1] - modifier)) - 1.0f) : 0.0f, |
| bitDepth[2] > 0 ? 1.0f / ((float)(1 << (bitDepth[2] - modifier)) - 1.0f) : 0.0f, |
| bitDepth[3] > 0 ? 1.0f / ((float)(1 << (bitDepth[3] - modifier)) - 1.0f) : 0.0f); |
| |
| if (isSRGB(textureFormat)) |
| { |
| // Widen thresholds a bit due to possible low-precision sRGB conversions. |
| for (int i = 0; i < decltype(threshold)::SIZE; ++i) |
| threshold[i] *= 2.0f; |
| } |
| } |
| |
| // Apply swizzle and gather to thresholds. |
| threshold = applySwizzle(threshold, params.componentMapping); |
| |
| if (params.componentGather) |
| threshold = applyGather(threshold, *params.componentGather); |
| |
| for (int z = 0; z < access.getDepth(); ++z) |
| for (int y = 0; y < access.getHeight(); ++y) |
| for (int x = 0; x < access.getWidth(); ++x) |
| { |
| const tcu::Vec4 resColor (access.getPixel(x, y, z)); |
| const bool result = !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask)); |
| |
| if (!result || (x == 0 && y == 0 && z == 0)) |
| { |
| std::stringstream s; |
| s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor; |
| stringResult = s.str(); |
| } |
| |
| if (!result) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: |
| { |
| const tcu::UVec4 refColor (ref.uint32[0], |
| ref.uint32[1], |
| ref.uint32[2], |
| ref.uint32[3]); |
| tcu::UVec4 threshold (0u); |
| |
| if (params.isCustom()) |
| { |
| // Relax thresholds for custom color components. |
| const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat)); |
| |
| threshold = tcu::UVec4 ((bitDepth[0] > 0) ? 1 : 0, |
| (bitDepth[1] > 0) ? 1 : 0, |
| (bitDepth[2] > 0) ? 1 : 0, |
| (bitDepth[3] > 0) ? 1 : 0); |
| } |
| |
| // Apply swizzle and gather to thresholds. |
| threshold = applySwizzle(threshold, params.componentMapping); |
| |
| if (params.componentGather) |
| threshold = applyGather(threshold, *params.componentGather); |
| |
| for (int z = 0; z < access.getDepth(); ++z) |
| for (int y = 0; y < access.getHeight(); ++y) |
| for (int x = 0; x < access.getWidth(); ++x) |
| { |
| const tcu::UVec4 resColor (access.getPixelUint(x, y, z)); |
| const bool result = !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask)); |
| |
| if (!result || (x == 0 && y == 0 && z == 0)) |
| { |
| std::stringstream s; |
| s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor; |
| stringResult = s.str(); |
| } |
| |
| if (!result) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: |
| { |
| const tcu::IVec4 refColor (ref.int32[0], |
| ref.int32[1], |
| ref.int32[2], |
| ref.int32[3]); |
| tcu::IVec4 threshold (0); |
| |
| if (params.isCustom()) |
| { |
| // Relax thresholds for custom color components. |
| const tcu::IVec4 bitDepth (getTextureFormatBitDepth(textureFormat)); |
| |
| threshold = tcu::IVec4 ((bitDepth[0] > 0) ? 1 : 0, |
| (bitDepth[1] > 0) ? 1 : 0, |
| (bitDepth[2] > 0) ? 1 : 0, |
| (bitDepth[3] > 0) ? 1 : 0); |
| } |
| |
| // Apply swizzle and gather to thresholds. |
| threshold = applySwizzle(threshold, params.componentMapping); |
| |
| if (params.componentGather) |
| threshold = applyGather(threshold, *params.componentGather); |
| |
| for (int z = 0; z < access.getDepth(); ++z) |
| for (int y = 0; y < access.getHeight(); ++y) |
| for (int x = 0; x < access.getWidth(); ++x) |
| { |
| const tcu::IVec4 resColor (access.getPixelInt(x, y, z)); |
| const bool result = !(anyNotEqual(logicalAnd(lessThanEqual(absDiff(resColor, refColor), threshold), channelMask), channelMask)); |
| |
| if (!result || (x == 0 && y == 0 && z == 0)) |
| { |
| std::stringstream s; |
| s << "Ref:" << refColor << " Threshold:" << threshold << " Color:" << resColor; |
| stringResult = s.str(); |
| } |
| |
| if (!result) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: |
| { |
| using u64v4 = tcu::Vector<deUint64, 4>; |
| |
| const tcu::Vec4 refColor (ref.float32[0], |
| ref.float32[1], |
| ref.float32[2], |
| ref.float32[3]); |
| u64v4 threshold (0ull); |
| |
| if (params.isCustom()) |
| { |
| // Relax thresholds for custom color components. |
| const tcu::IVec4 mantissaBitsI (getTextureFormatMantissaBitDepth(textureFormat)); |
| const u64v4 mantissaBits (mantissaBitsI.x(), mantissaBitsI.y(), mantissaBitsI.z(), mantissaBitsI.w()); |
| |
| threshold = u64v4 ((mantissaBits[0] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[0])) : 0ull, |
| (mantissaBits[1] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[1])) : 0ull, |
| (mantissaBits[2] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[2])) : 0ull, |
| (mantissaBits[3] > 0ull) ? 10ull * (1ull << (23ull - mantissaBits[3])) : 0ull); |
| } |
| |
| // Apply swizzle and gather to thresholds. |
| threshold = applySwizzle(threshold, params.componentMapping); |
| |
| if (params.componentGather) |
| threshold = applyGather(threshold, *params.componentGather); |
| |
| DE_ASSERT(allEqual(greaterThanEqual(threshold, u64v4(0u)), tcu::BVec4(true))); |
| |
| for (int z = 0; z < access.getDepth(); ++z) |
| for (int y = 0; y < access.getHeight(); ++y) |
| for (int x = 0; x < access.getWidth(); ++x) |
| { |
| const tcu::Vec4 resColor (access.getPixel(x, y, z)); |
| |
| for (int ndx = 0; ndx < decltype(resColor)::SIZE; ndx++) |
| { |
| const bool result = !(calcFloatDiff(resColor[ndx], refColor[ndx]) > threshold[ndx] && channelMask[ndx]); |
| |
| if (!result || (x == 0 && y == 0 && z == 0)) |
| { |
| float floatThreshold = tcu::Float32((deUint32)(threshold)[0]).asFloat(); |
| tcu::Vec4 thresholdVec4 (floatThreshold, |
| floatThreshold, |
| floatThreshold, |
| floatThreshold); |
| std::stringstream s; |
| |
| s << "Ref:" << refColor << " Threshold:" << thresholdVec4 << " Color:" << resColor; |
| stringResult = s.str(); |
| } |
| |
| if (!result) |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| default: |
| DE_FATAL("Invalid channel class"); |
| return false; |
| } |
| } |
| |
| // Gets the clear color value from the border color. See "Texel Replacement" in the spec. |
| VkClearColorValue getBorderClearColorValue (const TestParams& params) |
| { |
| VkClearColorValue result; |
| deMemset(&result, 0, sizeof(result)); |
| |
| switch (params.borderColor) |
| { |
| case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: /* memset works. */ break; |
| case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK: /* memset works. */ break; |
| case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK: result.float32[3] = 1.0f; break; |
| case VK_BORDER_COLOR_INT_OPAQUE_BLACK: result.int32[3] = 1; break; |
| case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE: for (size_t i = 0; i < 4; ++i) result.float32[i] = 1.0f; break; |
| case VK_BORDER_COLOR_INT_OPAQUE_WHITE: for (size_t i = 0; i < 4; ++i) result.int32[i] = 1; break; |
| case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT: // fallthrough. |
| case VK_BORDER_COLOR_INT_CUSTOM_EXT: DE_ASSERT(params.customBorderColor); result = *params.customBorderColor; break; |
| default: DE_ASSERT(false); break; |
| } |
| |
| return result; |
| } |
| |
| tcu::TestStatus BorderSwizzleInstance::iterate (void) |
| { |
| const auto& vkd = m_context.getDeviceInterface(); |
| const auto device = m_context.getDevice(); |
| auto& alloc = m_context.getDefaultAllocator(); |
| const auto queue = m_context.getUniversalQueue(); |
| const auto qIndex = m_context.getUniversalQueueFamilyIndex(); |
| const auto extent = getImageExtent(); |
| const auto custom = m_params.isCustom(); |
| const auto colorAttachmentFormat = getColorAttachmentFormat(m_params.textureFormat); |
| const auto colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| |
| // Texture. |
| const VkImageCreateInfo textureCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| m_params.textureFormat, // VkFormat format; |
| extent, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| (VK_IMAGE_USAGE_SAMPLED_BIT // VkImageUsageFlags usage; |
| |VK_IMAGE_USAGE_TRANSFER_DST_BIT), |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // deUint32 queueFamilyIndexCount; |
| nullptr, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| ImageWithMemory texture (vkd, device, alloc, textureCreateInfo, MemoryRequirement::Any); |
| |
| const VkImageViewCreateInfo textureViewCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageViewCreateFlags flags; |
| texture.get(), // VkImage image; |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; |
| m_params.textureFormat, // VkFormat format; |
| m_params.componentMapping, // VkComponentMapping components; |
| colorSubresourceRange, // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| const auto textureView = createImageView(vkd, device, &textureViewCreateInfo); |
| |
| // Color attachment. |
| const VkImageCreateInfo colorAttachmentInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| VK_IMAGE_TYPE_2D, // VkImageType imageType; |
| colorAttachmentFormat, // VkFormat format; |
| extent, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
| | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // deUint32 queueFamilyIndexCount; |
| nullptr, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| ImageWithMemory colorAttachment (vkd, device, alloc, colorAttachmentInfo, MemoryRequirement::Any); |
| |
| const auto colorAttachmentView = makeImageView(vkd, device, colorAttachment.get(), VK_IMAGE_VIEW_TYPE_2D, colorAttachmentInfo.format, colorSubresourceRange); |
| |
| // Texure sampler. |
| de::MovePtr<VkSamplerCustomBorderColorCreateInfoEXT> customBorderColorInfo; |
| |
| const VkSamplerBorderColorComponentMappingCreateInfoEXT borderColorMappingInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT, |
| nullptr, |
| m_params.componentMapping, |
| isSrgbFormat(m_params.textureFormat), |
| }; |
| |
| const void* pNext = nullptr; |
| |
| if (custom) |
| { |
| customBorderColorInfo = de::MovePtr<VkSamplerCustomBorderColorCreateInfoEXT>(new VkSamplerCustomBorderColorCreateInfoEXT); |
| *customBorderColorInfo = initVulkanStructure(); |
| |
| DE_ASSERT(m_params.customBorderColor); |
| VkClearColorValue colorValue = m_params.customBorderColor.get(); |
| |
| if (m_params.useSamplerSwizzleHint) |
| customBorderColorInfo->pNext = &borderColorMappingInfo; |
| |
| // TODO: try combinations with customBorderColorWithoutFormat if supported? |
| customBorderColorInfo->format = m_params.textureFormat; |
| customBorderColorInfo->customBorderColor = colorValue; |
| |
| pNext = customBorderColorInfo.get(); |
| } |
| else |
| { |
| if (m_params.useSamplerSwizzleHint) |
| pNext = &borderColorMappingInfo; |
| } |
| |
| const VkSamplerCreateInfo samplerCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType; |
| pNext, // const void* pNext; |
| 0u, // VkSamplerCreateFlags flags; |
| VK_FILTER_NEAREST, // VkFilter magFilter; |
| VK_FILTER_NEAREST, // VkFilter minFilter; |
| VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode; |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, // VkSamplerAddressMode addressModeU; |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, // VkSamplerAddressMode addressModeV; |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, // VkSamplerAddressMode addressModeW; |
| 0u, // float mipLodBias; |
| VK_FALSE, // VkBool32 anisotropyEnable; |
| 0.0f, // float maxAnisotropy; |
| VK_FALSE, // VkBool32 compareEnable; |
| VK_COMPARE_OP_NEVER, // VkCompareOp compareOp; |
| 0.0f, // float minLod; |
| 1.0f, // float maxLod; |
| m_params.borderColor, // VkBorderColor borderColor; |
| VK_FALSE, // VkBool32 unnormalizedCoordinates; |
| }; |
| |
| const auto sampler = createSampler(vkd, device, &samplerCreateInfo); |
| |
| // Descriptor set layout. |
| DescriptorSetLayoutBuilder dsLayoutBuilder; |
| dsLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT); |
| const auto dsLayout = dsLayoutBuilder.build(vkd, device); |
| |
| // Pipeline layout. |
| const auto pipelineLayout = makePipelineLayout(vkd, device, dsLayout.get()); |
| |
| // Descriptor pool. |
| DescriptorPoolBuilder poolBuilder; |
| poolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); |
| const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| |
| // Descriptor set. |
| const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), dsLayout.get()); |
| |
| // Update descriptor set. |
| { |
| DescriptorSetUpdateBuilder updateBuilder; |
| VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(sampler.get(), textureView.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descriptorImageInfo); |
| updateBuilder.update(vkd, device); |
| } |
| |
| // Render pass. |
| const auto renderPass = makeRenderPass(vkd, device, colorAttachmentFormat); |
| |
| // Shader modules. |
| const auto vertShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u); |
| const auto fragShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u); |
| |
| // Pipeline. |
| const VkPipelineShaderStageCreateInfo vertStageInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; |
| vertShader.get(), // VkShaderModule module; |
| "main", // const char* pName; |
| nullptr, // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| const SpecConstants specConstantData = |
| { |
| m_params.textureCoordinates.x(), |
| m_params.textureCoordinates.y(), |
| (m_params.componentGather ? 1 : 0), |
| //(m_params.componentGather ? *m_params.componentGather : -1), |
| }; |
| |
| const VkSpecializationMapEntry specializationMap[] = |
| { |
| { 0u, offsetof(SpecConstants, u), sizeof(specConstantData.u) }, |
| { 1u, offsetof(SpecConstants, v), sizeof(specConstantData.v) }, |
| { 2u, offsetof(SpecConstants, gatherFlag), sizeof(specConstantData.gatherFlag) }, |
| //{ 3u, offsetof(SpecConstants, gatherComp), sizeof(specConstantData.gatherComp) }, |
| }; |
| |
| const VkSpecializationInfo specializationInfo = |
| { |
| static_cast<deUint32>(DE_LENGTH_OF_ARRAY(specializationMap)), // deUint32 mapEntryCount; |
| specializationMap, // const VkSpecializationMapEntry* pMapEntries; |
| static_cast<deUintptr>(sizeof(specConstantData)), // deUintptr dataSize; |
| &specConstantData, // const void* pData; |
| }; |
| |
| const VkPipelineShaderStageCreateInfo fragStageInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; |
| fragShader.get(), // VkShaderModule module; |
| "main", // const char* pName; |
| &specializationInfo, // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| const VkPipelineShaderStageCreateInfo shaderStagesInfo[] = { vertStageInfo, fragStageInfo }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputInfo = initVulkanStructure(); |
| |
| VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = initVulkanStructure(); |
| inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; |
| |
| const auto viewport = makeViewport(extent); |
| const auto scissor = makeRect2D(extent); |
| |
| const VkPipelineViewportStateCreateInfo viewportInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineViewportStateCreateFlags flags; |
| 1u, // deUint32 viewportCount; |
| &viewport, // const VkViewport* pViewports; |
| 1u, // deUint32 scissorCount; |
| &scissor, // const VkRect2D* pScissors; |
| }; |
| |
| const VkPipelineTessellationStateCreateInfo tessInfo = initVulkanStructure(); |
| |
| const VkPipelineRasterizationStateCreateInfo rasterizationInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineRasterizationStateCreateFlags flags; |
| VK_FALSE, // VkBool32 depthClampEnable; |
| VK_FALSE, // VkBool32 rasterizerDiscardEnable; |
| VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; |
| VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; |
| VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace; |
| VK_FALSE, // VkBool32 depthBiasEnable; |
| 0.0f, // float depthBiasConstantFactor; |
| 0.0f, // float depthBiasClamp; |
| 0.0f, // float depthBiasSlopeFactor; |
| 1.0f, // float lineWidth; |
| }; |
| |
| const VkPipelineMultisampleStateCreateInfo multisampleInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineMultisampleStateCreateFlags flags; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; |
| VK_FALSE, // VkBool32 sampleShadingEnable; |
| 1.0f, // float minSampleShading; |
| nullptr, // const VkSampleMask* pSampleMask; |
| VK_FALSE, // VkBool32 alphaToCoverageEnable; |
| VK_FALSE, // VkBool32 alphaToOneEnable; |
| }; |
| |
| const VkPipelineDepthStencilStateCreateInfo depthStencilInfo = initVulkanStructure(); |
| |
| VkPipelineColorBlendAttachmentState colorBlendAttachmentState; |
| deMemset(&colorBlendAttachmentState, 0, sizeof(colorBlendAttachmentState)); |
| colorBlendAttachmentState.colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); |
| |
| const VkPipelineColorBlendStateCreateInfo colorBlendInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineColorBlendStateCreateFlags flags; |
| VK_FALSE, // VkBool32 logicOpEnable; |
| VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp; |
| 1u, // deUint32 attachmentCount; |
| &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; |
| { .0f, .0f, .0f, .0f }, // float blendConstants[4]; |
| }; |
| |
| const VkGraphicsPipelineCreateInfo pipelineCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineCreateFlags flags; |
| static_cast<deUint32>(DE_LENGTH_OF_ARRAY(shaderStagesInfo)), // deUint32 stageCount; |
| shaderStagesInfo, // const VkPipelineShaderStageCreateInfo* pStages; |
| &vertexInputInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; |
| &inputAssemblyInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; |
| &tessInfo, // const VkPipelineTessellationStateCreateInfo* pTessellationState; |
| &viewportInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; |
| &rasterizationInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; |
| &multisampleInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; |
| &depthStencilInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; |
| &colorBlendInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; |
| nullptr, // const VkPipelineDynamicStateCreateInfo* pDynamicState; |
| pipelineLayout.get(), // VkPipelineLayout layout; |
| renderPass.get(), // VkRenderPass renderPass; |
| 0u, // deUint32 subpass; |
| DE_NULL, // VkPipeline basePipelineHandle; |
| 0, // deInt32 basePipelineIndex; |
| }; |
| |
| const auto graphicsPipeline = createGraphicsPipeline(vkd, device, DE_NULL, &pipelineCreateInfo); |
| |
| // Framebuffer. |
| const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), extent.width, extent.height); |
| |
| // Command pool and buffer. |
| const auto cmdPool = makeCommandPool(vkd, device, qIndex); |
| const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| const auto cmdBuffer = cmdBufferPtr.get(); |
| |
| // Empty clear color for the framebuffer. |
| VkClearValue zeroClearColor; |
| deMemset(&zeroClearColor, 0, sizeof(zeroClearColor)); |
| |
| // Texture barriers to fill it before using it. |
| const auto preClearBarrier = makeImageMemoryBarrier( |
| 0u, |
| VK_ACCESS_TRANSFER_WRITE_BIT, |
| VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| texture.get(), |
| colorSubresourceRange); |
| |
| const auto postClearBarrier = makeImageMemoryBarrier( |
| VK_ACCESS_TRANSFER_WRITE_BIT, |
| VK_ACCESS_SHADER_READ_BIT, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
| texture.get(), |
| colorSubresourceRange); |
| |
| // Record and submit. |
| beginCommandBuffer(vkd, cmdBuffer); |
| |
| // Prepare texture. |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preClearBarrier); |
| vkd.cmdClearColorImage(cmdBuffer, texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &m_params.textureColor, 1u, &colorSubresourceRange); |
| vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &postClearBarrier); |
| |
| // Read from the texture to render a full-screen quad to the color buffer. |
| beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, zeroClearColor); |
| vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get()); |
| vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr); |
| vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u); |
| endRenderPass(vkd, cmdBuffer); |
| |
| endCommandBuffer(vkd, cmdBuffer); |
| submitCommandsAndWait(vkd, device, queue, cmdBuffer); |
| |
| // Verify color buffer. |
| const auto renderSize = tcu::UVec2(extent.width, extent.height); |
| const auto colorAttachmentLevel = readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment.get(), colorAttachmentFormat, renderSize); |
| const auto colorPixels = colorAttachmentLevel->getAccess(); |
| const auto tcuTextureFormat = mapVkFormat(m_params.textureFormat); |
| const auto borderColor = getBorderClearColorValue(m_params); |
| const auto expectedColor = getExpectedColor(borderColor, m_params); |
| std::string resultMsg; |
| |
| if (!comparePixelToColorClearValue(m_params, colorPixels, tcuTextureFormat, expectedColor, resultMsg)) |
| TCU_FAIL(resultMsg); |
| |
| return tcu::TestStatus::pass(resultMsg); |
| } |
| |
| using ComponentSwizzleArray = std::array<VkComponentSwizzle, 4>; |
| |
| // Convert the component swizzle array to a component mapping structure. |
| void makeComponentMapping(VkComponentMapping& mapping, const ComponentSwizzleArray& array) |
| { |
| mapping.r = array[0]; |
| mapping.g = array[1]; |
| mapping.b = array[2]; |
| mapping.a = array[3]; |
| } |
| |
| std::string swizzleArrayToString(const ComponentSwizzleArray& swizzles) |
| { |
| std::ostringstream stream; |
| |
| for (const auto& s : swizzles) |
| { |
| switch (s) |
| { |
| case VK_COMPONENT_SWIZZLE_IDENTITY: stream << "i"; break; |
| case VK_COMPONENT_SWIZZLE_ZERO: stream << "0"; break; |
| case VK_COMPONENT_SWIZZLE_ONE: stream << "1"; break; |
| case VK_COMPONENT_SWIZZLE_R: stream << "r"; break; |
| case VK_COMPONENT_SWIZZLE_G: stream << "g"; break; |
| case VK_COMPONENT_SWIZZLE_B: stream << "b"; break; |
| case VK_COMPONENT_SWIZZLE_A: stream << "a"; break; |
| default: |
| DE_ASSERT(false); break; |
| } |
| } |
| |
| return stream.str(); |
| } |
| |
| // Generate mapping permutations for the swizzle components. |
| // Note: using every permutation for component swizzle values results in 7^4=2401 combinations, which are too many. |
| std::vector<ComponentSwizzleArray> genMappingPermutations () |
| { |
| std::vector<ComponentSwizzleArray> result; |
| const ComponentSwizzleArray standardSwizzle = {{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }}; |
| |
| // Standard normal swizzle. |
| result.push_back(standardSwizzle); |
| |
| // Add a few combinations with rotated swizzles. |
| for (size_t rotations = 1u; rotations < standardSwizzle.size(); ++rotations) |
| { |
| ComponentSwizzleArray rotatedSwizzle = standardSwizzle; |
| std::rotate(rotatedSwizzle.begin(), rotatedSwizzle.begin() + rotations, rotatedSwizzle.end()); |
| result.push_back(rotatedSwizzle); |
| } |
| |
| // Try placing each special value in each of the positions. |
| VkComponentSwizzle specialSwizzles[] = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ZERO }; |
| for (const auto& special : specialSwizzles) |
| { |
| for (size_t pos = 0; pos < standardSwizzle.size(); ++pos) |
| { |
| ComponentSwizzleArray newArray = standardSwizzle; |
| newArray[pos] = special; |
| result.push_back(newArray); |
| } |
| } |
| |
| return result; |
| } |
| |
| std::string gatherIndexToString(int gatherIndex) |
| { |
| if (gatherIndex < 0) |
| return "no_gather"; |
| return "gather_" + std::to_string(gatherIndex); |
| } |
| |
| bool isIntegerBorder (VkBorderColor borderType) |
| { |
| bool isInt = false; |
| switch (borderType) |
| { |
| case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: |
| case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK: |
| case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE: |
| case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT: |
| isInt = false; break; |
| case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK: |
| case VK_BORDER_COLOR_INT_OPAQUE_BLACK: |
| case VK_BORDER_COLOR_INT_OPAQUE_WHITE: |
| case VK_BORDER_COLOR_INT_CUSTOM_EXT: |
| isInt = true; break; |
| default: |
| DE_ASSERT(false); break; |
| } |
| |
| return isInt; |
| } |
| |
| tcu::Vec2 getRandomBorderCoordinates (de::Random& rnd) |
| { |
| tcu::Vec2 coords; |
| |
| // Two bits to decide which coordinates will be out of range (at least one). |
| const deUint32 outOfRangeMask = static_cast<deUint32>(rnd.getInt(1, 3)); |
| |
| for (int i = 0; i < 2; ++i) |
| { |
| // 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. |
| bool outOfRange = (outOfRangeMask & (1<<i)); |
| bool negative = (outOfRange && rnd.getBool()); |
| float minCoord = (outOfRange ? 1.1f : 0.0f); |
| float maxCoord = (outOfRange ? 5.0f : 0.9f); |
| float value = (negative ? -1.0f : 1.0f) * rnd.getFloat(minCoord, maxCoord); |
| |
| coords[i] = value; |
| } |
| |
| return coords; |
| } |
| |
| // Generate a random clear color usable for the given format. |
| VkClearColorValue getRandomClearColor (VkFormat format, de::Random& rnd) |
| { |
| VkClearColorValue color; |
| deMemset(&color, 0, sizeof(color)); |
| |
| const auto tcuFormat = mapVkFormat(format); |
| const auto numComponents = tcu::getNumUsedChannels(tcuFormat.order); |
| const auto componentSize = tcu::getChannelSize(tcuFormat.type); |
| |
| DE_ASSERT(componentSize > 0); |
| |
| const deUint64 mask = (1ull << (componentSize*8)) - 1ull; |
| const deUint64 signBit = (1ull << (componentSize*8-1)); |
| const deUint64 signMask = (~mask); // Used to extend the sign bit. |
| const auto formatType = getFormatType(format); |
| |
| for (int i = 0; i < numComponents; ++i) |
| { |
| if (formatType == FormatType::SIGNED_INT || formatType == FormatType::UNSIGNED_INT) |
| { |
| const auto value = rnd.getUint64(); |
| |
| if (formatType == FormatType::SIGNED_INT) |
| { |
| // Extend sign bit for negative values. |
| auto finalValue = (value & mask); |
| if (finalValue & signBit) |
| finalValue |= signMask; |
| color.int32[i] = static_cast<deInt32>(finalValue); |
| } |
| else |
| color.uint32[i] = static_cast<deUint32>(value & mask); |
| } |
| else |
| color.float32[i] = rnd.getFloat(); |
| } |
| |
| return color; |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createSamplerBorderSwizzleTests (tcu::TestContext& testCtx) |
| { |
| const deUint32 baseSeed = 1610707317u; |
| |
| const VkFormat textureFormats[] = |
| { |
| //VK_FORMAT_UNDEFINED, |
| //VK_FORMAT_R4G4_UNORM_PACK8, |
| //VK_FORMAT_R4G4B4A4_UNORM_PACK16, |
| //VK_FORMAT_B4G4R4A4_UNORM_PACK16, |
| //VK_FORMAT_R5G6B5_UNORM_PACK16, |
| //VK_FORMAT_B5G6R5_UNORM_PACK16, |
| //VK_FORMAT_R5G5B5A1_UNORM_PACK16, |
| //VK_FORMAT_B5G5R5A1_UNORM_PACK16, |
| //VK_FORMAT_A1R5G5B5_UNORM_PACK16, |
| VK_FORMAT_R8_UNORM, |
| VK_FORMAT_R8_SNORM, |
| //VK_FORMAT_R8_USCALED, |
| //VK_FORMAT_R8_SSCALED, |
| VK_FORMAT_R8_UINT, |
| VK_FORMAT_R8_SINT, |
| VK_FORMAT_R8_SRGB, |
| VK_FORMAT_R8G8_UNORM, |
| VK_FORMAT_R8G8_SNORM, |
| //VK_FORMAT_R8G8_USCALED, |
| //VK_FORMAT_R8G8_SSCALED, |
| VK_FORMAT_R8G8_UINT, |
| VK_FORMAT_R8G8_SINT, |
| VK_FORMAT_R8G8_SRGB, |
| VK_FORMAT_R8G8B8_UNORM, |
| VK_FORMAT_R8G8B8_SNORM, |
| //VK_FORMAT_R8G8B8_USCALED, |
| //VK_FORMAT_R8G8B8_SSCALED, |
| VK_FORMAT_R8G8B8_UINT, |
| VK_FORMAT_R8G8B8_SINT, |
| VK_FORMAT_R8G8B8_SRGB, |
| VK_FORMAT_B8G8R8_UNORM, |
| VK_FORMAT_B8G8R8_SNORM, |
| //VK_FORMAT_B8G8R8_USCALED, |
| //VK_FORMAT_B8G8R8_SSCALED, |
| VK_FORMAT_B8G8R8_UINT, |
| VK_FORMAT_B8G8R8_SINT, |
| VK_FORMAT_B8G8R8_SRGB, |
| VK_FORMAT_R8G8B8A8_UNORM, |
| VK_FORMAT_R8G8B8A8_SNORM, |
| //VK_FORMAT_R8G8B8A8_USCALED, |
| //VK_FORMAT_R8G8B8A8_SSCALED, |
| VK_FORMAT_R8G8B8A8_UINT, |
| VK_FORMAT_R8G8B8A8_SINT, |
| VK_FORMAT_R8G8B8A8_SRGB, |
| VK_FORMAT_B8G8R8A8_UNORM, |
| VK_FORMAT_B8G8R8A8_SNORM, |
| //VK_FORMAT_B8G8R8A8_USCALED, |
| //VK_FORMAT_B8G8R8A8_SSCALED, |
| VK_FORMAT_B8G8R8A8_UINT, |
| VK_FORMAT_B8G8R8A8_SINT, |
| VK_FORMAT_B8G8R8A8_SRGB, |
| // VK_FORMAT_A8B8G8R8_UNORM_PACK32, |
| // VK_FORMAT_A8B8G8R8_SNORM_PACK32, |
| // VK_FORMAT_A8B8G8R8_USCALED_PACK32, |
| // VK_FORMAT_A8B8G8R8_SSCALED_PACK32, |
| // VK_FORMAT_A8B8G8R8_UINT_PACK32, |
| // VK_FORMAT_A8B8G8R8_SINT_PACK32, |
| // VK_FORMAT_A8B8G8R8_SRGB_PACK32, |
| // VK_FORMAT_A2R10G10B10_UNORM_PACK32, |
| // VK_FORMAT_A2R10G10B10_SNORM_PACK32, |
| // VK_FORMAT_A2R10G10B10_USCALED_PACK32, |
| // VK_FORMAT_A2R10G10B10_SSCALED_PACK32, |
| // VK_FORMAT_A2R10G10B10_UINT_PACK32, |
| // VK_FORMAT_A2R10G10B10_SINT_PACK32, |
| // VK_FORMAT_A2B10G10R10_UNORM_PACK32, |
| // VK_FORMAT_A2B10G10R10_SNORM_PACK32, |
| // VK_FORMAT_A2B10G10R10_USCALED_PACK32, |
| // VK_FORMAT_A2B10G10R10_SSCALED_PACK32, |
| // VK_FORMAT_A2B10G10R10_UINT_PACK32, |
| // VK_FORMAT_A2B10G10R10_SINT_PACK32, |
| VK_FORMAT_R16_UNORM, |
| VK_FORMAT_R16_SNORM, |
| //VK_FORMAT_R16_USCALED, |
| //VK_FORMAT_R16_SSCALED, |
| VK_FORMAT_R16_UINT, |
| VK_FORMAT_R16_SINT, |
| VK_FORMAT_R16_SFLOAT, |
| VK_FORMAT_R16G16_UNORM, |
| VK_FORMAT_R16G16_SNORM, |
| //VK_FORMAT_R16G16_USCALED, |
| //VK_FORMAT_R16G16_SSCALED, |
| VK_FORMAT_R16G16_UINT, |
| VK_FORMAT_R16G16_SINT, |
| VK_FORMAT_R16G16_SFLOAT, |
| VK_FORMAT_R16G16B16_UNORM, |
| VK_FORMAT_R16G16B16_SNORM, |
| //VK_FORMAT_R16G16B16_USCALED, |
| //VK_FORMAT_R16G16B16_SSCALED, |
| VK_FORMAT_R16G16B16_UINT, |
| VK_FORMAT_R16G16B16_SINT, |
| VK_FORMAT_R16G16B16_SFLOAT, |
| VK_FORMAT_R16G16B16A16_UNORM, |
| VK_FORMAT_R16G16B16A16_SNORM, |
| //VK_FORMAT_R16G16B16A16_USCALED, |
| //VK_FORMAT_R16G16B16A16_SSCALED, |
| VK_FORMAT_R16G16B16A16_UINT, |
| VK_FORMAT_R16G16B16A16_SINT, |
| VK_FORMAT_R16G16B16A16_SFLOAT, |
| VK_FORMAT_R32_UINT, |
| VK_FORMAT_R32_SINT, |
| VK_FORMAT_R32_SFLOAT, |
| VK_FORMAT_R32G32_UINT, |
| VK_FORMAT_R32G32_SINT, |
| VK_FORMAT_R32G32_SFLOAT, |
| VK_FORMAT_R32G32B32_UINT, |
| VK_FORMAT_R32G32B32_SINT, |
| VK_FORMAT_R32G32B32_SFLOAT, |
| VK_FORMAT_R32G32B32A32_UINT, |
| VK_FORMAT_R32G32B32A32_SINT, |
| VK_FORMAT_R32G32B32A32_SFLOAT, |
| }; |
| |
| const auto mappingPermutations = genMappingPermutations(); |
| |
| const struct |
| { |
| VkBorderColor borderType; |
| const char* borderTypeName; |
| } |
| borderColors[] = |
| { |
| { VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, "transparent_black" }, |
| { VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, "transparent_black" }, |
| { VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, "opaque_black" }, |
| { VK_BORDER_COLOR_INT_OPAQUE_BLACK, "opaque_black" }, |
| { VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE, "opaque_white" }, |
| { VK_BORDER_COLOR_INT_OPAQUE_WHITE, "opaque_white" }, |
| { VK_BORDER_COLOR_FLOAT_CUSTOM_EXT, "custom" }, |
| { VK_BORDER_COLOR_INT_CUSTOM_EXT, "custom" }, |
| }; |
| |
| const struct |
| { |
| bool useSwizzleHint; |
| const char* name; |
| } swizzleHintCases[] = |
| { |
| { false, "no_swizzle_hint" }, |
| { true, "with_swizzle_hint" }, |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, "border_swizzle", "Border color swizzle tests")); |
| |
| for (const auto& format : textureFormats) |
| { |
| const auto skip = std::strlen("VK_FORMAT_"); |
| const std::string formatName = de::toLower(std::string(getFormatName(format)).substr(skip)); |
| de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), "")); |
| |
| for (size_t mappingIdx = 0u; mappingIdx < mappingPermutations.size(); ++mappingIdx) |
| { |
| const auto& mapping = mappingPermutations[mappingIdx]; |
| de::MovePtr<tcu::TestCaseGroup> mappingGroup (new tcu::TestCaseGroup(testCtx, swizzleArrayToString(mapping).c_str(), "")); |
| |
| for (int borderColorIdx = 0; borderColorIdx < DE_LENGTH_OF_ARRAY(borderColors); ++borderColorIdx) |
| { |
| const auto& borderColor = borderColors[borderColorIdx]; |
| de::MovePtr<tcu::TestCaseGroup> borderTypeGroup (new tcu::TestCaseGroup(testCtx, borderColor.borderTypeName, "")); |
| |
| const auto formatType = getFormatType(format); |
| const auto isIntBorder = isIntegerBorder(borderColor.borderType); |
| |
| // Skip cases that do not make sense for the format and border type combination. |
| if (isIntBorder && formatType == FormatType::FLOAT) |
| continue; |
| else if (!isIntBorder && formatType != FormatType::FLOAT) |
| continue; |
| |
| for (int gatherIdx = -1; gatherIdx <= 3; ++gatherIdx) |
| { |
| const auto componentGather = gatherIndexToString(gatherIdx); |
| de::MovePtr<tcu::TestCaseGroup> gatherGroup (new tcu::TestCaseGroup(testCtx, componentGather.c_str(), "")); |
| |
| for (const auto& swizzleHint : swizzleHintCases) |
| { |
| TestParams params; |
| |
| const deUint32 seed = baseSeed + static_cast<deUint32>(format) + static_cast<deUint32>(mappingIdx) + static_cast<deUint32>(borderColorIdx) + static_cast<deUint32>(gatherIdx); |
| de::Random rnd (seed); |
| |
| params.textureFormat = format; |
| params.textureColor = getRandomClearColor(format, rnd); |
| |
| makeComponentMapping(params.componentMapping, mapping); |
| params.borderColor = borderColor.borderType; |
| params.componentGather = ((gatherIdx < 0) ? tcu::nothing<int>() : tcu::just(gatherIdx)); |
| params.textureCoordinates = getRandomBorderCoordinates(rnd); |
| |
| if (params.isCustom()) |
| params.customBorderColor = tcu::just(getRandomClearColor(format, rnd)); |
| else |
| params.customBorderColor = tcu::nothing<VkClearColorValue>(); |
| |
| params.useSamplerSwizzleHint = swizzleHint.useSwizzleHint; |
| |
| gatherGroup->addChild(new BorderSwizzleCase(testCtx, swizzleHint.name, "", params)); |
| } |
| |
| borderTypeGroup->addChild(gatherGroup.release()); |
| } |
| |
| mappingGroup->addChild(borderTypeGroup.release()); |
| } |
| |
| formatGroup->addChild(mappingGroup.release()); |
| } |
| |
| mainGroup->addChild(formatGroup.release()); |
| } |
| |
| return mainGroup.release(); |
| } |
| |
| } // pipeline |
| } // vkt |
| |
| |
| |