mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-01-12 21:59:12 +00:00
Delete PhysicalMemory field and replace it with a physical memory list, implement MapForeign for mapping memory from another process
This commit is contained in:
parent
640ea94cd8
commit
4d3f5e3818
8 changed files with 261 additions and 97 deletions
|
@ -412,8 +412,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var bufferCache = memoryManager.GetBackingMemory(dstGpuVa).BufferCache;
|
|
||||||
|
|
||||||
if (remap &&
|
if (remap &&
|
||||||
_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.ConstA &&
|
_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.ConstA &&
|
||||||
_state.State.SetRemapComponentsDstY == SetRemapComponentsDst.ConstA &&
|
_state.State.SetRemapComponentsDstY == SetRemapComponentsDst.ConstA &&
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MemoryManager(physicalMemory);
|
return new MemoryManager(this, physicalMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -40,10 +40,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
private GpuContext _context;
|
private GpuContext _context;
|
||||||
private PhysicalMemory _physicalMemory;
|
|
||||||
|
|
||||||
private SizeInfo _sizeInfo;
|
private SizeInfo _sizeInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backing memory for the texture.
|
||||||
|
/// </summary>
|
||||||
|
public PhysicalMemory PhysicalMemory { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Texture format.
|
/// Texture format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -251,7 +254,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
MultiRange range)
|
MultiRange range)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_physicalMemory = physicalMemory;
|
PhysicalMemory = physicalMemory;
|
||||||
_sizeInfo = sizeInfo;
|
_sizeInfo = sizeInfo;
|
||||||
Range = range;
|
Range = range;
|
||||||
|
|
||||||
|
@ -315,7 +318,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="incompatibleOverlaps">Groups that overlap with this one but are incompatible</param>
|
/// <param name="incompatibleOverlaps">Groups that overlap with this one but are incompatible</param>
|
||||||
public void InitializeGroup(bool hasLayerViews, bool hasMipViews, List<TextureIncompatibleOverlap> incompatibleOverlaps)
|
public void InitializeGroup(bool hasLayerViews, bool hasMipViews, List<TextureIncompatibleOverlap> incompatibleOverlaps)
|
||||||
{
|
{
|
||||||
Group = new TextureGroup(_context, _physicalMemory, this, incompatibleOverlaps);
|
Group = new TextureGroup(_context, PhysicalMemory, this, incompatibleOverlaps);
|
||||||
|
|
||||||
Group.Initialize(ref _sizeInfo, hasLayerViews, hasMipViews);
|
Group.Initialize(ref _sizeInfo, hasLayerViews, hasMipViews);
|
||||||
}
|
}
|
||||||
|
@ -336,7 +339,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
Texture texture = new(
|
Texture texture = new(
|
||||||
_context,
|
_context,
|
||||||
_physicalMemory,
|
PhysicalMemory,
|
||||||
info,
|
info,
|
||||||
sizeInfo,
|
sizeInfo,
|
||||||
range,
|
range,
|
||||||
|
@ -636,7 +639,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SynchronizeFull()
|
public void SynchronizeFull()
|
||||||
{
|
{
|
||||||
ReadOnlySpan<byte> data = _physicalMemory.GetSpan(Range);
|
ReadOnlySpan<byte> data = PhysicalMemory.GetSpan(Range);
|
||||||
|
|
||||||
// If the host does not support ASTC compression, we need to do the decompression.
|
// If the host does not support ASTC compression, we need to do the decompression.
|
||||||
// The decompression is slow, so we want to avoid it as much as possible.
|
// The decompression is slow, so we want to avoid it as much as possible.
|
||||||
|
@ -1027,7 +1030,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="texture">The specific host texture to flush. Defaults to this texture</param>
|
/// <param name="texture">The specific host texture to flush. Defaults to this texture</param>
|
||||||
public void FlushTextureDataToGuest(bool tracked, ITexture texture = null)
|
public void FlushTextureDataToGuest(bool tracked, ITexture texture = null)
|
||||||
{
|
{
|
||||||
using WritableRegion region = _physicalMemory.GetWritableRegion(Range, tracked);
|
using WritableRegion region = PhysicalMemory.GetWritableRegion(Range, tracked);
|
||||||
|
|
||||||
GetTextureDataFromGpu(region.Memory.Span, tracked, texture);
|
GetTextureDataFromGpu(region.Memory.Span, tracked, texture);
|
||||||
}
|
}
|
||||||
|
@ -1419,7 +1422,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
Group.SignalModified(this);
|
Group.SignalModified(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_physicalMemory.TextureCache.Lift(this);
|
PhysicalMemory.TextureCache.Lift(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1440,7 +1443,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
Group.SignalModifying(this, bound);
|
Group.SignalModifying(this, bound);
|
||||||
}
|
}
|
||||||
|
|
||||||
_physicalMemory.TextureCache.Lift(this);
|
PhysicalMemory.TextureCache.Lift(this);
|
||||||
|
|
||||||
if (bound)
|
if (bound)
|
||||||
{
|
{
|
||||||
|
@ -1528,7 +1531,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (ShortCacheEntry != null)
|
if (ShortCacheEntry != null)
|
||||||
{
|
{
|
||||||
_physicalMemory.TextureCache.RemoveShortCache(this);
|
PhysicalMemory.TextureCache.RemoveShortCache(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1557,7 +1560,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_viewStorage.RemoveView(this);
|
_viewStorage.RemoveView(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_physicalMemory.TextureCache.RemoveTextureFromCache(this);
|
PhysicalMemory.TextureCache.RemoveTextureFromCache(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(newRefCount >= 0);
|
Debug.Assert(newRefCount >= 0);
|
||||||
|
@ -1613,7 +1616,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// If this is called from another thread (unmapped), the short cache will
|
// If this is called from another thread (unmapped), the short cache will
|
||||||
// have to remove this texture on a future tick.
|
// have to remove this texture on a future tick.
|
||||||
|
|
||||||
_physicalMemory.TextureCache.RemoveShortCache(this);
|
PhysicalMemory.TextureCache.RemoveShortCache(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidatedSequence++;
|
InvalidatedSequence++;
|
||||||
|
|
|
@ -524,8 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind
|
||||||
// to ensure we're not using a old buffer that was already deleted.
|
// to ensure we're not using a old buffer that was already deleted.
|
||||||
var bufferCache = _channel.MemoryManager.GetBackingMemory(descriptor.UnpackAddress()).BufferCache;
|
_channel.BufferManager.SetBufferTextureStorage(stage, texture, hostTexture, bindingInfo, bindingInfo.Format, false);
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, bufferCache, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
|
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
|
@ -662,8 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
format = texture.Format;
|
format = texture.Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufferCache = _channel.MemoryManager.GetBackingMemory(descriptor.UnpackAddress()).BufferCache;
|
_channel.BufferManager.SetBufferTextureStorage(stage, texture, hostTexture, bindingInfo, format, true);
|
||||||
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, bufferCache, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
|
|
||||||
|
|
||||||
// Cache is not used for buffer texture, it must always rebind.
|
// Cache is not used for buffer texture, it must always rebind.
|
||||||
state.CachedTexture = null;
|
state.CachedTexture = null;
|
||||||
|
|
|
@ -490,17 +490,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
|
var isStore = binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
|
||||||
var range = binding.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
|
var range = binding.BufferCache.GetBufferRange(binding.Address, binding.Size, isStore);
|
||||||
binding.Texture.SetStorage(range);
|
binding.HostTexture.SetStorage(range);
|
||||||
|
|
||||||
// The texture must be rebound to use the new storage if it was updated.
|
// The texture must be rebound to use the new storage if it was updated.
|
||||||
|
|
||||||
if (binding.IsImage)
|
if (binding.IsImage)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format);
|
_context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.HostTexture, binding.Format);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetTextureAndSampler(binding.Stage, binding.BindingInfo.Binding, binding.Texture, null);
|
_context.Renderer.Pipeline.SetTextureAndSampler(binding.Stage, binding.BindingInfo.Binding, binding.HostTexture, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,25 +801,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stage">Shader stage accessing the texture</param>
|
/// <param name="stage">Shader stage accessing the texture</param>
|
||||||
/// <param name="texture">Buffer texture</param>
|
/// <param name="texture">Buffer texture</param>
|
||||||
/// <param name="bufferCache">Buffer cache that owns the buffer texture</param>
|
/// <param name="hostTexture">Buffer host texture</param>
|
||||||
/// <param name="address">Address of the buffer in memory</param>
|
|
||||||
/// <param name="size">Size of the buffer in bytes</param>
|
|
||||||
/// <param name="bindingInfo">Binding info for the buffer texture</param>
|
/// <param name="bindingInfo">Binding info for the buffer texture</param>
|
||||||
/// <param name="format">Format of the buffer texture</param>
|
/// <param name="format">Format of the buffer texture</param>
|
||||||
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||||
public void SetBufferTextureStorage(
|
public void SetBufferTextureStorage(
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
ITexture texture,
|
Image.Texture texture,
|
||||||
BufferCache bufferCache,
|
ITexture hostTexture,
|
||||||
ulong address,
|
|
||||||
ulong size,
|
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
Format format,
|
Format format,
|
||||||
bool isImage)
|
bool isImage)
|
||||||
{
|
{
|
||||||
bufferCache.CreateBuffer(address, size);
|
var binding = new BufferTextureBinding(stage, texture, hostTexture, bindingInfo, format, isImage);
|
||||||
|
|
||||||
_bufferTextures.Add(new BufferTextureBinding(stage, texture, bufferCache, address, size, bindingInfo, format, isImage));
|
texture.PhysicalMemory.BufferCache.CreateBuffer(binding.Address, binding.Size);
|
||||||
|
|
||||||
|
_bufferTextures.Add(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -17,22 +17,27 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The buffer texture.
|
/// The buffer texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ITexture Texture { get; }
|
public Image.Texture Texture { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer host texture.
|
||||||
|
/// </summary>
|
||||||
|
public ITexture HostTexture { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Buffer cache that owns the buffer.
|
/// Buffer cache that owns the buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BufferCache BufferCache { get; }
|
public BufferCache BufferCache => Texture.PhysicalMemory.BufferCache;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base address of the buffer binding.
|
/// The base address of the buffer binding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong Address { get; }
|
public ulong Address => Texture.Range.GetSubRange(0).Address;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The size of the buffer binding in bytes.
|
/// The size of the buffer binding in bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong Size { get; }
|
public ulong Size => Texture.Size;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The image or sampler binding info for the buffer texture.
|
/// The image or sampler binding info for the buffer texture.
|
||||||
|
@ -54,27 +59,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stage">Shader stage accessing the texture</param>
|
/// <param name="stage">Shader stage accessing the texture</param>
|
||||||
/// <param name="texture">Buffer texture</param>
|
/// <param name="texture">Buffer texture</param>
|
||||||
/// <param name="bufferCache">Buffer cache that owns the buffer</param>
|
/// <param name="hostTexture">Buffer host texture</param>
|
||||||
/// <param name="address">Base address</param>
|
|
||||||
/// <param name="size">Size in bytes</param>
|
|
||||||
/// <param name="bindingInfo">Binding info</param>
|
/// <param name="bindingInfo">Binding info</param>
|
||||||
/// <param name="format">Binding format</param>
|
/// <param name="format">Binding format</param>
|
||||||
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||||
public BufferTextureBinding(
|
public BufferTextureBinding(
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
ITexture texture,
|
Image.Texture texture,
|
||||||
BufferCache bufferCache,
|
ITexture hostTexture,
|
||||||
ulong address,
|
|
||||||
ulong size,
|
|
||||||
TextureBindingInfo bindingInfo,
|
TextureBindingInfo bindingInfo,
|
||||||
Format format,
|
Format format,
|
||||||
bool isImage)
|
bool isImage)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
BufferCache = bufferCache;
|
HostTexture = hostTexture;
|
||||||
Address = address;
|
|
||||||
Size = size;
|
|
||||||
BindingInfo = bindingInfo;
|
BindingInfo = bindingInfo;
|
||||||
Format = format;
|
Format = format;
|
||||||
IsImage = isImage;
|
IsImage = isImage;
|
||||||
|
|
|
@ -34,10 +34,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
public event EventHandler<UnmapEventArgs> MemoryUnmapped;
|
public event EventHandler<UnmapEventArgs> MemoryUnmapped;
|
||||||
|
|
||||||
/// <summary>
|
private readonly GpuContext _context;
|
||||||
/// Physical memory where the virtual memory is mapped into.
|
private readonly List<PhysicalMemory> _physicalMemoryList;
|
||||||
/// </summary>
|
private readonly Dictionary<PhysicalMemory, byte> _physicalMemoryMap;
|
||||||
private PhysicalMemory Physical { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cache of GPU counters.
|
/// Cache of GPU counters.
|
||||||
|
@ -47,14 +46,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the GPU memory manager.
|
/// Creates a new instance of the GPU memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="context">GPU context</param>
|
||||||
/// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
|
/// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
|
||||||
internal MemoryManager(PhysicalMemory physicalMemory)
|
internal MemoryManager(GpuContext context, PhysicalMemory physicalMemory)
|
||||||
{
|
{
|
||||||
Physical = physicalMemory;
|
_context = context;
|
||||||
|
|
||||||
|
_physicalMemoryList = new List<PhysicalMemory>()
|
||||||
|
{
|
||||||
|
physicalMemory
|
||||||
|
};
|
||||||
|
|
||||||
|
_physicalMemoryMap = new Dictionary<PhysicalMemory, byte>
|
||||||
|
{
|
||||||
|
{ physicalMemory, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
CounterCache = new CounterCache();
|
CounterCache = new CounterCache();
|
||||||
_pageTable = new ulong[PtLvl0Size][];
|
_pageTable = new ulong[PtLvl0Size][];
|
||||||
MemoryUnmapped += Physical.TextureCache.MemoryUnmappedHandler;
|
MemoryUnmapped += physicalMemory.TextureCache.MemoryUnmappedHandler;
|
||||||
MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
|
MemoryUnmapped += physicalMemory.BufferCache.MemoryUnmappedHandler;
|
||||||
MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
|
MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,19 +75,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="rebind">Action to be performed when the buffer cache changes</param>
|
/// <param name="rebind">Action to be performed when the buffer cache changes</param>
|
||||||
internal void AttachToChannel(Action rebind)
|
internal void AttachToChannel(Action rebind)
|
||||||
{
|
{
|
||||||
Physical.IncrementReferenceCount();
|
PhysicalMemory physicalMemory = GetOwnPhysicalMemory();
|
||||||
Physical.BufferCache.NotifyBuffersModified += rebind;
|
|
||||||
Physical.BufferCache.QueuePrune();
|
physicalMemory.IncrementReferenceCount();
|
||||||
|
physicalMemory.BufferCache.NotifyBuffersModified += rebind;
|
||||||
|
physicalMemory.BufferCache.QueuePrune();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attaches the memory manager to a new GPU channel.
|
/// Detaches the memory manager from a GPU channel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rebind">Action that was performed when the buffer cache changed</param>
|
/// <param name="rebind">Action that was performed when the buffer cache changed</param>
|
||||||
internal void DetachFromChannel(Action rebind)
|
internal void DetachFromChannel(Action rebind)
|
||||||
{
|
{
|
||||||
Physical.BufferCache.NotifyBuffersModified -= rebind;
|
PhysicalMemory physicalMemory = GetOwnPhysicalMemory();
|
||||||
Physical.DecrementReferenceCount();
|
|
||||||
|
physicalMemory.BufferCache.NotifyBuffersModified -= rebind;
|
||||||
|
physicalMemory.DecrementReferenceCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -84,7 +99,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void QueuePrune()
|
internal void QueuePrune()
|
||||||
{
|
{
|
||||||
Physical.BufferCache.QueuePrune();
|
GetOwnPhysicalMemory().BufferCache.QueuePrune();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -100,15 +115,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if (IsContiguous(va, size))
|
if (IsContiguous(va, size))
|
||||||
{
|
{
|
||||||
ulong address = Translate(va);
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
if (tracked)
|
if (tracked)
|
||||||
{
|
{
|
||||||
return Physical.ReadTracked<T>(address);
|
return physicalMemory.ReadTracked<T>(address);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Physical.Read<T>(address);
|
return physicalMemory.Read<T>(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -132,7 +147,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
if (IsContiguous(va, size))
|
if (IsContiguous(va, size))
|
||||||
{
|
{
|
||||||
return Physical.GetSpan(Translate(va), size, tracked);
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
|
return physicalMemory.GetSpan(address, size, tracked);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -157,7 +174,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
bool isContiguous = true;
|
bool isContiguous = true;
|
||||||
int mappedSize;
|
int mappedSize;
|
||||||
|
|
||||||
if (ValidateAddress(va) && GetPte(va) != PteUnmapped && Physical.IsMapped(Translate(va)))
|
if (ValidateAddress(va) && IsMappedOnGpuAndPhysical(va))
|
||||||
{
|
{
|
||||||
ulong endVa = va + (ulong)size;
|
ulong endVa = va + (ulong)size;
|
||||||
ulong endVaAligned = (endVa + PageMask) & ~PageMask;
|
ulong endVaAligned = (endVa + PageMask) & ~PageMask;
|
||||||
|
@ -170,7 +187,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
ulong nextVa = currentVa + PageSize;
|
ulong nextVa = currentVa + PageSize;
|
||||||
ulong nextPa = Translate(nextVa);
|
ulong nextPa = Translate(nextVa);
|
||||||
|
|
||||||
if (!ValidateAddress(nextVa) || GetPte(nextVa) == PteUnmapped || !Physical.IsMapped(nextPa))
|
if (!ValidateAddress(nextVa) || !IsMappedOnGpuAndPhysical(nextVa))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +216,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if (isContiguous)
|
if (isContiguous)
|
||||||
{
|
{
|
||||||
return Physical.GetSpan(Translate(va), mappedSize, tracked);
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
|
return physicalMemory.GetSpan(address, mappedSize, tracked);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -211,6 +230,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a page of memory is mapped on the GPU and its backing memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="va">GPU virtual address of the page</param>
|
||||||
|
/// <returns>True if mapped, false otherwise</returns>
|
||||||
|
private bool IsMappedOnGpuAndPhysical(ulong va)
|
||||||
|
{
|
||||||
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
|
if (address == PteUnmapped)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return physicalMemory.IsMapped(address);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads data from a possibly non-contiguous region of GPU mapped memory.
|
/// Reads data from a possibly non-contiguous region of GPU mapped memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -228,22 +264,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if ((va & PageMask) != 0)
|
if ((va & PageMask) != 0)
|
||||||
{
|
{
|
||||||
ulong pa = Translate(va);
|
(PhysicalMemory physicalMemory, ulong pa) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
||||||
|
|
||||||
Physical.GetSpan(pa, size, tracked).CopyTo(data[..size]);
|
physicalMemory.GetSpan(pa, size, tracked).CopyTo(data[..size]);
|
||||||
|
|
||||||
offset += size;
|
offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; offset < data.Length; offset += size)
|
for (; offset < data.Length; offset += size)
|
||||||
{
|
{
|
||||||
ulong pa = Translate(va + (ulong)offset);
|
(PhysicalMemory physicalMemory, ulong pa) = TranslateWithPhysicalMemory(va + (ulong)offset);
|
||||||
|
|
||||||
size = Math.Min(data.Length - offset, (int)PageSize);
|
size = Math.Min(data.Length - offset, (int)PageSize);
|
||||||
|
|
||||||
Physical.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
|
physicalMemory.GetSpan(pa, size, tracked).CopyTo(data.Slice(offset, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +294,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
if (IsContiguous(va, size))
|
if (IsContiguous(va, size))
|
||||||
{
|
{
|
||||||
return Physical.GetWritableRegion(Translate(va), size, tracked);
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
|
return physicalMemory.GetWritableRegion(address, size, tracked);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -288,7 +326,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="data">The data to be written</param>
|
/// <param name="data">The data to be written</param>
|
||||||
public void Write(ulong va, ReadOnlySpan<byte> data)
|
public void Write(ulong va, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
WriteImpl(va, data, Physical.Write);
|
WriteImpl(va, data, (physical, va, data) => physical.Write(va, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -298,7 +336,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="data">The data to be written</param>
|
/// <param name="data">The data to be written</param>
|
||||||
public void WriteTrackedResource(ulong va, ReadOnlySpan<byte> data)
|
public void WriteTrackedResource(ulong va, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
WriteImpl(va, data, Physical.WriteTrackedResource);
|
WriteImpl(va, data, (physical, va, data) => physical.WriteTrackedResource(va, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -308,10 +346,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="data">The data to be written</param>
|
/// <param name="data">The data to be written</param>
|
||||||
public void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
|
public void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
WriteImpl(va, data, Physical.WriteUntracked);
|
WriteImpl(va, data, (physical, va, data) => physical.WriteUntracked(va, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
|
private delegate void WriteCallback(PhysicalMemory physicalMemory, ulong address, ReadOnlySpan<byte> data);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes data to possibly non-contiguous GPU mapped memory.
|
/// Writes data to possibly non-contiguous GPU mapped memory.
|
||||||
|
@ -323,7 +361,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
if (IsContiguous(va, data.Length))
|
if (IsContiguous(va, data.Length))
|
||||||
{
|
{
|
||||||
writeCallback(Translate(va), data);
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
|
writeCallback(physicalMemory, address, data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -331,22 +371,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if ((va & PageMask) != 0)
|
if ((va & PageMask) != 0)
|
||||||
{
|
{
|
||||||
ulong pa = Translate(va);
|
(PhysicalMemory physicalMemory, ulong pa) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
||||||
|
|
||||||
writeCallback(pa, data[..size]);
|
writeCallback(physicalMemory, pa, data[..size]);
|
||||||
|
|
||||||
offset += size;
|
offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; offset < data.Length; offset += size)
|
for (; offset < data.Length; offset += size)
|
||||||
{
|
{
|
||||||
ulong pa = Translate(va + (ulong)offset);
|
(PhysicalMemory physicalMemory, ulong pa) = TranslateWithPhysicalMemory(va + (ulong)offset);
|
||||||
|
|
||||||
size = Math.Min(data.Length - offset, (int)PageSize);
|
size = Math.Min(data.Length - offset, (int)PageSize);
|
||||||
|
|
||||||
writeCallback(pa, data.Slice(offset, size));
|
writeCallback(physicalMemory, pa, data.Slice(offset, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +400,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
if (IsContiguous(va, data.Length))
|
if (IsContiguous(va, data.Length))
|
||||||
{
|
{
|
||||||
Physical.Write(Translate(va), data);
|
(PhysicalMemory physicalMemory, ulong address) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
|
physicalMemory.Write(address, data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -368,13 +410,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
if ((va & PageMask) != 0)
|
if ((va & PageMask) != 0)
|
||||||
{
|
{
|
||||||
ulong pa = Translate(va);
|
(PhysicalMemory physicalMemory, ulong pa) = TranslateWithPhysicalMemory(va);
|
||||||
|
|
||||||
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask));
|
||||||
|
|
||||||
if (pa != PteUnmapped && Physical.IsMapped(pa))
|
if (pa != PteUnmapped && physicalMemory.IsMapped(pa))
|
||||||
{
|
{
|
||||||
Physical.Write(pa, data[..size]);
|
physicalMemory.Write(pa, data[..size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += size;
|
offset += size;
|
||||||
|
@ -382,13 +424,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
for (; offset < data.Length; offset += size)
|
for (; offset < data.Length; offset += size)
|
||||||
{
|
{
|
||||||
ulong pa = Translate(va + (ulong)offset);
|
(PhysicalMemory physicalMemory, ulong pa) = TranslateWithPhysicalMemory(va + (ulong)offset);
|
||||||
|
|
||||||
size = Math.Min(data.Length - offset, (int)PageSize);
|
size = Math.Min(data.Length - offset, (int)PageSize);
|
||||||
|
|
||||||
if (pa != PteUnmapped && Physical.IsMapped(pa))
|
if (pa != PteUnmapped && physicalMemory.IsMapped(pa))
|
||||||
{
|
{
|
||||||
Physical.Write(pa, data.Slice(offset, size));
|
physicalMemory.Write(pa, data.Slice(offset, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,15 +463,51 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="size">Size in bytes of the mapping</param>
|
/// <param name="size">Size in bytes of the mapping</param>
|
||||||
/// <param name="kind">Kind of the resource located at the mapping</param>
|
/// <param name="kind">Kind of the resource located at the mapping</param>
|
||||||
public void Map(ulong pa, ulong va, ulong size, PteKind kind)
|
public void Map(ulong pa, ulong va, ulong size, PteKind kind)
|
||||||
|
{
|
||||||
|
MapImpl(pa, va, size, kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps a given range of pages to the specified CPU virtual address from a different process.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// All addresses and sizes must be page aligned.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="pa">CPU virtual address to map into</param>
|
||||||
|
/// <param name="va">GPU virtual address to be mapped</param>
|
||||||
|
/// <param name="size">Size in bytes of the mapping</param>
|
||||||
|
/// <param name="kind">Kind of the resource located at the mapping</param>
|
||||||
|
/// <param name="ownedPid">PID of the process that owns the mapping</param>
|
||||||
|
public void MapForeign(ulong pa, ulong va, ulong size, PteKind kind, ulong ownedPid)
|
||||||
|
{
|
||||||
|
if (_context.PhysicalMemoryRegistry.TryGetValue(ownedPid, out PhysicalMemory physicalMemory))
|
||||||
|
{
|
||||||
|
MapImpl(pa, va, size, kind, physicalMemory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps a given range of pages to the specified CPU virtual address.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// All addresses and sizes must be page aligned.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="pa">CPU virtual address to map into</param>
|
||||||
|
/// <param name="va">GPU virtual address to be mapped</param>
|
||||||
|
/// <param name="size">Size in bytes of the mapping</param>
|
||||||
|
/// <param name="kind">Kind of the resource located at the mapping</param>
|
||||||
|
/// <param name="physicalMemory">Optional physical memory to import for the mapping</param>
|
||||||
|
private void MapImpl(ulong pa, ulong va, ulong size, PteKind kind, PhysicalMemory physicalMemory = null)
|
||||||
{
|
{
|
||||||
lock (_pageTable)
|
lock (_pageTable)
|
||||||
{
|
{
|
||||||
UnmapEventArgs e = new(va, size);
|
UnmapEventArgs e = new(va, size);
|
||||||
MemoryUnmapped?.Invoke(this, e);
|
MemoryUnmapped?.Invoke(this, e);
|
||||||
|
byte pIndex = physicalMemory != null ? GetOrAddPhysicalMemory(physicalMemory) : (byte)0;
|
||||||
|
|
||||||
for (ulong offset = 0; offset < size; offset += PageSize)
|
for (ulong offset = 0; offset < size; offset += PageSize)
|
||||||
{
|
{
|
||||||
SetPte(va + offset, PackPte(pa + offset, kind));
|
SetPte(va + offset, PackPte(pa + offset, pIndex, kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
RunRemapActions(e);
|
RunRemapActions(e);
|
||||||
|
@ -480,12 +558,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
for (int page = 0; page < pages - 1; page++)
|
for (int page = 0; page < pages - 1; page++)
|
||||||
{
|
{
|
||||||
if (!ValidateAddress(va + PageSize) || GetPte(va + PageSize) == PteUnmapped)
|
ulong nextPte = GetPte(va + PageSize);
|
||||||
|
|
||||||
|
if (!ValidateAddress(va + PageSize) || nextPte == PteUnmapped)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Translate(va) + PageSize != Translate(va + PageSize))
|
if (GetPte(va) + PageSize != nextPte)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -592,9 +672,47 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the backing memory for a given GPU virtual address.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="va">GPU virtual address to get the backing memory from</param>
|
||||||
|
/// <returns>The backing memory for the specified GPU virtual address</returns>
|
||||||
internal PhysicalMemory GetBackingMemory(ulong va)
|
internal PhysicalMemory GetBackingMemory(ulong va)
|
||||||
{
|
{
|
||||||
return Physical;
|
ulong pte = GetPte(va);
|
||||||
|
|
||||||
|
if (pte == PteUnmapped)
|
||||||
|
{
|
||||||
|
return GetOwnPhysicalMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _physicalMemoryList[UnpackPIndexFromPte(pte)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the backing memory that is owned by this GPU memory manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The backing memory owned by this memory manager</returns>
|
||||||
|
private PhysicalMemory GetOwnPhysicalMemory()
|
||||||
|
{
|
||||||
|
return _physicalMemoryList[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the index for a given physical memory on the list, adding it to the list if needed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="physicalMemory">Physical memory to get the index from</param>
|
||||||
|
/// <returns>The index of the physical memory on the list</returns>
|
||||||
|
private byte GetOrAddPhysicalMemory(PhysicalMemory physicalMemory)
|
||||||
|
{
|
||||||
|
if (!_physicalMemoryMap.TryGetValue(physicalMemory, out byte pIndex))
|
||||||
|
{
|
||||||
|
pIndex = checked((byte)_physicalMemoryList.Count);
|
||||||
|
_physicalMemoryList.Add(physicalMemory);
|
||||||
|
_physicalMemoryMap.Add(physicalMemory, pIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -698,6 +816,28 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
return Math.Min(maxSize, va - startVa);
|
return Math.Min(maxSize, va - startVa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Translates a GPU virtual address to a CPU virtual address and the associated physical memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="va">GPU virtual address to be translated</param>
|
||||||
|
/// <returns>CPU virtual address with the physical memory, or <see cref="PteUnmapped"/> if unmapped</returns>
|
||||||
|
private (PhysicalMemory, ulong) TranslateWithPhysicalMemory(ulong va)
|
||||||
|
{
|
||||||
|
if (!ValidateAddress(va))
|
||||||
|
{
|
||||||
|
return (GetOwnPhysicalMemory(), PteUnmapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong pte = GetPte(va);
|
||||||
|
|
||||||
|
if (pte == PteUnmapped)
|
||||||
|
{
|
||||||
|
return (GetOwnPhysicalMemory(), PteUnmapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (_physicalMemoryList[UnpackPIndexFromPte(pte)], UnpackPaFromPte(pte) + (va & PageMask));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the kind of a given memory page.
|
/// Gets the kind of a given memory page.
|
||||||
/// This might indicate the type of resource that can be allocated on the page, and also texture tiling.
|
/// This might indicate the type of resource that can be allocated on the page, and also texture tiling.
|
||||||
|
@ -766,11 +906,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// Creates a page table entry from a physical address and kind.
|
/// Creates a page table entry from a physical address and kind.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pa">Physical address</param>
|
/// <param name="pa">Physical address</param>
|
||||||
|
/// <param name="pIndex">Index of the physical memory on the list</param>
|
||||||
/// <param name="kind">Kind</param>
|
/// <param name="kind">Kind</param>
|
||||||
/// <returns>Page table entry</returns>
|
/// <returns>Page table entry</returns>
|
||||||
private static ulong PackPte(ulong pa, PteKind kind)
|
private static ulong PackPte(ulong pa, byte pIndex, PteKind kind)
|
||||||
{
|
{
|
||||||
return pa | ((ulong)kind << 56);
|
return pa | ((ulong)pIndex << 48) | ((ulong)kind << 56);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -783,6 +924,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
return (PteKind)(pte >> 56);
|
return (PteKind)(pte >> 56);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unpacks the physical memory index in the list from a page table entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pte">Page table entry</param>
|
||||||
|
/// <returns>Physical memory index</returns>
|
||||||
|
private static byte UnpackPIndexFromPte(ulong pte)
|
||||||
|
{
|
||||||
|
return (byte)(pte >> 48);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unpacks physical address from a page table entry.
|
/// Unpacks physical address from a page table entry.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -730,8 +730,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray();
|
codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray();
|
||||||
codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
|
codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
|
||||||
byte[] cb1DataA = physical.GetSpan(cb1DataAddress, vertexA.Cb1DataSize).ToArray();
|
byte[] cb1DataA = Read(physical, cb1DataAddress, vertexA.Cb1DataSize);
|
||||||
byte[] cb1DataB = physical.GetSpan(cb1DataAddress, currentStage.Cb1DataSize).ToArray();
|
byte[] cb1DataB = Read(physical, cb1DataAddress, currentStage.Cb1DataSize);
|
||||||
|
|
||||||
ShaderDumpPaths pathsA = default;
|
ShaderDumpPaths pathsA = default;
|
||||||
ShaderDumpPaths pathsB = default;
|
ShaderDumpPaths pathsB = default;
|
||||||
|
@ -770,7 +770,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
? channel.BufferManager.GetComputeUniformBufferAddress(1)
|
? channel.BufferManager.GetComputeUniformBufferAddress(1)
|
||||||
: channel.BufferManager.GetGraphicsUniformBufferAddress(StageToStageIndex(context.Stage), 1);
|
: channel.BufferManager.GetGraphicsUniformBufferAddress(StageToStageIndex(context.Stage), 1);
|
||||||
|
|
||||||
byte[] cb1Data = physical.GetSpan(cb1DataAddress, context.Cb1DataSize).ToArray();
|
byte[] cb1Data = Read(physical, cb1DataAddress, context.Cb1DataSize);
|
||||||
code ??= memoryManager.GetSpan(context.Address, context.Size).ToArray();
|
code ??= memoryManager.GetSpan(context.Address, context.Size).ToArray();
|
||||||
|
|
||||||
ShaderDumpPaths paths = dumper?.Dump(code, context.Stage == ShaderStage.Compute) ?? default;
|
ShaderDumpPaths paths = dumper?.Dump(code, context.Stage == ShaderStage.Compute) ?? default;
|
||||||
|
@ -781,6 +781,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return new TranslatedShader(new CachedShaderStage(program.Info, code, cb1Data), program);
|
return new TranslatedShader(new CachedShaderStage(program.Info, code, cb1Data), program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data from physical memory, if it exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="physicalMemory">Physical memory to read the data from, might be null</param>
|
||||||
|
/// <param name="address">Address to read the data from</param>
|
||||||
|
/// <param name="size">Size of the data to read</param>
|
||||||
|
/// <returns>An array with the data</returns>
|
||||||
|
private static byte[] Read(PhysicalMemory physicalMemory, ulong address, int size)
|
||||||
|
{
|
||||||
|
if (size == 0 || physicalMemory == null)
|
||||||
|
{
|
||||||
|
return Array.Empty<byte>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return physicalMemory.GetSpan(address, size).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the index of a stage from a <see cref="ShaderStage"/>.
|
/// Gets the index of a stage from a <see cref="ShaderStage"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue