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
This commit is contained in:
parent
3bad321d2b
commit
c4f56c5704
18 changed files with 1141 additions and 167 deletions
|
@ -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;
|
||||
}
|
||||
|
@ -1045,17 +1046,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
HostTexture = hostTexture;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue