aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.Graphics/Gal/GalPipelineState.cs13
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs51
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs36
-rw-r--r--Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs3
4 files changed, 103 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gal/GalPipelineState.cs b/Ryujinx.Graphics/Gal/GalPipelineState.cs
index 8630da9c..8deb68b4 100644
--- a/Ryujinx.Graphics/Gal/GalPipelineState.cs
+++ b/Ryujinx.Graphics/Gal/GalPipelineState.cs
@@ -91,6 +91,13 @@
public GalStencilOp StencilFrontOpZPass;
public uint StencilFrontMask;
+ public int ScissorTestCount;
+ public bool[] ScissorTestEnabled;
+ public int[] ScissorTestX;
+ public int[] ScissorTestY;
+ public int[] ScissorTestWidth;
+ public int[] ScissorTestHeight;
+
public bool BlendIndependent;
public BlendState[] Blends;
@@ -111,6 +118,12 @@
Blends = new BlendState[RenderTargetsCount];
+ ScissorTestEnabled = new bool[RenderTargetsCount];
+ ScissorTestY = new int[RenderTargetsCount];
+ ScissorTestX = new int[RenderTargetsCount];
+ ScissorTestWidth = new int[RenderTargetsCount];
+ ScissorTestHeight = new int[RenderTargetsCount];
+
ColorMasks = new ColorMaskState[RenderTargetsCount];
}
}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
index eb7f958b..e9143c19 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
@@ -270,6 +270,57 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
+
+ // Scissor Test
+ bool forceUpdate;
+
+ for (int Index = 0; Index < New.ScissorTestCount; Index++)
+ {
+ forceUpdate = false;
+
+ if (New.ScissorTestEnabled[Index] != Old.ScissorTestEnabled[Index])
+ {
+ if (New.ScissorTestEnabled[Index])
+ {
+ // If there is only 1 scissor test geometry shaders are disables so the scissor test applies to all viewports
+ if (New.ScissorTestCount == 1)
+ {
+ GL.Enable(EnableCap.ScissorTest);
+ }
+ else
+ {
+ GL.Enable(IndexedEnableCap.ScissorTest, Index);
+ }
+ forceUpdate = true;
+ }
+ else
+ {
+ GL.Disable(IndexedEnableCap.ScissorTest, Index);
+ }
+ }
+
+ if (New.ScissorTestEnabled[Index] &&
+ (New.ScissorTestX[Index] != Old.ScissorTestX[Index] ||
+ New.ScissorTestY[Index] != Old.ScissorTestY[Index] ||
+ New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] ||
+ New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index] ||
+ forceUpdate)) // Force update intentionally last to reduce if comparisons
+ {
+ // If there is only 1 scissor test geometry shaders are disables so the scissor test applies to all viewports
+ if (New.ScissorTestCount == 1)
+ {
+ GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index],
+ New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
+ }
+ else
+ {
+ GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index],
+ New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
+ }
+ }
+ }
+
+
if (New.BlendIndependent)
{
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
index dc1eec3b..9a22c85f 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
@@ -24,6 +24,9 @@ namespace Ryujinx.Graphics.Graphics3d
private ConstBuffer[][] ConstBuffers;
+ // Height kept for flipping y axis
+ private int ViewportHeight = 0;
+
private int CurrentInstance = 0;
public NvGpuEngine3d(NvGpu Gpu)
@@ -97,6 +100,7 @@ namespace Ryujinx.Graphics.Graphics3d
SetCullFace(State);
SetDepth(State);
SetStencil(State);
+ SetScissor(State);
SetBlending(State);
SetColorMask(State);
SetPrimitiveRestart(State);
@@ -208,6 +212,8 @@ namespace Ryujinx.Graphics.Graphics3d
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
+ ViewportHeight = VpH;
+
Gpu.Renderer.RenderTarget.SetViewport(FbIndex, VpX, VpY, VpW, VpH);
}
@@ -407,6 +413,36 @@ namespace Ryujinx.Graphics.Graphics3d
}
}
+ private void SetScissor(GalPipelineState State)
+ {
+ // FIXME: Stubbed, only the first scissor test is valid without a geometry shader loaded. At time of writing geometry shaders are also stubbed.
+ // Once geometry shaders are fixed it should be equal to GalPipelineState.RenderTargetCount when shader loaded, otherwise equal to 1
+ State.ScissorTestCount = 1;
+
+ for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
+ {
+ State.ScissorTestEnabled[Index] = ReadRegisterBool(NvGpuEngine3dReg.ScissorEnable + Index * 4);
+
+ if (State.ScissorTestEnabled[Index])
+ {
+ uint ScissorHorizontal = (uint)ReadRegister(NvGpuEngine3dReg.ScissorHorizontal + Index * 4);
+ uint ScissorVertical = (uint)ReadRegister(NvGpuEngine3dReg.ScissorVertical + Index * 4);
+
+ State.ScissorTestX[Index] = (int)((ScissorHorizontal & 0xFFFF) * State.FlipX); // X, lower 16 bits
+ State.ScissorTestWidth[Index] = (int)((ScissorHorizontal >> 16) * State.FlipX) - State.ScissorTestX[Index]; // Width, right side is upper 16 bits
+
+ State.ScissorTestY[Index] = (int)((ScissorVertical & 0xFFFF)); // Y, lower 16 bits
+ State.ScissorTestHeight[Index] = (int)((ScissorVertical >> 16)) - State.ScissorTestY[Index]; // Height, top side is upper 16 bits
+
+ // Y coordinates may have to be flipped
+ if ((int)State.FlipY == -1)
+ {
+ State.ScissorTestY[Index] = ViewportHeight - State.ScissorTestY[Index] - State.ScissorTestHeight[Index];
+ }
+ }
+ }
+ }
+
private void SetBlending(GalPipelineState State)
{
bool BlendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent);
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs
index 30243c02..026b0cd1 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs
@@ -22,6 +22,9 @@ namespace Ryujinx.Graphics.Graphics3d
ClearNColor = 0x360,
ClearDepth = 0x364,
ClearStencil = 0x368,
+ ScissorEnable = 0x380,
+ ScissorHorizontal = 0x381,
+ ScissorVertical = 0x382,
StencilBackFuncRef = 0x3d5,
StencilBackMask = 0x3d6,
StencilBackFuncMask = 0x3d7,