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
|
||||
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 };
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user