From 98ff136f67bcf6d21bf70663e93c55e53d3853ce Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 26 Apr 2020 19:15:49 +1000 Subject: [PATCH] GPU: Round texture coordinates instead of flooring Fixes misaligned textures in some games such as Crash Bandicoot. Currently, because the vertex offset is not applied at >1x resolution scale, this will not work so it is disabled at >1x. --- src/core/gpu_hw_shadergen.cpp | 5 ++++- src/core/gpu_sw.cpp | 18 +++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index dc288d3e4..a20bdc2aa 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -118,6 +118,7 @@ void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss) else { ss << "#define HLSL 1\n"; + ss << "#define roundEven round\n"; ss << "#define CONSTANT static const\n"; ss << "#define VECTOR_EQ(a, b) (all((a) == (b)))\n"; ss << "#define VECTOR_NEQ(a, b) (any((a) != (b)))\n"; @@ -602,7 +603,9 @@ float4 SampleFromVRAM(uint4 texpage, uint2 icoord) texcol.rgb /= float3(ialpha, ialpha, ialpha); semitransparent = (texcol.a != 0.0); #else - float4 texcol = SampleFromVRAM(v_texpage, uint2(floor(v_tex0))); + // With the vertex offset applied at 1x resolution scale, we want to round the texture coordinates. + // Floor them otherwise, as it currently breaks when upscaling as the vertex offset is not applied. + float4 texcol = SampleFromVRAM(v_texpage, uint2((RESOLUTION_SCALE == 1u) ? roundEven(v_tex0) : floor(v_tex0))); if (VECTOR_EQ(texcol, TRANSPARENT_PIXEL_COLOR)) discard; diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp index d118d6722..dc39639ff 100644 --- a/src/core/gpu_sw.cpp +++ b/src/core/gpu_sw.cpp @@ -374,11 +374,11 @@ static constexpr bool IsTopLeftEdge(s32 ex, s32 ey) return (ey < 0 || (ey == 0 && ex < 0)); } -static constexpr u8 Interpolate(u8 v0, u8 v1, u8 v2, s32 w0, s32 w1, s32 w2, s32 ws) +static constexpr u8 Interpolate(u8 v0, u8 v1, u8 v2, s32 w0, s32 w1, s32 w2, s32 ws, s32 half_ws) { const s32 v = w0 * static_cast(static_cast(v0)) + w1 * static_cast(static_cast(v1)) + w2 * static_cast(static_cast(v2)); - const s32 vd = v / ws; + const s32 vd = (v + half_ws) / ws; return (vd < 0) ? 0 : ((vd > 0xFF) ? 0xFF : static_cast(vd)); } @@ -401,6 +401,7 @@ void GPU_SW::DrawTriangle(const SWVertex* v0, const SWVertex* v1, const SWVertex // Barycentric coordinates at minX/minY corner const s32 ws = orient2d(px0, py0, px1, py1, px2, py2); + const s32 half_ws = std::max((ws / 2) - 1, 0); if (ws == 0) return; @@ -451,12 +452,15 @@ void GPU_SW::DrawTriangle(const SWVertex* v0, const SWVertex* v1, const SWVertex const s32 b1 = row_w1; const s32 b2 = row_w2; - const u8 r = shading_enable ? Interpolate(v0->color_r, v1->color_r, v2->color_r, b0, b1, b2, ws) : v0->color_r; - const u8 g = shading_enable ? Interpolate(v0->color_g, v1->color_g, v2->color_g, b0, b1, b2, ws) : v0->color_g; - const u8 b = shading_enable ? Interpolate(v0->color_b, v1->color_b, v2->color_b, b0, b1, b2, ws) : v0->color_b; + const u8 r = + shading_enable ? Interpolate(v0->color_r, v1->color_r, v2->color_r, b0, b1, b2, ws, half_ws) : v0->color_r; + const u8 g = + shading_enable ? Interpolate(v0->color_g, v1->color_g, v2->color_g, b0, b1, b2, ws, half_ws) : v0->color_g; + const u8 b = + shading_enable ? Interpolate(v0->color_b, v1->color_b, v2->color_b, b0, b1, b2, ws, half_ws) : v0->color_b; - const u8 texcoord_x = Interpolate(v0->texcoord_x, v1->texcoord_x, v2->texcoord_x, b0, b1, b2, ws); - const u8 texcoord_y = Interpolate(v0->texcoord_y, v1->texcoord_y, v2->texcoord_y, b0, b1, b2, ws); + const u8 texcoord_x = Interpolate(v0->texcoord_x, v1->texcoord_x, v2->texcoord_x, b0, b1, b2, ws, half_ws); + const u8 texcoord_y = Interpolate(v0->texcoord_y, v1->texcoord_y, v2->texcoord_y, b0, b1, b2, ws, half_ws); ShadePixel( static_cast(x), static_cast(y), r, g, b, texcoord_x, texcoord_y);