From d17be812ea800f4f81355b154132a262545fed64 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 28 Jun 2025 00:08:46 -0700 Subject: [PATCH] nv2a/glsl: Unify dirty shader state check --- hw/xbox/nv2a/pgraph/gl/shaders.c | 78 +-------------------------- hw/xbox/nv2a/pgraph/glsl/shaders.c | 57 ++++++++++++++++++++ hw/xbox/nv2a/pgraph/glsl/shaders.h | 2 + hw/xbox/nv2a/pgraph/vk/shaders.c | 86 +++--------------------------- 4 files changed, 67 insertions(+), 156 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index 8cdf4f2bd9..c716ce7f6a 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -696,87 +696,13 @@ static void update_shader_uniforms(PGRAPHState *pg, ShaderBinding *binding) &psh_values, PshUniform__COUNT); } -static bool test_shaders_dirty(PGRAPHState *pg) -{ - #define CR_1(reg) CR_x(reg, 1) - #define CR_4(reg) CR_x(reg, 4) - #define CR_8(reg) CR_x(reg, 8) - #define CF(src, name) CF_x(typeof(src), (&src), name, 1) - #define CFA(src, name) CF_x(typeof(src[0]), src, name, ARRAY_SIZE(src)) - #define CNAME(name) reg_check__ ## name - #define CX_x__define(type, name, x) static type CNAME(name)[x]; - #define CR_x__define(reg, x) CX_x__define(uint32_t, reg, x) - #define CF_x__define(type, src, name, x) CX_x__define(type, name, x) - #define CR_x__check(reg, x) \ - for (int i = 0; i < x; i++) { if (pgraph_reg_r(pg, reg+i*4) != CNAME(reg)[i]) goto dirty; } - #define CF_x__check(type, src, name, x) \ - for (int i = 0; i < x; i++) { if (src[i] != CNAME(name)[i]) goto dirty; } - #define CR_x__update(reg, x) \ - for (int i = 0; i < x; i++) { CNAME(reg)[i] = pgraph_reg_r(pg, reg+i*4); } - #define CF_x__update(type, src, name, x) \ - for (int i = 0; i < x; i++) { CNAME(name)[i] = src[i]; } - - #define DIRTY_REGS \ - CR_1(NV_PGRAPH_COMBINECTL) \ - CR_1(NV_PGRAPH_SHADERCTL) \ - CR_1(NV_PGRAPH_SHADOWCTL) \ - CR_1(NV_PGRAPH_COMBINESPECFOG0) \ - CR_1(NV_PGRAPH_COMBINESPECFOG1) \ - CR_1(NV_PGRAPH_CONTROL_0) \ - CR_1(NV_PGRAPH_CONTROL_3) \ - CR_1(NV_PGRAPH_CSV0_C) \ - CR_1(NV_PGRAPH_CSV0_D) \ - CR_1(NV_PGRAPH_CSV1_A) \ - CR_1(NV_PGRAPH_CSV1_B) \ - CR_1(NV_PGRAPH_SETUPRASTER) \ - CR_1(NV_PGRAPH_SHADERPROG) \ - CR_1(NV_PGRAPH_ZCOMPRESSOCCLUDE) \ - CR_8(NV_PGRAPH_COMBINECOLORI0) \ - CR_8(NV_PGRAPH_COMBINECOLORO0) \ - CR_8(NV_PGRAPH_COMBINEALPHAI0) \ - CR_8(NV_PGRAPH_COMBINEALPHAO0) \ - CR_8(NV_PGRAPH_COMBINEFACTOR0) \ - CR_8(NV_PGRAPH_COMBINEFACTOR1) \ - CR_1(NV_PGRAPH_SHADERCLIPMODE) \ - CR_4(NV_PGRAPH_TEXCTL0_0) \ - CR_4(NV_PGRAPH_TEXFMT0) \ - CR_4(NV_PGRAPH_TEXFILTER0) \ - CR_8(NV_PGRAPH_WINDOWCLIPX0) \ - CR_8(NV_PGRAPH_WINDOWCLIPY0) \ - CF(pg->primitive_mode, primitive_mode) \ - CF(pg->surface_scale_factor, surface_scale_factor) \ - CF(pg->compressed_attrs, compressed_attrs) \ - CFA(pg->texture_matrix_enable, texture_matrix_enable) \ - CR_4(NV_PGRAPH_COLORKEYCOLOR0) - - #define CR_x(reg, x) CR_x__define(reg, x) - #define CF_x(type, src, name, x) CF_x__define(type, src, name, x) - DIRTY_REGS - #undef CR_x - #undef CF_x - - #define CR_x(reg, x) CR_x__check(reg, x) - #define CF_x(type, src, name, x) CF_x__check(type, src, name, x) - DIRTY_REGS - #undef CR_x - #undef CF_x - return false; - -dirty: - #define CR_x(reg, x) CR_x__update(reg, x) - #define CF_x(type, src, name, x) CF_x__update(type, src, name, x) - DIRTY_REGS - #undef CR_x - #undef CF_x - return true; -} - void pgraph_gl_bind_shaders(PGRAPHState *pg) { PGRAPHGLState *r = pg->gl_renderer_state; bool binding_changed = false; - if (r->shader_binding && !test_shaders_dirty(pg) && !pg->program_data_dirty) { + if (r->shader_binding && + !pgraph_check_shader_state_dirty(pg, &r->shader_binding->state)) { nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND_NOTDIRTY); goto update_uniforms; } diff --git a/hw/xbox/nv2a/pgraph/glsl/shaders.c b/hw/xbox/nv2a/pgraph/glsl/shaders.c index 9144dd19f2..8ed959f69d 100644 --- a/hw/xbox/nv2a/pgraph/glsl/shaders.c +++ b/hw/xbox/nv2a/pgraph/glsl/shaders.c @@ -34,3 +34,60 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) return state; } + +bool pgraph_check_shader_state_dirty(PGRAPHState *pg, const ShaderState *state) +{ + if (pg->program_data_dirty) { + return true; + } + + unsigned int regs[] = { + NV_PGRAPH_COMBINECTL, NV_PGRAPH_COMBINESPECFOG0, + NV_PGRAPH_COMBINESPECFOG1, NV_PGRAPH_CONTROL_0, + NV_PGRAPH_CONTROL_3, NV_PGRAPH_CSV0_C, + NV_PGRAPH_CSV0_D, NV_PGRAPH_CSV1_A, + NV_PGRAPH_CSV1_B, NV_PGRAPH_POINTSIZE, + NV_PGRAPH_SETUPRASTER, NV_PGRAPH_SHADERCLIPMODE, + NV_PGRAPH_SHADERCTL, NV_PGRAPH_SHADERPROG, + NV_PGRAPH_SHADOWCTL, NV_PGRAPH_ZCOMPRESSOCCLUDE, + }; + for (int i = 0; i < ARRAY_SIZE(regs); i++) { + if (pgraph_is_reg_dirty(pg, regs[i])) { + return true; + } + } + + int num_stages = pgraph_reg_r(pg, NV_PGRAPH_COMBINECTL) & 0xFF; + for (int i = 0; i < num_stages; i++) { + if (pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINEALPHAI0 + i * 4) || + pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINEALPHAO0 + i * 4) || + pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINECOLORI0 + i * 4) || + pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINECOLORO0 + i * 4)) { + return true; + } + } + + if (pg->uniform_attrs != state->vsh.uniform_attrs || + pg->swizzle_attrs != state->vsh.swizzle_attrs || + pg->compressed_attrs != state->vsh.compressed_attrs || + pg->primitive_mode != state->vsh.primitive_mode || + pg->surface_scale_factor != state->vsh.surface_scale_factor) { + return true; + } + + // Textures + for (int i = 0; i < 4; i++) { + if (pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXCTL0_0 + i * 4) || + pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXFILTER0 + i * 4) || + pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXFMT0 + i * 4)) { + return true; + } + + if (pg->texture_matrix_enable[i] != + state->vsh.fixed_function.texture_matrix_enable[i]) { + return true; + } + } + + return false; +} diff --git a/hw/xbox/nv2a/pgraph/glsl/shaders.h b/hw/xbox/nv2a/pgraph/glsl/shaders.h index c6642543c9..4712557f2e 100644 --- a/hw/xbox/nv2a/pgraph/glsl/shaders.h +++ b/hw/xbox/nv2a/pgraph/glsl/shaders.h @@ -33,4 +33,6 @@ typedef struct PGRAPHState PGRAPHState; ShaderState pgraph_get_shader_state(PGRAPHState *pg); +bool pgraph_check_shader_state_dirty(PGRAPHState *pg, const ShaderState *state); + #endif diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index 8eb90dd717..1be9f9445a 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -382,84 +382,6 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state) return snode; } -// Quickly check PGRAPH state to see if any registers have changed that -// necessitate a full shader state inspection. -static bool check_shaders_dirty(PGRAPHState *pg) -{ - PGRAPHVkState *r = pg->vk_renderer_state; - - if (!r->shader_binding) { - return true; - } - if (pg->program_data_dirty) { - return true; - } - - int num_stages = pgraph_reg_r(pg, NV_PGRAPH_COMBINECTL) & 0xFF; - for (int i = 0; i < num_stages; i++) { - if (pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINEALPHAI0 + i * 4) || - pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINEALPHAO0 + i * 4) || - pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINECOLORI0 + i * 4) || - pgraph_is_reg_dirty(pg, NV_PGRAPH_COMBINECOLORO0 + i * 4)) { - return true; - } - } - - unsigned int regs[] = { - NV_PGRAPH_COMBINECTL, - NV_PGRAPH_COMBINESPECFOG0, - NV_PGRAPH_COMBINESPECFOG1, - NV_PGRAPH_CONTROL_0, - NV_PGRAPH_CONTROL_3, - NV_PGRAPH_CSV0_C, - NV_PGRAPH_CSV0_D, - NV_PGRAPH_CSV1_A, - NV_PGRAPH_CSV1_B, - NV_PGRAPH_POINTSIZE, - NV_PGRAPH_SETUPRASTER, - NV_PGRAPH_SHADERCLIPMODE, - NV_PGRAPH_SHADERCTL, - NV_PGRAPH_SHADERPROG, - NV_PGRAPH_SHADOWCTL, - NV_PGRAPH_ZCOMPRESSOCCLUDE, - }; - for (int i = 0; i < ARRAY_SIZE(regs); i++) { - if (pgraph_is_reg_dirty(pg, regs[i])) { - return true; - } - } - - ShaderState *state = &r->shader_binding->state; - if (pg->uniform_attrs != state->vsh.uniform_attrs || - pg->swizzle_attrs != state->vsh.swizzle_attrs || - pg->compressed_attrs != state->vsh.compressed_attrs || - pg->primitive_mode != state->vsh.primitive_mode || - pg->surface_scale_factor != state->vsh.surface_scale_factor) { - return true; - } - - // Textures - for (int i = 0; i < 4; i++) { - if (pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXCTL0_0 + i * 4) || - pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXFILTER0 + i * 4) || - pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXFMT0 + i * 4)) { - return true; - } - - if (pg->vk_renderer_state->shader_binding->state.vsh - .is_fixed_function && - (pg->texture_matrix_enable[i] != - pg->vk_renderer_state->shader_binding->state.vsh.fixed_function - .texture_matrix_enable[i])) { - return true; - } - } - - nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND_NOTDIRTY); - - return false; -} - static void apply_uniform_updates(ShaderUniformLayout *layout, const UniformInfo *info, int *locs, void *values, size_t count) @@ -533,12 +455,16 @@ void pgraph_vk_bind_shaders(PGRAPHState *pg) r->shader_bindings_changed = false; - if (check_shaders_dirty(pg)) { + if (!r->shader_binding || + pgraph_check_shader_state_dirty(pg, &r->shader_binding->state)) { ShaderState new_state = pgraph_get_shader_state(pg); - if (!r->shader_binding || memcmp(&r->shader_binding->state, &new_state, sizeof(ShaderState))) { + if (!r->shader_binding || memcmp(&r->shader_binding->state, &new_state, + sizeof(ShaderState))) { r->shader_binding = gen_shaders(pg, &new_state); r->shader_bindings_changed = true; } + } else { + nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND_NOTDIRTY); } update_shader_uniforms(pg);