blob: 5740083fa0ba3f8e96aa6b1595bd6d45307bd1d4 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* 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
*/
#include <gtest/gtest.h>
#include <vulkan/vulkan_core.h>
#include "../framework/layer_validation_tests.h"
#include "../framework/descriptor_helper.h"
#include "../framework/pipeline_helper.h"
class NegativeYcbcr : public VkLayerTest {};
TEST_F(NegativeYcbcr, Sampler) {
TEST_DESCRIPTION("Verify YCbCr sampler creation.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
PFN_vkSetPhysicalDeviceFormatPropertiesEXT fpvkSetPhysicalDeviceFormatPropertiesEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceFormatPropertiesEXT, fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE;
VkSamplerYcbcrConversionCreateInfo sycci = vku::InitStructHelper();
sycci.format = VK_FORMAT_UNDEFINED;
sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
sycci.forceExplicitReconstruction = VK_FALSE;
sycci.chromaFilter = VK_FILTER_NEAREST;
sycci.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
// test non external conversion with a VK_FORMAT_UNDEFINED
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-format-04061");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// test for non unorm
sycci.format = VK_FORMAT_R8G8B8A8_SNORM;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-format-04061");
m_errorMonitor->SetUnexpectedError("VUID-VkSamplerYcbcrConversionCreateInfo-format-01650");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Force the multi-planar format support desired format features
VkFormat mp_format = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM;
VkFormatProperties formatProps;
fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, &formatProps);
formatProps.linearTilingFeatures = 0;
formatProps.optimalTilingFeatures = 0;
fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, formatProps);
// Check that errors are caught when format feature don't exist
sycci.format = mp_format;
// No Chroma Sampler Bit set
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-format-01650");
// 01651 set off twice for both xChromaOffset and yChromaOffset
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01651");
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01651");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Cosited feature supported, but midpoint samples set
formatProps.linearTilingFeatures = 0;
formatProps.optimalTilingFeatures = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, formatProps);
sycci.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01652");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Moving support to Linear to test that it checks either linear or optimal
formatProps.linearTilingFeatures = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
formatProps.optimalTilingFeatures = 0;
fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, formatProps);
sycci.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01652");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Using forceExplicitReconstruction without feature bit
sycci.forceExplicitReconstruction = VK_TRUE;
sycci.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-forceExplicitReconstruction-01656");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Linear chroma filtering without feature bit
sycci.forceExplicitReconstruction = VK_FALSE;
sycci.chromaFilter = VK_FILTER_LINEAR;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-01657");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Add linear feature bit so can create valid SamplerYcbcrConversion
formatProps.linearTilingFeatures = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
formatProps.optimalTilingFeatures = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, formatProps);
vkt::SamplerYcbcrConversion conversion(*m_device, sycci);
// Try to create a Sampler with non-matching filters without feature bit set
VkSamplerYcbcrConversionInfo sampler_ycbcr_info = vku::InitStructHelper();
sampler_ycbcr_info.conversion = conversion;
VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo();
sampler_info.minFilter = VK_FILTER_NEAREST; // Different than chromaFilter
sampler_info.magFilter = VK_FILTER_LINEAR;
sampler_info.pNext = (void *)&sampler_ycbcr_info;
CreateSamplerTest(sampler_info, "VUID-VkSamplerCreateInfo-minFilter-01645");
sampler_info.magFilter = VK_FILTER_NEAREST;
sampler_info.minFilter = VK_FILTER_LINEAR;
CreateSamplerTest(sampler_info, "VUID-VkSamplerCreateInfo-minFilter-01645");
}
TEST_F(NegativeYcbcr, Swizzle) {
TEST_DESCRIPTION("Verify Invalid use of siwizzle components when dealing with YCbCr.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
const VkFormat mp_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
// Make sure components doesn't affect _444 formats
VkFormatProperties format_props;
vk::GetPhysicalDeviceFormatProperties(Gpu(), mp_format, &format_props);
if ((format_props.optimalTilingFeatures &
(VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT)) == 0) {
GTEST_SKIP() << "Device does not support chroma sampling of 3plane 420 format";
}
const VkComponentMapping identity = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
VkSamplerYcbcrConversion ycbcr_conv = VK_NULL_HANDLE;
VkSamplerYcbcrConversionCreateInfo sycci = vku::InitStructHelper();
sycci.format = mp_format;
sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
sycci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
sycci.forceExplicitReconstruction = VK_FALSE;
sycci.chromaFilter = VK_FILTER_NEAREST;
sycci.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
sycci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
// test components.g
// This test is also serves as positive form of VU 01655 since SWIZZLE_A is considered only valid with this format because
// ycbcrModel RGB_IDENTITY
sycci.components = identity;
sycci.components.g = VK_COMPONENT_SWIZZLE_A;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02581");
vk::CreateSamplerYcbcrConversion(device(), &sycci, NULL, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// test components.a
sycci.components = identity;
sycci.components.a = VK_COMPONENT_SWIZZLE_R;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02582");
vk::CreateSamplerYcbcrConversion(device(), &sycci, NULL, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// make sure zero and one are allowed for components.a
{
sycci.components.a = VK_COMPONENT_SWIZZLE_ONE;
vkt::SamplerYcbcrConversion conversion(*m_device, sycci);
}
{
sycci.components.a = VK_COMPONENT_SWIZZLE_ZERO;
vkt::SamplerYcbcrConversion conversion(*m_device, sycci);
}
// test components.r
sycci.components = identity;
sycci.components.r = VK_COMPONENT_SWIZZLE_G;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02583");
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02585");
vk::CreateSamplerYcbcrConversion(device(), &sycci, NULL, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// test components.b
sycci.components = identity;
sycci.components.b = VK_COMPONENT_SWIZZLE_G;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02584");
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02585");
vk::CreateSamplerYcbcrConversion(device(), &sycci, NULL, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// test components.r and components.b together
sycci.components = identity;
sycci.components.r = VK_COMPONENT_SWIZZLE_B;
sycci.components.b = VK_COMPONENT_SWIZZLE_B;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02585");
vk::CreateSamplerYcbcrConversion(device(), &sycci, NULL, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// make sure components.r and components.b can be swapped
{
sycci.components = identity;
sycci.components.r = VK_COMPONENT_SWIZZLE_B;
sycci.components.b = VK_COMPONENT_SWIZZLE_R;
vkt::SamplerYcbcrConversion conversion(*m_device, sycci);
}
// Non RGB Identity model
sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY;
{
// Non RGB Identity can't have a explicit zero swizzle
sycci.components = identity;
sycci.components.g = VK_COMPONENT_SWIZZLE_ZERO;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrModel-01655");
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02581");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// Non RGB Identity can't have a explicit one swizzle
sycci.components = identity;
sycci.components.g = VK_COMPONENT_SWIZZLE_ONE;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrModel-01655");
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02581");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
// VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM has 3 component so RGBA conversion has implicit A as one
sycci.components = identity;
sycci.components.g = VK_COMPONENT_SWIZZLE_A;
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrModel-01655");
m_errorMonitor->SetDesiredError("VUID-VkSamplerYcbcrConversionCreateInfo-components-02581");
vk::CreateSamplerYcbcrConversion(device(), &sycci, nullptr, &ycbcr_conv);
m_errorMonitor->VerifyFound();
}
sycci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; // reset
// Make sure components doesn't affect _444 formats
vk::GetPhysicalDeviceFormatProperties(Gpu(), VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, &format_props);
if ((format_props.optimalTilingFeatures & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0) {
sycci.format = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM;
sycci.components = identity;
sycci.components.g = VK_COMPONENT_SWIZZLE_R;
vkt::SamplerYcbcrConversion conversion(*m_device, sycci);
}
// Create a valid conversion with guaranteed support
sycci.format = mp_format;
sycci.components = identity;
vkt::SamplerYcbcrConversion conversion(*m_device, sycci);
vkt::Image image(*m_device, 128, 128, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
VkSamplerYcbcrConversionInfo conversion_info = vku::InitStructHelper();
conversion_info.conversion = conversion;
VkImageViewCreateInfo image_view_create_info = vku::InitStructHelper(&conversion_info);
image_view_create_info.image = image;
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_create_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_view_create_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
image_view_create_info.components = identity;
image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_B;
CreateImageViewTest(image_view_create_info, "VUID-VkImageViewCreateInfo-pNext-01970");
}
TEST_F(NegativeYcbcr, Formats) {
TEST_DESCRIPTION("Creating images with Ycbcr Formats.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
PFN_vkSetPhysicalDeviceFormatPropertiesEXT fpvkSetPhysicalDeviceFormatPropertiesEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceFormatPropertiesEXT, fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
if (!FormatIsSupported(Gpu(), VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM)) {
GTEST_SKIP() << "VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM is unsupported";
}
// Set format features as needed for tests
VkFormatProperties formatProps;
const VkFormat mp_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, &formatProps);
formatProps.optimalTilingFeatures |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
formatProps.optimalTilingFeatures = formatProps.optimalTilingFeatures & ~VK_FORMAT_FEATURE_DISJOINT_BIT;
fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, formatProps);
// Create ycbcr image with all valid values
// Each test changes needed values and returns them back after
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = mp_format;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image_create_info.arrayLayers = 1;
VkImageCreateInfo reset_create_info = image_create_info;
// invalid samples count
image_create_info.samples = VK_SAMPLE_COUNT_4_BIT;
// Might need to add extra validation because implementation probably doesn't support YUV
VkImageFormatProperties image_format_props;
GetImageFormatProps(Gpu(), image_create_info, image_format_props);
if ((image_format_props.sampleCounts & VK_SAMPLE_COUNT_4_BIT) == 0) {
m_errorMonitor->SetDesiredError("VUID-VkImageCreateInfo-samples-02258");
}
CreateImageTest(image_create_info, "VUID-VkImageCreateInfo-format-06411");
image_create_info = reset_create_info;
// invalid width
image_create_info.extent.width = 31;
CreateImageTest(image_create_info, "VUID-VkImageCreateInfo-format-04712");
image_create_info = reset_create_info;
// invalid height (since 420 format)
image_create_info.extent.height = 31;
CreateImageTest(image_create_info, "VUID-VkImageCreateInfo-format-04713");
image_create_info = reset_create_info;
// invalid imageType
image_create_info.imageType = VK_IMAGE_TYPE_1D;
if (GetImageFormatProps(Gpu(), image_create_info, image_format_props) == VK_SUCCESS) {
// Can't just set height to 1 as stateless validation will hit 04713 first
m_errorMonitor->SetUnexpectedError("VUID-VkImageCreateInfo-imageType-00956");
m_errorMonitor->SetUnexpectedError("VUID-VkImageCreateInfo-extent-02253");
CreateImageTest(image_create_info, "VUID-VkImageCreateInfo-format-06412");
}
image_create_info = reset_create_info;
// Test using a format that doesn't support disjoint
image_create_info.flags = VK_IMAGE_CREATE_DISJOINT_BIT;
CreateImageTest(image_create_info, "VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260");
image_create_info = reset_create_info;
}
TEST_F(NegativeYcbcr, FormatsLimits) {
TEST_DESCRIPTION("Creating images with Ycbcr Formats.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
PFN_vkSetPhysicalDeviceFormatPropertiesEXT fpvkSetPhysicalDeviceFormatPropertiesEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceFormatPropertiesEXT fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceFormatPropertiesEXT, fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
if (!FormatIsSupported(Gpu(), VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM)) {
GTEST_SKIP() << "VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM is unsupported";
}
// Set format features as needed for tests
VkFormatProperties formatProps;
const VkFormat mp_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
fpvkGetOriginalPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, &formatProps);
formatProps.optimalTilingFeatures |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
formatProps.optimalTilingFeatures = formatProps.optimalTilingFeatures & ~VK_FORMAT_FEATURE_DISJOINT_BIT;
fpvkSetPhysicalDeviceFormatPropertiesEXT(Gpu(), mp_format, formatProps);
// Create ycbcr image with all valid values
// Each test changes needed values and returns them back after
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = mp_format;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
image_create_info.arrayLayers = 1;
VkImageFormatProperties img_limits;
ASSERT_EQ(VK_SUCCESS, GetImageFormatProps(Gpu(), image_create_info, img_limits));
if (img_limits.maxMipLevels == 1) {
GTEST_SKIP() << "Multiplane image maxMipLevels is already 1.";
}
// needs to be 2
// if more then 2 the VU since its larger the (depth^2 + 1)
// if up the depth the VU for IMAGE_TYPE_2D and depth != 1 hits
image_create_info.mipLevels = 2;
CreateImageTest(image_create_info, "VUID-VkImageCreateInfo-format-06410");
}
TEST_F(NegativeYcbcr, ImageViewFormat) {
TEST_DESCRIPTION("Creating image view with invalid formats, but use image format list to get a valid VkImage.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (!FormatIsSupported(Gpu(), VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM)) {
GTEST_SKIP() << "VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM is unsupported";
}
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
image_create_info.extent = {31, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.arrayLayers = 1;
// The only way around this is to use VK_KHR_image_format_list, but currently could not find anyone who supports it for YCbCr
// formats, but could in the future
m_errorMonitor->SetAllowedFailureMsg("VUID-VkImageCreateInfo-format-04712");
vkt::Image image(*m_device, image_create_info);
if (!image.initialized()) {
GTEST_SKIP() << "image couldn't be created";
}
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
auto ivci = vku::InitStruct<VkImageViewCreateInfo>(&conversion_info);
ivci.image = image;
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
ivci.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
m_errorMonitor->SetDesiredError("VUID-VkImageViewCreateInfo-format-04714");
vkt::ImageView view(*m_device, ivci);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, CopyImageSinglePlane422Alignment) {
TEST_DESCRIPTION("Image copy tests on single-plane _422 formats with block alignment errors");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
VkImageCreateInfo ci = vku::InitStructHelper();
ci.flags = 0;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_G8B8G8R8_422_UNORM;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
VkFormatFeatureFlags features = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
if (!IsImageFormatSupported(Gpu(), ci, features)) {
// Assume there's low ROI on searching for different mp formats
GTEST_SKIP() << "Single-plane _422 image format not supported";
}
ci.extent = {64, 64, 1};
vkt::Image image_422(*m_device, ci, vkt::set_layout);
ci.extent = {64, 64, 1};
ci.format = VK_FORMAT_R8G8B8A8_UNORM;
vkt::Image image_ucmp(*m_device, ci, vkt::set_layout);
m_command_buffer.Begin();
VkImageCopy copy_region;
copy_region.extent = {24, 48, 1};
copy_region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
copy_region.srcOffset = {0, 0, 0};
copy_region.dstOffset = {0, 0, 0};
// Src offsets must be multiples of compressed block sizes
copy_region.srcOffset = {3, 4, 0}; // source offset x
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-pRegions-07278");
vk::CmdCopyImage(m_command_buffer, image_422, VK_IMAGE_LAYOUT_GENERAL, image_ucmp, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.srcOffset = {0, 0, 0};
// Dst offsets must be multiples of compressed block sizes
copy_region.dstOffset = {1, 0, 0};
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-pRegions-07281");
vk::CmdCopyImage(m_command_buffer, image_ucmp, VK_IMAGE_LAYOUT_GENERAL, image_422, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.dstOffset = {0, 0, 0};
// Copy extent must be multiples of compressed block sizes if not full width/height
copy_region.extent = {31, 60, 1}; // 422 source, extent.x
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-srcImage-01728");
vk::CmdCopyImage(m_command_buffer, image_422, VK_IMAGE_LAYOUT_GENERAL, image_ucmp, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, MultiplaneImageCopyBufferToImage) {
TEST_DESCRIPTION("Positive test of multiplane copy buffer to image");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
auto ci = vku::InitStruct<VkImageCreateInfo>();
ci.flags = 0;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM; // All planes of equal extent
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
ci.extent = {16, 16, 1};
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
VkFormatFeatureFlags features = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
if (!IsImageFormatSupported(Gpu(), ci, features)) {
// Assume there's low ROI on searching for different mp formats
GTEST_SKIP() << "Multiplane image format not supported";
}
vkt::Image image(*m_device, ci);
m_command_buffer.Reset();
m_command_buffer.Begin();
image.ImageMemoryBarrier(m_command_buffer, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
std::array<VkImageAspectFlagBits, 3> aspects = {
{VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT}};
std::array<vkt::Buffer, 3> buffers;
VkBufferImageCopy copy = {};
copy.imageSubresource.layerCount = 1;
copy.imageExtent = {16, 16, 1};
copy.bufferOffset = 16; // pushes over
for (size_t i = 0; i < aspects.size(); ++i) {
buffers[i].Init(*m_device, 16 * 16 * 1, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
copy.imageSubresource.aspectMask = aspects[i];
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyBufferToImage-pRegions-00171");
vk::CmdCopyBufferToImage(m_command_buffer, buffers[i], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy);
m_errorMonitor->VerifyFound();
}
m_command_buffer.End();
}
TEST_F(NegativeYcbcr, CopyImageMultiplaneAspectBits) {
// Image copy tests on multiplane images with aspect errors
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
// Select multi-plane formats and verify support
VkFormat mp3_format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM;
VkFormat mp2_format = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM;
VkImageCreateInfo ci = vku::InitStructHelper();
ci.flags = 0;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = mp2_format;
ci.extent = {256, 256, 1};
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
// Verify formats
VkFormatFeatureFlags features = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
bool supported = IsImageFormatSupported(Gpu(), ci, features);
ci.format = VK_FORMAT_D24_UNORM_S8_UINT;
supported = supported && IsImageFormatSupported(Gpu(), ci, features);
ci.format = mp3_format;
supported = supported && IsImageFormatSupported(Gpu(), ci, features);
if (!supported) {
// Assume there's low ROI on searching for different mp formats
GTEST_SKIP() << "Multiplane image formats or optimally tiled depth-stencil buffers not supported";
}
// Create images
vkt::Image mp3_image(*m_device, ci, vkt::set_layout);
ci.format = mp2_format;
vkt::Image mp2_image(*m_device, ci, vkt::set_layout);
ci.format = VK_FORMAT_D24_UNORM_S8_UINT;
vkt::Image sp_image(*m_device, ci, vkt::set_layout);
m_command_buffer.Begin();
VkImageCopy copy_region;
copy_region.extent = {128, 128, 1};
copy_region.srcSubresource = {VK_IMAGE_ASPECT_PLANE_2_BIT, 0, 0, 1};
copy_region.dstSubresource = {VK_IMAGE_ASPECT_PLANE_2_BIT, 0, 0, 1};
copy_region.srcOffset = {0, 0, 0};
copy_region.dstOffset = {0, 0, 0};
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-srcImage-08713");
vk::CmdCopyImage(m_command_buffer, mp2_image, VK_IMAGE_LAYOUT_GENERAL, mp3_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT;
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-srcImage-08713");
vk::CmdCopyImage(m_command_buffer, mp3_image, VK_IMAGE_LAYOUT_GENERAL, mp2_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT;
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT;
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-dstImage-08714");
vk::CmdCopyImage(m_command_buffer, mp3_image, VK_IMAGE_LAYOUT_GENERAL, mp2_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-dstImage-08714");
vk::CmdCopyImage(m_command_buffer, mp2_image, VK_IMAGE_LAYOUT_GENERAL, mp3_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-srcImage-01556");
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-None-01549"); // since also non-compatiable
vk::CmdCopyImage(m_command_buffer, mp2_image, VK_IMAGE_LAYOUT_GENERAL, sp_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT;
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-dstImage-01557");
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-None-01549"); // since also non-compatiable
vk::CmdCopyImage(m_command_buffer, sp_image, VK_IMAGE_LAYOUT_GENERAL, mp3_image, VK_IMAGE_LAYOUT_GENERAL, 1, &copy_region);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeYcbcr, SamplerYcbcrConversionEnable) {
TEST_DESCRIPTION("Checks samplerYcbcrConversion is enabled before calling vkCreateSamplerYcbcrConversion");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
VkSamplerYcbcrConversion conversions;
VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = {VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
nullptr,
VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
VK_CHROMA_LOCATION_COSITED_EVEN,
VK_CHROMA_LOCATION_COSITED_EVEN,
VK_FILTER_NEAREST,
false};
m_errorMonitor->SetDesiredError("VUID-vkCreateSamplerYcbcrConversion-None-01648");
vk::CreateSamplerYcbcrConversionKHR(*m_device, &ycbcr_create_info, nullptr, &conversions);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, ClearColorImageFormat) {
TEST_DESCRIPTION("Record clear color with an invalid image formats");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
VkFormat mp_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = mp_format;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
image_create_info.arrayLayers = 1;
bool supported = IsImageFormatSupported(Gpu(), image_create_info, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
if (supported == false) {
GTEST_SKIP() << "Multiplane image format not supported";
}
vkt::Image mp_image(*m_device, image_create_info, vkt::set_layout);
m_command_buffer.Begin();
VkClearColorValue color_clear_value = {};
VkImageSubresourceRange clear_range;
clear_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear_range.baseMipLevel = 0;
clear_range.baseArrayLayer = 0;
clear_range.layerCount = 1;
clear_range.levelCount = 1;
m_errorMonitor->SetDesiredError("VUID-vkCmdClearColorImage-image-01545");
vk::CmdClearColorImage(m_command_buffer, mp_image, VK_IMAGE_LAYOUT_GENERAL, &color_clear_value, 1, &clear_range);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, WriteDescriptorSet) {
TEST_DESCRIPTION("Attempt to use VkSamplerYcbcrConversion ImageView to update descriptors that are not allowed.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) {
GTEST_SKIP() << "Required formats/features not supported";
}
// Create Ycbcr conversion
VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; // guaranteed sampling support
auto ycbcr_create_info = vku::InitStruct<VkSamplerYcbcrConversionCreateInfo>(
nullptr, mp_format, VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
VkComponentMapping{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY},
VK_CHROMA_LOCATION_COSITED_EVEN, VK_CHROMA_LOCATION_COSITED_EVEN, VK_FILTER_NEAREST, VK_FALSE);
vkt::SamplerYcbcrConversion conversion(*m_device, ycbcr_create_info);
OneOffDescriptorSet descriptor_set(m_device, {
{0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr},
});
auto image_ci = vku::InitStruct<VkImageCreateInfo>(
nullptr, VkImageCreateFlags{VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT}, // need for multi-planar
VK_IMAGE_TYPE_2D, mp_format, VkExtent3D{64, 64u, 1u}, 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL,
VkImageUsageFlags{VK_IMAGE_USAGE_SAMPLED_BIT}, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr, VK_IMAGE_LAYOUT_UNDEFINED);
vkt::Image image_obj(*m_device, image_ci, vkt::set_layout);
VkSamplerYcbcrConversionInfo ycbcr_info = vku::InitStructHelper();
ycbcr_info.conversion = conversion;
vkt::ImageView image_view = image_obj.CreateView(VK_IMAGE_ASPECT_COLOR_BIT, &ycbcr_info);
descriptor_set.WriteDescriptorImageInfo(0, image_view, VK_NULL_HANDLE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
m_errorMonitor->SetDesiredError("VUID-VkWriteDescriptorSet-descriptorType-01946");
descriptor_set.UpdateDescriptorSets();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, MultiplaneImageLayoutAspectFlags) {
TEST_DESCRIPTION("Query layout of a multiplane image using illegal aspect flag masks");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
VkImageCreateInfo ci = vku::InitStructHelper();
ci.flags = 0;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
ci.extent = {128, 128, 1};
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
ci.tiling = VK_IMAGE_TILING_LINEAR;
ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
// Verify formats
bool supported = IsImageFormatSupported(Gpu(), ci, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
ci.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
supported = supported && IsImageFormatSupported(Gpu(), ci, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
if (!supported) {
// Assume there's low ROI on searching for different mp formats
GTEST_SKIP() << "Multiplane image format not supported";
}
VkImage image_2plane, image_3plane;
ci.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
VkResult err = vk::CreateImage(device(), &ci, NULL, &image_2plane);
ASSERT_EQ(VK_SUCCESS, err);
ci.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
err = vk::CreateImage(device(), &ci, NULL, &image_3plane);
ASSERT_EQ(VK_SUCCESS, err);
// Query layout of 3rd plane, for a 2-plane image
VkImageSubresource subres = {};
subres.aspectMask = VK_IMAGE_ASPECT_PLANE_2_BIT;
subres.mipLevel = 0;
subres.arrayLayer = 0;
VkSubresourceLayout layout = {};
m_errorMonitor->SetDesiredError("VUID-vkGetImageSubresourceLayout-tiling-08717");
vk::GetImageSubresourceLayout(device(), image_2plane, &subres, &layout);
m_errorMonitor->VerifyFound();
// Query layout using color aspect, for a 3-plane image
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
m_errorMonitor->SetDesiredError("VUID-vkGetImageSubresourceLayout-tiling-08717");
vk::GetImageSubresourceLayout(device(), image_3plane, &subres, &layout);
m_errorMonitor->VerifyFound();
// Clean up
vk::DestroyImage(device(), image_2plane, NULL);
vk::DestroyImage(device(), image_3plane, NULL);
}
TEST_F(NegativeYcbcr, BindMemoryDisjoint) {
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
// Try to bind an image created with Disjoint bit
VkFormatProperties format_properties;
VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
vk::GetPhysicalDeviceFormatProperties(m_device->Physical(), mp_format, &format_properties);
// Need to make sure disjoint is supported for format
// Also need to support an arbitrary image usage feature
constexpr VkFormatFeatureFlags disjoint_sampled = VK_FORMAT_FEATURE_DISJOINT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
if (disjoint_sampled != (format_properties.optimalTilingFeatures & disjoint_sampled)) {
GTEST_SKIP() << "test requires disjoint and sampled feature bit on format";
}
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = mp_format;
image_create_info.extent = {64, 64, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.flags = VK_IMAGE_CREATE_DISJOINT_BIT;
vkt::Image image(*m_device, image_create_info, vkt::no_mem);
VkImagePlaneMemoryRequirementsInfo image_plane_req = vku::InitStructHelper();
image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper(&image_plane_req);
mem_req_info2.image = image;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mem_req2);
// Find a valid memory type index to memory to be allocated from
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.allocationSize = mem_req2.memoryRequirements.size;
ASSERT_TRUE(m_device->Physical().SetMemoryType(mem_req2.memoryRequirements.memoryTypeBits, &alloc_info, 0));
vkt::DeviceMemory image_memory(*m_device, alloc_info);
// Bind disjoint with BindImageMemory instead of BindImageMemory2
m_errorMonitor->SetDesiredError("VUID-vkBindImageMemory-image-01608");
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-image-07736");
vk::BindImageMemory(device(), image, image_memory, 0);
m_errorMonitor->VerifyFound();
VkBindImagePlaneMemoryInfo plane_memory_info = vku::InitStructHelper();
ASSERT_TRUE(vkuFormatPlaneCount(mp_format) == 2);
plane_memory_info.planeAspect = VK_IMAGE_ASPECT_PLANE_2_BIT;
VkBindImageMemoryInfo bind_image_info = vku::InitStructHelper(&plane_memory_info);
bind_image_info.image = image;
bind_image_info.memory = image_memory;
bind_image_info.memoryOffset = 0;
// Set invalid planeAspect
m_errorMonitor->SetDesiredError("VUID-VkBindImagePlaneMemoryInfo-planeAspect-02283");
// Error is thrown from not having both planes bound
m_errorMonitor->SetDesiredError("VUID-vkBindImageMemory2-pBindInfos-02858");
m_errorMonitor->SetDesiredError("VUID-vkBindImageMemory2-pBindInfos-02858");
// Might happen as plane2 wasn't queried for its memroy type
m_errorMonitor->SetUnexpectedError("VUID-VkBindImageMemoryInfo-pNext-01619");
m_errorMonitor->SetUnexpectedError("VUID-VkBindImageMemoryInfo-pNext-01621");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, BindMemoryNoDisjoint) {
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
// Try to bind an image created with Disjoint bit
VkFormatProperties format_properties;
VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
vk::GetPhysicalDeviceFormatProperties(m_device->Physical(), mp_format, &format_properties);
// Bind image with VkBindImagePlaneMemoryInfo without disjoint bit in image
// Need to support an arbitrary image usage feature for multi-planar format
if (0 == (format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
GTEST_SKIP() << "test requires sampled feature bit on multi-planar format";
}
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = mp_format;
image_create_info.extent = {64, 64, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.flags = 0; // no disjoint bit set
vkt::Image image(*m_device, image_create_info, vkt::no_mem);
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper();
mem_req_info2.image = image;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mem_req2);
// Find a valid memory type index to memory to be allocated from
VkMemoryAllocateInfo alloc_info = vku::InitStructHelper();
alloc_info.allocationSize = mem_req2.memoryRequirements.size;
ASSERT_TRUE(m_device->Physical().SetMemoryType(mem_req2.memoryRequirements.memoryTypeBits, &alloc_info, 0));
vkt::DeviceMemory image_memory(*m_device, alloc_info);
VkBindImagePlaneMemoryInfo plane_memory_info = vku::InitStructHelper();
plane_memory_info.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
VkBindImageMemoryInfo bind_image_info = vku::InitStructHelper(&plane_memory_info);
bind_image_info.image = image;
bind_image_info.memory = image_memory;
bind_image_info.memoryOffset = 0;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01618");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, BindMemory2Disjoint) {
TEST_DESCRIPTION("These tests deal with VK_KHR_bind_memory_2 and disjoint memory being bound");
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = tex_format;
image_create_info.extent = {256, 256, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.flags = 0;
// Only gets used in MP tests
VkImageCreateInfo mp_image_create_info = image_create_info;
mp_image_create_info.format = mp_format;
mp_image_create_info.flags = VK_IMAGE_CREATE_DISJOINT_BIT;
// Check for support of format used by all multi-planar tests
// Need seperate boolean as its valid to do tests that support YCbCr but not disjoint
bool mp_disjoint_support = false;
VkFormatProperties mp_format_properties;
vk::GetPhysicalDeviceFormatProperties(m_device->Physical(), mp_format, &mp_format_properties);
if ((mp_format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) &&
(mp_format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
mp_disjoint_support = true;
}
// Try to bind memory to an object with an invalid memoryOffset
vkt::Image image(*m_device, image_create_info, vkt::no_mem);
VkMemoryRequirements image_mem_reqs = {};
vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs);
VkMemoryAllocateInfo image_alloc_info = vku::InitStructHelper();
// Leave some extra space for alignment wiggle room
image_alloc_info.allocationSize = image_mem_reqs.size + image_mem_reqs.alignment;
m_device->Physical().SetMemoryType(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0);
vkt::DeviceMemory image_mem(*m_device, image_alloc_info);
// Keep values outside scope so multiple tests cases can reuse
vkt::Image mp_image;
vkt::DeviceMemory mp_image_mem[2];
VkMemoryRequirements2 mp_image_mem_reqs2[2];
VkMemoryAllocateInfo mp_image_alloc_info[2];
if (mp_disjoint_support) {
mp_image.InitNoMemory(*m_device, mp_image_create_info);
VkImagePlaneMemoryRequirementsInfo image_plane_req = vku::InitStructHelper();
image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper(&image_plane_req);
mem_req_info2.image = mp_image;
mp_image_mem_reqs2[0] = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mp_image_mem_reqs2[0]);
image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT;
mp_image_mem_reqs2[1] = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mp_image_mem_reqs2[1]);
mp_image_alloc_info[0] = vku::InitStructHelper();
mp_image_alloc_info[1] = vku::InitStructHelper();
// Leave some extra space for alignment wiggle room
// plane 0
mp_image_alloc_info[0].allocationSize =
mp_image_mem_reqs2[0].memoryRequirements.size + mp_image_mem_reqs2[0].memoryRequirements.alignment;
m_device->Physical().SetMemoryType(mp_image_mem_reqs2[0].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[0], 0);
// Exact size as VU will always be for plane 1
// plane 1
mp_image_alloc_info[1].allocationSize = mp_image_mem_reqs2[1].memoryRequirements.size;
m_device->Physical().SetMemoryType(mp_image_mem_reqs2[1].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[1], 0);
mp_image_mem[0].Init(*m_device, mp_image_alloc_info[0]);
mp_image_mem[1].Init(*m_device, mp_image_alloc_info[1]);
}
// All planes must be bound at once the same here
VkBindImagePlaneMemoryInfo plane_memory_info[2];
plane_memory_info[0] = vku::InitStructHelper();
plane_memory_info[0].planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
plane_memory_info[1] = vku::InitStructHelper();
plane_memory_info[1].planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT;
// Test unaligned memory offset
// single-plane image
VkBindImageMemoryInfo bind_image_info = vku::InitStructHelper();
bind_image_info.image = image;
bind_image_info.memory = image_mem;
bind_image_info.memoryOffset = 1; // off alignment
if (mp_disjoint_support == true) {
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper();
mem_req_info2.image = image;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mem_req2);
if (mem_req2.memoryRequirements.alignment > 1) {
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01616");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
} else {
// Same as 01048 but with bindImageMemory2 call
if (image_mem_reqs.alignment > 1) {
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01616");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
}
// Multi-plane image
if (mp_disjoint_support == true) {
if (mp_image_mem_reqs2[0].memoryRequirements.alignment > 1) {
VkBindImageMemoryInfo bind_image_infos[2];
bind_image_infos[0] = vku::InitStructHelper(&plane_memory_info[0]);
bind_image_infos[0].image = mp_image;
bind_image_infos[0].memory = mp_image_mem[0];
bind_image_infos[0].memoryOffset = 1; // off alignment
bind_image_infos[1] = vku::InitStructHelper(&plane_memory_info[1]);
bind_image_infos[1].image = mp_image;
bind_image_infos[1].memory = mp_image_mem[1];
bind_image_infos[1].memoryOffset = 0;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01620");
vk::BindImageMemory2KHR(device(), 2, bind_image_infos);
m_errorMonitor->VerifyFound();
}
}
// Test memory offsets within the memory allocation, but which leave too little memory for
// the resource.
// single-plane image
bind_image_info = vku::InitStructHelper();
bind_image_info.image = image;
bind_image_info.memory = image_mem;
if (mp_disjoint_support == true) {
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper();
mem_req_info2.image = image;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mem_req2);
VkDeviceSize image2_offset = (mem_req2.memoryRequirements.size - 1) & ~(mem_req2.memoryRequirements.alignment - 1);
if ((image2_offset > 0) &&
(mem_req2.memoryRequirements.size < (image_alloc_info.allocationSize - mem_req2.memoryRequirements.alignment))) {
bind_image_info.memoryOffset = image2_offset;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01617");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
} else {
// Same as 01049 but with bindImageMemory2 call
VkDeviceSize image_offset = (image_mem_reqs.size - 1) & ~(image_mem_reqs.alignment - 1);
if ((image_offset > 0) && (image_mem_reqs.size < (image_alloc_info.allocationSize - image_mem_reqs.alignment))) {
bind_image_info.memoryOffset = image_offset;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01617");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
}
// Multi-plane image
if (mp_disjoint_support == true) {
VkDeviceSize mp_image_offset =
(mp_image_mem_reqs2[0].memoryRequirements.size - 1) & ~(mp_image_mem_reqs2[0].memoryRequirements.alignment - 1);
if ((mp_image_offset > 0) &&
(mp_image_mem_reqs2[0].memoryRequirements.size <
(mp_image_alloc_info[0].allocationSize - mp_image_mem_reqs2[0].memoryRequirements.alignment))) {
VkBindImageMemoryInfo bind_image_infos[2];
bind_image_infos[0] = vku::InitStructHelper(&plane_memory_info[0]);
bind_image_infos[0].image = mp_image;
bind_image_infos[0].memory = mp_image_mem[0];
bind_image_infos[0].memoryOffset = mp_image_offset; // mis-offset
bind_image_infos[1] = vku::InitStructHelper(&plane_memory_info[1]);
bind_image_infos[1].image = mp_image;
bind_image_infos[1].memory = mp_image_mem[1];
bind_image_infos[1].memoryOffset = 0;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01621");
vk::BindImageMemory2KHR(device(), 2, bind_image_infos);
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(NegativeYcbcr, BindMemory2DisjointUnsupported) {
TEST_DESCRIPTION("These tests deal with VK_KHR_bind_memory_2 and disjoint memory being bound");
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageCreateInfo image_create_info = vku::InitStructHelper();
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = tex_format;
image_create_info.extent = {256, 256, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
image_create_info.flags = 0;
// Only gets used in MP tests
VkImageCreateInfo mp_image_create_info = image_create_info;
mp_image_create_info.format = mp_format;
mp_image_create_info.flags = VK_IMAGE_CREATE_DISJOINT_BIT;
// Check for support of format used by all multi-planar tests
// Need seperate boolean as its valid to do tests that support YCbCr but not disjoint
bool mp_disjoint_support = false;
VkFormatProperties mp_format_properties;
vk::GetPhysicalDeviceFormatProperties(m_device->Physical(), mp_format, &mp_format_properties);
if ((mp_format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) &&
(mp_format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
mp_disjoint_support = true;
}
// Try to bind memory to an object with an invalid memoryOffset
vkt::Image image(*m_device, image_create_info, vkt::no_mem);
VkMemoryRequirements image_mem_reqs = {};
vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs);
VkMemoryAllocateInfo image_alloc_info = vku::InitStructHelper();
// Leave some extra space for alignment wiggle room
image_alloc_info.allocationSize = image_mem_reqs.size + image_mem_reqs.alignment;
m_device->Physical().SetMemoryType(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0);
vkt::DeviceMemory image_mem(*m_device, image_alloc_info);
// Keep values outside scope so multiple tests cases can reuse
vkt::Image mp_image;
vkt::DeviceMemory mp_image_mem[2];
VkMemoryRequirements2 mp_image_mem_reqs2[2];
VkMemoryAllocateInfo mp_image_alloc_info[2];
if (mp_disjoint_support) {
mp_image.InitNoMemory(*m_device, mp_image_create_info);
VkImagePlaneMemoryRequirementsInfo image_plane_req = vku::InitStructHelper();
image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper(&image_plane_req);
mem_req_info2.image = mp_image;
mp_image_mem_reqs2[0] = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mp_image_mem_reqs2[0]);
image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT;
mp_image_mem_reqs2[1] = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mp_image_mem_reqs2[1]);
mp_image_alloc_info[0] = vku::InitStructHelper();
mp_image_alloc_info[1] = vku::InitStructHelper();
// Leave some extra space for alignment wiggle room
// plane 0
mp_image_alloc_info[0].allocationSize =
mp_image_mem_reqs2[0].memoryRequirements.size + mp_image_mem_reqs2[0].memoryRequirements.alignment;
m_device->Physical().SetMemoryType(mp_image_mem_reqs2[0].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[0], 0);
// Exact size as VU will always be for plane 1
// plane 1
mp_image_alloc_info[1].allocationSize = mp_image_mem_reqs2[1].memoryRequirements.size;
m_device->Physical().SetMemoryType(mp_image_mem_reqs2[1].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[1], 0);
mp_image_mem[0].Init(*m_device, mp_image_alloc_info[0]);
mp_image_mem[1].Init(*m_device, mp_image_alloc_info[1]);
}
// All planes must be bound at once the same here
VkBindImagePlaneMemoryInfo plane_memory_info[2];
plane_memory_info[0] = vku::InitStructHelper();
plane_memory_info[0].planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
plane_memory_info[1] = vku::InitStructHelper();
plane_memory_info[1].planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT;
// Try to bind memory to an object with an invalid memory type
// Create a mask of available memory types *not* supported by these resources, and try to use one of them.
VkPhysicalDeviceMemoryProperties memory_properties = {};
vk::GetPhysicalDeviceMemoryProperties(m_device->Physical(), &memory_properties);
// single-plane image
VkBindImageMemoryInfo bind_image_info = vku::InitStructHelper();
bind_image_info.image = image;
bind_image_info.memoryOffset = 0;
if (mp_disjoint_support == true) {
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper();
mem_req_info2.image = image;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mem_req2);
uint32_t image2_unsupported_mem_type_bits =
((1 << memory_properties.memoryTypeCount) - 1) & ~mem_req2.memoryRequirements.memoryTypeBits;
bool found_type =
m_device->Physical().SetMemoryType(image2_unsupported_mem_type_bits, &image_alloc_info, 0,
VK_MEMORY_PROPERTY_PROTECTED_BIT | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD);
if (image2_unsupported_mem_type_bits != 0 && found_type) {
vkt::DeviceMemory image_mem_tmp(*m_device, image_alloc_info);
bind_image_info.memory = image_mem_tmp;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01615");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
} else {
// Same as 01047 but with bindImageMemory2 call
uint32_t image_unsupported_mem_type_bits = ((1 << memory_properties.memoryTypeCount) - 1) & ~image_mem_reqs.memoryTypeBits;
bool found_type =
m_device->Physical().SetMemoryType(image_unsupported_mem_type_bits, &image_alloc_info, 0,
VK_MEMORY_PROPERTY_PROTECTED_BIT | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD);
if (image_unsupported_mem_type_bits != 0 && found_type) {
vkt::DeviceMemory image_mem_tmp(*m_device, image_alloc_info);
bind_image_info.memory = image_mem_tmp;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01615");
vk::BindImageMemory2KHR(device(), 1, &bind_image_info);
m_errorMonitor->VerifyFound();
}
}
// Multi-plane image
if (mp_disjoint_support == true) {
// Get plane 0 memory requirements
VkImagePlaneMemoryRequirementsInfo image_plane_req = vku::InitStructHelper();
image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT;
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper(&image_plane_req);
mem_req_info2.image = mp_image;
vk::GetImageMemoryRequirements2KHR(device(), &mem_req_info2, &mp_image_mem_reqs2[0]);
uint32_t mp_image_unsupported_mem_type_bits =
((1 << memory_properties.memoryTypeCount) - 1) & ~mp_image_mem_reqs2[0].memoryRequirements.memoryTypeBits;
bool found_type =
m_device->Physical().SetMemoryType(mp_image_unsupported_mem_type_bits, &mp_image_alloc_info[0], 0,
VK_MEMORY_PROPERTY_PROTECTED_BIT | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD);
if (mp_image_unsupported_mem_type_bits != 0 && found_type) {
mp_image_alloc_info[0].allocationSize = mp_image_mem_reqs2[0].memoryRequirements.size;
vkt::DeviceMemory mp_image_mem_tmp(*m_device, mp_image_alloc_info[0]);
VkBindImageMemoryInfo bind_image_infos[2];
bind_image_infos[0] = vku::InitStructHelper(&plane_memory_info[0]);
bind_image_infos[0].image = mp_image;
bind_image_infos[0].memory = mp_image_mem_tmp;
bind_image_infos[0].memoryOffset = 0;
bind_image_infos[1] = vku::InitStructHelper(&plane_memory_info[1]);
bind_image_infos[1].image = mp_image;
bind_image_infos[1].memory = mp_image_mem[1];
bind_image_infos[1].memoryOffset = 0;
m_errorMonitor->SetDesiredError("VUID-VkBindImageMemoryInfo-pNext-01619");
vk::BindImageMemory2KHR(device(), 2, bind_image_infos);
m_errorMonitor->VerifyFound();
}
}
}
TEST_F(NegativeYcbcr, MismatchedImageViewAndSamplerFormat) {
TEST_DESCRIPTION("Create image view with a different format that SamplerYcbcr was created with.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
vkt::Image image(*m_device, 128, 128, VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT);
VkSamplerYcbcrConversionCreateInfo sampler_conversion_ci = vku::InitStructHelper();
sampler_conversion_ci.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
sampler_conversion_ci.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
sampler_conversion_ci.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
sampler_conversion_ci.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY};
sampler_conversion_ci.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
sampler_conversion_ci.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
sampler_conversion_ci.chromaFilter = VK_FILTER_NEAREST;
sampler_conversion_ci.forceExplicitReconstruction = false;
vkt::SamplerYcbcrConversion sampler_conversion(*m_device, sampler_conversion_ci);
VkSamplerYcbcrConversionInfo sampler_ycbcr_conversion_info = vku::InitStructHelper();
sampler_ycbcr_conversion_info.conversion = sampler_conversion;
VkImageViewCreateInfo view_info = vku::InitStructHelper(&sampler_ycbcr_conversion_info);
view_info.flags = 0;
view_info.image = image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
CreateImageViewTest(view_info, "VUID-VkImageViewCreateInfo-pNext-06658");
}
TEST_F(NegativeYcbcr, MultiplaneIncompatibleViewFormat3Plane) {
TEST_DESCRIPTION("Postive/negative tests of multiplane imageview format compatibility");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) {
GTEST_SKIP() << "Required formats/features not supported";
}
VkImageCreateInfo ci = vku::InitStructHelper();
ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
ci.extent = {128, 128, 1};
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
const VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
bool supported = IsImageFormatSupported(Gpu(), ci, features);
// Verify format 3 Plane format
if (!supported) {
GTEST_SKIP() << "Multiplane image format not supported";
}
vkt::Image image_obj(*m_device, ci, vkt::set_layout);
VkImageViewCreateInfo ivci = vku::InitStructHelper();
ivci.image = image_obj;
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = VK_FORMAT_R8G8_UNORM; // Compat is VK_FORMAT_R8_UNORM
ivci.subresourceRange.layerCount = 1;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT;
// Incompatible format error
CreateImageViewTest(ivci, "VUID-VkImageViewCreateInfo-image-01586");
// Correct format succeeds
ivci.format = VK_FORMAT_R8_UNORM;
vkt::ImageView image_view(*m_device, ivci);
// R8_SNORM is compatible with R8_UNORM
ivci.format = VK_FORMAT_R8_SNORM;
vkt::ImageView image_view2(*m_device, ivci);
// Try a multiplane imageview
ivci.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
CreateImageViewTest(ivci, "VUID-VkImageViewCreateInfo-format-06415");
}
TEST_F(NegativeYcbcr, MultiplaneIncompatibleViewFormat2Plane) {
TEST_DESCRIPTION("Postive/negative tests of multiplane imageview format compatibility");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) {
GTEST_SKIP() << "Required formats/features not supported";
}
VkImageCreateInfo ci = vku::InitStructHelper();
ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
ci.extent = {128, 128, 1};
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
const VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
bool supported = IsImageFormatSupported(Gpu(), ci, features);
// Verify format 2 Plane format
if (!supported) {
GTEST_SKIP() << "Multiplane image format not supported";
}
vkt::Image image_obj(*m_device, ci, vkt::set_layout);
VkImageViewCreateInfo ivci = vku::InitStructHelper();
ivci.image = image_obj;
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.subresourceRange.layerCount = 1;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
// Plane 0 is compatible with VK_FORMAT_R8_UNORM
// Plane 1 is compatible with VK_FORMAT_R8G8_UNORM
// Correct format succeeds
ivci.format = VK_FORMAT_R8_UNORM;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT;
vkt::ImageView image_view(*m_device, ivci);
ivci.format = VK_FORMAT_R8G8_UNORM;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT;
vkt::ImageView image_view2(*m_device, ivci);
// Incompatible format error
ivci.format = VK_FORMAT_R8_UNORM;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_1_BIT;
CreateImageViewTest(ivci, "VUID-VkImageViewCreateInfo-image-01586");
ivci.format = VK_FORMAT_R8G8_UNORM;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT;
CreateImageViewTest(ivci, "VUID-VkImageViewCreateInfo-image-01586");
}
TEST_F(NegativeYcbcr, MultiplaneImageViewAspectMasks) {
TEST_DESCRIPTION("Create a VkImageView with multiple planar aspect masks");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
const VkFormat mp_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
if (!(m_device->FormatFeaturesOptimal(mp_format) & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT)) {
GTEST_SKIP() << "Missing MIDPOINT_CHROMA_SAMPLES support";
}
VkImageCreateInfo ci = vku::InitStructHelper();
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = mp_format;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
ci.extent = {128, 128, 1};
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
VkImageViewCreateInfo ivci = vku::InitStructHelper();
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.subresourceRange.layerCount = 1;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
// Different formats between VkImage and VkImageView
{
ci.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
vkt::Image image(*m_device, ci, vkt::set_layout);
ivci.image = image;
ivci.format = VK_FORMAT_R8_UNORM;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
CreateImageViewTest(ivci, "VUID-VkImageViewCreateInfo-subresourceRange-07818");
}
// Without Mutable format
{
ci.flags = 0;
vkt::Image image(*m_device, ci, vkt::set_layout);
VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = vku::InitStructHelper();
ycbcr_create_info.format = mp_format;
ycbcr_create_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
ycbcr_create_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
ycbcr_create_info.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY};
ycbcr_create_info.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
ycbcr_create_info.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
ycbcr_create_info.chromaFilter = VK_FILTER_NEAREST;
ycbcr_create_info.forceExplicitReconstruction = false;
vkt::SamplerYcbcrConversion conversion(*m_device, ycbcr_create_info);
VkSamplerYcbcrConversionInfo ycbcr_info = vku::InitStructHelper();
ycbcr_info.conversion = conversion;
ivci.image = image;
ivci.format = mp_format;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
ivci.pNext = &ycbcr_info;
CreateImageViewTest(ivci, "VUID-VkImageViewCreateInfo-subresourceRange-07818");
}
}
TEST_F(NegativeYcbcr, MultiplaneAspectBits) {
TEST_DESCRIPTION("Attempt to update descriptor sets for images that do not have correct aspect bits sets.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
if (!FormatFeaturesAreSupported(Gpu(), VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, VK_IMAGE_TILING_OPTIMAL,
VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) {
GTEST_SKIP() << "Required formats/features not supported";
}
VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; // commonly supported multi-planar format
VkFormatProperties format_props;
vk::GetPhysicalDeviceFormatProperties(m_device->Physical(), mp_format, &format_props);
if (!vkt::Image::IsCompatible(*m_device, VK_IMAGE_USAGE_SAMPLED_BIT, format_props.optimalTilingFeatures)) {
GTEST_SKIP() << "multi-planar format cannot be sampled for optimalTiling.";
}
auto image_ci = vku::InitStruct<VkImageCreateInfo>(
nullptr, VkImageCreateFlags{VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT}, // need for multi-planar
VK_IMAGE_TYPE_2D, mp_format, VkExtent3D{64, 64, 1}, 1u, 1u, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL,
VkImageUsageFlags{VK_IMAGE_USAGE_SAMPLED_BIT}, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr, VK_IMAGE_LAYOUT_UNDEFINED);
vkt::Image image_obj(*m_device, image_ci, vkt::set_layout);
VkSamplerYcbcrConversionCreateInfo ycbcr_create_info = vku::InitStructHelper();
ycbcr_create_info.format = mp_format;
ycbcr_create_info.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
ycbcr_create_info.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
ycbcr_create_info.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY};
ycbcr_create_info.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_create_info.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN;
ycbcr_create_info.chromaFilter = VK_FILTER_NEAREST;
ycbcr_create_info.forceExplicitReconstruction = false;
vkt::SamplerYcbcrConversion conversion(*m_device, ycbcr_create_info);
VkSamplerYcbcrConversionInfo ycbcr_info = vku::InitStructHelper();
ycbcr_info.conversion = conversion;
auto image_view_ci = image_obj.BasicViewCreatInfo();
image_view_ci.pNext = &ycbcr_info;
vkt::ImageView image_view(*m_device, image_view_ci);
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&ycbcr_info));
ASSERT_TRUE(sampler.initialized());
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_ALL, &sampler.handle()},
});
if (descriptor_set.set_ == VK_NULL_HANDLE) {
GTEST_SKIP() << "Couldn't create descriptor set";
}
// TODO - 01564 appears to be impossible to hit due to the following check in descriptor_validation.cpp:
// if (sampler && !desc->IsImmutableSampler() && vkuFormatIsMultiplane(image_state->createInfo.format)) ...
// - !desc->IsImmutableSampler() will cause 02738; IOW, multi-plane conversion _requires_ an immutable sampler
// - !desc->IsImmutableSampler() must be removed for 01564 to get hit, but it's not clear whether or not this is
// correct based on the comments in the code
// m_errorMonitor->SetDesiredError("VUID-VkDescriptorImageInfo-sampler-01564");
descriptor_set.WriteDescriptorImageInfo(0, image_view, sampler, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
descriptor_set.UpdateDescriptorSets();
// m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, DisjointImageWithDrmFormatModifier) {
TEST_DESCRIPTION("Create image with VK_IMAGE_CREATE_DISJOINT_BIT and VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
VkFormat format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
std::vector<uint64_t> mods;
VkDrmFormatModifierPropertiesListEXT mod_props = vku::InitStructHelper();
VkFormatProperties2 format_props = vku::InitStructHelper(&mod_props);
vk::GetPhysicalDeviceFormatProperties2(Gpu(), format, &format_props);
if (mod_props.drmFormatModifierCount == 0) {
GTEST_SKIP() << "drmFormatModifierCount is 0.";
}
std::vector<VkDrmFormatModifierPropertiesEXT> mod_props_length(mod_props.drmFormatModifierCount);
mod_props.pDrmFormatModifierProperties = mod_props_length.data();
vk::GetPhysicalDeviceFormatProperties2(Gpu(), format, &format_props);
for (uint32_t i = 0; i < mod_props.drmFormatModifierCount; ++i) {
auto &mod = mod_props.pDrmFormatModifierProperties[i];
if (((mod.drmFormatModifierTilingFeatures &
(VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_DISJOINT_BIT)) ==
(VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_DISJOINT_BIT))) {
mods.push_back(mod.drmFormatModifier);
}
}
if (mods.empty()) {
GTEST_SKIP() << "Required format features not supported.";
}
VkImageDrmFormatModifierListCreateInfoEXT mod_list = vku::InitStructHelper();
mod_list.pDrmFormatModifiers = mods.data();
mod_list.drmFormatModifierCount = mods.size();
VkImageCreateInfo image_create_info = vku::InitStructHelper(&mod_list);
image_create_info.flags = VK_IMAGE_CREATE_DISJOINT_BIT;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.format = format;
image_create_info.extent = {64, 64, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
vkt::Image image(*m_device, image_create_info, vkt::no_mem);
VkImageMemoryRequirementsInfo2 mem_req_info2 = vku::InitStructHelper();
mem_req_info2.image = image;
VkMemoryRequirements2 mem_req2 = vku::InitStructHelper();
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryRequirementsInfo2-image-01589");
m_errorMonitor->SetDesiredError("VUID-VkImageMemoryRequirementsInfo2-image-02279");
vk::GetImageMemoryRequirements2(device(), &mem_req_info2, &mem_req2);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, TexelFetch) {
TEST_DESCRIPTION("Do OpImageFetch on a Ycbcr COMBINED_IMAGE_SAMPLER.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char fsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 0) uniform sampler2D ycbcr;
layout(location=0) out vec4 out_color;
void main() {
out_color = texelFetch(ycbcr, ivec2(0), 0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeSampledImage-12206");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, TexelFetchArray) {
TEST_DESCRIPTION("Do OpImageFetch on a Ycbcr COMBINED_IMAGE_SAMPLER.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
VkSampler immutable_samplers[2] = {sampler, sampler};
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_FRAGMENT_BIT, immutable_samplers},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char fsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 0) uniform sampler2D ycbcr[2];
layout(location=0) out vec4 out_color;
void main() {
out_color = texelFetch(ycbcr[1], ivec2(0), 0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeSampledImage-12206");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, TexelFetchIndexed) {
TEST_DESCRIPTION("Do OpImageFetch on a Ycbcr COMBINED_IMAGE_SAMPLER.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
VkSampler immutable_samplers[2] = {sampler, sampler};
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2, VK_SHADER_STAGE_VERTEX_BIT, immutable_samplers},
{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char vsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 0) uniform sampler2D ycbcr[2];
layout (set = 0, binding = 1) uniform UBO { uint index; };
void main() {
gl_Position = texelFetch(ycbcr[index], ivec2(0), 0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[0] = vs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeSampledImage-12206");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, TexelFetchNonArrayPartiallyBound) {
TEST_DESCRIPTION("Do OpImageFetch on a Ycbcr COMBINED_IMAGE_SAMPLER.");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
AddRequiredFeature(vkt::Feature::descriptorBindingPartiallyBound);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps);
uint32_t *buffer_ptr = (uint32_t *)buffer.Memory().Map();
buffer_ptr[0] = 1;
OneOffDescriptorIndexingSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT, &sampler.handle(),
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char vsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 0) uniform sampler2D ycbcr;
void main() {
gl_Position = texelFetch(ycbcr, ivec2(0), 0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[0] = vs.GetStageCreateInfo();
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeSampledImage-12206");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, TexelFetchDestroyedSampler) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
// Sampler was baked into the pipeline layout, valid to destroy now
sampler.Destroy();
const char fsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 0) uniform sampler2D ycbcr;
layout(location=0) out vec4 out_color;
void main() {
out_color = texelFetch(ycbcr, ivec2(0), 0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeSampledImage-12206");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, TextureGather) {
TEST_DESCRIPTION("Do OpImageGather on a Ycbcr COMBINED_IMAGE_SAMPLER.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char fsSource[] = R"glsl(
#version 450
layout (set = 0, binding = 0) uniform sampler2D ycbcr;
layout(location=0) out vec4 out_color;
void main() {
out_color = textureGather(ycbcr, ivec2(0), 0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeSampledImage-12206");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, ConstOffset) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
OneOffDescriptorSet descriptor_set(
m_device, {
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, &sampler.handle()},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char fs_source[] = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %out_color
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %out_color "out_color"
OpName %ycbcr "ycbcr"
OpDecorate %out_color Location 0
OpDecorate %ycbcr DescriptorSet 0
OpDecorate %ycbcr Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%out_color = OpVariable %_ptr_Output_v4float Output
%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
%11 = OpTypeSampledImage %10
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
%ycbcr = OpVariable %_ptr_UniformConstant_11 UniformConstant
%v2float = OpTypeVector %float 2
%float_0 = OpConstant %float 0
%17 = OpConstantComposite %v2float %float_0 %float_0
%v2int = OpTypeVector %int 2
%int_0 = OpConstant %int 0
%offset_0 = OpConstantComposite %v2int %int_0 %int_0
%main = OpFunction %void None %3
%5 = OpLabel
%14 = OpLoad %11 %ycbcr
%18 = OpImageSampleImplicitLod %v4float %14 %17 ConstOffset %offset_0
OpStore %out_color %18
OpReturn
OpFunctionEnd
)";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.gp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-ConstOffset-10718");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, FormatCompatibilitySamePlane) {
AddRequiredExtensions(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkFormat formats[2] = {VK_FORMAT_R8_SNORM, VK_FORMAT_R8G8_UNORM};
VkImageFormatListCreateInfo format_list = vku::InitStructHelper();
format_list.viewFormatCount = 2;
format_list.pViewFormats = formats;
VkImageCreateInfo image_create_info = vku::InitStructHelper(&format_list);
// all three plans are VK_FORMAT_R8_UNORM
image_create_info.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
image_create_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
if (!IsImageFormatSupported(Gpu(), image_create_info, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
GTEST_SKIP() << "Multiplane image format not supported";
}
m_errorMonitor->SetDesiredError("VUID-VkImageCreateInfo-pNext-10062");
vkt::Image image(*m_device, image_create_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, FormatCompatibilityDifferentPlane) {
AddRequiredExtensions(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkFormat formats[2] = {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8_UNORM};
VkImageFormatListCreateInfo format_list = vku::InitStructHelper();
format_list.viewFormatCount = 2;
format_list.pViewFormats = formats;
VkImageCreateInfo image_create_info = vku::InitStructHelper(&format_list);
// planes are VK_FORMAT_R8_UNORM and VK_FORMAT_R8G8_UNORM
image_create_info.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
image_create_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
if (!IsImageFormatSupported(Gpu(), image_create_info, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
GTEST_SKIP() << "Multiplane image format not supported";
}
m_errorMonitor->SetDesiredError("VUID-VkImageCreateInfo-pNext-10062");
vkt::Image image(*m_device, image_create_info);
m_errorMonitor->VerifyFound();
}
// Discussion in https://gitlab.khronos.org/vulkan/vulkan/-/merge_requests/6967
// This "should" be invalid, but currently no VU catches it
TEST_F(NegativeYcbcr, DISABLED_FormatCompatibilityNonMutable) {
AddRequiredExtensions(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
const VkFormat view_format = VK_FORMAT_R8G8B8A8_UNORM;
VkImageFormatListCreateInfo format_list = vku::InitStructHelper();
format_list.viewFormatCount = 1;
format_list.pViewFormats = &view_format;
VkImageCreateInfo image_create_info = vku::InitStructHelper(&format_list);
image_create_info.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
image_create_info.flags = 0;
image_create_info.imageType = VK_IMAGE_TYPE_2D;
image_create_info.extent = {32, 32, 1};
image_create_info.mipLevels = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
if (!IsImageFormatSupported(Gpu(), image_create_info, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
GTEST_SKIP() << "Multiplane image format not supported";
}
m_errorMonitor->SetDesiredError("VUID-VkImageCreateInfo-pNext-10062");
vkt::Image image(*m_device, image_create_info);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, MultiplaneImageCopyAspectMask) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
InitRenderTarget();
auto ci = vku::InitStruct<VkImageCreateInfo>();
ci.imageType = VK_IMAGE_TYPE_2D;
ci.format = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM;
ci.tiling = VK_IMAGE_TILING_OPTIMAL;
ci.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
ci.extent = {128, 128, 1};
ci.mipLevels = 1;
ci.arrayLayers = 1;
ci.samples = VK_SAMPLE_COUNT_1_BIT;
if (!IsImageFormatSupported(Gpu(), ci, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT)) {
GTEST_SKIP() << "Multiplane image format not supported";
}
vkt::Image image(*m_device, ci, vkt::no_mem);
vkt::DeviceMemory mem_obj(*m_device, vkt::DeviceMemory::GetResourceAllocInfo(*m_device, image.MemoryRequirements(), 0));
vk::BindImageMemory(device(), image, mem_obj, 0);
VkImageCopy image_copy = {};
image_copy.srcSubresource = {VK_IMAGE_ASPECT_PLANE_0_BIT, 0, 0, 1};
image_copy.srcOffset = {0, 0, 0};
image_copy.dstSubresource = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0, 1};
image_copy.dstOffset = {0, 0, 0};
image_copy.extent = {16, 16, 1};
m_command_buffer.Begin();
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-dstImage-08714");
m_errorMonitor->SetDesiredError("VUID-vkCmdCopyImage-aspectMask-00143");
image.ImageMemoryBarrier(m_command_buffer, 0, 0, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
vk::CmdCopyImage(m_command_buffer, image, VK_IMAGE_LAYOUT_GENERAL, image, VK_IMAGE_LAYOUT_GENERAL, 1, &image_copy);
m_errorMonitor->VerifyFound();
m_command_buffer.End();
}
TEST_F(NegativeYcbcr, DescriptorIndexCombinedSampledImage) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
VkSampler samplers[4] = {sampler, sampler, sampler, sampler};
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4, VK_SHADER_STAGE_COMPUTE_BIT, samplers},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char *cs_source = R"glsl(
#version 460
#extension GL_EXT_nonuniform_qualifier : require
layout(set = 0, binding = 0) uniform sampler2D ycbcr[4];
layout(set = 0, binding = 1) buffer SSBO {
vec4 result;
uint x;
};
void main() {
// try and mask with valid access before and after
result = texture(ycbcr[2], vec2(0));
result = texture(ycbcr[x], vec2(0));
result = texture(ycbcr[1], vec2(0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT);
pipe.cp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-None-12205");
pipe.CreateComputePipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, DescriptorIndexNonCombinedSampledImage) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
VkSampler samplers[4] = {sampler, sampler, sampler, sampler};
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_SAMPLER, 4, VK_SHADER_STAGE_COMPUTE_BIT, samplers};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &binding;
VkDescriptorSetLayout ds_layout = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-12215");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, MixingYcbcrWithNonYcbcrInArray) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler_ycbcr(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo());
VkSampler samplers[4] = {sampler, sampler_ycbcr, sampler, sampler};
VkDescriptorSetLayoutBinding binding = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4, VK_SHADER_STAGE_COMPUTE_BIT, samplers};
VkDescriptorSetLayoutCreateInfo ds_layout_ci = vku::InitStructHelper();
ds_layout_ci.bindingCount = 1;
ds_layout_ci.pBindings = &binding;
VkDescriptorSetLayout ds_layout = VK_NULL_HANDLE;
m_errorMonitor->SetDesiredError("VUID-VkDescriptorSetLayoutBinding-descriptorType-12200");
vk::CreateDescriptorSetLayout(*m_device, &ds_layout_ci, nullptr, &ds_layout);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, DescriptorIndexSlang) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::computeDerivativeGroupQuads);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
RETURN_IF_SKIP(CheckSlangSupport());
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
VkSampler samplers[4] = {sampler, sampler, sampler, sampler};
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4, VK_SHADER_STAGE_COMPUTE_BIT, samplers},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_});
const char *cs_source = R"slang(
[[vk::binding(0, 0)]]
uniform Sampler2D ycbcr[4];
struct Payload {
float4 result;
uint x;
};
[[vk::binding(1, 0)]]
RWStructuredBuffer<Payload> ssbo;
[shader("compute")]
[numthreads(2, 2, 1)]
void main() {
ssbo[0].result = ycbcr[2].Sample(float2(0.0, 0.0));
ssbo[0].result = ycbcr[ssbo[0].x].Sample(float2(0.0, 0.0));
}
)slang";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_SLANG);
pipe.cp_ci_.layout = pipeline_layout;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-None-12205");
pipe.CreateComputePipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeYcbcr, DescriptorIndexShaderObject) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
AddRequiredFeature(vkt::Feature::samplerYcbcrConversion);
RETURN_IF_SKIP(Init());
vkt::SamplerYcbcrConversion conversion(*m_device, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM);
auto conversion_info = conversion.ConversionInfo();
vkt::Sampler sampler(*m_device, SafeSaneSamplerCreateInfo(&conversion_info));
VkSampler samplers[4] = {sampler, sampler, sampler, sampler};
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4, VK_SHADER_STAGE_COMPUTE_BIT, samplers},
{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr},
});
const char *cs_source = R"glsl(
#version 460
#extension GL_EXT_nonuniform_qualifier : require
layout(set = 0, binding = 0) uniform sampler2D ycbcr[4];
layout(set = 0, binding = 1) buffer SSBO {
vec4 result;
uint x;
};
void main() {
// try and mask with valid access before and after
result = texture(ycbcr[2], vec2(0));
result = texture(ycbcr[x], vec2(0));
result = texture(ycbcr[1], vec2(0));
}
)glsl";
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-None-12205");
const vkt::Shader comp_shader(*m_device, VK_SHADER_STAGE_COMPUTE_BIT, GLSLToSPV(VK_SHADER_STAGE_COMPUTE_BIT, cs_source),
&descriptor_set.layout_.handle());
m_errorMonitor->VerifyFound();
}