Initial support for separate GPU address spaces (#2394)

* Make GPU memory manager a member of GPU channel

* Move physical memory instance to the memory manager, and the caches to the physical memory

* PR feedback
This commit is contained in:
gdkchan 2021-06-29 14:32:02 -03:00 committed by GitHub
parent 8cc872fb60
commit fbb4019ed5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 780 additions and 481 deletions

View file

@ -1,4 +1,5 @@
using Ryujinx.Cpu.Tracking;
using Ryujinx.Graphics.Gpu.Memory;
using System;
namespace Ryujinx.Graphics.Gpu.Image
@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image
protected const int DescriptorSize = 0x20;
protected GpuContext Context;
protected PhysicalMemory PhysicalMemory;
protected T1[] Items;
protected T2[] DescriptorCache;
@ -38,9 +40,17 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly CpuMultiRegionHandle _memoryTracking;
private readonly Action<ulong, ulong> _modifiedDelegate;
public Pool(GpuContext context, ulong address, int maximumId)
/// <summary>
/// Creates a new instance of the GPU resource pool.
/// </summary>
/// <param name="context">GPU context that the pool belongs to</param>
/// <param name="physicalMemory">Physical memory where the resource descriptors are mapped</param>
/// <param name="address">Address of the pool in physical memory</param>
/// <param name="maximumId">Maximum index of an item on the pool (inclusive)</param>
public Pool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId)
{
Context = context;
Context = context;
PhysicalMemory = physicalMemory;
MaximumId = maximumId;
int count = maximumId + 1;
@ -53,11 +63,10 @@ namespace Ryujinx.Graphics.Gpu.Image
Address = address;
Size = size;
_memoryTracking = context.PhysicalMemory.BeginGranularTracking(address, size);
_memoryTracking = physicalMemory.BeginGranularTracking(address, size);
_modifiedDelegate = RegionModified;
}
/// <summary>
/// Gets the descriptor for a given ID.
/// </summary>
@ -65,7 +74,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The descriptor</returns>
public T2 GetDescriptor(int id)
{
return Context.PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
return PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
}
/// <summary>

View file

@ -1,3 +1,5 @@
using Ryujinx.Graphics.Gpu.Memory;
namespace Ryujinx.Graphics.Gpu.Image
{
/// <summary>
@ -11,9 +13,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the sampler pool.
/// </summary>
/// <param name="context">GPU context that the sampler pool belongs to</param>
/// <param name="physicalMemory">Physical memory where the sampler descriptors are mapped</param>
/// <param name="address">Address of the sampler pool in guest memory</param>
/// <param name="maximumId">Maximum sampler ID of the sampler pool (equal to maximum samplers minus one)</param>
public SamplerPool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { }
public SamplerPool(GpuContext context, PhysicalMemory physicalMemory, ulong address, int maximumId) : base(context, physicalMemory, address, maximumId) { }
/// <summary>
/// Gets the sampler with the given ID.

View file

@ -28,6 +28,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
private GpuContext _context;
private PhysicalMemory _physicalMemory;
private SizeInfo _sizeInfo;
@ -139,6 +140,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the cached GPU texture.
/// </summary>
/// <param name="context">GPU context that the texture belongs to</param>
/// <param name="physicalMemory">Physical memory where the texture is mapped</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>
@ -147,16 +149,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="scaleFactor">The floating point scale factor to initialize with</param>
/// <param name="scaleMode">The scale mode to initialize with</param>
private Texture(
GpuContext context,
TextureInfo info,
SizeInfo sizeInfo,
MultiRange range,
int firstLayer,
int firstLevel,
float scaleFactor,
GpuContext context,
PhysicalMemory physicalMemory,
TextureInfo info,
SizeInfo sizeInfo,
MultiRange range,
int firstLayer,
int firstLevel,
float scaleFactor,
TextureScaleMode scaleMode)
{
InitializeTexture(context, info, sizeInfo, range);
InitializeTexture(context, physicalMemory, info, sizeInfo, range);
FirstLayer = firstLayer;
FirstLevel = firstLevel;
@ -171,16 +174,23 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the cached GPU texture.
/// </summary>
/// <param name="context">GPU context that the texture belongs to</param>
/// <param name="physicalMemory">Physical memory where the texture is mapped</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, MultiRange range, TextureScaleMode scaleMode)
public Texture(
GpuContext context,
PhysicalMemory physicalMemory,
TextureInfo info,
SizeInfo sizeInfo,
MultiRange range,
TextureScaleMode scaleMode)
{
ScaleFactor = 1f; // Texture is first loaded at scale 1x.
ScaleMode = scaleMode;
InitializeTexture(context, info, sizeInfo, range);
InitializeTexture(context, physicalMemory, info, sizeInfo, range);
}
/// <summary>
@ -189,14 +199,21 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Other fields are initialized with their default values.
/// </summary>
/// <param name="context">GPU context that the texture belongs to</param>
/// <param name="physicalMemory">Physical memory where the texture is mapped</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>
private void InitializeTexture(GpuContext context, TextureInfo info, SizeInfo sizeInfo, MultiRange range)
private void InitializeTexture(
GpuContext context,
PhysicalMemory physicalMemory,
TextureInfo info,
SizeInfo sizeInfo,
MultiRange range)
{
_context = context;
_context = context;
_physicalMemory = physicalMemory;
_sizeInfo = sizeInfo;
Range = range;
Range = range;
SetInfo(info);
@ -255,7 +272,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="hasMipViews">True if the texture will have mip views</param>
public void InitializeGroup(bool hasLayerViews, bool hasMipViews)
{
Group = new TextureGroup(_context, this);
Group = new TextureGroup(_context, _physicalMemory, this);
Group.Initialize(ref _sizeInfo, hasLayerViews, hasMipViews);
}
@ -276,6 +293,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
Texture texture = new Texture(
_context,
_physicalMemory,
info,
sizeInfo,
range,
@ -638,7 +656,7 @@ namespace Ryujinx.Graphics.Gpu.Image
BlacklistScale();
}
ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Range);
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Range);
IsModified = false;
@ -805,11 +823,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (tracked)
{
_context.PhysicalMemory.Write(Range, GetTextureDataFromGpu(tracked));
_physicalMemory.Write(Range, GetTextureDataFromGpu(tracked));
}
else
{
_context.PhysicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(tracked));
_physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(tracked));
}
}
@ -846,7 +864,7 @@ namespace Ryujinx.Graphics.Gpu.Image
texture = _flushHostTexture = GetScaledHostTexture(1f, _flushHostTexture);
}
_context.PhysicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(false, texture));
_physicalMemory.WriteUntracked(Range, GetTextureDataFromGpu(false, texture));
});
}
@ -1280,7 +1298,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_viewStorage.RemoveView(this);
}
_context.Methods.TextureCache.RemoveTextureFromCache(this);
_physicalMemory.TextureCache.RemoveTextureFromCache(this);
}
Debug.Assert(newRefCount >= 0);

