From 73dcb0f1d60d8499b87f0af08a7c7d501fe294e8 Mon Sep 17 00:00:00 2001 From: coldhex Date: Mon, 5 May 2025 21:56:31 +0300 Subject: [PATCH] nv2a: Use trunc in vertex rounding instead of floor Xbox seems to truncate instead of flooring, which can be inferred from interpolated depth buffer values. --- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 2 +- hw/xbox/nv2a/pgraph/glsl/vsh-prog.c | 6 ++---- hw/xbox/nv2a/pgraph/glsl/vsh.c | 7 +++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 02b1a8fda8..8cee360997 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -474,7 +474,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz " oPos.w = clampAwayZeroInf(oPos.w);\n" " oPos.xy /= oPos.w;\n" " oPos.xy += c[" stringify(NV_IGRAPH_XF_XFCTX_VPOFF) "].xy;\n" - " oPos.xy = floor(oPos.xy * 16.0f) / 16.0f;\n" + " oPos.xy = roundScreenCoords(oPos.xy);\n" " oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n" " oPos.xy *= oPos.w;\n" ); diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index e26d0c0304..3068684d32 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -822,11 +822,9 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, mstring_append(body, /* The shaders leave the result in screen space, while OpenGL expects it - * in clip space. Xbox NV2A rasterizer appears to have 4 bit precision - * fixed point fractional part and to convert floating point coordinates - * by flooring. + * in clip space. */ - " oPos.xy = floor(oPos.xy * 16.0f) / 16.0f;\n" + " oPos.xy = roundScreenCoords(oPos.xy);\n" " oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n" " oPos.z = oPos.z / clipRange.y;\n" diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index f3c5dd5a43..b6b7045186 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -85,6 +85,13 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) "\n" "vec4 NaNToOne(vec4 src) {\n" " return mix(src, vec4(1.0), isnan(src));\n" + "}\n" + "\n" + // Xbox NV2A rasterizer appears to have 4 bit precision fixed-point + // fractional part and to convert floating-point coordinates by + // by truncating (not flooring). + "vec2 roundScreenCoords(vec2 pos) {\n" + " return trunc(pos * 16.0f) / 16.0f;\n" "}\n"); pgraph_get_glsl_vtx_header(header, state->vulkan, state->smooth_shading,