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:
gdkchan 2020-11-08 08:10:00 -03:00 committed by GitHub
parent 5561a3b95e
commit 8d168574eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 496 additions and 551 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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)

View file

@ -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);
}