forked from Mirror/Ryujinx
Implement multiple rendertarget attachments and depth writting (#375)
* Add depth writting * Implement multiple attachments * Address feedback
This commit is contained in:
parent
9977acad0f
commit
624e813cd3
7 changed files with 201 additions and 29 deletions
|
@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
void Set(byte[] Data, int Width, int Height);
|
void Set(byte[] Data, int Width, int Height);
|
||||||
|
|
||||||
|
void SetMap(int[] Map);
|
||||||
|
|
||||||
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom);
|
||||||
|
|
||||||
void SetWindowSize(int Width, int Height);
|
void SetWindowSize(int Width, int Height);
|
||||||
|
|
|
@ -21,18 +21,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly DrawBuffersEnum[] DrawBuffers = new DrawBuffersEnum[]
|
|
||||||
{
|
|
||||||
DrawBuffersEnum.ColorAttachment0,
|
|
||||||
DrawBuffersEnum.ColorAttachment1,
|
|
||||||
DrawBuffersEnum.ColorAttachment2,
|
|
||||||
DrawBuffersEnum.ColorAttachment3,
|
|
||||||
DrawBuffersEnum.ColorAttachment4,
|
|
||||||
DrawBuffersEnum.ColorAttachment5,
|
|
||||||
DrawBuffersEnum.ColorAttachment6,
|
|
||||||
DrawBuffersEnum.ColorAttachment7,
|
|
||||||
};
|
|
||||||
|
|
||||||
private const int NativeWidth = 1280;
|
private const int NativeWidth = 1280;
|
||||||
private const int NativeHeight = 720;
|
private const int NativeHeight = 720;
|
||||||
|
|
||||||
|
@ -194,6 +182,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
ReadTex = RawTex;
|
ReadTex = RawTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetMap(int[] Map)
|
||||||
|
{
|
||||||
|
if (Map != null && Map.Length > 0)
|
||||||
|
{
|
||||||
|
DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < Map.Length; i++)
|
||||||
|
{
|
||||||
|
Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.DrawBuffers(Mode.Length, Mode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
|
||||||
{
|
{
|
||||||
this.FlipX = FlipX;
|
this.FlipX = FlipX;
|
||||||
|
@ -421,8 +428,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||||
|
|
||||||
GL.DrawBuffers(8, DrawBuffers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||||
|
|
|
@ -16,7 +16,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public const int VertexIdAttr = 0x2fc;
|
public const int VertexIdAttr = 0x2fc;
|
||||||
public const int FaceAttr = 0x3fc;
|
public const int FaceAttr = 0x3fc;
|
||||||
|
|
||||||
public const int MaxFrameBufferAttachments = 8;
|
|
||||||
public const int MaxUboSize = 1024;
|
public const int MaxUboSize = 1024;
|
||||||
|
|
||||||
public const int GlPositionVec4Index = 7;
|
public const int GlPositionVec4Index = 7;
|
||||||
|
@ -94,16 +93,33 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType) : this(ShaderType)
|
public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header)
|
||||||
|
: this(ShaderType)
|
||||||
{
|
{
|
||||||
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
||||||
|
|
||||||
if (ShaderType == GalShaderType.Fragment)
|
if (ShaderType == GalShaderType.Fragment)
|
||||||
{
|
{
|
||||||
//Note: Replace 1 with MaxFrameBufferAttachments when attachments start to work
|
int Index = 0;
|
||||||
for (int Index = 0; Index < 1; Index++)
|
|
||||||
|
for (int Attachment = 0; Attachment < 8; Attachment++)
|
||||||
{
|
{
|
||||||
m_Gprs.Add(Index * 4, new ShaderDeclInfo(FragmentOutputName + Index, Index * 4, false, 0, 4));
|
for (int Component = 0; Component < 4; Component++)
|
||||||
|
{
|
||||||
|
if (Header.OmapTargets[Attachment].ComponentEnabled(Component))
|
||||||
|
{
|
||||||
|
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
|
||||||
|
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Header.OmapDepth)
|
||||||
|
{
|
||||||
|
Index = Header.DepthRegister;
|
||||||
|
|
||||||
|
m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +169,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return Combined;
|
return Combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetGprName(int Index)
|
||||||
|
{
|
||||||
|
return GprName + Index;
|
||||||
|
}
|
||||||
|
|
||||||
private static void Merge(
|
private static void Merge(
|
||||||
Dictionary<int, ShaderDeclInfo> C,
|
Dictionary<int, ShaderDeclInfo> C,
|
||||||
Dictionary<int, ShaderDeclInfo> A,
|
Dictionary<int, ShaderDeclInfo> A,
|
||||||
|
@ -316,9 +337,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
case ShaderIrOperGpr Gpr:
|
case ShaderIrOperGpr Gpr:
|
||||||
{
|
{
|
||||||
if (!Gpr.IsConst && !HasName(m_Gprs, Gpr.Index))
|
if (!Gpr.IsConst)
|
||||||
{
|
{
|
||||||
string Name = GprName + Gpr.Index;
|
string Name = GetGprName(Gpr.Index);
|
||||||
|
|
||||||
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,8 +120,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
|
Blocks = ShaderDecoder.Decode(Memory, VpAPosition);
|
||||||
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
|
BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
|
||||||
|
|
||||||
GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType);
|
GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType, Header);
|
||||||
GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType);
|
GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType, HeaderB);
|
||||||
|
|
||||||
Decl = GlslDecl.Merge(DeclVpA, DeclVpB);
|
Decl = GlslDecl.Merge(DeclVpA, DeclVpB);
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Blocks = ShaderDecoder.Decode(Memory, Position);
|
Blocks = ShaderDecoder.Decode(Memory, Position);
|
||||||
BlocksB = null;
|
BlocksB = null;
|
||||||
|
|
||||||
Decl = new GlslDecl(Blocks, ShaderType);
|
Decl = new GlslDecl(Blocks, ShaderType, Header);
|
||||||
|
|
||||||
return Decompile();
|
return Decompile();
|
||||||
}
|
}
|
||||||
|
@ -304,7 +304,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private void PrintDeclOutAttributes()
|
private void PrintDeclOutAttributes()
|
||||||
{
|
{
|
||||||
if (Decl.ShaderType != GalShaderType.Fragment)
|
if (Decl.ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
for (int Attachment = 0; Attachment < 8; Attachment++)
|
||||||
|
{
|
||||||
|
if (Header.OmapTargets[Attachment].Enabled)
|
||||||
|
{
|
||||||
|
SB.AppendLine("layout (location = " + Attachment + ") out vec4 " + GlslDecl.FragmentOutputName + Attachment + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||||
}
|
}
|
||||||
|
@ -432,6 +442,33 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
PrintAttrToOutput();
|
PrintAttrToOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Decl.ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
if (Header.OmapDepth)
|
||||||
|
{
|
||||||
|
SB.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(Header.DepthRegister) + ";");
|
||||||
|
}
|
||||||
|
|
||||||
|
int GprIndex = 0;
|
||||||
|
|
||||||
|
for (int Attachment = 0; Attachment < 8; Attachment++)
|
||||||
|
{
|
||||||
|
string Output = GlslDecl.FragmentOutputName + Attachment;
|
||||||
|
|
||||||
|
OmapTarget Target = Header.OmapTargets[Attachment];
|
||||||
|
|
||||||
|
for (int Component = 0; Component < 4; Component++)
|
||||||
|
{
|
||||||
|
if (Target.ComponentEnabled(Component))
|
||||||
|
{
|
||||||
|
SB.AppendLine(IdentationStr + Output + "[" + Component + "] = " + GlslDecl.GetGprName(GprIndex) + ";");
|
||||||
|
|
||||||
|
GprIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SB.AppendLine("}");
|
SB.AppendLine("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,30 @@
|
||||||
namespace Ryujinx.Graphics.Gal.Shader
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
|
struct OmapTarget
|
||||||
|
{
|
||||||
|
public bool Red;
|
||||||
|
public bool Green;
|
||||||
|
public bool Blue;
|
||||||
|
public bool Alpha;
|
||||||
|
|
||||||
|
public bool Enabled => Red || Green || Blue || 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 ArgumentException(nameof(Component));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ShaderHeader
|
class ShaderHeader
|
||||||
{
|
{
|
||||||
public const int PointList = 1;
|
public const int PointList = 1;
|
||||||
|
@ -30,6 +55,10 @@
|
||||||
public int StoreReqStart { get; private set; }
|
public int StoreReqStart { get; private set; }
|
||||||
public int StoreReqEnd { get; private set; }
|
public int StoreReqEnd { get; private set; }
|
||||||
|
|
||||||
|
public OmapTarget[] OmapTargets { get; private set; }
|
||||||
|
public bool OmapSampleMask { get; private set; }
|
||||||
|
public bool OmapDepth { get; private set; }
|
||||||
|
|
||||||
public ShaderHeader(IGalMemory Memory, long Position)
|
public ShaderHeader(IGalMemory Memory, long Position)
|
||||||
{
|
{
|
||||||
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
|
uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
|
||||||
|
@ -61,6 +90,50 @@
|
||||||
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
|
MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12);
|
||||||
StoreReqStart = ReadBits(CommonWord4, 12, 8);
|
StoreReqStart = ReadBits(CommonWord4, 12, 8);
|
||||||
StoreReqEnd = ReadBits(CommonWord4, 24, 8);
|
StoreReqEnd = ReadBits(CommonWord4, 24, 8);
|
||||||
|
|
||||||
|
//Type 2 (fragment?) reading
|
||||||
|
uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72);
|
||||||
|
uint Type2Omap = (uint)Memory.ReadInt32(Position + 76);
|
||||||
|
|
||||||
|
OmapTargets = new OmapTarget[8];
|
||||||
|
|
||||||
|
for (int i = 0; i < OmapTargets.Length; i++)
|
||||||
|
{
|
||||||
|
int Offset = i * 4;
|
||||||
|
|
||||||
|
OmapTargets[i] = new OmapTarget
|
||||||
|
{
|
||||||
|
Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0,
|
||||||
|
Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0,
|
||||||
|
Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0,
|
||||||
|
Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0;
|
||||||
|
OmapDepth = ReadBits(Type2Omap, 1, 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int DepthRegister
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < OmapTargets.Length; Index++)
|
||||||
|
{
|
||||||
|
for (int Component = 0; Component < 4; Component++)
|
||||||
|
{
|
||||||
|
if (OmapTargets[Index].ComponentEnabled(Component))
|
||||||
|
{
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth register is always two registers after the last color output
|
||||||
|
return Count + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ReadBits(uint Word, int Offset, int BitWidth)
|
private static int ReadBits(uint Word, int Offset, int BitWidth)
|
||||||
|
|
|
@ -102,10 +102,15 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
SetAlphaBlending(State);
|
SetAlphaBlending(State);
|
||||||
SetPrimitiveRestart(State);
|
SetPrimitiveRestart(State);
|
||||||
|
|
||||||
//Enabling multiple framebuffer attachments cause graphics reggresions
|
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
||||||
SetFrameBuffer(Vmm, 0);
|
{
|
||||||
|
SetFrameBuffer(Vmm, 0);
|
||||||
|
}
|
||||||
|
|
||||||
SetZeta(Vmm);
|
SetZeta(Vmm);
|
||||||
|
|
||||||
|
SetRenderTargets();
|
||||||
|
|
||||||
long[] Keys = UploadShaders(Vmm);
|
long[] Keys = UploadShaders(Vmm);
|
||||||
|
|
||||||
Gpu.Renderer.Shader.BindProgram();
|
Gpu.Renderer.Shader.BindProgram();
|
||||||
|
@ -415,6 +420,33 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetRenderTargets()
|
||||||
|
{
|
||||||
|
bool SeparateFragData = (ReadRegister(NvGpuEngine3dReg.RTSeparateFragData) & 1) != 0;
|
||||||
|
|
||||||
|
if (SeparateFragData)
|
||||||
|
{
|
||||||
|
uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
|
||||||
|
|
||||||
|
uint Count = Control & 0xf;
|
||||||
|
|
||||||
|
int[] Map = new int[Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
int Shift = 4 + i * 3;
|
||||||
|
|
||||||
|
Map[i] = (int)((Control >> Shift) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gpu.Renderer.FrameBuffer.SetMap(Map);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Gpu.Renderer.FrameBuffer.SetMap(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)
|
private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys)
|
||||||
{
|
{
|
||||||
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
@ -801,4 +833,4 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
return Vmm.IsRegionModified(Key, Size, Type);
|
return Vmm.IsRegionModified(Key, Size, Type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,13 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
StencilBackFuncRef = 0x3d5,
|
StencilBackFuncRef = 0x3d5,
|
||||||
StencilBackMask = 0x3d6,
|
StencilBackMask = 0x3d6,
|
||||||
StencilBackFuncMask = 0x3d7,
|
StencilBackFuncMask = 0x3d7,
|
||||||
|
RTSeparateFragData = 0x3eb,
|
||||||
ZetaAddress = 0x3f8,
|
ZetaAddress = 0x3f8,
|
||||||
ZetaFormat = 0x3fa,
|
ZetaFormat = 0x3fa,
|
||||||
ZetaBlockDimensions = 0x3fb,
|
ZetaBlockDimensions = 0x3fb,
|
||||||
ZetaLayerStride = 0x3fc,
|
ZetaLayerStride = 0x3fc,
|
||||||
VertexAttribNFormat = 0x458,
|
VertexAttribNFormat = 0x458,
|
||||||
|
RTControl = 0x487,
|
||||||
ZetaHoriz = 0x48a,
|
ZetaHoriz = 0x48a,
|
||||||
ZetaVert = 0x48b,
|
ZetaVert = 0x48b,
|
||||||
ZetaArrayMode = 0x48c,
|
ZetaArrayMode = 0x48c,
|
||||||
|
|
Loading…
Reference in a new issue