blob: 3a170d92aa41fe1930d8edbc4e99761d45df8ff3 [file] [log] [blame]
/*------------------------------------------------------------------------
* 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 &params);
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 &params)
: 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