mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-03-13 16:00:17 +00:00
Changes 2
This commit is contained in:
parent
4984005926
commit
6b22f41e10
7 changed files with 613 additions and 145 deletions
|
@ -201,7 +201,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
// of the shader for the new state.
|
// of the shader for the new state.
|
||||||
if (_shaderSpecState != null)
|
if (_shaderSpecState != null)
|
||||||
{
|
{
|
||||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState()))
|
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), false))
|
||||||
{
|
{
|
||||||
ForceShaderUpdate();
|
ForceShaderUpdate();
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
{
|
{
|
||||||
UpdateStorageBuffers();
|
UpdateStorageBuffers();
|
||||||
|
|
||||||
_channel.TextureManager.CommitGraphicsBindings();
|
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState))
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Gpu, "Oh my");
|
||||||
|
UpdateShaderState();
|
||||||
|
}
|
||||||
|
|
||||||
_channel.BufferManager.CommitGraphicsBindings();
|
_channel.BufferManager.CommitGraphicsBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,6 +1153,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int maxTextureBinding = 0;
|
||||||
|
int maxImageBinding = 0;
|
||||||
|
|
||||||
Span<TextureBindingInfo> textureBindings = _channel.TextureManager.RentGraphicsTextureBindings(stage, info.Textures.Count);
|
Span<TextureBindingInfo> textureBindings = _channel.TextureManager.RentGraphicsTextureBindings(stage, info.Textures.Count);
|
||||||
|
|
||||||
if (info.UsesRtLayer)
|
if (info.UsesRtLayer)
|
||||||
|
@ -1167,6 +1175,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
descriptor.CbufSlot,
|
descriptor.CbufSlot,
|
||||||
descriptor.HandleIndex,
|
descriptor.HandleIndex,
|
||||||
descriptor.Flags);
|
descriptor.Flags);
|
||||||
|
|
||||||
|
if (descriptor.Binding > maxTextureBinding)
|
||||||
|
{
|
||||||
|
maxTextureBinding = descriptor.Binding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentGraphicsImageBindings(stage, info.Images.Count);
|
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentGraphicsImageBindings(stage, info.Images.Count);
|
||||||
|
@ -1185,8 +1198,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||||
descriptor.CbufSlot,
|
descriptor.CbufSlot,
|
||||||
descriptor.HandleIndex,
|
descriptor.HandleIndex,
|
||||||
descriptor.Flags);
|
descriptor.Flags);
|
||||||
|
|
||||||
|
if (descriptor.Binding > maxImageBinding)
|
||||||
|
{
|
||||||
|
maxImageBinding = descriptor.Binding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_channel.TextureManager.SetGraphicsMaxBindings(maxTextureBinding, maxImageBinding);
|
||||||
|
|
||||||
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
|
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
|
||||||
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
|
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Cpu.Tracking;
|
using Ryujinx.Cpu.Tracking;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
private readonly CpuMultiRegionHandle _memoryTracking;
|
private readonly CpuMultiRegionHandle _memoryTracking;
|
||||||
private readonly Action<ulong, ulong> _modifiedDelegate;
|
private readonly Action<ulong, ulong> _modifiedDelegate;
|
||||||
|
|
||||||
|
private bool _modified;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the GPU resource pool.
|
/// Creates a new instance of the GPU resource pool.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -79,6 +82,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
|
return PhysicalMemory.Read<T2>(Address + (ulong)id * DescriptorSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a reference to the descriptor for a given ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">ID of the descriptor. This is effectively a zero-based index</param>
|
||||||
|
/// <returns>A reference to the descriptor</returns>
|
||||||
|
public ref readonly T2 GetDescriptorRef(int id)
|
||||||
|
{
|
||||||
|
return ref MemoryMarshal.Cast<byte, T2>(PhysicalMemory.GetSpan(Address + (ulong)id * DescriptorSize, DescriptorSize))[0];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the GPU resource with the given ID.
|
/// Gets the GPU resource with the given ID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -91,9 +104,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// This causes invalidation of pool entries,
|
/// This causes invalidation of pool entries,
|
||||||
/// if a modification of entries by the CPU is detected.
|
/// if a modification of entries by the CPU is detected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SynchronizeMemory()
|
public bool SynchronizeMemory()
|
||||||
{
|
{
|
||||||
|
_modified = false;
|
||||||
_memoryTracking.QueryModified(_modifiedDelegate);
|
_memoryTracking.QueryModified(_modifiedDelegate);
|
||||||
|
return _modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -103,6 +118,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="mSize">Size of the modified region</param>
|
/// <param name="mSize">Size of the modified region</param>
|
||||||
private void RegionModified(ulong mAddress, ulong mSize)
|
private void RegionModified(ulong mAddress, ulong mSize)
|
||||||
{
|
{
|
||||||
|
_modified = true;
|
||||||
|
|
||||||
if (mAddress < Address)
|
if (mAddress < Address)
|
||||||
{
|
{
|
||||||
mAddress = Address;
|
mAddress = Address;
|
||||||
|
@ -129,6 +146,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
if (write && Context.SequenceNumber == SequenceNumber)
|
if (write && Context.SequenceNumber == SequenceNumber)
|
||||||
{
|
{
|
||||||
|
//Common.Logging.Logger.Error?.Print(Common.Logging.LogClass.Gpu, "Precise action...");
|
||||||
SequenceNumber--;
|
SequenceNumber--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
class SamplerPool : Pool<Sampler, SamplerDescriptor>
|
class SamplerPool : Pool<Sampler, SamplerDescriptor>
|
||||||
{
|
{
|
||||||
private float _forcedAnisotropy;
|
private float _forcedAnisotropy;
|
||||||
|
private int _modifiedSequenceNumber;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new instance of the sampler pool.
|
/// Constructs a new instance of the sampler pool.
|
||||||
|
@ -52,7 +53,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
SequenceNumber = Context.SequenceNumber;
|
SequenceNumber = Context.SequenceNumber;
|
||||||
|
|
||||||
SynchronizeMemory();
|
if (SynchronizeMemory())
|
||||||
|
{
|
||||||
|
_modifiedSequenceNumber = SequenceNumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sampler sampler = Items[id];
|
Sampler sampler = Items[id];
|
||||||
|
@ -71,6 +75,42 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return sampler;
|
return sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The last sequence number where a modification was detected</returns>
|
||||||
|
public int CheckModified()
|
||||||
|
{
|
||||||
|
if (SequenceNumber != Context.SequenceNumber)
|
||||||
|
{
|
||||||
|
SequenceNumber = Context.SequenceNumber;
|
||||||
|
|
||||||
|
if (_forcedAnisotropy != GraphicsConfig.MaxAnisotropy)
|
||||||
|
{
|
||||||
|
_forcedAnisotropy = GraphicsConfig.MaxAnisotropy;
|
||||||
|
|
||||||
|
for (int i = 0; i < Items.Length; i++)
|
||||||
|
{
|
||||||
|
if (Items[i] != null)
|
||||||
|
{
|
||||||
|
Items[i].Dispose();
|
||||||
|
|
||||||
|
Items[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_modifiedSequenceNumber = SequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SynchronizeMemory())
|
||||||
|
{
|
||||||
|
_modifiedSequenceNumber = SequenceNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _modifiedSequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of the sampler pool range invalidation.
|
/// Implementation of the sampler pool range invalidation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
|
@ -11,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class TextureBindingsManager : IDisposable
|
class TextureBindingsManager : IDisposable
|
||||||
{
|
{
|
||||||
private const int InitialTextureStateSize = 32;
|
private const int InitialTextureStateSize = 32; // Should match binding range for host.
|
||||||
private const int InitialImageStateSize = 8;
|
private const int InitialImageStateSize = 8;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
|
@ -35,18 +39,22 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
public ITexture Texture;
|
public ITexture Texture;
|
||||||
public ISampler Sampler;
|
public ISampler Sampler;
|
||||||
|
|
||||||
|
public int TextureHandle;
|
||||||
|
public int SamplerHandle;
|
||||||
|
public int InvalidatedSequence;
|
||||||
|
public Texture CachedTexture;
|
||||||
|
public Sampler CachedSampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly TextureStatePerStage[][] _textureState;
|
private TextureStatePerStage[] _textureState;
|
||||||
private readonly TextureStatePerStage[][] _imageState;
|
private TextureStatePerStage[] _imageState;
|
||||||
|
|
||||||
private int[] _textureBindingsCount;
|
private int[] _textureBindingsCount;
|
||||||
private int[] _imageBindingsCount;
|
private int[] _imageBindingsCount;
|
||||||
|
|
||||||
private int _textureBufferIndex;
|
private int _textureBufferIndex;
|
||||||
|
|
||||||
private bool _rebind;
|
|
||||||
|
|
||||||
private readonly float[] _scales;
|
private readonly float[] _scales;
|
||||||
private bool _scaleChanged;
|
private bool _scaleChanged;
|
||||||
private int _lastFragmentTotal;
|
private int _lastFragmentTotal;
|
||||||
|
@ -72,8 +80,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_textureBindings = new TextureBindingInfo[stages][];
|
_textureBindings = new TextureBindingInfo[stages][];
|
||||||
_imageBindings = new TextureBindingInfo[stages][];
|
_imageBindings = new TextureBindingInfo[stages][];
|
||||||
|
|
||||||
_textureState = new TextureStatePerStage[stages][];
|
_textureState = new TextureStatePerStage[InitialTextureStateSize];
|
||||||
_imageState = new TextureStatePerStage[stages][];
|
_imageState = new TextureStatePerStage[InitialImageStateSize];
|
||||||
|
|
||||||
_textureBindingsCount = new int[stages];
|
_textureBindingsCount = new int[stages];
|
||||||
_imageBindingsCount = new int[stages];
|
_imageBindingsCount = new int[stages];
|
||||||
|
@ -82,9 +90,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
_textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize];
|
_textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize];
|
||||||
_imageBindings[stage] = new TextureBindingInfo[InitialImageStateSize];
|
_imageBindings[stage] = new TextureBindingInfo[InitialImageStateSize];
|
||||||
|
|
||||||
_textureState[stage] = new TextureStatePerStage[InitialTextureStateSize];
|
|
||||||
_imageState[stage] = new TextureStatePerStage[InitialImageStateSize];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,15 +104,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
if (count > _textureBindings[stage].Length)
|
if (count > _textureBindings[stage].Length)
|
||||||
{
|
{
|
||||||
Array.Resize(ref _textureBindings[stage], count);
|
Array.Resize(ref _textureBindings[stage], count);
|
||||||
Array.Resize(ref _textureState[stage], count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int toClear = Math.Max(_textureBindingsCount[stage], count);
|
|
||||||
TextureStatePerStage[] state = _textureState[stage];
|
|
||||||
|
|
||||||
for (int i = 0; i < toClear; i++)
|
|
||||||
{
|
|
||||||
state[i] = new TextureStatePerStage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_textureBindingsCount[stage] = count;
|
_textureBindingsCount[stage] = count;
|
||||||
|
@ -126,15 +122,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
if (count > _imageBindings[stage].Length)
|
if (count > _imageBindings[stage].Length)
|
||||||
{
|
{
|
||||||
Array.Resize(ref _imageBindings[stage], count);
|
Array.Resize(ref _imageBindings[stage], count);
|
||||||
Array.Resize(ref _imageState[stage], count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int toClear = Math.Max(_imageBindingsCount[stage], count);
|
|
||||||
TextureStatePerStage[] state = _imageState[stage];
|
|
||||||
|
|
||||||
for (int i = 0; i < toClear; i++)
|
|
||||||
{
|
|
||||||
state[i] = new TextureStatePerStage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_imageBindingsCount[stage] = count;
|
_imageBindingsCount[stage] = count;
|
||||||
|
@ -142,6 +129,24 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return _imageBindings[stage];
|
return _imageBindings[stage];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the max binding indexes for textures and images.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="maxTextureBinding">The maximum texture binding</param>
|
||||||
|
/// <param name="maxImageBinding">The maximum image binding</param>
|
||||||
|
public void SetMaxBindings(int maxTextureBinding, int maxImageBinding)
|
||||||
|
{
|
||||||
|
if (maxTextureBinding >= _textureState.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _textureState, maxTextureBinding + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxImageBinding >= _imageState.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _imageState, maxImageBinding + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the textures constant buffer index.
|
/// Sets the textures constant buffer index.
|
||||||
/// The constant buffer specified holds the texture handles.
|
/// The constant buffer specified holds the texture handles.
|
||||||
|
@ -319,11 +324,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int _texturePoolSequence;
|
||||||
|
private int _samplerPoolSequence;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the bindings are visible to the host GPU.
|
/// Ensures that the bindings are visible to the host GPU.
|
||||||
/// Note: this actually performs the binding using the host graphics API.
|
/// Note: this actually performs the binding using the host graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitBindings()
|
/// <param name="specState">Specialization state for the bound shader</param>
|
||||||
|
/// <returns>True if all bound textures match the current shader specialiation state, false otherwise</returns>
|
||||||
|
public bool CommitBindings(ShaderSpecializationState specState)
|
||||||
{
|
{
|
||||||
ulong texturePoolAddress = _texturePoolAddress;
|
ulong texturePoolAddress = _texturePoolAddress;
|
||||||
|
|
||||||
|
@ -331,10 +341,38 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
? _texturePoolCache.FindOrCreate(_channel, texturePoolAddress, _texturePoolMaximumId)
|
? _texturePoolCache.FindOrCreate(_channel, texturePoolAddress, _texturePoolMaximumId)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
// Check if the texture pool has been modified since bindings were last committed.
|
||||||
|
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
|
||||||
|
bool poolModified = false;
|
||||||
|
|
||||||
|
if (texturePool != null)
|
||||||
|
{
|
||||||
|
int texturePoolSequence = texturePool.CheckModified();
|
||||||
|
|
||||||
|
if (_texturePoolSequence != texturePoolSequence)
|
||||||
|
{
|
||||||
|
poolModified = true;
|
||||||
|
_texturePoolSequence = texturePoolSequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_samplerPool != null)
|
||||||
|
{
|
||||||
|
int samplerPoolSequence = _samplerPool.CheckModified();
|
||||||
|
|
||||||
|
if (_samplerPoolSequence != samplerPoolSequence)
|
||||||
|
{
|
||||||
|
poolModified = true;
|
||||||
|
_samplerPoolSequence = samplerPoolSequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool specStateMatches = true;
|
||||||
|
|
||||||
if (_isCompute)
|
if (_isCompute)
|
||||||
{
|
{
|
||||||
CommitTextureBindings(texturePool, ShaderStage.Compute, 0);
|
specStateMatches &= CommitTextureBindings(texturePool, ShaderStage.Compute, 0, poolModified, specState);
|
||||||
CommitImageBindings (texturePool, ShaderStage.Compute, 0);
|
specStateMatches &= CommitImageBindings(texturePool, ShaderStage.Compute, 0, poolModified, specState);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -342,14 +380,57 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
int stageIndex = (int)stage - 1;
|
int stageIndex = (int)stage - 1;
|
||||||
|
|
||||||
CommitTextureBindings(texturePool, stage, stageIndex);
|
specStateMatches &= CommitTextureBindings(texturePool, stage, stageIndex, poolModified, specState);
|
||||||
CommitImageBindings (texturePool, stage, stageIndex);
|
specStateMatches &= CommitImageBindings(texturePool, stage, stageIndex, poolModified, specState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CommitRenderScale();
|
CommitRenderScale();
|
||||||
|
|
||||||
_rebind = false;
|
return specStateMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetch the constant buffers used for a texture to cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stageIndex">Stage index of the constant buffer</param>
|
||||||
|
/// <param name="cachedTextureBufferIndex">The currently cached texture buffer index</param>
|
||||||
|
/// <param name="cachedSamplerBufferIndex">The currently cached sampler buffer index</param>
|
||||||
|
/// <param name="cachedTextureBuffer">The currently cached texture buffer data</param>
|
||||||
|
/// <param name="cachedSamplerBuffer">The currently cached sampler buffer data</param>
|
||||||
|
/// <param name="textureBufferIndex">The new texture buffer index</param>
|
||||||
|
/// <param name="samplerBufferIndex">The new sampler buffer index</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void UpdateCachedBuffer(
|
||||||
|
int stageIndex,
|
||||||
|
ref int cachedTextureBufferIndex,
|
||||||
|
ref int cachedSamplerBufferIndex,
|
||||||
|
ref ReadOnlySpan<int> cachedTextureBuffer,
|
||||||
|
ref ReadOnlySpan<int> cachedSamplerBuffer,
|
||||||
|
int textureBufferIndex,
|
||||||
|
int samplerBufferIndex)
|
||||||
|
{
|
||||||
|
if (textureBufferIndex != cachedTextureBufferIndex)
|
||||||
|
{
|
||||||
|
ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, textureBufferIndex);
|
||||||
|
|
||||||
|
cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(_channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
|
||||||
|
cachedTextureBufferIndex = textureBufferIndex;
|
||||||
|
|
||||||
|
if (samplerBufferIndex == textureBufferIndex)
|
||||||
|
{
|
||||||
|
cachedSamplerBuffer = cachedTextureBuffer;
|
||||||
|
cachedSamplerBufferIndex = samplerBufferIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cachedSamplerBufferIndex != samplerBufferIndex)
|
||||||
|
{
|
||||||
|
ref BufferBounds bounds = ref _channel.BufferManager.GetUniformBufferBounds(_isCompute, stageIndex, samplerBufferIndex);
|
||||||
|
|
||||||
|
cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(_channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
|
||||||
|
cachedSamplerBufferIndex = samplerBufferIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -358,13 +439,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pool">The current texture pool</param>
|
/// <param name="pool">The current texture pool</param>
|
||||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||||
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
/// <param name="stageIndex">The stage number of the specified shader stage</param
|
||||||
private void CommitTextureBindings(TexturePool pool, ShaderStage stage, int stageIndex)
|
/// <param name="poolModified">True if either the texture or sampler pool was modified, false otherwise</param>
|
||||||
|
/// <param name="specState">Specialization state for the bound shader</param>
|
||||||
|
/// <returns>True if all bound textures match the current shader specialiation state, false otherwise</returns>
|
||||||
|
private bool CommitTextureBindings(TexturePool pool, ShaderStage stage, int stageIndex, bool poolModified, ShaderSpecializationState specState)
|
||||||
{
|
{
|
||||||
int textureCount = _textureBindingsCount[stageIndex];
|
int textureCount = _textureBindingsCount[stageIndex];
|
||||||
if (textureCount == 0)
|
if (textureCount == 0)
|
||||||
{
|
{
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var samplerPool = _samplerPool;
|
var samplerPool = _samplerPool;
|
||||||
|
@ -372,17 +456,26 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
if (pool == null)
|
if (pool == null)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses textures, but texture pool was not set.");
|
Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses textures, but texture pool was not set.");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool specStateMatches = true;
|
||||||
|
|
||||||
|
int cachedTextureBufferIndex = -1;
|
||||||
|
int cachedSamplerBufferIndex = -1;
|
||||||
|
ReadOnlySpan<int> cachedTextureBuffer = Span<int>.Empty;
|
||||||
|
ReadOnlySpan<int> cachedSamplerBuffer = Span<int>.Empty;
|
||||||
|
|
||||||
for (int index = 0; index < textureCount; index++)
|
for (int index = 0; index < textureCount; index++)
|
||||||
{
|
{
|
||||||
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
|
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
|
||||||
|
|
||||||
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex);
|
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex);
|
||||||
|
|
||||||
int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex, samplerBufferIndex);
|
UpdateCachedBuffer(stageIndex, ref cachedTextureBufferIndex, ref cachedSamplerBufferIndex, ref cachedTextureBuffer, ref cachedSamplerBuffer, textureBufferIndex, samplerBufferIndex);
|
||||||
int textureId = UnpackTextureId(packedId);
|
|
||||||
|
int packedId = TextureHandle.ReadPackedId(bindingInfo.Handle, cachedTextureBuffer, cachedSamplerBuffer);
|
||||||
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
int samplerId;
|
int samplerId;
|
||||||
|
|
||||||
if (_samplerIndex == SamplerIndex.ViaHeaderIndex)
|
if (_samplerIndex == SamplerIndex.ViaHeaderIndex)
|
||||||
|
@ -394,7 +487,27 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
samplerId = UnpackSamplerId(packedId);
|
samplerId = UnpackSamplerId(packedId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture texture = pool.Get(textureId);
|
ref TextureStatePerStage state = ref _textureState[bindingInfo.Binding];
|
||||||
|
|
||||||
|
if (!poolModified &&
|
||||||
|
state.TextureHandle == textureId &&
|
||||||
|
state.SamplerHandle == samplerId &&
|
||||||
|
state.CachedTexture != null &&
|
||||||
|
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence &&
|
||||||
|
state.CachedSampler?.IsDisposed != true)
|
||||||
|
{
|
||||||
|
// The texture is already bound.
|
||||||
|
state.CachedTexture.SynchronizeMemory();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.TextureHandle = textureId;
|
||||||
|
state.SamplerHandle = samplerId;
|
||||||
|
|
||||||
|
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture);
|
||||||
|
|
||||||
|
specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
|
||||||
|
|
||||||
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
|
@ -407,30 +520,36 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_textureState[stageIndex][index].Texture != hostTexture || _rebind)
|
if (state.Texture != hostTexture)
|
||||||
{
|
{
|
||||||
if (UpdateScale(texture, bindingInfo, index, stage))
|
if (UpdateScale(texture, bindingInfo, index, stage))
|
||||||
{
|
{
|
||||||
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
_textureState[stageIndex][index].Texture = hostTexture;
|
state.Texture = hostTexture;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTexture);
|
_context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sampler sampler = samplerPool?.Get(samplerId);
|
Sampler sampler = samplerPool?.Get(samplerId);
|
||||||
|
state.CachedSampler = sampler;
|
||||||
|
|
||||||
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
ISampler hostSampler = sampler?.GetHostSampler(texture);
|
||||||
|
|
||||||
if (_textureState[stageIndex][index].Sampler != hostSampler || _rebind)
|
if (state.Sampler != hostSampler)
|
||||||
{
|
{
|
||||||
_textureState[stageIndex][index].Sampler = hostSampler;
|
state.Sampler = hostSampler;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetSampler(bindingInfo.Binding, hostSampler);
|
_context.Renderer.Pipeline.SetSampler(bindingInfo.Binding, hostSampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.CachedTexture = texture;
|
||||||
|
state.InvalidatedSequence = texture?.InvalidatedSequence ?? 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return specStateMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -440,38 +559,72 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="pool">The current texture pool</param>
|
/// <param name="pool">The current texture pool</param>
|
||||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||||
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||||
private void CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex)
|
/// <param name="poolModified">True if either the texture or sampler pool was modified, false otherwise</param>
|
||||||
|
/// <param name="specState">Specialization state for the bound shader</param>
|
||||||
|
/// <returns>True if all bound images match the current shader specialiation state, false otherwise</returns>
|
||||||
|
private bool CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex, bool poolModified, ShaderSpecializationState specState)
|
||||||
{
|
{
|
||||||
int imageCount = _imageBindingsCount[stageIndex];
|
int imageCount = _imageBindingsCount[stageIndex];
|
||||||
if (imageCount == 0)
|
if (imageCount == 0)
|
||||||
{
|
{
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pool == null)
|
if (pool == null)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses images, but texture pool was not set.");
|
Logger.Error?.Print(LogClass.Gpu, $"Shader stage \"{stage}\" uses images, but texture pool was not set.");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scales for images appear after the texture ones.
|
// Scales for images appear after the texture ones.
|
||||||
int baseScaleIndex = _textureBindingsCount[stageIndex];
|
int baseScaleIndex = _textureBindingsCount[stageIndex];
|
||||||
|
|
||||||
|
int cachedTextureBufferIndex = -1;
|
||||||
|
int cachedSamplerBufferIndex = -1;
|
||||||
|
ReadOnlySpan<int> cachedTextureBuffer = Span<int>.Empty;
|
||||||
|
ReadOnlySpan<int> cachedSamplerBuffer = Span<int>.Empty;
|
||||||
|
|
||||||
|
bool specStateMatches = true;
|
||||||
|
|
||||||
for (int index = 0; index < imageCount; index++)
|
for (int index = 0; index < imageCount; index++)
|
||||||
{
|
{
|
||||||
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
|
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
|
||||||
|
|
||||||
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex);
|
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, _textureBufferIndex);
|
||||||
|
|
||||||
int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, textureBufferIndex, samplerBufferIndex);
|
UpdateCachedBuffer(stageIndex, ref cachedTextureBufferIndex, ref cachedSamplerBufferIndex, ref cachedTextureBuffer, ref cachedSamplerBuffer, textureBufferIndex, samplerBufferIndex);
|
||||||
int textureId = UnpackTextureId(packedId);
|
|
||||||
|
|
||||||
Texture texture = pool.Get(textureId);
|
int packedId = TextureHandle.ReadPackedId(bindingInfo.Handle, cachedTextureBuffer, cachedSamplerBuffer);
|
||||||
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
|
|
||||||
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
ref TextureStatePerStage state = ref _imageState[bindingInfo.Binding];
|
||||||
|
|
||||||
bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
|
bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
|
||||||
|
|
||||||
|
if (!poolModified &&
|
||||||
|
state.TextureHandle == textureId &&
|
||||||
|
state.CachedTexture != null &&
|
||||||
|
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
|
||||||
|
{
|
||||||
|
// The texture is already bound.
|
||||||
|
state.CachedTexture.SynchronizeMemory();
|
||||||
|
|
||||||
|
if (isStore)
|
||||||
|
{
|
||||||
|
state.CachedTexture?.SignalModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.TextureHandle = textureId;
|
||||||
|
|
||||||
|
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture);
|
||||||
|
|
||||||
|
specStateMatches &= specState.MatchesImage(stage, index, descriptor);
|
||||||
|
|
||||||
|
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Target == Target.TextureBuffer)
|
||||||
{
|
{
|
||||||
// Ensure that the buffer texture is using the correct buffer as storage.
|
// Ensure that the buffer texture is using the correct buffer as storage.
|
||||||
|
@ -494,14 +647,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
texture?.SignalModified();
|
texture?.SignalModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_imageState[stageIndex][index].Texture != hostTexture || _rebind)
|
if (state.Texture != hostTexture)
|
||||||
{
|
{
|
||||||
if (UpdateScale(texture, bindingInfo, baseScaleIndex + index, stage))
|
if (UpdateScale(texture, bindingInfo, baseScaleIndex + index, stage))
|
||||||
{
|
{
|
||||||
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
_imageState[stageIndex][index].Texture = hostTexture;
|
state.Texture = hostTexture;
|
||||||
|
|
||||||
Format format = bindingInfo.Format;
|
Format format = bindingInfo.Format;
|
||||||
|
|
||||||
|
@ -512,8 +665,13 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.CachedTexture = texture;
|
||||||
|
state.InvalidatedSequence = texture?.InvalidatedSequence ?? 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return specStateMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -537,7 +695,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(cbufSlot, bufferIndex);
|
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(cbufSlot, bufferIndex);
|
||||||
|
|
||||||
int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, samplerBufferIndex);
|
int packedId = ReadPackedId(stageIndex, handle, textureBufferIndex, samplerBufferIndex);
|
||||||
int textureId = UnpackTextureId(packedId);
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
|
|
||||||
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
|
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
|
||||||
|
|
||||||
|
@ -555,13 +713,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="textureBufferIndex">Index of the constant buffer holding the texture handles</param>
|
/// <param name="textureBufferIndex">Index of the constant buffer holding the texture handles</param>
|
||||||
/// <param name="samplerBufferIndex">Index of the constant buffer holding the sampler handles</param>
|
/// <param name="samplerBufferIndex">Index of the constant buffer holding the sampler handles</param>
|
||||||
/// <returns>The packed texture and sampler ID (the real texture handle)</returns>
|
/// <returns>The packed texture and sampler ID (the real texture handle)</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private int ReadPackedId(int stageIndex, int wordOffset, int textureBufferIndex, int samplerBufferIndex)
|
private int ReadPackedId(int stageIndex, int wordOffset, int textureBufferIndex, int samplerBufferIndex)
|
||||||
{
|
{
|
||||||
(int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = TextureHandle.UnpackOffsets(wordOffset);
|
(int textureWordOffset, int samplerWordOffset, TextureHandleType handleType) = TextureHandle.UnpackOffsets(wordOffset);
|
||||||
|
|
||||||
ulong textureBufferAddress = _isCompute
|
ulong textureBufferAddress = _isCompute
|
||||||
? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
|
? _channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex)
|
||||||
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
|
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, textureBufferIndex);
|
||||||
|
|
||||||
int handle = _channel.MemoryManager.Physical.Read<int>(textureBufferAddress + (uint)textureWordOffset * 4);
|
int handle = _channel.MemoryManager.Physical.Read<int>(textureBufferAddress + (uint)textureWordOffset * 4);
|
||||||
|
|
||||||
|
@ -574,8 +733,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
if (handleType != TextureHandleType.CombinedSampler)
|
if (handleType != TextureHandleType.CombinedSampler)
|
||||||
{
|
{
|
||||||
ulong samplerBufferAddress = _isCompute
|
ulong samplerBufferAddress = _isCompute
|
||||||
? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
|
? _channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex)
|
||||||
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
|
: _channel.BufferManager.GetGraphicsUniformBufferAddress(stageIndex, samplerBufferIndex);
|
||||||
|
|
||||||
int samplerHandle = _channel.MemoryManager.Physical.Read<int>(samplerBufferAddress + (uint)samplerWordOffset * 4);
|
int samplerHandle = _channel.MemoryManager.Physical.Read<int>(samplerBufferAddress + (uint)samplerWordOffset * 4);
|
||||||
|
|
||||||
|
@ -590,16 +749,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unpacks the texture ID from the real texture handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="packedId">The real texture handle</param>
|
|
||||||
/// <returns>The texture ID</returns>
|
|
||||||
private static int UnpackTextureId(int packedId)
|
|
||||||
{
|
|
||||||
return (packedId >> 0) & 0xfffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unpacks the sampler ID from the real texture handle.
|
/// Unpacks the sampler ID from the real texture handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -615,7 +764,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Rebind()
|
public void Rebind()
|
||||||
{
|
{
|
||||||
_rebind = true;
|
Array.Clear(_textureState);
|
||||||
|
Array.Clear(_imageState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
@ -10,9 +11,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
class TextureManager : IDisposable
|
class TextureManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
|
private readonly GpuChannel _channel;
|
||||||
|
|
||||||
private readonly TextureBindingsManager _cpBindingsManager;
|
private readonly TextureBindingsManager _cpBindingsManager;
|
||||||
private readonly TextureBindingsManager _gpBindingsManager;
|
private readonly TextureBindingsManager _gpBindingsManager;
|
||||||
|
private readonly TexturePoolCache _texturePoolCache;
|
||||||
|
|
||||||
private readonly Texture[] _rtColors;
|
private readonly Texture[] _rtColors;
|
||||||
private readonly ITexture[] _rtHostColors;
|
private readonly ITexture[] _rtHostColors;
|
||||||
|
@ -35,6 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
public TextureManager(GpuContext context, GpuChannel channel)
|
public TextureManager(GpuContext context, GpuChannel channel)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_channel = channel;
|
||||||
|
|
||||||
TexturePoolCache texturePoolCache = new TexturePoolCache(context);
|
TexturePoolCache texturePoolCache = new TexturePoolCache(context);
|
||||||
|
|
||||||
|
@ -43,6 +47,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
_cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, scales, isCompute: true);
|
_cpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, scales, isCompute: true);
|
||||||
_gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, scales, isCompute: false);
|
_gpBindingsManager = new TextureBindingsManager(context, channel, texturePoolCache, scales, isCompute: false);
|
||||||
|
_texturePoolCache = texturePoolCache;
|
||||||
|
|
||||||
_rtColors = new Texture[Constants.TotalRenderTargets];
|
_rtColors = new Texture[Constants.TotalRenderTargets];
|
||||||
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
_rtHostColors = new ITexture[Constants.TotalRenderTargets];
|
||||||
|
@ -99,6 +104,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_cpBindingsManager.SetTextureBufferIndex(index);
|
_cpBindingsManager.SetTextureBufferIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the max binding indexes on the compute pipeline.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="maxTextureBinding">The maximum texture binding</param>
|
||||||
|
/// <param name="maxImageBinding">The maximum image binding</param>
|
||||||
|
public void SetComputeMaxBindings(int maxTextureBinding, int maxImageBinding)
|
||||||
|
{
|
||||||
|
_cpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the texture constant buffer index on the graphics pipeline.
|
/// Sets the texture constant buffer index on the graphics pipeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -108,6 +123,16 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
_gpBindingsManager.SetTextureBufferIndex(index);
|
_gpBindingsManager.SetTextureBufferIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the max binding indexes on the graphics pipeline.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="maxTextureBinding">The maximum texture binding</param>
|
||||||
|
/// <param name="maxImageBinding">The maximum image binding</param>
|
||||||
|
public void SetGraphicsMaxBindings(int maxTextureBinding, int maxImageBinding)
|
||||||
|
{
|
||||||
|
_gpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the current sampler pool on the compute pipeline.
|
/// Sets the current sampler pool on the compute pipeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -335,25 +360,48 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Commits bindings on the compute pipeline.
|
/// Commits bindings on the compute pipeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitComputeBindings()
|
/// <param name="specState">Specialization state for the bound shader</param>
|
||||||
|
/// <returns>True if all bound textures match the current shader specialiation state, false otherwise</returns>
|
||||||
|
public bool CommitComputeBindings(ShaderSpecializationState specState)
|
||||||
{
|
{
|
||||||
// Every time we switch between graphics and compute work,
|
// Every time we switch between graphics and compute work,
|
||||||
// we must rebind everything.
|
// we must rebind everything.
|
||||||
// Since compute work happens less often, we always do that
|
// Since compute work happens less often, we always do that
|
||||||
// before and after the compute dispatch.
|
// before and after the compute dispatch.
|
||||||
_cpBindingsManager.Rebind();
|
_cpBindingsManager.Rebind();
|
||||||
_cpBindingsManager.CommitBindings();
|
bool result = _cpBindingsManager.CommitBindings(specState);
|
||||||
_gpBindingsManager.Rebind();
|
_gpBindingsManager.Rebind();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Commits bindings on the graphics pipeline.
|
/// Commits bindings on the graphics pipeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitGraphicsBindings()
|
/// <param name="specState">Specialization state for the bound shader</param>
|
||||||
|
/// <returns>True if all bound textures match the current shader specialiation state, false otherwise</returns>
|
||||||
|
public bool CommitGraphicsBindings(ShaderSpecializationState specState)
|
||||||
{
|
{
|
||||||
_gpBindingsManager.CommitBindings();
|
bool result = _gpBindingsManager.CommitBindings(specState);
|
||||||
|
|
||||||
UpdateRenderTargets();
|
UpdateRenderTargets();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a texture pool from the cache, with the given address and maximum id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="poolGpuVa">GPU virtual address of the texture pool</param>
|
||||||
|
/// <param name="maximumId">Maximum ID of the texture pool</param>
|
||||||
|
/// <returns>The texture pool</returns>
|
||||||
|
public TexturePool GetTexturePool(ulong poolGpuVa, int maximumId)
|
||||||
|
{
|
||||||
|
ulong poolAddress = _channel.MemoryManager.Translate(poolGpuVa);
|
||||||
|
|
||||||
|
TexturePool texturePool = _texturePoolCache.FindOrCreate(_channel, poolAddress, maximumId);
|
||||||
|
|
||||||
|
return texturePool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
private readonly ConcurrentQueue<Texture> _dereferenceQueue = new ConcurrentQueue<Texture>();
|
private readonly ConcurrentQueue<Texture> _dereferenceQueue = new ConcurrentQueue<Texture>();
|
||||||
|
private int _modifiedSequenceNumber;
|
||||||
|
private TextureDescriptor _defaultDescriptor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Intrusive linked list node used on the texture pool cache.
|
/// Intrusive linked list node used on the texture pool cache.
|
||||||
|
@ -33,30 +35,19 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the texture with the given ID.
|
/// Gets the texture descripor and texture with the given ID with no bounds check or synchronization.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||||
/// <returns>The texture with the given ID</returns>
|
/// <param name="texture">The texture with the given ID</param>
|
||||||
public override Texture Get(int id)
|
/// <returns>The texture descriptor with the given ID</returns>
|
||||||
|
public ref readonly TextureDescriptor GetInternal(int id, out Texture texture)
|
||||||
{
|
{
|
||||||
if ((uint)id >= Items.Length)
|
texture = Items[id];
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SequenceNumber != Context.SequenceNumber)
|
ref readonly TextureDescriptor descriptor = ref GetDescriptorRef(id);
|
||||||
{
|
|
||||||
SequenceNumber = Context.SequenceNumber;
|
|
||||||
|
|
||||||
SynchronizeMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture texture = Items[id];
|
|
||||||
|
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
TextureDescriptor descriptor = GetDescriptor(id);
|
|
||||||
|
|
||||||
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
TextureInfo info = GetInfo(descriptor, out int layerSize);
|
||||||
|
|
||||||
ProcessDereferenceQueue();
|
ProcessDereferenceQueue();
|
||||||
|
@ -66,7 +57,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
// If this happens, then the texture address is invalid, we can't add it to the cache.
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
{
|
||||||
return null;
|
return ref descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
texture.IncrementReferenceCount(this, id);
|
texture.IncrementReferenceCount(this, id);
|
||||||
|
@ -82,8 +73,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
// Texture changed size at one point - it may be a different size than the sampler expects.
|
// Texture changed size at one point - it may be a different size than the sampler expects.
|
||||||
// This can be triggered when the size is changed by a size hint on copy or draw, but the texture has been sampled before.
|
// This can be triggered when the size is changed by a size hint on copy or draw, but the texture has been sampled before.
|
||||||
|
|
||||||
TextureDescriptor descriptor = GetDescriptor(id);
|
|
||||||
|
|
||||||
int baseLevel = descriptor.UnpackBaseLevel();
|
int baseLevel = descriptor.UnpackBaseLevel();
|
||||||
int width = Math.Max(1, descriptor.UnpackWidth() >> baseLevel);
|
int width = Math.Max(1, descriptor.UnpackWidth() >> baseLevel);
|
||||||
int height = Math.Max(1, descriptor.UnpackHeight() >> baseLevel);
|
int height = Math.Max(1, descriptor.UnpackHeight() >> baseLevel);
|
||||||
|
@ -98,9 +87,77 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
texture.SynchronizeMemory();
|
texture.SynchronizeMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ref descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the texture with the given ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||||
|
/// <returns>The texture with the given ID</returns>
|
||||||
|
public override Texture Get(int id)
|
||||||
|
{
|
||||||
|
if ((uint)id >= Items.Length)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SequenceNumber != Context.SequenceNumber)
|
||||||
|
{
|
||||||
|
SequenceNumber = Context.SequenceNumber;
|
||||||
|
|
||||||
|
if (SynchronizeMemory())
|
||||||
|
{
|
||||||
|
_modifiedSequenceNumber = SequenceNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GetInternal(id, out Texture texture);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the texture descripor and texture with the given ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method assumes that the pool has been manually synchronized before doing binding.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
|
||||||
|
/// <param name="texture">The texture with the given ID</param>
|
||||||
|
/// <returns>The texture descriptor with the given ID</returns>
|
||||||
|
public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture)
|
||||||
|
{
|
||||||
|
if ((uint)id >= Items.Length)
|
||||||
|
{
|
||||||
|
texture = null;
|
||||||
|
return ref _defaultDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When getting for binding, assume the pool has already been synchronized.
|
||||||
|
|
||||||
|
return ref GetInternal(id, out texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The last sequence number where a modifiaction was detected</returns>
|
||||||
|
public int CheckModified()
|
||||||
|
{
|
||||||
|
if (SequenceNumber != Context.SequenceNumber)
|
||||||
|
{
|
||||||
|
SequenceNumber = Context.SequenceNumber;
|
||||||
|
|
||||||
|
if (SynchronizeMemory())
|
||||||
|
{
|
||||||
|
_modifiedSequenceNumber = SequenceNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _modifiedSequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forcibly remove a texture from this pool's items.
|
/// Forcibly remove a texture from this pool's items.
|
||||||
/// If deferred, the dereference will be queued to occur on the render thread.
|
/// If deferred, the dereference will be queued to occur on the render thread.
|
||||||
|
@ -175,7 +232,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// <param name="descriptor">The texture descriptor</param>
|
/// <param name="descriptor">The texture descriptor</param>
|
||||||
/// <param name="layerSize">Layer size for textures using a sub-range of mipmap levels, otherwise 0</param>
|
/// <param name="layerSize">Layer size for textures using a sub-range of mipmap levels, otherwise 0</param>
|
||||||
/// <returns>The texture information</returns>
|
/// <returns>The texture information</returns>
|
||||||
private TextureInfo GetInfo(TextureDescriptor descriptor, out int layerSize)
|
private TextureInfo GetInfo(in TextureDescriptor descriptor, out int layerSize)
|
||||||
{
|
{
|
||||||
int depthOrLayers = descriptor.UnpackDepth();
|
int depthOrLayers = descriptor.UnpackDepth();
|
||||||
int levels = descriptor.UnpackLevels();
|
int levels = descriptor.UnpackLevels();
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Graphics.Gpu.Image;
|
||||||
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Gpu.Shader.DiskCache;
|
using Ryujinx.Graphics.Gpu.Shader.DiskCache;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Shader
|
namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
|
@ -158,6 +163,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization;
|
private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization;
|
||||||
|
private KeyValuePair<TextureKey, Box<TextureSpecializationState>>[] _allTextures;
|
||||||
|
private Box<TextureSpecializationState>[][] _textureByBinding;
|
||||||
|
private Box<TextureSpecializationState>[][] _imageByBinding;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the shader specialization state.
|
/// Creates a new instance of the shader specialization state.
|
||||||
|
@ -194,6 +202,42 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Prepare(CachedShaderStage[] stages)
|
||||||
|
{
|
||||||
|
_allTextures = _textureSpecialization.ToArray();
|
||||||
|
|
||||||
|
_textureByBinding = new Box<TextureSpecializationState>[stages.Length][];
|
||||||
|
_imageByBinding = new Box<TextureSpecializationState>[stages.Length][];
|
||||||
|
|
||||||
|
for (int i = 0; i < stages.Length; i++)
|
||||||
|
{
|
||||||
|
CachedShaderStage stage = stages[i];
|
||||||
|
if (stage != null)
|
||||||
|
{
|
||||||
|
var textures = stage.Info.Textures;
|
||||||
|
var images = stage.Info.Images;
|
||||||
|
|
||||||
|
var texBindings = new Box<TextureSpecializationState>[textures.Count];
|
||||||
|
var imageBindings = new Box<TextureSpecializationState>[images.Count];
|
||||||
|
|
||||||
|
for (int j = 0; j < textures.Count; j++)
|
||||||
|
{
|
||||||
|
var texture = textures[j];
|
||||||
|
texBindings[j] = GetTextureSpecState(i, texture.HandleIndex, texture.CbufSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < images.Count; j++)
|
||||||
|
{
|
||||||
|
var image = images[j];
|
||||||
|
imageBindings[j] = GetTextureSpecState(i, image.HandleIndex, image.CbufSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
_textureByBinding[i] = texBindings;
|
||||||
|
_imageByBinding[i] = imageBindings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the shader accesses the early Z force state.
|
/// Indicates that the shader accesses the early Z force state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -396,15 +440,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
/// <param name="graphicsState">Graphics state</param>
|
/// <param name="graphicsState">Graphics state</param>
|
||||||
|
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||||
/// <returns>True if the state matches, false otherwise</returns>
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState)
|
public bool MatchesGraphics(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelGraphicsState graphicsState, bool checkTextures)
|
||||||
{
|
{
|
||||||
if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
|
if (graphicsState.ViewportTransformDisable != GraphicsState.ViewportTransformDisable)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Matches(channel, poolState, isCompute: false);
|
return Matches(channel, poolState, checkTextures, isCompute: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -412,10 +457,64 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
|
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||||
/// <returns>True if the state matches, false otherwise</returns>
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState)
|
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures)
|
||||||
{
|
{
|
||||||
return Matches(channel, poolState, isCompute: true);
|
return Matches(channel, poolState, checkTextures, isCompute: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetch the constant buffers used for a texture to cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channel">GPU channel</param>
|
||||||
|
/// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
|
||||||
|
/// <param name="stageIndex">Stage index of the constant buffer</param>
|
||||||
|
/// <param name="cachedTextureBufferIndex">The currently cached texture buffer index</param>
|
||||||
|
/// <param name="cachedSamplerBufferIndex">The currently cached sampler buffer index</param>
|
||||||
|
/// <param name="cachedTextureBuffer">The currently cached texture buffer data</param>
|
||||||
|
/// <param name="cachedSamplerBuffer">The currently cached sampler buffer data</param>
|
||||||
|
/// <param name="cachedStageIndex">The currently cached stage</param>
|
||||||
|
/// <param name="textureBufferIndex">The new texture buffer index</param>
|
||||||
|
/// <param name="samplerBufferIndex">The new sampler buffer index</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void UpdateCachedBuffer(
|
||||||
|
GpuChannel channel,
|
||||||
|
bool isCompute,
|
||||||
|
ref int cachedTextureBufferIndex,
|
||||||
|
ref int cachedSamplerBufferIndex,
|
||||||
|
ref ReadOnlySpan<int> cachedTextureBuffer,
|
||||||
|
ref ReadOnlySpan<int> cachedSamplerBuffer,
|
||||||
|
ref int cachedStageIndex,
|
||||||
|
int textureBufferIndex,
|
||||||
|
int samplerBufferIndex,
|
||||||
|
int stageIndex)
|
||||||
|
{
|
||||||
|
bool stageChange = stageIndex != cachedStageIndex;
|
||||||
|
|
||||||
|
if (stageChange || textureBufferIndex != cachedTextureBufferIndex)
|
||||||
|
{
|
||||||
|
ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, textureBufferIndex);
|
||||||
|
|
||||||
|
cachedTextureBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
|
||||||
|
cachedTextureBufferIndex = textureBufferIndex;
|
||||||
|
|
||||||
|
if (samplerBufferIndex == textureBufferIndex)
|
||||||
|
{
|
||||||
|
cachedSamplerBuffer = cachedTextureBuffer;
|
||||||
|
cachedSamplerBufferIndex = samplerBufferIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stageChange || cachedSamplerBufferIndex != samplerBufferIndex)
|
||||||
|
{
|
||||||
|
ref BufferBounds bounds = ref channel.BufferManager.GetUniformBufferBounds(isCompute, stageIndex, samplerBufferIndex);
|
||||||
|
|
||||||
|
cachedSamplerBuffer = MemoryMarshal.Cast<byte, int>(channel.MemoryManager.Physical.GetSpan(bounds.Address, (int)bounds.Size));
|
||||||
|
cachedSamplerBufferIndex = samplerBufferIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedStageIndex = stageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -423,9 +522,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="poolState">Texture pool state</param>
|
/// <param name="poolState">Texture pool state</param>
|
||||||
|
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||||
/// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
|
/// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
|
||||||
/// <returns>True if the state matches, false otherwise</returns>
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool isCompute)
|
private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
|
||||||
{
|
{
|
||||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||||
|
|
||||||
|
@ -445,55 +545,62 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
constantBufferUsePerStageMask &= ~(1 << index);
|
constantBufferUsePerStageMask &= ~(1 << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var kv in _textureSpecialization)
|
if (checkTextures)
|
||||||
{
|
{
|
||||||
TextureKey textureKey = kv.Key;
|
TexturePool pool = channel.TextureManager.GetTexturePool(poolState.TexturePoolGpuVa, poolState.TexturePoolMaximumId);
|
||||||
|
|
||||||
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
|
int cachedTextureBufferIndex = -1;
|
||||||
|
int cachedSamplerBufferIndex = -1;
|
||||||
|
int cachedStageIndex = -1;
|
||||||
|
ReadOnlySpan<int> cachedTextureBuffer = Span<int>.Empty;
|
||||||
|
ReadOnlySpan<int> cachedSamplerBuffer = Span<int>.Empty;
|
||||||
|
|
||||||
ulong textureCbAddress;
|
foreach (var kv in _allTextures)
|
||||||
ulong samplerCbAddress;
|
|
||||||
|
|
||||||
if (isCompute)
|
|
||||||
{
|
{
|
||||||
textureCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(textureBufferIndex);
|
TextureKey textureKey = kv.Key;
|
||||||
samplerCbAddress = channel.BufferManager.GetComputeUniformBufferAddress(samplerBufferIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
textureCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, textureBufferIndex);
|
|
||||||
samplerCbAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(textureKey.StageIndex, samplerBufferIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!channel.MemoryManager.Physical.IsMapped(textureCbAddress) || !channel.MemoryManager.Physical.IsMapped(samplerCbAddress))
|
(int textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(textureKey.CbufSlot, poolState.TextureBufferIndex);
|
||||||
{
|
|
||||||
continue;
|
UpdateCachedBuffer(channel,
|
||||||
|
isCompute,
|
||||||
|
ref cachedTextureBufferIndex,
|
||||||
|
ref cachedSamplerBufferIndex,
|
||||||
|
ref cachedTextureBuffer,
|
||||||
|
ref cachedSamplerBuffer,
|
||||||
|
ref cachedStageIndex,
|
||||||
|
textureBufferIndex,
|
||||||
|
samplerBufferIndex,
|
||||||
|
textureKey.StageIndex);
|
||||||
|
|
||||||
|
int packedId = TextureHandle.ReadPackedId(textureKey.Handle, cachedTextureBuffer, cachedSamplerBuffer);
|
||||||
|
|
||||||
|
int textureId = TextureHandle.UnpackTextureId(packedId);
|
||||||
|
|
||||||
|
ref readonly Image.TextureDescriptor descriptor = ref pool.GetDescriptorRef(textureId);
|
||||||
|
|
||||||
|
Box<TextureSpecializationState> specializationState = kv.Value;
|
||||||
|
|
||||||
|
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
||||||
|
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Image.TextureDescriptor descriptor;
|
return true;
|
||||||
|
}
|
||||||
if (isCompute)
|
|
||||||
{
|
|
||||||
descriptor = channel.TextureManager.GetComputeTextureDescriptor(
|
|
||||||
poolState.TexturePoolGpuVa,
|
|
||||||
poolState.TextureBufferIndex,
|
|
||||||
poolState.TexturePoolMaximumId,
|
|
||||||
textureKey.Handle,
|
|
||||||
textureKey.CbufSlot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
descriptor = channel.TextureManager.GetGraphicsTextureDescriptor(
|
|
||||||
poolState.TexturePoolGpuVa,
|
|
||||||
poolState.TextureBufferIndex,
|
|
||||||
poolState.TexturePoolMaximumId,
|
|
||||||
textureKey.StageIndex,
|
|
||||||
textureKey.Handle,
|
|
||||||
textureKey.CbufSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
Box<TextureSpecializationState> specializationState = kv.Value;
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the recorded texture state matches the given texture descriptor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="specializationState">Texture specialization state</param>
|
||||||
|
/// <param name="descriptor">Texture descriptor</param>
|
||||||
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
|
private bool MatchesTexture(Box<TextureSpecializationState> specializationState, in Image.TextureDescriptor descriptor)
|
||||||
|
{
|
||||||
|
if (specializationState != null)
|
||||||
|
{
|
||||||
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
||||||
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
||||||
{
|
{
|
||||||
|
@ -504,6 +611,34 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the recorded texture state for a given texture binding matches a texture descriptor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stage">The shader stage</param>
|
||||||
|
/// <param name="index">The texture index</param>
|
||||||
|
/// <param name="descriptor">Texture descriptor</param>
|
||||||
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
|
public bool MatchesTexture(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
|
||||||
|
{
|
||||||
|
Box<TextureSpecializationState> specializationState = _textureByBinding[(int)stage][index];
|
||||||
|
|
||||||
|
return MatchesTexture(specializationState, descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the recorded texture state for a given image binding matches a texture descriptor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stage">The shader stage</param>
|
||||||
|
/// <param name="index">The texture index</param>
|
||||||
|
/// <param name="descriptor">Texture descriptor</param>
|
||||||
|
/// <returns>True if the state matches, false otherwise</returns>
|
||||||
|
public bool MatchesImage(ShaderStage stage, int index, in Image.TextureDescriptor descriptor)
|
||||||
|
{
|
||||||
|
Box<TextureSpecializationState> specializationState = _imageByBinding[(int)stage][index];
|
||||||
|
|
||||||
|
return MatchesTexture(specializationState, descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads shader specialization state that has been serialized.
|
/// Reads shader specialization state that has been serialized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in a new issue