View file

@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="samplerIndex">Type of the sampler pool indexing used for bound samplers</param>
public void SetSamplerPool(ulong gpuVa, int maximumId, SamplerIndex samplerIndex)
{
ulong address = _context.MemoryManager.Translate(gpuVa);
ulong address = _channel.MemoryManager.Translate(gpuVa);
if (_samplerPool != null)
{
@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_samplerPool.Dispose();
}
_samplerPool = new SamplerPool(_context, address, maximumId);
_samplerPool = new SamplerPool(_context, _channel.MemoryManager.Physical, address, maximumId);
_samplerIndex = samplerIndex;
}
@ -142,7 +142,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="maximumId">Maximum ID of the pool (total count minus one)</param>
public void SetTexturePool(ulong gpuVa, int maximumId)
{
ulong address = _context.MemoryManager.Translate(gpuVa);
ulong address = _channel.MemoryManager.Translate(gpuVa);
_texturePoolAddress = address;
_texturePoolMaximumId = maximumId;
@ -228,6 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public void CommitBindings()
{
TexturePool texturePool = _texturePoolCache.FindOrCreate(
_channel,
_texturePoolAddress,
_texturePoolMaximumId);
@ -437,9 +438,9 @@ namespace Ryujinx.Graphics.Gpu.Image
var poolState = state.Get<PoolState>(MethodOffset.TexturePoolState);
ulong poolAddress = _context.MemoryManager.Translate(poolState.Address.Pack());
ulong poolAddress = _channel.MemoryManager.Translate(poolState.Address.Pack());
TexturePool texturePool = _texturePoolCache.FindOrCreate(poolAddress, poolState.MaximumId);
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, poolState.MaximumId);
return texturePool.GetDescriptor(textureId);
}
@ -455,12 +456,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The packed texture and sampler ID (the real texture handle)</returns>
private int ReadPackedId(int stageIndex, int wordOffset, int textureBufferIndex, int samplerBufferIndex)
{
var bufferManager = _context.Methods.BufferCache;
ulong textureBufferAddress = _isCompute
? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
int handle = _context.PhysicalMemory.Read<int>(textureBufferAddress + (ulong)(wordOffset & HandleMask) * 4);
int handle = _channel.MemoryManager.Physical.Read<int>(textureBufferAddress + (ulong)(wordOffset & HandleMask) * 4);
// The "wordOffset" (which is really the immediate value used on texture instructions on the shader)
// is a 13-bit value. However, in order to also support separate samplers and textures (which uses
@ -474,7 +474,7 @@ namespace Ryujinx.Graphics.Gpu.Image
? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
handle |= _context.PhysicalMemory.Read<int>(samplerBufferAddress + (ulong)((wordOffset >> HandleHigh) - 1) * 4);
handle |= _channel.MemoryManager.Physical.Read<int>(samplerBufferAddress + (ulong)((wordOffset >> HandleHigh) - 1) * 4);
}
return handle;
@ -514,7 +514,6 @@ namespace Ryujinx.Graphics.Gpu.Image
public void Dispose()
{
_samplerPool?.Dispose();
_texturePoolCache.Dispose();
}
}
}

