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
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue