/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2017 Google Inc. * * 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 YCbCr format copy tests *//*--------------------------------------------------------------------*/ #include "vktYCbCrCopyTests.hpp" #include "vktTestCaseUtil.hpp" #include "vktTestGroupUtil.hpp" #include "vktYCbCrUtil.hpp" #include "vkQueryUtil.hpp" #include "vkRefUtil.hpp" #include "vkTypeUtil.hpp" #include "vkCmdUtil.hpp" #include "tcuSeedBuilder.hpp" #include "tcuTestLog.hpp" #include "tcuVector.hpp" #include "tcuVectorUtil.hpp" #include "deRandom.hpp" #include "deSTLUtil.hpp" #include "deStringUtil.hpp" #include #include #include using tcu::UVec2; using tcu::Vec4; using tcu::TestLog; using std::string; using std::vector; using std::pair; namespace vkt { namespace ycbcr { namespace { struct ImageConfig { ImageConfig (vk::VkFormat format_, vk::VkImageTiling tiling_, bool disjoint_, const UVec2& size_) : format (format_) , tiling (tiling_) , disjoint (disjoint_) , size (size_) { } vk::VkFormat format; vk::VkImageTiling tiling; bool disjoint; UVec2 size; }; struct TestConfig { TestConfig (const ImageConfig& src_, const ImageConfig& dst_) : src (src_) , dst (dst_) { } ImageConfig src; ImageConfig dst; }; void checkFormatSupport(Context& context, const ImageConfig& config) { try { const vk::VkFormatProperties properties (vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), config.format)); const vk::VkFormatFeatureFlags features (config.tiling == vk::VK_IMAGE_TILING_OPTIMAL ? properties.optimalTilingFeatures : properties.linearTilingFeatures); if ((features & vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) == 0 && (features & vk::VK_FORMAT_FEATURE_TRANSFER_DST_BIT) == 0) { TCU_THROW(NotSupportedError, "Format doesn't support copies"); } if (config.disjoint && ((features & vk::VK_FORMAT_FEATURE_DISJOINT_BIT) == 0)) TCU_THROW(NotSupportedError, "Format doesn't support disjoint planes"); } catch (const vk::Error& err) { if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED) TCU_THROW(NotSupportedError, "Format not supported"); throw; } } void checkSupport (Context& context, const TestConfig config) { const vk::VkPhysicalDeviceLimits limits = context.getDeviceProperties().limits; if (config.src.size.x() > limits.maxImageDimension2D || config.src.size.y() > limits.maxImageDimension2D || config.dst.size.x() > limits.maxImageDimension2D || config.dst.size.y() > limits.maxImageDimension2D) { TCU_THROW(NotSupportedError, "Requested image dimensions not supported"); } if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), string("VK_KHR_sampler_ycbcr_conversion"))) TCU_THROW(NotSupportedError, "Extension VK_KHR_sampler_ycbcr_conversion not supported"); checkFormatSupport(context, config.src); checkFormatSupport(context, config.dst); } vk::Move createImage (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkFormat format, const UVec2& size, bool disjoint, vk::VkImageTiling tiling) { const vk::VkImageCreateInfo createInfo = { vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, DE_NULL, disjoint ? (vk::VkImageCreateFlags)vk::VK_IMAGE_CREATE_DISJOINT_BIT : (vk::VkImageCreateFlags)0u, vk::VK_IMAGE_TYPE_2D, format, vk::makeExtent3D(size.x(), size.y(), 1u), 1u, 1u, vk::VK_SAMPLE_COUNT_1_BIT, tiling, vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT, vk::VK_SHARING_MODE_EXCLUSIVE, 0u, (const deUint32*)DE_NULL, tiling == vk::VK_IMAGE_TILING_LINEAR ? vk::VK_IMAGE_LAYOUT_PREINITIALIZED : vk::VK_IMAGE_LAYOUT_UNDEFINED, }; return vk::createImage(vkd, device, &createInfo); } bool isCompatible (vk::VkFormat srcFormat, vk::VkFormat dstFormat) { if (srcFormat == dstFormat) return true; else { const vk::VkFormat class8Bit[] = { vk::VK_FORMAT_R4G4_UNORM_PACK8, vk::VK_FORMAT_R8_UNORM, vk::VK_FORMAT_R8_SNORM, vk::VK_FORMAT_R8_USCALED, vk::VK_FORMAT_R8_SSCALED, vk::VK_FORMAT_R8_UINT, vk::VK_FORMAT_R8_SINT, vk::VK_FORMAT_R8_SRGB }; const vk::VkFormat class16Bit[] = { vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16, vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16, vk::VK_FORMAT_R5G6B5_UNORM_PACK16, vk::VK_FORMAT_B5G6R5_UNORM_PACK16, vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16, vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16, vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16, vk::VK_FORMAT_R8G8_UNORM, vk::VK_FORMAT_R8G8_SNORM, vk::VK_FORMAT_R8G8_USCALED, vk::VK_FORMAT_R8G8_SSCALED, vk::VK_FORMAT_R8G8_UINT, vk::VK_FORMAT_R8G8_SINT, vk::VK_FORMAT_R8G8_SRGB, vk::VK_FORMAT_R16_UNORM, vk::VK_FORMAT_R16_SNORM, vk::VK_FORMAT_R16_USCALED, vk::VK_FORMAT_R16_SSCALED, vk::VK_FORMAT_R16_UINT, vk::VK_FORMAT_R16_SINT, vk::VK_FORMAT_R16_SFLOAT, vk::VK_FORMAT_R10X6_UNORM_PACK16, vk::VK_FORMAT_R12X4_UNORM_PACK16 }; const vk::VkFormat class24Bit[] = { vk::VK_FORMAT_R8G8B8_UNORM, vk::VK_FORMAT_R8G8B8_SNORM, vk::VK_FORMAT_R8G8B8_USCALED, vk::VK_FORMAT_R8G8B8_SSCALED, vk::VK_FORMAT_R8G8B8_UINT, vk::VK_FORMAT_R8G8B8_SINT, vk::VK_FORMAT_R8G8B8_SRGB, vk::VK_FORMAT_B8G8R8_UNORM, vk::VK_FORMAT_B8G8R8_SNORM, vk::VK_FORMAT_B8G8R8_USCALED, vk::VK_FORMAT_B8G8R8_SSCALED, vk::VK_FORMAT_B8G8R8_UINT, vk::VK_FORMAT_B8G8R8_SINT, vk::VK_FORMAT_B8G8R8_SRGB }; const vk::VkFormat class32Bit[] = { vk::VK_FORMAT_R8G8B8A8_UNORM, vk::VK_FORMAT_R8G8B8A8_SNORM, vk::VK_FORMAT_R8G8B8A8_USCALED, vk::VK_FORMAT_R8G8B8A8_SSCALED, vk::VK_FORMAT_R8G8B8A8_UINT, vk::VK_FORMAT_R8G8B8A8_SINT, vk::VK_FORMAT_R8G8B8A8_SRGB, vk::VK_FORMAT_B8G8R8A8_UNORM, vk::VK_FORMAT_B8G8R8A8_SNORM, vk::VK_FORMAT_B8G8R8A8_USCALED, vk::VK_FORMAT_B8G8R8A8_SSCALED, vk::VK_FORMAT_B8G8R8A8_UINT, vk::VK_FORMAT_B8G8R8A8_SINT, vk::VK_FORMAT_B8G8R8A8_SRGB, vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32, vk::VK_FORMAT_A8B8G8R8_SNORM_PACK32, vk::VK_FORMAT_A8B8G8R8_USCALED_PACK32, vk::VK_FORMAT_A8B8G8R8_SSCALED_PACK32, vk::VK_FORMAT_A8B8G8R8_UINT_PACK32, vk::VK_FORMAT_A8B8G8R8_SINT_PACK32, vk::VK_FORMAT_A8B8G8R8_SRGB_PACK32, vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32, vk::VK_FORMAT_A2R10G10B10_SNORM_PACK32, vk::VK_FORMAT_A2R10G10B10_USCALED_PACK32, vk::VK_FORMAT_A2R10G10B10_SSCALED_PACK32, vk::VK_FORMAT_A2R10G10B10_UINT_PACK32, vk::VK_FORMAT_A2R10G10B10_SINT_PACK32, vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32, vk::VK_FORMAT_A2B10G10R10_SNORM_PACK32, vk::VK_FORMAT_A2B10G10R10_USCALED_PACK32, vk::VK_FORMAT_A2B10G10R10_SSCALED_PACK32, vk::VK_FORMAT_A2B10G10R10_UINT_PACK32, vk::VK_FORMAT_A2B10G10R10_SINT_PACK32, vk::VK_FORMAT_R16G16_UNORM, vk::VK_FORMAT_R16G16_SNORM, vk::VK_FORMAT_R16G16_USCALED, vk::VK_FORMAT_R16G16_SSCALED, vk::VK_FORMAT_R16G16_UINT, vk::VK_FORMAT_R16G16_SINT, vk::VK_FORMAT_R16G16_SFLOAT, vk::VK_FORMAT_R32_UINT, vk::VK_FORMAT_R32_SINT, vk::VK_FORMAT_R32_SFLOAT, vk::VK_FORMAT_B10G11R11_UFLOAT_PACK32, vk::VK_FORMAT_E5B9G9R9_UFLOAT_PACK32, vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16, vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16 }; const vk::VkFormat class48Bit[] = { vk::VK_FORMAT_R16G16B16_UNORM, vk::VK_FORMAT_R16G16B16_SNORM, vk::VK_FORMAT_R16G16B16_USCALED, vk::VK_FORMAT_R16G16B16_SSCALED, vk::VK_FORMAT_R16G16B16_UINT, vk::VK_FORMAT_R16G16B16_SINT, vk::VK_FORMAT_R16G16B16_SFLOAT }; const vk::VkFormat class64Bit[] = { vk::VK_FORMAT_R16G16B16A16_UNORM, vk::VK_FORMAT_R16G16B16A16_SNORM, vk::VK_FORMAT_R16G16B16A16_USCALED, vk::VK_FORMAT_R16G16B16A16_SSCALED, vk::VK_FORMAT_R16G16B16A16_UINT, vk::VK_FORMAT_R16G16B16A16_SINT, vk::VK_FORMAT_R16G16B16A16_SFLOAT, vk::VK_FORMAT_R32G32_UINT, vk::VK_FORMAT_R32G32_SINT, vk::VK_FORMAT_R32G32_SFLOAT, vk::VK_FORMAT_R64_UINT, vk::VK_FORMAT_R64_SINT, vk::VK_FORMAT_R64_SFLOAT }; const vk::VkFormat class96Bit[] = { vk::VK_FORMAT_R32G32B32_UINT, vk::VK_FORMAT_R32G32B32_SINT, vk::VK_FORMAT_R32G32B32_SFLOAT }; const vk::VkFormat class128Bit[] = { vk::VK_FORMAT_R32G32B32A32_UINT, vk::VK_FORMAT_R32G32B32A32_SINT, vk::VK_FORMAT_R32G32B32A32_SFLOAT, vk::VK_FORMAT_R64G64_UINT, vk::VK_FORMAT_R64G64_SINT, vk::VK_FORMAT_R64G64_SFLOAT }; const vk::VkFormat class192Bit[] = { vk::VK_FORMAT_R64G64B64_UINT, vk::VK_FORMAT_R64G64B64_SINT, vk::VK_FORMAT_R64G64B64_SFLOAT }; const vk::VkFormat class256Bit[] = { vk::VK_FORMAT_R64G64B64A64_UINT, vk::VK_FORMAT_R64G64B64A64_SINT, vk::VK_FORMAT_R64G64B64A64_SFLOAT }; if (de::contains(DE_ARRAY_BEGIN(class8Bit), DE_ARRAY_END(class8Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class8Bit), DE_ARRAY_END(class8Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class16Bit), DE_ARRAY_END(class16Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class16Bit), DE_ARRAY_END(class16Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class24Bit), DE_ARRAY_END(class24Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class24Bit), DE_ARRAY_END(class24Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class32Bit), DE_ARRAY_END(class32Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class32Bit), DE_ARRAY_END(class32Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class48Bit), DE_ARRAY_END(class48Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class48Bit), DE_ARRAY_END(class48Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class64Bit), DE_ARRAY_END(class64Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class64Bit), DE_ARRAY_END(class64Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class96Bit), DE_ARRAY_END(class96Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class96Bit), DE_ARRAY_END(class96Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class128Bit), DE_ARRAY_END(class128Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class128Bit), DE_ARRAY_END(class128Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class192Bit), DE_ARRAY_END(class192Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class192Bit), DE_ARRAY_END(class192Bit), dstFormat)) return true; if (de::contains(DE_ARRAY_BEGIN(class256Bit), DE_ARRAY_END(class256Bit), srcFormat) && de::contains(DE_ARRAY_BEGIN(class256Bit), DE_ARRAY_END(class256Bit), dstFormat)) return true; return false; } } deUint32 getBlockByteSize (vk::VkFormat format) { switch (format) { case vk::VK_FORMAT_B8G8R8G8_422_UNORM: case vk::VK_FORMAT_G8B8G8R8_422_UNORM: return 4u; case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: case vk::VK_FORMAT_B16G16R16G16_422_UNORM: case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: case vk::VK_FORMAT_G16B16G16R16_422_UNORM: case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: case vk::VK_FORMAT_R16G16B16A16_UNORM: return 4u * 2u; case vk::VK_FORMAT_R10X6_UNORM_PACK16: case vk::VK_FORMAT_R12X4_UNORM_PACK16: return 2u; case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16: case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16: return 2u * 2u; case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: return 3u * 2u; case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: case vk::VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT: case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT: case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT: case vk::VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT: DE_FATAL("Plane formats not supported"); return ~0u; default: return (deUint32)vk::mapVkFormat(format).getPixelSize(); } } UVec2 randomUVec2 (de::Random& rng, const UVec2& min, const UVec2& max) { UVec2 result; result[0] = min[0] + (rng.getUint32() % (1 + max[0] - min[0])); result[1] = min[1] + (rng.getUint32() % (1 + max[1] - min[1])); return result; } void genCopies (de::Random& rng, size_t copyCount, vk::VkFormat srcFormat, const UVec2& srcSize, vk::VkFormat dstFormat, const UVec2& dstSize, vector* copies) { vector > pairs; const vk::PlanarFormatDescription srcPlaneInfo (vk::getPlanarFormatDescription(srcFormat)); const vk::PlanarFormatDescription dstPlaneInfo (vk::getPlanarFormatDescription(dstFormat)); for (deUint32 srcPlaneNdx = 0; srcPlaneNdx < srcPlaneInfo.numPlanes; srcPlaneNdx++) { for (deUint32 dstPlaneNdx = 0; dstPlaneNdx < dstPlaneInfo.numPlanes; dstPlaneNdx++) { const vk::VkFormat srcPlaneFormat (getPlaneCompatibleFormat(srcPlaneInfo, srcPlaneNdx)); const vk::VkFormat dstPlaneFormat (getPlaneCompatibleFormat(dstPlaneInfo, dstPlaneNdx)); if (isCompatible(srcPlaneFormat, dstPlaneFormat)) pairs.push_back(std::make_pair(srcPlaneNdx, dstPlaneNdx)); } } DE_ASSERT(!pairs.empty()); copies->reserve(copyCount); for (size_t copyNdx = 0; copyNdx < copyCount; copyNdx++) { const pair planes (rng.choose >(pairs.begin(), pairs.end())); const deUint32 srcPlaneNdx (planes.first); const vk::VkFormat srcPlaneFormat (getPlaneCompatibleFormat(srcPlaneInfo, srcPlaneNdx)); const UVec2 srcBlockExtent (getBlockExtent(srcPlaneFormat)); const UVec2 srcPlaneExtent (getPlaneExtent(srcPlaneInfo, srcSize, srcPlaneNdx, 0)); const UVec2 srcPlaneBlockExtent (srcPlaneExtent / srcBlockExtent); const deUint32 dstPlaneNdx (planes.second); const vk::VkFormat dstPlaneFormat (getPlaneCompatibleFormat(dstPlaneInfo, dstPlaneNdx)); const UVec2 dstBlockExtent (getBlockExtent(dstPlaneFormat)); const UVec2 dstPlaneExtent (getPlaneExtent(dstPlaneInfo, dstSize, dstPlaneNdx, 0)); const UVec2 dstPlaneBlockExtent (dstPlaneExtent / dstBlockExtent); const UVec2 copyBlockExtent (randomUVec2(rng, UVec2(1u, 1u), tcu::min(srcPlaneBlockExtent, dstPlaneBlockExtent))); const UVec2 srcOffset (srcBlockExtent * randomUVec2(rng, UVec2(0u, 0u), srcPlaneBlockExtent - copyBlockExtent)); const UVec2 dstOffset (dstBlockExtent * randomUVec2(rng, UVec2(0u, 0u), dstPlaneBlockExtent - copyBlockExtent)); const UVec2 copyExtent (copyBlockExtent * srcBlockExtent); const vk::VkImageCopy copy = { // src { static_cast(srcPlaneInfo.numPlanes > 1 ? vk::getPlaneAspect(srcPlaneNdx) : vk::VK_IMAGE_ASPECT_COLOR_BIT), 0u, 0u, 1u }, { (deInt32)srcOffset.x(), (deInt32)srcOffset.y(), 0, }, // dst { static_cast(dstPlaneInfo.numPlanes > 1 ? vk::getPlaneAspect(dstPlaneNdx) : vk::VK_IMAGE_ASPECT_COLOR_BIT), 0u, 0u, 1u }, { (deInt32)dstOffset.x(), (deInt32)dstOffset.y(), 0, }, // size { copyExtent.x(), copyExtent.y(), 1u } }; copies->push_back(copy); } } tcu::SeedBuilder& operator<< (tcu::SeedBuilder& builder, const ImageConfig& config) { builder << (deUint32)config.format << (deUint32)config.tiling << config.disjoint << config.size[0] << config.size[1]; return builder; } deUint32 buildSeed (const TestConfig& config) { tcu::SeedBuilder builder; builder << 6792903u << config.src << config.dst; return builder.get(); } void logImageInfo (TestLog& log, const ImageConfig& config) { log << TestLog::Message << "Format: " << config.format << TestLog::EndMessage; log << TestLog::Message << "Tiling: " << config.tiling << TestLog::EndMessage; log << TestLog::Message << "Size: " << config.size << TestLog::EndMessage; log << TestLog::Message << "Disjoint: " << (config.disjoint ? "true" : "false") << TestLog::EndMessage; } void logTestCaseInfo (TestLog& log, const TestConfig& config, const vector& copies) { { const tcu::ScopedLogSection section (log, "SourceImage", "SourceImage"); logImageInfo(log, config.src); } { const tcu::ScopedLogSection section (log, "DestinationImage", "DestinationImage"); logImageInfo(log, config.dst); } { const tcu::ScopedLogSection section (log, "Copies", "Copies"); for (size_t copyNdx = 0; copyNdx < copies.size(); copyNdx++) log << TestLog::Message << copies[copyNdx] << TestLog::EndMessage; } } tcu::TestStatus imageCopyTest (Context& context, const TestConfig config) { { const size_t copyCount = 10; TestLog& log (context.getTestContext().getLog()); MultiPlaneImageData srcData (config.src.format, config.src.size); MultiPlaneImageData dstData (config.dst.format, config.dst.size); MultiPlaneImageData result (config.dst.format, config.dst.size); vector copies; de::Random rng (buildSeed(config)); const bool noNan = true; genCopies(rng, copyCount, config.src.format, config.src.size, config.dst.format, config.dst.size, &copies); logTestCaseInfo(log, config, copies); // To avoid putting NaNs in dst in the image copy fillRandom(&rng, &srcData, config.dst.format, noNan); fillRandom(&rng, &dstData, config.dst.format, noNan); { const vk::DeviceInterface& vkd (context.getDeviceInterface()); const vk::VkDevice device (context.getDevice()); const vk::Unique srcImage (createImage(vkd, device, config.src.format, config.src.size, config.src.disjoint, config.src.tiling)); const vk::MemoryRequirement srcMemoryRequirement (config.src.tiling == vk::VK_IMAGE_TILING_OPTIMAL ? vk::MemoryRequirement::Any : vk::MemoryRequirement::HostVisible); const vk::VkImageCreateFlags srcCreateFlags (config.src.disjoint ? vk::VK_IMAGE_CREATE_DISJOINT_BIT : (vk::VkImageCreateFlagBits)0u); const vector srcImageMemory (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *srcImage, config.src.format, srcCreateFlags, srcMemoryRequirement)); const vk::Unique dstImage (createImage(vkd, device, config.dst.format, config.dst.size, config.dst.disjoint, config.dst.tiling)); const vk::MemoryRequirement dstMemoryRequirement (config.dst.tiling == vk::VK_IMAGE_TILING_OPTIMAL ? vk::MemoryRequirement::Any : vk::MemoryRequirement::HostVisible); const vk::VkImageCreateFlags dstCreateFlags (config.dst.disjoint ? vk::VK_IMAGE_CREATE_DISJOINT_BIT : (vk::VkImageCreateFlagBits)0u); const vector dstImageMemory (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *dstImage, config.dst.format, dstCreateFlags, dstMemoryRequirement)); if (config.src.tiling == vk::VK_IMAGE_TILING_OPTIMAL) uploadImage(vkd, device, context.getUniversalQueueFamilyIndex(), context.getDefaultAllocator(), *srcImage, srcData, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); else fillImageMemory(vkd, device, context.getUniversalQueueFamilyIndex(), *srcImage, srcImageMemory, srcData, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); if (config.dst.tiling == vk::VK_IMAGE_TILING_OPTIMAL) uploadImage(vkd, device, context.getUniversalQueueFamilyIndex(), context.getDefaultAllocator(), *dstImage, dstData, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); else fillImageMemory(vkd, device, context.getUniversalQueueFamilyIndex(), *dstImage, dstImageMemory, dstData, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); { const deUint32 queueFamilyNdx (context.getUniversalQueueFamilyIndex()); const vk::VkQueue queue (context.getUniversalQueue()); const vk::Unique cmdPool (createCommandPool(vkd, device, (vk::VkCommandPoolCreateFlags)0, queueFamilyNdx)); const vk::Unique cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); beginCommandBuffer(vkd, *cmdBuffer); for (size_t i = 0; i < copies.size(); i++) { vkd.cmdCopyImage(*cmdBuffer, *srcImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *dstImage, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copies[i]); const vk::VkImageMemoryBarrier preCopyBarrier = { vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, DE_NULL, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT | vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, *dstImage, { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } }; vkd.cmdPipelineBarrier(*cmdBuffer, (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkPipelineStageFlags)vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkDependencyFlags)0u, 0u, (const vk::VkMemoryBarrier*)DE_NULL, 0u, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1u, &preCopyBarrier); } endCommandBuffer(vkd, *cmdBuffer); submitCommandsAndWait(vkd, device, queue, *cmdBuffer); } if (config.dst.tiling == vk::VK_IMAGE_TILING_OPTIMAL) downloadImage(vkd, device, context.getUniversalQueueFamilyIndex(), context.getDefaultAllocator(), *dstImage, &result, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); else readImageMemory(vkd, device, context.getUniversalQueueFamilyIndex(), *dstImage, dstImageMemory, &result, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } { MultiPlaneImageData reference (dstData); const size_t maxErrorCount = 30; size_t errorCount = 0; for (size_t copyNdx = 0; copyNdx < copies.size(); copyNdx++) { const vk::VkImageCopy& copy (copies[copyNdx]); const deUint32 srcPlaneNdx (copy.srcSubresource.aspectMask != vk::VK_IMAGE_ASPECT_COLOR_BIT ? vk::getAspectPlaneNdx((vk::VkImageAspectFlagBits)copy.srcSubresource.aspectMask) : 0u); const UVec2 srcPlaneExtent (getPlaneExtent(srcData.getDescription(), config.src.size, srcPlaneNdx, 0)); const vk::VkFormat srcPlaneFormat (getPlaneCompatibleFormat(config.src.format, srcPlaneNdx)); const UVec2 srcBlockExtent (getBlockExtent(srcPlaneFormat)); const deUint32 blockSizeBytes (getBlockByteSize(srcPlaneFormat)); const UVec2 srcPlaneBlockExtent (srcPlaneExtent / srcBlockExtent); const UVec2 srcBlockOffset (copy.srcOffset.x / srcBlockExtent.x(), copy.srcOffset.y / srcBlockExtent.y()); const UVec2 srcBlockPitch (blockSizeBytes, blockSizeBytes * srcPlaneBlockExtent.x()); const deUint32 dstPlaneNdx (copy.dstSubresource.aspectMask != vk::VK_IMAGE_ASPECT_COLOR_BIT ? vk::getAspectPlaneNdx((vk::VkImageAspectFlagBits)copy.dstSubresource.aspectMask) : 0u); const UVec2 dstPlaneExtent (getPlaneExtent(dstData.getDescription(), config.dst.size, dstPlaneNdx, 0)); const vk::VkFormat dstPlaneFormat (getPlaneCompatibleFormat(config.dst.format, dstPlaneNdx)); const UVec2 dstBlockExtent (getBlockExtent(dstPlaneFormat)); const UVec2 dstPlaneBlockExtent (dstPlaneExtent / dstBlockExtent); const UVec2 dstBlockOffset (copy.dstOffset.x / dstBlockExtent.x(), copy.dstOffset.y / dstBlockExtent.y()); const UVec2 dstBlockPitch (blockSizeBytes, blockSizeBytes * dstPlaneBlockExtent.x()); const UVec2 blockExtent (copy.extent.width / srcBlockExtent.x(), copy.extent.height / srcBlockExtent.y()); DE_ASSERT(blockSizeBytes == getBlockByteSize(dstPlaneFormat)); for (deUint32 y = 0; y < blockExtent.y(); y++) { const deUint32 size = blockExtent.x() * blockSizeBytes; const deUint32 srcPos = tcu::dot(srcBlockPitch, UVec2(srcBlockOffset.x(), srcBlockOffset.y() + y)); const deUint32 dstPos = tcu::dot(dstBlockPitch, UVec2(dstBlockOffset.x(), dstBlockOffset.y() + y)); deMemcpy(((deUint8*)reference.getPlanePtr(dstPlaneNdx)) + dstPos, ((const deUint8*)srcData.getPlanePtr(srcPlaneNdx)) + srcPos, size); } } bool ignoreLsb6Bits = areLsb6BitsDontCare(srcData.getFormat(), dstData.getFormat()); bool ignoreLsb4Bits = areLsb4BitsDontCare(srcData.getFormat(), dstData.getFormat()); for (deUint32 planeNdx = 0; planeNdx < result.getDescription().numPlanes; ++planeNdx) { deUint32 planeSize = vk::getPlaneSizeInBytes(result.getDescription(), result.getSize(), planeNdx, 0u, 1u); for (size_t byteNdx = 0; byteNdx < planeSize; byteNdx++) { const deUint8 res = ((const deUint8*)result.getPlanePtr(planeNdx))[byteNdx]; const deUint8 ref = ((const deUint8*)reference.getPlanePtr(planeNdx))[byteNdx]; deUint8 mask = 0xFF; if (!(byteNdx & 0x01) && (ignoreLsb6Bits)) mask = 0xC0; else if (!(byteNdx & 0x01) && (ignoreLsb4Bits)) mask = 0xF0; if ((res & mask) != (ref & mask)) { log << TestLog::Message << "Plane: " << planeNdx << ", Offset: " << byteNdx << ", Expected: " << (deUint32)(ref & mask) << ", Got: " << (deUint32)(res & mask) << TestLog::EndMessage; errorCount++; if (errorCount > maxErrorCount) break; } } if (errorCount > maxErrorCount) break; } if (errorCount > 0) return tcu::TestStatus::fail("Failed, found " + (errorCount > maxErrorCount ? de::toString(maxErrorCount) + "+" : de::toString(errorCount)) + " incorrect bytes"); else return tcu::TestStatus::pass("Pass"); } } } bool isCopyCompatible (vk::VkFormat srcFormat, vk::VkFormat dstFormat) { if (isYCbCrFormat(srcFormat) && isYCbCrFormat(dstFormat)) { const vk::PlanarFormatDescription srcPlaneInfo (vk::getPlanarFormatDescription(srcFormat)); const vk::PlanarFormatDescription dstPlaneInfo (vk::getPlanarFormatDescription(dstFormat)); for (deUint32 srcPlaneNdx = 0; srcPlaneNdx < srcPlaneInfo.numPlanes; srcPlaneNdx++) { for (deUint32 dstPlaneNdx = 0; dstPlaneNdx < dstPlaneInfo.numPlanes; dstPlaneNdx++) { const vk::VkFormat srcPlaneFormat (getPlaneCompatibleFormat(srcFormat, srcPlaneNdx)); const vk::VkFormat dstPlaneFormat (getPlaneCompatibleFormat(dstFormat, dstPlaneNdx)); if (isCompatible(srcPlaneFormat, dstPlaneFormat)) return true; } } } else if (isYCbCrFormat(srcFormat)) { const vk::PlanarFormatDescription srcPlaneInfo (vk::getPlanarFormatDescription(srcFormat)); for (deUint32 srcPlaneNdx = 0; srcPlaneNdx < srcPlaneInfo.numPlanes; srcPlaneNdx++) { const vk::VkFormat srcPlaneFormat (getPlaneCompatibleFormat(srcFormat, srcPlaneNdx)); if (isCompatible(srcPlaneFormat, dstFormat)) return true; } } else if (isYCbCrFormat(dstFormat)) { const vk::PlanarFormatDescription dstPlaneInfo (vk::getPlanarFormatDescription(dstFormat)); for (deUint32 dstPlaneNdx = 0; dstPlaneNdx < dstPlaneInfo.numPlanes; dstPlaneNdx++) { const vk::VkFormat dstPlaneFormat (getPlaneCompatibleFormat(dstFormat, dstPlaneNdx)); if (isCompatible(dstPlaneFormat, srcFormat)) return true; } } else return isCompatible(srcFormat, dstFormat); return false; } void initYcbcrDefaultCopyTests (tcu::TestCaseGroup* testGroup) { const vk::VkFormat ycbcrFormats[] = { vk::VK_FORMAT_R4G4_UNORM_PACK8, vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16, vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16, vk::VK_FORMAT_R5G6B5_UNORM_PACK16, vk::VK_FORMAT_B5G6R5_UNORM_PACK16, vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16, vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16, vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16, vk::VK_FORMAT_R8_UNORM, vk::VK_FORMAT_R8G8_UNORM, vk::VK_FORMAT_R8G8B8_UNORM, vk::VK_FORMAT_B8G8R8_UNORM, vk::VK_FORMAT_R8G8B8A8_UNORM, vk::VK_FORMAT_B8G8R8A8_UNORM, vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32, vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32, vk::VK_FORMAT_R16_UNORM, vk::VK_FORMAT_R16G16_UNORM, vk::VK_FORMAT_R16G16B16_UNORM, vk::VK_FORMAT_R16G16B16A16_UNORM, vk::VK_FORMAT_B10G11R11_UFLOAT_PACK32, vk::VK_FORMAT_G8B8G8R8_422_UNORM, vk::VK_FORMAT_B8G8R8G8_422_UNORM, vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, vk::VK_FORMAT_R10X6_UNORM_PACK16, vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16, vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, vk::VK_FORMAT_R12X4_UNORM_PACK16, vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16, vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, vk::VK_FORMAT_G16B16G16R16_422_UNORM, vk::VK_FORMAT_B16G16R16G16_422_UNORM, vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, vk::VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT, vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT, vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT, vk::VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT, }; const struct { const char* name; vk::VkImageTiling value; } imageTilings[] = { { "linear", vk::VK_IMAGE_TILING_LINEAR }, { "optimal", vk::VK_IMAGE_TILING_OPTIMAL } }; tcu::TestContext& testCtx = testGroup->getTestContext(); for (size_t srcFormatNdx = 0; srcFormatNdx < DE_LENGTH_OF_ARRAY(ycbcrFormats); srcFormatNdx++) { const vk::VkFormat srcFormat (ycbcrFormats[srcFormatNdx]); const UVec2 srcSize (isYCbCrFormat(srcFormat) ? UVec2(24u, 16u) : UVec2(23u, 17u)); const string srcFormatName (de::toLower(std::string(getFormatName(srcFormat)).substr(10))); de::MovePtr srcFormatGroup (new tcu::TestCaseGroup(testCtx, srcFormatName.c_str(), ("Tests for copies using format " + srcFormatName).c_str())); for (size_t dstFormatNdx = 0; dstFormatNdx < DE_LENGTH_OF_ARRAY(ycbcrFormats); dstFormatNdx++) { const vk::VkFormat dstFormat (ycbcrFormats[dstFormatNdx]); const UVec2 dstSize (isYCbCrFormat(dstFormat) ? UVec2(24u, 16u) : UVec2(23u, 17u)); const string dstFormatName (de::toLower(std::string(getFormatName(dstFormat)).substr(10))); if ((!vk::isYCbCrFormat(srcFormat) && !vk::isYCbCrFormat(dstFormat)) || !isCopyCompatible(srcFormat, dstFormat)) continue; de::MovePtr dstFormatGroup (new tcu::TestCaseGroup(testCtx, dstFormatName.c_str(), ("Tests for copies using format " + dstFormatName).c_str())); for (size_t srcTilingNdx = 0; srcTilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); srcTilingNdx++) { const vk::VkImageTiling srcTiling = imageTilings[srcTilingNdx].value; const char* const srcTilingName = imageTilings[srcTilingNdx].name; for (size_t dstTilingNdx = 0; dstTilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); dstTilingNdx++) { const vk::VkImageTiling dstTiling = imageTilings[dstTilingNdx].value; const char* const dstTilingName = imageTilings[dstTilingNdx].name; for (size_t srcDisjointNdx = 0; srcDisjointNdx < 2; srcDisjointNdx++) for (size_t dstDisjointNdx = 0; dstDisjointNdx < 2; dstDisjointNdx++) { const bool srcDisjoint = srcDisjointNdx == 1; const bool dstDisjoint = dstDisjointNdx == 1; const TestConfig config (ImageConfig(srcFormat, srcTiling, srcDisjoint, srcSize), ImageConfig(dstFormat, dstTiling, dstDisjoint, dstSize)); addFunctionCase(dstFormatGroup.get(), string(srcTilingName) + (srcDisjoint ? "_disjoint_" : "_") + string(dstTilingName) + (dstDisjoint ? "_disjoint" : ""), "", checkSupport, imageCopyTest, config); } } } srcFormatGroup->addChild(dstFormatGroup.release()); } testGroup->addChild(srcFormatGroup.release()); } } void initYcbcrDimensionsCopyTests (tcu::TestCaseGroup* testGroup) { tcu::TestContext& testCtx = testGroup->getTestContext(); const vk::VkFormat testFormats[] = { // 8-bit vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, // 10-bit vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, // 12-bit vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, // 16-bit vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, // Non-ycbcr vk::VK_FORMAT_R8G8B8A8_UNORM, }; const tcu::UVec2 imageDimensions[] = { // Wide: large pot x small pot tcu::UVec2(4096, 4u), tcu::UVec2(8192, 4u), tcu::UVec2(16384, 4u), tcu::UVec2(32768, 4u), // Wide: large pot x small npot tcu::UVec2(4096, 6u), tcu::UVec2(8192, 6u), tcu::UVec2(16384, 6u), tcu::UVec2(32768, 6u), // Tall: small pot x large pot tcu::UVec2(4u, 4096), tcu::UVec2(4u, 8192), tcu::UVec2(4u, 16384), tcu::UVec2(4u, 32768), // Tall: small npot x large pot tcu::UVec2(6u, 4096), tcu::UVec2(6u, 8192), tcu::UVec2(6u, 16384), tcu::UVec2(6u, 32768) }; const struct { const char* name; vk::VkImageTiling value; } imageTilings[] = { { "linear", vk::VK_IMAGE_TILING_LINEAR }, { "optimal", vk::VK_IMAGE_TILING_OPTIMAL } }; for (size_t imageDimensionNdx = 0; imageDimensionNdx < DE_LENGTH_OF_ARRAY(imageDimensions); imageDimensionNdx++) { const UVec2 srcSize (imageDimensions[imageDimensionNdx]); const UVec2 dstSize (imageDimensions[imageDimensionNdx]); const string dimensionsName ("src" + de::toString(srcSize.x()) + "x" + de::toString(srcSize.y()) + "_dst" + de::toString(dstSize.x()) + "x" + de::toString(dstSize.y())); de::MovePtr dimensionGroup (new tcu::TestCaseGroup(testCtx, dimensionsName.c_str(), ("Image dimensions " + dimensionsName).c_str())); for (size_t srcFormatNdx = 0; srcFormatNdx < DE_LENGTH_OF_ARRAY(testFormats); srcFormatNdx++) { const vk::VkFormat srcFormat (testFormats[srcFormatNdx]); const string srcFormatName (de::toLower(std::string(getFormatName(srcFormat)).substr(10))); de::MovePtr srcFormatGroup (new tcu::TestCaseGroup(testCtx, srcFormatName.c_str(), ("Tests for copies using format " + srcFormatName).c_str())); for (size_t dstFormatNdx = 0; dstFormatNdx < DE_LENGTH_OF_ARRAY(testFormats); dstFormatNdx++) { const vk::VkFormat dstFormat (testFormats[dstFormatNdx]); const string dstFormatName (de::toLower(std::string(getFormatName(dstFormat)).substr(10))); if ((!vk::isYCbCrFormat(srcFormat) && !vk::isYCbCrFormat(dstFormat)) || !isCopyCompatible(srcFormat, dstFormat)) continue; de::MovePtr dstFormatGroup (new tcu::TestCaseGroup(testCtx, dstFormatName.c_str(), ("Tests for copies using format " + dstFormatName).c_str())); for (size_t srcTilingNdx = 0; srcTilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); srcTilingNdx++) { const vk::VkImageTiling srcTiling = imageTilings[srcTilingNdx].value; const char* const srcTilingName = imageTilings[srcTilingNdx].name; for (size_t dstTilingNdx = 0; dstTilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); dstTilingNdx++) { const vk::VkImageTiling dstTiling = imageTilings[dstTilingNdx].value; const char* const dstTilingName = imageTilings[dstTilingNdx].name; for (size_t srcDisjointNdx = 0; srcDisjointNdx < 2; srcDisjointNdx++) for (size_t dstDisjointNdx = 0; dstDisjointNdx < 2; dstDisjointNdx++) { const bool srcDisjoint = srcDisjointNdx == 1; const bool dstDisjoint = dstDisjointNdx == 1; const TestConfig config (ImageConfig(srcFormat, srcTiling, srcDisjoint, srcSize), ImageConfig(dstFormat, dstTiling, dstDisjoint, dstSize)); addFunctionCase(dstFormatGroup.get(), string(srcTilingName) + (srcDisjoint ? "_disjoint_" : "_") + string(dstTilingName) + (dstDisjoint ? "_disjoint" : ""), "", checkSupport, imageCopyTest, config); } } } srcFormatGroup->addChild(dstFormatGroup.release()); } dimensionGroup->addChild(srcFormatGroup.release()); } testGroup->addChild(dimensionGroup.release()); } } } // anonymous tcu::TestCaseGroup* createCopyTests (tcu::TestContext& testCtx) { return createTestGroup(testCtx, "copy", "YCbCr Format Copy Tests", initYcbcrDefaultCopyTests); } tcu::TestCaseGroup* createDimensionsCopyTests (tcu::TestContext& testCtx) { return createTestGroup(testCtx, "copy_dimensions", "YCbCr format copy tests between different image dimensions", initYcbcrDimensionsCopyTests); } } // ycbcr } // vkt