Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9ac66336a2 | ||
|
4965681e06 |
@@ -202,57 +202,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
|
||||
}
|
||||
|
||||
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
|
||||
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
|
||||
_channel.BufferManager.SetComputeBufferBindings(cs.Bindings);
|
||||
|
||||
int maxTextureBinding = -1;
|
||||
int maxImageBinding = -1;
|
||||
|
||||
TextureBindingInfo[] textureBindings = _channel.TextureManager.RentComputeTextureBindings(info.Textures.Count);
|
||||
|
||||
for (int index = 0; index < info.Textures.Count; index++)
|
||||
{
|
||||
var descriptor = info.Textures[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
|
||||
textureBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxTextureBinding)
|
||||
{
|
||||
maxTextureBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentComputeImageBindings(info.Images.Count);
|
||||
|
||||
for (int index = 0; index < info.Images.Count; index++)
|
||||
{
|
||||
var descriptor = info.Images[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
|
||||
imageBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxImageBinding)
|
||||
{
|
||||
maxImageBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
_channel.TextureManager.SetComputeMaxBindings(maxTextureBinding, maxImageBinding);
|
||||
_channel.TextureManager.SetComputeBindings(cs.Bindings);
|
||||
|
||||
// Should never return false for mismatching spec state, since the shader was fetched above.
|
||||
_channel.TextureManager.CommitComputeBindings(cs.SpecializationState);
|
||||
|
@@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
private readonly DrawState _drawState;
|
||||
private readonly SpecializationStateUpdater _currentSpecState;
|
||||
private bool _topologySet;
|
||||
|
||||
private bool _instancedDrawPending;
|
||||
@@ -44,12 +45,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">Channel state</param>
|
||||
/// <param name="drawState">Draw state</param>
|
||||
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
|
||||
/// <param name="spec">Specialization state updater</param>
|
||||
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
_drawState = drawState;
|
||||
_currentSpecState = spec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,6 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.FirstIndex = firstIndex;
|
||||
_drawState.IndexCount = indexCount;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(false);
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
@@ -256,6 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
if (_drawState.Topology != topology || !_topologySet)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||
_currentSpecState.SetTopology(topology);
|
||||
_drawState.Topology = topology;
|
||||
_topologySet = true;
|
||||
}
|
||||
@@ -452,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.FirstInstance = (uint)firstInstance;
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.HasConstantBufferDrawParameters = true;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(true);
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
@@ -469,7 +474,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.FirstInstance = 0;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.HasConstantBufferDrawParameters = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
@@ -527,7 +531,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.DrawIndirect = true;
|
||||
_drawState.HasConstantBufferDrawParameters = true;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(true);
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
@@ -561,7 +565,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.DrawIndirect = false;
|
||||
_drawState.HasConstantBufferDrawParameters = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
|
280
Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
Normal file
280
Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a "current" specialiation state, and provides a flag to check if it has changed meaningfully.
|
||||
/// </summary>
|
||||
internal class SpecializationStateUpdater
|
||||
{
|
||||
private GpuChannelGraphicsState _graphics;
|
||||
private GpuChannelPoolState _pool;
|
||||
|
||||
private bool _usesDrawParameters;
|
||||
private bool _usesTopology;
|
||||
|
||||
private bool _changed;
|
||||
|
||||
/// <summary>
|
||||
/// Signal that the specialization state has changed.
|
||||
/// </summary>
|
||||
private void Signal()
|
||||
{
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specialization state has changed since the last check.
|
||||
/// </summary>
|
||||
/// <returns>True if it has changed, false otherwise</returns>
|
||||
public bool HasChanged()
|
||||
{
|
||||
if (_changed)
|
||||
{
|
||||
_changed = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the active shader, clearing the dirty state and recording if certain specializations are noteworthy.
|
||||
/// </summary>
|
||||
/// <param name="gs">The active shader</param>
|
||||
public void SetShader(CachedShaderProgram gs)
|
||||
{
|
||||
_usesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
_usesTopology = gs.SpecializationState.IsPrimitiveTopologyQueried();
|
||||
|
||||
_changed = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current graphics state.
|
||||
/// </summary>
|
||||
/// <returns>GPU graphics state</returns>
|
||||
public ref GpuChannelGraphicsState GetGraphicsState()
|
||||
{
|
||||
return ref _graphics;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current pool state.
|
||||
/// </summary>
|
||||
/// <returns>GPU pool state</returns>
|
||||
public ref GpuChannelPoolState GetPoolState()
|
||||
{
|
||||
return ref _pool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Early Z force enable.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetEarlyZForce(bool value)
|
||||
{
|
||||
_graphics.EarlyZForce = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology of current draw.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetTopology(PrimitiveTopology value)
|
||||
{
|
||||
if (value != _graphics.Topology)
|
||||
{
|
||||
_graphics.Topology = value;
|
||||
|
||||
if (_usesTopology)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tessellation mode.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetTessellationMode(TessMode value)
|
||||
{
|
||||
if (value.Packed != _graphics.TessellationMode.Packed)
|
||||
{
|
||||
_graphics.TessellationMode = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates alpha-to-coverage state, and sets it as changed.
|
||||
/// </summary>
|
||||
/// <param name="enable">Whether alpha-to-coverage is enabled</param>
|
||||
/// <param name="ditherEnable">Whether alpha-to-coverage dithering is enabled</param>
|
||||
public void SetAlphaToCoverageEnable(bool enable, bool ditherEnable)
|
||||
{
|
||||
_graphics.AlphaToCoverageEnable = enable;
|
||||
_graphics.AlphaToCoverageDitherEnable = ditherEnable;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the viewport transform is disabled.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetViewportTransformDisable(bool value)
|
||||
{
|
||||
if (value != _graphics.ViewportTransformDisable)
|
||||
{
|
||||
_graphics.ViewportTransformDisable = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Depth mode zero to one or minus one to one.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetDepthMode(bool value)
|
||||
{
|
||||
if (value != _graphics.DepthMode)
|
||||
{
|
||||
_graphics.DepthMode = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the point size is set on the shader or is fixed.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetProgramPointSizeEnable(bool value)
|
||||
{
|
||||
if (value != _graphics.ProgramPointSizeEnable)
|
||||
{
|
||||
_graphics.ProgramPointSizeEnable = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Point size used if <see cref="SetProgramPointSizeEnable" /> is provided false.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetPointSize(float value)
|
||||
{
|
||||
if (value != _graphics.PointSize)
|
||||
{
|
||||
_graphics.PointSize = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates alpha test specialization state, and sets it as changed.
|
||||
/// </summary>
|
||||
/// <param name="enable">Whether alpha test is enabled</param>
|
||||
/// <param name="reference">The value to compare with the fragment output alpha</param>
|
||||
/// <param name="op">The comparison that decides if the fragment should be discarded</param>
|
||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||
{
|
||||
_graphics.AlphaTestEnable = enable;
|
||||
_graphics.AlphaTestReference = reference;
|
||||
_graphics.AlphaTestCompare = op;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the type of the vertex attributes consumed by the shader.
|
||||
/// </summary>
|
||||
/// <param name="state">The new state</param>
|
||||
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
|
||||
{
|
||||
bool changed = false;
|
||||
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||
|
||||
for (int location = 0; location < state.Length; location++)
|
||||
{
|
||||
VertexAttribType type = state[location].UnpackType();
|
||||
|
||||
AttributeType value = type switch
|
||||
{
|
||||
VertexAttribType.Sint => AttributeType.Sint,
|
||||
VertexAttribType.Uint => AttributeType.Uint,
|
||||
_ => AttributeType.Float
|
||||
};
|
||||
|
||||
if (attributeTypes[location] != value)
|
||||
{
|
||||
attributeTypes[location] = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetHasConstantBufferDrawParameters(bool value)
|
||||
{
|
||||
if (value != _graphics.HasConstantBufferDrawParameters)
|
||||
{
|
||||
_graphics.HasConstantBufferDrawParameters = value;
|
||||
|
||||
if (_usesDrawParameters)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that any storage buffer use is unaligned.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetHasUnalignedStorageBuffer(bool value)
|
||||
{
|
||||
if (value != _graphics.HasUnalignedStorageBuffer)
|
||||
{
|
||||
_graphics.HasUnalignedStorageBuffer = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the GPU pool state.
|
||||
/// </summary>
|
||||
/// <param name="state">The new state</param>
|
||||
public void SetPoolState(GpuChannelPoolState state)
|
||||
{
|
||||
if (!state.Equals(_pool))
|
||||
{
|
||||
_pool = state;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
@@ -16,9 +17,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
class StateUpdater
|
||||
{
|
||||
public const int ShaderStateIndex = 16;
|
||||
public const int ShaderStateIndex = 26;
|
||||
public const int RasterizerStateIndex = 15;
|
||||
public const int ScissorStateIndex = 18;
|
||||
public const int ScissorStateIndex = 16;
|
||||
public const int VertexBufferStateIndex = 0;
|
||||
public const int PrimitiveRestartStateIndex = 12;
|
||||
|
||||
@@ -31,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
private readonly ShaderProgramInfo[] _currentProgramInfo;
|
||||
private ShaderSpecializationState _shaderSpecState;
|
||||
private SpecializationStateUpdater _currentSpecState;
|
||||
|
||||
private ProgramPipelineState _pipeline;
|
||||
|
||||
@@ -54,15 +56,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">3D engine state</param>
|
||||
/// <param name="drawState">Draw state</param>
|
||||
public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
|
||||
/// <param name="spec">Specialization state updater</param>
|
||||
public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
_drawState = drawState;
|
||||
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
|
||||
_currentSpecState = spec;
|
||||
|
||||
// ShaderState must be updated after other state updates, as pipeline state is sent to the backend when compiling new shaders.
|
||||
// ShaderState must be updated after other state updates, as specialization/pipeline state is used when fetching shaders.
|
||||
// Render target state must appear after shader state as it depends on information from the currently bound shader.
|
||||
// Rasterizer and scissor states are checked by render target clear, their indexes
|
||||
// must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
|
||||
@@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
nameof(ThreedClassState.DepthTestFunc)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateTessellationState,
|
||||
nameof(ThreedClassState.TessMode),
|
||||
nameof(ThreedClassState.TessOuterLevel),
|
||||
nameof(ThreedClassState.TessInnerLevel),
|
||||
nameof(ThreedClassState.PatchVertices)),
|
||||
@@ -138,17 +143,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateShaderState,
|
||||
nameof(ThreedClassState.ShaderBaseAddress),
|
||||
nameof(ThreedClassState.ShaderState)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateRenderTargetState,
|
||||
nameof(ThreedClassState.RtColorState),
|
||||
nameof(ThreedClassState.RtDepthStencilState),
|
||||
nameof(ThreedClassState.RtControl),
|
||||
nameof(ThreedClassState.RtDepthStencilSize),
|
||||
nameof(ThreedClassState.RtDepthStencilEnable)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateScissorState,
|
||||
nameof(ThreedClassState.ScissorState),
|
||||
nameof(ThreedClassState.ScreenScissorState)),
|
||||
@@ -179,7 +173,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateMultisampleState,
|
||||
nameof(ThreedClassState.AlphaToCoverageDitherEnable),
|
||||
nameof(ThreedClassState.MultisampleControl))
|
||||
nameof(ThreedClassState.MultisampleControl)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateEarlyZState,
|
||||
nameof(ThreedClassState.EarlyZForce)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateShaderState,
|
||||
nameof(ThreedClassState.ShaderBaseAddress),
|
||||
nameof(ThreedClassState.ShaderState)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateRenderTargetState,
|
||||
nameof(ThreedClassState.RtColorState),
|
||||
nameof(ThreedClassState.RtDepthStencilState),
|
||||
nameof(ThreedClassState.RtControl),
|
||||
nameof(ThreedClassState.RtDepthStencilSize),
|
||||
nameof(ThreedClassState.RtDepthStencilEnable)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,17 +217,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Update()
|
||||
{
|
||||
// If any state that the shader depends on changed,
|
||||
// then we may need to compile/bind a different version
|
||||
// of the shader for the new state.
|
||||
if (_shaderSpecState != null)
|
||||
{
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||
{
|
||||
ForceShaderUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// The vertex buffer size is calculated using a different
|
||||
// method when doing indexed draws, so we need to make sure
|
||||
// to update the vertex buffers if we are doing a regular
|
||||
@@ -271,6 +268,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_updateTracker.Update(ulong.MaxValue);
|
||||
|
||||
// If any state that the shader depends on changed,
|
||||
// then we may need to compile/bind a different version
|
||||
// of the shader for the new state.
|
||||
if (_shaderSpecState != null && _currentSpecState.HasChanged())
|
||||
{
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||
{
|
||||
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
||||
UpdateShaderState();
|
||||
}
|
||||
}
|
||||
|
||||
CommitBindings();
|
||||
|
||||
if (tfEnable && !_prevTfEnable)
|
||||
@@ -302,7 +311,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
|
||||
{
|
||||
// Shader must be reloaded.
|
||||
_currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers);
|
||||
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
||||
UpdateShaderState();
|
||||
}
|
||||
|
||||
@@ -351,6 +361,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.PatchVertices,
|
||||
_state.State.TessOuterLevel.AsSpan(),
|
||||
_state.State.TessInnerLevel.AsSpan());
|
||||
|
||||
_currentSpecState.SetTessellationMode(_state.State.TessMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -611,6 +623,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestRef,
|
||||
_state.State.AlphaTestFunc);
|
||||
|
||||
_currentSpecState.SetAlphaTest(
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestRef,
|
||||
_state.State.AlphaTestFunc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -710,6 +727,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
|
||||
_context.Renderer.Pipeline.SetViewports(viewports, disableTransform);
|
||||
|
||||
_currentSpecState.SetViewportTransformDisable(_state.State.ViewportTransformEnable == 0);
|
||||
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -847,6 +867,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
|
||||
_channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex);
|
||||
|
||||
_currentSpecState.SetPoolState(GetPoolState());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -887,6 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -914,6 +937,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
|
||||
|
||||
_context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
|
||||
|
||||
_currentSpecState.SetProgramPointSizeEnable(isProgramPointSize);
|
||||
_currentSpecState.SetPointSize(size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1212,6 +1238,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
alphaToCoverageEnable,
|
||||
_state.State.AlphaToCoverageDitherEnable,
|
||||
alphaToOneEnable));
|
||||
|
||||
_currentSpecState.SetAlphaToCoverageEnable(alphaToCoverageEnable, _state.State.AlphaToCoverageDitherEnable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the early z flag, based on guest state.
|
||||
/// </summary>
|
||||
private void UpdateEarlyZState()
|
||||
{
|
||||
_currentSpecState.SetEarlyZForce(_state.State.EarlyZForce);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1239,10 +1275,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
addressesSpan[index] = baseAddress + shader.Offset;
|
||||
}
|
||||
|
||||
GpuChannelPoolState poolState = GetPoolState();
|
||||
GpuChannelGraphicsState graphicsState = GetGraphicsState();
|
||||
CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses);
|
||||
|
||||
CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, poolState, graphicsState, addresses);
|
||||
// Consume the modified flag for spec state so that it isn't checked again.
|
||||
_currentSpecState.SetShader(gs);
|
||||
|
||||
_shaderSpecState = gs.SpecializationState;
|
||||
|
||||
@@ -1257,88 +1293,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
UpdateUserClipState();
|
||||
}
|
||||
|
||||
UpdateShaderBindings(gs.Bindings);
|
||||
|
||||
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
||||
{
|
||||
UpdateStageBindings(stageIndex, gs.Shaders[stageIndex + 1]?.Info);
|
||||
_currentProgramInfo[stageIndex] = gs.Shaders[stageIndex + 1]?.Info;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates bindings consumed by the shader stage on the texture and buffer managers.
|
||||
/// Updates bindings consumed by the shader on the texture and buffer managers.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage to have the bindings updated</param>
|
||||
/// <param name="info">Shader stage bindings info</param>
|
||||
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
private void UpdateShaderBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
_currentProgramInfo[stage] = info;
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
_channel.TextureManager.RentGraphicsTextureBindings(stage, 0);
|
||||
_channel.TextureManager.RentGraphicsImageBindings(stage, 0);
|
||||
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
|
||||
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
|
||||
return;
|
||||
}
|
||||
|
||||
int maxTextureBinding = -1;
|
||||
int maxImageBinding = -1;
|
||||
|
||||
Span<TextureBindingInfo> textureBindings = _channel.TextureManager.RentGraphicsTextureBindings(stage, info.Textures.Count);
|
||||
|
||||
if (info.UsesRtLayer)
|
||||
{
|
||||
_vtgWritesRtLayer = true;
|
||||
}
|
||||
|
||||
for (int index = 0; index < info.Textures.Count; index++)
|
||||
{
|
||||
var descriptor = info.Textures[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
|
||||
textureBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxTextureBinding)
|
||||
{
|
||||
maxTextureBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentGraphicsImageBindings(stage, info.Images.Count);
|
||||
|
||||
for (int index = 0; index < info.Images.Count; index++)
|
||||
{
|
||||
var descriptor = info.Images[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
|
||||
imageBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxImageBinding)
|
||||
{
|
||||
maxImageBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
_channel.TextureManager.SetGraphicsMaxBindings(maxTextureBinding, maxImageBinding);
|
||||
|
||||
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
|
||||
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
|
||||
_channel.TextureManager.SetGraphicsBindings(bindings);
|
||||
_channel.BufferManager.SetGraphicsBufferBindings(bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1353,46 +1325,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
(int)_state.State.TextureBufferIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current GPU channel state for shader creation or compatibility verification.
|
||||
/// </summary>
|
||||
/// <returns>Current GPU channel state</returns>
|
||||
private GpuChannelGraphicsState GetGraphicsState()
|
||||
{
|
||||
ref var vertexAttribState = ref _state.State.VertexAttribState;
|
||||
|
||||
Array32<AttributeType> attributeTypes = new Array32<AttributeType>();
|
||||
|
||||
for (int location = 0; location < attributeTypes.Length; location++)
|
||||
{
|
||||
VertexAttribType type = vertexAttribState[location].UnpackType();
|
||||
|
||||
attributeTypes[location] = type switch
|
||||
{
|
||||
VertexAttribType.Sint => AttributeType.Sint,
|
||||
VertexAttribType.Uint => AttributeType.Uint,
|
||||
_ => AttributeType.Float
|
||||
};
|
||||
}
|
||||
|
||||
return new GpuChannelGraphicsState(
|
||||
_state.State.EarlyZForce,
|
||||
_drawState.Topology,
|
||||
_state.State.TessMode,
|
||||
(_state.State.MultisampleControl & 1) != 0,
|
||||
_state.State.AlphaToCoverageDitherEnable,
|
||||
_state.State.ViewportTransformEnable == 0,
|
||||
GetDepthMode() == DepthMode.MinusOneToOne,
|
||||
_state.State.VertexProgramPointSize,
|
||||
_state.State.PointSize,
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestFunc,
|
||||
_state.State.AlphaTestRef,
|
||||
ref attributeTypes,
|
||||
_drawState.HasConstantBufferDrawParameters,
|
||||
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the depth mode that is currently being used (zero to one or minus one to one).
|
||||
/// </summary>
|
||||
|
@@ -67,12 +67,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
|
||||
|
||||
var spec = new SpecializationStateUpdater();
|
||||
var drawState = new DrawState();
|
||||
|
||||
_drawManager = new DrawManager(context, channel, _state, drawState);
|
||||
_drawManager = new DrawManager(context, channel, _state, drawState, spec);
|
||||
_semaphoreUpdater = new SemaphoreUpdater(context, channel, _state);
|
||||
_cbUpdater = new ConstantBufferUpdater(channel, _state);
|
||||
_stateUpdater = new StateUpdater(context, channel, _state, drawState);
|
||||
_stateUpdater = new StateUpdater(context, channel, _state, drawState, spec);
|
||||
|
||||
// This defaults to "always", even without any register write.
|
||||
// Reads just return 0, regardless of what was set there.
|
||||
|
@@ -37,8 +37,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private TexturePool _cachedTexturePool;
|
||||
private SamplerPool _cachedSamplerPool;
|
||||
|
||||
private readonly TextureBindingInfo[][] _textureBindings;
|
||||
private readonly TextureBindingInfo[][] _imageBindings;
|
||||
private TextureBindingInfo[][] _textureBindings;
|
||||
private TextureBindingInfo[][] _imageBindings;
|
||||
|
||||
private struct TextureState
|
||||
{
|
||||
@@ -56,9 +56,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private TextureState[] _textureState;
|
||||
private TextureState[] _imageState;
|
||||
|
||||
private int[] _textureBindingsCount;
|
||||
private int[] _imageBindingsCount;
|
||||
|
||||
private int _texturePoolSequence;
|
||||
private int _samplerPoolSequence;
|
||||
|
||||
@@ -101,9 +98,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_textureState = new TextureState[InitialTextureStateSize];
|
||||
_imageState = new TextureState[InitialImageStateSize];
|
||||
|
||||
_textureBindingsCount = new int[stages];
|
||||
_imageBindingsCount = new int[stages];
|
||||
|
||||
for (int stage = 0; stage < stages; stage++)
|
||||
{
|
||||
_textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize];
|
||||
@@ -112,39 +106,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the texture bindings array for a given stage, so that they can be modified.
|
||||
/// Sets the texture and image bindings.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The texture bindings array</returns>
|
||||
public TextureBindingInfo[] RentTextureBindings(int stage, int count)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
if (count > _textureBindings[stage].Length)
|
||||
{
|
||||
Array.Resize(ref _textureBindings[stage], count);
|
||||
}
|
||||
_textureBindings = bindings.TextureBindings;
|
||||
_imageBindings = bindings.ImageBindings;
|
||||
|
||||
_textureBindingsCount[stage] = count;
|
||||
|
||||
return _textureBindings[stage];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the image bindings array for a given stage, so that they can be modified.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The image bindings array</returns>
|
||||
public TextureBindingInfo[] RentImageBindings(int stage, int count)
|
||||
{
|
||||
if (count > _imageBindings[stage].Length)
|
||||
{
|
||||
Array.Resize(ref _imageBindings[stage], count);
|
||||
}
|
||||
|
||||
_imageBindingsCount[stage] = count;
|
||||
|
||||
return _imageBindings[stage];
|
||||
SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -257,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
case ShaderStage.Vertex:
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
index += _textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex];
|
||||
index += _textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length;
|
||||
|
||||
result = texture.ScaleFactor;
|
||||
break;
|
||||
@@ -284,7 +254,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
private bool VertexRequiresScale()
|
||||
{
|
||||
for (int i = 0; i < _textureBindingsCount[0]; i++)
|
||||
for (int i = 0; i < _textureBindings[0].Length; i++)
|
||||
{
|
||||
if ((_textureBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
|
||||
{
|
||||
@@ -292,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _imageBindingsCount[0]; i++)
|
||||
for (int i = 0; i < _imageBindings[0].Length; i++)
|
||||
{
|
||||
if ((_imageBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
|
||||
{
|
||||
@@ -309,10 +279,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private void CommitRenderScale()
|
||||
{
|
||||
// Stage 0 total: Compute or Vertex.
|
||||
int total = _textureBindingsCount[0] + _imageBindingsCount[0];
|
||||
int total = _textureBindings[0].Length + _imageBindings[0].Length;
|
||||
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
int fragmentTotal = _isCompute ? 0 : (_textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex]);
|
||||
int fragmentTotal = _isCompute ? 0 : (_textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length);
|
||||
|
||||
if (total != 0 && fragmentTotal != _lastFragmentTotal && VertexRequiresScale())
|
||||
{
|
||||
@@ -481,7 +451,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
bool poolModified,
|
||||
ShaderSpecializationState specState)
|
||||
{
|
||||
int textureCount = _textureBindingsCount[stageIndex];
|
||||
int textureCount = _textureBindings[stageIndex].Length;
|
||||
if (textureCount == 0)
|
||||
{
|
||||
return true;
|
||||
@@ -609,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <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 = _imageBindings[stageIndex].Length;
|
||||
if (imageCount == 0)
|
||||
{
|
||||
return true;
|
||||
@@ -622,7 +592,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
// Scales for images appear after the texture ones.
|
||||
int baseScaleIndex = _textureBindingsCount[stageIndex];
|
||||
int baseScaleIndex = _textureBindings[stageIndex].Length;
|
||||
|
||||
int cachedTextureBufferIndex = -1;
|
||||
int cachedSamplerBufferIndex = -1;
|
||||
|
@@ -57,45 +57,21 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the texture bindings array of the compute pipeline.
|
||||
/// Sets the texture and image bindings for the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The texture bindings array</returns>
|
||||
public TextureBindingInfo[] RentComputeTextureBindings(int count)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetComputeBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
return _cpBindingsManager.RentTextureBindings(0, count);
|
||||
_cpBindingsManager.SetBindings(bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the texture bindings array for a given stage on the graphics pipeline.
|
||||
/// Sets the texture and image bindings for the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">The index of the shader stage to bind the textures</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The texture bindings array</returns>
|
||||
public TextureBindingInfo[] RentGraphicsTextureBindings(int stage, int count)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetGraphicsBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
return _gpBindingsManager.RentTextureBindings(stage, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the image bindings array of the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The image bindings array</returns>
|
||||
public TextureBindingInfo[] RentComputeImageBindings(int count)
|
||||
{
|
||||
return _cpBindingsManager.RentImageBindings(0, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the image bindings array for a given stage on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">The index of the shader stage to bind the images</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The image bindings array</returns>
|
||||
public TextureBindingInfo[] RentGraphicsImageBindings(int stage, int count)
|
||||
{
|
||||
return _gpBindingsManager.RentImageBindings(stage, count);
|
||||
_gpBindingsManager.SetBindings(bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,16 +83,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_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>
|
||||
/// Sets the texture constant buffer index on the graphics pipeline.
|
||||
/// </summary>
|
||||
@@ -126,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_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>
|
||||
/// Sets the current sampler pool on the compute pipeline.
|
||||
/// </summary>
|
||||
|
@@ -1,10 +1,10 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Shader buffer binding information.
|
||||
/// </summary>
|
||||
public BufferDescriptor[] Bindings { get; }
|
||||
public BufferDescriptor[] Bindings { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Buffer regions.
|
||||
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Sets shader buffer binding information.
|
||||
/// </summary>
|
||||
/// <param name="descriptors">Buffer binding information</param>
|
||||
public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
public void SetBindings(BufferDescriptor[] descriptors)
|
||||
{
|
||||
if (descriptors == null)
|
||||
{
|
||||
@@ -86,8 +86,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
return;
|
||||
}
|
||||
|
||||
descriptors.CopyTo(Bindings, 0);
|
||||
Count = descriptors.Count;
|
||||
if ((Count = descriptors.Length) != 0)
|
||||
{
|
||||
Bindings = descriptors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,41 +322,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Sets the binding points for the storage buffers bound on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetComputeBufferBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
_cpStorageBuffers.SetBindings(descriptors);
|
||||
_cpStorageBuffers.SetBindings(bindings.StorageBufferBindings[0]);
|
||||
_cpUniformBuffers.SetBindings(bindings.ConstantBufferBindings[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the binding points for the storage buffers bound on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">Index of the shader stage</param>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetGraphicsBufferBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
_gpStorageBuffers[stage].SetBindings(descriptors);
|
||||
for (int i = 0; i < Constants.ShaderStages; i++)
|
||||
{
|
||||
_gpStorageBuffers[i].SetBindings(bindings.StorageBufferBindings[i]);
|
||||
_gpUniformBuffers[i].SetBindings(bindings.ConstantBufferBindings[i]);
|
||||
}
|
||||
|
||||
_gpStorageBuffersDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the binding points for the uniform buffers bound on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
{
|
||||
_cpUniformBuffers.SetBindings(descriptors);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the enabled uniform buffers mask on the graphics pipeline.
|
||||
/// Each bit set on the mask indicates that the respective buffer index is enabled.
|
||||
/// </summary>
|
||||
/// <param name="stage">Index of the shader stage</param>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
{
|
||||
_gpUniformBuffers[stage].SetBindings(descriptors);
|
||||
_gpUniformBuffersDirty = true;
|
||||
}
|
||||
|
||||
|
103
Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs
Normal file
103
Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of shader bindings ready for insertion into the buffer and texture managers.
|
||||
/// </summary>
|
||||
internal class CachedShaderBindings
|
||||
{
|
||||
public TextureBindingInfo[][] TextureBindings { get; }
|
||||
public TextureBindingInfo[][] ImageBindings { get; }
|
||||
public BufferDescriptor[][] ConstantBufferBindings { get; }
|
||||
public BufferDescriptor[][] StorageBufferBindings { get; }
|
||||
|
||||
public int MaxTextureBinding { get; }
|
||||
public int MaxImageBinding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new cached shader bindings collection.
|
||||
/// </summary>
|
||||
/// <param name="isCompute">Whether the shader is for compute</param>
|
||||
/// <param name="stages">The stages used by the shader</param>
|
||||
public CachedShaderBindings(bool isCompute, CachedShaderStage[] stages)
|
||||
{
|
||||
int stageCount = isCompute ? 1 : Constants.ShaderStages;
|
||||
|
||||
TextureBindings = new TextureBindingInfo[stageCount][];
|
||||
ImageBindings = new TextureBindingInfo[stageCount][];
|
||||
ConstantBufferBindings = new BufferDescriptor[stageCount][];
|
||||
StorageBufferBindings = new BufferDescriptor[stageCount][];
|
||||
|
||||
int maxTextureBinding = -1;
|
||||
int maxImageBinding = -1;
|
||||
int offset = isCompute ? 0 : 1;
|
||||
|
||||
for (int i = 0; i < stageCount; i++)
|
||||
{
|
||||
CachedShaderStage stage = stages[i + offset];
|
||||
|
||||
if (stage == null)
|
||||
{
|
||||
TextureBindings[i] = Array.Empty<TextureBindingInfo>();
|
||||
ImageBindings[i] = Array.Empty<TextureBindingInfo>();
|
||||
ConstantBufferBindings[i] = Array.Empty<BufferDescriptor>();
|
||||
StorageBufferBindings[i] = Array.Empty<BufferDescriptor>();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
TextureBindings[i] = stage.Info.Textures.Select(descriptor =>
|
||||
{
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxTextureBinding)
|
||||
{
|
||||
maxTextureBinding = descriptor.Binding;
|
||||
}
|
||||
|
||||
return result;
|
||||
}).ToArray();
|
||||
|
||||
ImageBindings[i] = stage.Info.Images.Select(descriptor =>
|
||||
{
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxImageBinding)
|
||||
{
|
||||
maxImageBinding = descriptor.Binding;
|
||||
}
|
||||
|
||||
return result;
|
||||
}).ToArray();
|
||||
|
||||
ConstantBufferBindings[i] = stage.Info.CBuffers.ToArray();
|
||||
StorageBufferBindings[i] = stage.Info.SBuffers.ToArray();
|
||||
}
|
||||
|
||||
MaxTextureBinding = maxTextureBinding;
|
||||
MaxImageBinding = maxImageBinding;
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,6 +24,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
public CachedShaderStage[] Shaders { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached shader bindings, ready for placing into the bindings manager.
|
||||
/// </summary>
|
||||
public CachedShaderBindings Bindings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the shader bundle.
|
||||
/// </summary>
|
||||
@@ -37,6 +42,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
Shaders = shaders;
|
||||
|
||||
SpecializationState.Prepare(shaders);
|
||||
Bindings = new CachedShaderBindings(shaders.Length == 1, shaders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -15,62 +15,62 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Early Z force enable.
|
||||
/// </summary>
|
||||
public readonly bool EarlyZForce;
|
||||
public bool EarlyZForce;
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology of current draw.
|
||||
/// </summary>
|
||||
public readonly PrimitiveTopology Topology;
|
||||
public PrimitiveTopology Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Tessellation mode.
|
||||
/// </summary>
|
||||
public readonly TessMode TessellationMode;
|
||||
public TessMode TessellationMode;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether alpha-to-coverage is enabled.
|
||||
/// </summary>
|
||||
public readonly bool AlphaToCoverageEnable;
|
||||
public bool AlphaToCoverageEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether alpha-to-coverage dithering is enabled.
|
||||
/// </summary>
|
||||
public readonly bool AlphaToCoverageDitherEnable;
|
||||
public bool AlphaToCoverageDitherEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the viewport transform is disabled.
|
||||
/// </summary>
|
||||
public readonly bool ViewportTransformDisable;
|
||||
public bool ViewportTransformDisable;
|
||||
|
||||
/// <summary>
|
||||
/// Depth mode zero to one or minus one to one.
|
||||
/// </summary>
|
||||
public readonly bool DepthMode;
|
||||
public bool DepthMode;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the point size is set on the shader or is fixed.
|
||||
/// </summary>
|
||||
public readonly bool ProgramPointSizeEnable;
|
||||
public bool ProgramPointSizeEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Point size used if <see cref="ProgramPointSizeEnable" /> is false.
|
||||
/// </summary>
|
||||
public readonly float PointSize;
|
||||
public float PointSize;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether alpha test is enabled.
|
||||
/// </summary>
|
||||
public readonly bool AlphaTestEnable;
|
||||
public bool AlphaTestEnable;
|
||||
|
||||
/// <summary>
|
||||
/// When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded.
|
||||
/// </summary>
|
||||
public readonly CompareOp AlphaTestCompare;
|
||||
public CompareOp AlphaTestCompare;
|
||||
|
||||
/// <summary>
|
||||
/// When alpha test is enabled, indicates the value to compare with the fragment output alpha.
|
||||
/// </summary>
|
||||
public readonly float AlphaTestReference;
|
||||
public float AlphaTestReference;
|
||||
|
||||
/// <summary>
|
||||
/// Type of the vertex attributes consumed by the shader.
|
||||
@@ -80,12 +80,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
public readonly bool HasConstantBufferDrawParameters;
|
||||
public bool HasConstantBufferDrawParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that any storage buffer use is unaligned.
|
||||
/// </summary>
|
||||
public readonly bool HasUnalignedStorageBuffer;
|
||||
public bool HasUnalignedStorageBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GPU graphics state.
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
/// <summary>
|
||||
/// State used by the <see cref="GpuAccessor"/>.
|
||||
/// </summary>
|
||||
struct GpuChannelPoolState
|
||||
struct GpuChannelPoolState : IEquatable<GpuChannelPoolState>
|
||||
{
|
||||
/// <summary>
|
||||
/// GPU virtual address of the texture pool.
|
||||
@@ -32,5 +34,17 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
TexturePoolMaximumId = texturePoolMaximumId;
|
||||
TextureBufferIndex = textureBufferIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the pool states are equal.
|
||||
/// </summary>
|
||||
/// <param name="other">Pool state to compare with</param>
|
||||
/// <returns>True if they are equal, false otherwise</returns>
|
||||
public bool Equals(GpuChannelPoolState other)
|
||||
{
|
||||
return TexturePoolGpuVa == other.TexturePoolGpuVa &&
|
||||
TexturePoolMaximumId == other.TexturePoolMaximumId &&
|
||||
TextureBufferIndex == other.TextureBufferIndex;
|
||||
}
|
||||
}
|
||||
}
|
@@ -300,16 +300,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
ref ThreedClassState state,
|
||||
ref ProgramPipelineState pipeline,
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
ShaderAddresses addresses)
|
||||
{
|
||||
if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, poolState, graphicsState, gpShaders, addresses))
|
||||
if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses))
|
||||
{
|
||||
return gpShaders;
|
||||
}
|
||||
|
||||
if (_graphicsShaderCache.TryFind(channel, poolState, graphicsState, addresses, out gpShaders, out var cachedGuestCode))
|
||||
if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out var cachedGuestCode))
|
||||
{
|
||||
_gpPrograms[addresses] = gpShaders;
|
||||
return gpShaders;
|
||||
@@ -498,7 +498,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
if (IsShaderEqual(channel.MemoryManager, cpShader.Shaders[0], gpuVa))
|
||||
{
|
||||
return cpShader.SpecializationState.MatchesCompute(channel, poolState, computeState, true);
|
||||
return cpShader.SpecializationState.MatchesCompute(channel, ref poolState, computeState, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -515,8 +515,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if the code is different, false otherwise</returns>
|
||||
private static bool IsShaderEqual(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
CachedShaderProgram gpShaders,
|
||||
ShaderAddresses addresses)
|
||||
{
|
||||
@@ -536,7 +536,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
bool usesDrawParameters = gpShaders.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
|
||||
return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true);
|
||||
return gpShaders.SpecializationState.MatchesGraphics(channel, ref poolState, ref graphicsState, usesDrawParameters, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -215,8 +215,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if a cached host program was found, false otherwise</returns>
|
||||
public bool TryFind(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
ShaderAddresses addresses,
|
||||
out CachedShaderProgram program,
|
||||
out CachedGraphicsGuestCode guestCode)
|
||||
@@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
if (found && _shaderPrograms.TryGetValue(idTable, out ShaderSpecializationList specList))
|
||||
{
|
||||
return specList.TryFindForGraphics(channel, poolState, graphicsState, out program);
|
||||
return specList.TryFindForGraphics(channel, ref poolState, ref graphicsState, out program);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@@ -29,15 +29,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if a compatible program is found, false otherwise</returns>
|
||||
public bool TryFindForGraphics(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
out CachedShaderProgram program)
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
bool usesDrawParameters = entry.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
|
||||
if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true))
|
||||
if (entry.SpecializationState.MatchesGraphics(channel, ref poolState, ref graphicsState, usesDrawParameters, true))
|
||||
{
|
||||
program = entry;
|
||||
return true;
|
||||
@@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
if (entry.SpecializationState.MatchesCompute(channel, poolState, computeState, true))
|
||||
if (entry.SpecializationState.MatchesCompute(channel, ref poolState, computeState, true))
|
||||
{
|
||||
program = entry;
|
||||
return true;
|
||||
|
@@ -392,6 +392,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
state.Value.QueriedFlags |= QueriedTextureStateFlags.CoordNormalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if primitive topology was queried by the shader.
|
||||
/// </summary>
|
||||
/// <returns>True if queried, false otherwise</returns>
|
||||
public bool IsPrimitiveTopologyQueried()
|
||||
{
|
||||
return _queriedState.HasFlag(QueriedStateFlags.PrimitiveTopology);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given texture was registerd on this specialization state.
|
||||
/// </summary>
|
||||
@@ -486,8 +495,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
public bool MatchesGraphics(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
bool usesDrawParameters,
|
||||
bool checkTextures)
|
||||
{
|
||||
@@ -536,7 +545,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, poolState, checkTextures, isCompute: false);
|
||||
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -547,14 +556,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="computeState">Compute state</param>
|
||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
|
||||
public bool MatchesCompute(GpuChannel channel, ref GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
|
||||
{
|
||||
if (computeState.HasUnalignedStorageBuffer != ComputeState.HasUnalignedStorageBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, poolState, checkTextures, isCompute: true);
|
||||
return Matches(channel, ref poolState, checkTextures, isCompute: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -618,7 +627,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <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>
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
|
||||
private bool Matches(GpuChannel channel, ref GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
|
||||
{
|
||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||
|
||||
|
Reference in New Issue
Block a user