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:
parent
97a91c816f
commit
2922b780c1
@ -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 };
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user