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
|
@ -697,20 +697,20 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
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 (unit != -1 && texture != null)
|
||||
if (texture == null)
|
||||
{
|
||||
TextureBase texBase = (TextureBase)texture;
|
||||
return;
|
||||
}
|
||||
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||
TextureBase texBase = (TextureBase)texture;
|
||||
|
||||
if (format != 0)
|
||||
{
|
||||
GL.BindImageTexture(unit, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format);
|
||||
}
|
||||
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
|
||||
|
||||
if (format != 0)
|
||||
{
|
||||
GL.BindImageTexture(binding, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -866,14 +866,14 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
UpdateDepthTest();
|
||||
}
|
||||
|
||||
public void SetSampler(int index, ShaderStage stage, ISampler sampler)
|
||||
public void SetSampler(int binding, ISampler sampler)
|
||||
{
|
||||
int unit = _program.GetTextureUnit(stage, index);
|
||||
|
||||
if (unit != -1 && sampler != null)
|
||||
if (sampler == null)
|
||||
{
|
||||
((Sampler)sampler).Bind(unit);
|
||||
return;
|
||||
}
|
||||
|
||||
((Sampler)sampler).Bind(binding);
|
||||
}
|
||||
|
||||
public void SetScissorEnable(int index, bool enable)
|
||||
|
@ -939,25 +939,25 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
_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 (unit != -1 && texture != null)
|
||||
if (texture == null)
|
||||
{
|
||||
if (unit == 0)
|
||||
{
|
||||
_unit0Texture = (TextureBase)texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
((TextureBase)texture).Bind(unit);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (binding == 0)
|
||||
{
|
||||
_unit0Texture = (TextureBase)texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
((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)
|
||||
|
@ -1077,30 +1077,22 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
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
|
||||
? _program.GetStorageBufferBindingPoint(stage, index)
|
||||
: _program.GetUniformBufferBindingPoint(stage, index);
|
||||
BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer;
|
||||
|
||||
if (bindingPoint == -1)
|
||||
for (int index = 0; index < buffers.Length; index++)
|
||||
{
|
||||
return;
|
||||
BufferRange buffer = buffers[index];
|
||||
|
||||
if (buffer.Handle == BufferHandle.Null)
|
||||
{
|
||||
GL.BindBufferRange(target, index, 0, IntPtr.Zero, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
}
|
||||
|
||||
BufferRangeTarget target = isStorage
|
||||
? BufferRangeTarget.ShaderStorageBuffer
|
||||
: BufferRangeTarget.UniformBuffer;
|
||||
|
||||
if (buffer.Handle == BufferHandle.Null)
|
||||
{
|
||||
GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr bufferOffset = (IntPtr)buffer.Offset;
|
||||
|
||||
GL.BindBufferRange(target, bindingPoint, buffer.Handle.ToInt32(), bufferOffset, buffer.Size);
|
||||
}
|
||||
|
||||
private void SetOrigin(ClipOrigin origin)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -11,18 +10,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
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 FragmentIsBgraUniform { get; }
|
||||
|
@ -31,38 +18,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
public bool IsLinked { get; private set; }
|
||||
|
||||
private int[] _ubBindingPoints;
|
||||
private int[] _sbBindingPoints;
|
||||
private int[] _textureUnits;
|
||||
private int[] _imageUnits;
|
||||
|
||||
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();
|
||||
|
||||
for (int index = 0; index < shaders.Length; index++)
|
||||
|
@ -131,92 +88,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
|
||||
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");
|
||||
FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
|
||||
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
|
||||
|
@ -227,26 +98,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
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()
|
||||
{
|
||||
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
|
||||
|
|
|
@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
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)
|
||||
|
|
|
@ -8,31 +8,22 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
{
|
||||
public int Handle { get; private set; }
|
||||
|
||||
private ShaderProgram _program;
|
||||
|
||||
public ShaderProgramInfo Info => _program.Info;
|
||||
|
||||
public ShaderStage Stage => _program.Stage;
|
||||
|
||||
public Shader(ShaderProgram program)
|
||||
public Shader(ShaderStage stage, string code)
|
||||
{
|
||||
_program = program;
|
||||
|
||||
ShaderType type = ShaderType.VertexShader;
|
||||
|
||||
switch (program.Stage)
|
||||
ShaderType type = stage switch
|
||||
{
|
||||
case ShaderStage.Compute: type = ShaderType.ComputeShader; break;
|
||||
case ShaderStage.Vertex: type = ShaderType.VertexShader; break;
|
||||
case ShaderStage.TessellationControl: type = ShaderType.TessControlShader; break;
|
||||
case ShaderStage.TessellationEvaluation: type = ShaderType.TessEvaluationShader; break;
|
||||
case ShaderStage.Geometry: type = ShaderType.GeometryShader; break;
|
||||
case ShaderStage.Fragment: type = ShaderType.FragmentShader; break;
|
||||
}
|
||||
ShaderStage.Compute => ShaderType.ComputeShader,
|
||||
ShaderStage.Vertex => ShaderType.VertexShader,
|
||||
ShaderStage.TessellationControl => ShaderType.TessControlShader,
|
||||
ShaderStage.TessellationEvaluation => ShaderType.TessEvaluationShader,
|
||||
ShaderStage.Geometry => ShaderType.GeometryShader,
|
||||
ShaderStage.Fragment => ShaderType.FragmentShader,
|
||||
_ => ShaderType.VertexShader
|
||||
};
|
||||
|
||||
Handle = GL.CreateShader(type);
|
||||
|
||||
GL.ShaderSource(Handle, program.Code);
|
||||
GL.ShaderSource(Handle, code);
|
||||
GL.CompileShader(Handle);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue