aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodClear.cs4
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs24
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs82
4 files changed, 76 insertions, 40 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs
index da6c94e5..43f8b25d 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
private void Clear(GpuState state, int argument)
{
- UpdateRenderTargetStateIfNeeded(state);
+ UpdateRenderTargetState(state, useControl: false);
_textureManager.CommitGraphicsBindings();
@@ -49,6 +49,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
stencilValue,
stencilMask);
}
+
+ UpdateRenderTargetState(state, useControl: true);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
index d69b9ea0..b7e8a64b 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
@@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
private int _firstIndex;
private int _indexCount;
- private bool _instancedHasState;
+ private bool _instancedDrawPending;
private bool _instancedIndexed;
private int _instancedFirstIndex;
@@ -32,9 +32,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (instanced)
{
- if (!_instancedHasState)
+ if (!_instancedDrawPending)
{
- _instancedHasState = true;
+ _instancedDrawPending = true;
_instancedIndexed = _drawIndexed;
@@ -82,20 +82,22 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void DrawBegin(GpuState state, int argument)
{
- PrimitiveType type = (PrimitiveType)(argument & 0xffff);
-
- _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert());
-
- PrimitiveType = type;
-
if ((argument & (1 << 26)) != 0)
{
_instanceIndex++;
}
else if ((argument & (1 << 27)) == 0)
{
+ PerformDeferredDraws();
+
_instanceIndex = 0;
}
+
+ PrimitiveType type = (PrimitiveType)(argument & 0xffff);
+
+ _context.Renderer.Pipeline.SetPrimitiveTopology(type.Convert());
+
+ PrimitiveType = type;
}
private void SetIndexBufferCount(GpuState state, int argument)
@@ -106,9 +108,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
public void PerformDeferredDraws()
{
// Perform any pending instanced draw.
- if (_instancedHasState)
+ if (_instancedDrawPending)
{
- _instancedHasState = false;
+ _instancedDrawPending = false;
if (_instancedIndexed)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
index 12d44f51..43bab243 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.State;
namespace Ryujinx.Graphics.Gpu.Engine
@@ -9,11 +8,6 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
var uniformBuffer = state.Get<UniformBufferState>(MethodOffset.UniformBufferState);
- if (_context.MemoryManager.Translate(uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset) == MemoryManager.BadAddress)
- {
- return;
- }
-
_context.MemoryAccessor.Write(uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset, argument);
state.SetUniformBufferOffset(uniformBuffer.Offset + 4);
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index 18fd7e70..5388c86d 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -86,7 +86,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
UpdateShaderState(state);
}
- UpdateRenderTargetStateIfNeeded(state);
+ if (state.QueryModified(MethodOffset.RtColorState,
+ MethodOffset.RtDepthStencilState,
+ MethodOffset.RtControl,
+ MethodOffset.RtDepthStencilSize,
+ MethodOffset.RtDepthStencilEnable))
+ {
+ UpdateRenderTargetState(state, useControl: true);
+ }
if (state.QueryModified(MethodOffset.DepthTestEnable,
MethodOffset.DepthWriteEnable,
@@ -155,7 +162,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
UpdateFaceState(state);
}
- if (state.QueryModified(MethodOffset.RtColorMask))
+ if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
{
UpdateRtColorMask(state);
}
@@ -210,19 +217,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
}
- private void UpdateRenderTargetStateIfNeeded(GpuState state)
+ private void UpdateRenderTargetState(GpuState state, bool useControl)
{
- if (state.QueryModified(MethodOffset.RtColorState,
- MethodOffset.RtDepthStencilState,
- MethodOffset.RtDepthStencilSize,
- MethodOffset.RtDepthStencilEnable))
- {
- UpdateRenderTargetState(state);
- }
- }
+ var rtControl = state.Get<RtControl>(MethodOffset.RtControl);
+
+ int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
- private void UpdateRenderTargetState(GpuState state)
- {
var msaaMode = state.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
int samplesInX = msaaMode.SamplesInX();
@@ -230,9 +230,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
- var colorState = state.Get<RtColorState>(MethodOffset.RtColorState, index);
+ int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
- if (!IsRtEnabled(colorState))
+ var colorState = state.Get<RtColorState>(MethodOffset.RtColorState, rtIndex);
+
+ if (index >= count || !IsRtEnabled(colorState))
{
_textureManager.SetRenderTargetColor(index, null);
@@ -292,6 +294,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateViewportTransform(GpuState state)
{
+ bool transformEnable = GetViewportTransformEnable(state);
+
bool flipY = (state.Get<int>(MethodOffset.YControl) & 1) != 0;
float yFlip = flipY ? -1 : 1;
@@ -303,13 +307,35 @@ namespace Ryujinx.Graphics.Gpu.Engine
var transform = state.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
var extents = state.Get<ViewportExtents> (MethodOffset.ViewportExtents, index);
- float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
- float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
+ RectangleF region;
- float width = transform.ScaleX * 2;
- float height = transform.ScaleY * 2 * yFlip;
+ if (transformEnable)
+ {
+ float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
+ float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
- RectangleF region = new RectangleF(x, y, width, height);
+ float width = transform.ScaleX * 2;
+ float height = transform.ScaleY * 2 * yFlip;
+
+ region = new RectangleF(x, y, width, height);
+ }
+ else
+ {
+ // It's not possible to fully disable viewport transform, at least with the most
+ // common graphics APIs, but we can effectively disable it with a dummy transform.
+ // The transform is defined as: xw = (width / 2) * xndc + x + (width / 2)
+ // By setting x to -(width / 2), we effectively remove the translation.
+ // By setting the width to 2, we remove the scale since 2 / 2 = 1.
+ // Now, the only problem is the viewport clipping, that we also can't disable.
+ // To prevent the values from being clipped, we multiply (-1, -1, 2, 2) by
+ // the maximum supported viewport dimensions.
+ // This must be compensated on the shader, by dividing the vertex position
+ // by the maximum viewport dimensions.
+ float maxSize = (float)_context.Capabilities.MaximumViewportDimensions;
+ float halfMaxSize = (float)_context.Capabilities.MaximumViewportDimensions * 0.5f;
+
+ region = new RectangleF(-halfMaxSize, -halfMaxSize, maxSize, maxSize * yFlip);
+ }
viewports[index] = new Viewport(
region,
@@ -537,11 +563,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateRtColorMask(GpuState state)
{
+ bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared);
+
uint[] componentMasks = new uint[Constants.TotalRenderTargets];
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
- var colorMask = state.Get<RtColorMask>(MethodOffset.RtColorMask, index);
+ var colorMask = state.Get<RtColorMask>(MethodOffset.RtColorMask, rtColorMaskShared ? 0 : index);
uint componentMask = 0;
@@ -634,7 +662,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
addressesArray[index] = baseAddress + shader.Offset;
}
- GraphicsShader gs = _shaderCache.GetGraphicsShader(addresses);
+ bool viewportTransformEnable = GetViewportTransformEnable(state);
+
+ GraphicsShader gs = _shaderCache.GetGraphicsShader(addresses, !viewportTransformEnable);
_vsUsesInstanceId = gs.Shader[0].Program.Info.UsesInstanceId;
@@ -695,6 +725,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
_context.Renderer.Pipeline.BindProgram(gs.HostProgram);
}
+ private bool GetViewportTransformEnable(GpuState state)
+ {
+ // FIXME: We should read ViewportTransformEnable, but it seems that some games writes 0 there?
+ // return state.Get<Boolean32>(MethodOffset.ViewportTransformEnable) != 0;
+
+ return true;
+ }
+
private static Target GetTarget(SamplerType type)
{
type &= ~(SamplerType.Indexed | SamplerType.Shadow);