diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 08d0fc7244..7ef4fdc42e 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -151,6 +151,25 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) { return 0; } +void SoftwareTransform::SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale) { + memcpy(&projMatrix_.m, mtx, 16 * sizeof(float)); + + if (invertedY) { + projMatrix_.xy = -projMatrix_.xy; + projMatrix_.yy = -projMatrix_.yy; + projMatrix_.zy = -projMatrix_.zy; + projMatrix_.wy = -projMatrix_.wy; + } + if (invertedX) { + projMatrix_.xx = -projMatrix_.xx; + projMatrix_.yx = -projMatrix_.yx; + projMatrix_.zx = -projMatrix_.zx; + projMatrix_.wx = -projMatrix_.wx; + } + + projMatrix_.translateAndScale(trans, scale); +} + void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result) { u8 *decoded = params_.decoded; TransformedVertex *transformed = params_.transformed; @@ -560,30 +579,6 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy numTrans = vertexCount; result->drawIndexed = true; } else { - // Pretty bad hackery where we re-do the transform (in RotateUV) to see if the vertices are flipped in screen space. - // Since we've already got API-specific assumptions (Y direction, etc) baked into the projMatrix (which we arguably shouldn't), - // this gets nasty and very hard to understand. - - float flippedMatrix[16]; - if (!throughmode) { - memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float)); - - const bool invertedY = params_.flippedY ? (gstate_c.vpHeight < 0) : (gstate_c.vpHeight > 0); - if (invertedY) { - flippedMatrix[1] = -flippedMatrix[1]; - flippedMatrix[5] = -flippedMatrix[5]; - flippedMatrix[9] = -flippedMatrix[9]; - flippedMatrix[13] = -flippedMatrix[13]; - } - const bool invertedX = gstate_c.vpWidth < 0; - if (invertedX) { - flippedMatrix[0] = -flippedMatrix[0]; - flippedMatrix[4] = -flippedMatrix[4]; - flippedMatrix[8] = -flippedMatrix[8]; - flippedMatrix[12] = -flippedMatrix[12]; - } - } - //rectangles always need 2 vertices, disregard the last one if there's an odd number vertexCount = vertexCount & ~1; numTrans = 0; @@ -625,9 +620,9 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy RotateUVThrough(trans); } else { Vec4f tl; - Vec3ByMatrix44(tl.AsArray(), transVtxTL.pos, flippedMatrix); + Vec3ByMatrix44(tl.AsArray(), transVtxTL.pos, projMatrix_.m); Vec4f br; - Vec3ByMatrix44(br.AsArray(), transVtxBR.pos, flippedMatrix); + Vec3ByMatrix44(br.AsArray(), transVtxBR.pos, projMatrix_.m); // If both transformed verts are outside Z, cull this rectangle entirely. constexpr float outsideValue = 1.000030517578125f; diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index e1acd1cab5..0e6ce3b56d 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -18,8 +18,8 @@ #pragma once #include "Common/CommonTypes.h" - -#include "VertexDecoderCommon.h" +#include "Common/Math/lin/matrix4x4.h" +#include "GPU/Common/VertexDecoderCommon.h" class FramebufferManagerCommon; class TextureCacheCommon; @@ -64,10 +64,12 @@ public: SoftwareTransform(SoftwareTransformParams ¶ms) : params_(params) { } + void SetProjMatrix(float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale); void Decode(int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result); void DetectOffsetTexture(int maxIndex); void BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result); protected: const SoftwareTransformParams ¶ms_; + Lin::Matrix4x4 projMatrix_; }; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 4426572efa..61500e79c3 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -599,6 +599,11 @@ rotateVBO: int maxIndex = indexGen.MaxIndex(); SoftwareTransform swTransform(params); + + const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); + const Lin::Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); + swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index 712a1f14e4..a05dc17494 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -568,6 +568,17 @@ rotateVBO: int maxIndex = indexGen.MaxIndex(); SoftwareTransform swTransform(params); + + // Half pixel offset hack. + float xScale = gstate_c.vpWidth < 0 ? -1.0f : 1.0f; + float xOffset = -1.0f / gstate_c.curRTRenderWidth; + float yScale = gstate_c.vpHeight > 0 ? -1.0f : 1.0f; + float yOffset = 1.0f / gstate_c.curRTRenderHeight; + + const Lin::Vec3 trans(gstate_c.vpXOffset * xScale + xOffset, gstate_c.vpYOffset * yScale + yOffset, gstate_c.vpZOffset * 0.5f + 0.5f); + const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight > 0, trans, scale); + swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 4efdd09102..8fc26ef780 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -563,7 +563,7 @@ void DrawEngineGLES::DoFlush() { params.allowClear = true; params.allowSeparateAlphaClear = true; params.provokeFlatFirst = false; - params.flippedY = !framebufferManager_->UseBufferedRendering(); + params.flippedY = framebufferManager_->UseBufferedRendering(); // We need correct viewport values in gstate_c already. if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { @@ -583,6 +583,12 @@ void DrawEngineGLES::DoFlush() { #endif SoftwareTransform swTransform(params); + + const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset); + const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale * (params.flippedY ? 1.0 : -1.0f), gstate_c.vpDepthScale); + const bool invertedY = gstate_c.vpHeight * (params.flippedY ? 1.0 : -1.0f) < 0; + swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale); + swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); if (result.action == SW_NOT_READY) swTransform.DetectOffsetTexture(maxIndex); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index fcfb09bfbe..db211f3efa 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -909,7 +909,7 @@ void DrawEngineVulkan::DoFlush() { params.allowClear = framebufferManager_->UseBufferedRendering(); params.allowSeparateAlphaClear = false; params.provokeFlatFirst = true; - params.flippedY = false; + params.flippedY = true; // We need to update the viewport early because it's checked for flipping in SoftwareTransform. // We don't have a "DrawStateEarly" in vulkan, so... @@ -924,6 +924,11 @@ void DrawEngineVulkan::DoFlush() { int maxIndex = indexGen.MaxIndex(); SoftwareTransform swTransform(params); + + const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f); + const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f); + swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, gstate_c.vpHeight < 0, trans, scale); + swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result); if (result.action == SW_NOT_READY) { swTransform.DetectOffsetTexture(maxIndex);