From d86249cb0add1504c0d3a5c41527cbef43346742 Mon Sep 17 00:00:00 2001 From: MaxLastBreath <136052075+MaxLastBreath@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:33:38 +0300 Subject: [PATCH] Convert MaxTextureCacheCapacity to Dynamic MaxTextureCacheCapacity for High Resolution Mod support. (#7307) * Add Texture Size Capacity and 8GB Dram Build * Update AutoDeleteCache.cs * Dynamic Texture Cache (WIP) * Change to float Multiplier, in-case it needs fine-tuning. * Delete src/src.sln * Update AutoDeleteCache.cs * Format * Fix Formatting * Add DefaultTextureSizeCapacity and MemoryScaleFactor - Also remove redundant New Lines * Fix 4GB dram crashing * Format newline * Refractor - Added Initialize() function to TextureCache and AutoDeleteCache - Removed GetMaxTextureCapacity() function and instead added _maxCacheMemoryUsage - Added private const MaxTextureSizeCapacity to AutoDelete Cache - Added TextureCache.Initialize() to MemoryManager in order to fetch MaxGpuMemory at the right time. - Moved and Changed Logger.Info for Gpu Memory to Logger.Notice and Moved it to PrintGpuInformation function. - Opted to use a ternary operator for the Initialize function, I think it looks cleaner than bunch of if statements. * Update src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs Co-authored-by: gdkchan * maxMemory to CacheMemory, use Clamp instead of Ternary. Changed MinTextureCapacity 1GiB to 512 MiB * Update src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs Co-authored-by: gdkchan * Format comment * comment context * Increase TextureSize capacity for OpenGL back to 1024 - Added a new const ulong for OpenGLTextureSizeCapacity * Fix changes from last commit. * Adjust last OpenGL changes. * Remove garbage VSC file * Update src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs Co-authored-by: gdkchan * Update src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs Co-authored-by: gdkchan * Update src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs Co-authored-by: gdkchan --------- Co-authored-by: gdkchan --- src/Ryujinx.Graphics.GAL/Capabilities.cs | 6 +++- .../Image/AutoDeleteCache.cs | 30 +++++++++++++++++-- .../Image/TextureCache.cs | 8 +++++ .../Memory/MemoryManager.cs | 2 ++ src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs | 3 +- src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 22 +++++++++++++- 6 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/Ryujinx.Graphics.GAL/Capabilities.cs b/src/Ryujinx.Graphics.GAL/Capabilities.cs index a5c6eb5c8e..1eec80e51b 100644 --- a/src/Ryujinx.Graphics.GAL/Capabilities.cs +++ b/src/Ryujinx.Graphics.GAL/Capabilities.cs @@ -71,6 +71,8 @@ namespace Ryujinx.Graphics.GAL public readonly int GatherBiasPrecision; + public readonly ulong MaximumGpuMemory; + public Capabilities( TargetApi api, string vendorName, @@ -131,7 +133,8 @@ namespace Ryujinx.Graphics.GAL int shaderSubgroupSize, int storageBufferOffsetAlignment, int textureBufferOffsetAlignment, - int gatherBiasPrecision) + int gatherBiasPrecision, + ulong maximumGpuMemory) { Api = api; VendorName = vendorName; @@ -193,6 +196,7 @@ namespace Ryujinx.Graphics.GAL StorageBufferOffsetAlignment = storageBufferOffsetAlignment; TextureBufferOffsetAlignment = textureBufferOffsetAlignment; GatherBiasPrecision = gatherBiasPrecision; + MaximumGpuMemory = maximumGpuMemory; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs index 5e66a3b543..ad6c1fecb2 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/AutoDeleteCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; @@ -46,7 +47,11 @@ namespace Ryujinx.Graphics.Gpu.Image { private const int MinCountForDeletion = 32; private const int MaxCapacity = 2048; - private const ulong MaxTextureSizeCapacity = 1024 * 1024 * 1024; // MB; + private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024; + private const ulong MaxTextureSizeCapacity = 4UL * 1024 * 1024 * 1024; + private const ulong DefaultTextureSizeCapacity = 1UL * 1024 * 1024 * 1024; + private const float MemoryScaleFactor = 0.50f; + private ulong _maxCacheMemoryUsage = 0; private readonly LinkedList _textures; private ulong _totalSize; @@ -56,6 +61,25 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly Dictionary _shortCacheLookup; + /// + /// Initializes the cache, setting the maximum texture capacity for the specified GPU context. + /// + /// + /// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`. + /// + /// The GPU context that the cache belongs to + public void Initialize(GpuContext context) + { + var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor); + + _maxCacheMemoryUsage = Math.Clamp(cacheMemory, MinTextureSizeCapacity, MaxTextureSizeCapacity); + + if (context.Capabilities.MaximumGpuMemory == 0) + { + _maxCacheMemoryUsage = DefaultTextureSizeCapacity; + } + } + /// /// Creates a new instance of the automatic deletion cache. /// @@ -85,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Image texture.CacheNode = _textures.AddLast(texture); if (_textures.Count > MaxCapacity || - (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)) + (_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion)) { RemoveLeastUsedTexture(); } @@ -110,7 +134,7 @@ namespace Ryujinx.Graphics.Gpu.Image _textures.AddLast(texture.CacheNode); } - if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion) + if (_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion) { RemoveLeastUsedTexture(); } diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 5a3319b06a..1587e20189 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -68,6 +68,14 @@ namespace Ryujinx.Graphics.Gpu.Image _cache = new AutoDeleteCache(); } + /// + /// Initializes the cache, setting the maximum texture capacity for the specified GPU context. + /// + public void Initialize() + { + _cache.Initialize(_context); + } + /// /// Handles marking of textures written to a memory region being (partially) remapped. /// diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 59a940a4f9..d1065431d1 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Memory; +using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Memory; using Ryujinx.Memory.Range; using System; @@ -64,6 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Memory MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler; MemoryUnmapped += VirtualRangeCache.MemoryUnmappedHandler; MemoryUnmapped += CounterCache.MemoryUnmappedHandler; + Physical.TextureCache.Initialize(); } /// diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index ba9cd45c67..9fcdf1ad79 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs @@ -202,7 +202,8 @@ namespace Ryujinx.Graphics.OpenGL shaderSubgroupSize: Constants.MaxSubgroupSize, storageBufferOffsetAlignment: HwCapabilities.StorageBufferOffsetAlignment, textureBufferOffsetAlignment: HwCapabilities.TextureBufferOffsetAlignment, - gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0); // Precision is 8 for these vendors on Vulkan. + gatherBiasPrecision: intelWindows || amdWindows ? 8 : 0, // Precision is 8 for these vendors on Vulkan. + maximumGpuMemory: 0); } public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data) diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 33e41ab489..0faaec82a4 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -781,7 +781,26 @@ namespace Ryujinx.Graphics.Vulkan shaderSubgroupSize: (int)Capabilities.SubgroupSize, storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment, textureBufferOffsetAlignment: (int)limits.MinTexelBufferOffsetAlignment, - gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0); + gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0, + maximumGpuMemory: GetTotalGPUMemory()); + } + + private ulong GetTotalGPUMemory() + { + ulong totalMemory = 0; + + Api.GetPhysicalDeviceMemoryProperties(_physicalDevice.PhysicalDevice, out PhysicalDeviceMemoryProperties memoryProperties); + + for (int i = 0; i < memoryProperties.MemoryHeapCount; i++) + { + var heap = memoryProperties.MemoryHeaps[i]; + if ((heap.Flags & MemoryHeapFlags.DeviceLocalBit) == MemoryHeapFlags.DeviceLocalBit) + { + totalMemory += heap.Size; + } + } + + return totalMemory; } public HardwareInfo GetHardwareInfo() @@ -865,6 +884,7 @@ namespace Ryujinx.Graphics.Vulkan private void PrintGpuInformation() { Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})"); + Logger.Notice.Print(LogClass.Gpu, $"GPU Memory: {GetTotalGPUMemory() / (1024 * 1024)} MiB"); } public void Initialize(GraphicsDebugLevel logLevel)