Handle signed texture sampler channels in shaders

This commit is contained in:
izzy2lost
2026-04-08 02:34:53 -04:00
parent f6522b69ea
commit 4d995d1109
5 changed files with 87 additions and 25 deletions
-6
View File
@@ -701,12 +701,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 = 0;
size_t length, palette_length = 0;
+58 -10
View File
@@ -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)
@@ -195,6 +196,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
@@ -802,6 +805,31 @@ 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();
@@ -1173,7 +1201,10 @@ static MString* psh_convert(struct PixelShader *ps)
case PS_TEXTUREMODES_BUMPENVMAP:
assert(i >= 1);
if (ps->state->snorm_tex[ps->input_tex[i]]) {
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 (FIXME: May not always want signed textures in this case) */
mstring_append_fmt(vars, "vec2 dsdt%d = t%d.bg;\n",
i, ps->input_tex[i]);
@@ -1199,15 +1230,28 @@ 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);
@@ -1403,6 +1447,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"
+1
View File
@@ -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];
+28
View File
@@ -50,8 +50,36 @@ 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,
-9
View File
@@ -1703,15 +1703,6 @@ static void create_texture(PGRAPHState *pg, int texture_idx)
}
}
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");
VkFilter vk_min_filter, vk_mag_filter;
unsigned int mag_filter = GET_MASK(filter, NV_PGRAPH_TEXFILTER0_MAG);
assert(mag_filter < ARRAY_SIZE(pgraph_texture_mag_filter_vk_map));