|
@@ -488,25 +488,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
/// <param name="state">Current GPU state</param>
|
|
/// <param name="state">Current GPU state</param>
|
|
|
private void UpdateViewportTransform(GpuState state)
|
|
private void UpdateViewportTransform(GpuState state)
|
|
|
{
|
|
{
|
|
|
- DepthMode depthMode = state.Get<DepthMode>(MethodOffset.DepthMode);
|
|
|
|
|
|
|
+ var yControl = state.Get<YControl> (MethodOffset.YControl);
|
|
|
|
|
+ var face = state.Get<FaceState>(MethodOffset.FaceState);
|
|
|
|
|
|
|
|
- _context.Renderer.Pipeline.SetDepthMode(depthMode);
|
|
|
|
|
|
|
+ UpdateFrontFace(yControl, face.FrontFace);
|
|
|
|
|
|
|
|
- YControl yControl = state.Get<YControl>(MethodOffset.YControl);
|
|
|
|
|
-
|
|
|
|
|
- bool flipY = yControl.HasFlag(YControl.NegateY);
|
|
|
|
|
- Origin origin = yControl.HasFlag(YControl.TriangleRastFlip) ? Origin.LowerLeft : Origin.UpperLeft;
|
|
|
|
|
-
|
|
|
|
|
- _context.Renderer.Pipeline.SetOrigin(origin);
|
|
|
|
|
-
|
|
|
|
|
- // The triangle rast flip flag only affects rasterization, the viewport is not flipped.
|
|
|
|
|
- // Setting the origin mode to upper left on the host, however, not only affects rasterization,
|
|
|
|
|
- // but also flips the viewport.
|
|
|
|
|
- // We negate the effects of flipping the viewport by flipping it again using the viewport swizzle.
|
|
|
|
|
- if (origin == Origin.UpperLeft)
|
|
|
|
|
- {
|
|
|
|
|
- flipY = !flipY;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ bool flipY = yControl.HasFlag(YControl.NegateY);
|
|
|
|
|
|
|
|
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
|
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
|
|
|
|
|
|
@@ -515,11 +502,42 @@ 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);
|
|
|
|
|
|
|
+ float scaleX = MathF.Abs(transform.ScaleX);
|
|
|
|
|
+ float scaleY = transform.ScaleY;
|
|
|
|
|
|
|
|
- float width = MathF.Abs(transform.ScaleX) * 2;
|
|
|
|
|
- float height = MathF.Abs(transform.ScaleY) * 2;
|
|
|
|
|
|
|
+ if (flipY)
|
|
|
|
|
+ {
|
|
|
|
|
+ scaleY = -scaleY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!_context.Capabilities.SupportsViewportSwizzle && transform.UnpackSwizzleY() == ViewportSwizzle.NegativeY)
|
|
|
|
|
+ {
|
|
|
|
|
+ scaleY = -scaleY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (index == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Try to guess the depth mode being used on the high level API
|
|
|
|
|
+ // based on current transform.
|
|
|
|
|
+ // It is setup like so by said APIs:
|
|
|
|
|
+ // If depth mode is ZeroToOne:
|
|
|
|
|
+ // TranslateZ = Near
|
|
|
|
|
+ // ScaleZ = Far - Near
|
|
|
|
|
+ // If depth mode is MinusOneToOne:
|
|
|
|
|
+ // TranslateZ = (Near + Far) / 2
|
|
|
|
|
+ // ScaleZ = (Far - Near) / 2
|
|
|
|
|
+ // DepthNear/Far are sorted such as that Near is always less than Far.
|
|
|
|
|
+ DepthMode depthMode = extents.DepthNear != transform.TranslateZ &&
|
|
|
|
|
+ extents.DepthFar != transform.TranslateZ ? DepthMode.MinusOneToOne : DepthMode.ZeroToOne;
|
|
|
|
|
+
|
|
|
|
|
+ _context.Renderer.Pipeline.SetDepthMode(depthMode);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ float x = transform.TranslateX - scaleX;
|
|
|
|
|
+ float y = transform.TranslateY - scaleY;
|
|
|
|
|
+
|
|
|
|
|
+ float width = scaleX * 2;
|
|
|
|
|
+ float height = scaleY * 2;
|
|
|
|
|
|
|
|
float scale = TextureManager.RenderTargetScale;
|
|
float scale = TextureManager.RenderTargetScale;
|
|
|
if (scale != 1f)
|
|
if (scale != 1f)
|
|
@@ -537,34 +555,17 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
|
|
ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
|
|
|
ViewportSwizzle swizzleW = transform.UnpackSwizzleW();
|
|
ViewportSwizzle swizzleW = transform.UnpackSwizzleW();
|
|
|
|
|
|
|
|
- if (transform.ScaleX < 0)
|
|
|
|
|
- {
|
|
|
|
|
- swizzleX ^= ViewportSwizzle.NegativeFlag;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (flipY)
|
|
|
|
|
- {
|
|
|
|
|
- swizzleY ^= ViewportSwizzle.NegativeFlag;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (transform.ScaleY < 0)
|
|
|
|
|
- {
|
|
|
|
|
- swizzleY ^= ViewportSwizzle.NegativeFlag;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ float depthNear = extents.DepthNear;
|
|
|
|
|
+ float depthFar = extents.DepthFar;
|
|
|
|
|
|
|
|
if (transform.ScaleZ < 0)
|
|
if (transform.ScaleZ < 0)
|
|
|
{
|
|
{
|
|
|
- swizzleZ ^= ViewportSwizzle.NegativeFlag;
|
|
|
|
|
|
|
+ float temp = depthNear;
|
|
|
|
|
+ depthNear = depthFar;
|
|
|
|
|
+ depthFar = temp;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- viewports[index] = new Viewport(
|
|
|
|
|
- region,
|
|
|
|
|
- swizzleX,
|
|
|
|
|
- swizzleY,
|
|
|
|
|
- swizzleZ,
|
|
|
|
|
- swizzleW,
|
|
|
|
|
- extents.DepthNear,
|
|
|
|
|
- extents.DepthFar);
|
|
|
|
|
|
|
+ viewports[index] = new Viewport(region, swizzleX, swizzleY, swizzleZ, swizzleW, depthNear, depthFar);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
_context.Renderer.Pipeline.SetViewports(0, viewports);
|
|
_context.Renderer.Pipeline.SetViewports(0, viewports);
|
|
@@ -832,11 +833,29 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|
|
/// <param name="state">Current GPU state</param>
|
|
/// <param name="state">Current GPU state</param>
|
|
|
private void UpdateFaceState(GpuState state)
|
|
private void UpdateFaceState(GpuState state)
|
|
|
{
|
|
{
|
|
|
- var face = state.Get<FaceState>(MethodOffset.FaceState);
|
|
|
|
|
|
|
+ var yControl = state.Get<YControl> (MethodOffset.YControl);
|
|
|
|
|
+ var face = state.Get<FaceState>(MethodOffset.FaceState);
|
|
|
|
|
|
|
|
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
|
|
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
|
|
|
|
|
|
|
|
- _context.Renderer.Pipeline.SetFrontFace(face.FrontFace);
|
|
|
|
|
|
|
+ UpdateFrontFace(yControl, face.FrontFace);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Updates the front face based on the current front face and the origin.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ /// <param name="yControl">Y control register value, where the origin is located</param>
|
|
|
|
|
+ /// <param name="frontFace">Front face</param>
|
|
|
|
|
+ private void UpdateFrontFace(YControl yControl, FrontFace frontFace)
|
|
|
|
|
+ {
|
|
|
|
|
+ bool isUpperLeftOrigin = !yControl.HasFlag(YControl.TriangleRastFlip);
|
|
|
|
|
+
|
|
|
|
|
+ if (isUpperLeftOrigin)
|
|
|
|
|
+ {
|
|
|
|
|
+ frontFace = frontFace == FrontFace.CounterClockwise ? FrontFace.Clockwise : FrontFace.CounterClockwise;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _context.Renderer.Pipeline.SetFrontFace(frontFace);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|