diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2021-01-17 15:44:34 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-17 19:44:34 +0100 |
| commit | c4f56c570494a6186792439e3c0e74458cc82b5c (patch) | |
| tree | 40be96f5f3f24b711e088bf2ca681d94aac68c15 /Ryujinx.Graphics.Gpu/Image | |
| parent | 3bad321d2b0994cd19129bc18ed98bb3ab81c3b0 (diff) | |
Support for resources on non-contiguous GPU memory regions (#1905)
* Support for resources on non-contiguous GPU memory regions
* Implement MultiRange physical addresses, only used with a single range for now
* Actually use non-contiguous ranges
* GetPhysicalRegions fixes
* Documentation and remove Address property from TextureInfo
* Finish implementing GetWritableRegion
* Fix typo
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Image')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/Texture.cs | 84 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs | 4 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureInfo.cs | 10 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 100 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TexturePool.cs | 25 |
5 files changed, 108 insertions, 115 deletions
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index ae7fa6cf..1c558f56 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -1,7 +1,7 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Cpu.Tracking; using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture.Astc; using Ryujinx.Memory.Range; @@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// <summary> /// Represents a cached GPU texture. /// </summary> - class Texture : IRange, IDisposable + class Texture : IMultiRangeItem, IDisposable { // How many updates we need before switching to the byte-by-byte comparison // modification check method. @@ -95,21 +95,16 @@ namespace Ryujinx.Graphics.Gpu.Image public event Action<Texture> Disposed; /// <summary> - /// Start address of the texture in guest memory. + /// Physical memory ranges where the texture data is located. /// </summary> - public ulong Address => Info.Address; - - /// <summary> - /// End address of the texture in guest memory. - /// </summary> - public ulong EndAddress => Info.Address + Size; + public MultiRange Range { get; private set; } /// <summary> /// Texture size in bytes. /// </summary> public ulong Size => (ulong)_sizeInfo.TotalSize; - private CpuRegionHandle _memoryTracking; + private GpuRegionHandle _memoryTracking; private int _referenceCount; @@ -119,6 +114,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// <param name="context">GPU context that the texture belongs to</param> /// <param name="info">Texture information</param> /// <param name="sizeInfo">Size information of the texture</param> + /// <param name="range">Physical memory ranges where the texture data is located</param> /// <param name="firstLayer">The first layer of the texture, or 0 if the texture has no parent</param> /// <param name="firstLevel">The first mipmap level of the texture, or 0 if the texture has no parent</param> /// <param name="scaleFactor">The floating point scale factor to initialize with</param> @@ -127,12 +123,13 @@ namespace Ryujinx.Graphics.Gpu.Image GpuContext context, TextureInfo info, SizeInfo sizeInfo, + MultiRange range, int firstLayer, int firstLevel, float scaleFactor, TextureScaleMode scaleMode) { - InitializeTexture(context, info, sizeInfo); + InitializeTexture(context, info, sizeInfo, range); _firstLayer = firstLayer; _firstLevel = firstLevel; @@ -149,13 +146,14 @@ namespace Ryujinx.Graphics.Gpu.Image /// <param name="context">GPU context that the texture belongs to</param> /// <param name="info">Texture information</param> /// <param name="sizeInfo">Size information of the texture</param> + /// <param name="range">Physical memory ranges where the texture data is located</param> /// <param name="scaleMode">The scale mode to initialize with. If scaled, the texture's data is loaded immediately and scaled up</param> - public Texture(GpuContext context, TextureInfo info, SizeInfo sizeInfo, TextureScaleMode scaleMode) + public Texture(GpuContext context, TextureInfo info, SizeInfo sizeInfo, MultiRange range, TextureScaleMode scaleMode) { ScaleFactor = 1f; // Texture is first loaded at scale 1x. ScaleMode = scaleMode; - InitializeTexture(context, info, sizeInfo); + InitializeTexture(context, info, sizeInfo, range); } /// <summary> @@ -166,10 +164,12 @@ namespace Ryujinx.Graphics.Gpu.Image /// <param name="context">GPU context that the texture belongs to</param> /// <param name="info">Texture information</param> /// <param name="sizeInfo">Size information of the texture</param> - private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo) + /// <param name="range">Physical memory ranges where the texture data is located</param> + private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo, MultiRange range) { _context = context; _sizeInfo = sizeInfo; + Range = range; SetInfo(info); @@ -186,7 +186,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// <param name="withData">True if the texture is to be initialized with data</param> public void InitializeData(bool isView, bool withData = false) { - _memoryTracking = _context.PhysicalMemory.BeginTracking(Address, Size); + _memoryTracking = _context.PhysicalMemory.BeginTracking(Range); if (withData) { @@ -229,15 +229,17 @@ namespace Ryujinx.Graphics.Gpu.Image /// </summary> /// <param name="info">Child texture information</param> /// <param name="sizeInfo">Child texture size information</param> + /// <param name="range">Physical memory ranges where the texture data is located</param> /// <param name="firstLayer">Start layer of the child texture on the parent texture</param> /// <param name="firstLevel">Start mipmap level of the child texture on the parent texture</param> /// <returns>The child texture</returns> - public Texture CreateView(TextureInfo info, SizeInfo sizeInfo, int firstLayer, int firstLevel) + public Texture CreateView(TextureInfo info, SizeInfo sizeInfo, MultiRange range, int firstLayer, int firstLevel) { Texture texture = new Texture( _context, info, sizeInfo, + range, _firstLayer + firstLayer, _firstLevel + firstLevel, ScaleFactor, @@ -367,7 +369,7 @@ namespace Ryujinx.Graphics.Gpu.Image ChangedSize = true; SetInfo(new TextureInfo( - Info.Address, + Info.GpuAddress, width, height, depthOrLayers, @@ -554,7 +556,7 @@ namespace Ryujinx.Graphics.Gpu.Image _memoryTracking?.Reprotect(); - ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Address, (int)Size); + ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Range); IsModified = false; @@ -586,6 +588,10 @@ namespace Ryujinx.Graphics.Gpu.Image _hasData = true; } + /// <summary> + /// Uploads new texture data to the host GPU. + /// </summary> + /// <param name="data">New data</param> public void SetData(ReadOnlySpan<byte> data) { BlacklistScale(); @@ -653,7 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Image { string texInfo = $"{Info.Target} {Info.FormatInfo.Format} {Info.Width}x{Info.Height}x{Info.DepthOrLayers} levels {Info.Levels}"; - Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.Address:X} ({texInfo})."); + Logger.Debug?.Print(LogClass.Gpu, $"Invalid ASTC texture at 0x{Info.GpuAddress:X} ({texInfo})."); } data = decoded; @@ -689,15 +695,14 @@ namespace Ryujinx.Graphics.Gpu.Image if (tracked) { - _context.PhysicalMemory.Write(Address, GetTextureDataFromGpu(tracked)); + _context.PhysicalMemory.Write(Range, GetTextureDataFromGpu(tracked)); } else { - _context.PhysicalMemory.WriteUntracked(Address, GetTextureDataFromGpu(tracked)); + _context.PhysicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(tracked)); } } - /// <summary> /// Flushes the texture data, to be called from an external thread. /// The host backend must ensure that we have shared access to the resource from this thread. @@ -725,7 +730,7 @@ namespace Ryujinx.Graphics.Gpu.Image texture = _flushHostTexture = GetScaledHostTexture(1f, _flushHostTexture); } - _context.PhysicalMemory.WriteUntracked(Address, GetTextureDataFromGpu(false, texture)); + _context.PhysicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(false, texture)); }); } @@ -847,25 +852,23 @@ namespace Ryujinx.Graphics.Gpu.Image return TextureMatchQuality.NoMatch; } - return Info.Address == info.Address && Info.Levels == info.Levels ? matchQuality : TextureMatchQuality.NoMatch; + return Info.Levels == info.Levels ? matchQuality : TextureMatchQuality.NoMatch; } /// <summary> /// Check if it's possible to create a view, with the given parameters, from this texture. /// </summary> /// <param name="info">Texture view information</param> - /// <param name="size">Texture view size</param> + /// <param name="range">Texture view physical memory ranges</param> /// <param name="firstLayer">Texture view initial layer on this texture</param> /// <param name="firstLevel">Texture view first mipmap level on this texture</param> /// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns> - public TextureViewCompatibility IsViewCompatible( - TextureInfo info, - ulong size, - out int firstLayer, - out int firstLevel) + public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, out int firstLayer, out int firstLevel) { + int offset = Range.FindOffset(range); + // Out of range. - if (info.Address < Address || info.Address + size > EndAddress) + if (offset < 0) { firstLayer = 0; firstLevel = 0; @@ -873,9 +876,7 @@ namespace Ryujinx.Graphics.Gpu.Image return TextureViewCompatibility.Incompatible; } - int offset = (int)(info.Address - Address); - - if (!_sizeInfo.FindView(offset, (int)size, out firstLayer, out firstLevel)) + if (!_sizeInfo.FindView(offset, out firstLayer, out firstLevel)) { return TextureViewCompatibility.Incompatible; } @@ -1046,17 +1047,6 @@ namespace Ryujinx.Graphics.Gpu.Image } /// <summary> - /// Checks if the texture overlaps with a memory range. - /// </summary> - /// <param name="address">Start address of the range</param> - /// <param name="size">Size of the range</param> - /// <returns>True if the texture overlaps with the range, false otherwise</returns> - public bool OverlapsWith(ulong address, ulong size) - { - return Address < address + size && address < EndAddress; - } - - /// <summary> /// Determine if any of our child textures are compaible as views of the given texture. /// </summary> /// <param name="texture">The texture to check against</param> @@ -1070,7 +1060,7 @@ namespace Ryujinx.Graphics.Gpu.Image foreach (Texture view in _views) { - if (texture.IsViewCompatible(view.Info, view.Size, out int _, out int _) != TextureViewCompatibility.Incompatible) + if (texture.IsViewCompatible(view.Info, view.Range, out _, out _) != TextureViewCompatibility.Incompatible) { return true; } @@ -1153,7 +1143,7 @@ namespace Ryujinx.Graphics.Gpu.Image { IsModified = false; // We shouldn't flush this texture, as its memory is no longer mapped. - CpuRegionHandle tracking = _memoryTracking; + var tracking = _memoryTracking; tracking?.Reprotect(); tracking?.RegisterAction(null); } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 9601b832..173340b3 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -303,7 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Image // Ensure that the buffer texture is using the correct buffer as storage. // Buffers are frequently re-created to accomodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. - _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Address, texture.Size, _isCompute); + _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, _isCompute); } Sampler sampler = _samplerPool.Get(samplerId); @@ -354,7 +354,7 @@ namespace Ryujinx.Graphics.Gpu.Image // Ensure that the buffer texture is using the correct buffer as storage. // Buffers are frequently re-created to accomodate larger data, so we need to re-bind // to ensure we're not using a old buffer that was already deleted. - _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Address, texture.Size, _isCompute); + _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, _isCompute); } if (_imageState[stageIndex][index].Texture != hostTexture || _rebind) diff --git a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs index d27194b8..3137f8b8 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs @@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Gpu.Image struct TextureInfo { /// <summary> - /// Address of the texture in guest memory. + /// Address of the texture in GPU mapped memory. /// </summary> - public ulong Address { get; } + public ulong GpuAddress { get; } /// <summary> /// The width of the texture. @@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// <summary> /// Constructs the texture information structure. /// </summary> - /// <param name="address">The address of the texture</param> + /// <param name="gpuAddress">The GPU address of the texture</param> /// <param name="width">The width of the texture</param> /// <param name="height">The height or the texture</param> /// <param name="depthOrLayers">The depth or layers count of the texture</param> @@ -132,7 +132,7 @@ namespace Ryujinx.Graphics.Gpu.Image /// <param name="swizzleB">Swizzle for the blue color channel</param> /// <param name="swizzleA">Swizzle for the alpha color channel</param> public TextureInfo( - ulong address, + ulong gpuAddress, int width, int height, int depthOrLayers, @@ -152,7 +152,7 @@ namespace Ryujinx.Graphics.Gpu.Image SwizzleComponent swizzleB = SwizzleComponent.Blue, SwizzleComponent swizzleA = SwizzleComponent.Alpha) { - Address = address; + GpuAddress = gpuAddress; Width = width; Height = height; DepthOrLayers = depthOrLayers; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs index 5bad3952..30137d06 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs @@ -37,14 +37,11 @@ namespace Ryujinx.Graphics.Gpu.Image private readonly TextureBindingsManager _gpBindingsManager; private readonly Texture[] _rtColors; - - private Texture _rtDepthStencil; - private readonly ITexture[] _rtHostColors; - + private Texture _rtDepthStencil; private ITexture _rtHostDs; - private readonly RangeList<Texture> _textures; + private readonly MultiRangeList<Texture> _textures; private Texture[] _textureOverlaps; private OverlapInfo[] _overlapInfo; @@ -70,10 +67,9 @@ namespace Ryujinx.Graphics.Gpu.Image _gpBindingsManager = new TextureBindingsManager(context, texturePoolCache, isCompute: false); _rtColors = new Texture[Constants.TotalRenderTargets]; - _rtHostColors = new ITexture[Constants.TotalRenderTargets]; - _textures = new RangeList<Texture>(); + _textures = new MultiRangeList<Texture>(); _textureOverlaps = new Texture[OverlapsBufferInitialCapacity]; _overlapInfo = new OverlapInfo[OverlapsBufferInitialCapacity]; @@ -470,13 +466,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// <returns>The texture</returns> public Texture FindOrCreateTexture(CopyTexture copyTexture, FormatInfo formatInfo, bool preferScaling = true, Size? sizeHint = null) { - ulong address = _context.MemoryManager.Translate(copyTexture.Address.Pack()); - - if (address == MemoryManager.PteUnmapped) - { - return null; - } - int gobBlocksInY = copyTexture.MemoryLayout.UnpackGobBlocksInY(); int gobBlocksInZ = copyTexture.MemoryLayout.UnpackGobBlocksInZ(); @@ -492,7 +481,7 @@ namespace Ryujinx.Graphics.Gpu.Image } TextureInfo info = new TextureInfo( - address, + copyTexture.Address.Pack(), width, copyTexture.Height, copyTexture.Depth, @@ -514,9 +503,9 @@ namespace Ryujinx.Graphics.Gpu.Image flags |= TextureSearchFlags.WithUpscale; } - Texture texture = FindOrCreateTexture(info, flags, 0, sizeHint); + Texture texture = FindOrCreateTexture(flags, info, 0, sizeHint); - texture.SynchronizeMemory(); + texture?.SynchronizeMemory(); return texture; } @@ -531,13 +520,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// <returns>The texture</returns> public Texture FindOrCreateTexture(RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint) { - ulong address = _context.MemoryManager.Translate(colorState.Address.Pack()); - - if (address == MemoryManager.PteUnmapped) - { - return null; - } - bool isLinear = colorState.MemoryLayout.UnpackIsLinear(); int gobBlocksInY = colorState.MemoryLayout.UnpackGobBlocksInY(); @@ -583,7 +565,7 @@ namespace Ryujinx.Graphics.Gpu.Image } TextureInfo info = new TextureInfo( - address, + colorState.Address.Pack(), width, colorState.Height, colorState.Depth, @@ -600,9 +582,9 @@ namespace Ryujinx.Graphics.Gpu.Image int layerSize = !isLinear ? colorState.LayerSize * 4 : 0; - Texture texture = FindOrCreateTexture(info, TextureSearchFlags.WithUpscale, layerSize, sizeHint); + Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, layerSize, sizeHint); - texture.SynchronizeMemory(); + texture?.SynchronizeMemory(); return texture; } @@ -618,13 +600,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// <returns>The texture</returns> public Texture FindOrCreateTexture(RtDepthStencilState dsState, Size3D size, int samplesInX, int samplesInY, Size sizeHint) { - ulong address = _context.MemoryManager.Translate(dsState.Address.Pack()); - - if (address == MemoryManager.PteUnmapped) - { - return null; - } - int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY(); int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ(); @@ -635,7 +610,7 @@ namespace Ryujinx.Graphics.Gpu.Image FormatInfo formatInfo = dsState.Format.Convert(); TextureInfo info = new TextureInfo( - address, + dsState.Address.Pack(), size.Width, size.Height, size.Depth, @@ -650,9 +625,9 @@ namespace Ryujinx.Graphics.Gpu.Image target, formatInfo); - Texture texture = FindOrCreateTexture(info, TextureSearchFlags.WithUpscale, dsState.LayerSize * 4, sizeHint); + Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint); - texture.SynchronizeMemory(); + texture?.SynchronizeMemory(); return texture; } @@ -660,12 +635,13 @@ namespace Ryujinx.Graphics.Gpu.Image /// <summary> /// Tries to find an existing texture, or create a new one if not found. /// </summary> - /// <param name="info">Texture information of the texture to be found or created</param> /// <param name="flags">The texture search flags, defines texture comparison rules</param> + /// <param name="info">Texture information of the texture to be found or created</param> /// <param name="layerSize">Size in bytes of a single texture layer</param> /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param> + /// <param name="range">Optional ranges of physical memory where the texture data is located</param> /// <returns>The texture</returns> - public Texture FindOrCreateTexture(TextureInfo info, TextureSearchFlags flags = TextureSearchFlags.None, int layerSize = 0, Size? sizeHint = null) + public Texture FindOrCreateTexture(TextureSearchFlags flags, TextureInfo info, int layerSize = 0, Size? sizeHint = null, MultiRange? range = null) { bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0; @@ -677,12 +653,28 @@ namespace Ryujinx.Graphics.Gpu.Image scaleMode = (flags & TextureSearchFlags.WithUpscale) != 0 ? TextureScaleMode.Scaled : TextureScaleMode.Eligible; } + ulong address; + + if (range != null) + { + address = range.Value.GetSubRange(0).Address; + } + else + { + address = _context.MemoryManager.Translate(info.GpuAddress); + + if (address == MemoryManager.PteUnmapped) + { + return null; + } + } + int sameAddressOverlapsCount; lock (_textures) { // Try to find a perfect texture match, with the same address and parameters. - sameAddressOverlapsCount = _textures.FindOverlaps(info.Address, ref _textureOverlaps); + sameAddressOverlapsCount = _textures.FindOverlaps(address, ref _textureOverlaps); } Texture texture = null; @@ -693,6 +685,12 @@ namespace Ryujinx.Graphics.Gpu.Image { Texture overlap = _textureOverlaps[index]; + bool rangeMatches = range != null ? overlap.Range.Equals(range.Value) : overlap.Info.GpuAddress == info.GpuAddress; + if (!rangeMatches) + { + continue; + } + TextureMatchQuality matchQuality = overlap.IsExactMatch(info, flags); if (matchQuality == TextureMatchQuality.Perfect) @@ -727,19 +725,25 @@ namespace Ryujinx.Graphics.Gpu.Image // Calculate texture sizes, used to find all overlapping textures. SizeInfo sizeInfo = info.CalculateSizeInfo(layerSize); - // Find view compatible matches. ulong size = (ulong)sizeInfo.TotalSize; + + if (range == null) + { + range = _context.MemoryManager.GetPhysicalRegions(info.GpuAddress, size); + } + + // Find view compatible matches. int overlapsCount; lock (_textures) { - overlapsCount = _textures.FindOverlaps(info.Address, size, ref _textureOverlaps); + overlapsCount = _textures.FindOverlaps(range.Value, ref _textureOverlaps); } for (int index = 0; index < overlapsCount; index++) { Texture overlap = _textureOverlaps[index]; - TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible(info, size, out int firstLayer, out int firstLevel); + TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible(info, range.Value, out int firstLayer, out int firstLevel); if (overlapCompatibility == TextureViewCompatibility.Full) { @@ -750,7 +754,7 @@ namespace Ryujinx.Graphics.Gpu.Image info = oInfo; } - texture = overlap.CreateView(oInfo, sizeInfo, firstLayer, firstLevel); + texture = overlap.CreateView(oInfo, sizeInfo, range.Value, firstLayer, firstLevel); if (overlap.IsModified) { @@ -771,7 +775,7 @@ namespace Ryujinx.Graphics.Gpu.Image // No match, create a new texture. if (texture == null) { - texture = new Texture(_context, info, sizeInfo, scaleMode); + texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode); // Step 1: Find textures that are view compatible with the new texture. // Any textures that are incompatible will contain garbage data, so they should be removed where possible. @@ -784,7 +788,7 @@ namespace Ryujinx.Graphics.Gpu.Image Texture overlap = _textureOverlaps[index]; bool overlapInCache = overlap.CacheNode != null; - TextureViewCompatibility compatibility = texture.IsViewCompatible(overlap.Info, overlap.Size, out int firstLayer, out int firstLevel); + TextureViewCompatibility compatibility = texture.IsViewCompatible(overlap.Info, overlap.Range, out int firstLayer, out int firstLevel); if (compatibility != TextureViewCompatibility.Incompatible) { @@ -812,7 +816,7 @@ namespace Ryujinx.Graphics.Gpu.Image // If the data has been modified by the CPU, then it also shouldn't be flushed. bool modified = overlap.ConsumeModified(); - bool flush = overlapInCache && !modified && (overlap.Address < texture.Address || overlap.EndAddress > texture.EndAddress) && overlap.HasViewCompatibleChild(texture); + bool flush = overlapInCache && !modified && !texture.Range.Contains(overlap.Range) && overlap.HasViewCompatibleChild(texture); setData |= modified || flush; @@ -1070,7 +1074,7 @@ namespace Ryujinx.Graphics.Gpu.Image } return new TextureInfo( - info.Address, + info.GpuAddress, width, height, depthOrLayers, diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs index 333ebaed..065844cb 100644 --- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs +++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs @@ -54,15 +54,14 @@ namespace Ryujinx.Graphics.Gpu.Image TextureInfo info = GetInfo(descriptor, out int layerSize); - // Bad address. We can't add a texture with a invalid address - // to the cache. - if (info.Address == MemoryManager.PteUnmapped) + texture = Context.Methods.TextureManager.FindOrCreateTexture(TextureSearchFlags.ForSampler, info, layerSize); + + // If this happens, then the texture address is invalid, we can't add it to the cache. + if (texture == null) { return null; } - texture = Context.Methods.TextureManager.FindOrCreateTexture(info, TextureSearchFlags.ForSampler, layerSize); - texture.IncrementReferenceCount(); Items[id] = texture; @@ -123,7 +122,8 @@ namespace Ryujinx.Graphics.Gpu.Image // If the descriptors are the same, the texture is the same, // we don't need to remove as it was not modified. Just continue. - if (texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch) + if (texture.Info.GpuAddress == descriptor.UnpackAddress() && + texture.IsExactMatch(GetInfo(descriptor, out _), TextureSearchFlags.Strict) != TextureMatchQuality.NoMatch) { continue; } @@ -143,9 +143,6 @@ namespace Ryujinx.Graphics.Gpu.Image /// <returns>The texture information</returns> private TextureInfo GetInfo(TextureDescriptor descriptor, out int layerSize) { - ulong address = Context.MemoryManager.Translate(descriptor.UnpackAddress()); - bool addressIsValid = address != MemoryManager.PteUnmapped; - int width = descriptor.UnpackWidth(); int height = descriptor.UnpackHeight(); int depthOrLayers = descriptor.UnpackDepth(); @@ -183,9 +180,11 @@ namespace Ryujinx.Graphics.Gpu.Image uint format = descriptor.UnpackFormat(); bool srgb = descriptor.UnpackSrgb(); + ulong gpuVa = descriptor.UnpackAddress(); + if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo)) { - if (addressIsValid && (int)format > 0) + if (Context.MemoryManager.IsMapped(gpuVa) && (int)format > 0) { Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb})."); } @@ -204,7 +203,7 @@ namespace Ryujinx.Graphics.Gpu.Image int maxLod = descriptor.UnpackMaxLevelInclusive(); // Linear textures don't support mipmaps, so we don't handle this case here. - if ((minLod != 0 || maxLod + 1 != levels) && target != Target.TextureBuffer && !isLinear && addressIsValid) + if ((minLod != 0 || maxLod + 1 != levels) && target != Target.TextureBuffer && !isLinear) { int depth = TextureInfo.GetDepth(target, depthOrLayers); int layers = TextureInfo.GetLayers(target, depthOrLayers); @@ -229,7 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Image // If the base level is not zero, we additionally add the mip level offset // to the address, this allows the texture manager to find the base level from the // address if there is a overlapping texture on the cache that can contain the new texture. - address += (ulong)sizeInfo.GetMipOffset(minLod); + gpuVa += (ulong)sizeInfo.GetMipOffset(minLod); width = Math.Max(1, width >> minLod); height = Math.Max(1, height >> minLod); @@ -274,7 +273,7 @@ namespace Ryujinx.Graphics.Gpu.Image } return new TextureInfo( - address, + gpuVa, width, height, depthOrLayers, |
