mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Restore signed texture channel handling in fragment shaders
Re-applies the fix from 0f623fe906 that was lost in the sloppy-stuff mega-commit. The RSIGNED/GSIGNED/BSIGNED/ASIGNED bits in TEXFILTER0 tell the hardware to interpret each sampled texture channel as a signed value (-1..1). Without this, bump-mapped and environment-mapped surfaces render with incorrect channel values, causing visual artifacts in games that use G8B8/R6G5B5 bump map textures with the signed filter flags set. Changes: - texture.h: add PgraphTextureSignedChannel enum and pgraph_get_texture_signed_component_mask_from_filter() - psh.h: add tex_signed[4] to PshState - psh.c: populate tex_signed from filter register, add apply_signed_texture_remap(), update BUMPENVMAP/BUMPENVMAP_LUM cases to check per-channel signed flags, apply remap after sampling - gl/texture.c: remove NV2A_UNIMPLEMENTED stubs for SIGNED flags (handled in shader now, same as VK path) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
d726dbc780
commit
ee2fb9a94b
@@ -532,12 +532,6 @@ void pgraph_gl_bind_textures(NV2AState *d)
|
||||
1 << (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_TEXCTL0_0 + i*4),
|
||||
NV_PGRAPH_TEXCTL0_0_MAX_ANISOTROPY));
|
||||
|
||||
/* Check for unsupported features */
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_ASIGNED) NV2A_UNIMPLEMENTED("NV_PGRAPH_TEXFILTER0_ASIGNED");
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_RSIGNED) NV2A_UNIMPLEMENTED("NV_PGRAPH_TEXFILTER0_RSIGNED");
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_GSIGNED) NV2A_UNIMPLEMENTED("NV_PGRAPH_TEXFILTER0_GSIGNED");
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_BSIGNED) NV2A_UNIMPLEMENTED("NV_PGRAPH_TEXFILTER0_BSIGNED");
|
||||
|
||||
TextureShape state = pgraph_get_texture_shape(pg, i);
|
||||
hwaddr texture_vram_offset, palette_vram_offset;
|
||||
size_t length, palette_length;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xbox/nv2a/debug.h"
|
||||
#include "hw/xbox/nv2a/pgraph/pgraph.h"
|
||||
#include "hw/xbox/nv2a/pgraph/texture.h"
|
||||
#include "psh.h"
|
||||
|
||||
DEF_UNIFORM_INFO_ARR(PshUniform, PSH_UNIFORM_DECL_X)
|
||||
@@ -186,6 +187,8 @@ void pgraph_glsl_set_psh_state(PGRAPHState *pg, PshState *state)
|
||||
state->shadow_map[i] = f.depth;
|
||||
|
||||
uint32_t filter = pgraph_reg_r(pg, NV_PGRAPH_TEXFILTER0 + i * 4);
|
||||
state->tex_signed[i] =
|
||||
pgraph_get_texture_signed_component_mask_from_filter(filter);
|
||||
unsigned int min_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MIN);
|
||||
enum ConvolutionFilter kernel = CONVOLUTION_FILTER_DISABLED;
|
||||
/* FIXME: We do not distinguish between min and mag when
|
||||
@@ -793,6 +796,26 @@ static void define_colorkey_comparator(MString *preflight)
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
static bool texture_channels_are_signed(const struct PixelShader *ps, int tex,
|
||||
uint8_t mask)
|
||||
{
|
||||
return (ps->state->tex_signed[tex] & mask) == mask;
|
||||
}
|
||||
|
||||
static void apply_signed_texture_remap(const struct PixelShader *ps,
|
||||
MString *vars, int tex)
|
||||
{
|
||||
uint8_t mask = ps->state->tex_signed[tex];
|
||||
if (mask & PGRAPH_TEXTURE_SIGNED_R)
|
||||
mstring_append_fmt(vars, "t%d.r = sign3(t%d.r);\n", tex, tex);
|
||||
if (mask & PGRAPH_TEXTURE_SIGNED_G)
|
||||
mstring_append_fmt(vars, "t%d.g = sign3(t%d.g);\n", tex, tex);
|
||||
if (mask & PGRAPH_TEXTURE_SIGNED_B)
|
||||
mstring_append_fmt(vars, "t%d.b = sign3(t%d.b);\n", tex, tex);
|
||||
if (mask & PGRAPH_TEXTURE_SIGNED_A)
|
||||
mstring_append_fmt(vars, "t%d.a = sign3(t%d.a);\n", tex, tex);
|
||||
}
|
||||
|
||||
static MString* psh_convert(struct PixelShader *ps)
|
||||
{
|
||||
MString *preflight = mstring_new();
|
||||
@@ -1164,8 +1187,11 @@ static MString* psh_convert(struct PixelShader *ps)
|
||||
case PS_TEXTUREMODES_BUMPENVMAP:
|
||||
assert(i >= 1);
|
||||
|
||||
if (ps->state->snorm_tex[ps->input_tex[i]]) {
|
||||
/* Input color channels already signed (FIXME: May not always want signed textures in this case) */
|
||||
if (ps->state->snorm_tex[ps->input_tex[i]] ||
|
||||
texture_channels_are_signed(
|
||||
ps, ps->input_tex[i],
|
||||
PGRAPH_TEXTURE_SIGNED_G | PGRAPH_TEXTURE_SIGNED_B)) {
|
||||
/* Input color channels already signed */
|
||||
mstring_append_fmt(vars, "vec2 dsdt%d = t%d.bg;\n",
|
||||
i, ps->input_tex[i]);
|
||||
} else {
|
||||
@@ -1190,15 +1216,27 @@ static MString* psh_convert(struct PixelShader *ps)
|
||||
case PS_TEXTUREMODES_BUMPENVMAP_LUM:
|
||||
assert(i >= 1);
|
||||
|
||||
if (ps->state->snorm_tex[ps->input_tex[i]]) {
|
||||
/* Input color channels already signed (FIXME: May not always want signed textures in this case) */
|
||||
mstring_append_fmt(vars, "vec3 dsdtl%d = vec3(t%d.bg, sign3_to_0_to_1(t%d.r));\n",
|
||||
i, ps->input_tex[i], ps->input_tex[i]);
|
||||
} else {
|
||||
/* Convert to signed (FIXME: loss of accuracy due to filtering/interpolation) */
|
||||
mstring_append_fmt(vars, "vec3 dsdtl%d = vec3(sign3(t%d.b), sign3(t%d.g), t%d.r);\n",
|
||||
i, ps->input_tex[i], ps->input_tex[i], ps->input_tex[i]);
|
||||
}
|
||||
{
|
||||
bool bg_signed =
|
||||
ps->state->snorm_tex[ps->input_tex[i]] ||
|
||||
texture_channels_are_signed(
|
||||
ps, ps->input_tex[i],
|
||||
PGRAPH_TEXTURE_SIGNED_G | PGRAPH_TEXTURE_SIGNED_B);
|
||||
bool r_signed =
|
||||
ps->state->snorm_tex[ps->input_tex[i]] ||
|
||||
texture_channels_are_signed(
|
||||
ps, ps->input_tex[i], PGRAPH_TEXTURE_SIGNED_R);
|
||||
g_autofree gchar *b_expr = g_strdup_printf(
|
||||
bg_signed ? "t%d.b" : "sign3(t%d.b)", ps->input_tex[i]);
|
||||
g_autofree gchar *g_expr = g_strdup_printf(
|
||||
bg_signed ? "t%d.g" : "sign3(t%d.g)", ps->input_tex[i]);
|
||||
g_autofree gchar *r_expr = g_strdup_printf(
|
||||
r_signed ? "sign3_to_0_to_1(t%d.r)" : "t%d.r",
|
||||
ps->input_tex[i]);
|
||||
mstring_append_fmt(vars,
|
||||
"vec3 dsdtl%d = vec3(%s, %s, %s);\n", i,
|
||||
b_expr, g_expr, r_expr);
|
||||
}
|
||||
|
||||
mstring_append_fmt(vars, "dsdtl%d.st = bumpMat[%d] * dsdtl%d.st;\n",
|
||||
i, i, i);
|
||||
@@ -1394,6 +1432,10 @@ static MString* psh_convert(struct PixelShader *ps)
|
||||
mstring_append(vars, "}\n");
|
||||
}
|
||||
|
||||
if (!ps->state->shadow_map[i] && !ps->state->tex_x8y24[i]) {
|
||||
apply_signed_texture_remap(ps, vars, i);
|
||||
}
|
||||
|
||||
if (ps->state->rect_tex[i]) {
|
||||
mstring_append_fmt(preflight,
|
||||
"vec2 norm%d(vec2 coord) {\n"
|
||||
|
||||
@@ -47,6 +47,7 @@ typedef struct PshState {
|
||||
bool point_sprite;
|
||||
bool rect_tex[4];
|
||||
bool snorm_tex[4];
|
||||
uint8_t tex_signed[4];
|
||||
bool compare_mode[4][4];
|
||||
bool alphakill[4];
|
||||
int colorkey_mode[4];
|
||||
|
||||
@@ -50,8 +50,26 @@ typedef struct BasicColorFormatInfo {
|
||||
bool depth;
|
||||
} BasicColorFormatInfo;
|
||||
|
||||
enum PgraphTextureSignedChannel {
|
||||
PGRAPH_TEXTURE_SIGNED_R = 1 << 0,
|
||||
PGRAPH_TEXTURE_SIGNED_G = 1 << 1,
|
||||
PGRAPH_TEXTURE_SIGNED_B = 1 << 2,
|
||||
PGRAPH_TEXTURE_SIGNED_A = 1 << 3,
|
||||
};
|
||||
|
||||
extern const BasicColorFormatInfo kelvin_color_format_info_map[66];
|
||||
|
||||
static inline uint8_t
|
||||
pgraph_get_texture_signed_component_mask_from_filter(uint32_t filter)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_RSIGNED) mask |= PGRAPH_TEXTURE_SIGNED_R;
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_GSIGNED) mask |= PGRAPH_TEXTURE_SIGNED_G;
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_BSIGNED) mask |= PGRAPH_TEXTURE_SIGNED_B;
|
||||
if (filter & NV_PGRAPH_TEXFILTER0_ASIGNED) mask |= PGRAPH_TEXTURE_SIGNED_A;
|
||||
return mask;
|
||||
}
|
||||
|
||||
uint8_t *pgraph_convert_texture_data(const TextureShape s, const uint8_t *data,
|
||||
const uint8_t *palette_data,
|
||||
unsigned int width, unsigned int height,
|
||||
|
||||
Reference in New Issue
Block a user