|
@@ -86,7 +86,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
UpdateShaderState(state);
|
|
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,
|
|
if (state.QueryModified(MethodOffset.DepthTestEnable,
|
|
|
MethodOffset.DepthWriteEnable,
|
|
MethodOffset.DepthWriteEnable,
|
|
@@ -155,7 +162,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
UpdateFaceState(state);
|
|
UpdateFaceState(state);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (state.QueryModified(MethodOffset.RtColorMask))
|
|
|
|
|
|
|
+ if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
|
|
|
{
|
|
{
|
|
|
UpdateRtColorMask(state);
|
|
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);
|
|
var msaaMode = state.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
|
|
|
|
|
|
|
|
int samplesInX = msaaMode.SamplesInX();
|
|
int samplesInX = msaaMode.SamplesInX();
|
|
@@ -230,9 +230,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
|
|
|
|
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
|
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);
|
|
_textureManager.SetRenderTargetColor(index, null);
|
|
|
|
|
|
|
@@ -292,6 +294,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
|
|
|
|
|
private void UpdateViewportTransform(GpuState state)
|
|
private void UpdateViewportTransform(GpuState state)
|
|
|
{
|
|
{
|
|
|
|
|
+ bool transformEnable = GetViewportTransformEnable(state);
|
|
|
|
|
+
|
|
|
bool flipY = (state.Get<int>(MethodOffset.YControl) & 1) != 0;
|
|
bool flipY = (state.Get<int>(MethodOffset.YControl) & 1) != 0;
|
|
|
|
|
|
|
|
float yFlip = flipY ? -1 : 1;
|
|
float yFlip = flipY ? -1 : 1;
|
|
@@ -303,13 +307,35 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
var transform = state.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
|
|
var transform = state.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
|
|
|
var extents = state.Get<ViewportExtents> (MethodOffset.ViewportExtents, 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(
|
|
viewports[index] = new Viewport(
|
|
|
region,
|
|
region,
|
|
@@ -537,11 +563,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
|
|
|
|
|
private void UpdateRtColorMask(GpuState state)
|
|
private void UpdateRtColorMask(GpuState state)
|
|
|
{
|
|
{
|
|
|
|
|
+ bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared);
|
|
|
|
|
+
|
|
|
uint[] componentMasks = new uint[Constants.TotalRenderTargets];
|
|
uint[] componentMasks = new uint[Constants.TotalRenderTargets];
|
|
|
|
|
|
|
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
|
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;
|
|
uint componentMask = 0;
|
|
|
|
|
|
|
@@ -634,7 +662,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
addressesArray[index] = baseAddress + shader.Offset;
|
|
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;
|
|
_vsUsesInstanceId = gs.Shader[0].Program.Info.UsesInstanceId;
|
|
|
|
|
|
|
@@ -695,6 +725,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
_context.Renderer.Pipeline.BindProgram(gs.HostProgram);
|
|
_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)
|
|
private static Target GetTarget(SamplerType type)
|
|
|
{
|
|
{
|
|
|
type &= ~(SamplerType.Indexed | SamplerType.Shadow);
|
|
type &= ~(SamplerType.Indexed | SamplerType.Shadow);
|