| /* |
| * Copyright (c) 2015-2021 The Khronos Group Inc. |
| * Copyright (c) 2015-2021 Valve Corporation |
| * Copyright (c) 2015-2021 LunarG, Inc. |
| * Copyright (c) 2015-2021 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 |
| * |
| * Author: Chia-I Wu <olvaffe@gmail.com> |
| * Author: Chris Forbes <chrisf@ijw.co.nz> |
| * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> |
| * Author: Mark Lobodzinski <mark@lunarg.com> |
| * Author: Mike Stroyan <mike@LunarG.com> |
| * Author: Tobin Ehlis <tobine@google.com> |
| * Author: Tony Barbour <tony@LunarG.com> |
| * Author: Cody Northrop <cnorthrop@google.com> |
| * Author: Dave Houlton <daveh@lunarg.com> |
| * Author: Jeremy Kniager <jeremyk@lunarg.com> |
| * Author: Shannon McPherson <shannon@lunarg.com> |
| * Author: John Zulauf <jzulauf@lunarg.com> |
| * Author: Tobias Hector <tobias.hector@amd.com> |
| */ |
| |
| #include <type_traits> |
| |
| #include "cast_utils.h" |
| #include "layer_validation_tests.h" |
| |
| TEST_F(VkLayerTest, BufferExtents) { |
| TEST_DESCRIPTION("Perform copies across a buffer, provoking out-of-range errors."); |
| |
| AddRequiredExtensions(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| |
| const bool copy_commands2 = CanEnableDeviceExtension(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME); |
| |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| PFN_vkCmdCopyBuffer2KHR vkCmdCopyBuffer2Function = nullptr; |
| if (copy_commands2) { |
| vkCmdCopyBuffer2Function = (PFN_vkCmdCopyBuffer2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkCmdCopyBuffer2KHR"); |
| } |
| |
| const VkDeviceSize buffer_size = 2048; |
| |
| VkBufferObj buffer_one; |
| VkBufferObj buffer_two; |
| VkMemoryPropertyFlags reqs = 0; |
| buffer_one.init_as_src_and_dst(*m_device, buffer_size, reqs); |
| buffer_two.init_as_src_and_dst(*m_device, buffer_size, reqs); |
| |
| VkBufferCopy copy_info = {4096, 256, 256}; |
| |
| m_commandBuffer->begin(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBuffer-srcOffset-00113"); |
| vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_one.handle(), buffer_two.handle(), 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // equivalent test using KHR_copy_commands2 |
| if (copy_commands2 && vkCmdCopyBuffer2Function) { |
| const VkBufferCopy2KHR copy_info2 = {VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR, NULL, copy_info.srcOffset, copy_info.dstOffset, |
| copy_info.size}; |
| const VkCopyBufferInfo2KHR copy_buffer_info2 = { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR, NULL, buffer_one.handle(), buffer_two.handle(), 1, ©_info2}; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyBufferInfo2KHR-srcOffset-00113"); |
| vkCmdCopyBuffer2Function(m_commandBuffer->handle(), ©_buffer_info2); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBuffer-dstOffset-00114"); |
| copy_info = {256, 4096, 256}; |
| vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_one.handle(), buffer_two.handle(), 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // equivalent test using KHR_copy_commands2 |
| if (copy_commands2 && vkCmdCopyBuffer2Function) { |
| const VkBufferCopy2KHR copy_info2 = {VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR, NULL, copy_info.srcOffset, copy_info.dstOffset, |
| copy_info.size}; |
| const VkCopyBufferInfo2KHR copy_buffer_info2 = { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR, NULL, buffer_one.handle(), buffer_two.handle(), 1, ©_info2}; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyBufferInfo2KHR-dstOffset-00114"); |
| vkCmdCopyBuffer2Function(m_commandBuffer->handle(), ©_buffer_info2); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBuffer-size-00115"); |
| copy_info = {1024, 256, 1280}; |
| vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_one.handle(), buffer_two.handle(), 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // equivalent test using KHR_copy_commands2 |
| if (copy_commands2 && vkCmdCopyBuffer2Function) { |
| const VkBufferCopy2KHR copy_info2 = {VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR, NULL, copy_info.srcOffset, copy_info.dstOffset, |
| copy_info.size}; |
| const VkCopyBufferInfo2KHR copy_buffer_info2 = { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR, NULL, buffer_one.handle(), buffer_two.handle(), 1, ©_info2}; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyBufferInfo2KHR-size-00115"); |
| vkCmdCopyBuffer2Function(m_commandBuffer->handle(), ©_buffer_info2); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBuffer-size-00116"); |
| copy_info = {256, 1024, 1280}; |
| vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_one.handle(), buffer_two.handle(), 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // equivalent test using KHR_copy_commands2 |
| if (copy_commands2 && vkCmdCopyBuffer2Function) { |
| const VkBufferCopy2KHR copy_info2 = {VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR, NULL, copy_info.srcOffset, copy_info.dstOffset, |
| copy_info.size}; |
| const VkCopyBufferInfo2KHR copy_buffer_info2 = { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR, NULL, buffer_one.handle(), buffer_two.handle(), 1, ©_info2}; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyBufferInfo2KHR-size-00116"); |
| vkCmdCopyBuffer2Function(m_commandBuffer->handle(), ©_buffer_info2); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBuffer-pRegions-00117"); |
| copy_info = {256, 512, 512}; |
| vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_two.handle(), buffer_two.handle(), 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBufferCopy-size-01988"); |
| copy_info = {256, 256, 0}; |
| vk::CmdCopyBuffer(m_commandBuffer->handle(), buffer_two.handle(), buffer_two.handle(), 1, ©_info); |
| m_errorMonitor->VerifyFound(); |
| |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(VkLayerTest, MirrorClampToEdgeNotEnabled) { |
| TEST_DESCRIPTION("Validation should catch using CLAMP_TO_EDGE addressing mode if the extension is not enabled."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_0); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSamplerCreateInfo-addressModeU-01079"); |
| VkSampler sampler = VK_NULL_HANDLE; |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| // Set the modes to cause the error |
| sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| |
| vk::CreateSampler(m_device->device(), &sampler_info, NULL, &sampler); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, MirrorClampToEdgeNotEnabled12) { |
| TEST_DESCRIPTION("Validation using CLAMP_TO_EDGE for Vulkan 1.2 without the samplerMirrorClampToEdge feature enabled."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| if (DeviceValidationVersion() < VK_API_VERSION_1_2) { |
| printf("%s Tests requires Vulkan 1.2+, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSamplerCreateInfo-addressModeU-01079"); |
| VkSampler sampler = VK_NULL_HANDLE; |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; |
| |
| vk::CreateSampler(m_device->device(), &sampler_info, NULL, &sampler); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, AnisotropyFeatureDisabled) { |
| TEST_DESCRIPTION("Validation should check anisotropy parameters are correct with samplerAnisotropy disabled."); |
| |
| // Determine if required device features are available |
| VkPhysicalDeviceFeatures device_features = {}; |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features)); |
| device_features.samplerAnisotropy = VK_FALSE; // force anisotropy off |
| ASSERT_NO_FATAL_FAILURE(InitState(&device_features)); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSamplerCreateInfo-anisotropyEnable-01070"); |
| VkSamplerCreateInfo sampler_info = SafeSaneSamplerCreateInfo(); |
| // With the samplerAnisotropy disable, the sampler must not enable it. |
| sampler_info.anisotropyEnable = VK_TRUE; |
| VkSampler sampler = VK_NULL_HANDLE; |
| |
| VkResult err; |
| err = vk::CreateSampler(m_device->device(), &sampler_info, NULL, &sampler); |
| m_errorMonitor->VerifyFound(); |
| if (VK_SUCCESS == err) { |
| vk::DestroySampler(m_device->device(), sampler, NULL); |
| } |
| sampler = VK_NULL_HANDLE; |
| } |
| |
| TEST_F(VkLayerTest, AnisotropyFeatureEnabled) { |
| TEST_DESCRIPTION("Validation must check several conditions that apply only when Anisotropy is enabled."); |
| |
| // Determine if required device features are available |
| AddRequiredExtensions(VK_IMG_FILTER_CUBIC_EXTENSION_NAME); |
| VkPhysicalDeviceFeatures device_features = {}; |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features)); |
| |
| // These tests require that the device support anisotropic filtering |
| if (VK_TRUE != device_features.samplerAnisotropy) { |
| printf("%s Test requires unsupported samplerAnisotropy feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| const bool cubic_support = CanEnableDeviceExtension(VK_IMG_FILTER_CUBIC_EXTENSION_NAME); |
| |
| VkSamplerCreateInfo sampler_info_ref = SafeSaneSamplerCreateInfo(); |
| sampler_info_ref.anisotropyEnable = VK_TRUE; |
| VkSamplerCreateInfo sampler_info = sampler_info_ref; |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // maxAnisotropy out-of-bounds low. |
| sampler_info.maxAnisotropy = NearestSmaller(1.0F); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-anisotropyEnable-01071"); |
| sampler_info.maxAnisotropy = sampler_info_ref.maxAnisotropy; |
| |
| // maxAnisotropy out-of-bounds high. |
| sampler_info.maxAnisotropy = NearestGreater(m_device->phy().properties().limits.maxSamplerAnisotropy); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-anisotropyEnable-01071"); |
| sampler_info.maxAnisotropy = sampler_info_ref.maxAnisotropy; |
| |
| // Both anisotropy and unnormalized coords enabled |
| sampler_info.unnormalizedCoordinates = VK_TRUE; |
| // If unnormalizedCoordinates is VK_TRUE, minLod and maxLod must be zero |
| sampler_info.minLod = 0; |
| sampler_info.maxLod = 0; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01076"); |
| sampler_info.unnormalizedCoordinates = sampler_info_ref.unnormalizedCoordinates; |
| |
| // Both anisotropy and cubic filtering enabled |
| if (cubic_support) { |
| sampler_info.minFilter = VK_FILTER_CUBIC_IMG; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-magFilter-01081"); |
| sampler_info.minFilter = sampler_info_ref.minFilter; |
| |
| sampler_info.magFilter = VK_FILTER_CUBIC_IMG; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-magFilter-01081"); |
| sampler_info.magFilter = sampler_info_ref.magFilter; |
| } else { |
| printf("%s Test requires unsupported extension \"VK_IMG_filter_cubic\". Skipped.\n", kSkipPrefix); |
| } |
| } |
| |
| TEST_F(VkLayerTest, UnnormalizedCoordinatesEnabled) { |
| TEST_DESCRIPTION("Validate restrictions on sampler parameters when unnormalizedCoordinates is true."); |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| VkSamplerCreateInfo sampler_info_ref = SafeSaneSamplerCreateInfo(); |
| sampler_info_ref.unnormalizedCoordinates = VK_TRUE; |
| sampler_info_ref.minLod = 0.0f; |
| sampler_info_ref.maxLod = 0.0f; |
| VkSamplerCreateInfo sampler_info = sampler_info_ref; |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // min and mag filters must be the same |
| sampler_info.minFilter = VK_FILTER_NEAREST; |
| sampler_info.magFilter = VK_FILTER_LINEAR; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01072"); |
| std::swap(sampler_info.minFilter, sampler_info.magFilter); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01072"); |
| sampler_info = sampler_info_ref; |
| |
| // mipmapMode must be NEAREST |
| sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01073"); |
| sampler_info = sampler_info_ref; |
| |
| // minlod and maxlod must be zero |
| sampler_info.maxLod = 3.14159f; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01074"); |
| sampler_info.minLod = 2.71828f; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01074"); |
| sampler_info = sampler_info_ref; |
| |
| // addressModeU and addressModeV must both be CLAMP_TO_EDGE or CLAMP_TO_BORDER |
| // checks all 12 invalid combinations out of 16 total combinations |
| const std::array<VkSamplerAddressMode, 4> kAddressModes = {{ |
| VK_SAMPLER_ADDRESS_MODE_REPEAT, |
| VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| }}; |
| for (const auto umode : kAddressModes) { |
| for (const auto vmode : kAddressModes) { |
| if ((umode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE && umode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER) || |
| (vmode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE && vmode != VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)) { |
| sampler_info.addressModeU = umode; |
| sampler_info.addressModeV = vmode; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01075"); |
| } |
| } |
| } |
| sampler_info = sampler_info_ref; |
| |
| // VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01076 is tested in AnisotropyFeatureEnabled above |
| // Since it requires checking/enabling the anisotropic filtering feature, it's easier to do it |
| // with the other anisotropic tests. |
| |
| // compareEnable must be VK_FALSE |
| sampler_info.compareEnable = VK_TRUE; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-unnormalizedCoordinates-01077"); |
| sampler_info = sampler_info_ref; |
| } |
| |
| TEST_F(VkLayerTest, InvalidSamplerCreateInfo) { |
| TEST_DESCRIPTION("Checks various cases where VkSamplerCreateInfo is invalid"); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // reference to reset values between test cases |
| VkSamplerCreateInfo const sampler_info_ref = SafeSaneSamplerCreateInfo(); |
| VkSamplerCreateInfo sampler_info = sampler_info_ref; |
| |
| // Mix up Lod values |
| sampler_info.minLod = 4.0f; |
| sampler_info.maxLod = 1.0f; |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-maxLod-01973"); |
| sampler_info.minLod = sampler_info_ref.minLod; |
| sampler_info.maxLod = sampler_info_ref.maxLod; |
| |
| // Larger mipLodBias than max limit |
| sampler_info.mipLodBias = NearestGreater(m_device->phy().properties().limits.maxSamplerLodBias); |
| CreateSamplerTest(*this, &sampler_info, "VUID-VkSamplerCreateInfo-mipLodBias-01069"); |
| sampler_info.mipLodBias = sampler_info_ref.mipLodBias; |
| } |
| |
| TEST_F(VkLayerTest, UpdateBufferAlignment) { |
| TEST_DESCRIPTION("Check alignment parameters for vkCmdUpdateBuffer"); |
| uint32_t updateData[] = {1, 2, 3, 4, 5, 6, 7, 8}; |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
| VkBufferObj buffer; |
| buffer.init_as_dst(*m_device, (VkDeviceSize)20, reqs); |
| |
| m_commandBuffer->begin(); |
| // Introduce failure by using dstOffset that is not multiple of 4 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, " is not a multiple of 4"); |
| m_commandBuffer->UpdateBuffer(buffer.handle(), 1, 4, updateData); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using dataSize that is not multiple of 4 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, " is not a multiple of 4"); |
| m_commandBuffer->UpdateBuffer(buffer.handle(), 0, 6, updateData); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using dataSize that is < 0 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "must be greater than zero and less than or equal to 65536"); |
| m_commandBuffer->UpdateBuffer(buffer.handle(), 0, (VkDeviceSize)-44, updateData); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using dataSize that is > 65536 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "must be greater than zero and less than or equal to 65536"); |
| m_commandBuffer->UpdateBuffer(buffer.handle(), 0, (VkDeviceSize)80000, updateData); |
| m_errorMonitor->VerifyFound(); |
| |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(VkLayerTest, FillBufferAlignmentAndSize) { |
| TEST_DESCRIPTION("Check alignment and size parameters for vkCmdFillBuffer"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkMemoryPropertyFlags reqs = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
| VkBufferObj buffer; |
| buffer.init_as_dst(*m_device, (VkDeviceSize)20, reqs); |
| |
| m_commandBuffer->begin(); |
| |
| // Introduce failure by using dstOffset greater than bufferSize |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdFillBuffer-dstOffset-00024"); |
| m_commandBuffer->FillBuffer(buffer.handle(), 40, 4, 0x11111111); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using size <= buffersize minus dstoffset |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdFillBuffer-size-00027"); |
| m_commandBuffer->FillBuffer(buffer.handle(), 16, 12, 0x11111111); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using dstOffset that is not multiple of 4 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, " is not a multiple of 4"); |
| m_commandBuffer->FillBuffer(buffer.handle(), 1, 4, 0x11111111); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using size that is not multiple of 4 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, " is not a multiple of 4"); |
| m_commandBuffer->FillBuffer(buffer.handle(), 0, 6, 0x11111111); |
| m_errorMonitor->VerifyFound(); |
| |
| // Introduce failure by using size that is zero |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "must be greater than zero"); |
| m_commandBuffer->FillBuffer(buffer.handle(), 0, 0, 0x11111111); |
| m_errorMonitor->VerifyFound(); |
| |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(VkLayerTest, SparseBindingImageBufferCreate) { |
| TEST_DESCRIPTION("Create buffer/image with sparse attributes but without the sparse_binding bit set"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkBufferCreateInfo buf_info = {}; |
| buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buf_info.pNext = NULL; |
| buf_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; |
| buf_info.size = 2048; |
| buf_info.queueFamilyIndexCount = 0; |
| buf_info.pQueueFamilyIndices = NULL; |
| buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| |
| if (m_device->phy().features().sparseResidencyBuffer) { |
| buf_info.flags = VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT; |
| CreateBufferTest(*this, &buf_info, "VUID-VkBufferCreateInfo-flags-00918"); |
| } else { |
| printf("%s Test requires unsupported sparseResidencyBuffer feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| if (m_device->phy().features().sparseResidencyAliased) { |
| buf_info.flags = VK_BUFFER_CREATE_SPARSE_ALIASED_BIT; |
| CreateBufferTest(*this, &buf_info, "VUID-VkBufferCreateInfo-flags-00918"); |
| } else { |
| printf("%s Test requires unsupported sparseResidencyAliased feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 512; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 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.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_create_info.queueFamilyIndexCount = 0; |
| image_create_info.pQueueFamilyIndices = NULL; |
| image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| |
| if (m_device->phy().features().sparseResidencyImage2D) { |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-flags-00987"); |
| } else { |
| printf("%s Test requires unsupported sparseResidencyImage2D feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| if (m_device->phy().features().sparseResidencyAliased) { |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_ALIASED_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-flags-00987"); |
| } else { |
| printf("%s Test requires unsupported sparseResidencyAliased feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| } |
| |
| TEST_F(VkLayerTest, SparseResidencyImageCreateUnsupportedTypes) { |
| TEST_DESCRIPTION("Create images with sparse residency with unsupported types"); |
| |
| // Determine which device feature are available |
| VkPhysicalDeviceFeatures device_features = {}; |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features)); |
| |
| // Mask out device features we don't want and initialize device state |
| device_features.sparseResidencyImage2D = VK_FALSE; |
| device_features.sparseResidencyImage3D = VK_FALSE; |
| ASSERT_NO_FATAL_FAILURE(InitState(&device_features)); |
| |
| if (!m_device->phy().features().sparseBinding) { |
| printf("%s Test requires unsupported sparseBinding feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_1D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 512; |
| image_create_info.extent.height = 1; |
| image_create_info.extent.depth = 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.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_create_info.queueFamilyIndexCount = 0; |
| image_create_info.pQueueFamilyIndices = NULL; |
| image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| |
| // 1D image w/ sparse residency is an error |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00970"); |
| |
| // 2D image w/ sparse residency when feature isn't available |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.extent.height = 64; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00971"); |
| |
| // 3D image w/ sparse residency when feature isn't available |
| image_create_info.imageType = VK_IMAGE_TYPE_3D; |
| image_create_info.extent.depth = 8; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00972"); |
| } |
| |
| TEST_F(VkLayerTest, SparseResidencyImageCreateUnsupportedSamples) { |
| TEST_DESCRIPTION("Create images with sparse residency with unsupported tiling or sample counts"); |
| |
| // Determine which device feature are available |
| VkPhysicalDeviceFeatures device_features = {}; |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features)); |
| |
| // These tests require that the device support sparse residency for 2D images |
| if (VK_TRUE != device_features.sparseResidencyImage2D) { |
| printf("%s Test requires unsupported SparseResidencyImage2D feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| // Mask out device features we don't want and initialize device state |
| device_features.sparseResidency2Samples = VK_FALSE; |
| device_features.sparseResidency4Samples = VK_FALSE; |
| device_features.sparseResidency8Samples = VK_FALSE; |
| device_features.sparseResidency16Samples = VK_FALSE; |
| ASSERT_NO_FATAL_FAILURE(InitState(&device_features)); |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 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_LINEAR; |
| image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_create_info.queueFamilyIndexCount = 0; |
| image_create_info.pQueueFamilyIndices = NULL; |
| image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_BINDING_BIT; |
| |
| // 2D image w/ sparse residency and linear tiling is an error |
| CreateImageTest(*this, &image_create_info, |
| "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then image tiling of VK_IMAGE_TILING_LINEAR is not supported"); |
| image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| |
| // Multi-sample image w/ sparse residency when feature isn't available (4 flavors) |
| image_create_info.samples = VK_SAMPLE_COUNT_2_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00973"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_4_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00974"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_8_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00975"); |
| |
| image_create_info.samples = VK_SAMPLE_COUNT_16_BIT; |
| CreateImageTest(*this, &image_create_info, "VUID-VkImageCreateInfo-imageType-00976"); |
| } |
| |
| TEST_F(VkLayerTest, SparseResidencyFlagMissing) { |
| TEST_DESCRIPTION("Try to use VkSparseImageMemoryBindInfo without sparse residency flag"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| if (!m_device->phy().features().sparseResidencyImage2D) { |
| printf("%s Test requires unsupported sparseResidencyImage2D feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 512; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 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.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| image_create_info.queueFamilyIndexCount = 0; |
| image_create_info.pQueueFamilyIndices = NULL; |
| image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| |
| VkImageObj image(m_device); |
| image.init_no_mem(*m_device, image_create_info); |
| |
| VkSparseImageMemoryBind image_memory_bind = {}; |
| image_memory_bind.subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| VkSparseImageMemoryBindInfo image_memory_bind_info = {}; |
| image_memory_bind_info.image = image.handle(); |
| image_memory_bind_info.bindCount = 1; |
| image_memory_bind_info.pBinds = &image_memory_bind; |
| |
| VkBindSparseInfo bind_info = {}; |
| bind_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; |
| bind_info.imageBindCount = 1; |
| bind_info.pImageBinds = &image_memory_bind_info; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkSparseImageMemoryBindInfo-image-02901"); |
| vk::QueueBindSparse(m_device->m_queue, 1, &bind_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InvalidMemoryMapping) { |
| TEST_DESCRIPTION("Attempt to map memory in a number of incorrect ways"); |
| VkResult err; |
| bool pass; |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkBuffer buffer; |
| VkDeviceMemory mem; |
| VkMemoryRequirements mem_reqs; |
| |
| const VkDeviceSize atom_size = m_device->props.limits.nonCoherentAtomSize; |
| |
| VkBufferCreateInfo buf_info = {}; |
| buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buf_info.pNext = NULL; |
| buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; |
| buf_info.size = 256; |
| buf_info.queueFamilyIndexCount = 0; |
| buf_info.pQueueFamilyIndices = NULL; |
| buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| buf_info.flags = 0; |
| err = vk::CreateBuffer(m_device->device(), &buf_info, NULL, &buffer); |
| ASSERT_VK_SUCCESS(err); |
| |
| vk::GetBufferMemoryRequirements(m_device->device(), buffer, &mem_reqs); |
| VkMemoryAllocateInfo alloc_info = {}; |
| alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| alloc_info.pNext = NULL; |
| alloc_info.memoryTypeIndex = 0; |
| |
| // Ensure memory is big enough for both bindings |
| // Want to make sure entire allocation is aligned to atom size |
| static const VkDeviceSize allocation_size = atom_size * 64; |
| alloc_info.allocationSize = allocation_size; |
| pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); |
| if (!pass) { |
| printf("%s Failed to set memory type.\n", kSkipPrefix); |
| vk::DestroyBuffer(m_device->device(), buffer, NULL); |
| return; |
| } |
| err = vk::AllocateMemory(m_device->device(), &alloc_info, NULL, &mem); |
| ASSERT_VK_SUCCESS(err); |
| |
| uint8_t *pData; |
| // Attempt to map memory size 0 is invalid |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMapMemory-size-00680"); |
| err = vk::MapMemory(m_device->device(), mem, 0, 0, 0, (void **)&pData); |
| m_errorMonitor->VerifyFound(); |
| // Map memory twice |
| err = vk::MapMemory(m_device->device(), mem, 0, mem_reqs.size, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMapMemory-memory-00678"); |
| m_errorMonitor->SetUnexpectedError("VUID-vkMapMemory-size-00681"); |
| err = vk::MapMemory(m_device->device(), mem, 0, mem_reqs.size, 0, (void **)&pData); |
| m_errorMonitor->VerifyFound(); |
| |
| // Unmap the memory to avoid re-map error |
| vk::UnmapMemory(m_device->device(), mem); |
| // overstep offset with VK_WHOLE_SIZE |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMapMemory-offset-00679"); |
| err = vk::MapMemory(m_device->device(), mem, allocation_size + 1, VK_WHOLE_SIZE, 0, (void **)&pData); |
| m_errorMonitor->VerifyFound(); |
| // overstep offset w/o VK_WHOLE_SIZE |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMapMemory-offset-00679"); |
| err = vk::MapMemory(m_device->device(), mem, allocation_size + 1, VK_WHOLE_SIZE, 0, (void **)&pData); |
| m_errorMonitor->VerifyFound(); |
| // overstep allocation w/o VK_WHOLE_SIZE |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMapMemory-size-00681"); |
| err = vk::MapMemory(m_device->device(), mem, 1, allocation_size, 0, (void **)&pData); |
| m_errorMonitor->VerifyFound(); |
| // Now error due to unmapping memory that's not mapped |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkUnmapMemory-memory-00689"); |
| vk::UnmapMemory(m_device->device(), mem); |
| m_errorMonitor->VerifyFound(); |
| |
| // Now map memory and cause errors due to flushing invalid ranges |
| err = vk::MapMemory(m_device->device(), mem, 4 * atom_size, VK_WHOLE_SIZE, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| VkMappedMemoryRange mmr = {}; |
| mmr.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; |
| mmr.pNext = nullptr; |
| mmr.memory = mem; |
| mmr.offset = atom_size; // Error b/c offset less than offset of mapped mem |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-size-00685"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| // Now flush range that oversteps mapped range |
| vk::UnmapMemory(m_device->device(), mem); |
| err = vk::MapMemory(m_device->device(), mem, 0, 4 * atom_size, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| mmr.offset = atom_size; |
| mmr.size = 4 * atom_size; // Flushing bounds exceed mapped bounds |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-size-00685"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| // Now flush range with VK_WHOLE_SIZE that oversteps offset |
| vk::UnmapMemory(m_device->device(), mem); |
| err = vk::MapMemory(m_device->device(), mem, 2 * atom_size, 4 * atom_size, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| mmr.offset = atom_size; |
| mmr.size = VK_WHOLE_SIZE; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-size-00686"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| // Some platforms have an atomsize of 1 which makes the test meaningless |
| if (atom_size > 3) { |
| // Now with an offset NOT a multiple of the device limit |
| vk::UnmapMemory(m_device->device(), mem); |
| err = vk::MapMemory(m_device->device(), mem, 0, 4 * atom_size, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| mmr.offset = 3; // Not a multiple of atom_size |
| mmr.size = VK_WHOLE_SIZE; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-offset-00687"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| // Now with a size NOT a multiple of the device limit |
| vk::UnmapMemory(m_device->device(), mem); |
| err = vk::MapMemory(m_device->device(), mem, 0, 4 * atom_size, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| mmr.offset = atom_size; |
| mmr.size = 2 * atom_size + 1; // Not a multiple of atom_size |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-size-01390"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| // Now with VK_WHOLE_SIZE and a mapping that does not end at a multiple of atom_size nor at the end of the memory. |
| vk::UnmapMemory(m_device->device(), mem); |
| err = vk::MapMemory(m_device->device(), mem, 0, 4 * atom_size + 1, 0, (void **)&pData); |
| ASSERT_VK_SUCCESS(err); |
| mmr.offset = atom_size; |
| mmr.size = VK_WHOLE_SIZE; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-size-01389"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Try flushing and invalidating host memory not mapped |
| vk::UnmapMemory(m_device->device(), mem); |
| mmr.offset = 0; |
| mmr.size = VK_WHOLE_SIZE; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-memory-00684"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-memory-00684"); |
| vk::InvalidateMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::DestroyBuffer(m_device->device(), buffer, NULL); |
| vk::FreeMemory(m_device->device(), mem, NULL); |
| |
| // device memory not atom size aligned |
| alloc_info.allocationSize = (atom_size * 4) + 1; |
| ASSERT_VK_SUCCESS(vk::CreateBuffer(m_device->device(), &buf_info, NULL, &buffer)); |
| pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); |
| if (!pass) { |
| printf("%s Failed to set memory type.\n", kSkipPrefix); |
| vk::DestroyBuffer(m_device->device(), buffer, NULL); |
| return; |
| } |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(m_device->device(), &alloc_info, NULL, &mem)); |
| ASSERT_VK_SUCCESS(vk::MapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, (void **)&pData)); |
| // Some platforms have an atomsize of 1 which makes the test meaningless |
| if (atom_size > 1) { |
| // Offset is atom size, but total memory range is not atom size |
| mmr.memory = mem; |
| mmr.offset = atom_size; |
| mmr.size = VK_WHOLE_SIZE; |
| m_errorMonitor->ExpectSuccess(); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &mmr); |
| m_errorMonitor->VerifyNotFound(); |
| } |
| |
| pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &alloc_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, |
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); |
| if (!pass) { |
| printf("%s Failed to set memory type.\n", kSkipPrefix); |
| vk::FreeMemory(m_device->device(), mem, NULL); |
| vk::DestroyBuffer(m_device->device(), buffer, NULL); |
| return; |
| } |
| // TODO : If we can get HOST_VISIBLE w/o HOST_COHERENT we can test cases of |
| // kVUID_Core_MemTrack_InvalidMap in validateAndCopyNoncoherentMemoryToDriver() |
| |
| vk::DestroyBuffer(m_device->device(), buffer, NULL); |
| vk::FreeMemory(m_device->device(), mem, NULL); |
| } |
| |
| TEST_F(VkLayerTest, MapMemWithoutHostVisibleBit) { |
| TEST_DESCRIPTION("Allocate memory that is not mappable and then attempt to map it."); |
| VkResult err; |
| bool pass; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkMapMemory-memory-00682"); |
| m_errorMonitor->SetUnexpectedError("VUID-vkMapMemory-memory-00683"); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkMemoryAllocateInfo mem_alloc = {}; |
| mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mem_alloc.pNext = NULL; |
| mem_alloc.allocationSize = 1024; |
| |
| pass = m_device->phy().set_memory_type(0xFFFFFFFF, &mem_alloc, 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); |
| if (!pass) { // If we can't find any unmappable memory this test doesn't |
| // make sense |
| printf("%s No unmappable memory types found, skipping test\n", kSkipPrefix); |
| return; |
| } |
| |
| VkDeviceMemory mem; |
| err = vk::AllocateMemory(m_device->device(), &mem_alloc, NULL, &mem); |
| ASSERT_VK_SUCCESS(err); |
| |
| void *mappedAddress = NULL; |
| err = vk::MapMemory(m_device->device(), mem, 0, VK_WHOLE_SIZE, 0, &mappedAddress); |
| m_errorMonitor->VerifyFound(); |
| |
| // Attempt to flush and invalidate non-host memory |
| VkMappedMemoryRange memory_range = {}; |
| memory_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; |
| memory_range.pNext = nullptr; |
| memory_range.memory = mem; |
| memory_range.offset = 0; |
| memory_range.size = VK_WHOLE_SIZE; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-memory-00684"); |
| vk::FlushMappedMemoryRanges(m_device->device(), 1, &memory_range); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkMappedMemoryRange-memory-00684"); |
| vk::InvalidateMappedMemoryRanges(m_device->device(), 1, &memory_range); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(m_device->device(), mem, NULL); |
| } |
| |
| TEST_F(VkLayerTest, RebindMemory_MultiObjectDebugUtils) { |
| VkResult err; |
| bool pass; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-image-01044"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // Create an image, allocate memory, free it, and then try to bind it |
| VkImage image; |
| VkDeviceMemory mem1; |
| VkDeviceMemory mem2; |
| VkMemoryRequirements mem_reqs; |
| |
| const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; |
| const int32_t tex_width = 32; |
| const int32_t tex_height = 32; |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = tex_format; |
| image_create_info.extent.width = tex_width; |
| image_create_info.extent.height = tex_height; |
| image_create_info.extent.depth = 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; |
| |
| VkMemoryAllocateInfo mem_alloc = {}; |
| mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mem_alloc.pNext = NULL; |
| mem_alloc.allocationSize = 0; |
| mem_alloc.memoryTypeIndex = 0; |
| |
| // Introduce failure, do NOT set memProps to |
| // VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
| mem_alloc.memoryTypeIndex = 1; |
| err = vk::CreateImage(m_device->device(), &image_create_info, NULL, &image); |
| ASSERT_VK_SUCCESS(err); |
| |
| vk::GetImageMemoryRequirements(m_device->device(), image, &mem_reqs); |
| |
| mem_alloc.allocationSize = mem_reqs.size; |
| pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); |
| ASSERT_TRUE(pass); |
| |
| // allocate 2 memory objects |
| err = vk::AllocateMemory(m_device->device(), &mem_alloc, NULL, &mem1); |
| ASSERT_VK_SUCCESS(err); |
| err = vk::AllocateMemory(m_device->device(), &mem_alloc, NULL, &mem2); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Bind first memory object to Image object |
| err = vk::BindImageMemory(m_device->device(), image, mem1, 0); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Introduce validation failure, try to bind a different memory object to |
| // the same image object |
| err = vk::BindImageMemory(m_device->device(), image, mem2, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| // This particular VU should output three objects in its error message. Verify this works correctly. |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VK_OBJECT_TYPE_IMAGE"); |
| err = vk::BindImageMemory(m_device->device(), image, mem2, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::DestroyImage(m_device->device(), image, NULL); |
| vk::FreeMemory(m_device->device(), mem1, NULL); |
| vk::FreeMemory(m_device->device(), mem2, NULL); |
| } |
| |
| TEST_F(VkLayerTest, QueryMemoryCommitmentWithoutLazyProperty) { |
| TEST_DESCRIPTION("Attempt to query memory commitment on memory without lazy allocation"); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| auto image_ci = vk_testing::Image::create_info(); |
| image_ci.imageType = VK_IMAGE_TYPE_2D; |
| image_ci.format = VK_FORMAT_B8G8R8A8_UNORM; |
| image_ci.extent.width = 32; |
| image_ci.extent.height = 32; |
| image_ci.tiling = VK_IMAGE_TILING_OPTIMAL; |
| image_ci.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| VkImageObj image(m_device); |
| image.init_no_mem(*m_device, image_ci); |
| |
| auto mem_reqs = image.memory_requirements(); |
| // memory_type_index is set to 0 here, but is set properly below |
| auto image_alloc_info = vk_testing::DeviceMemory::alloc_info(mem_reqs.size, 0); |
| |
| bool pass; |
| // the last argument is the "forbid" argument for set_memory_type, disallowing |
| // that particular memory type rather than requiring it |
| pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &image_alloc_info, 0, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT); |
| if (!pass) { |
| printf("%s Failed to set memory type.\n", kSkipPrefix); |
| return; |
| } |
| vk_testing::DeviceMemory mem; |
| mem.init(*m_device, image_alloc_info); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetDeviceMemoryCommitment-memory-00690"); |
| VkDeviceSize size; |
| vk::GetDeviceMemoryCommitment(m_device->device(), mem.handle(), &size); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InvalidSparseImageUsageBits) { |
| TEST_DESCRIPTION("Try to use VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT with sparse image"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| VkPhysicalDeviceFeatures device_features = {}; |
| ASSERT_NO_FATAL_FAILURE(GetPhysicalDeviceFeatures(&device_features)); |
| |
| if (!device_features.sparseBinding) { |
| printf("%s No sparseBinding feature. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| auto image_create_info = LvlInitStruct<VkImageCreateInfo>(); |
| image_create_info.flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 32; |
| image_create_info.extent.height = 32; |
| image_create_info.extent.depth = 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.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| image_create_info.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
| image_create_info.queueFamilyIndexCount = 0; |
| image_create_info.pQueueFamilyIndices = NULL; |
| image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| |
| VkImageObj image(m_device); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageCreateInfo-None-01925"); |
| VkImage img = image.image(); |
| vk::CreateImage(m_device->device(), &image_create_info, nullptr, &img); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, InvalidUsageBits) { |
| TEST_DESCRIPTION( |
| "Specify wrong usage for image then create conflicting view of image Initialize buffer with wrong usage then perform copy " |
| "expecting errors from both the image and the buffer (2 calls)"); |
| |
| AddRequiredExtensions(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| |
| const bool copy_commands2 = CanEnableDeviceExtension(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| PFN_vkCmdCopyBufferToImage2KHR vkCmdCopyBufferToImage2Function = nullptr; |
| if (copy_commands2) { |
| vkCmdCopyBufferToImage2Function = |
| (PFN_vkCmdCopyBufferToImage2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkCmdCopyBufferToImage2KHR"); |
| } |
| |
| auto format = FindSupportedDepthStencilFormat(gpu()); |
| if (!format) { |
| printf("%s No Depth + Stencil format found. Skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkImageObj image(m_device); |
| // Initialize image with transfer source usage |
| image.Init(128, 128, 1, format, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_IMAGE_TILING_OPTIMAL, 0); |
| ASSERT_TRUE(image.initialized()); |
| |
| VkImageView dsv; |
| VkImageViewCreateInfo dsvci = {}; |
| dsvci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
| dsvci.image = image.handle(); |
| dsvci.viewType = VK_IMAGE_VIEW_TYPE_2D; |
| dsvci.format = format; |
| dsvci.subresourceRange.layerCount = 1; |
| dsvci.subresourceRange.baseMipLevel = 0; |
| dsvci.subresourceRange.levelCount = 1; |
| dsvci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; |
| |
| // Create a view with depth / stencil aspect for image with different usage |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkImageViewCreateInfo-image-04441"); |
| vk::CreateImageView(m_device->device(), &dsvci, NULL, &dsv); |
| m_errorMonitor->VerifyFound(); |
| |
| // Initialize buffer with TRANSFER_DST usage |
| VkBufferObj buffer; |
| VkMemoryPropertyFlags reqs = 0; |
| buffer.init_as_dst(*m_device, 128 * 128, reqs); |
| VkBufferImageCopy region = {}; |
| region.bufferRowLength = 128; |
| region.bufferImageHeight = 128; |
| region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
| region.imageSubresource.layerCount = 1; |
| region.imageExtent.height = 16; |
| region.imageExtent.width = 16; |
| region.imageExtent.depth = 1; |
| |
| // Buffer usage not set to TRANSFER_SRC and image usage not set to TRANSFER_DST |
| m_commandBuffer->begin(); |
| |
| // two separate errors from this call: |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBufferToImage-dstImage-00177"); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBufferToImage-srcBuffer-00174"); |
| |
| vk::CmdCopyBufferToImage(m_commandBuffer->handle(), buffer.handle(), image.handle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, |
| ®ion); |
| m_errorMonitor->VerifyFound(); |
| |
| // equvalent test using using KHR_copy_commands2 |
| if (copy_commands2 && vkCmdCopyBufferToImage2Function) { |
| const VkBufferImageCopy2KHR region2 = {VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR, |
| NULL, |
| region.bufferRowLength, |
| region.bufferImageHeight, |
| region.bufferImageHeight, |
| region.imageSubresource, |
| region.imageOffset, |
| region.imageExtent}; |
| VkCopyBufferToImageInfo2KHR buffer_to_image_info2 = {VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR, |
| NULL, |
| buffer.handle(), |
| image.handle(), |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
| 1, |
| ®ion2}; |
| // two separate errors from this call: |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyBufferToImageInfo2KHR-dstImage-00177"); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkCopyBufferToImageInfo2KHR-srcBuffer-00174"); |
| vkCmdCopyBufferToImage2Function(m_commandBuffer->handle(), &buffer_to_image_info2); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| TEST_F(VkLayerTest, CopyBufferToCompressedImage) { |
| TEST_DESCRIPTION("Copy buffer to compressed image when buffer is larger than image."); |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // Verify format support |
| if (!ImageFormatAndFeaturesSupported(gpu(), VK_FORMAT_BC1_RGBA_SRGB_BLOCK, VK_IMAGE_TILING_OPTIMAL, |
| VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR)) { |
| printf("%s Required formats/features not supported - CopyBufferToCompressedImage skipped.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkImageObj width_image(m_device); |
| VkImageObj height_image(m_device); |
| VkBufferObj buffer; |
| VkMemoryPropertyFlags reqs = 0; |
| buffer.init_as_src(*m_device, 8 * 4 * 2, reqs); |
| VkBufferImageCopy region = {}; |
| region.bufferRowLength = 0; |
| region.bufferImageHeight = 0; |
| region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; |
| region.imageSubresource.layerCount = 1; |
| region.imageExtent.width = 8; |
| region.imageExtent.height = 4; |
| region.imageExtent.depth = 1; |
| |
| width_image.Init(5, 4, 1, VK_FORMAT_BC1_RGBA_SRGB_BLOCK, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_TILING_OPTIMAL); |
| height_image.Init(8, 3, 1, VK_FORMAT_BC1_RGBA_SRGB_BLOCK, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_TILING_OPTIMAL); |
| if (!width_image.initialized() || (!height_image.initialized())) { |
| printf("%s Unable to initialize surfaces - UncompressedToCompressedImageCopy skipped.\n", kSkipPrefix); |
| return; |
| } |
| m_commandBuffer->begin(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBufferToImage-pRegions-06218"); |
| vk::CmdCopyBufferToImage(m_commandBuffer->handle(), buffer.handle(), width_image.handle(), VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkCmdCopyBufferToImage-imageOffset-00200"); |
| m_errorMonitor->SetUnexpectedError("VUID-vkCmdCopyBufferToImage-pRegions-06217"); |
| |
| VkResult err; |
| VkImageCreateInfo depth_image_create_info = {}; |
| depth_image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| depth_image_create_info.pNext = NULL; |
| depth_image_create_info.imageType = VK_IMAGE_TYPE_3D; |
| depth_image_create_info.format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; |
| depth_image_create_info.extent.width = 8; |
| depth_image_create_info.extent.height = 4; |
| depth_image_create_info.extent.depth = 1; |
| depth_image_create_info.mipLevels = 1; |
| depth_image_create_info.arrayLayers = 1; |
| depth_image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| depth_image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| depth_image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; |
| depth_image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
| depth_image_create_info.queueFamilyIndexCount = 0; |
| depth_image_create_info.pQueueFamilyIndices = NULL; |
| |
| VkImage depth_image = VK_NULL_HANDLE; |
| err = vk::CreateImage(m_device->handle(), &depth_image_create_info, NULL, &depth_image); |
| ASSERT_VK_SUCCESS(err); |
| |
| VkDeviceMemory mem1; |
| VkMemoryRequirements mem_reqs; |
| mem_reqs.memoryTypeBits = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
| VkMemoryAllocateInfo mem_alloc = {}; |
| mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mem_alloc.pNext = NULL; |
| mem_alloc.allocationSize = 0; |
| mem_alloc.memoryTypeIndex = 0; |
| mem_alloc.memoryTypeIndex = 1; |
| vk::GetImageMemoryRequirements(m_device->device(), depth_image, &mem_reqs); |
| mem_alloc.allocationSize = mem_reqs.size; |
| bool pass = m_device->phy().set_memory_type(mem_reqs.memoryTypeBits, &mem_alloc, 0); |
| ASSERT_TRUE(pass); |
| err = vk::AllocateMemory(m_device->device(), &mem_alloc, NULL, &mem1); |
| ASSERT_VK_SUCCESS(err); |
| err = vk::BindImageMemory(m_device->device(), depth_image, mem1, 0); |
| |
| region.imageExtent.depth = 2; |
| vk::CmdCopyBufferToImage(m_commandBuffer->handle(), buffer.handle(), depth_image, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::DestroyImage(m_device->device(), depth_image, NULL); |
| vk::FreeMemory(m_device->device(), mem1, NULL); |
| m_commandBuffer->end(); |
| } |
| |
| TEST_F(VkLayerTest, CreateUnknownObject) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkGetImageMemoryRequirements-image-parameter"); |
| |
| TEST_DESCRIPTION("Pass an invalid image object handle into a Vulkan API call."); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // Pass bogus handle into GetImageMemoryRequirements |
| VkMemoryRequirements mem_reqs; |
| uint64_t fakeImageHandle = 0xCADECADE; |
| VkImage fauxImage = reinterpret_cast<VkImage &>(fakeImageHandle); |
| |
| vk::GetImageMemoryRequirements(m_device->device(), fauxImage, &mem_reqs); |
| |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(VkLayerTest, BindImageInvalidMemoryType) { |
| VkResult err; |
| |
| TEST_DESCRIPTION("Test validation check for an invalid memory type index during bind[Buffer|Image]Memory time"); |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| // Create an image, allocate memory, set a bad typeIndex and then try to |
| // bind it |
| VkImage image; |
| VkDeviceMemory mem; |
| VkMemoryRequirements mem_reqs; |
| const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM; |
| const int32_t tex_width = 32; |
| const int32_t tex_height = 32; |
| |
| VkImageCreateInfo image_create_info = LvlInitStruct<VkImageCreateInfo>(); |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = tex_format; |
| image_create_info.extent.width = tex_width; |
| image_create_info.extent.height = tex_height; |
| image_create_info.extent.depth = 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; |
| |
| VkMemoryAllocateInfo mem_alloc = LvlInitStruct<VkMemoryAllocateInfo>(); |
| mem_alloc.allocationSize = 0; |
| mem_alloc.memoryTypeIndex = 0; |
| |
| err = vk::CreateImage(m_device->device(), &image_create_info, nullptr, &image); |
| ASSERT_VK_SUCCESS(err); |
| |
| vk::GetImageMemoryRequirements(m_device->device(), image, &mem_reqs); |
| mem_alloc.allocationSize = mem_reqs.size; |
| |
| // Introduce Failure, select invalid TypeIndex |
| VkPhysicalDeviceMemoryProperties memory_info; |
| |
| vk::GetPhysicalDeviceMemoryProperties(gpu(), &memory_info); |
| uint32_t i = 0; |
| for (; i < memory_info.memoryTypeCount; i++) { |
| // Would require deviceCoherentMemory feature |
| if (memory_info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD) { |
| continue; |
| } |
| if ((mem_reqs.memoryTypeBits & (1 << i)) == 0) { |
| mem_alloc.memoryTypeIndex = i; |
| break; |
| } |
| } |
| if (i >= memory_info.memoryTypeCount) { |
| printf("%s No invalid memory type index could be found; skipped.\n", kSkipPrefix); |
| vk::DestroyImage(m_device->device(), image, nullptr); |
| return; |
| } |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "for this object type are not compatible with the memory"); |
| |
| err = vk::AllocateMemory(m_device->device(), &mem_alloc, nullptr, &mem); |
| ASSERT_VK_SUCCESS(err); |
| |
| err = vk::BindImageMemory(m_device->device(), image, mem, 0); |
| (void)err; |
| |
| m_errorMonitor->VerifyFound(); |
| |
| vk::DestroyImage(m_device->device(), image, nullptr); |
| vk::FreeMemory(m_device->device(), mem, nullptr); |
| } |
| |
| TEST_F(VkLayerTest, BindInvalidMemory) { |
| VkResult err; |
| bool pass; |
| |
| ASSERT_NO_FATAL_FAILURE(Init()); |
| |
| const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; |
| const int32_t tex_width = 256; |
| const int32_t tex_height = 256; |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = tex_format; |
| image_create_info.extent.width = tex_width; |
| image_create_info.extent.height = tex_height; |
| image_create_info.extent.depth = 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; |
| |
| VkBufferCreateInfo buffer_create_info = {}; |
| buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buffer_create_info.pNext = NULL; |
| buffer_create_info.flags = 0; |
| buffer_create_info.size = 4 * 1024 * 1024; |
| buffer_create_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| |
| // Create an image/buffer, allocate memory, free it, and then try to bind it |
| { |
| VkImage image = VK_NULL_HANDLE; |
| VkBuffer buffer = VK_NULL_HANDLE; |
| err = vk::CreateImage(device(), &image_create_info, NULL, &image); |
| ASSERT_VK_SUCCESS(err); |
| err = vk::CreateBuffer(device(), &buffer_create_info, NULL, &buffer); |
| ASSERT_VK_SUCCESS(err); |
| VkMemoryRequirements image_mem_reqs = {}, buffer_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| vk::GetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs); |
| |
| VkMemoryAllocateInfo image_mem_alloc = {}, buffer_mem_alloc = {}; |
| image_mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| image_mem_alloc.allocationSize = image_mem_reqs.size; |
| pass = m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_mem_alloc, 0); |
| ASSERT_TRUE(pass); |
| buffer_mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| buffer_mem_alloc.allocationSize = buffer_mem_reqs.size; |
| pass = m_device->phy().set_memory_type(buffer_mem_reqs.memoryTypeBits, &buffer_mem_alloc, 0); |
| ASSERT_TRUE(pass); |
| |
| VkDeviceMemory image_mem = VK_NULL_HANDLE, buffer_mem = VK_NULL_HANDLE; |
| err = vk::AllocateMemory(device(), &image_mem_alloc, NULL, &image_mem); |
| ASSERT_VK_SUCCESS(err); |
| err = vk::AllocateMemory(device(), &buffer_mem_alloc, NULL, &buffer_mem); |
| ASSERT_VK_SUCCESS(err); |
| |
| vk::FreeMemory(device(), image_mem, NULL); |
| vk::FreeMemory(device(), buffer_mem, NULL); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-memory-parameter"); |
| err = vk::BindImageMemory(device(), image, image_mem, 0); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memory-parameter"); |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, 0); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| |
| vk::DestroyImage(m_device->device(), image, NULL); |
| vk::DestroyBuffer(m_device->device(), buffer, NULL); |
| } |
| |
| // Try to bind memory to an object that already has a memory binding |
| { |
| VkImage image = VK_NULL_HANDLE; |
| err = vk::CreateImage(device(), &image_create_info, NULL, &image); |
| ASSERT_VK_SUCCESS(err); |
| VkBuffer buffer = VK_NULL_HANDLE; |
| err = vk::CreateBuffer(device(), &buffer_create_info, NULL, &buffer); |
| ASSERT_VK_SUCCESS(err); |
| VkMemoryRequirements image_mem_reqs = {}, buffer_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| vk::GetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}, buffer_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| image_alloc_info.allocationSize = image_mem_reqs.size; |
| buffer_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| buffer_alloc_info.allocationSize = buffer_mem_reqs.size; |
| pass = m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0); |
| ASSERT_TRUE(pass); |
| pass = m_device->phy().set_memory_type(buffer_mem_reqs.memoryTypeBits, &buffer_alloc_info, 0); |
| ASSERT_TRUE(pass); |
| VkDeviceMemory image_mem, buffer_mem; |
| err = vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem); |
| ASSERT_VK_SUCCESS(err); |
| err = vk::AllocateMemory(device(), &buffer_alloc_info, NULL, &buffer_mem); |
| ASSERT_VK_SUCCESS(err); |
| |
| err = vk::BindImageMemory(device(), image, image_mem, 0); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-image-01044"); |
| err = vk::BindImageMemory(device(), image, image_mem, 0); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, 0); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-buffer-01029"); |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, 0); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), image_mem, NULL); |
| vk::FreeMemory(device(), buffer_mem, NULL); |
| vk::DestroyImage(device(), image, NULL); |
| vk::DestroyBuffer(device(), buffer, NULL); |
| } |
| |
| // Try to bind memory to an object with an invalid memoryOffset |
| { |
| VkImage image = VK_NULL_HANDLE; |
| err = vk::CreateImage(device(), &image_create_info, NULL, &image); |
| ASSERT_VK_SUCCESS(err); |
| VkBuffer buffer = VK_NULL_HANDLE; |
| err = vk::CreateBuffer(device(), &buffer_create_info, NULL, &buffer); |
| ASSERT_VK_SUCCESS(err); |
| VkMemoryRequirements image_mem_reqs = {}, buffer_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| vk::GetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}, buffer_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| // Leave some extra space for alignment wiggle room |
| image_alloc_info.allocationSize = image_mem_reqs.size + image_mem_reqs.alignment; |
| buffer_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| buffer_alloc_info.allocationSize = buffer_mem_reqs.size + buffer_mem_reqs.alignment; |
| pass = m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0); |
| ASSERT_TRUE(pass); |
| pass = m_device->phy().set_memory_type(buffer_mem_reqs.memoryTypeBits, &buffer_alloc_info, 0); |
| ASSERT_TRUE(pass); |
| VkDeviceMemory image_mem, buffer_mem; |
| err = vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem); |
| ASSERT_VK_SUCCESS(err); |
| err = vk::AllocateMemory(device(), &buffer_alloc_info, NULL, &buffer_mem); |
| ASSERT_VK_SUCCESS(err); |
| |
| // Test unaligned memory offset |
| { |
| if (image_mem_reqs.alignment > 1) { |
| VkDeviceSize image_offset = 1; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-memoryOffset-01048"); |
| err = vk::BindImageMemory(device(), image, image_mem, image_offset); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| if (buffer_mem_reqs.alignment > 1) { |
| VkDeviceSize buffer_offset = 1; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memoryOffset-01036"); |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, buffer_offset); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| // Test memory offsets outside the memory allocation |
| { |
| VkDeviceSize image_offset = |
| (image_alloc_info.allocationSize + image_mem_reqs.alignment) & ~(image_mem_reqs.alignment - 1); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-memoryOffset-01046"); |
| err = vk::BindImageMemory(device(), image, image_mem, image_offset); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| |
| VkDeviceSize buffer_offset = |
| (buffer_alloc_info.allocationSize + buffer_mem_reqs.alignment) & ~(buffer_mem_reqs.alignment - 1); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memoryOffset-01031"); |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, buffer_offset); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| // Test memory offsets within the memory allocation, but which leave too little memory for |
| // the resource. |
| { |
| 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))) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-size-01049"); |
| err = vk::BindImageMemory(device(), image, image_mem, image_offset); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| VkDeviceSize buffer_offset = (buffer_mem_reqs.size - 1) & ~(buffer_mem_reqs.alignment - 1); |
| if (buffer_offset > 0) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-size-01037"); |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, buffer_offset); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| vk::FreeMemory(device(), image_mem, NULL); |
| vk::FreeMemory(device(), buffer_mem, NULL); |
| vk::DestroyImage(device(), image, NULL); |
| vk::DestroyBuffer(device(), buffer, NULL); |
| } |
| |
| // Try to bind memory to an object with an invalid memory type |
| { |
| VkImage image = VK_NULL_HANDLE; |
| err = vk::CreateImage(device(), &image_create_info, NULL, &image); |
| ASSERT_VK_SUCCESS(err); |
| VkBuffer buffer = VK_NULL_HANDLE; |
| err = vk::CreateBuffer(device(), &buffer_create_info, NULL, &buffer); |
| ASSERT_VK_SUCCESS(err); |
| VkMemoryRequirements image_mem_reqs = {}, buffer_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| vk::GetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}, buffer_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| image_alloc_info.allocationSize = image_mem_reqs.size; |
| buffer_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| buffer_alloc_info.allocationSize = buffer_mem_reqs.size; |
| // 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->phy().handle(), &memory_properties); |
| VkDeviceMemory image_mem, buffer_mem; |
| |
| uint32_t image_unsupported_mem_type_bits = ((1 << memory_properties.memoryTypeCount) - 1) & ~image_mem_reqs.memoryTypeBits; |
| if (image_unsupported_mem_type_bits != 0) { |
| pass = m_device->phy().set_memory_type(image_unsupported_mem_type_bits, &image_alloc_info, 0); |
| ASSERT_TRUE(pass); |
| err = vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-memory-01047"); |
| err = vk::BindImageMemory(device(), image, image_mem, 0); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(device(), image_mem, NULL); |
| } |
| |
| uint32_t buffer_unsupported_mem_type_bits = |
| ((1 << memory_properties.memoryTypeCount) - 1) & ~buffer_mem_reqs.memoryTypeBits; |
| if (buffer_unsupported_mem_type_bits != 0) { |
| pass = m_device->phy().set_memory_type(buffer_unsupported_mem_type_bits, &buffer_alloc_info, 0); |
| ASSERT_TRUE(pass); |
| err = vk::AllocateMemory(device(), &buffer_alloc_info, NULL, &buffer_mem); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memory-01035"); |
| err = vk::BindBufferMemory(device(), buffer, buffer_mem, 0); |
| (void)err; // This may very well return an error. |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(device(), buffer_mem, NULL); |
| } |
| |
| vk::DestroyImage(device(), image, NULL); |
| vk::DestroyBuffer(device(), buffer, NULL); |
| } |
| |
| // Try to bind memory to an image created with sparse memory flags |
| { |
| VkImageCreateInfo sparse_image_create_info = image_create_info; |
| sparse_image_create_info.flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| VkImageFormatProperties image_format_properties = {}; |
| err = vk::GetPhysicalDeviceImageFormatProperties(m_device->phy().handle(), sparse_image_create_info.format, |
| sparse_image_create_info.imageType, sparse_image_create_info.tiling, |
| sparse_image_create_info.usage, sparse_image_create_info.flags, |
| &image_format_properties); |
| if (!m_device->phy().features().sparseResidencyImage2D || err == VK_ERROR_FORMAT_NOT_SUPPORTED) { |
| // most likely means sparse formats aren't supported here; skip this test. |
| } else { |
| ASSERT_VK_SUCCESS(err); |
| if (image_format_properties.maxExtent.width == 0) { |
| printf("%s Sparse image format not supported; skipped.\n", kSkipPrefix); |
| return; |
| } else { |
| VkImage sparse_image = VK_NULL_HANDLE; |
| err = vk::CreateImage(m_device->device(), &sparse_image_create_info, NULL, &sparse_image); |
| ASSERT_VK_SUCCESS(err); |
| VkMemoryRequirements sparse_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(m_device->device(), sparse_image, &sparse_mem_reqs); |
| if (sparse_mem_reqs.memoryTypeBits != 0) { |
| VkMemoryAllocateInfo sparse_mem_alloc = {}; |
| sparse_mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| sparse_mem_alloc.pNext = NULL; |
| sparse_mem_alloc.allocationSize = sparse_mem_reqs.size; |
| sparse_mem_alloc.memoryTypeIndex = 0; |
| pass = m_device->phy().set_memory_type(sparse_mem_reqs.memoryTypeBits, &sparse_mem_alloc, 0); |
| ASSERT_TRUE(pass); |
| VkDeviceMemory sparse_mem = VK_NULL_HANDLE; |
| err = vk::AllocateMemory(m_device->device(), &sparse_mem_alloc, NULL, &sparse_mem); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-image-01045"); |
| err = vk::BindImageMemory(m_device->device(), sparse_image, sparse_mem, 0); |
| // This may very well return an error. |
| (void)err; |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(m_device->device(), sparse_mem, NULL); |
| } |
| vk::DestroyImage(m_device->device(), sparse_image, NULL); |
| } |
| } |
| } |
| |
| // Try to bind memory to a buffer created with sparse memory flags |
| { |
| VkBufferCreateInfo sparse_buffer_create_info = buffer_create_info; |
| sparse_buffer_create_info.flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT; |
| if (!m_device->phy().features().sparseResidencyBuffer) { |
| // most likely means sparse formats aren't supported here; skip this test. |
| } else { |
| VkBuffer sparse_buffer = VK_NULL_HANDLE; |
| err = vk::CreateBuffer(m_device->device(), &sparse_buffer_create_info, NULL, &sparse_buffer); |
| ASSERT_VK_SUCCESS(err); |
| VkMemoryRequirements sparse_mem_reqs = {}; |
| vk::GetBufferMemoryRequirements(m_device->device(), sparse_buffer, &sparse_mem_reqs); |
| if (sparse_mem_reqs.memoryTypeBits != 0) { |
| VkMemoryAllocateInfo sparse_mem_alloc = {}; |
| sparse_mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| sparse_mem_alloc.pNext = NULL; |
| sparse_mem_alloc.allocationSize = sparse_mem_reqs.size; |
| sparse_mem_alloc.memoryTypeIndex = 0; |
| pass = m_device->phy().set_memory_type(sparse_mem_reqs.memoryTypeBits, &sparse_mem_alloc, 0); |
| ASSERT_TRUE(pass); |
| VkDeviceMemory sparse_mem = VK_NULL_HANDLE; |
| err = vk::AllocateMemory(m_device->device(), &sparse_mem_alloc, NULL, &sparse_mem); |
| ASSERT_VK_SUCCESS(err); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-buffer-01030"); |
| err = vk::BindBufferMemory(m_device->device(), sparse_buffer, sparse_mem, 0); |
| // This may very well return an error. |
| (void)err; |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(m_device->device(), sparse_mem, NULL); |
| } |
| vk::DestroyBuffer(m_device->device(), sparse_buffer, NULL); |
| } |
| } |
| } |
| |
| TEST_F(VkLayerTest, BindInvalidMemoryYcbcr) { |
| // Enable KHR YCbCr req'd extensions for Disjoint Bit |
| if (!AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME)) { |
| printf("%s test requires KHR multiplane extensions, not available. Skipping.\n", kSkipPrefix); |
| return; |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| |
| if (!AreRequestedExtensionsEnabled()) { |
| printf("%s test requires KHR multiplane extensions, not available. Skipping.\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Create aliased function pointers for 1.0 and 1.1 contexts |
| PFN_vkBindImageMemory2KHR vkBindImageMemory2Function = nullptr; |
| PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2Function = nullptr; |
| if (DeviceValidationVersion() >= VK_API_VERSION_1_1) { |
| vkBindImageMemory2Function = vk::BindImageMemory2; |
| vkGetImageMemoryRequirements2Function = vk::GetImageMemoryRequirements2; |
| } else { |
| vkBindImageMemory2Function = (PFN_vkBindImageMemory2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkBindImageMemory2KHR"); |
| vkGetImageMemoryRequirements2Function = |
| (PFN_vkGetImageMemoryRequirements2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkGetImageMemoryRequirements2KHR"); |
| } |
| |
| // 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->phy().handle(), 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)) { |
| printf("%s test requires disjoint and sampled feature bit on format. Skipping.\n", kSkipPrefix); |
| } else { |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = mp_format; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 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; |
| |
| VkImage image; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &image)); |
| |
| VkImagePlaneMemoryRequirementsInfo image_plane_req = {VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO}; |
| image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = &image_plane_req; |
| mem_req_info2.image = image; |
| VkMemoryRequirements2 mem_req2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mem_req2); |
| |
| // Find a valid memory type index to memory to be allocated from |
| VkMemoryAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; |
| alloc_info.allocationSize = mem_req2.memoryRequirements.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(mem_req2.memoryRequirements.memoryTypeBits, &alloc_info, 0)); |
| |
| VkDeviceMemory image_memory; |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &alloc_info, NULL, &image_memory)); |
| |
| // Bind disjoint with BindImageMemory instead of BindImageMemory2 |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-image-01608"); |
| vk::BindImageMemory(device(), image, image_memory, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| VkBindImagePlaneMemoryInfo plane_memory_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO}; |
| ASSERT_TRUE(FormatPlaneCount(mp_format) == 2); |
| plane_memory_info.planeAspect = VK_IMAGE_ASPECT_PLANE_2_BIT; |
| |
| VkBindImageMemoryInfo bind_image_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO}; |
| bind_image_info.pNext = &plane_memory_info; |
| bind_image_info.image = image; |
| bind_image_info.memory = image_memory; |
| bind_image_info.memoryOffset = 0; |
| |
| // Set invalid planeAspect |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImagePlaneMemoryInfo-planeAspect-02283"); |
| // Error is thrown from not having both planes bound |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory2-pBindInfos-02858"); |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "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"); |
| vkBindImageMemory2Function(device(), 1, &bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), image_memory, NULL); |
| vk::DestroyImage(device(), image, nullptr); |
| } |
| |
| // 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)) { |
| printf("%s test requires sampled feature bit on multi-planar format. Skipping.\n", kSkipPrefix); |
| } else { |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = mp_format; |
| image_create_info.extent.width = 64; |
| image_create_info.extent.height = 64; |
| image_create_info.extent.depth = 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 |
| |
| VkImage image; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &image)); |
| |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = NULL; |
| mem_req_info2.image = image; |
| VkMemoryRequirements2 mem_req2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mem_req2); |
| |
| // Find a valid memory type index to memory to be allocated from |
| VkMemoryAllocateInfo alloc_info = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; |
| alloc_info.allocationSize = mem_req2.memoryRequirements.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(mem_req2.memoryRequirements.memoryTypeBits, &alloc_info, 0)); |
| |
| VkDeviceMemory image_memory; |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &alloc_info, NULL, &image_memory)); |
| |
| VkBindImagePlaneMemoryInfo plane_memory_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO}; |
| plane_memory_info.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| VkBindImageMemoryInfo bind_image_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO}; |
| bind_image_info.pNext = &plane_memory_info; |
| bind_image_info.image = image; |
| bind_image_info.memory = image_memory; |
| bind_image_info.memoryOffset = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01618"); |
| vkBindImageMemory2Function(device(), 1, &bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), image_memory, NULL); |
| vk::DestroyImage(device(), image, nullptr); |
| } |
| } |
| |
| TEST_F(VkLayerTest, BindInvalidMemory2Disjoint) { |
| TEST_DESCRIPTION("These tests deal with VK_KHR_bind_memory_2 and disjoint memory being bound"); |
| |
| // Enable KHR YCbCr req'd extensions for Disjoint Bit |
| AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| |
| const bool mp_extensions = CanEnableDeviceExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| const bool bind_memory_2_extension = CanEnableDeviceExtension(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| |
| if (!bind_memory_2_extension) { |
| printf("%s test requires VK_KHR_bind_memory2 extensions, not available. Skipping.\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Create aliased function pointers for 1.0 and 1.1 contexts |
| PFN_vkBindImageMemory2KHR vkBindImageMemory2Function = nullptr; |
| PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2Function = nullptr; |
| |
| if (bind_memory_2_extension) { |
| if (DeviceValidationVersion() >= VK_API_VERSION_1_1) { |
| vkBindImageMemory2Function = vk::BindImageMemory2; |
| } else { |
| vkBindImageMemory2Function = |
| (PFN_vkBindImageMemory2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkBindImageMemory2KHR"); |
| } |
| } |
| |
| if (mp_extensions) { |
| if (DeviceValidationVersion() >= VK_API_VERSION_1_1) { |
| vkGetImageMemoryRequirements2Function = vk::GetImageMemoryRequirements2; |
| } else { |
| vkGetImageMemoryRequirements2Function = |
| (PFN_vkGetImageMemoryRequirements2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkGetImageMemoryRequirements2KHR"); |
| } |
| } |
| |
| const VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM; |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = tex_format; |
| image_create_info.extent.width = 256; |
| image_create_info.extent.height = 256; |
| image_create_info.extent.depth = 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; |
| if (mp_extensions == true) { |
| VkFormatProperties mp_format_properties; |
| vk::GetPhysicalDeviceFormatProperties(m_device->phy().handle(), 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 |
| |
| VkImage image = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &image)); |
| VkMemoryRequirements image_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| // Leave some extra space for alignment wiggle room |
| image_alloc_info.allocationSize = image_mem_reqs.size + image_mem_reqs.alignment; |
| ASSERT_TRUE(m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0)); |
| VkDeviceMemory image_mem; |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem)); |
| |
| // Keep values outside scope so multiple tests cases can reuse |
| VkImage mp_image = VK_NULL_HANDLE; |
| VkDeviceMemory mp_image_mem[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; |
| VkMemoryRequirements2 mp_image_mem_reqs2[2]; |
| VkMemoryAllocateInfo mp_image_alloc_info[2]; |
| if (mp_disjoint_support == true) { |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &mp_image_create_info, NULL, &mp_image)); |
| |
| VkImagePlaneMemoryRequirementsInfo image_plane_req = {VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO}; |
| image_plane_req.pNext = nullptr; |
| image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = (void *)&image_plane_req; |
| mem_req_info2.image = mp_image; |
| mp_image_mem_reqs2[0].sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; |
| mp_image_mem_reqs2[0].pNext = nullptr; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mp_image_mem_reqs2[0]); |
| |
| image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT; |
| mp_image_mem_reqs2[1].sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; |
| mp_image_mem_reqs2[1].pNext = nullptr; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mp_image_mem_reqs2[1]); |
| |
| mp_image_alloc_info[0].sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mp_image_alloc_info[0].pNext = nullptr; |
| mp_image_alloc_info[1].sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mp_image_alloc_info[1].pNext = nullptr; |
| // 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; |
| ASSERT_TRUE( |
| m_device->phy().set_memory_type(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; |
| ASSERT_TRUE( |
| m_device->phy().set_memory_type(mp_image_mem_reqs2[1].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[1], 0)); |
| |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[0], NULL, &mp_image_mem[0])); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[1], NULL, &mp_image_mem[1])); |
| } |
| |
| // All planes must be bound at once the same here |
| VkBindImagePlaneMemoryInfo plane_memory_info[2]; |
| plane_memory_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; |
| plane_memory_info[0].pNext = nullptr; |
| plane_memory_info[0].planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| plane_memory_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; |
| plane_memory_info[1].pNext = nullptr; |
| plane_memory_info[1].planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT; |
| |
| // Test unaligned memory offset |
| |
| // single-plane image |
| if (bind_memory_2_extension == true) { |
| VkBindImageMemoryInfo bind_image_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO}; |
| bind_image_info.pNext = nullptr; |
| 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 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = nullptr; |
| mem_req_info2.image = image; |
| VkMemoryRequirements2 mem_req2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, nullptr}; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mem_req2); |
| |
| if (mem_req2.memoryRequirements.alignment > 1) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01616"); |
| vkBindImageMemory2Function(device(), 1, &bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| } else { |
| // Same as 01048 but with bindImageMemory2 call |
| if (image_mem_reqs.alignment > 1) { |
| const char *vuid = |
| (mp_extensions) ? "VUID-VkBindImageMemoryInfo-pNext-01616" : "VUID-VkBindImageMemoryInfo-memoryOffset-01613"; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, vuid); |
| vkBindImageMemory2Function(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_info[2]; |
| bind_image_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[0].pNext = (void *)&plane_memory_info[0]; |
| bind_image_info[0].image = mp_image; |
| bind_image_info[0].memory = mp_image_mem[0]; |
| bind_image_info[0].memoryOffset = 1; // off alignment |
| bind_image_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[1].pNext = (void *)&plane_memory_info[1]; |
| bind_image_info[1].image = mp_image; |
| bind_image_info[1].memory = mp_image_mem[1]; |
| bind_image_info[1].memoryOffset = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01620"); |
| vkBindImageMemory2Function(device(), 2, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| // Test memory offsets within the memory allocation, but which leave too little memory for |
| // the resource. |
| // single-plane image |
| if (bind_memory_2_extension == true) { |
| VkBindImageMemoryInfo bind_image_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO}; |
| bind_image_info.pNext = nullptr; |
| bind_image_info.image = image; |
| bind_image_info.memory = image_mem; |
| |
| if (mp_disjoint_support == true) { |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = nullptr; |
| mem_req_info2.image = image; |
| VkMemoryRequirements2 mem_req2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, nullptr}; |
| vkGetImageMemoryRequirements2Function(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->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01617"); |
| vkBindImageMemory2Function(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; |
| const char *vuid = |
| (mp_extensions) ? "VUID-VkBindImageMemoryInfo-pNext-01617" : "VUID-VkBindImageMemoryInfo-memory-01614"; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, vuid); |
| vkBindImageMemory2Function(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_info[2]; |
| bind_image_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[0].pNext = (void *)&plane_memory_info[0]; |
| bind_image_info[0].image = mp_image; |
| bind_image_info[0].memory = mp_image_mem[0]; |
| bind_image_info[0].memoryOffset = mp_image_offset; // mis-offset |
| bind_image_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[1].pNext = (void *)&plane_memory_info[1]; |
| bind_image_info[1].image = mp_image; |
| bind_image_info[1].memory = mp_image_mem[1]; |
| bind_image_info[1].memoryOffset = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01621"); |
| vkBindImageMemory2Function(device(), 2, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| } |
| |
| // Free Memory to reset |
| vk::FreeMemory(device(), image_mem, NULL); |
| if (mp_disjoint_support == true) { |
| // only reset plane 0 |
| vk::FreeMemory(device(), mp_image_mem[0], NULL); |
| } |
| |
| // 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->phy().handle(), &memory_properties); |
| |
| // single-plane image |
| if (bind_memory_2_extension == true) { |
| VkBindImageMemoryInfo bind_image_info = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO}; |
| bind_image_info.pNext = nullptr; |
| bind_image_info.image = image; |
| bind_image_info.memoryOffset = 0; |
| |
| if (mp_disjoint_support == true) { |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = nullptr; |
| mem_req_info2.image = image; |
| VkMemoryRequirements2 mem_req2 = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, nullptr}; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mem_req2); |
| |
| uint32_t image2_unsupported_mem_type_bits = |
| ((1 << memory_properties.memoryTypeCount) - 1) & ~mem_req2.memoryRequirements.memoryTypeBits; |
| if (image2_unsupported_mem_type_bits != 0) { |
| ASSERT_TRUE(m_device->phy().set_memory_type(image2_unsupported_mem_type_bits, &image_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem)); |
| bind_image_info.memory = image_mem; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01615"); |
| vkBindImageMemory2Function(device(), 1, &bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(device(), image_mem, NULL); |
| } |
| } else { |
| // Same as 01047 but with bindImageMemory2 call |
| uint32_t image_unsupported_mem_type_bits = |
| ((1 << memory_properties.memoryTypeCount) - 1) & ~image_mem_reqs.memoryTypeBits; |
| if (image_unsupported_mem_type_bits != 0) { |
| ASSERT_TRUE(m_device->phy().set_memory_type(image_unsupported_mem_type_bits, &image_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem)); |
| bind_image_info.memory = image_mem; |
| const char *vuid = |
| (mp_extensions) ? "VUID-VkBindImageMemoryInfo-pNext-01615" : "VUID-VkBindImageMemoryInfo-memory-01612"; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, vuid); |
| vkBindImageMemory2Function(device(), 1, &bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(device(), image_mem, NULL); |
| } |
| } |
| } |
| |
| // Multi-plane image |
| if (mp_disjoint_support == true) { |
| // Get plane 0 memory requirements |
| VkImagePlaneMemoryRequirementsInfo image_plane_req = {VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO}; |
| image_plane_req.pNext = nullptr; |
| image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = (void *)&image_plane_req; |
| mem_req_info2.image = mp_image; |
| vkGetImageMemoryRequirements2Function(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; |
| if (mp_image_unsupported_mem_type_bits != 0) { |
| mp_image_alloc_info[0].allocationSize = mp_image_mem_reqs2[0].memoryRequirements.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(mp_image_unsupported_mem_type_bits, &mp_image_alloc_info[0], 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[0], NULL, &mp_image_mem[0])); |
| |
| VkBindImageMemoryInfo bind_image_info[2]; |
| bind_image_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[0].pNext = (void *)&plane_memory_info[0]; |
| bind_image_info[0].image = mp_image; |
| bind_image_info[0].memory = mp_image_mem[0]; |
| bind_image_info[0].memoryOffset = 0; |
| bind_image_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[1].pNext = (void *)&plane_memory_info[1]; |
| bind_image_info[1].image = mp_image; |
| bind_image_info[1].memory = mp_image_mem[1]; |
| bind_image_info[1].memoryOffset = 0; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01619"); |
| vkBindImageMemory2Function(device(), 2, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| vk::FreeMemory(device(), mp_image_mem[0], NULL); |
| } |
| } |
| |
| vk::DestroyImage(device(), image, NULL); |
| if (mp_disjoint_support == true) { |
| vk::FreeMemory(device(), mp_image_mem[1], NULL); |
| vk::DestroyImage(device(), mp_image, NULL); |
| } |
| } |
| |
| TEST_F(VkLayerTest, BindInvalidMemoryNoCheck) { |
| TEST_DESCRIPTION("Tests case were no call to memory requirements was made prior to binding"); |
| |
| // Enable KHR YCbCr req'd extensions for Disjoint Bit |
| AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| const bool mp_extensions = CanEnableDeviceExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // first test buffer |
| { |
| VkBufferCreateInfo buffer_create_info = {}; |
| buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
| buffer_create_info.pNext = NULL; |
| buffer_create_info.flags = 0; |
| buffer_create_info.size = 1024; |
| buffer_create_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
| |
| // Create 2 buffers, one that is checked and one that isn't by GetBufferMemoryRequirements |
| VkBuffer buffer = VK_NULL_HANDLE; |
| VkBuffer unchecked_buffer = VK_NULL_HANDLE; |
| VkDeviceMemory buffer_mem = VK_NULL_HANDLE; |
| VkDeviceMemory unchecked_buffer_mem = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vk::CreateBuffer(device(), &buffer_create_info, NULL, &buffer)); |
| ASSERT_VK_SUCCESS(vk::CreateBuffer(device(), &buffer_create_info, NULL, &unchecked_buffer)); |
| |
| VkMemoryRequirements buffer_mem_reqs = {}; |
| vk::GetBufferMemoryRequirements(device(), buffer, &buffer_mem_reqs); |
| VkMemoryAllocateInfo buffer_alloc_info = {}; |
| buffer_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| // Leave some extra space for alignment wiggle room |
| buffer_alloc_info.allocationSize = buffer_mem_reqs.size + buffer_mem_reqs.alignment; |
| ASSERT_TRUE(m_device->phy().set_memory_type(buffer_mem_reqs.memoryTypeBits, &buffer_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &buffer_alloc_info, NULL, &buffer_mem)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &buffer_alloc_info, NULL, &unchecked_buffer_mem)); |
| |
| if (buffer_mem_reqs.alignment > 1) { |
| VkDeviceSize buffer_offset = 1; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memoryOffset-01036"); |
| vk::BindBufferMemory(device(), buffer, buffer_mem, buffer_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| // Should trigger same VUID even when image was never checked |
| // this makes an assumption that the driver will return the same image requirements for same createImageInfo where even |
| // being close to running out of heap space |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindBufferMemory-memoryOffset-01036"); |
| vk::BindBufferMemory(device(), unchecked_buffer, unchecked_buffer_mem, buffer_offset); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| vk::DestroyBuffer(device(), buffer, NULL); |
| vk::DestroyBuffer(device(), unchecked_buffer, NULL); |
| vk::FreeMemory(device(), buffer_mem, NULL); |
| vk::FreeMemory(device(), unchecked_buffer_mem, NULL); |
| } |
| |
| // Next test is a single-plane image |
| { |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 256; |
| image_create_info.extent.height = 256; |
| image_create_info.extent.depth = 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; |
| |
| // Create 2 images, one that is checked and one that isn't by GetImageMemoryRequirements |
| VkImage image = VK_NULL_HANDLE; |
| VkImage unchecked_image = VK_NULL_HANDLE; |
| VkDeviceMemory image_mem = VK_NULL_HANDLE; |
| VkDeviceMemory unchecked_image_mem = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &image)); |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &unchecked_image)); |
| |
| VkMemoryRequirements image_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image, &image_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| // Leave some extra space for alignment wiggle room |
| image_alloc_info.allocationSize = image_mem_reqs.size + image_mem_reqs.alignment; |
| ASSERT_TRUE(m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_mem)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &unchecked_image_mem)); |
| |
| // single-plane image |
| if (image_mem_reqs.alignment > 1) { |
| VkDeviceSize image_offset = 1; |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-memoryOffset-01048"); |
| vk::BindImageMemory(device(), image, image_mem, image_offset); |
| m_errorMonitor->VerifyFound(); |
| |
| // Should trigger same VUID even when image was never checked |
| // this makes an assumption that the driver will return the same image requirements for same createImageInfo where even |
| // being close to running out of heap space |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory-memoryOffset-01048"); |
| vk::BindImageMemory(device(), unchecked_image, unchecked_image_mem, image_offset); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| vk::DestroyImage(device(), image, NULL); |
| vk::DestroyImage(device(), unchecked_image, NULL); |
| vk::FreeMemory(device(), image_mem, NULL); |
| vk::FreeMemory(device(), unchecked_image_mem, NULL); |
| } |
| |
| // Same style test but with a multi-planar disjoint image |
| // Test doesn't check either of the planes for the unchecked image |
| if (mp_extensions == false) { |
| printf("%s Rest of test rely on YCbCr Multi-planar support.\n", kSkipPrefix); |
| return; |
| } else { |
| // Check for support of format used by all multi-planar tests |
| const VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| VkFormatProperties mp_format_properties; |
| vk::GetPhysicalDeviceFormatProperties(m_device->phy().handle(), 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))) { |
| printf("%s Rest of test rely on a supported disjoint format.\n", kSkipPrefix); |
| return; |
| } |
| |
| VkImageCreateInfo mp_image_create_info = {}; |
| mp_image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| mp_image_create_info.pNext = NULL; |
| mp_image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| mp_image_create_info.format = mp_format; |
| mp_image_create_info.extent.width = 256; |
| mp_image_create_info.extent.height = 256; |
| mp_image_create_info.extent.depth = 1; |
| mp_image_create_info.mipLevels = 1; |
| mp_image_create_info.arrayLayers = 1; |
| mp_image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; |
| mp_image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; |
| mp_image_create_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
| mp_image_create_info.flags = VK_IMAGE_CREATE_DISJOINT_BIT; |
| |
| // Create aliased function pointers for 1.0 and 1.1 contexts |
| PFN_vkBindImageMemory2KHR vkBindImageMemory2Function = nullptr; |
| PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2Function = nullptr; |
| |
| if (DeviceValidationVersion() >= VK_API_VERSION_1_1) { |
| vkBindImageMemory2Function = vk::BindImageMemory2; |
| vkGetImageMemoryRequirements2Function = vk::GetImageMemoryRequirements2; |
| } else { |
| vkGetImageMemoryRequirements2Function = |
| (PFN_vkGetImageMemoryRequirements2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkGetImageMemoryRequirements2KHR"); |
| vkBindImageMemory2Function = |
| (PFN_vkBindImageMemory2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkBindImageMemory2KHR"); |
| } |
| |
| VkImage mp_image = VK_NULL_HANDLE; |
| VkImage mp_unchecked_image = VK_NULL_HANDLE; |
| // Array represent planes for disjoint images |
| VkDeviceMemory mp_image_mem[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; |
| VkDeviceMemory mp_unchecked_image_mem[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; |
| VkMemoryRequirements2 mp_image_mem_reqs2[2]; |
| VkMemoryAllocateInfo mp_image_alloc_info[2]; |
| |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &mp_image_create_info, NULL, &mp_image)); |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &mp_image_create_info, NULL, &mp_unchecked_image)); |
| |
| VkImagePlaneMemoryRequirementsInfo image_plane_req = {VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO}; |
| image_plane_req.pNext = nullptr; |
| image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| |
| VkImageMemoryRequirementsInfo2 mem_req_info2 = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2}; |
| mem_req_info2.pNext = (void *)&image_plane_req; |
| mem_req_info2.image = mp_image; |
| mp_image_mem_reqs2[0].sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; |
| mp_image_mem_reqs2[0].pNext = nullptr; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mp_image_mem_reqs2[0]); |
| |
| image_plane_req.planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT; |
| mp_image_mem_reqs2[1].sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; |
| mp_image_mem_reqs2[1].pNext = nullptr; |
| vkGetImageMemoryRequirements2Function(device(), &mem_req_info2, &mp_image_mem_reqs2[1]); |
| |
| mp_image_alloc_info[0].sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mp_image_alloc_info[0].pNext = nullptr; |
| mp_image_alloc_info[1].sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| mp_image_alloc_info[1].pNext = nullptr; |
| |
| mp_image_alloc_info[0].allocationSize = mp_image_mem_reqs2[0].memoryRequirements.size; |
| ASSERT_TRUE( |
| m_device->phy().set_memory_type(mp_image_mem_reqs2[0].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[0], 0)); |
| // Leave some extra space for alignment wiggle room |
| mp_image_alloc_info[1].allocationSize = |
| mp_image_mem_reqs2[1].memoryRequirements.size + mp_image_mem_reqs2[1].memoryRequirements.alignment; |
| ASSERT_TRUE( |
| m_device->phy().set_memory_type(mp_image_mem_reqs2[1].memoryRequirements.memoryTypeBits, &mp_image_alloc_info[1], 0)); |
| |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[0], NULL, &mp_image_mem[0])); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[1], NULL, &mp_image_mem[1])); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[0], NULL, &mp_unchecked_image_mem[0])); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &mp_image_alloc_info[1], NULL, &mp_unchecked_image_mem[1])); |
| |
| // Sets an invalid offset to plane 1 |
| if (mp_image_mem_reqs2[1].memoryRequirements.alignment > 1) { |
| VkBindImagePlaneMemoryInfo plane_memory_info[2]; |
| plane_memory_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; |
| plane_memory_info[0].pNext = nullptr; |
| plane_memory_info[0].planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| plane_memory_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; |
| plane_memory_info[1].pNext = nullptr; |
| plane_memory_info[1].planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT; |
| |
| VkBindImageMemoryInfo bind_image_info[2]; |
| bind_image_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[0].pNext = (void *)&plane_memory_info[0]; |
| bind_image_info[0].image = mp_image; |
| bind_image_info[0].memory = mp_image_mem[0]; |
| bind_image_info[0].memoryOffset = 0; |
| bind_image_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[1].pNext = (void *)&plane_memory_info[1]; |
| bind_image_info[1].image = mp_image; |
| bind_image_info[1].memory = mp_image_mem[1]; |
| bind_image_info[1].memoryOffset = 1; // off alignment |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01620"); |
| vkBindImageMemory2Function(device(), 2, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // Should trigger same VUID even when image was never checked |
| // this makes an assumption that the driver will return the same image requirements for same createImageInfo where even |
| // being close to running out of heap space |
| bind_image_info[0].image = mp_unchecked_image; |
| bind_image_info[0].memory = mp_unchecked_image_mem[0]; |
| bind_image_info[1].image = mp_unchecked_image; |
| bind_image_info[1].memory = mp_unchecked_image_mem[1]; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkBindImageMemoryInfo-pNext-01620"); |
| vkBindImageMemory2Function(device(), 2, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| vk::DestroyImage(device(), mp_image, NULL); |
| vk::DestroyImage(device(), mp_unchecked_image, NULL); |
| vk::FreeMemory(device(), mp_image_mem[0], NULL); |
| vk::FreeMemory(device(), mp_image_mem[1], NULL); |
| vk::FreeMemory(device(), mp_unchecked_image_mem[0], NULL); |
| vk::FreeMemory(device(), mp_unchecked_image_mem[1], NULL); |
| } |
| } |
| |
| TEST_F(VkLayerTest, BindInvalidMemory2BindInfos) { |
| TEST_DESCRIPTION("These tests deal with VK_KHR_bind_memory_2 and invalid VkBindImageMemoryInfo* pBindInfos"); |
| |
| // Enable KHR YCbCr req'd extensions for Disjoint Bit |
| AddRequiredExtensions(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| ASSERT_NO_FATAL_FAILURE(InitFramework(m_errorMonitor)); |
| const bool mp_extensions = CanEnableDeviceExtension(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
| const bool bind_memory_2_extension = CanEnableDeviceExtension(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
| |
| if (!bind_memory_2_extension) { |
| printf("%s test requires VK_KHR_bind_memory2 extensions, not available. Skipping.\n", kSkipPrefix); |
| return; |
| } |
| ASSERT_NO_FATAL_FAILURE(InitState()); |
| |
| // Create aliased function pointers for 1.0 and 1.1 contexts |
| PFN_vkBindImageMemory2KHR vkBindImageMemory2Function = nullptr; |
| if (DeviceValidationVersion() >= VK_API_VERSION_1_1) { |
| vkBindImageMemory2Function = vk::BindImageMemory2; |
| } else { |
| vkBindImageMemory2Function = (PFN_vkBindImageMemory2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkBindImageMemory2KHR"); |
| } |
| |
| VkImageCreateInfo image_create_info = {}; |
| image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
| image_create_info.pNext = NULL; |
| image_create_info.imageType = VK_IMAGE_TYPE_2D; |
| image_create_info.format = VK_FORMAT_R8G8B8A8_UNORM; |
| image_create_info.extent.width = 256; |
| image_create_info.extent.height = 256; |
| image_create_info.extent.depth = 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; |
| |
| { |
| // Create 2 image with 2 memory objects |
| VkImage image_a = VK_NULL_HANDLE; |
| VkImage image_b = VK_NULL_HANDLE; |
| VkDeviceMemory image_a_mem = VK_NULL_HANDLE; |
| VkDeviceMemory image_b_mem = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &image_a)); |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &image_b)); |
| |
| VkMemoryRequirements image_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), image_a, &image_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| image_alloc_info.allocationSize = image_mem_reqs.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_a_mem)); |
| vk::GetImageMemoryRequirements(device(), image_b, &image_mem_reqs); |
| image_alloc_info.allocationSize = image_mem_reqs.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &image_b_mem)); |
| |
| // Try binding same image twice in array |
| VkBindImageMemoryInfo bind_image_info[3]; |
| bind_image_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[0].pNext = nullptr; |
| bind_image_info[0].image = image_a; |
| bind_image_info[0].memory = image_a_mem; |
| bind_image_info[0].memoryOffset = 0; |
| bind_image_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[1].pNext = nullptr; |
| bind_image_info[1].image = image_b; |
| bind_image_info[1].memory = image_b_mem; |
| bind_image_info[1].memoryOffset = 0; |
| bind_image_info[2] = bind_image_info[0]; // duplicate bind |
| |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory2-pBindInfos-04006"); |
| vkBindImageMemory2Function(device(), 3, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // Bind same image to 2 different memory in same array |
| bind_image_info[1].image = image_a; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory2-pBindInfos-04006"); |
| vkBindImageMemory2Function(device(), 2, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::FreeMemory(device(), image_a_mem, NULL); |
| vk::FreeMemory(device(), image_b_mem, NULL); |
| vk::DestroyImage(device(), image_a, NULL); |
| vk::DestroyImage(device(), image_b, NULL); |
| } |
| |
| if (mp_extensions) { |
| const VkFormat mp_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; |
| |
| // Check for support of format used by all multi-planar tests |
| VkFormatProperties mp_format_properties; |
| vk::GetPhysicalDeviceFormatProperties(m_device->phy().handle(), 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))) { |
| printf("%s test requires disjoint support extensions, not available. Skipping.\n", kSkipPrefix); |
| return; |
| } |
| |
| PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2Function = nullptr; |
| if (DeviceValidationVersion() >= VK_API_VERSION_1_1) { |
| vkGetImageMemoryRequirements2Function = vk::GetImageMemoryRequirements2; |
| } else { |
| vkGetImageMemoryRequirements2Function = |
| (PFN_vkGetImageMemoryRequirements2KHR)vk::GetDeviceProcAddr(m_device->handle(), "vkGetImageMemoryRequirements2KHR"); |
| } |
| |
| // Creat 1 normal, not disjoint image |
| VkImage normal_image = VK_NULL_HANDLE; |
| VkDeviceMemory normal_image_mem = VK_NULL_HANDLE; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &image_create_info, NULL, &normal_image)); |
| VkMemoryRequirements image_mem_reqs = {}; |
| vk::GetImageMemoryRequirements(device(), normal_image, &image_mem_reqs); |
| VkMemoryAllocateInfo image_alloc_info = {}; |
| image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; |
| image_alloc_info.allocationSize = image_mem_reqs.size; |
| ASSERT_TRUE(m_device->phy().set_memory_type(image_mem_reqs.memoryTypeBits, &image_alloc_info, 0)); |
| ASSERT_VK_SUCCESS(vk::AllocateMemory(device(), &image_alloc_info, NULL, &normal_image_mem)); |
| |
| // Create 2 disjoint images with memory backing each plane |
| 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; |
| |
| VkImage mp_image_a = VK_NULL_HANDLE; |
| VkImage mp_image_b = VK_NULL_HANDLE; |
| VkDeviceMemory mp_image_a_mem[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; |
| VkDeviceMemory mp_image_b_mem[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &mp_image_create_info, NULL, &mp_image_a)); |
| ASSERT_VK_SUCCESS(vk::CreateImage(device(), &mp_image_create_info, NULL, &mp_image_b)); |
| |
| AllocateDisjointMemory(m_device, vkGetImageMemoryRequirements2Function, mp_image_a, &mp_image_a_mem[0], |
| VK_IMAGE_ASPECT_PLANE_0_BIT); |
| AllocateDisjointMemory(m_device, vkGetImageMemoryRequirements2Function, mp_image_a, &mp_image_a_mem[1], |
| VK_IMAGE_ASPECT_PLANE_1_BIT); |
| AllocateDisjointMemory(m_device, vkGetImageMemoryRequirements2Function, mp_image_b, &mp_image_b_mem[0], |
| VK_IMAGE_ASPECT_PLANE_0_BIT); |
| AllocateDisjointMemory(m_device, vkGetImageMemoryRequirements2Function, mp_image_b, &mp_image_b_mem[1], |
| VK_IMAGE_ASPECT_PLANE_1_BIT); |
| |
| VkBindImagePlaneMemoryInfo plane_memory_info[2]; |
| plane_memory_info[0].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; |
| plane_memory_info[0].pNext = nullptr; |
| plane_memory_info[0].planeAspect = VK_IMAGE_ASPECT_PLANE_0_BIT; |
| plane_memory_info[1].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; |
| plane_memory_info[1].pNext = nullptr; |
| plane_memory_info[1].planeAspect = VK_IMAGE_ASPECT_PLANE_1_BIT; |
| |
| // set all sType and memoryOffset as they are the same |
| VkBindImageMemoryInfo bind_image_info[6]; |
| for (int i = 0; i < 6; i++) { |
| bind_image_info[i].sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO; |
| bind_image_info[i].memoryOffset = 0; |
| } |
| |
| // Try only binding part of image_b |
| bind_image_info[0].pNext = (void *)&plane_memory_info[0]; |
| bind_image_info[0].image = mp_image_a; |
| bind_image_info[0].memory = mp_image_a_mem[0]; |
| bind_image_info[1].pNext = (void *)&plane_memory_info[1]; |
| bind_image_info[1].image = mp_image_a; |
| bind_image_info[1].memory = mp_image_a_mem[1]; |
| bind_image_info[2].pNext = (void *)&plane_memory_info[0]; |
| bind_image_info[2].image = mp_image_b; |
| bind_image_info[2].memory = mp_image_b_mem[0]; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory2-pBindInfos-02858"); |
| vkBindImageMemory2Function(device(), 3, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // Same thing, but mix in a non-disjoint image |
| bind_image_info[3].pNext = nullptr; |
| bind_image_info[3].image = normal_image; |
| bind_image_info[3].memory = normal_image_mem; |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-vkBindImageMemory2-pBindInfos-02858"); |
| vkBindImageMemory2Function(device(), 4, bind_image_info); |
| m_errorMonitor->VerifyFound(); |
| |
| // Try binding image_b plane 1 twice |
| // Valid case where binding disjoint and non-disjoint |
| bind_image_info[4].pNext = (void *)&plane_memory_info[1 |