View file

@ -32,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private const int OverlapsBufferMaxCapacity = 10000;
private readonly GpuContext _context;
private readonly PhysicalMemory _physicalMemory;
private readonly MultiRangeList<Texture> _textures;
@ -44,9 +45,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the texture manager.
/// </summary>
/// <param name="context">The GPU context that the texture manager belongs to</param>
public TextureCache(GpuContext context)
/// <param name="physicalMemory">Physical memory where the textures managed by this cache are mapped</param>
public TextureCache(GpuContext context, PhysicalMemory physicalMemory)
{
_context = context;
_physicalMemory = physicalMemory;
_textures = new MultiRangeList<Texture>();
@ -68,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Image
lock (_textures)
{
overlapCount = _textures.FindOverlaps(_context.MemoryManager.Translate(e.Address), e.Size, ref overlaps);
overlapCount = _textures.FindOverlaps(((MemoryManager)sender).Translate(e.Address), e.Size, ref overlaps);
}
for (int i = 0; i < overlapCount; i++)
@ -139,13 +142,20 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Tries to find an existing texture, or create a new one if not found.
/// </summary>
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
/// <param name="copyTexture">Copy texture to find or create</param>
/// <param name="offset">Offset to be added to the physical texture address</param>
/// <param name="formatInfo">Format information of the copy texture</param>
/// <param name="preferScaling">Indicates if the texture should be scaled from the start</param>
/// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
/// <returns>The texture</returns>
public Texture FindOrCreateTexture(CopyTexture copyTexture, ulong offset, FormatInfo formatInfo, bool preferScaling = true, Size? sizeHint = null)
public Texture FindOrCreateTexture(
MemoryManager memoryManager,
CopyTexture copyTexture,
ulong offset,
FormatInfo formatInfo,
bool preferScaling = true,
Size? sizeHint = null)
{
int gobBlocksInY = copyTexture.MemoryLayout.UnpackGobBlocksInY();
int gobBlocksInZ = copyTexture.MemoryLayout.UnpackGobBlocksInZ();
@ -184,7 +194,7 @@ namespace Ryujinx.Graphics.Gpu.Image
flags |= TextureSearchFlags.WithUpscale;
}
Texture texture = FindOrCreateTexture(flags, info, 0, sizeHint);
Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0, sizeHint);
texture?.SynchronizeMemory();
@ -194,12 +204,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Tries to find an existing texture, or create a new one if not found.
/// </summary>
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
/// <param name="colorState">Color buffer texture to find or create</param>
/// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
/// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
/// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
/// <returns>The texture</returns>
public Texture FindOrCreateTexture(RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint)
public Texture FindOrCreateTexture(MemoryManager memoryManager, RtColorState colorState, int samplesInX, int samplesInY, Size sizeHint)
{
bool isLinear = colorState.MemoryLayout.UnpackIsLinear();
@ -263,7 +274,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int layerSize = !isLinear ? colorState.LayerSize * 4 : 0;
Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
texture?.SynchronizeMemory();
@ -273,13 +284,20 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Tries to find an existing texture, or create a new one if not found.
/// </summary>
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
/// <param name="dsState">Depth-stencil buffer texture to find or create</param>
/// <param name="size">Size of the depth-stencil texture</param>
/// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
/// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
/// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
/// <returns>The texture</returns>
public Texture FindOrCreateTexture(RtDepthStencilState dsState, Size3D size, int samplesInX, int samplesInY, Size sizeHint)
public Texture FindOrCreateTexture(
MemoryManager memoryManager,
RtDepthStencilState dsState,
Size3D size,
int samplesInX,
int samplesInY,
Size sizeHint)
{
int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY();
int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ();
@ -306,7 +324,7 @@ namespace Ryujinx.Graphics.Gpu.Image
target,
formatInfo);
Texture texture = FindOrCreateTexture(TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
texture?.SynchronizeMemory();
@ -316,13 +334,20 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Tries to find an existing texture, or create a new one if not found.
/// </summary>
/// <param name="memoryManager">GPU memory manager where the texture is mapped</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(TextureSearchFlags flags, TextureInfo info, int layerSize = 0, Size? sizeHint = null, MultiRange? range = null)
public Texture FindOrCreateTexture(
MemoryManager memoryManager,
TextureSearchFlags flags,
TextureInfo info,
int layerSize = 0,
Size? sizeHint = null,
MultiRange? range = null)
{
bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0;
@ -342,7 +367,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
else
{
address = _context.MemoryManager.Translate(info.GpuAddress);
address = memoryManager.Translate(info.GpuAddress);
if (address == MemoryManager.PteUnmapped)
{
@ -371,22 +396,26 @@ namespace Ryujinx.Graphics.Gpu.Image
if (matchQuality != TextureMatchQuality.NoMatch)
{
// If the parameters match, we need to make sure the texture is mapped to the same memory regions.
// If a range of memory was supplied, just check if the ranges match.
if (range != null && !overlap.Range.Equals(range.Value))
if (range != null)
{
continue;
// If a range of memory was supplied, just check if the ranges match.
if (!overlap.Range.Equals(range.Value))
{
continue;
}
}
// If no range was supplied, we can check if the GPU virtual address match. If they do,
// we know the textures are located at the same memory region.
// If they don't, it may still be mapped to the same physical region, so we
// do a more expensive check to tell if they are mapped into the same physical regions.
// If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
!_context.MemoryManager.CompareRange(overlap.Range, info.GpuAddress))
else
{
continue;
// If no range was supplied, we can check if the GPU virtual address match. If they do,
// we know the textures are located at the same memory region.
// If they don't, it may still be mapped to the same physical region, so we
// do a more expensive check to tell if they are mapped into the same physical regions.
// If the GPU VA for the texture has ever been unmapped, then the range must be checked regardless.
if ((overlap.Info.GpuAddress != info.GpuAddress || overlap.ChangedMapping) &&
!memoryManager.CompareRange(overlap.Range, info.GpuAddress))
{
continue;
}
}
}
@ -426,7 +455,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (range == null)
{
range = _context.MemoryManager.GetPhysicalRegions(info.GpuAddress, size);
range = memoryManager.GetPhysicalRegions(info.GpuAddress, size);
}
// Find view compatible matches.
@ -495,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{
// Only copy compatible. If there's another choice for a FULLY compatible texture, choose that instead.
texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode);
texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode);
texture.InitializeGroup(true, true);
texture.InitializeData(false, false);
@ -531,7 +560,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// No match, create a new texture.
if (texture == null)
{
texture = new Texture(_context, info, sizeInfo, range.Value, scaleMode);
texture = new Texture(_context, _physicalMemory, 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.
@ -722,14 +751,15 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary>
/// Tries to find an existing texture matching the given buffer copy destination. If none is found, returns null.
/// </summary>
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
/// <param name="tex">The texture information</param>
/// <param name="cbp">The copy buffer parameters</param>
/// <param name="swizzle">The copy buffer swizzle</param>
/// <param name="linear">True if the texture has a linear layout, false otherwise</param>
/// <returns>A matching texture, or null if there is no match</returns>
public Texture FindTexture(CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
public Texture FindTexture(MemoryManager memoryManager, CopyBufferTexture tex, CopyBufferParams cbp, CopyBufferSwizzle swizzle, bool linear)
{
ulong address = _context.MemoryManager.Translate(cbp.DstAddress.Pack());
ulong address = memoryManager.Translate(cbp.DstAddress.Pack());
if (address == MemoryManager.PteUnmapped)
{

View file

@ -1,5 +1,6 @@
using Ryujinx.Cpu.Tracking;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture;
using Ryujinx.Memory.Range;
using System;
@ -28,7 +29,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public bool HasCopyDependencies { get; set; }
private GpuContext _context;
private readonly GpuContext _context;
private readonly PhysicalMemory _physicalMemory;
private int[] _allOffsets;
private int[] _sliceSizes;
@ -51,11 +53,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Create a new texture group.
/// </summary>
/// <param name="context">GPU context that the texture group belongs to</param>
/// <param name="physicalMemory">Physical memory where the <paramref name="storage"/> texture is mapped</param>
/// <param name="storage">The storage texture for this group</param>
public TextureGroup(GpuContext context, Texture storage)
public TextureGroup(GpuContext context, PhysicalMemory physicalMemory, Texture storage)
{
Storage = storage;
_context = context;
_physicalMemory = physicalMemory;
_is3D = storage.Info.Target == Target.Texture3D;
_layers = storage.Info.GetSlices();
@ -211,7 +215,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int endOffset = (offsetIndex + 1 == _allOffsets.Length) ? (int)Storage.Size : _allOffsets[offsetIndex + 1];
int size = endOffset - offset;
ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Storage.Range.GetSlice((ulong)offset, (ulong)size));
data = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel, true);
@ -561,7 +565,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>A CpuRegionHandle covering the given range</returns>
private CpuRegionHandle GenerateHandle(ulong address, ulong size)
{
return _context.PhysicalMemory.BeginTracking(address, size);
return _physicalMemory.BeginTracking(address, size);
}
/// <summary>

View file

@ -13,6 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Image
class TexturePool : Pool<Texture, TextureDescriptor>
{
private int _sequenceNumber;
private readonly GpuChannel _channel;
private readonly ConcurrentQueue<Texture> _dereferenceQueue = new ConcurrentQueue<Texture>();
/// <summary>
@ -24,9 +25,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs a new instance of the texture pool.
/// </summary>
/// <param name="context">GPU context that the texture pool belongs to</param>
/// <param name="channel">GPU channel that the texture pool belongs to</param>
/// <param name="address">Address of the texture pool in guest memory</param>
/// <param name="maximumId">Maximum texture ID of the texture pool (equal to maximum textures minus one)</param>
public TexturePool(GpuContext context, ulong address, int maximumId) : base(context, address, maximumId) { }
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
{
_channel = channel;
}
/// <summary>
/// Gets the texture with the given ID.
@ -57,7 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ProcessDereferenceQueue();
texture = Context.Methods.TextureCache.FindOrCreateTexture(TextureSearchFlags.ForSampler, info, layerSize);
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
// If this happens, then the texture address is invalid, we can't add it to the cache.
if (texture == null)
@ -148,7 +153,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (texture != null)
{
TextureDescriptor descriptor = Context.PhysicalMemory.Read<TextureDescriptor>(address);
TextureDescriptor descriptor = PhysicalMemory.Read<TextureDescriptor>(address);
// If the descriptors are the same, the texture is the same,
// we don't need to remove as it was not modified. Just continue.
@ -214,7 +219,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
{
if (Context.MemoryManager.IsMapped(gpuVa) && (int)format > 0)
if (gpuVa != 0 && (int)format > 0)
{
Logger.Error?.Print(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
}

View file

@ -8,13 +8,12 @@ namespace Ryujinx.Graphics.Gpu.Image
/// This can keep multiple texture pools, and return the current one as needed.
/// It is useful for applications that uses multiple texture pools.
/// </summary>
class TexturePoolCache : IDisposable
class TexturePoolCache
{
private const int MaxCapacity = 4;
private GpuContext _context;
private LinkedList<TexturePool> _pools;
private readonly GpuContext _context;
private readonly LinkedList<TexturePool> _pools;
/// <summary>
/// Constructs a new instance of the texture pool.
@ -23,17 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Image
public TexturePoolCache(GpuContext context)
{
_context = context;
_pools = new LinkedList<TexturePool>();
}
/// <summary>
/// Finds a cache texture pool, or creates a new one if not found.
/// </summary>
/// <param name="channel">GPU channel that the texture pool cache belongs to</param>
/// <param name="address">Start address of the texture pool</param>
/// <param name="maximumId">Maximum ID of the texture pool</param>
/// <returns>The found or newly created texture pool</returns>
public TexturePool FindOrCreate(ulong address, int maximumId)
public TexturePool FindOrCreate(GpuChannel channel, ulong address, int maximumId)
{
TexturePool pool;
@ -56,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
// If not found, create a new one.
pool = new TexturePool(_context, address, maximumId);
pool = new TexturePool(_context, channel, address, maximumId);
pool.CacheNode = _pools.AddLast(pool);
@ -73,19 +72,5 @@ namespace Ryujinx.Graphics.Gpu.Image
return pool;
}
/// <summary>
/// Disposes the texture pool cache.
/// It's an error to use the texture pool cache after disposal.
/// </summary>
public void Dispose()
{
foreach (TexturePool pool in _pools)
{
pool.Dispose();
}
_pools.Clear();
}
}
}