Use explicit buffer and texture bindings on shaders (#1666)
* Use explicit buffer and texture bindings on shaders * More XML docs and other nits
This commit is contained in:
parent
5561a3b95e
commit
8d168574eb
20 changed files with 496 additions and 551 deletions
|
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
void SetIndexBuffer(BufferRange buffer, IndexType type);
|
void SetIndexBuffer(BufferRange buffer, IndexType type);
|
||||||
|
|
||||||
void SetImage(int index, ShaderStage stage, ITexture texture, Format imageFormat);
|
void SetImage(int binding, ITexture texture, Format imageFormat);
|
||||||
|
|
||||||
void SetLogicOpState(bool enable, LogicalOp op);
|
void SetLogicOpState(bool enable, LogicalOp op);
|
||||||
|
|
||||||
|
@ -64,19 +64,19 @@ namespace Ryujinx.Graphics.GAL
|
||||||
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
|
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
|
||||||
void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
|
void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
|
||||||
|
|
||||||
void SetSampler(int index, ShaderStage stage, ISampler sampler);
|
void SetSampler(int binding, ISampler sampler);
|
||||||
|
|
||||||
void SetScissorEnable(int index, bool enable);
|
void SetScissorEnable(int index, bool enable);
|
||||||
void SetScissor(int index, int x, int y, int width, int height);
|
void SetScissor(int index, int x, int y, int width, int height);
|
||||||
|
|
||||||
void SetStencilTest(StencilTestDescriptor stencilTest);
|
void SetStencilTest(StencilTestDescriptor stencilTest);
|
||||||
|
|
||||||
void SetStorageBuffer(int index, ShaderStage stage, BufferRange buffer);
|
void SetStorageBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||||
|
|
||||||
void SetTexture(int index, ShaderStage stage, ITexture texture);
|
void SetTexture(int binding, ITexture texture);
|
||||||
|
|
||||||
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||||
void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer);
|
void SetUniformBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||||
|
|
||||||
void SetUserClipDistance(int index, bool enableClip);
|
void SetUserClipDistance(int index, bool enableClip);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
void BackgroundContextAction(Action action);
|
void BackgroundContextAction(Action action);
|
||||||
|
|
||||||
IShader CompileShader(ShaderProgram shader);
|
IShader CompileShader(ShaderStage stage, string code);
|
||||||
|
|
||||||
BufferHandle CreateBuffer(int size);
|
BufferHandle CreateBuffer(int size);
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);
|
int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);
|
||||||
|
|
||||||
uint sbEnableMask = 0;
|
|
||||||
uint ubEnableMask = 0;
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
|
for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
|
||||||
{
|
{
|
||||||
if (!qmd.ConstantBufferValid(index))
|
if (!qmd.ConstantBufferValid(index))
|
||||||
|
@ -38,8 +35,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubEnableMask |= 1u << index;
|
|
||||||
|
|
||||||
ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
|
ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
|
||||||
ulong size = (ulong)qmd.ConstantBufferSize(index);
|
ulong size = (ulong)qmd.ConstantBufferSize(index);
|
||||||
|
|
||||||
|
@ -58,13 +53,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
_context.Renderer.Pipeline.SetProgram(cs.HostProgram);
|
_context.Renderer.Pipeline.SetProgram(cs.HostProgram);
|
||||||
|
|
||||||
var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState);
|
var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState);
|
||||||
|
|
||||||
TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);
|
|
||||||
|
|
||||||
var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
|
var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
|
||||||
|
|
||||||
|
TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);
|
||||||
TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
|
TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
|
||||||
|
|
||||||
TextureManager.SetComputeTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
|
TextureManager.SetComputeTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
|
||||||
|
|
||||||
ShaderProgramInfo info = cs.Shaders[0].Program.Info;
|
ShaderProgramInfo info = cs.Shaders[0].Program.Info;
|
||||||
|
@ -82,8 +74,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubEnableMask |= 1u << cb.Slot;
|
|
||||||
|
|
||||||
ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);
|
ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);
|
||||||
|
|
||||||
int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10;
|
int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10;
|
||||||
|
@ -99,8 +89,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
{
|
{
|
||||||
BufferDescriptor sb = info.SBuffers[index];
|
BufferDescriptor sb = info.SBuffers[index];
|
||||||
|
|
||||||
sbEnableMask |= 1u << sb.Slot;
|
|
||||||
|
|
||||||
ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);
|
ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);
|
||||||
|
|
||||||
int sbDescOffset = 0x310 + sb.Slot * 0x10;
|
int sbDescOffset = 0x310 + sb.Slot * 0x10;
|
||||||
|
@ -112,15 +100,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
|
BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ubEnableMask = 0;
|
BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
|
||||||
|
BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
|
||||||
for (int index = 0; index < info.CBuffers.Count; index++)
|
|
||||||
{
|
|
||||||
ubEnableMask |= 1u << info.CBuffers[index].Slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferManager.SetComputeStorageBufferEnableMask(sbEnableMask);
|
|
||||||
BufferManager.SetComputeUniformBufferEnableMask(ubEnableMask);
|
|
||||||
|
|
||||||
var textureBindings = new TextureBindingInfo[info.Textures.Count];
|
var textureBindings = new TextureBindingInfo[info.Textures.Count];
|
||||||
|
|
||||||
|
@ -132,11 +113,16 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
if (descriptor.IsBindless)
|
if (descriptor.IsBindless)
|
||||||
{
|
{
|
||||||
textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufOffset, descriptor.CbufSlot, descriptor.Flags);
|
textureBindings[index] = new TextureBindingInfo(
|
||||||
|
target,
|
||||||
|
descriptor.Binding,
|
||||||
|
descriptor.CbufOffset,
|
||||||
|
descriptor.CbufSlot,
|
||||||
|
descriptor.Flags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex, descriptor.Flags);
|
textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +137,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||||
|
|
||||||
imageBindings[index] = new TextureBindingInfo(target, format, descriptor.HandleIndex, descriptor.Flags);
|
imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureManager.SetComputeImages(imageBindings);
|
TextureManager.SetComputeImages(imageBindings);
|
||||||
|
|
|
@ -6,6 +6,7 @@ using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Gpu.State;
|
using Ryujinx.Graphics.Gpu.State;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine
|
namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
@ -997,6 +998,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
_vsUsesInstanceId = gs.Shaders[0]?.Program.Info.UsesInstanceId ?? false;
|
_vsUsesInstanceId = gs.Shaders[0]?.Program.Info.UsesInstanceId ?? false;
|
||||||
|
|
||||||
|
int storageBufferBindingsCount = 0;
|
||||||
|
int uniformBufferBindingsCount = 0;
|
||||||
|
|
||||||
for (int stage = 0; stage < Constants.ShaderStages; stage++)
|
for (int stage = 0; stage < Constants.ShaderStages; stage++)
|
||||||
{
|
{
|
||||||
ShaderProgramInfo info = gs.Shaders[stage]?.Program.Info;
|
ShaderProgramInfo info = gs.Shaders[stage]?.Program.Info;
|
||||||
|
@ -1005,6 +1009,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
if (info == null)
|
if (info == null)
|
||||||
{
|
{
|
||||||
|
TextureManager.SetGraphicsTextures(stage, Array.Empty<TextureBindingInfo>());
|
||||||
|
TextureManager.SetGraphicsImages(stage, Array.Empty<TextureBindingInfo>());
|
||||||
|
BufferManager.SetGraphicsStorageBufferBindings(stage, null);
|
||||||
|
BufferManager.SetGraphicsUniformBufferBindings(stage, null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,11 +1026,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
|
|
||||||
if (descriptor.IsBindless)
|
if (descriptor.IsBindless)
|
||||||
{
|
{
|
||||||
textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags);
|
textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex, descriptor.Flags);
|
textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,27 +1045,27 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
||||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||||
|
|
||||||
imageBindings[index] = new TextureBindingInfo(target, format, descriptor.HandleIndex, descriptor.Flags);
|
imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureManager.SetGraphicsImages(stage, imageBindings);
|
TextureManager.SetGraphicsImages(stage, imageBindings);
|
||||||
|
|
||||||
uint sbEnableMask = 0;
|
BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
|
||||||
uint ubEnableMask = 0;
|
BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
|
||||||
|
|
||||||
for (int index = 0; index < info.SBuffers.Count; index++)
|
if (info.SBuffers.Count != 0)
|
||||||
{
|
{
|
||||||
sbEnableMask |= 1u << info.SBuffers[index].Slot;
|
storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < info.CBuffers.Count; index++)
|
if (info.CBuffers.Count != 0)
|
||||||
{
|
{
|
||||||
ubEnableMask |= 1u << info.CBuffers[index].Slot;
|
uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferManager.SetGraphicsStorageBufferEnableMask(stage, sbEnableMask);
|
BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
|
||||||
BufferManager.SetGraphicsUniformBufferEnableMask(stage, ubEnableMask);
|
BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);
|
||||||
}
|
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Format Format { get; }
|
public Format Format { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shader texture host binding point.
|
||||||
|
/// </summary>
|
||||||
|
public int Binding { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shader texture handle.
|
/// Shader texture handle.
|
||||||
/// This is an index into the texture constant buffer.
|
/// This is an index into the texture constant buffer.
|
||||||
|
@ -53,12 +58,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The shader sampler target type</param>
|
/// <param name="target">The shader sampler target type</param>
|
||||||
/// <param name="format">Format of the image as declared on the shader</param>
|
/// <param name="format">Format of the image as declared on the shader</param>
|
||||||
|
/// <param name="binding">The shader texture binding point</param>
|
||||||
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
||||||
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
||||||
public TextureBindingInfo(Target target, Format format, int handle, TextureUsageFlags flags)
|
public TextureBindingInfo(Target target, Format format, int binding, int handle, TextureUsageFlags flags)
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
Format = format;
|
Format = format;
|
||||||
|
Binding = binding;
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
|
|
||||||
IsBindless = false;
|
IsBindless = false;
|
||||||
|
@ -73,9 +80,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// Constructs the texture binding information structure.
|
/// Constructs the texture binding information structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The shader sampler target type</param>
|
/// <param name="target">The shader sampler target type</param>
|
||||||
|
/// <param name="binding">The shader texture binding point</param>
|
||||||
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
|
||||||
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
||||||
public TextureBindingInfo(Target target, int handle, TextureUsageFlags flags) : this(target, (Format)0, handle, flags)
|
public TextureBindingInfo(Target target, int binding, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, handle, flags)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +91,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// Constructs the bindless texture binding information structure.
|
/// Constructs the bindless texture binding information structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The shader sampler target type</param>
|
/// <param name="target">The shader sampler target type</param>
|
||||||
|
/// <param name="binding">The shader texture binding point</param>
|
||||||
/// <param name="cbufSlot">Constant buffer slot where the bindless texture handle is located</param>
|
/// <param name="cbufSlot">Constant buffer slot where the bindless texture handle is located</param>
|
||||||
/// <param name="cbufOffset">Constant buffer offset of the bindless texture handle</param>
|
/// <param name="cbufOffset">Constant buffer offset of the bindless texture handle</param>
|
||||||
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
|
||||||
public TextureBindingInfo(Target target, int cbufSlot, int cbufOffset, TextureUsageFlags flags)
|
public TextureBindingInfo(Target target, int binding, int cbufSlot, int cbufOffset, TextureUsageFlags flags)
|
||||||
{
|
{
|
||||||
Target = target;
|
Target = target;
|
||||||
Format = 0;
|
Format = 0;
|
||||||
|
Binding = binding;
|
||||||
Handle = 0;
|
Handle = 0;
|
||||||
|
|
||||||
IsBindless = true;
|
IsBindless = true;
|
||||||
|
|
|
@ -265,11 +265,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
for (int index = 0; index < _textureBindings[stageIndex].Length; index++)
|
for (int index = 0; index < _textureBindings[stageIndex].Length; index++)
|
||||||
{
|
{
|
||||||
TextureBindingInfo binding = _textureBindings[stageIndex][index];
|
TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index];
|
||||||
|
|
||||||
int packedId;
|
int packedId;
|
||||||
|
|
||||||
if (binding.IsBindless)
|
if (bindingInfo.IsBindless)
|
||||||
{
|
{
|
||||||
ulong address;
|
ulong address;
|
||||||
|
|
||||||
|
@ -277,18 +277,18 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (_isCompute)
|
if (_isCompute)
|
||||||
{
|
{
|
||||||
address = bufferManager.GetComputeUniformBufferAddress(binding.CbufSlot);
|
address = bufferManager.GetComputeUniformBufferAddress(bindingInfo.CbufSlot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, binding.CbufSlot);
|
address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, bindingInfo.CbufSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
packedId = _context.PhysicalMemory.Read<int>(address + (ulong)binding.CbufOffset * 4);
|
packedId = _context.PhysicalMemory.Read<int>(address + (ulong)bindingInfo.CbufOffset * 4);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
packedId = ReadPackedId(stageIndex, binding.Handle, _textureBufferIndex);
|
packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int textureId = UnpackTextureId(packedId);
|
int textureId = UnpackTextureId(packedId);
|
||||||
|
@ -305,18 +305,18 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
Texture texture = pool.Get(textureId);
|
Texture texture = pool.Get(textureId);
|
||||||
|
|
||||||
ITexture hostTexture = texture?.GetTargetTexture(binding.Target);
|
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
if (_textureState[stageIndex][index].Texture != hostTexture || _rebind)
|
if (_textureState[stageIndex][index].Texture != hostTexture || _rebind)
|
||||||
{
|
{
|
||||||
if (UpdateScale(texture, binding, index, stage))
|
if (UpdateScale(texture, bindingInfo, index, stage))
|
||||||
{
|
{
|
||||||
hostTexture = texture?.GetTargetTexture(binding.Target);
|
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
_textureState[stageIndex][index].Texture = hostTexture;
|
_textureState[stageIndex][index].Texture = hostTexture;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetTexture(index, stage, hostTexture);
|
_context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hostTexture != null && texture.Info.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Info.Target == Target.TextureBuffer)
|
||||||
|
@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
_textureState[stageIndex][index].Sampler = hostSampler;
|
_textureState[stageIndex][index].Sampler = hostSampler;
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetSampler(index, stage, hostSampler);
|
_context.Renderer.Pipeline.SetSampler(bindingInfo.Binding, hostSampler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,14 +359,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
for (int index = 0; index < _imageBindings[stageIndex].Length; index++)
|
for (int index = 0; index < _imageBindings[stageIndex].Length; index++)
|
||||||
{
|
{
|
||||||
TextureBindingInfo binding = _imageBindings[stageIndex][index];
|
TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index];
|
||||||
|
|
||||||
int packedId = ReadPackedId(stageIndex, binding.Handle, _textureBufferIndex);
|
int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex);
|
||||||
int textureId = UnpackTextureId(packedId);
|
int textureId = UnpackTextureId(packedId);
|
||||||
|
|
||||||
Texture texture = pool.Get(textureId);
|
Texture texture = pool.Get(textureId);
|
||||||
|
|
||||||
ITexture hostTexture = texture?.GetTargetTexture(binding.Target);
|
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
|
|
||||||
if (hostTexture != null && texture.Info.Target == Target.TextureBuffer)
|
if (hostTexture != null && texture.Info.Target == Target.TextureBuffer)
|
||||||
{
|
{
|
||||||
|
@ -378,21 +378,21 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (_imageState[stageIndex][index].Texture != hostTexture || _rebind)
|
if (_imageState[stageIndex][index].Texture != hostTexture || _rebind)
|
||||||
{
|
{
|
||||||
if (UpdateScale(texture, binding, baseScaleIndex + index, stage))
|
if (UpdateScale(texture, bindingInfo, baseScaleIndex + index, stage))
|
||||||
{
|
{
|
||||||
hostTexture = texture?.GetTargetTexture(binding.Target);
|
hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
_imageState[stageIndex][index].Texture = hostTexture;
|
_imageState[stageIndex][index].Texture = hostTexture;
|
||||||
|
|
||||||
Format format = binding.Format;
|
Format format = bindingInfo.Format;
|
||||||
|
|
||||||
if (format == 0 && texture != null)
|
if (format == 0 && texture != null)
|
||||||
{
|
{
|
||||||
format = texture.Format;
|
format = texture.Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImage(index, stage, hostTexture, format);
|
_context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,25 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct BufferBounds
|
struct BufferBounds
|
||||||
{
|
{
|
||||||
public ulong Address;
|
/// <summary>
|
||||||
public ulong Size;
|
/// Region virtual address.
|
||||||
|
/// </summary>
|
||||||
|
public ulong Address { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Region size in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public ulong Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new buffer region.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">Region address</param>
|
||||||
|
/// <param name="size">Region size</param>
|
||||||
|
public BufferBounds(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
Address = address;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,6 +4,8 @@ using Ryujinx.Graphics.Gpu.State;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
|
@ -12,6 +14,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class BufferManager
|
class BufferManager
|
||||||
{
|
{
|
||||||
|
private const int StackToHeapThreshold = 16;
|
||||||
|
|
||||||
private const int OverlapsBufferInitialCapacity = 10;
|
private const int OverlapsBufferInitialCapacity = 10;
|
||||||
private const int OverlapsBufferMaxCapacity = 10000;
|
private const int OverlapsBufferMaxCapacity = 10000;
|
||||||
|
|
||||||
|
@ -28,21 +32,61 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
private VertexBuffer[] _vertexBuffers;
|
private VertexBuffer[] _vertexBuffers;
|
||||||
private BufferBounds[] _transformFeedbackBuffers;
|
private BufferBounds[] _transformFeedbackBuffers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds shader stage buffer state and binding information.
|
||||||
|
/// </summary>
|
||||||
private class BuffersPerStage
|
private class BuffersPerStage
|
||||||
{
|
{
|
||||||
public uint EnableMask { get; set; }
|
/// <summary>
|
||||||
|
/// Shader buffer binding information.
|
||||||
|
/// </summary>
|
||||||
|
public BufferDescriptor[] Bindings { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Buffer regions.
|
||||||
|
/// </summary>
|
||||||
public BufferBounds[] Buffers { get; }
|
public BufferBounds[] Buffers { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total amount of buffers used on the shader.
|
||||||
|
/// </summary>
|
||||||
|
public int Count { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the shader stage buffer information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">Maximum amount of buffers that the shader stage can use</param>
|
||||||
public BuffersPerStage(int count)
|
public BuffersPerStage(int count)
|
||||||
{
|
{
|
||||||
|
Bindings = new BufferDescriptor[count];
|
||||||
Buffers = new BufferBounds[count];
|
Buffers = new BufferBounds[count];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind(int index, ulong address, ulong size)
|
/// <summary>
|
||||||
|
/// Sets the region of a buffer at a given slot.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Buffer slot</param>
|
||||||
|
/// <param name="address">Region virtual address</param>
|
||||||
|
/// <param name="size">Region size in bytes</param>
|
||||||
|
public void SetBounds(int index, ulong address, ulong size)
|
||||||
{
|
{
|
||||||
Buffers[index].Address = address;
|
Buffers[index] = new BufferBounds(address, size);
|
||||||
Buffers[index].Size = size;
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets shader buffer binding information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptors">Buffer binding information</param>
|
||||||
|
public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||||
|
{
|
||||||
|
if (descriptors == null)
|
||||||
|
{
|
||||||
|
Count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptors.CopyTo(Bindings, 0);
|
||||||
|
Count = descriptors.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +95,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
private BuffersPerStage[] _gpStorageBuffers;
|
private BuffersPerStage[] _gpStorageBuffers;
|
||||||
private BuffersPerStage[] _gpUniformBuffers;
|
private BuffersPerStage[] _gpUniformBuffers;
|
||||||
|
|
||||||
|
private int _cpStorageBufferBindings;
|
||||||
|
private int _cpUniformBufferBindings;
|
||||||
|
private int _gpStorageBufferBindings;
|
||||||
|
private int _gpUniformBufferBindings;
|
||||||
|
|
||||||
private bool _gpStorageBuffersDirty;
|
private bool _gpStorageBuffersDirty;
|
||||||
private bool _gpUniformBuffersDirty;
|
private bool _gpUniformBuffersDirty;
|
||||||
|
|
||||||
|
@ -159,9 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
||||||
|
|
||||||
_transformFeedbackBuffers[index].Address = address;
|
_transformFeedbackBuffers[index] = new BufferBounds(address, size);
|
||||||
_transformFeedbackBuffers[index].Size = size;
|
|
||||||
|
|
||||||
_transformFeedbackBuffersDirty = true;
|
_transformFeedbackBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
|
|
||||||
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
||||||
|
|
||||||
_cpStorageBuffers.Bind(index, address, size);
|
_cpStorageBuffers.SetBounds(index, address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -205,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
_gpStorageBuffersDirty = true;
|
_gpStorageBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gpStorageBuffers[stage].Bind(index, address, size);
|
_gpStorageBuffers[stage].SetBounds(index, address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -219,7 +266,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
||||||
|
|
||||||
_cpUniformBuffers.Bind(index, address, size);
|
_cpUniformBuffers.SetBounds(index, address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -234,42 +281,69 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
ulong address = TranslateAndCreateBuffer(gpuVa, size);
|
||||||
|
|
||||||
_gpUniformBuffers[stage].Bind(index, address, size);
|
_gpUniformBuffers[stage].SetBounds(index, address, size);
|
||||||
|
|
||||||
_gpUniformBuffersDirty = true;
|
_gpUniformBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the enabled storage buffers mask on the compute pipeline.
|
/// Sets the binding points for the storage buffers bound on the compute pipeline.
|
||||||
/// Each bit set on the mask indicates that the respective buffer index is enabled.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mask">Buffer enable mask</param>
|
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||||
public void SetComputeStorageBufferEnableMask(uint mask)
|
public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
_cpStorageBuffers.EnableMask = mask;
|
_cpStorageBuffers.SetBindings(descriptors);
|
||||||
|
_cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the enabled storage buffers mask on the graphics pipeline.
|
/// Sets the binding points for the storage buffers bound on the graphics pipeline.
|
||||||
/// Each bit set on the mask indicates that the respective buffer index is enabled.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stage">Index of the shader stage</param>
|
/// <param name="stage">Index of the shader stage</param>
|
||||||
/// <param name="mask">Buffer enable mask</param>
|
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||||
public void SetGraphicsStorageBufferEnableMask(int stage, uint mask)
|
public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
_gpStorageBuffers[stage].EnableMask = mask;
|
_gpStorageBuffers[stage].SetBindings(descriptors);
|
||||||
|
|
||||||
_gpStorageBuffersDirty = true;
|
_gpStorageBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the enabled uniform buffers mask on the compute pipeline.
|
/// Sets the total number of storage buffer bindings used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">Number of storage buffer bindings used</param>
|
||||||
|
public void SetGraphicsStorageBufferBindingsCount(int count)
|
||||||
|
{
|
||||||
|
_gpStorageBufferBindings = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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);
|
||||||
|
_cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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.
|
/// Each bit set on the mask indicates that the respective buffer index is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mask">Buffer enable mask</param>
|
/// <param name="stage">Index of the shader stage</param>
|
||||||
public void SetComputeUniformBufferEnableMask(uint mask)
|
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||||
|
public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||||
{
|
{
|
||||||
_cpUniformBuffers.EnableMask = mask;
|
_gpUniformBuffers[stage].SetBindings(descriptors);
|
||||||
|
_gpUniformBuffersDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the total number of uniform buffer bindings used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">Number of uniform buffer bindings used</param>
|
||||||
|
public void SetGraphicsUniformBufferBindingsCount(int count)
|
||||||
|
{
|
||||||
|
_gpUniformBufferBindings = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -291,19 +365,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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="mask">Buffer enable mask</param>
|
|
||||||
public void SetGraphicsUniformBufferEnableMask(int stage, uint mask)
|
|
||||||
{
|
|
||||||
_gpUniformBuffers[stage].EnableMask = mask;
|
|
||||||
|
|
||||||
_gpUniformBuffersDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a bit mask indicating which graphics uniform buffers are currently bound.
|
/// Gets a bit mask indicating which graphics uniform buffers are currently bound.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -476,47 +537,41 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CommitComputeBindings()
|
public void CommitComputeBindings()
|
||||||
{
|
{
|
||||||
uint enableMask = _cpStorageBuffers.EnableMask;
|
int sCount = _cpStorageBufferBindings;
|
||||||
|
|
||||||
for (int index = 0; (enableMask >> index) != 0; index++)
|
Span<BufferRange> sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount];
|
||||||
|
|
||||||
|
for (int index = 0; index < _cpStorageBuffers.Count; index++)
|
||||||
{
|
{
|
||||||
if ((enableMask & (1u << index)) == 0)
|
ref var bindingInfo = ref _cpStorageBuffers.Bindings[index];
|
||||||
|
|
||||||
|
BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot];
|
||||||
|
|
||||||
|
if (bounds.Address != 0)
|
||||||
{
|
{
|
||||||
continue;
|
sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferBounds bounds = _cpStorageBuffers.Buffers[index];
|
_context.Renderer.Pipeline.SetStorageBuffers(sRanges);
|
||||||
|
|
||||||
if (bounds.Address == 0)
|
int uCount = _cpUniformBufferBindings;
|
||||||
|
|
||||||
|
Span<BufferRange> uRanges = uCount < StackToHeapThreshold ? stackalloc BufferRange[uCount] : new BufferRange[uCount];
|
||||||
|
|
||||||
|
for (int index = 0; index < _cpUniformBuffers.Count; index++)
|
||||||
{
|
{
|
||||||
continue;
|
ref var bindingInfo = ref _cpUniformBuffers.Bindings[index];
|
||||||
}
|
|
||||||
|
|
||||||
BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);
|
BufferBounds bounds = _cpUniformBuffers.Buffers[bindingInfo.Slot];
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetStorageBuffer(index, ShaderStage.Compute, buffer);
|
if (bounds.Address != 0)
|
||||||
}
|
|
||||||
|
|
||||||
enableMask = _cpUniformBuffers.EnableMask;
|
|
||||||
|
|
||||||
for (int index = 0; (enableMask >> index) != 0; index++)
|
|
||||||
{
|
{
|
||||||
if ((enableMask & (1u << index)) == 0)
|
uRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
||||||
{
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferBounds bounds = _cpUniformBuffers.Buffers[index];
|
_context.Renderer.Pipeline.SetUniformBuffers(uRanges);
|
||||||
|
|
||||||
if (bounds.Address == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);
|
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetUniformBuffer(index, ShaderStage.Compute, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force rebind after doing compute work.
|
// Force rebind after doing compute work.
|
||||||
_rebind = true;
|
_rebind = true;
|
||||||
|
@ -651,7 +706,35 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param>
|
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param>
|
||||||
private void BindBuffers(BuffersPerStage[] bindings, bool isStorage)
|
private void BindBuffers(BuffersPerStage[] bindings, bool isStorage)
|
||||||
{
|
{
|
||||||
BindOrUpdateBuffers(bindings, bind: true, isStorage);
|
int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings;
|
||||||
|
|
||||||
|
Span<BufferRange> ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count];
|
||||||
|
|
||||||
|
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
||||||
|
{
|
||||||
|
ref var buffers = ref bindings[(int)stage - 1];
|
||||||
|
|
||||||
|
for (int index = 0; index < buffers.Count; index++)
|
||||||
|
{
|
||||||
|
ref var bindingInfo = ref buffers.Bindings[index];
|
||||||
|
|
||||||
|
BufferBounds bounds = buffers.Buffers[bindingInfo.Slot];
|
||||||
|
|
||||||
|
if (bounds.Address != 0)
|
||||||
|
{
|
||||||
|
ranges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isStorage)
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.SetStorageBuffers(ranges);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_context.Renderer.Pipeline.SetUniformBuffers(ranges);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -659,73 +742,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bindings">Bindings to update</param>
|
/// <param name="bindings">Bindings to update</param>
|
||||||
private void UpdateBuffers(BuffersPerStage[] bindings)
|
private void UpdateBuffers(BuffersPerStage[] bindings)
|
||||||
{
|
|
||||||
BindOrUpdateBuffers(bindings, bind: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This binds buffers into the host API, or updates data for already bound buffers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bindings">Bindings to bind or update</param>
|
|
||||||
/// <param name="bind">True to bind, false to update</param>
|
|
||||||
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
|
|
||||||
private void BindOrUpdateBuffers(BuffersPerStage[] bindings, bool bind, bool isStorage = false)
|
|
||||||
{
|
{
|
||||||
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
||||||
{
|
{
|
||||||
uint enableMask = bindings[(int)stage - 1].EnableMask;
|
ref var buffers = ref bindings[(int)stage - 1];
|
||||||
|
|
||||||
if (enableMask == 0)
|
for (int index = 0; index < buffers.Count; index++)
|
||||||
{
|
{
|
||||||
continue;
|
ref var binding = ref buffers.Bindings[index];
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; (enableMask >> index) != 0; index++)
|
BufferBounds bounds = buffers.Buffers[binding.Slot];
|
||||||
{
|
|
||||||
if ((enableMask & (1u << index)) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferBounds bounds = bindings[(int)stage - 1].Buffers[index];
|
|
||||||
|
|
||||||
if (bounds.Address == 0)
|
if (bounds.Address == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind)
|
|
||||||
{
|
|
||||||
BindBuffer(index, stage, bounds, isStorage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SynchronizeBufferRange(bounds.Address, bounds.Size);
|
SynchronizeBufferRange(bounds.Address, bounds.Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Binds a buffer on the host API.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index">Index to bind the buffer into</param>
|
|
||||||
/// <param name="stage">Shader stage to bind the buffer into</param>
|
|
||||||
/// <param name="bounds">Buffer address and size</param>
|
|
||||||
/// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param>
|
|
||||||
private void BindBuffer(int index, ShaderStage stage, BufferBounds bounds, bool isStorage)
|
|
||||||
{
|
|
||||||
BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);
|
|
||||||
|
|
||||||
if (isStorage)
|
|
||||||
{
|
|
||||||
_context.Renderer.Pipeline.SetStorageBuffer(index, stage, buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_context.Renderer.Pipeline.SetUniformBuffer(index, stage, buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the buffer storage of a buffer texture.
|
/// Sets the buffer storage of a buffer texture.
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
localMemorySize,
|
localMemorySize,
|
||||||
sharedMemorySize);
|
sharedMemorySize);
|
||||||
|
|
||||||
shader.HostShader = _context.Renderer.CompileShader(shader.Program);
|
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
|
||||||
|
|
||||||
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);
|
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null);
|
||||||
|
|
||||||
|
@ -134,19 +134,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
flags |= TranslationFlags.Feedback;
|
flags |= TranslationFlags.Feedback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TranslationCounts counts = new TranslationCounts();
|
||||||
|
|
||||||
if (addresses.VertexA != 0)
|
if (addresses.VertexA != 0)
|
||||||
{
|
{
|
||||||
shaders[0] = TranslateGraphicsShader(state, flags, ShaderStage.Vertex, addresses.Vertex, addresses.VertexA);
|
shaders[0] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex, addresses.VertexA);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
shaders[0] = TranslateGraphicsShader(state, flags, ShaderStage.Vertex, addresses.Vertex);
|
shaders[0] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
shaders[1] = TranslateGraphicsShader(state, flags, ShaderStage.TessellationControl, addresses.TessControl);
|
shaders[1] = TranslateGraphicsShader(state, counts, flags, ShaderStage.TessellationControl, addresses.TessControl);
|
||||||
shaders[2] = TranslateGraphicsShader(state, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
|
shaders[2] = TranslateGraphicsShader(state, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
|
||||||
shaders[3] = TranslateGraphicsShader(state, flags, ShaderStage.Geometry, addresses.Geometry);
|
shaders[3] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Geometry, addresses.Geometry);
|
||||||
shaders[4] = TranslateGraphicsShader(state, flags, ShaderStage.Fragment, addresses.Fragment);
|
shaders[4] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Fragment, addresses.Fragment);
|
||||||
|
|
||||||
List<IShader> hostShaders = new List<IShader>();
|
List<IShader> hostShaders = new List<IShader>();
|
||||||
|
|
||||||
|
@ -159,7 +161,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IShader hostShader = _context.Renderer.CompileShader(program);
|
IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code);
|
||||||
|
|
||||||
shaders[stage].HostShader = hostShader;
|
shaders[stage].HostShader = hostShader;
|
||||||
|
|
||||||
|
@ -334,12 +336,19 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader.
|
/// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
|
/// <param name="counts">Cumulative shader resource counts</param>
|
||||||
/// <param name="flags">Flags that controls shader translation</param>
|
/// <param name="flags">Flags that controls shader translation</param>
|
||||||
/// <param name="stage">Shader stage</param>
|
/// <param name="stage">Shader stage</param>
|
||||||
/// <param name="gpuVa">GPU virtual address of the shader code</param>
|
/// <param name="gpuVa">GPU virtual address of the shader code</param>
|
||||||
/// <param name="gpuVaA">Optional GPU virtual address of the "Vertex A" shader code</param>
|
/// <param name="gpuVaA">Optional GPU virtual address of the "Vertex A" shader code</param>
|
||||||
/// <returns>Compiled graphics shader code</returns>
|
/// <returns>Compiled graphics shader code</returns>
|
||||||
private ShaderCodeHolder TranslateGraphicsShader(GpuState state, TranslationFlags flags, ShaderStage stage, ulong gpuVa, ulong gpuVaA = 0)
|
private ShaderCodeHolder TranslateGraphicsShader(
|
||||||
|
GpuState state,
|
||||||
|
TranslationCounts counts,
|
||||||
|
TranslationFlags flags,
|
||||||
|
ShaderStage stage,
|
||||||
|
ulong gpuVa,
|
||||||
|
ulong gpuVaA = 0)
|
||||||
{
|
{
|
||||||
if (gpuVa == 0)
|
if (gpuVa == 0)
|
||||||
{
|
{
|
||||||
|
@ -350,7 +359,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
if (gpuVaA != 0)
|
if (gpuVaA != 0)
|
||||||
{
|
{
|
||||||
ShaderProgram program = Translator.Translate(gpuVaA, gpuVa, gpuAccessor, flags);
|
ShaderProgram program = Translator.Translate(gpuVaA, gpuVa, gpuAccessor, flags, counts);
|
||||||
|
|
||||||
byte[] codeA = _context.MemoryManager.GetSpan(gpuVaA, program.SizeA).ToArray();
|
byte[] codeA = _context.MemoryManager.GetSpan(gpuVaA, program.SizeA).ToArray();
|
||||||
byte[] codeB = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray();
|
byte[] codeB = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray();
|
||||||
|
@ -370,7 +379,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShaderProgram program = Translator.Translate(gpuVa, gpuAccessor, flags);
|
ShaderProgram program = Translator.Translate(gpuVa, gpuAccessor, flags, counts);
|
||||||
|
|
||||||
byte[] code = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray();
|
byte[] code = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray();
|
||||||
|
|
||||||
|
|
|
@ -697,20 +697,20 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
SetFrontFace(_frontFace = frontFace.Convert());
|
SetFrontFace(_frontFace = frontFace.Convert());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetImage(int index, ShaderStage stage, ITexture texture, Format imageFormat)
|
public void SetImage(int binding, ITexture texture, Format imageFormat)
|
||||||
{
|
{
|
||||||
int unit = _program.GetImageUnit(stage, index);
|
if (texture == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (unit != -1 && texture != null)
|
|
||||||
{
|
|
||||||
TextureBase texBase = (TextureBase)texture;
|
TextureBase texBase = (TextureBase)texture;
|
||||||
|
|
||||||
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||||
|
|
||||||
if (format != 0)
|
if (format != 0)
|
||||||
{
|
{
|
||||||
GL.BindImageTexture(unit, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format);
|
GL.BindImageTexture(binding, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,14 +866,14 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
UpdateDepthTest();
|
UpdateDepthTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSampler(int index, ShaderStage stage, ISampler sampler)
|
public void SetSampler(int binding, ISampler sampler)
|
||||||
{
|
{
|
||||||
int unit = _program.GetTextureUnit(stage, index);
|
if (sampler == null)
|
||||||
|
|
||||||
if (unit != -1 && sampler != null)
|
|
||||||
{
|
{
|
||||||
((Sampler)sampler).Bind(unit);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
((Sampler)sampler).Bind(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetScissorEnable(int index, bool enable)
|
public void SetScissorEnable(int index, bool enable)
|
||||||
|
@ -939,25 +939,25 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
_stencilFrontMask = stencilTest.FrontMask;
|
_stencilFrontMask = stencilTest.FrontMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStorageBuffer(int index, ShaderStage stage, BufferRange buffer)
|
public void SetStorageBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||||
{
|
{
|
||||||
SetBuffer(index, stage, buffer, isStorage: true);
|
SetBuffers(buffers, isStorage: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTexture(int index, ShaderStage stage, ITexture texture)
|
public void SetTexture(int binding, ITexture texture)
|
||||||
{
|
{
|
||||||
int unit = _program.GetTextureUnit(stage, index);
|
if (texture == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (unit != -1 && texture != null)
|
if (binding == 0)
|
||||||
{
|
|
||||||
if (unit == 0)
|
|
||||||
{
|
{
|
||||||
_unit0Texture = (TextureBase)texture;
|
_unit0Texture = (TextureBase)texture;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
((TextureBase)texture).Bind(unit);
|
((TextureBase)texture).Bind(binding);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -997,9 +997,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer)
|
public void SetUniformBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||||
{
|
{
|
||||||
SetBuffer(index, stage, buffer, isStorage: false);
|
SetBuffers(buffers, isStorage: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetUserClipDistance(int index, bool enableClip)
|
public void SetUserClipDistance(int index, bool enableClip)
|
||||||
|
@ -1077,30 +1077,22 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
|
GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetBuffer(int index, ShaderStage stage, BufferRange buffer, bool isStorage)
|
private void SetBuffers(ReadOnlySpan<BufferRange> buffers, bool isStorage)
|
||||||
{
|
{
|
||||||
int bindingPoint = isStorage
|
BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer;
|
||||||
? _program.GetStorageBufferBindingPoint(stage, index)
|
|
||||||
: _program.GetUniformBufferBindingPoint(stage, index);
|
|
||||||
|
|
||||||
if (bindingPoint == -1)
|
for (int index = 0; index < buffers.Length; index++)
|
||||||
{
|
{
|
||||||
return;
|
BufferRange buffer = buffers[index];
|
||||||
}
|
|
||||||
|
|
||||||
BufferRangeTarget target = isStorage
|
|
||||||
? BufferRangeTarget.ShaderStorageBuffer
|
|
||||||
: BufferRangeTarget.UniformBuffer;
|
|
||||||
|
|
||||||
if (buffer.Handle == BufferHandle.Null)
|
if (buffer.Handle == BufferHandle.Null)
|
||||||
{
|
{
|
||||||
GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
|
GL.BindBufferRange(target, index, 0, IntPtr.Zero, 0);
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr bufferOffset = (IntPtr)buffer.Offset;
|
GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||||
|
}
|
||||||
GL.BindBufferRange(target, bindingPoint, buffer.Handle.ToInt32(), bufferOffset, buffer.Size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetOrigin(ClipOrigin origin)
|
private void SetOrigin(ClipOrigin origin)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
|
||||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -11,18 +10,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
class Program : IProgram
|
class Program : IProgram
|
||||||
{
|
{
|
||||||
private const int ShaderStages = 6;
|
|
||||||
|
|
||||||
private const int UbStageShift = 5;
|
|
||||||
private const int SbStageShift = 4;
|
|
||||||
private const int TexStageShift = 5;
|
|
||||||
private const int ImgStageShift = 3;
|
|
||||||
|
|
||||||
private const int UbsPerStage = 1 << UbStageShift;
|
|
||||||
private const int SbsPerStage = 1 << SbStageShift;
|
|
||||||
private const int TexsPerStage = 1 << TexStageShift;
|
|
||||||
private const int ImgsPerStage = 1 << ImgStageShift;
|
|
||||||
|
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
public int FragmentIsBgraUniform { get; }
|
public int FragmentIsBgraUniform { get; }
|
||||||
|
@ -31,38 +18,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
public bool IsLinked { get; private set; }
|
public bool IsLinked { get; private set; }
|
||||||
|
|
||||||
private int[] _ubBindingPoints;
|
|
||||||
private int[] _sbBindingPoints;
|
|
||||||
private int[] _textureUnits;
|
|
||||||
private int[] _imageUnits;
|
|
||||||
|
|
||||||
public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
|
||||||
{
|
{
|
||||||
_ubBindingPoints = new int[UbsPerStage * ShaderStages];
|
|
||||||
_sbBindingPoints = new int[SbsPerStage * ShaderStages];
|
|
||||||
_textureUnits = new int[TexsPerStage * ShaderStages];
|
|
||||||
_imageUnits = new int[ImgsPerStage * ShaderStages];
|
|
||||||
|
|
||||||
for (int index = 0; index < _ubBindingPoints.Length; index++)
|
|
||||||
{
|
|
||||||
_ubBindingPoints[index] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < _sbBindingPoints.Length; index++)
|
|
||||||
{
|
|
||||||
_sbBindingPoints[index] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < _textureUnits.Length; index++)
|
|
||||||
{
|
|
||||||
_textureUnits[index] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int index = 0; index < _imageUnits.Length; index++)
|
|
||||||
{
|
|
||||||
_imageUnits[index] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle = GL.CreateProgram();
|
Handle = GL.CreateProgram();
|
||||||
|
|
||||||
for (int index = 0; index < shaders.Length; index++)
|
for (int index = 0; index < shaders.Length; index++)
|
||||||
|
@ -131,92 +88,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
|
|
||||||
CheckProgramLink();
|
CheckProgramLink();
|
||||||
|
|
||||||
int ubBindingPoint = 0;
|
|
||||||
int sbBindingPoint = 0;
|
|
||||||
int textureUnit = 0;
|
|
||||||
int imageUnit = 0;
|
|
||||||
|
|
||||||
for (int index = 0; index < shaders.Length; index++)
|
|
||||||
{
|
|
||||||
Shader shader = (Shader)shaders[index];
|
|
||||||
|
|
||||||
foreach (BufferDescriptor descriptor in shader.Info.CBuffers)
|
|
||||||
{
|
|
||||||
int location = GL.GetUniformBlockIndex(Handle, descriptor.Name);
|
|
||||||
|
|
||||||
if (location < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.UniformBlockBinding(Handle, location, ubBindingPoint);
|
|
||||||
|
|
||||||
int bpIndex = (int)shader.Stage << UbStageShift | descriptor.Slot;
|
|
||||||
|
|
||||||
_ubBindingPoints[bpIndex] = ubBindingPoint;
|
|
||||||
|
|
||||||
ubBindingPoint++;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (BufferDescriptor descriptor in shader.Info.SBuffers)
|
|
||||||
{
|
|
||||||
int location = GL.GetProgramResourceIndex(Handle, ProgramInterface.ShaderStorageBlock, descriptor.Name);
|
|
||||||
|
|
||||||
if (location < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.ShaderStorageBlockBinding(Handle, location, sbBindingPoint);
|
|
||||||
|
|
||||||
int bpIndex = (int)shader.Stage << SbStageShift | descriptor.Slot;
|
|
||||||
|
|
||||||
_sbBindingPoints[bpIndex] = sbBindingPoint;
|
|
||||||
|
|
||||||
sbBindingPoint++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int samplerIndex = 0;
|
|
||||||
|
|
||||||
foreach (TextureDescriptor descriptor in shader.Info.Textures)
|
|
||||||
{
|
|
||||||
int location = GL.GetUniformLocation(Handle, descriptor.Name);
|
|
||||||
|
|
||||||
if (location < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.ProgramUniform1(Handle, location, textureUnit);
|
|
||||||
|
|
||||||
int uIndex = (int)shader.Stage << TexStageShift | samplerIndex++;
|
|
||||||
|
|
||||||
_textureUnits[uIndex] = textureUnit;
|
|
||||||
|
|
||||||
textureUnit++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int imageIndex = 0;
|
|
||||||
|
|
||||||
foreach (TextureDescriptor descriptor in shader.Info.Images)
|
|
||||||
{
|
|
||||||
int location = GL.GetUniformLocation(Handle, descriptor.Name);
|
|
||||||
|
|
||||||
if (location < 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.ProgramUniform1(Handle, location, imageUnit);
|
|
||||||
|
|
||||||
int uIndex = (int)shader.Stage << ImgStageShift | imageIndex++;
|
|
||||||
|
|
||||||
_imageUnits[uIndex] = imageUnit;
|
|
||||||
|
|
||||||
imageUnit++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra");
|
FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra");
|
||||||
FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
|
FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
|
||||||
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
|
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
|
||||||
|
@ -227,26 +98,6 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
GL.UseProgram(Handle);
|
GL.UseProgram(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetUniformBufferBindingPoint(ShaderStage stage, int index)
|
|
||||||
{
|
|
||||||
return _ubBindingPoints[(int)stage << UbStageShift | index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetStorageBufferBindingPoint(ShaderStage stage, int index)
|
|
||||||
{
|
|
||||||
return _sbBindingPoints[(int)stage << SbStageShift | index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetTextureUnit(ShaderStage stage, int index)
|
|
||||||
{
|
|
||||||
return _textureUnits[(int)stage << TexStageShift | index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetImageUnit(ShaderStage stage, int index)
|
|
||||||
{
|
|
||||||
return _imageUnits[(int)stage << ImgStageShift | index];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckProgramLink()
|
private void CheckProgramLink()
|
||||||
{
|
{
|
||||||
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
|
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
|
||||||
|
|
|
@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
ResourcePool = new ResourcePool();
|
ResourcePool = new ResourcePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IShader CompileShader(ShaderProgram shader)
|
public IShader CompileShader(ShaderStage stage, string code)
|
||||||
{
|
{
|
||||||
return new Shader(shader);
|
return new Shader(stage, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferHandle CreateBuffer(int size)
|
public BufferHandle CreateBuffer(int size)
|
||||||
|
|
|
@ -8,31 +8,22 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
|
||||||
private ShaderProgram _program;
|
public Shader(ShaderStage stage, string code)
|
||||||
|
|
||||||
public ShaderProgramInfo Info => _program.Info;
|
|
||||||
|
|
||||||
public ShaderStage Stage => _program.Stage;
|
|
||||||
|
|
||||||
public Shader(ShaderProgram program)
|
|
||||||
{
|
{
|
||||||
_program = program;
|
ShaderType type = stage switch
|
||||||
|
|
||||||
ShaderType type = ShaderType.VertexShader;
|
|
||||||
|
|
||||||
switch (program.Stage)
|
|
||||||
{
|
{
|
||||||
case ShaderStage.Compute: type = ShaderType.ComputeShader; break;
|
ShaderStage.Compute => ShaderType.ComputeShader,
|
||||||
case ShaderStage.Vertex: type = ShaderType.VertexShader; break;
|
ShaderStage.Vertex => ShaderType.VertexShader,
|
||||||
case ShaderStage.TessellationControl: type = ShaderType.TessControlShader; break;
|
ShaderStage.TessellationControl => ShaderType.TessControlShader,
|
||||||
case ShaderStage.TessellationEvaluation: type = ShaderType.TessEvaluationShader; break;
|
ShaderStage.TessellationEvaluation => ShaderType.TessEvaluationShader,
|
||||||
case ShaderStage.Geometry: type = ShaderType.GeometryShader; break;
|
ShaderStage.Geometry => ShaderType.GeometryShader,
|
||||||
case ShaderStage.Fragment: type = ShaderType.FragmentShader; break;
|
ShaderStage.Fragment => ShaderType.FragmentShader,
|
||||||
}
|
_ => ShaderType.VertexShader
|
||||||
|
};
|
||||||
|
|
||||||
Handle = GL.CreateShader(type);
|
Handle = GL.CreateShader(type);
|
||||||
|
|
||||||
GL.ShaderSource(Handle, program.Code);
|
GL.ShaderSource(Handle, code);
|
||||||
GL.CompileShader(Handle);
|
GL.CompileShader(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,12 @@ namespace Ryujinx.Graphics.Shader
|
||||||
{
|
{
|
||||||
public struct BufferDescriptor
|
public struct BufferDescriptor
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public int Binding { get; }
|
||||||
|
|
||||||
public int Slot { get; }
|
public int Slot { get; }
|
||||||
|
|
||||||
public BufferDescriptor(string name, int slot)
|
public BufferDescriptor(int binding, int slot)
|
||||||
{
|
{
|
||||||
Name = name;
|
Binding = binding;
|
||||||
Slot = slot;
|
Slot = slot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,50 +218,46 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
if (info.UsesCbIndexing)
|
if (info.UsesCbIndexing)
|
||||||
{
|
{
|
||||||
|
int count = info.CBuffers.Max() + 1;
|
||||||
|
|
||||||
|
int[] bindings = new int[count];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
bindings[i] = context.Config.Counts.IncrementUniformBuffersCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
||||||
|
{
|
||||||
|
context.CBufferDescriptors.Add(new BufferDescriptor(bindings[cbufSlot], cbufSlot));
|
||||||
|
}
|
||||||
|
|
||||||
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||||
|
|
||||||
ubName += "_" + DefaultNames.UniformNamePrefix;
|
ubName += "_" + DefaultNames.UniformNamePrefix;
|
||||||
|
|
||||||
string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
|
string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
|
||||||
|
|
||||||
int maxSlot = 0;
|
context.AppendLine($"layout (binding = {bindings[0]}, std140) uniform {blockName}");
|
||||||
|
|
||||||
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
|
||||||
{
|
|
||||||
context.CBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{cbufSlot}]", cbufSlot));
|
|
||||||
|
|
||||||
if (maxSlot < cbufSlot)
|
|
||||||
{
|
|
||||||
maxSlot = cbufSlot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.AppendLine("layout (std140) uniform " + blockName);
|
|
||||||
|
|
||||||
context.EnterScope();
|
context.EnterScope();
|
||||||
|
|
||||||
context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
|
context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
|
||||||
|
context.LeaveScope($" {ubName}[{NumberFormatter.FormatInt(count)}];");
|
||||||
string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
|
|
||||||
|
|
||||||
context.LeaveScope($" {ubName}[{arraySize}];");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
|
||||||
{
|
{
|
||||||
|
int binding = context.Config.Counts.IncrementUniformBuffersCount();
|
||||||
|
|
||||||
|
context.CBufferDescriptors.Add(new BufferDescriptor(binding, cbufSlot));
|
||||||
|
|
||||||
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||||
|
|
||||||
ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
|
ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
|
||||||
|
|
||||||
context.CBufferDescriptors.Add(new BufferDescriptor(ubName, cbufSlot));
|
context.AppendLine($"layout (binding = {binding}, std140) uniform {ubName}");
|
||||||
|
|
||||||
context.AppendLine("layout (std140) uniform " + ubName);
|
|
||||||
|
|
||||||
context.EnterScope();
|
context.EnterScope();
|
||||||
|
|
||||||
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot, false) + ubSize + ";");
|
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot, false) + ubSize + ";");
|
||||||
|
|
||||||
context.LeaveScope(";");
|
context.LeaveScope(";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,32 +271,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
|
string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
|
||||||
|
|
||||||
int maxSlot = 0;
|
int count = info.SBuffers.Max() + 1;
|
||||||
|
|
||||||
|
int[] bindings = new int[count];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
bindings[i] = context.Config.Counts.IncrementStorageBuffersCount();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (int sbufSlot in info.SBuffers)
|
foreach (int sbufSlot in info.SBuffers)
|
||||||
{
|
{
|
||||||
context.SBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{sbufSlot}]", sbufSlot));
|
context.SBufferDescriptors.Add(new BufferDescriptor(bindings[sbufSlot], sbufSlot));
|
||||||
|
|
||||||
if (maxSlot < sbufSlot)
|
|
||||||
{
|
|
||||||
maxSlot = sbufSlot;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.AppendLine("layout (std430) buffer " + blockName);
|
context.AppendLine($"layout (binding = {bindings[0]}, std430) buffer {blockName}");
|
||||||
|
|
||||||
context.EnterScope();
|
context.EnterScope();
|
||||||
|
|
||||||
context.AppendLine("uint " + DefaultNames.DataName + "[];");
|
context.AppendLine("uint " + DefaultNames.DataName + "[];");
|
||||||
|
context.LeaveScope($" {sbName}[{NumberFormatter.FormatInt(count)}];");
|
||||||
string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
|
|
||||||
|
|
||||||
context.LeaveScope($" {sbName}[{arraySize}];");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
|
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
|
||||||
{
|
{
|
||||||
Dictionary<string, AstTextureOperation> samplers = new Dictionary<string, AstTextureOperation>();
|
HashSet<string> samplers = new HashSet<string>();
|
||||||
|
|
||||||
// Texture instructions other than TextureSample (like TextureSize)
|
// Texture instructions other than TextureSample (like TextureSize)
|
||||||
// may have incomplete sampler type information. In those cases,
|
// may have incomplete sampler type information. In those cases,
|
||||||
|
@ -312,29 +305,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
if (!samplers.TryAdd(samplerName, texOp))
|
if (!samplers.Add(samplerName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string samplerTypeName = texOp.Type.ToGlslSamplerType();
|
int firstBinding = -1;
|
||||||
|
|
||||||
context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, AstTextureOperation> kv in samplers)
|
|
||||||
{
|
|
||||||
string samplerName = kv.Key;
|
|
||||||
|
|
||||||
AstTextureOperation texOp = kv.Value;
|
|
||||||
|
|
||||||
TextureDescriptor desc;
|
|
||||||
|
|
||||||
if ((texOp.Flags & TextureFlags.Bindless) != 0)
|
if ((texOp.Flags & TextureFlags.Bindless) != 0)
|
||||||
{
|
{
|
||||||
AstOperand operand = texOp.GetSource(0) as AstOperand;
|
AstOperand operand = texOp.GetSource(0) as AstOperand;
|
||||||
|
|
||||||
desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset);
|
firstBinding = context.Config.Counts.IncrementTexturesCount();
|
||||||
|
|
||||||
|
var desc = new TextureDescriptor(firstBinding, texOp.Type, operand.CbufSlot, operand.CbufOffset);
|
||||||
|
|
||||||
context.TextureDescriptors.Add(desc);
|
context.TextureDescriptors.Add(desc);
|
||||||
}
|
}
|
||||||
|
@ -342,27 +326,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
{
|
{
|
||||||
for (int index = 0; index < texOp.ArraySize; index++)
|
for (int index = 0; index < texOp.ArraySize; index++)
|
||||||
{
|
{
|
||||||
string indexExpr = NumberFormatter.FormatInt(index);
|
int binding = context.Config.Counts.IncrementTexturesCount();
|
||||||
|
|
||||||
string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
if (firstBinding < 0)
|
||||||
|
{
|
||||||
|
firstBinding = binding;
|
||||||
|
}
|
||||||
|
|
||||||
desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
||||||
|
|
||||||
context.TextureDescriptors.Add(desc);
|
context.TextureDescriptors.Add(desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Format, texOp.Handle);
|
firstBinding = context.Config.Counts.IncrementTexturesCount();
|
||||||
|
|
||||||
|
var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
|
||||||
|
|
||||||
context.TextureDescriptors.Add(desc);
|
context.TextureDescriptors.Add(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string samplerTypeName = texOp.Type.ToGlslSamplerType();
|
||||||
|
|
||||||
|
context.AppendLine($"layout (binding = {firstBinding}) uniform {samplerTypeName} {samplerName};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareImages(CodeGenContext context, StructuredProgramInfo info)
|
private static void DeclareImages(CodeGenContext context, StructuredProgramInfo info)
|
||||||
{
|
{
|
||||||
Dictionary<string, AstTextureOperation> images = new Dictionary<string, AstTextureOperation>();
|
HashSet<string> images = new HashSet<string>();
|
||||||
|
|
||||||
foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle))
|
foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle))
|
||||||
{
|
{
|
||||||
|
@ -370,48 +363,48 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||||
|
|
||||||
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
|
||||||
|
|
||||||
if (!images.TryAdd(imageName, texOp))
|
if (!images.Add(imageName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int firstBinding = -1;
|
||||||
|
|
||||||
|
if ((texOp.Type & SamplerType.Indexed) != 0)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < texOp.ArraySize; index++)
|
||||||
|
{
|
||||||
|
int binding = context.Config.Counts.IncrementImagesCount();
|
||||||
|
|
||||||
|
if (firstBinding < 0)
|
||||||
|
{
|
||||||
|
firstBinding = binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
||||||
|
|
||||||
|
context.ImageDescriptors.Add(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstBinding = context.Config.Counts.IncrementImagesCount();
|
||||||
|
|
||||||
|
var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
|
||||||
|
|
||||||
|
context.ImageDescriptors.Add(desc);
|
||||||
|
}
|
||||||
|
|
||||||
string layout = texOp.Format.ToGlslFormat();
|
string layout = texOp.Format.ToGlslFormat();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(layout))
|
if (!string.IsNullOrEmpty(layout))
|
||||||
{
|
{
|
||||||
layout = "layout(" + layout + ") ";
|
layout = ", " + layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
string imageTypeName = texOp.Type.ToGlslImageType(texOp.Format.GetComponentType());
|
string imageTypeName = texOp.Type.ToGlslImageType(texOp.Format.GetComponentType());
|
||||||
|
|
||||||
context.AppendLine("uniform " + layout + imageTypeName + " " + imageName + ";");
|
context.AppendLine($"layout (binding = {firstBinding}{layout}) uniform {imageTypeName} {imageName};");
|
||||||
}
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, AstTextureOperation> kv in images)
|
|
||||||
{
|
|
||||||
string imageName = kv.Key;
|
|
||||||
|
|
||||||
AstTextureOperation texOp = kv.Value;
|
|
||||||
|
|
||||||
if ((texOp.Type & SamplerType.Indexed) != 0)
|
|
||||||
{
|
|
||||||
for (int index = 0; index < texOp.ArraySize; index++)
|
|
||||||
{
|
|
||||||
string indexExpr = NumberFormatter.FormatInt(index);
|
|
||||||
|
|
||||||
string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
|
|
||||||
|
|
||||||
var desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Format, texOp.Handle + index * 2);
|
|
||||||
|
|
||||||
context.TextureDescriptors.Add(desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var desc = new TextureDescriptor(imageName, texOp.Type, texOp.Format, texOp.Handle);
|
|
||||||
|
|
||||||
context.ImageDescriptors.Add(desc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,79 +2,79 @@
|
||||||
{
|
{
|
||||||
public interface IGpuAccessor
|
public interface IGpuAccessor
|
||||||
{
|
{
|
||||||
public void Log(string message)
|
void Log(string message)
|
||||||
{
|
{
|
||||||
// No default log output.
|
// No default log output.
|
||||||
}
|
}
|
||||||
|
|
||||||
T MemoryRead<T>(ulong address) where T : unmanaged;
|
T MemoryRead<T>(ulong address) where T : unmanaged;
|
||||||
|
|
||||||
public bool MemoryMapped(ulong address)
|
bool MemoryMapped(ulong address)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryComputeLocalSizeX()
|
int QueryComputeLocalSizeX()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryComputeLocalSizeY()
|
int QueryComputeLocalSizeY()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryComputeLocalSizeZ()
|
int QueryComputeLocalSizeZ()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryComputeLocalMemorySize()
|
int QueryComputeLocalMemorySize()
|
||||||
{
|
{
|
||||||
return 0x1000;
|
return 0x1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryComputeSharedMemorySize()
|
int QueryComputeSharedMemorySize()
|
||||||
{
|
{
|
||||||
return 0xc000;
|
return 0xc000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint QueryConstantBufferUse()
|
uint QueryConstantBufferUse()
|
||||||
{
|
{
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool QueryIsTextureBuffer(int handle)
|
bool QueryIsTextureBuffer(int handle)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool QueryIsTextureRectangle(int handle)
|
bool QueryIsTextureRectangle(int handle)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputTopology QueryPrimitiveTopology()
|
InputTopology QueryPrimitiveTopology()
|
||||||
{
|
{
|
||||||
return InputTopology.Points;
|
return InputTopology.Points;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryStorageBufferOffsetAlignment()
|
int QueryStorageBufferOffsetAlignment()
|
||||||
{
|
{
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool QuerySupportsImageLoadFormatted()
|
bool QuerySupportsImageLoadFormatted()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool QuerySupportsNonConstantTextureOffset()
|
bool QuerySupportsNonConstantTextureOffset()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureFormat QueryTextureFormat(int handle)
|
TextureFormat QueryTextureFormat(int handle)
|
||||||
{
|
{
|
||||||
return TextureFormat.R8G8B8A8Unorm;
|
return TextureFormat.R8G8B8A8Unorm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
{
|
{
|
||||||
public struct TextureDescriptor
|
public struct TextureDescriptor
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public int Binding { get; }
|
||||||
|
|
||||||
public SamplerType Type { get; }
|
public SamplerType Type { get; }
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@ namespace Ryujinx.Graphics.Shader
|
||||||
|
|
||||||
public TextureUsageFlags Flags { get; set; }
|
public TextureUsageFlags Flags { get; set; }
|
||||||
|
|
||||||
public TextureDescriptor(string name, SamplerType type, TextureFormat format, int handleIndex)
|
public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int handleIndex)
|
||||||
{
|
{
|
||||||
Name = name;
|
Binding = binding;
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
HandleIndex = handleIndex;
|
HandleIndex = handleIndex;
|
||||||
|
@ -32,9 +32,9 @@ namespace Ryujinx.Graphics.Shader
|
||||||
Flags = TextureUsageFlags.None;
|
Flags = TextureUsageFlags.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureDescriptor(string name, SamplerType type, int cbufSlot, int cbufOffset)
|
public TextureDescriptor(int binding, SamplerType type, int cbufSlot, int cbufOffset)
|
||||||
{
|
{
|
||||||
Name = name;
|
Binding = binding;
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = TextureFormat.Unknown;
|
Format = TextureFormat.Unknown;
|
||||||
HandleIndex = 0;
|
HandleIndex = 0;
|
||||||
|
|
|
@ -20,11 +20,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
public TranslationFlags Flags { get; }
|
public TranslationFlags Flags { get; }
|
||||||
|
|
||||||
|
public TranslationCounts Counts { get; }
|
||||||
|
|
||||||
public int Size { get; private set; }
|
public int Size { get; private set; }
|
||||||
|
|
||||||
public FeatureFlags UsedFeatures { get; private set; }
|
public FeatureFlags UsedFeatures { get; private set; }
|
||||||
|
|
||||||
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags)
|
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
|
||||||
{
|
{
|
||||||
Stage = ShaderStage.Compute;
|
Stage = ShaderStage.Compute;
|
||||||
OutputTopology = OutputTopology.PointList;
|
OutputTopology = OutputTopology.PointList;
|
||||||
|
@ -38,9 +40,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
Size = 0;
|
Size = 0;
|
||||||
UsedFeatures = FeatureFlags.None;
|
UsedFeatures = FeatureFlags.None;
|
||||||
|
Counts = counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
|
||||||
{
|
{
|
||||||
Stage = header.Stage;
|
Stage = header.Stage;
|
||||||
OutputTopology = header.OutputTopology;
|
OutputTopology = header.OutputTopology;
|
||||||
|
@ -54,6 +57,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
Size = 0;
|
Size = 0;
|
||||||
UsedFeatures = FeatureFlags.None;
|
UsedFeatures = FeatureFlags.None;
|
||||||
|
Counts = counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetDepthRegister()
|
public int GetDepthRegister()
|
||||||
|
|
30
Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs
Normal file
30
Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
{
|
||||||
|
public class TranslationCounts
|
||||||
|
{
|
||||||
|
public int UniformBuffersCount { get; private set; }
|
||||||
|
public int StorageBuffersCount { get; private set; }
|
||||||
|
public int TexturesCount { get; private set; }
|
||||||
|
public int ImagesCount { get; private set; }
|
||||||
|
|
||||||
|
internal int IncrementUniformBuffersCount()
|
||||||
|
{
|
||||||
|
return UniformBuffersCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int IncrementStorageBuffersCount()
|
||||||
|
{
|
||||||
|
return StorageBuffersCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int IncrementTexturesCount()
|
||||||
|
{
|
||||||
|
return TexturesCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int IncrementImagesCount()
|
||||||
|
{
|
||||||
|
return ImagesCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,15 +24,28 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderProgram Translate(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
public static ShaderProgram Translate(
|
||||||
|
ulong address,
|
||||||
|
IGpuAccessor gpuAccessor,
|
||||||
|
TranslationFlags flags,
|
||||||
|
TranslationCounts counts = null)
|
||||||
{
|
{
|
||||||
return Translate(DecodeShader(address, gpuAccessor, flags, out ShaderConfig config), config);
|
counts ??= new TranslationCounts();
|
||||||
|
|
||||||
|
return Translate(DecodeShader(address, gpuAccessor, flags, counts, out ShaderConfig config), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderProgram Translate(ulong addressA, ulong addressB, IGpuAccessor gpuAccessor, TranslationFlags flags)
|
public static ShaderProgram Translate(
|
||||||
|
ulong addressA,
|
||||||
|
ulong addressB,
|
||||||
|
IGpuAccessor gpuAccessor,
|
||||||
|
TranslationFlags flags,
|
||||||
|
TranslationCounts counts = null)
|
||||||
{
|
{
|
||||||
FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, out ShaderConfig configA);
|
counts ??= new TranslationCounts();
|
||||||
FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, out ShaderConfig config);
|
|
||||||
|
FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, counts, out ShaderConfig configA);
|
||||||
|
FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, counts, out ShaderConfig config);
|
||||||
|
|
||||||
config.SetUsedFeature(configA.UsedFeatures);
|
config.SetUsedFeature(configA.UsedFeatures);
|
||||||
|
|
||||||
|
@ -105,19 +118,24 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return new ShaderProgram(spInfo, config.Stage, glslCode, config.Size, sizeA);
|
return new ShaderProgram(spInfo, config.Stage, glslCode, config.Size, sizeA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FunctionCode[] DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags, out ShaderConfig config)
|
private static FunctionCode[] DecodeShader(
|
||||||
|
ulong address,
|
||||||
|
IGpuAccessor gpuAccessor,
|
||||||
|
TranslationFlags flags,
|
||||||
|
TranslationCounts counts,
|
||||||
|
out ShaderConfig config)
|
||||||
{
|
{
|
||||||
Block[][] cfg;
|
Block[][] cfg;
|
||||||
|
|
||||||
if ((flags & TranslationFlags.Compute) != 0)
|
if ((flags & TranslationFlags.Compute) != 0)
|
||||||
{
|
{
|
||||||
config = new ShaderConfig(gpuAccessor, flags);
|
config = new ShaderConfig(gpuAccessor, flags, counts);
|
||||||
|
|
||||||
cfg = Decoder.Decode(gpuAccessor, address);
|
cfg = Decoder.Decode(gpuAccessor, address);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags);
|
config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags, counts);
|
||||||
|
|
||||||
cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
|
cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue