GPU: Swap bindings array instead of copying (#4003)
* GPU: Swap bindings array instead of copying Reduces work on UpdateShaderState. Now the cost is a few reference moves for arrays, rather than copying data. Downside: bindings arrays are no longer readonly. * Micro optimisation * Add missing docs * Address Feedback
This commit is contained in:
parent
3868a00206
commit
4965681e06
7 changed files with 162 additions and 252 deletions
|
@ -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);
|
||||
|
|
|
@ -1257,88 +1257,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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue