diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index a8a02e78a4..f3135fe2d0 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -134,6 +134,7 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView flippedMatrix = flippedMatrix * g_display_rot_matrix; } CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr()); + ub->rotation = (float)g_display_rotation; } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 5292a10494..1195af4547 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -28,7 +28,8 @@ struct UB_VS_FS_Base { float tex[12]; float uvScaleOffset[4]; float depthRange[4]; - float fogCoef[2]; float stencil; float pad0; + // Rotation is used only for software transform. + float fogCoef[2]; float stencil; float rotation; float matAmbient[4]; float cullRangeMin[4]; float cullRangeMax[4]; @@ -55,6 +56,7 @@ R"( mat4 u_proj; vec4 u_depthRange; vec2 u_fogcoef; float u_stencilReplaceValue; + float u_rotation; vec4 u_matambientalpha; vec4 u_cullRangeMin; vec4 u_cullRangeMax; diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 93a72e07da..a24414ce5e 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -64,16 +64,14 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) { // Note: 0 is BR and 2 is TL. -static void RotateUV(TransformedVertex v[4], Vec4f tl, Vec4f br, bool flippedY) { +static void RotateUV(TransformedVertex v[4], bool flippedY) { // We use the transformed tl/br coordinates to figure out whether they're flipped or not. float ySign = flippedY ? -1.0 : 1.0; - const float invtlw = 1.0f / tl.w; - const float invbrw = 1.0f / br.w; - const float x1 = tl.x * invtlw; - const float x2 = br.x * invbrw; - const float y1 = tl.y * invtlw * ySign; - const float y2 = br.y * invbrw * ySign; + const float x1 = v[2].x; + const float x2 = v[0].x; + const float y1 = v[2].y * ySign; + const float y2 = v[0].y * ySign; if ((x1 < x2 && y1 < y2) || (x1 > x2 && y1 > y2)) SwapUVs(v[1], v[3]); @@ -151,6 +149,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; @@ -196,6 +213,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt // TODO: Write to a flexible buffer, we don't always need all four components. TransformedVertex &vert = transformed[index]; reader.ReadPos(vert.pos); + vert.posw = 1.0f; if (reader.hasColor0()) { if (provokeIndOffset != 0 && index + provokeIndOffset < maxIndex) { @@ -412,14 +430,13 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt fogCoef = (v[2] + fog_end) * fog_slope; // TODO: Write to a flexible buffer, we don't always need all four components. - memcpy(&transformed[index].x, v, 3 * sizeof(float)); + Vec3ByMatrix44(transformed[index].pos, v, projMatrix_.m); transformed[index].fog = fogCoef; - memcpy(&transformed[index].u, uv, 3 * sizeof(float)); + memcpy(&transformed[index].uv, uv, 3 * sizeof(float)); transformed[index].color0_32 = c0.ToRGBA(); transformed[index].color1_32 = c1.ToRGBA(); - // The multiplication by the projection matrix is still performed in the vertex shader. - // So is vertex depth rounding, to simulate the 16-bit depth buffer. + // Vertex depth rounding is done in the shader, to simulate the 16-bit depth buffer. } } @@ -428,7 +445,6 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt // // An alternative option is to simply ditch all the verts except the first and last to create a single // rectangle out of many. Quite a small optimization though. - // Experiment: Disable on PowerVR (see issue #6290) // TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not. // TODO: Allow creating a depth clear and a color draw. bool reallyAClear = false; @@ -555,37 +571,11 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy FramebufferManagerCommon *fbman = params_.fbman; bool useBufferedRendering = fbman->UseBufferedRendering(); - bool flippedY = g_Config.iGPUBackend == (int)GPUBackend::OPENGL && !useBufferedRendering; - if (prim != GE_PRIM_RECTANGLES) { // We can simply draw the unexpanded buffer. 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 = 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; @@ -626,21 +616,8 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy if (throughmode) { RotateUVThrough(trans); } else { - Vec4f tl; - Vec3ByMatrix44(tl.AsArray(), transVtxTL.pos, flippedMatrix); - Vec4f br; - Vec3ByMatrix44(br.AsArray(), transVtxBR.pos, flippedMatrix); - - // If both transformed verts are outside Z, cull this rectangle entirely. - constexpr float outsideValue = 1.000030517578125f; - bool tlOutside = fabsf(tl.z / tl.w) >= outsideValue; - bool brOutside = fabsf(br.z / br.w) >= outsideValue; - if (tlOutside && brOutside) - continue; - if (!gstate.isDepthClampEnabled() && (tlOutside || brOutside)) - continue; - - RotateUV(trans, tl, br, flippedY); + // TODO: Should apply culling here, based on projection depth range. + RotateUV(trans, params_.flippedY); } // Triangle: BR-TR-TL diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index 98250afbea..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; @@ -56,6 +56,7 @@ struct SoftwareTransformParams { bool allowClear; bool allowSeparateAlphaClear; bool provokeFlatFirst; + bool flippedY; }; class SoftwareTransform { @@ -63,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/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index afa0173989..4bebe73e6b 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -236,11 +236,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (useHWTransform) WRITE(p, "layout (location = %d) in vec3 position;\n", (int)PspAttributeLocation::POSITION); else - // we pass the fog coord in w WRITE(p, "layout (location = %d) in vec4 position;\n", (int)PspAttributeLocation::POSITION); if (useHWTransform && hasNormal) WRITE(p, "layout (location = %d) in vec3 normal;\n", (int)PspAttributeLocation::NORMAL); + if (!useHWTransform && enableFog) + WRITE(p, "layout (location = %d) in float fog;\n", (int)PspAttributeLocation::NORMAL); if (doTexture && hasTexcoord) { if (!useHWTransform && doTextureTransform && !isModeThrough) { @@ -278,9 +279,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "#pragma warning( disable : 3571 )\n"); if (isModeThrough) { WRITE(p, "mat4 u_proj_through : register(c%i);\n", CONST_VS_PROJ_THROUGH); - } else { + } else if (useHWTransform) { WRITE(p, "mat4 u_proj : register(c%i);\n", CONST_VS_PROJ); - // Add all the uniforms we'll need to transform properly. + } else { + WRITE(p, "float u_rotation : register(c%i);\n", CONST_VS_ROTATION); } if (enableFog) { @@ -385,6 +387,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (lmode) { WRITE(p, " vec3 color1 : COLOR1;\n"); } + if (enableFog) { + WRITE(p, " float fog : NORMAL;\n"); + } WRITE(p, "};\n"); } @@ -434,6 +439,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "%s mediump vec3 normal;\n", compat.attribute); *attrMask |= 1 << ATTR_NORMAL; } + if (!useHWTransform && enableFog) { + WRITE(p, "%s highp float fog;\n", compat.attribute); + *attrMask |= 1 << ATTR_NORMAL; + } if (doTexture && hasTexcoord) { if (!useHWTransform && doTextureTransform && !isModeThrough) { @@ -456,10 +465,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (isModeThrough) { WRITE(p, "uniform mat4 u_proj_through;\n"); *uniformMask |= DIRTY_PROJTHROUGHMATRIX; - } else { + } else if (useHWTransform) { WRITE(p, "uniform mat4 u_proj;\n"); *uniformMask |= DIRTY_PROJMATRIX; - // Add all the uniforms we'll need to transform properly. } if (useHWTransform) { @@ -519,6 +527,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, "uniform lowp vec3 u_matemissive;\n"); *uniformMask |= DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE; } + } else { + WRITE(p, "uniform lowp float u_rotation;\n"); } if (useHWTransform || !hasColor) { @@ -763,6 +773,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag } else { WRITE(p, " vec4 position = In.position;\n"); } + if (!useHWTransform && enableFog) { + WRITE(p, " float fog = In.fog;\n"); + } if (enableBones) { WRITE(p, "%s", boneWeightAttrInitHLSL[numBoneWeights]); } @@ -787,16 +800,24 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " %sv_color1 = splat3(0.0);\n", compat.vsOutPrefix); } if (enableFog) { - WRITE(p, " %sv_fogdepth = position.w;\n", compat.vsOutPrefix); + WRITE(p, " %sv_fogdepth = fog;\n", compat.vsOutPrefix); } if (isModeThrough) { WRITE(p, " vec4 outPos = mul(u_proj_through, vec4(position.xyz, 1.0));\n"); } else { + // Apply rotation from the uniform. + WRITE(p, " mat4 displayRotation = mat4(\n"); + WRITE(p, " u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), u_rotation == 1.0 ? 1.0 : (u_rotation == 3.0 ? -1.0 : 0.0), 0.0, 0.0,\n"); + WRITE(p, " u_rotation == 3.0 ? 1.0 : (u_rotation == 1.0 ? -1.0 : 0.0), u_rotation == 0.0 ? 1.0 : (u_rotation == 2.0 ? -1.0 : 0.0), 0.0, 0.0,\n"); + WRITE(p, " 0.0, 0.0, 1.0, 0.0,\n"); + WRITE(p, " 0.0, 0.0, 0.0, 1.0\n"); + WRITE(p, " );\n"); + // The viewport is used in this case, so need to compensate for that. if (gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) { - WRITE(p, " vec4 outPos = depthRoundZVP(mul(u_proj, vec4(position.xyz, 1.0)));\n"); + WRITE(p, " vec4 outPos = depthRoundZVP(mul(displayRotation, position));\n"); } else { - WRITE(p, " vec4 outPos = mul(u_proj, vec4(position.xyz, 1.0));\n"); + WRITE(p, " vec4 outPos = mul(displayRotation, position);\n"); } } } else { diff --git a/GPU/Common/VertexShaderGenerator.h b/GPU/Common/VertexShaderGenerator.h index 65b151e9f4..c1899001e6 100644 --- a/GPU/Common/VertexShaderGenerator.h +++ b/GPU/Common/VertexShaderGenerator.h @@ -60,4 +60,5 @@ enum { CONST_VS_BONE8 = 77, CONST_VS_CULLRANGEMIN = 80, CONST_VS_CULLRANGEMAX = 81, + CONST_VS_ROTATION = 82, }; diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 6dc47766fb..289f1390f3 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -61,10 +61,11 @@ enum { }; static const D3D11_INPUT_ELEMENT_DESC TransformedVertexElements[] = { - { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(TransformedVertex, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, offsetof(TransformedVertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(TransformedVertex, color0), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(TransformedVertex, color1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "NORMAL", 0, DXGI_FORMAT_R32_FLOAT, 0, offsetof(TransformedVertex, fog), D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; DrawEngineD3D11::DrawEngineD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context) @@ -586,9 +587,24 @@ rotateVBO: params.allowClear = true; params.allowSeparateAlphaClear = false; // D3D11 doesn't support separate alpha clears params.provokeFlatFirst = true; + params.flippedY = false; + + // We need correct viewport values in gstate_c already. + if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { + ViewportAndScissor vpAndScissor; + ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(), + framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), + framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), + vpAndScissor); + } 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 377d2164f4..5febe909e3 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -77,10 +77,11 @@ enum { enum { VAI_KILL_AGE = 120, VAI_UNRELIABLE_KILL_AGE = 240, VAI_UNRELIABLE_KILL_MAX = 4 }; static const D3DVERTEXELEMENT9 TransformedVertexElements[] = { - { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, - { 0, 16, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, - { 0, 28, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, - { 0, 32, D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 }, + { 0, offsetof(TransformedVertex, pos), D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, + { 0, offsetof(TransformedVertex, uv), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, offsetof(TransformedVertex, color0), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, offsetof(TransformedVertex, color1), D3DDECLTYPE_UBYTE4N, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 }, + { 0, offsetof(TransformedVertex, fog), D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END() }; @@ -555,9 +556,30 @@ rotateVBO: params.allowClear = true; params.allowSeparateAlphaClear = false; params.provokeFlatFirst = true; + params.flippedY = false; + + // We need correct viewport values in gstate_c already. + if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { + ViewportAndScissor vpAndScissor; + ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(), + framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), + framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), + vpAndScissor); + } 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/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 9927460cd4..6dbb07918b 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -22,13 +22,14 @@ #include #include +#include "Common/Data/Convert/SmallDataConvert.h" +#include "Common/Data/Encoding/Utf8.h" #include "Common/Data/Text/I18n.h" #include "Common/Math/lin/matrix4x4.h" #include "Common/Math/math_util.h" -#include "Common/Data/Convert/SmallDataConvert.h" #include "Common/GPU/D3D9/D3D9ShaderCompiler.h" #include "Common/GPU/thin3d.h" -#include "Common/Data/Encoding/Utf8.h" +#include "Common/System/Display.h" #include "Common/Common.h" #include "Common/Log.h" @@ -344,6 +345,7 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) { ConvertProjMatrixToD3D(flippedMatrix, invertedX, invertedY); VSSetMatrix(CONST_VS_PROJ, flippedMatrix.getReadPtr()); + VSSetFloat(CONST_VS_ROTATION, (float)g_display_rotation); } if (dirtyUniforms & DIRTY_PROJTHROUGHMATRIX) { Matrix4x4 proj_through; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 122222be69..e95c5aa313 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -118,10 +118,11 @@ void DrawEngineGLES::InitDeviceObjects() { int vertexSize = sizeof(TransformedVertex); std::vector entries; - entries.push_back({ ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, 0 }); + entries.push_back({ ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, x) }); entries.push_back({ ATTR_TEXCOORD, 3, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, u) }); entries.push_back({ ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color0) }); entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, offsetof(TransformedVertex, color1) }); + entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, vertexSize, offsetof(TransformedVertex, fog) }); softwareInputLayout_ = render_->CreateInputLayout(entries); } @@ -563,6 +564,15 @@ void DrawEngineGLES::DoFlush() { params.allowClear = true; params.allowSeparateAlphaClear = true; params.provokeFlatFirst = false; + params.flippedY = framebufferManager_->UseBufferedRendering(); + + // We need correct viewport values in gstate_c already. + if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { + ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(), + framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), + framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), + vpAndScissor); + } int maxIndex = indexGen.MaxIndex(); int vertexCount = indexGen.VertexCount(); @@ -574,6 +584,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/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index f2c3514702..7d59ee150f 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -33,6 +33,7 @@ #include "Common/GPU/Shader.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/OpenGL/GLRenderManager.h" +#include "Common/System/Display.h" #include "Common/Log.h" #include "Common/File/FileUtil.h" @@ -84,7 +85,10 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, std::vector semantics; semantics.push_back({ ATTR_POSITION, "position" }); semantics.push_back({ ATTR_TEXCOORD, "texcoord" }); - semantics.push_back({ ATTR_NORMAL, "normal" }); + if (useHWTransform_) + semantics.push_back({ ATTR_NORMAL, "normal" }); + else + semantics.push_back({ ATTR_NORMAL, "fog" }); semantics.push_back({ ATTR_W1, "w1" }); semantics.push_back({ ATTR_W2, "w2" }); semantics.push_back({ ATTR_COLOR0, "color0" }); @@ -124,6 +128,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs, queries.push_back({ &u_depthRange, "u_depthRange" }); queries.push_back({ &u_cullRangeMin, "u_cullRangeMin" }); queries.push_back({ &u_cullRangeMax, "u_cullRangeMax" }); + queries.push_back({ &u_rotation, "u_rotation" }); #ifdef USE_BONE_ARRAY queries.push_back({ &u_bone, "u_bone" }); @@ -360,6 +365,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu ScaleProjMatrix(flippedMatrix, useBufferedRendering); render_->SetUniformM4x4(&u_proj, flippedMatrix.m); + render_->SetUniformF1(&u_rotation, (float)g_display_rotation); } if (dirty & DIRTY_PROJTHROUGHMATRIX) { diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index 24ef3e42f1..89b335b094 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -60,6 +60,7 @@ public: int u_depthRange; // x,y = viewport xscale/xcenter. z,w=clipping minz/maxz (?) int u_cullRangeMin; int u_cullRangeMax; + int u_rotation; #ifdef USE_BONE_ARRAY int u_bone; // array, size is numBones diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 3f4fe99b66..124c924bfe 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2259,6 +2259,7 @@ void GPUCommon::Execute_ImmVertexAlphaPrim(u32 op, u32 diff) { v.x = ((gstate.imm_vscx & 0xFFFFFF) - offsetX) / 16.0f; v.y = ((gstate.imm_vscy & 0xFFFFFF) - offsetY) / 16.0f; v.z = gstate.imm_vscz & 0xFFFF; + v.posw = 1.0f; v.u = getFloat24(gstate.imm_vtcs); v.v = getFloat24(gstate.imm_vtct); v.w = getFloat24(gstate.imm_vtcq); diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 5d5fa76f0c..3fd57d7f9d 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -43,7 +43,7 @@ enum { struct TransformedVertex { union { struct { - float x, y, z, fog; // in case of morph, preblend during decode + float x, y, z, posw; // in case of morph, preblend during decode }; float pos[4]; }; @@ -53,6 +53,7 @@ struct TransformedVertex { }; float uv[3]; }; + float fog; union { u8 color0[4]; // prelit u32 color0_32; diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 628f133f98..db211f3efa 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -909,17 +909,26 @@ void DrawEngineVulkan::DoFlush() { params.allowClear = framebufferManager_->UseBufferedRendering(); params.allowSeparateAlphaClear = false; params.provokeFlatFirst = true; + 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... // TODO: Probably should eventually refactor this and feed the vp size into SoftwareTransform directly (Unknown's idea). if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) { - gstate_c.vpWidth = gstate.getViewportXScale() * 2.0f; - gstate_c.vpHeight = gstate.getViewportYScale() * 2.0f; + ViewportAndScissor vpAndScissor; + ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(), + framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(), + framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(), + vpAndScissor); } 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/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 69ac5ee2cc..a7ade3555d 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -115,15 +115,18 @@ static int SetupVertexAttribs(VkVertexInputAttributeDescription attrs[], const D return count; } -static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsUV, bool needsColor1) { +static int SetupVertexAttribsPretransformed(VkVertexInputAttributeDescription attrs[], bool needsUV, bool needsColor1, bool needsFog) { int count = 0; - VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, 0, PspAttributeLocation::POSITION); + VertexAttribSetup(&attrs[count++], DEC_FLOAT_4, offsetof(TransformedVertex, pos), PspAttributeLocation::POSITION); if (needsUV) { - VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, 16, PspAttributeLocation::TEXCOORD); + VertexAttribSetup(&attrs[count++], DEC_FLOAT_3, offsetof(TransformedVertex, uv), PspAttributeLocation::TEXCOORD); } - VertexAttribSetup(&attrs[count++], DEC_U8_4, 28, PspAttributeLocation::COLOR0); + VertexAttribSetup(&attrs[count++], DEC_U8_4, offsetof(TransformedVertex, color0), PspAttributeLocation::COLOR0); if (needsColor1) { - VertexAttribSetup(&attrs[count++], DEC_U8_4, 32, PspAttributeLocation::COLOR1); + VertexAttribSetup(&attrs[count++], DEC_U8_4, offsetof(TransformedVertex, color1), PspAttributeLocation::COLOR1); + } + if (needsFog) { + VertexAttribSetup(&attrs[count++], DEC_FLOAT_1, offsetof(TransformedVertex, fog), PspAttributeLocation::NORMAL); } return count; } @@ -276,8 +279,9 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip } else { bool needsUV = vs->GetID().Bit(VS_BIT_DO_TEXTURE); bool needsColor1 = vs->GetID().Bit(VS_BIT_LMODE); - attributeCount = SetupVertexAttribsPretransformed(attrs, needsUV, needsColor1); - vertexStride = 36; + bool needsFog = vs->GetID().Bit(VS_BIT_ENABLE_FOG); + attributeCount = SetupVertexAttribsPretransformed(attrs, needsUV, needsColor1, needsFog); + vertexStride = (int)sizeof(TransformedVertex); } VkVertexInputBindingDescription ibd{};