From 8ea5db3fc0fab7f60472dcd0db7e5e40571549cb Mon Sep 17 00:00:00 2001 From: Joe Withers Date: Wed, 15 Nov 2023 17:46:25 +0000 Subject: [PATCH] Fix for render_to_image exceeding maxResourceSize Fixes an issue seen in render_to_image tests, where image creation may fail due to exceeding the maxResourceSize for the corresponding VkImageFormatProperties. Affects: dEQP-VK.pipeline.*.render_to_image.*.huge.* Components: Vulkan VK-GL-CTS issue: 4793 Change-Id: Idb5ec9fd5bb778d437a1e96b34c5cdc423490920 --- .../vktPipelineRenderToImageTests.cpp | 283 ++++++++++++------ 1 file changed, 199 insertions(+), 84 deletions(-) diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp index a8bc15b66685dda2f4af..c9ce129a0a0e8334f1ad 100644 --- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp @@ -645,38 +645,6 @@ IVec4 getMaxImageSize (const VkImageViewType viewType, const IVec4& sizeHint) return size; } -deUint32 getMemoryTypeNdx (Context& context, const CaseDef& caseDef) -{ - const DeviceInterface& vk = context.getDeviceInterface(); - const InstanceInterface& vki = context.getInstanceInterface(); - const VkDevice device = context.getDevice(); - const VkPhysicalDevice physDevice = context.getPhysicalDevice(); - - const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); - Move colorImage; - VkMemoryRequirements memReqs; - - const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - const IVec4 imageSize = getMaxImageSize(caseDef.viewType, caseDef.imageSizeHint); - - //create image, don't bind any memory to it - colorImage = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat, - imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), imageUsage); - - vk.getImageMemoryRequirements(device, *colorImage, &memReqs); - return selectMatchingMemoryType(memoryProperties, memReqs.memoryTypeBits, MemoryRequirement::Any); -} - -VkDeviceSize getMaxDeviceHeapSize (Context& context, const CaseDef& caseDef) -{ - const InstanceInterface& vki = context.getInstanceInterface(); - const VkPhysicalDevice physDevice = context.getPhysicalDevice(); - const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); - const deUint32 memoryTypeNdx = getMemoryTypeNdx (context, caseDef); - - return memoryProperties.memoryHeaps[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].size; -} - //! Get a smaller image size. Returns a vector of zeroes, if it can't reduce more. IVec4 getReducedImageSize (const CaseDef& caseDef, IVec4 size) { @@ -706,6 +674,41 @@ IVec4 getReducedImageSize (const CaseDef& caseDef, IVec4 size) return size; } +//! Get the image memory requirements for the image size under test, expecting potential image +//! creation failure if the required size is larger than the device's maxResourceSize, returning +//! false if creation failed. +bool getSupportedImageMemoryRequirements(Context& context, const CaseDef& caseDef, const VkFormat format, const IVec4 size, const VkImageUsageFlags usage, VkMemoryRequirements& imageMemoryRequiements) +{ + const DeviceInterface& vk = context.getDeviceInterface(); + const VkDevice device = context.getDevice(); + bool imageCreationPossible = true; + + try + { + Move image = makeImage( + vk, + device, + getImageCreateFlags(caseDef.viewType), + getImageType(caseDef.viewType), + format, + size.swizzle(0, 1, 2), + 1u, + size.w(), + usage + ); + + vk.getImageMemoryRequirements(device, *image, &imageMemoryRequiements); + } + // vkCreateImage is allowed to return VK_ERROR_OUT_OF_HOST_MEMORY if the image's + // memory requirements will exceed maxResourceSize. + catch (const vk::OutOfMemoryError& e) + { + imageCreationPossible = false; + } + + return imageCreationPossible; +} + bool isDepthStencilFormatSupported (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format) { const VkFormatProperties properties = getPhysicalDeviceFormatProperties(vki, physDevice, format); @@ -794,72 +797,150 @@ tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef) const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); Allocator& allocator = context.getDefaultAllocator(); - // The memory might be too small to allocate a largest possible attachment, so try to account for that. - const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED); - IVec4 imageSize = getMaxImageSize(caseDef.viewType, caseDef.imageSizeHint); - VkDeviceSize colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); - VkDeviceSize depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); - const VkDeviceSize reserveForChecking = 500ull * 1024ull; //left 512KB - const float additionalMemory = 1.15f; //left some free memory on device (15%) - VkDeviceSize neededMemory = static_cast(static_cast(colorSize + depthStencilSize) * additionalMemory) + reserveForChecking; - VkDeviceSize maxMemory = getMaxDeviceHeapSize(context, caseDef) >> 2; + const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + const VkImageUsageFlags depthStencilImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + const bool useDepthStencil = (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED); - tcu::PlatformMemoryLimits memoryLimits; - context.getTestContext().getPlatform().getMemoryLimits(memoryLimits); - maxMemory = std::min(maxMemory, VkDeviceSize(memoryLimits.totalSystemMemory)); + { + VkImageFormatProperties colorImageFormatProperties; + const auto result = vki.getPhysicalDeviceImageFormatProperties( + physDevice, + caseDef.colorFormat, + getImageType(caseDef.viewType), + VK_IMAGE_TILING_OPTIMAL, + colorImageUsage, + getImageCreateFlags(caseDef.viewType), + &colorImageFormatProperties + ); + + VK_CHECK(result); - const VkDeviceSize deviceMemoryBudget = std::min(neededMemory, maxMemory); - bool allocationPossible = false; + imageSize.x() = std::min(static_cast(imageSize.x()), colorImageFormatProperties.maxExtent.width); + imageSize.y() = std::min(static_cast(imageSize.y()), colorImageFormatProperties.maxExtent.height); + imageSize.z() = std::min(static_cast(imageSize.z()), colorImageFormatProperties.maxExtent.depth); + imageSize.w() = std::min(static_cast(imageSize.w()), colorImageFormatProperties.maxArrayLayers); + } - // Keep reducing the size, if image size is too big - while (neededMemory > deviceMemoryBudget) + if (useDepthStencil) { - imageSize = getReducedImageSize(caseDef, imageSize); + VkImageFormatProperties depthStencilImageFormatProperties; + const auto result = vki.getPhysicalDeviceImageFormatProperties( + physDevice, + caseDef.depthStencilFormat, + getImageType(caseDef.viewType), + VK_IMAGE_TILING_OPTIMAL, + depthStencilImageUsage, + getImageCreateFlags(caseDef.viewType), + &depthStencilImageFormatProperties + ); - if (imageSize == IVec4()) - return tcu::TestStatus::fail("Couldn't create an image with required size"); + VK_CHECK(result); - colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); - depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); - neededMemory = static_cast(static_cast(colorSize + depthStencilSize) * additionalMemory); + imageSize.x() = std::min(static_cast(imageSize.x()), depthStencilImageFormatProperties.maxExtent.width); + imageSize.y() = std::min(static_cast(imageSize.y()), depthStencilImageFormatProperties.maxExtent.height); + imageSize.z() = std::min(static_cast(imageSize.z()), depthStencilImageFormatProperties.maxExtent.depth); + imageSize.w() = std::min(static_cast(imageSize.w()), depthStencilImageFormatProperties.maxArrayLayers); } - // Keep reducing the size, if allocation return out of any memory + bool allocationPossible = false; while (!allocationPossible) { - VkDeviceMemory object = 0; - const VkMemoryAllocateInfo allocateInfo = - { - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, //VkStructureType sType; - DE_NULL, //const void* pNext; - neededMemory, //VkDeviceSize allocationSize; - getMemoryTypeNdx(context, caseDef) //deUint32 memoryTypeIndex; - }; - - const VkResult result = vk.allocateMemory(device, &allocateInfo, DE_NULL, &object); + // Get the image memory requirements + VkMemoryRequirements colorImageMemReqs; + VkDeviceSize neededMemory = 0; + deUint32 memoryTypeNdx = 0; - if (VK_ERROR_OUT_OF_DEVICE_MEMORY == result || VK_ERROR_OUT_OF_HOST_MEMORY == result) + if (!getSupportedImageMemoryRequirements(context, caseDef, caseDef.colorFormat, imageSize, colorImageUsage, colorImageMemReqs)) { + // Try again with reduced image size imageSize = getReducedImageSize(caseDef, imageSize); - if (imageSize == IVec4()) return tcu::TestStatus::fail("Couldn't create an image with required size"); + else + continue; + } + + neededMemory = colorImageMemReqs.size; + + if (useDepthStencil) + { + VkMemoryRequirements depthStencilImageMemReqs; - colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); - depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); - neededMemory = static_cast(static_cast(colorSize + depthStencilSize) * additionalMemory) + reserveForChecking; + if (!getSupportedImageMemoryRequirements(context, caseDef, caseDef.depthStencilFormat, imageSize, depthStencilImageUsage, depthStencilImageMemReqs)) + { + // Try again with reduced image size + imageSize = getReducedImageSize(caseDef, imageSize); + if (imageSize == IVec4()) + return tcu::TestStatus::fail("Couldn't create an image with required size"); + else + continue; + } + + neededMemory += depthStencilImageMemReqs.size; } - else if (VK_SUCCESS != result) + + // Reserve an additional 15% device memory, plus the 512KB for checking results { - return tcu::TestStatus::fail("Couldn't allocate memory"); + const VkDeviceSize reserveForChecking = 500ull * 1024ull; + const float additionalMemory = 1.15f; + neededMemory = static_cast(static_cast(neededMemory) * additionalMemory) + reserveForChecking; } - else + + // Query the available memory in the corresponding memory heap { - //free memory using Move pointer - Move memoryAllocated (check(object), Deleter(vk, device, DE_NULL)); - allocationPossible = true; + const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); + // Use the color image memory requirements, assume depth stencil uses the same memory type + memoryTypeNdx = selectMatchingMemoryType(memoryProperties, colorImageMemReqs.memoryTypeBits, MemoryRequirement::Any); + tcu::PlatformMemoryLimits memoryLimits; + context.getTestContext().getPlatform().getMemoryLimits(memoryLimits); + VkDeviceSize maxMemory = std::min( + memoryProperties.memoryHeaps[memoryProperties.memoryTypes[memoryTypeNdx].heapIndex].size, + VkDeviceSize(memoryLimits.totalSystemMemory) + ); + + if (neededMemory > maxMemory) + { + // Try again with reduced image size + imageSize = getReducedImageSize(caseDef, imageSize); + if (imageSize == IVec4()) + return tcu::TestStatus::fail("Couldn't create an image with required size"); + else + continue; + } + } + + // Attempt a memory allocation + { + VkDeviceMemory object = 0; + const VkMemoryAllocateInfo allocateInfo = + { + VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, //VkStructureType sType; + DE_NULL, //const void* pNext; + neededMemory, //VkDeviceSize allocationSize; + memoryTypeNdx //deUint32 memoryTypeIndex; + }; + + const VkResult result = vk.allocateMemory(device, &allocateInfo, DE_NULL, &object); + + if (VK_ERROR_OUT_OF_DEVICE_MEMORY == result || VK_ERROR_OUT_OF_HOST_MEMORY == result) + { + // Try again with reduced image size + imageSize = getReducedImageSize(caseDef, imageSize); + if (imageSize == IVec4()) + return tcu::TestStatus::fail("Couldn't create an image with required size"); + } + else if (VK_SUCCESS != result) + { + return tcu::TestStatus::fail("Couldn't allocate memory"); + } + else + { + //free memory using Move pointer + Move memoryAllocated (check(object), Deleter(vk, device, DE_NULL)); + allocationPossible = true; + } } } @@ -907,20 +988,16 @@ tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef) // Create a color image { - const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - colorImage = makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat, - imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), imageUsage); + imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), colorImageUsage); colorImageAlloc = bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind); } // Create a depth/stencil image (always a 2D image, optionally layered) if (useDepthStencil) { - const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - depthStencilImage = makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat, - IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, imageUsage); + IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, depthStencilImageUsage); depthStencilImageAlloc = bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind); } @@ -1153,13 +1230,51 @@ void checkImageViewTypeRequirements (Context& context, const VkImageViewType vie void checkSupportAttachmentSize (Context& context, const CaseDef caseDef) { + const InstanceInterface& vki = context.getInstanceInterface(); + const VkPhysicalDevice physDevice = context.getPhysicalDevice(); + checkImageViewTypeRequirements(context, caseDef.viewType); if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED) context.requireDeviceFunctionality("VK_KHR_dedicated_allocation"); - if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED && !isDepthStencilFormatSupported(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.depthStencilFormat)) - TCU_THROW(NotSupportedError, "Unsupported depth/stencil format"); + { + VkImageFormatProperties colorImageFormatProperties; + const auto result = vki.getPhysicalDeviceImageFormatProperties( + physDevice, + caseDef.colorFormat, + getImageType(caseDef.viewType), + VK_IMAGE_TILING_OPTIMAL, + (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), + getImageCreateFlags(caseDef.viewType), + &colorImageFormatProperties + ); + + if (result != VK_SUCCESS) + { + TCU_THROW(NotSupportedError, "Unsupported color attachment format"); + } + } + + if (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED) + { + + VkImageFormatProperties depthStencilImageFormatProperties; + const auto result = vki.getPhysicalDeviceImageFormatProperties( + physDevice, + caseDef.depthStencilFormat, + getImageType(caseDef.viewType), + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + getImageCreateFlags(caseDef.viewType), + &depthStencilImageFormatProperties + ); + + if (result != VK_SUCCESS) + { + TCU_THROW(NotSupportedError, "Unsupported depth/stencil attachment format"); + } + } checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), caseDef.pipelineConstructionType); } -- Cheers, Eric