aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-02-16 19:15:39 -0300
committerGitHub <noreply@github.com>2022-02-16 23:15:39 +0100
commit3bd357045f7581ee10d6c86ed8049bcebe35eda0 (patch)
treeaa2d243843f2d31d3afa690f26352713ddac4349
parentab5d77c0c4925955180dc51e9f289187ce6f2901 (diff)
Do not allow render targets not explicitly written by the fragment shader to be modified (#3063)1.1.31
* Do not allow render targets not explicitly written by the fragment shader to be modified * Shader cache version bump * Remove blank lines * Avoid redundant color mask updates * HostShaderCacheEntry can be null * Avoid more redundant glColorMask calls * nit: Mask -> Masks * Fix currentComponentMask * More efficient way to update _currentComponentMasks
-rw-r--r--Ryujinx.Graphics.GAL/IRenderer.cs4
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs8
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs6
-rw-r--r--Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs8
-rw-r--r--Ryujinx.Graphics.GAL/ShaderInfo.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs41
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs62
-rw-r--r--Ryujinx.Graphics.OpenGL/Program.cs23
-rw-r--r--Ryujinx.Graphics.OpenGL/Renderer.cs8
-rw-r--r--Ryujinx.Graphics.OpenGL/Shader.cs2
-rw-r--r--Ryujinx.Graphics.Shader/ShaderProgramInfo.cs21
-rw-r--r--Ryujinx.Graphics.Shader/Translation/EmitterContext.cs8
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs21
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs61
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs3
17 files changed, 176 insertions, 131 deletions
diff --git a/Ryujinx.Graphics.GAL/IRenderer.cs b/Ryujinx.Graphics.GAL/IRenderer.cs
index a1193208..a36d999d 100644
--- a/Ryujinx.Graphics.GAL/IRenderer.cs
+++ b/Ryujinx.Graphics.GAL/IRenderer.cs
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL
BufferHandle CreateBuffer(int size);
- IProgram CreateProgram(IShader[] shaders);
+ IProgram CreateProgram(IShader[] shaders, ShaderInfo info);
ISampler CreateSampler(SamplerCreateInfo info);
ITexture CreateTexture(TextureCreateInfo info, float scale);
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.GAL
Capabilities GetCapabilities();
- IProgram LoadProgramBinary(byte[] programBinary);
+ IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs
index 96bfedf8..b4c6853f 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs
@@ -5,17 +5,21 @@
public ThreadedProgram Threaded { get; set; }
private byte[] _data;
+ private bool _hasFragmentShader;
+ private ShaderInfo _info;
- public BinaryProgramRequest(ThreadedProgram program, byte[] data)
+ public BinaryProgramRequest(ThreadedProgram program, byte[] data, bool hasFragmentShader, ShaderInfo info)
{
Threaded = program;
_data = data;
+ _hasFragmentShader = hasFragmentShader;
+ _info = info;
}
public IProgram Create(IRenderer renderer)
{
- return renderer.LoadProgramBinary(_data);
+ return renderer.LoadProgramBinary(_data, _hasFragmentShader, _info);
}
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs
index 8e4cd1d4..d808fe22 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs
@@ -7,12 +7,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
public ThreadedProgram Threaded { get; set; }
private IShader[] _shaders;
+ private ShaderInfo _info;
- public SourceProgramRequest(ThreadedProgram program, IShader[] shaders)
+ public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, ShaderInfo info)
{
Threaded = program;
_shaders = shaders;
+ _info = info;
}
public IProgram Create(IRenderer renderer)
@@ -24,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
return threaded?.Base;
}).ToArray();
- return renderer.CreateProgram(shaders);
+ return renderer.CreateProgram(shaders, _info);
}
}
}
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
index df46b428..5030fee6 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
@@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return handle;
}
- public IProgram CreateProgram(IShader[] shaders)
+ public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
{
var program = new ThreadedProgram(this);
- SourceProgramRequest request = new SourceProgramRequest(program, shaders);
+ SourceProgramRequest request = new SourceProgramRequest(program, shaders, info);
Programs.Add(request);
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
@@ -355,11 +355,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_baseRenderer.Initialize(logLevel);
}
- public IProgram LoadProgramBinary(byte[] programBinary)
+ public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{
var program = new ThreadedProgram(this);
- BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary);
+ BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary, hasFragmentShader, info);
Programs.Add(request);
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
diff --git a/Ryujinx.Graphics.GAL/ShaderInfo.cs b/Ryujinx.Graphics.GAL/ShaderInfo.cs
new file mode 100644
index 00000000..0c187e06
--- /dev/null
+++ b/Ryujinx.Graphics.GAL/ShaderInfo.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.GAL
+{
+ public struct ShaderInfo
+ {
+ public int FragmentOutputMap { get; }
+
+ public ShaderInfo(int fragmentOutputMap)
+ {
+ FragmentOutputMap = fragmentOutputMap;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs
index 68f6b3c1..819c6bcc 100644
--- a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs
@@ -77,7 +77,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
programInfo.Images.Count,
programInfo.UsesInstanceId,
programInfo.UsesRtLayer,
- programInfo.ClipDistancesWritten);
+ programInfo.ClipDistancesWritten,
+ programInfo.FragmentOutputMap);
CBuffers = programInfo.CBuffers.ToArray();
SBuffers = programInfo.SBuffers.ToArray();
Textures = programInfo.Textures.ToArray();
@@ -97,7 +98,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
Images,
Header.UseFlags.HasFlag(UseFlags.InstanceId),
Header.UseFlags.HasFlag(UseFlags.RtLayer),
- Header.ClipDistancesWritten);
+ Header.ClipDistancesWritten,
+ Header.FragmentOutputMap);
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs
index 4b8b15bc..c3c0de22 100644
--- a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs
@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
/// <summary>
/// Host shader entry header used for binding information.
/// </summary>
- [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x14)]
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)]
struct HostShaderCacheEntryHeader
{
/// <summary>
@@ -71,6 +71,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
public byte Reserved;
/// <summary>
+ /// Mask of components written by the fragment shader stage.
+ /// </summary>
+ public int FragmentOutputMap;
+
+ /// <summary>
/// Create a new host shader cache entry header.
/// </summary>
/// <param name="cBuffersCount">Count of constant buffer descriptors</param>
@@ -78,6 +83,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
/// <param name="texturesCount">Count of texture descriptors</param>
/// <param name="imagesCount">Count of image descriptors</param>
/// <param name="usesInstanceId">Set to true if the shader uses instance id</param>
+ /// <param name="clipDistancesWritten">Mask of clip distances that are written to on the shader</param>
+ /// <param name="fragmentOutputMap">Mask of components written by the fragment shader stage</param>
public HostShaderCacheEntryHeader(
int cBuffersCount,
int sBuffersCount,
@@ -85,13 +92,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
int imagesCount,
bool usesInstanceId,
bool usesRtLayer,
- byte clipDistancesWritten) : this()
+ byte clipDistancesWritten,
+ int fragmentOutputMap) : this()
{
CBuffersCount = cBuffersCount;
SBuffersCount = sBuffersCount;
TexturesCount = texturesCount;
ImagesCount = imagesCount;
ClipDistancesWritten = clipDistancesWritten;
+ FragmentOutputMap = fragmentOutputMap;
InUse = true;
UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None;
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index f1e9f383..bf76d592 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// Version of the codegen (to be changed when codegen or guest format change).
/// </summary>
- private const ulong ShaderCodeGenVersion = 3106;
+ private const ulong ShaderCodeGenVersion = 3063;
// Progress reporting helpers
private volatile int _shaderCount;
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
hostProgramBinary = hostProgramBinarySpan.ToArray();
- hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
+ hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, false, new ShaderInfo(-1));
}
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
@@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
// Compile shader and create program as the shader program binary got invalidated.
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
- hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
+ hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
{
@@ -303,7 +303,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
hostProgramBinary = hostProgramBinarySpan.ToArray();
- hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
+
+ bool hasFragmentShader = false;
+ int fragmentOutputMap = -1;
+ int fragmentIndex = (int)ShaderStage.Fragment - 1;
+
+ if (hostShaderEntries[fragmentIndex] != null && hostShaderEntries[fragmentIndex].Header.InUse)
+ {
+ hasFragmentShader = true;
+ fragmentOutputMap = hostShaderEntries[fragmentIndex].Header.FragmentOutputMap;
+ }
+
+ hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, hasFragmentShader, new ShaderInfo(fragmentOutputMap));
}
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
@@ -426,7 +437,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
hostShaders.Add(hostShader);
}
- hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
+ int fragmentIndex = (int)ShaderStage.Fragment - 1;
+ int fragmentOutputMap = -1;
+
+ if (shaders[fragmentIndex] != null)
+ {
+ fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
+ }
+
+ hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
{
@@ -617,7 +636,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
- IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
+ IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
cpShader = new ShaderBundle(hostProgram, shader);
@@ -755,7 +774,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
hostShaders.Add(hostShader);
}
- IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
+ int fragmentIndex = (int)ShaderStage.Fragment - 1;
+ int fragmentOutputMap = -1;
+
+ if (shaders[fragmentIndex] != null)
+ {
+ fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
+ }
+
+ IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
gpShaders = new ShaderBundle(hostProgram, shaders);
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index ff5af42d..c20ce8a3 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -53,7 +53,9 @@ namespace Ryujinx.Graphics.OpenGL
private ClipOrigin _clipOrigin;
private ClipDepthMode _clipDepthMode;
- private readonly uint[] _componentMasks;
+ private uint _fragmentOutputMap;
+ private uint _componentMasks;
+ private uint _currentComponentMasks;
private uint _scissorEnables;
@@ -73,12 +75,8 @@ namespace Ryujinx.Graphics.OpenGL
_clipOrigin = ClipOrigin.LowerLeft;
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
- _componentMasks = new uint[Constants.MaxRenderTargets];
-
- for (int index = 0; index < Constants.MaxRenderTargets; index++)
- {
- _componentMasks[index] = 0xf;
- }
+ _fragmentOutputMap = uint.MaxValue;
+ _componentMasks = uint.MaxValue;
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
@@ -1001,18 +999,30 @@ namespace Ryujinx.Graphics.OpenGL
public void SetProgram(IProgram program)
{
- _program = (Program)program;
+ Program prg = (Program)program;
if (_tfEnabled)
{
GL.EndTransformFeedback();
- _program.Bind();
+ prg.Bind();
GL.BeginTransformFeedback(_tfTopology);
}
else
{
- _program.Bind();
+ prg.Bind();
+ }
+
+ if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap)
+ {
+ _fragmentOutputMap = (uint)prg.FragmentOutputMap;
+
+ for (int index = 0; index < Constants.MaxRenderTargets; index++)
+ {
+ RestoreComponentMask(index, force: false);
+ }
}
+
+ _program = prg;
}
public void SetRasterizerDiscard(bool discard)
@@ -1037,11 +1047,13 @@ namespace Ryujinx.Graphics.OpenGL
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
{
+ _componentMasks = 0;
+
for (int index = 0; index < componentMasks.Length; index++)
{
- _componentMasks[index] = componentMasks[index];
+ _componentMasks |= componentMasks[index] << (index * 4);
- RestoreComponentMask(index);
+ RestoreComponentMask(index, force: false);
}
}
@@ -1436,18 +1448,34 @@ namespace Ryujinx.Graphics.OpenGL
}
}
- public void RestoreComponentMask(int index)
+ public void RestoreComponentMask(int index, bool force = true)
{
// If the bound render target is bgra, swap the red and blue masks.
uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u;
uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u;
+ int shift = index * 4;
+ uint componentMask = _componentMasks & _fragmentOutputMap;
+ uint checkMask = 0xfu << shift;
+ uint componentMaskAtIndex = componentMask & checkMask;
+
+ if (!force && componentMaskAtIndex == (_currentComponentMasks & checkMask))
+ {
+ return;
+ }
+
+ componentMask >>= shift;
+ componentMask &= 0xfu;
+
GL.ColorMask(
index,
- (_componentMasks[index] & redMask) != 0,
- (_componentMasks[index] & 2u) != 0,
- (_componentMasks[index] & blueMask) != 0,
- (_componentMasks[index] & 8u) != 0);
+ (componentMask & redMask) != 0,
+ (componentMask & 2u) != 0,
+ (componentMask & blueMask) != 0,
+ (componentMask & 8u) != 0);
+
+ _currentComponentMasks &= ~checkMask;
+ _currentComponentMasks |= componentMaskAtIndex;
}
public void RestoreScissor0Enable()
diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs
index 95902990..838162cc 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -1,11 +1,8 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader.CodeGen.Glsl;
using System;
using System.Buffers.Binary;
-using System.Collections.Generic;
-using System.Linq;
namespace Ryujinx.Graphics.OpenGL
{
@@ -29,7 +26,10 @@ namespace Ryujinx.Graphics.OpenGL
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
private IShader[] _shaders;
- public Program(IShader[] shaders)
+ public bool HasFragmentShader;
+ public int FragmentOutputMap { get; }
+
+ public Program(IShader[] shaders, int fragmentOutputMap)
{
Handle = GL.CreateProgram();
@@ -37,17 +37,23 @@ namespace Ryujinx.Graphics.OpenGL
for (int index = 0; index < shaders.Length; index++)
{
- int shaderHandle = ((Shader)shaders[index]).Handle;
+ Shader shader = (Shader)shaders[index];
- GL.AttachShader(Handle, shaderHandle);
+ if (shader.IsFragment)
+ {
+ HasFragmentShader = true;
+ }
+
+ GL.AttachShader(Handle, shader.Handle);
}
GL.LinkProgram(Handle);
_shaders = shaders;
+ FragmentOutputMap = fragmentOutputMap;
}
- public Program(ReadOnlySpan<byte> code)
+ public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
{
BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
@@ -60,6 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
}
}
+
+ HasFragmentShader = hasFragmentShader;
+ FragmentOutputMap = fragmentOutputMap;
}
public void Bind()
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 8d44f2e4..a99ecfcc 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
return Buffer.Create(size);
}
- public IProgram CreateProgram(IShader[] shaders)
+ public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
{
- return new Program(shaders);
+ return new Program(shaders, info.FragmentOutputMap);
}
public ISampler CreateSampler(SamplerCreateInfo info)
@@ -202,9 +202,9 @@ namespace Ryujinx.Graphics.OpenGL
_sync.Dispose();
}
- public IProgram LoadProgramBinary(byte[] programBinary)
+ public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{
- return new Program(programBinary);
+ return new Program(programBinary, hasFragmentShader, info.FragmentOutputMap);
}
public void CreateSync(ulong id)
diff --git a/Ryujinx.Graphics.OpenGL/Shader.cs b/Ryujinx.Graphics.OpenGL/Shader.cs
index 1df07ee4..8374fa62 100644
--- a/Ryujinx.Graphics.OpenGL/Shader.cs
+++ b/Ryujinx.Graphics.OpenGL/Shader.cs
@@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.OpenGL
class Shader : IShader
{
public int Handle { get; private set; }
+ public bool IsFragment { get; }
public Shader(ShaderStage stage, string code)
{
@@ -22,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
};
Handle = GL.CreateShader(type);
+ IsFragment = stage == ShaderStage.Fragment;
GL.ShaderSource(Handle, code);
GL.CompileShader(Handle);
diff --git a/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs b/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs
index a9ce486b..d1c1b945 100644
--- a/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs
+++ b/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs
@@ -5,32 +5,35 @@ namespace Ryujinx.Graphics.Shader
{
public class ShaderProgramInfo
{
- public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
- public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
+ public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
+ public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
public ReadOnlyCollection<TextureDescriptor> Textures { get; }
- public ReadOnlyCollection<TextureDescriptor> Images { get; }
+ public ReadOnlyCollection<TextureDescriptor> Images { get; }
public bool UsesInstanceId { get; }
public bool UsesRtLayer { get; }
public byte ClipDistancesWritten { get; }
+ public int FragmentOutputMap { get; }
public ShaderProgramInfo(
- BufferDescriptor[] cBuffers,
- BufferDescriptor[] sBuffers,
+ BufferDescriptor[] cBuffers,
+ BufferDescriptor[] sBuffers,
TextureDescriptor[] textures,
TextureDescriptor[] images,
- bool usesInstanceId,
- bool usesRtLayer,
- byte clipDistancesWritten)
+ bool usesInstanceId,
+ bool usesRtLayer,
+ byte clipDistancesWritten,
+ int fragmentOutputMap)
{
CBuffers = Array.AsReadOnly(cBuffers);
SBuffers = Array.AsReadOnly(sBuffers);
Textures = Array.AsReadOnly(textures);
- Images = Array.AsReadOnly(images);
+ Images = Array.AsReadOnly(images);
UsesInstanceId = usesInstanceId;
UsesRtLayer = usesRtLayer;
ClipDistancesWritten = clipDistancesWritten;
+ FragmentOutputMap = fragmentOutputMap;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 3dcb04ad..775f1217 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -172,11 +172,10 @@ namespace Ryujinx.Graphics.Shader.Translation
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
{
- OmapTarget target = Config.OmapTargets[rtIndex];
-
for (int component = 0; component < 4; component++)
{
- if (!target.ComponentEnabled(component))
+ bool componentEnabled = (Config.OmapTargets & (1 << (rtIndex * 4 + component))) != 0;
+ if (!componentEnabled)
{
continue;
}
@@ -210,7 +209,8 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
- if (target.Enabled)
+ bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
+ if (targetEnabled)
{
Config.SetOutputUserAttribute(rtIndex, perPatch: false);
regIndexBase += 4;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 21f17041..996c2814 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -25,9 +25,9 @@ namespace Ryujinx.Graphics.Shader.Translation
public ImapPixelType[] ImapTypes { get; }
- public OmapTarget[] OmapTargets { get; }
- public bool OmapSampleMask { get; }
- public bool OmapDepth { get; }
+ public int OmapTargets { get; }
+ public bool OmapSampleMask { get; }
+ public bool OmapDepth { get; }
public IGpuAccessor GpuAccessor { get; }
@@ -135,21 +135,8 @@ namespace Ryujinx.Graphics.Shader.Translation
public int GetDepthRegister()
{
- int count = 0;
-
- for (int index = 0; index < OmapTargets.Length; index++)
- {
- for (int component = 0; component < 4; component++)
- {
- if (OmapTargets[index].ComponentEnabled(component))
- {
- count++;
- }
- }
- }
-
// The depth register is always two registers after the last color output.
- return count + 1;
+ return BitOperations.PopCount((uint)OmapTargets) + 1;
}
public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
index 0ad172da..e53c77af 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
@@ -36,37 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
- struct OmapTarget
- {
- public bool Red { get; }
- public bool Green { get; }
- public bool Blue { get; }
- public bool Alpha { get; }
-
- public bool Enabled => Red || Green || Blue || Alpha;
-
- public OmapTarget(bool red, bool green, bool blue, bool alpha)
- {
- Red = red;
- Green = green;
- Blue = blue;
- Alpha = alpha;
- }
-
- public bool ComponentEnabled(int component)
- {
- switch (component)
- {
- case 0: return Red;
- case 1: return Green;
- case 2: return Blue;
- case 3: return Alpha;
- }
-
- throw new ArgumentOutOfRangeException(nameof(component));
- }
- }
-
class ShaderHeader
{
public int SphType { get; }
@@ -85,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public bool GpPassthrough { get; }
public bool DoesLoadOrStore { get; }
- public bool DoesFp64 { get; }
+ public bool DoesFp64 { get; }
public int StreamOutMask { get; }
@@ -104,13 +73,13 @@ namespace Ryujinx.Graphics.Shader.Translation
public int MaxOutputVertexCount { get; }
public int StoreReqStart { get; }
- public int StoreReqEnd { get; }
+ public int StoreReqEnd { get; }
public ImapPixelType[] ImapTypes { get; }
- public OmapTarget[] OmapTargets { get; }
- public bool OmapSampleMask { get; }
- public bool OmapDepth { get; }
+ public int OmapTargets { get; }
+ public bool OmapSampleMask { get; }
+ public bool OmapDepth { get; }
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
{
@@ -144,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.Translation
GpPassthrough = commonWord0.Extract(24);
DoesLoadOrStore = commonWord0.Extract(26);
- DoesFp64 = commonWord0.Extract(27);
+ DoesFp64 = commonWord0.Extract(27);
StreamOutMask = commonWord0.Extract(28, 4);
@@ -163,7 +132,7 @@ namespace Ryujinx.Graphics.Shader.Translation
MaxOutputVertexCount = commonWord4.Extract(0, 12);
StoreReqStart = commonWord4.Extract(12, 8);
- StoreReqEnd = commonWord4.Extract(24, 8);
+ StoreReqEnd = commonWord4.Extract(24, 8);
ImapTypes = new ImapPixelType[32];
@@ -179,21 +148,11 @@ namespace Ryujinx.Graphics.Shader.Translation
}
int type2OmapTarget = header[18];
- int type2Omap = header[19];
-
- OmapTargets = new OmapTarget[8];
-
- for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4)
- {
- OmapTargets[offset >> 2] = new OmapTarget(
- type2OmapTarget.Extract(offset + 0),
- type2OmapTarget.Extract(offset + 1),
- type2OmapTarget.Extract(offset + 2),
- type2OmapTarget.Extract(offset + 3));
- }
+ int type2Omap = header[19];
+ OmapTargets = type2OmapTarget;
OmapSampleMask = type2Omap.Extract(0);
- OmapDepth = type2Omap.Extract(1);
+ OmapDepth = type2Omap.Extract(1);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 709b16db..603b20d6 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -105,7 +105,8 @@ namespace Ryujinx.Graphics.Shader.Translation
config.GetImageDescriptors(),
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
- config.ClipDistancesWritten);
+ config.ClipDistancesWritten,
+ config.OmapTargets);
return program;
}