blob: b2c4e7321bdfe84e6686c24b2fbf14c788165955 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
*
* Copyright (c) 2022 Khronos Group
*
* 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 Test for Image Compression control
*/ /*--------------------------------------------------------------------*/
#include <iostream>
#include <typeinfo>
#include "tcuCommandLine.hpp"
#include "tcuDefs.hpp"
#include "tcuFunctionLibrary.hpp"
#include "tcuPlatform.hpp"
#include "tcuResultCollector.hpp"
#include "tcuTestCase.hpp"
#include "tcuTestLog.hpp"
#include "vkApiVersion.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
#include "vktApiVersionCheck.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vktExternalMemoryUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vkDeviceUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkRefUtil.hpp"
#include "deString.h"
#include "deStringUtil.hpp"
#include <map>
#include <vector>
using namespace vk;
using namespace std;
namespace vkt
{
namespace api
{
struct TestParams
{
VkFormat format;
bool useExtension;
VkImageCompressionControlEXT control;
};
static void checkImageCompressionControlSupport(Context& context)
{
context.requireDeviceFunctionality("VK_EXT_image_compression_control");
vk::VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompressionControlFeatures{};
imageCompressionControlFeatures.sType =
vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT;
imageCompressionControlFeatures.pNext = DE_NULL;
vk::VkPhysicalDeviceFeatures2 features2{};
features2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features2.pNext = &imageCompressionControlFeatures;
context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
if (!imageCompressionControlFeatures.imageCompressionControl)
TCU_THROW(NotSupportedError, "VK_EXT_image_compression_control Image "
"compression control feature not supported.");
}
static void validate(Context& context, tcu::ResultCollector& results, VkDevice device, TestParams& testParams,
VkImage image)
{
constexpr VkImageAspectFlags planeAspects[]{ VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT,
VK_IMAGE_ASPECT_PLANE_2_BIT };
const bool isYCbCr = isYCbCrFormat(testParams.format);
const int numPlanes = isYCbCr ? getPlaneCount(testParams.format) : 1;
for (int planeIndex = 0; planeIndex < numPlanes; planeIndex++)
{
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
if (isYCbCr)
{
aspect = planeAspects[planeIndex];
}
VkImageCompressionPropertiesEXT compressionProperties = initVulkanStructure();
VkImageSubresource2EXT subresource = initVulkanStructure();
subresource.imageSubresource.aspectMask = aspect;
VkSubresourceLayout2EXT subresourceLayout = initVulkanStructure(&compressionProperties);
context.getDeviceInterface().getImageSubresourceLayout2EXT(device, image, &subresource, &subresourceLayout);
VkImageCompressionFixedRateFlagsEXT fixedRateFlags[3] = {
VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT,
VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT,
VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT
};
VkImageCompressionControlEXT compressionEnabled = initVulkanStructure();
compressionEnabled.compressionControlPlaneCount = testParams.control.compressionControlPlaneCount;
compressionEnabled.flags = testParams.control.flags;
if (compressionEnabled.compressionControlPlaneCount > 0)
{
compressionEnabled.pFixedRateFlags = fixedRateFlags;
}
VkPhysicalDeviceImageFormatInfo2 formatInfo = initVulkanStructure(&compressionEnabled);
formatInfo.format = testParams.format;
formatInfo.type = VK_IMAGE_TYPE_2D;
formatInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
formatInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
VkImageCompressionPropertiesEXT compressionPropertiesSupported = initVulkanStructure();
VkImageFormatProperties2 properties2 = initVulkanStructure(&compressionPropertiesSupported);
context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &formatInfo,
&properties2);
if (testParams.useExtension)
{
if ((compressionPropertiesSupported.imageCompressionFixedRateFlags &
compressionProperties.imageCompressionFixedRateFlags) !=
compressionProperties.imageCompressionFixedRateFlags)
{
results.fail("Got image with fixed rate flags that are not supported "
"in image format properties.");
}
if ((compressionPropertiesSupported.imageCompressionFlags & compressionProperties.imageCompressionFlags) !=
compressionProperties.imageCompressionFlags &&
compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT)
{
results.fail("Got image with compression flags that are not supported "
"in image format properties.");
}
if (testParams.control.flags == VK_IMAGE_COMPRESSION_DEFAULT_EXT &&
compressionProperties.imageCompressionFixedRateFlags != 0)
{
results.fail("Got lossy compression when DEFAULT compression was requested.");
}
if (testParams.control.flags == VK_IMAGE_COMPRESSION_DISABLED_EXT &&
compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT)
{
results.fail("Image compression not disabled.");
}
if (testParams.control.flags == VK_IMAGE_COMPRESSION_DISABLED_EXT &&
compressionProperties.imageCompressionFixedRateFlags != 0)
{
results.fail("Image compression disabled but got fixed rate flags.");
}
if (testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT &&
!(compressionProperties.imageCompressionFlags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT ||
compressionProperties.imageCompressionFlags == VK_IMAGE_COMPRESSION_DISABLED_EXT ||
compressionProperties.imageCompressionFlags == VK_IMAGE_COMPRESSION_DEFAULT_EXT))
{
results.fail("Explicit compression flags not returned for image "
"creation with FIXED RATE DEFAULT.");
}
if (testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT)
{
uint32_t minRequestedRate = 1 << deCtz32(testParams.control.pFixedRateFlags[planeIndex]);
uint32_t actualRate = compressionProperties.imageCompressionFixedRateFlags;
if (compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT &&
compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DEFAULT_EXT)
{
if (minRequestedRate > actualRate)
{
results.fail("Image created with less bpc than requested.");
}
}
}
}
else
{
if (compressionProperties.imageCompressionFixedRateFlags != VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT)
{
results.fail("Fixed rate compression should not be enabled.");
}
if (compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT &&
compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DEFAULT_EXT)
{
results.fail("Image compression should be default or not be enabled.");
}
}
}
}
static tcu::TestStatus ahbImageCreateTest(Context& context, TestParams testParams)
{
using namespace vkt::ExternalMemoryUtil;
context.requireDeviceFunctionality("VK_ANDROID_external_memory_android_hardware_buffer");
context.requireDeviceFunctionality("VK_EXT_image_compression_control");
const deUint32 width = 32;
const deUint32 height = 32;
deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
const vk::DeviceInterface& vkd = context.getDeviceInterface();
VkDevice device = context.getDevice();
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results(log);
const bool is_fixed_rate_ex = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
const uint32_t numPlanes = isYCbCrFormat(testParams.format) ? getPlaneCount(testParams.format) : 1;
testParams.control.compressionControlPlaneCount = is_fixed_rate_ex ? numPlanes : 0;
VkImageCompressionFixedRateFlagsEXT planeFlags[3]{};
for (unsigned i{}; i < (is_fixed_rate_ex ? 24 : 1); i++)
{
planeFlags[0] ^= 3 << i;
planeFlags[1] ^= 5 << i;
planeFlags[2] ^= 7 << i;
if (is_fixed_rate_ex)
{
testParams.control.compressionControlPlaneCount = numPlanes;
testParams.control.pFixedRateFlags = planeFlags;
}
const vk::VkExternalMemoryImageCreateInfo externalCreateInfo = {
vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, &testParams.control,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
};
const vk::VkImageCreateInfo createInfo = { vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
&externalCreateInfo,
0,
vk::VK_IMAGE_TYPE_2D,
testParams.format,
{
width,
height,
1u,
},
1,
1,
vk::VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_SAMPLED_BIT,
vk::VK_SHARING_MODE_EXCLUSIVE,
1,
&queueFamilyIndex,
vk::VK_IMAGE_LAYOUT_UNDEFINED };
Move<VkImage> image = vk::createImage(vkd, device, &createInfo);
const VkMemoryRequirements requirements = ExternalMemoryUtil::getImageMemoryRequirements(
vkd, device, image.get(), VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID);
const deUint32 exportedMemoryTypeIndex(ExternalMemoryUtil::chooseMemoryType(requirements.memoryTypeBits));
Move<VkDeviceMemory> memory = ExternalMemoryUtil::allocateExportableMemory(
vkd, device, requirements.size, exportedMemoryTypeIndex,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, image.get());
VK_CHECK(vkd.bindImageMemory(device, image.get(), memory.get(), 0u));
validate(context, results, context.getDevice(), testParams, image.get());
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
static tcu::TestStatus imageCreateTest(Context& context, TestParams testParams)
{
checkImageCompressionControlSupport(context);
deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
const VkDevice device = context.getDevice();
VkExtent3D extent = { 16, 16, 1 };
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results(log);
const bool is_fixed_rate_ex = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
VkImageCompressionFixedRateFlagsEXT planeFlags[3]{};
for (unsigned i{}; i < (is_fixed_rate_ex ? 24 : 1); i++)
{
planeFlags[0] ^= 3 << i;
planeFlags[1] ^= 5 << i;
planeFlags[2] ^= 7 << i;
if (is_fixed_rate_ex)
{
testParams.control.pFixedRateFlags = planeFlags;
}
VkImageCreateInfo imageCreateInfo = {
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType
testParams.format, // VkFormat format;
extent, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
if (testParams.useExtension)
{
imageCreateInfo.pNext = &testParams.control;
}
checkImageSupport(context.getInstanceInterface(), context.getPhysicalDevice(), imageCreateInfo);
Move<VkImage> image = createImage(context.getDeviceInterface(), device, &imageCreateInfo);
validate(context, results, context.getDevice(), testParams, image.get());
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
void addImageCompressionControlTests(tcu::TestCaseGroup* group, TestParams testParams)
{
const bool is_fixed_rate_ex = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
static const struct
{
VkFormat begin;
VkFormat end;
} s_formatRanges[] = {
// core formats
{ (VkFormat)(VK_FORMAT_UNDEFINED + 1), VK_CORE_FORMAT_LAST },
// YCbCr formats
{ VK_FORMAT_G8B8G8R8_422_UNORM, (VkFormat)(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM + 1) },
// YCbCr extended formats
{ VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT, (VkFormat)(VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT + 1) },
};
for (int rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(s_formatRanges); ++rangeNdx)
{
const VkFormat rangeBegin = s_formatRanges[rangeNdx].begin;
const VkFormat rangeEnd = s_formatRanges[rangeNdx].end;
for (testParams.format = rangeBegin; testParams.format != rangeEnd;
testParams.format = (VkFormat)(testParams.format + 1))
{
if (isCompressedFormat(testParams.format))
continue;
const uint32_t numPlanes = isYCbCrFormat(testParams.format) ? getPlaneCount(testParams.format) : 1;
testParams.control.compressionControlPlaneCount = is_fixed_rate_ex ? numPlanes : 0;
const char* const enumName = getFormatName(testParams.format);
const string caseName = de::toLower(string(enumName).substr(10));
addFunctionCase(group, caseName, enumName, imageCreateTest, testParams);
}
}
}
tcu::TestCaseGroup* createImageCompressionControlTests(tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(
new tcu::TestCaseGroup(testCtx, "image_compression_control", "Test for image compression control."));
TestParams testParams{};
tcu::TestCaseGroup* subgroup(
new tcu::TestCaseGroup(testCtx, "create_image", "Test creating images with compression control struct"));
subgroup->addChild(createTestGroup(testCtx, "no_compression_control",
"Queries images created without compression control struct.",
addImageCompressionControlTests, testParams));
testParams.useExtension = true;
testParams.control = initVulkanStructure();
testParams.control.flags = VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT;
struct
{
const char* name;
VkImageCompressionFlagsEXT flag;
} constexpr compression_flags[] = {
{ "default", VK_IMAGE_COMPRESSION_DEFAULT_EXT },
{ "fixed_rate_default", VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT },
{ "disabled", VK_IMAGE_COMPRESSION_DISABLED_EXT },
{ "explicit", VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT },
};
for (auto& flag : compression_flags)
{
testParams.control.flags = flag.flag;
subgroup->addChild(createTestGroup(testCtx, flag.name,
"Queries images created with compression control struct.",
addImageCompressionControlTests, testParams));
}
group->addChild(subgroup);
subgroup = new tcu::TestCaseGroup(testCtx, "android_hardware_buffer",
"Test creating Android Hardware buffer with compression control struct");
for (auto& flag : compression_flags)
{
testParams.control.flags = flag.flag;
addFunctionCase(subgroup, flag.name, flag.name, ahbImageCreateTest, testParams);
}
group->addChild(subgroup);
return group.release();
}
} // namespace api
} // namespace vkt