diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index bf6be23a..72276baa 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -365,6 +365,8 @@ namespace skyline::gpu::interconnect { /* Viewport */ private: + bool viewportOriginLowerLeft{}; //!< If the viewport origin follows the lower left convention (OpenGL) as opposed to upper left (Vulkan/Direct3D) + std::array viewportsFlipY{}; //!< If the Y axis of a viewport has been flipped via a viewport swizzle std::array viewports; std::array scissors; //!< The scissors applied to viewports/render targets for masking writes during draws or clears constexpr static vk::Rect2D DefaultScissor{ @@ -387,6 +389,11 @@ namespace skyline::gpu::interconnect { auto &viewport{viewports.at(index)}; viewport.y = translate - scale; // Counteract the addition of the half of the height (p_y/2 is center) to the host translation (o_y) viewport.height = scale * 2.0f; // Counteract the division of the height (p_y) by 2 for the host scale + if (viewportOriginLowerLeft ^ viewportsFlipY[index]) { + // Flip the viewport given that the viewport origin is lower left or the viewport Y has been flipped via a swizzle but not if both are active at the same time + viewport.y += viewport.height; + viewport.height = -viewport.height; + } } void SetViewportZ(size_t index, float scale, float translate) { @@ -395,6 +402,33 @@ namespace skyline::gpu::interconnect { viewport.maxDepth = scale + translate; // Counteract the subtraction of the maxDepth (p_z - o_z) by minDepth (o_z) for the host scale } + void SetViewportSwizzle(size_t index, maxwell3d::ViewportTransform::Swizzle x, maxwell3d::ViewportTransform::Swizzle y, maxwell3d::ViewportTransform::Swizzle z, maxwell3d::ViewportTransform::Swizzle w) { + using Swizzle = maxwell3d::ViewportTransform::Swizzle; + if (x != Swizzle::PositiveX && y != Swizzle::PositiveY && y != Swizzle::NegativeY && z != Swizzle::PositiveZ && w != Swizzle::PositiveW) + throw exception("Unsupported viewport swizzle: {}x{}x{}", maxwell3d::ViewportTransform::ToString(x), maxwell3d::ViewportTransform::ToString(y), maxwell3d::ViewportTransform::ToString(z)); + + bool shouldFlipY{y == Swizzle::NegativeY}; + + auto &viewportFlipY{viewportsFlipY[index]}; + if (viewportFlipY != shouldFlipY) { + auto &viewport{viewports[index]}; + viewport.y += viewport.height; + viewport.height = -viewport.height; + + viewportFlipY = shouldFlipY; + } + } + + void SetViewportOrigin(bool isLowerLeft) { + if (viewportOriginLowerLeft != isLowerLeft) { + for (auto &viewport : viewports) { + viewport.y += viewport.height; + viewport.height = -viewport.height; + } + viewportOriginLowerLeft = isLowerLeft; + } + } + void SetScissor(size_t index, std::optional scissor) { scissors.at(index) = scissor ? vk::Rect2D{ .offset.x = scissor->horizontal.minimum, diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index b9fe2302..0871a6ee 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -176,7 +176,18 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { NegativeW = 7, }; - struct { + ENUM_STRING(Swizzle, { + ENUM_CASE_PAIR(PositiveX, "+X"); + ENUM_CASE_PAIR(NegativeX, "-X"); + ENUM_CASE_PAIR(PositiveY, "+Y"); + ENUM_CASE_PAIR(NegativeY, "-Y"); + ENUM_CASE_PAIR(PositiveZ, "+Z"); + ENUM_CASE_PAIR(NegativeZ, "-Z"); + ENUM_CASE_PAIR(PositiveW, "+W"); + ENUM_CASE_PAIR(NegativeW, "-W"); + }) + + struct Swizzles { Swizzle x : 3; u8 _pad0_ : 1; Swizzle y : 3; diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index c233e7db..2a737df9 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -132,7 +132,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.SetDepthRenderTargetArrayMode(depthTargetArrayMode); }) - #define VIEWPORT_TRANSFORM_CALLBACKS(z, index, data) \ + #define VIEWPORT_TRANSFORM_CALLBACKS(_z, index, data) \ MAXWELL3D_ARRAY_STRUCT_CASE(viewportTransforms, index, scaleX, { \ context.SetViewportX(index, scaleX, registers.viewportTransforms[index].translateX); \ }) \ @@ -150,6 +150,9 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }) \ MAXWELL3D_ARRAY_STRUCT_CASE(viewportTransforms, index, translateZ, { \ context.SetViewportZ(index, registers.viewportTransforms[index].scaleZ, translateZ); \ + }) \ + MAXWELL3D_ARRAY_STRUCT_CASE(viewportTransforms, index, swizzles, { \ + context.SetViewportSwizzle(index, swizzles.x, swizzles.y, swizzles.z, swizzles.w); \ }) BOOST_PP_REPEAT(16, VIEWPORT_TRANSFORM_CALLBACKS, 0) @@ -303,6 +306,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.SetStencilBackWriteMask(writeMask); }) + MAXWELL3D_CASE(windowOriginMode, { + context.SetViewportOrigin(windowOriginMode.isOriginLowerLeft); + }) + MAXWELL3D_CASE(independentBlendEnable, { context.SetIndependentBlendingEnabled(independentBlendEnable); }) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 66945254..6a407995 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -166,6 +166,13 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x4E1, StencilFront> stencilFront; + struct WindowOriginMode { + bool isOriginLowerLeft : 1; + u8 _pad_ : 3; + bool flipFrontFace : 1; + }; + Register<0x4EB, WindowOriginMode> windowOriginMode; + Register<0x4EC, float> lineWidthSmooth; Register<0x4ED, float> lineWidthAliased;