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
DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = VK_IMAGE_TILING_LINEAR;
memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
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
// whether we need to use a dedicated allocation.
DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = info.tiling;
memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated };
@ -96,17 +97,6 @@ namespace dxvk {
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
bool isGpuWritable = (m_info.access & (
VK_ACCESS_SHADER_WRITE_BIT |
@ -136,6 +126,7 @@ namespace dxvk {
if (properties.metadataPageCount) {
DxvkMemoryRequirements memoryRequirements = { };
memoryRequirements.tiling = VK_IMAGE_TILING_OPTIMAL;
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 };
m_vkd->vkGetImageMemoryRequirements2(m_vkd->device(),

View File

@ -181,7 +181,6 @@ namespace dxvk {
DxvkMemoryAllocator::DxvkMemoryAllocator(DxvkDevice* device)
: m_device (device),
m_devProps (device->adapter()->deviceProperties()),
m_memProps (device->adapter()->memoryProperties()) {
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
m_memHeaps[i].properties = m_memProps.memoryHeaps[i];
@ -207,7 +206,7 @@ namespace dxvk {
DxvkMemory DxvkMemoryAllocator::alloc(
const DxvkMemoryRequirements& req,
DxvkMemoryRequirements req,
DxvkMemoryProperties info,
DxvkMemoryFlags hints) {
std::lock_guard<dxvk::mutex> lock(m_mutex);
@ -225,41 +224,58 @@ namespace dxvk {
if (info.flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
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);
if (!result && !req.dedicated.requiresDedicatedAllocation) {
// If that failed, try without a dedicated allocation
if (info.dedicated.image || info.dedicated.buffer) {
if (result)
return result;
}
// If possible, retry without a dedicated allocation
if (!req.dedicated.requiresDedicatedAllocation) {
info.dedicated.image = 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
hints.set(DxvkMemoryFlag::IgnoreConstraints);
result = this->tryAlloc(req, info, hints);
if (result)
return result;
}
if (!result) {
// If that still didn't work, probe slower memory types as well
VkMemoryPropertyFlags optFlags = info.flags & (
// If that still didn't work, probe slower memory types as
// well, but re-enable restrictions to decrease fragmentation.
hints.clr(DxvkMemoryFlag::IgnoreConstraints);
const VkMemoryPropertyFlags optionalFlags =
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
while (!result && optFlags) {
VkMemoryPropertyFlags bit = optFlags & -optFlags;
optFlags &= ~bit;
if (info.flags & optionalFlags) {
info.flags &= ~optionalFlags;
info.flags &= ~bit;
result = this->tryAlloc(req, info, hints);
}
DxvkMemory 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();
Logger::err(str::format(
@ -284,9 +300,6 @@ namespace dxvk {
throw DxvkError("DxvkMemoryAllocator: Memory allocation failed");
}
return result;
}
DxvkMemory DxvkMemoryAllocator::tryAlloc(
const DxvkMemoryRequirements& req,

View File

@ -277,6 +277,7 @@ namespace dxvk {
* \brief Memory requirement info
*/
struct DxvkMemoryRequirements {
VkImageTiling tiling;
VkMemoryDedicatedRequirements dedicated;
VkMemoryRequirements2 core;
};
@ -309,18 +310,6 @@ namespace dxvk {
DxvkMemoryAllocator(DxvkDevice* device);
~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
* \returns Sparse resource memory types
@ -338,7 +327,7 @@ namespace dxvk {
* \returns Allocated memory slice
*/
DxvkMemory alloc(
const DxvkMemoryRequirements& req,
DxvkMemoryRequirements req,
DxvkMemoryProperties info,
DxvkMemoryFlags hints);
@ -357,7 +346,6 @@ namespace dxvk {
private:
DxvkDevice* m_device;
VkPhysicalDeviceProperties m_devProps;
VkPhysicalDeviceMemoryProperties m_memProps;
dxvk::mutex m_mutex;

View File

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