From 5221675e3df89c950a5cbbaf81cf65620b28b2f5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Sarwa Date: Tue, 12 Sep 2017 13:28:39 +0200 Subject: [PATCH] Fix unreasonable memory expectations in pipeline.render_to_image Affects: dEQP-VK.pipeline.render_to_image.* Components: Vulkan VK-GL-CTS issue: 526 Change-Id: I71ea0381663c39786b227ed712e1111ec3c71cfb (cherry picked from commit 069aa0ad097f543438b39a260eea52278867ffa8) --- .../pipeline/vktPipelineRenderToImageTests.cpp | 215 +++++++++++++-------- 1 file changed, 137 insertions(+), 78 deletions(-) diff --git a/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp b/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp index d11c802..89b4e2e 100644 --- a/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp +++ b/external/vulkancts/modules/vulkan/pipeline/vktPipelineRenderToImageTests.cpp @@ -694,18 +694,90 @@ void generateExpectedImage (const tcu::PixelBufferAccess& outputImage, const IVe } } -VkDeviceSize getMaxDeviceHeapSize (const InstanceInterface& vki, const VkPhysicalDevice physDevice) +deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement) { - const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); - VkDeviceSize memorySize = 0; + const deUint32 compatibleTypes = getCompatibleMemoryTypes(deviceMemProps, requirement); + const deUint32 candidates = allowedMemTypeBits & compatibleTypes; + + if (candidates == 0) + TCU_THROW(NotSupportedError, "No compatible memory type found"); + + return (deUint32)deCtz32(candidates); +} + +IVec4 getMaxImageSize (const VkImageViewType viewType, const IVec4& sizeHint) +{ + //Limits have been taken from the vulkan specification + IVec4 size = IVec4( + sizeHint.x() != MAX_SIZE ? sizeHint.x() : 4096, + sizeHint.y() != MAX_SIZE ? sizeHint.y() : 4096, + sizeHint.z() != MAX_SIZE ? sizeHint.z() : 256, + sizeHint.w() != MAX_SIZE ? sizeHint.w() : 256); - for (deUint32 heapNdx = 0; heapNdx < memoryProperties.memoryHeapCount; ++heapNdx) + switch (viewType) { - if ((memoryProperties.memoryHeaps[heapNdx].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) - memorySize = std::max(memorySize, memoryProperties.memoryHeaps[heapNdx].size); + case VK_IMAGE_VIEW_TYPE_1D: + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: + size.x() = deMin32(4096, size.x()); + break; + + case VK_IMAGE_VIEW_TYPE_2D: + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: + size.x() = deMin32(4096, size.x()); + size.y() = deMin32(4096, size.y()); + break; + + case VK_IMAGE_VIEW_TYPE_3D: + size.x() = deMin32(256, size.x()); + size.y() = deMin32(256, size.y()); + break; + + case VK_IMAGE_VIEW_TYPE_CUBE: + case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: + size.x() = deMin32(4096, size.x()); + size.y() = deMin32(4096, size.y()); + size.w() = deMin32(252, size.w()); + size.w() = NUM_CUBE_FACES * (size.w() / NUM_CUBE_FACES); // round down to 6 faces + break; + + default: + DE_ASSERT(0); + return IVec4(); } - return memorySize; + 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. @@ -743,51 +815,6 @@ bool isDepthStencilFormatSupported (const InstanceInterface& vki, const VkPhysic return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0; } -IVec4 getMaxImageSize (const VkPhysicalDeviceLimits& limits, const VkImageViewType viewType, const IVec4& sizeHint, const bool useDepthStencil) -{ - // If we use a layered D/S together with a 3D image, we have to use the smallest common limit - const int maxDepth = (useDepthStencil ? deMin32(static_cast(limits.maxImageArrayLayers), static_cast(limits.maxImageDimension3D)) - : static_cast(limits.maxImageDimension3D)); - - // Images have to respect framebuffer limits and image limits (the framebuffer is not layered in this case) - IVec4 size = IVec4( - sizeHint.x() != MAX_SIZE ? sizeHint.x() : static_cast(limits.maxFramebufferWidth), - sizeHint.y() != MAX_SIZE ? sizeHint.y() : static_cast(limits.maxFramebufferHeight), - sizeHint.z() != MAX_SIZE ? sizeHint.z() : maxDepth, - sizeHint.w() != MAX_SIZE ? sizeHint.w() : static_cast(limits.maxImageArrayLayers)); - - switch (viewType) - { - case VK_IMAGE_VIEW_TYPE_1D: - case VK_IMAGE_VIEW_TYPE_1D_ARRAY: - size.x() = deMin32(size.x(), limits.maxImageDimension1D); - break; - - case VK_IMAGE_VIEW_TYPE_2D: - case VK_IMAGE_VIEW_TYPE_2D_ARRAY: - size.x() = deMin32(size.x(), limits.maxImageDimension2D); - size.y() = deMin32(size.y(), limits.maxImageDimension2D); - break; - - case VK_IMAGE_VIEW_TYPE_3D: - size.x() = deMin32(size.x(), limits.maxImageDimension3D); - size.y() = deMin32(size.y(), limits.maxImageDimension3D); - break; - - case VK_IMAGE_VIEW_TYPE_CUBE: - case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: - size.x() = size.y() = deMin32(size.x(), limits.maxImageDimensionCube); - size.w() = NUM_CUBE_FACES * (size.w() / NUM_CUBE_FACES); // round down to 6 faces - break; - - default: - DE_ASSERT(0); - return IVec4(); - } - - return size; -} - VkImageAspectFlags getFormatAspectFlags (const VkFormat format) { if (format == VK_FORMAT_UNDEFINED) @@ -860,7 +887,7 @@ void initPrograms (SourceCollections& programCollection, const CaseDef caseDef) } //! See testAttachmentSize() description -tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef, const int sizeReductionIndex) +tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef) { const DeviceInterface& vk = context.getDeviceInterface(); const InstanceInterface& vki = context.getInstanceInterface(); @@ -872,16 +899,67 @@ tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef, // 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); - const VkDeviceSize deviceMemoryBudget = getMaxDeviceHeapSize(vki, physDevice) >> 2; - IVec4 imageSize = getMaxImageSize(context.getDeviceProperties().limits, caseDef.viewType, caseDef.imageSizeHint, useDepthStencil); - // Keep reducing the size, if needed - for (int i = 0; i < sizeReductionIndex; ++i) + 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 VkDeviceSize deviceMemoryBudget = std::min(neededMemory, maxMemory); + bool allocationPossible = false; + + // Keep reducing the size, if image size is too big + while (neededMemory > deviceMemoryBudget) { imageSize = getReducedImageSize(caseDef, imageSize); if (imageSize == IVec4()) return tcu::TestStatus::fail("Couldn't create an image with required size"); + + 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); + } + + // Keep reducing the size, if allocation return out of any memory + 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); + + if (VK_ERROR_OUT_OF_DEVICE_MEMORY == result || VK_ERROR_OUT_OF_HOST_MEMORY == result) + { + imageSize = getReducedImageSize(caseDef, imageSize); + + if (imageSize == IVec4()) + return tcu::TestStatus::fail("Couldn't create an image with required size"); + + 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; + } + 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; + } } context.getTestContext().getLog() @@ -889,15 +967,11 @@ tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef, // "Slices" is either the depth of a 3D image, or the number of layers of an arrayed image const deInt32 numSlices = maxLayersOrDepth(imageSize); - const VkDeviceSize colorSize = product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)); - const VkDeviceSize depthStencilSize = (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull); + if (useDepthStencil && !isDepthStencilFormatSupported(vki, physDevice, caseDef.depthStencilFormat)) TCU_THROW(NotSupportedError, "Unsupported depth/stencil format"); - if (colorSize + depthStencilSize > deviceMemoryBudget) - throw OutOfMemoryError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Image size exceeds test's image memory budget"); - // Determine the verification bounds. The checked region will be in the center of the rendered image const IVec4 checkSize = tcu::min(imageSize, IVec4(MAX_VERIFICATION_REGION_SIZE, MAX_VERIFICATION_REGION_SIZE, @@ -1184,8 +1258,6 @@ tcu::TestStatus testAttachmentSize (Context& context, const CaseDef caseDef) { checkImageViewTypeRequirements(context, caseDef.viewType); - int sizeReductionIndex = 0; - if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED) { const std::string extensionName("VK_KHR_dedicated_allocation"); @@ -1194,20 +1266,7 @@ tcu::TestStatus testAttachmentSize (Context& context, const CaseDef caseDef) TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str()); } - for (;;) - { - try - { - return testWithSizeReduction(context, caseDef, sizeReductionIndex); - } - catch (OutOfMemoryError& ex) - { - context.getTestContext().getLog() - << tcu::TestLog::Message << "-- OutOfMemoryError: " << ex.getMessage() << tcu::TestLog::EndMessage; - - ++sizeReductionIndex; - } - } + return testWithSizeReduction(context, caseDef); // Never reached } -- 2.7.4