Fix wrong face culling once and for all (#1277)

* Viewport swizzle support on NV and clip origin

* Initialize default viewport swizzle state, emulate viewport swizzle on shaders when not supported

* Address PR feedback
This commit is contained in:
gdkchan 2020-05-27 20:03:07 -03:00 committed by GitHub
parent 83d94b21d0
commit a15b951721
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 202 additions and 53 deletions

View file

@ -422,10 +422,23 @@ namespace Ryujinx.Graphics.Gpu.Engine
_context.Renderer.Pipeline.SetDepthMode(depthMode);
bool flipY = (state.Get<YControl>(MethodOffset.YControl) & YControl.NegateY) != 0;
float yFlip = flipY ? -1 : 1;
YControl yControl = state.Get<YControl>(MethodOffset.YControl);
Viewport[] viewports = new Viewport[Constants.TotalViewports];
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 onlyy 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;
}
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
for (int index = 0; index < Constants.TotalViewports; index++)
{
@ -435,17 +448,42 @@ namespace Ryujinx.Graphics.Gpu.Engine
float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
float width = transform.ScaleX * 2;
float height = transform.ScaleY * 2 * yFlip;
float width = MathF.Abs(transform.ScaleX) * 2;
float height = MathF.Abs(transform.ScaleY) * 2;
RectangleF region = new RectangleF(x, y, width, height);
ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
ViewportSwizzle swizzleW = transform.UnpackSwizzleW();
if (transform.ScaleX < 0)
{
swizzleX ^= ViewportSwizzle.NegativeFlag;
}
if (flipY)
{
swizzleY ^= ViewportSwizzle.NegativeFlag;
}
if (transform.ScaleY < 0)
{
swizzleY ^= ViewportSwizzle.NegativeFlag;
}
if (transform.ScaleZ < 0)
{
swizzleZ ^= ViewportSwizzle.NegativeFlag;
}
viewports[index] = new Viewport(
region,
transform.UnpackSwizzleX(),
transform.UnpackSwizzleY(),
transform.UnpackSwizzleZ(),
transform.UnpackSwizzleW(),
swizzleX,
swizzleY,
swizzleZ,
swizzleW,
extents.DepthNear,
extents.DepthFar);
}

View file

@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Gpu.Image
float mipLodBias = descriptor.UnpackMipLodBias();
float maxRequestedAnisotropy = GraphicsConfig.MaxAnisotropy >= 0 && GraphicsConfig.MaxAnisotropy <= 16 ? GraphicsConfig.MaxAnisotropy : descriptor.UnpackMaxAnisotropy();
float maxSupportedAnisotropy = context.Capabilities.MaxSupportedAnisotropy;
float maxSupportedAnisotropy = context.Capabilities.MaximumSupportedAnisotropy;
if (maxRequestedAnisotropy > maxSupportedAnisotropy)
maxRequestedAnisotropy = maxSupportedAnisotropy;

View file

@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Shader;
using System;
namespace Ryujinx.Graphics.Gpu.Shader
{
@ -187,6 +188,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>True if the GPU and driver supports non-constant texture offsets, false otherwise</returns>
public bool QuerySupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
/// <summary>
/// Queries host GPU viewport swizzle support.
/// </summary>
/// <returns>True if the GPU and driver supports viewport swizzle, false otherwise</returns>
public bool QuerySupportsViewportSwizzle() => _context.Capabilities.SupportsViewportSwizzle;
/// <summary>
/// Queries texture format information, for shaders using image load or store.
/// </summary>
@ -250,6 +257,24 @@ namespace Ryujinx.Graphics.Gpu.Shader
};
}
public int QueryViewportSwizzle(int component)
{
YControl yControl = _state.Get<YControl>(MethodOffset.YControl);
bool flipY = yControl.HasFlag(YControl.NegateY) ^ !yControl.HasFlag(YControl.TriangleRastFlip);
ViewportTransform transform = _state.Get<ViewportTransform>(MethodOffset.ViewportTransform, 0);
return component switch
{
0 => (int)(transform.UnpackSwizzleX() ^ (transform.ScaleX < 0 ? ViewportSwizzle.NegativeFlag : 0)),
1 => (int)(transform.UnpackSwizzleY() ^ (transform.ScaleY < 0 ? ViewportSwizzle.NegativeFlag : 0) ^ (flipY ? ViewportSwizzle.NegativeFlag : 0)),
2 => (int)(transform.UnpackSwizzleZ() ^ (transform.ScaleZ < 0 ? ViewportSwizzle.NegativeFlag : 0)),
3 => (int)transform.UnpackSwizzleW(),
_ => throw new ArgumentOutOfRangeException(nameof(component))
};
}
/// <summary>
/// Gets the texture descriptor for a given texture on the pool.
/// </summary>

View file

@ -146,6 +146,9 @@ namespace Ryujinx.Graphics.Gpu.State
{
memory[(int)MethodOffset.ViewportExtents + index * 4 + 2] = 0;
memory[(int)MethodOffset.ViewportExtents + index * 4 + 3] = 0x3F800000;
// Set swizzle to +XYZW
memory[(int)MethodOffset.ViewportTransform + index * 8 + 6] = 0x6420;
}
// Viewport transform enable.