1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-12 13:08:50 +01:00

[dxvk] Properly handle bufferImageGranularity for images

Fixes validation errors about dedicated allocations being
bigger than the image's memory requirement on Nvidia.
This commit is contained in:
Philip Rebohle 2023-01-14 01:02:03 +01:00
parent 97a91c816f
commit 2922b780c1
5 changed files with 66 additions and 72 deletions

View File

@ -88,6 +88,7 @@ namespace dxvk {
// Query memory requirements and whether to use a dedicated allocation // Query memory requirements and whether to use a dedicated allocation
DxvkMemoryRequirements memoryRequirements = { }; DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = VK_IMAGE_TILING_LINEAR;
memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS }; memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated }; memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated };

View File

@ -65,6 +65,7 @@ namespace dxvk {
// Get memory requirements for the image and ask driver // Get memory requirements for the image and ask driver
// whether we need to use a dedicated allocation. // whether we need to use a dedicated allocation.
DxvkMemoryRequirements memoryRequirements = { }; DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = info.tiling;
memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS }; memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated }; memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated };
@ -96,17 +97,6 @@ namespace dxvk {
memoryProperties.dedicated.image = m_image.image; memoryProperties.dedicated.image = m_image.image;
} }
// If there's a chance we won't create the image with a dedicated
// allocation, enforce strict alignment for tiled images to not
// violate the bufferImageGranularity requirement on some GPUs.
if (info.tiling != VK_IMAGE_TILING_LINEAR && !memoryRequirements.dedicated.requiresDedicatedAllocation) {
VkDeviceSize granularity = memAlloc.bufferImageGranularity();
auto& core = memoryRequirements.core.memoryRequirements;
core.size = align(core.size, granularity);
core.alignment = align(core.alignment, granularity);
}
// Use high memory priority for GPU-writable resources // Use high memory priority for GPU-writable resources
bool isGpuWritable = (m_info.access & ( bool isGpuWritable = (m_info.access & (
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT |
@ -136,6 +126,7 @@ namespace dxvk {
if (properties.metadataPageCount) { if (properties.metadataPageCount) {
DxvkMemoryRequirements memoryRequirements = { }; DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = VK_IMAGE_TILING_OPTIMAL;
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 }; memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 };
m_vkd->vkGetImageMemoryRequirements2(m_vkd->device(), m_vkd->vkGetImageMemoryRequirements2(m_vkd->device(),

View File

@ -181,7 +181,6 @@ namespace dxvk {
DxvkMemoryAllocator::DxvkMemoryAllocator(DxvkDevice* device) DxvkMemoryAllocator::DxvkMemoryAllocator(DxvkDevice* device)
: m_device (device), : m_device (device),
m_devProps (device->adapter()->deviceProperties()),
m_memProps (device->adapter()->memoryProperties()) { m_memProps (device->adapter()->memoryProperties()) {
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) { for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
m_memHeaps[i].properties = m_memProps.memoryHeaps[i]; m_memHeaps[i].properties = m_memProps.memoryHeaps[i];
@ -207,7 +206,7 @@ namespace dxvk {
DxvkMemory DxvkMemoryAllocator::alloc( DxvkMemory DxvkMemoryAllocator::alloc(
const DxvkMemoryRequirements& req, DxvkMemoryRequirements req,
DxvkMemoryProperties info, DxvkMemoryProperties info,
DxvkMemoryFlags hints) { DxvkMemoryFlags hints) {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
@ -225,41 +224,58 @@ namespace dxvk {
if (info.flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) if (info.flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
hints = hints & DxvkMemoryFlag::Transient; hints = hints & DxvkMemoryFlag::Transient;
// Try to allocate from a memory type which supports the given flags exactly // If requested, try with a dedicated allocation first.
if (info.dedicated.image || info.dedicated.buffer) {
DxvkMemory result = this->tryAlloc(req, info, hints); DxvkMemory result = this->tryAlloc(req, info, hints);
if (!result && !req.dedicated.requiresDedicatedAllocation) { if (result)
// If that failed, try without a dedicated allocation return result;
if (info.dedicated.image || info.dedicated.buffer) { }
// If possible, retry without a dedicated allocation
if (!req.dedicated.requiresDedicatedAllocation) {
info.dedicated.image = VK_NULL_HANDLE; info.dedicated.image = VK_NULL_HANDLE;
info.dedicated.buffer = VK_NULL_HANDLE; info.dedicated.buffer = VK_NULL_HANDLE;
result = this->tryAlloc(req, info, hints); // If we're allocating tiled image memory, ensure
} // that it will not overlap with buffer memory.
if (req.tiling == VK_IMAGE_TILING_OPTIMAL) {
VkDeviceSize granularity = m_device->properties().core.properties.limits.bufferImageGranularity;
req.core.memoryRequirements.size = align(req.core.memoryRequirements.size, granularity);
req.core.memoryRequirements.alignment = align(req.core.memoryRequirements.alignment, granularity);
} }
if (!result) { DxvkMemory result = this->tryAlloc(req, info, hints);
if (result)
return result;
// Retry without the hint constraints // Retry without the hint constraints
hints.set(DxvkMemoryFlag::IgnoreConstraints); hints.set(DxvkMemoryFlag::IgnoreConstraints);
result = this->tryAlloc(req, info, hints); result = this->tryAlloc(req, info, hints);
if (result)
return result;
} }
if (!result) { // If that still didn't work, probe slower memory types as
// If that still didn't work, probe slower memory types as well // well, but re-enable restrictions to decrease fragmentation.
VkMemoryPropertyFlags optFlags = info.flags & ( hints.clr(DxvkMemoryFlag::IgnoreConstraints);
const VkMemoryPropertyFlags optionalFlags =
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_CACHED_BIT); VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
while (!result && optFlags) { if (info.flags & optionalFlags) {
VkMemoryPropertyFlags bit = optFlags & -optFlags; info.flags &= ~optionalFlags;
optFlags &= ~bit;
info.flags &= ~bit; DxvkMemory result = this->tryAlloc(req, info, hints);
result = this->tryAlloc(req, info, hints);
} if (result)
return result;
} }
if (!result) { // We weren't able to allocate memory for this resource form any type
DxvkAdapterMemoryInfo memHeapInfo = m_device->adapter()->getMemoryHeapInfo(); DxvkAdapterMemoryInfo memHeapInfo = m_device->adapter()->getMemoryHeapInfo();
Logger::err(str::format( Logger::err(str::format(
@ -284,9 +300,6 @@ namespace dxvk {
throw DxvkError("DxvkMemoryAllocator: Memory allocation failed"); throw DxvkError("DxvkMemoryAllocator: Memory allocation failed");
} }
return result;
}
DxvkMemory DxvkMemoryAllocator::tryAlloc( DxvkMemory DxvkMemoryAllocator::tryAlloc(
const DxvkMemoryRequirements& req, const DxvkMemoryRequirements& req,

View File

@ -277,6 +277,7 @@ namespace dxvk {
* \brief Memory requirement info * \brief Memory requirement info
*/ */
struct DxvkMemoryRequirements { struct DxvkMemoryRequirements {
VkImageTiling tiling;
VkMemoryDedicatedRequirements dedicated; VkMemoryDedicatedRequirements dedicated;
VkMemoryRequirements2 core; VkMemoryRequirements2 core;
}; };
@ -309,18 +310,6 @@ namespace dxvk {
DxvkMemoryAllocator(DxvkDevice* device); DxvkMemoryAllocator(DxvkDevice* device);
~DxvkMemoryAllocator(); ~DxvkMemoryAllocator();
/**
* \brief Buffer-image granularity
*
* The granularity between linear and non-linear
* resources in adjacent memory locations. See
* section 11.6 of the Vulkan spec for details.
* \returns Buffer-image granularity
*/
VkDeviceSize bufferImageGranularity() const {
return m_devProps.limits.bufferImageGranularity;
}
/** /**
* \brief Memory type mask for sparse resources * \brief Memory type mask for sparse resources
* \returns Sparse resource memory types * \returns Sparse resource memory types
@ -338,7 +327,7 @@ namespace dxvk {
* \returns Allocated memory slice * \returns Allocated memory slice
*/ */
DxvkMemory alloc( DxvkMemory alloc(
const DxvkMemoryRequirements& req, DxvkMemoryRequirements req,
DxvkMemoryProperties info, DxvkMemoryProperties info,
DxvkMemoryFlags hints); DxvkMemoryFlags hints);
@ -357,7 +346,6 @@ namespace dxvk {
private: private:
DxvkDevice* m_device; DxvkDevice* m_device;
VkPhysicalDeviceProperties m_devProps;
VkPhysicalDeviceMemoryProperties m_memProps; VkPhysicalDeviceMemoryProperties m_memProps;
dxvk::mutex m_mutex; dxvk::mutex m_mutex;

View File

@ -120,6 +120,7 @@ namespace dxvk {
Rc<DxvkSparsePage> DxvkSparsePageAllocator::allocPage() { Rc<DxvkSparsePage> DxvkSparsePageAllocator::allocPage() {
DxvkMemoryRequirements memoryRequirements = { }; DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = VK_IMAGE_TILING_LINEAR;
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 }; memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 };
// We don't know what kind of resource the memory6 // We don't know what kind of resource the memory6