nv2a: Extract VshState from ShaderState

This commit is contained in:
Matt Borgerson
2025-06-28 00:08:45 -07:00
committed by mborgerson
parent 9d9c88f71d
commit c575b08b5f
10 changed files with 244 additions and 231 deletions

View File

@ -195,7 +195,7 @@ static void update_shader_constant_locations(ShaderBinding *binding)
binding->point_params_loc[i] = glGetUniformLocation(binding->gl_program, tmp);
}
if (binding->state.fixed_function) {
if (binding->state.vsh.is_fixed_function) {
binding->material_alpha_loc =
glGetUniformLocation(binding->gl_program, "material_alpha");
binding->specular_power_loc =
@ -230,14 +230,11 @@ static void generate_shaders(ShaderBinding *binding)
ShaderState *state = &binding->state;
/* Create an optional geometry shader and find primitive type */
GLenum gl_primitive_mode =
get_gl_primitive_mode(state->polygon_front_mode, state->primitive_mode);
MString* geometry_shader_code =
pgraph_gen_geom_glsl(state->polygon_front_mode,
state->polygon_back_mode,
state->primitive_mode,
state->smooth_shading,
false);
GLenum gl_primitive_mode = get_gl_primitive_mode(
state->vsh.polygon_front_mode, state->vsh.primitive_mode);
MString *geometry_shader_code = pgraph_gen_geom_glsl(
state->vsh.polygon_front_mode, state->vsh.polygon_back_mode,
state->vsh.primitive_mode, state->vsh.smooth_shading, false);
if (geometry_shader_code) {
const char* geometry_shader_code_str =
mstring_get_str(geometry_shader_code);
@ -250,7 +247,7 @@ static void generate_shaders(ShaderBinding *binding)
/* create the vertex shader */
MString *vertex_shader_code =
pgraph_gen_vsh_glsl(state, geometry_shader_code != NULL);
pgraph_gen_vsh_glsl(&state->vsh, geometry_shader_code != NULL);
GLuint vertex_shader = create_gl_shader(GL_VERTEX_SHADER,
mstring_get_str(vertex_shader_code),
"vertex shader");
@ -378,8 +375,9 @@ bool pgraph_gl_shader_load_from_memory(ShaderBinding *binding)
glUseProgram(gl_program);
binding->gl_program = gl_program;
binding->gl_primitive_mode = get_gl_primitive_mode(
binding->state.polygon_front_mode, binding->state.primitive_mode);
binding->gl_primitive_mode =
get_gl_primitive_mode(binding->state.vsh.polygon_front_mode,
binding->state.vsh.primitive_mode);
binding->initialized = true;
g_free(binding->program);
@ -814,7 +812,7 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
assert(0);
}
if (state->fixed_function) {
if (state->vsh.is_fixed_function) {
/* update lighting constants */
struct {
uint32_t* v;
@ -1047,7 +1045,7 @@ void pgraph_gl_bind_shaders(PGRAPHState *pg)
ShaderBinding *old_binding = r->shader_binding;
ShaderState state = pgraph_get_shader_state(pg);
assert(!state.vulkan);
assert(!state.vsh.vulkan);
NV2A_GL_DGROUP_BEGIN("%s (VP: %s FFP: %s)", __func__,
state.vertex_program ? "yes" : "no",

View File

@ -29,7 +29,7 @@ static void append_skinning_code(MString* str, bool mix,
const char* output, const char* input,
const char* matrix, const char* swizzle);
void pgraph_gen_vsh_ff_glsl(const ShaderState *state, MString *header,
void pgraph_gen_vsh_ff_glsl(const VshState *state, MString *header,
MString *body, MString *uniforms)
{
int i, j;
@ -119,7 +119,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
/* Skinning */
unsigned int count;
bool mix;
switch (state->skinning) {
switch (state->fixed_function.skinning) {
case SKINNING_OFF:
mix = false; count = 0; break;
case SKINNING_1WEIGHTS:
@ -139,7 +139,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
break;
}
mstring_append_fmt(body, "/* Skinning mode %d */\n",
state->skinning);
state->fixed_function.skinning);
append_skinning_code(body, mix, count, "vec4",
"tPosition", "position",
@ -149,7 +149,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
"invModelViewMat", "xyz");
/* Normalization */
if (state->normalization) {
if (state->fixed_function.normalization) {
mstring_append(body, "tNormal = normalize(tNormal);\n");
}
@ -163,7 +163,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
/* TODO: TexGen View Model missing! */
char c = "xyzw"[j];
char cSuffix = "STRQ"[j];
switch (state->texgen[i][j]) {
switch (state->fixed_function.texgen[i][j]) {
case TEXGEN_DISABLE:
mstring_append_fmt(body, "oT%d.%c = texture%d.%c;\n",
i, c, i, c);
@ -220,7 +220,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
/* Apply texture matrices */
for (i = 0; i < NV2A_MAX_TEXTURES; i++) {
if (state->texture_matrix_enable[i]) {
if (state->fixed_function.texture_matrix_enable[i]) {
mstring_append_fmt(body,
"oT%d = oT%d * texMat%d;\n",
i, i, i);
@ -228,7 +228,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
}
/* Lighting */
if (!state->lighting) {
if (!state->fixed_function.lighting) {
mstring_append(body, " oD0 = diffuse;\n");
mstring_append(body, " oD1 = specular;\n");
mstring_append(body, " oB0 = backDiffuse;\n");
@ -242,47 +242,47 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
static char alpha_source_specular[] = "specular.a";
static char alpha_source_material[] = "material_alpha";
const char *alpha_source = alpha_source_diffuse;
if (state->diffuse_src == MATERIAL_COLOR_SRC_MATERIAL) {
if (state->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_MATERIAL) {
mstring_append_fmt(uniforms, "%sfloat material_alpha;\n", u);
alpha_source = alpha_source_material;
} else if (state->diffuse_src == MATERIAL_COLOR_SRC_SPECULAR) {
} else if (state->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_SPECULAR) {
alpha_source = alpha_source_specular;
}
if (state->ambient_src == MATERIAL_COLOR_SRC_MATERIAL) {
if (state->fixed_function.ambient_src == MATERIAL_COLOR_SRC_MATERIAL) {
mstring_append_fmt(body, "oD0 = vec4(sceneAmbientColor, %s);\n", alpha_source);
} else if (state->ambient_src == MATERIAL_COLOR_SRC_DIFFUSE) {
} else if (state->fixed_function.ambient_src == MATERIAL_COLOR_SRC_DIFFUSE) {
mstring_append_fmt(body, "oD0 = vec4(diffuse.rgb, %s);\n", alpha_source);
} else if (state->ambient_src == MATERIAL_COLOR_SRC_SPECULAR) {
} else if (state->fixed_function.ambient_src == MATERIAL_COLOR_SRC_SPECULAR) {
mstring_append_fmt(body, "oD0 = vec4(specular.rgb, %s);\n", alpha_source);
}
mstring_append(body, "oD0.rgb *= materialEmissionColor.rgb;\n");
if (state->emission_src == MATERIAL_COLOR_SRC_MATERIAL) {
if (state->fixed_function.emission_src == MATERIAL_COLOR_SRC_MATERIAL) {
mstring_append(body, "oD0.rgb += sceneAmbientColor;\n");
} else if (state->emission_src == MATERIAL_COLOR_SRC_DIFFUSE) {
} else if (state->fixed_function.emission_src == MATERIAL_COLOR_SRC_DIFFUSE) {
mstring_append(body, "oD0.rgb += diffuse.rgb;\n");
} else if (state->emission_src == MATERIAL_COLOR_SRC_SPECULAR) {
} else if (state->fixed_function.emission_src == MATERIAL_COLOR_SRC_SPECULAR) {
mstring_append(body, "oD0.rgb += specular.rgb;\n");
}
mstring_append(body, "oD1 = vec4(0.0, 0.0, 0.0, specular.a);\n");
if (state->local_eye) {
if (state->fixed_function.local_eye) {
mstring_append(body,
"vec3 VPeye = normalize(eyePosition.xyz / eyePosition.w - tPosition.xyz / tPosition.w);\n"
);
}
for (i = 0; i < NV2A_MAX_LIGHTS; i++) {
if (state->light[i] == LIGHT_OFF) {
if (state->fixed_function.light[i] == LIGHT_OFF) {
continue;
}
mstring_append_fmt(body, "/* Light %d */ {\n", i);
if (state->light[i] == LIGHT_LOCAL
|| state->light[i] == LIGHT_SPOT) {
if (state->fixed_function.light[i] == LIGHT_LOCAL
|| state->fixed_function.light[i] == LIGHT_SPOT) {
mstring_append_fmt(uniforms,
"%svec3 lightLocalPosition%d;\n"
@ -301,11 +301,11 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
" float nDotVP = max(0.0, dot(tNormal, VP));\n"
" float nDotHV = max(0.0, dot(tNormal, halfVector));\n",
i, i, i, i, i,
state->local_eye ? "VPeye" : "vec3(0.0, 0.0, 0.0)"
state->fixed_function.local_eye ? "VPeye" : "vec3(0.0, 0.0, 0.0)"
);
}
switch(state->light[i]) {
switch(state->fixed_function.light[i]) {
case LIGHT_INFINITE:
/* lightLocalRange will be 1e+30 here */
@ -320,7 +320,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
" vec3 lightDirection = normalize(lightInfiniteDirection%d);\n"
" float nDotVP = max(0.0, dot(tNormal, lightDirection));\n",
i);
if (state->local_eye) {
if (state->fixed_function.local_eye) {
mstring_append(body,
" float nDotHV = max(0.0, dot(tNormal, normalize(lightDirection + VPeye)));\n"
);
@ -371,7 +371,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
mstring_append(body,
" oD0.xyz += lightAmbient;\n");
switch (state->diffuse_src) {
switch (state->fixed_function.diffuse_src) {
case MATERIAL_COLOR_SRC_MATERIAL:
mstring_append(body,
" oD0.xyz += lightDiffuse;\n");
@ -386,7 +386,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
break;
}
switch (state->specular_src) {
switch (state->fixed_function.specular_src) {
case MATERIAL_COLOR_SRC_MATERIAL:
mstring_append(body,
" oD1.xyz += lightSpecular;\n");
@ -415,7 +415,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
mstring_append(body, " oB1 = vec4(0.0, 0.0, 0.0, 1.0);\n");
} else {
if (!state->separate_specular) {
if (state->lighting) {
if (state->fixed_function.lighting) {
mstring_append(body,
" oD0.xyz += oD1.xyz;\n"
" oB0.xyz += oB1.xyz;\n"
@ -438,7 +438,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
if (state->fog_enable) {
/* From: https://www.opengl.org/registry/specs/NV/fog_distance.txt */
switch(state->foggen) {
switch(state->fixed_function.foggen) {
case FOGGEN_SPEC_ALPHA:
/* FIXME: Do we have to clamp here? */
mstring_append(body, " float fogDistance = clamp(specular.a, 0.0, 1.0);\n");
@ -449,7 +449,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
case FOGGEN_PLANAR:
case FOGGEN_ABS_PLANAR:
mstring_append(body, " float fogDistance = dot(fogPlane.xyz, tPosition.xyz) + fogPlane.w;\n");
if (state->foggen == FOGGEN_ABS_PLANAR) {
if (state->fixed_function.foggen == FOGGEN_ABS_PLANAR) {
mstring_append(body, " fogDistance = abs(fogDistance);\n");
}
break;
@ -464,7 +464,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
}
/* If skinning is off the composite matrix already includes the MV matrix */
if (state->skinning == SKINNING_OFF) {
if (state->fixed_function.skinning == SKINNING_OFF) {
mstring_append(body, " tPosition = position;\n");
}

View File

@ -25,7 +25,7 @@
#include "qemu/mstring.h"
#include "hw/xbox/nv2a/pgraph/shaders.h"
void pgraph_gen_vsh_ff_glsl(const ShaderState *state, MString *header,
void pgraph_gen_vsh_ff_glsl(const VshState *state, MString *header,
MString *body, MString *uniforms);
#endif

View File

@ -27,7 +27,7 @@
#include "vsh-prog.h"
#include <stdbool.h>
MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs)
MString *pgraph_gen_vsh_glsl(const VshState *state, bool prefix_outputs)
{
int i;
MString *output = mstring_new();
@ -158,23 +158,20 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs)
}
if (state->fixed_function) {
if (state->is_fixed_function) {
pgraph_gen_vsh_ff_glsl(state, header, body, uniforms);
} else if (state->vertex_program) {
pgraph_gen_vsh_prog_glsl(VSH_VERSION_XVS,
(uint32_t *)state->program_data,
state->program_length,
state->vulkan, header, body);
} else {
assert(false);
pgraph_gen_vsh_prog_glsl(VSH_VERSION_XVS,
(uint32_t *)state->programmable.program_data,
state->programmable.program_length,
state->vulkan, header, body);
}
/* Fog */
if (state->fog_enable) {
if (state->vertex_program) {
if (!state->is_fixed_function) {
/* FIXME: Does foggen do something here? Let's do some tracking..
*
* "RollerCoaster Tycoon" has

View File

@ -28,6 +28,6 @@
// FIXME: Move to struct
#define VSH_UBO_BINDING 0
MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs);
MString *pgraph_gen_vsh_glsl(const VshState *state, bool prefix_outputs);
#endif

View File

@ -67,15 +67,15 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg)
// We will hash it, so make sure any padding is zeroed
memset(&state, 0, sizeof(ShaderState));
state.surface_scale_factor = pg->surface_scale_factor;
state.vsh.surface_scale_factor = pg->surface_scale_factor;
state.compressed_attrs = pg->compressed_attrs;
state.uniform_attrs = pg->uniform_attrs;
state.swizzle_attrs = pg->swizzle_attrs;
state.vsh.compressed_attrs = pg->compressed_attrs;
state.vsh.uniform_attrs = pg->uniform_attrs;
state.vsh.swizzle_attrs = pg->swizzle_attrs;
/* register combiner stuff */
state.psh.window_clip_exclusive =
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) & NV_PGRAPH_SETUPRASTER_WINDOWCLIPTYPE;
state.psh.window_clip_exclusive = pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
NV_PGRAPH_SETUPRASTER_WINDOWCLIPTYPE;
state.psh.combiner_control = pgraph_reg_r(pg, NV_PGRAPH_COMBINECTL);
state.psh.shader_stage_program = pgraph_reg_r(pg, NV_PGRAPH_SHADERPROG);
state.psh.other_stage_input = pgraph_reg_r(pg, NV_PGRAPH_SHADERCTL);
@ -93,35 +93,41 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg)
state.psh.shadow_depth_func = (enum PshShadowDepthFunc)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_SHADOWCTL), NV_PGRAPH_SHADOWCTL_SHADOW_ZFUNC);
state.fixed_function = fixed_function;
state.specular_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_C),
NV_PGRAPH_CSV0_C_SPECULAR_ENABLE);
state.vsh.is_fixed_function = fixed_function;
state.vsh.specular_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_C),
NV_PGRAPH_CSV0_C_SPECULAR_ENABLE);
/* fixed function stuff */
if (fixed_function) {
state.skinning = (enum VshSkinning)GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D),
NV_PGRAPH_CSV0_D_SKIN);
state.lighting =
GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_LIGHTING);
state.normalization =
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C) & NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE;
state.vsh.fixed_function.skinning = (enum VshSkinning)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_D), NV_PGRAPH_CSV0_D_SKIN);
state.vsh.fixed_function.lighting = GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_LIGHTING);
state.vsh.fixed_function.normalization =
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C) &
NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE;
/* color material */
state.emission_src = (enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_EMISSION);
state.ambient_src = (enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_AMBIENT);
state.diffuse_src = (enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_DIFFUSE);
state.specular_src = (enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SPECULAR);
state.vsh.fixed_function.emission_src =
(enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_EMISSION);
state.vsh.fixed_function.ambient_src =
(enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_AMBIENT);
state.vsh.fixed_function.diffuse_src =
(enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_DIFFUSE);
state.vsh.fixed_function.specular_src =
(enum MaterialColorSource)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SPECULAR);
state.local_eye = GET_MASK(
state.vsh.fixed_function.local_eye = GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_LOCALEYE);
/* Texture matrices */
for (int i = 0; i < 4; i++) {
state.texture_matrix_enable[i] = pg->texture_matrix_enable[i];
state.vsh.fixed_function.texture_matrix_enable[i] =
pg->texture_matrix_enable[i];
}
/* Texgen */
@ -134,62 +140,62 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg)
(i % 2) ? NV_PGRAPH_CSV1_A_T1_R : NV_PGRAPH_CSV1_A_T0_R,
(i % 2) ? NV_PGRAPH_CSV1_A_T1_Q : NV_PGRAPH_CSV1_A_T0_Q
};
state.texgen[i][j] =
state.vsh.fixed_function.texgen[i][j] =
(enum VshTexgen)GET_MASK(pgraph_reg_r(pg, reg), masks[j]);
}
}
}
state.separate_specular = GET_MASK(
state.vsh.separate_specular = GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SEPARATE_SPECULAR);
state.ignore_specular_alpha = !GET_MASK(
state.vsh.ignore_specular_alpha = !GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR);
state.specular_power = pg->specular_power;
state.specular_power_back = pg->specular_power_back;
state.vsh.specular_power = pg->specular_power;
state.vsh.specular_power_back = pg->specular_power_back;
/* vertex program stuff */
state.vertex_program = vertex_program,
state.z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
state.vsh.z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE;
state.psh.z_perspective = state.z_perspective;
state.psh.z_perspective = state.vsh.z_perspective;
state.point_params_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D),
state.vsh.point_params_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D),
NV_PGRAPH_CSV0_D_POINTPARAMSENABLE);
state.point_size =
state.vsh.point_size =
GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_POINTSIZE), NV097_SET_POINT_SIZE_V) / 8.0f;
if (state.point_params_enable) {
if (state.vsh.point_params_enable) {
for (int i = 0; i < 8; i++) {
state.point_params[i] = pg->point_params[i];
state.vsh.point_params[i] = pg->point_params[i];
}
}
/* geometry shader stuff */
state.primitive_mode = (enum ShaderPrimitiveMode)pg->primitive_mode;
state.polygon_front_mode = (enum ShaderPolygonMode)GET_MASK(
state.vsh.primitive_mode = (enum ShaderPrimitiveMode)pg->primitive_mode;
state.vsh.polygon_front_mode = (enum ShaderPolygonMode)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER), NV_PGRAPH_SETUPRASTER_FRONTFACEMODE);
state.polygon_back_mode = (enum ShaderPolygonMode)GET_MASK(
state.vsh.polygon_back_mode = (enum ShaderPolygonMode)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER), NV_PGRAPH_SETUPRASTER_BACKFACEMODE);
state.smooth_shading = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
state.vsh.smooth_shading = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
NV_PGRAPH_CONTROL_3_SHADEMODE_SMOOTH;
state.psh.smooth_shading = state.smooth_shading;
state.psh.smooth_shading = state.vsh.smooth_shading;
state.psh.depth_clipping = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_ZCOMPRESSOCCLUDE),
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN) ==
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CULL;
state.program_length = 0;
if (vertex_program) {
// copy in vertex program tokens
state.vsh.programmable.program_length = 0;
for (int i = program_start; i < NV2A_MAX_TRANSFORM_PROGRAM_LENGTH;
i++) {
uint32_t *cur_token = (uint32_t *)&pg->program_data[i];
memcpy(&state.program_data[state.program_length], cur_token,
VSH_TOKEN_SIZE * sizeof(uint32_t));
state.program_length++;
memcpy(&state.vsh.programmable
.program_data[state.vsh.programmable.program_length],
cur_token, VSH_TOKEN_SIZE * sizeof(uint32_t));
state.vsh.programmable.program_length++;
if (vsh_get_field(cur_token, FLD_FINAL)) {
break;
@ -198,35 +204,40 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg)
}
/* Fog */
state.fog_enable =
state.vsh.fog_enable =
pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3) & NV_PGRAPH_CONTROL_3_FOGENABLE;
if (state.fog_enable) {
if (state.vsh.fog_enable) {
/*FIXME: Use CSV0_D? */
state.fog_mode = (enum VshFogMode)GET_MASK(
state.vsh.fog_mode = (enum VshFogMode)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3), NV_PGRAPH_CONTROL_3_FOG_MODE);
state.foggen = (enum VshFoggen)GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D),
NV_PGRAPH_CSV0_D_FOGGENMODE);
state.vsh.fixed_function.foggen = (enum VshFoggen)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_D), NV_PGRAPH_CSV0_D_FOGGENMODE);
} else {
/* FIXME: Do we still pass the fogmode? */
state.fog_mode = (enum VshFogMode)0;
state.foggen = (enum VshFoggen)0;
state.vsh.fog_mode = (enum VshFogMode)0;
state.vsh.fixed_function.foggen = (enum VshFoggen)0;
}
/* Lighting */
if (state.lighting) {
if (state.vsh.fixed_function.lighting) {
for (int i = 0; i < NV2A_MAX_LIGHTS; i++) {
state.light[i] = (enum VshLight)GET_MASK(
pgraph_reg_r(pg, NV_PGRAPH_CSV0_D), NV_PGRAPH_CSV0_D_LIGHT0 << (i * 2));
state.vsh.fixed_function.light[i] =
(enum VshLight)GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D),
NV_PGRAPH_CSV0_D_LIGHT0 << (i * 2));
}
}
/* Copy content of enabled combiner stages */
int num_stages = pgraph_reg_r(pg, NV_PGRAPH_COMBINECTL) & 0xFF;
for (int i = 0; i < num_stages; i++) {
state.psh.rgb_inputs[i] = pgraph_reg_r(pg, NV_PGRAPH_COMBINECOLORI0 + i * 4);
state.psh.rgb_outputs[i] = pgraph_reg_r(pg, NV_PGRAPH_COMBINECOLORO0 + i * 4);
state.psh.alpha_inputs[i] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEALPHAI0 + i * 4);
state.psh.alpha_outputs[i] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEALPHAO0 + i * 4);
state.psh.rgb_inputs[i] =
pgraph_reg_r(pg, NV_PGRAPH_COMBINECOLORI0 + i * 4);
state.psh.rgb_outputs[i] =
pgraph_reg_r(pg, NV_PGRAPH_COMBINECOLORO0 + i * 4);
state.psh.alpha_inputs[i] =
pgraph_reg_r(pg, NV_PGRAPH_COMBINEALPHAI0 + i * 4);
state.psh.alpha_outputs[i] =
pgraph_reg_r(pg, NV_PGRAPH_COMBINEALPHAO0 + i * 4);
// constant_0[i] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4);
// constant_1[i] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4);
}

View File

@ -22,91 +22,13 @@
#define HW_XBOX_NV2A_PGRAPH_SHADERS_H
#include <stdint.h>
#include "hw/xbox/nv2a/nv2a_regs.h"
#include "vsh.h"
#include "psh.h"
enum ShaderPrimitiveMode {
PRIM_TYPE_INVALID,
PRIM_TYPE_POINTS,
PRIM_TYPE_LINES,
PRIM_TYPE_LINE_LOOP,
PRIM_TYPE_LINE_STRIP,
PRIM_TYPE_TRIANGLES,
PRIM_TYPE_TRIANGLE_STRIP,
PRIM_TYPE_TRIANGLE_FAN,
PRIM_TYPE_QUADS,
PRIM_TYPE_QUAD_STRIP,
PRIM_TYPE_POLYGON,
};
enum ShaderPolygonMode {
POLY_MODE_FILL,
POLY_MODE_POINT,
POLY_MODE_LINE,
};
enum MaterialColorSource {
MATERIAL_COLOR_SRC_MATERIAL,
MATERIAL_COLOR_SRC_DIFFUSE,
MATERIAL_COLOR_SRC_SPECULAR,
};
typedef struct ShaderState {
bool vulkan;
bool use_push_constants_for_uniform_attrs;
unsigned int surface_scale_factor;
VshState vsh;
PshState psh;
uint16_t compressed_attrs;
uint16_t uniform_attrs;
uint16_t swizzle_attrs;
bool texture_matrix_enable[4];
enum VshTexgen texgen[4][4];
bool fog_enable;
enum VshFoggen foggen;
enum VshFogMode fog_mode;
enum VshSkinning skinning;
bool normalization;
enum MaterialColorSource emission_src;
enum MaterialColorSource ambient_src;
enum MaterialColorSource diffuse_src;
enum MaterialColorSource specular_src;
bool separate_specular;
bool ignore_specular_alpha;
bool local_eye;
float specular_power;
float specular_power_back;
bool lighting;
enum VshLight light[NV2A_MAX_LIGHTS];
bool fixed_function;
bool specular_enable;
/* vertex program */
bool vertex_program;
uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
int program_length;
bool z_perspective;
/* primitive format for geometry shader */
enum ShaderPolygonMode polygon_front_mode;
enum ShaderPolygonMode polygon_back_mode;
enum ShaderPrimitiveMode primitive_mode;
bool point_params_enable;
float point_size;
float point_params[8];
bool smooth_shading;
} ShaderState;
typedef struct PGRAPHState PGRAPHState;

View File

@ -51,8 +51,8 @@ static VkPrimitiveTopology get_primitive_topology(PGRAPHState *pg)
{
PGRAPHVkState *r = pg->vk_renderer_state;
int polygon_mode = r->shader_binding->state.polygon_front_mode;
int primitive_mode = r->shader_binding->state.primitive_mode;
int polygon_mode = r->shader_binding->state.vsh.polygon_front_mode;
int primitive_mode = r->shader_binding->state.vsh.primitive_mode;
if (polygon_mode == POLY_MODE_POINT) {
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
@ -816,7 +816,7 @@ static void create_pipeline(PGRAPHState *pg)
.depthClampEnable = VK_TRUE,
.rasterizerDiscardEnable = VK_FALSE,
.polygonMode = pgraph_polygon_mode_vk_map[r->shader_binding->state
.polygon_front_mode],
.vsh.polygon_front_mode],
.lineWidth = 1.0f,
.frontFace = (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
NV_PGRAPH_SETUPRASTER_FRONTFACE) ?
@ -951,11 +951,11 @@ static void create_pipeline(PGRAPHState *pg)
int num_dynamic_states = 2;
snode->has_dynamic_line_width =
(r->enabled_physical_device_features.wideLines == VK_TRUE)
&& (r->shader_binding->state.polygon_front_mode == POLY_MODE_LINE ||
r->shader_binding->state.primitive_mode == PRIM_TYPE_LINES ||
r->shader_binding->state.primitive_mode == PRIM_TYPE_LINE_LOOP ||
r->shader_binding->state.primitive_mode == PRIM_TYPE_LINE_STRIP);
(r->enabled_physical_device_features.wideLines == VK_TRUE) &&
(r->shader_binding->state.vsh.polygon_front_mode == POLY_MODE_LINE ||
r->shader_binding->state.vsh.primitive_mode == PRIM_TYPE_LINES ||
r->shader_binding->state.vsh.primitive_mode == PRIM_TYPE_LINE_LOOP ||
r->shader_binding->state.vsh.primitive_mode == PRIM_TYPE_LINE_STRIP);
if (snode->has_dynamic_line_width) {
dynamic_states[num_dynamic_states++] = VK_DYNAMIC_STATE_LINE_WIDTH;
}
@ -1012,9 +1012,9 @@ static void create_pipeline(PGRAPHState *pg)
};
VkPushConstantRange push_constant_range;
if (r->shader_binding->state.use_push_constants_for_uniform_attrs) {
if (r->shader_binding->state.vsh.use_push_constants_for_uniform_attrs) {
int num_uniform_attributes =
__builtin_popcount(r->shader_binding->state.uniform_attrs);
__builtin_popcount(r->shader_binding->state.vsh.uniform_attrs);
if (num_uniform_attributes) {
push_constant_range = (VkPushConstantRange){
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
@ -1067,7 +1067,7 @@ static void push_vertex_attr_values(PGRAPHState *pg)
{
PGRAPHVkState *r = pg->vk_renderer_state;
if (!r->shader_binding->state.use_push_constants_for_uniform_attrs) {
if (!r->shader_binding->state.vsh.use_push_constants_for_uniform_attrs) {
return;
}
@ -1076,8 +1076,8 @@ static void push_vertex_attr_values(PGRAPHState *pg)
float values[NV2A_VERTEXSHADER_ATTRIBUTES][4];
int num_uniform_attrs = 0;
pgraph_get_inline_values(pg, r->shader_binding->state.uniform_attrs, values,
&num_uniform_attrs);
pgraph_get_inline_values(pg, r->shader_binding->state.vsh.uniform_attrs,
values, &num_uniform_attrs);
if (num_uniform_attrs > 0) {
vkCmdPushConstants(r->command_buffer, r->pipeline_binding->layout,

View File

@ -405,8 +405,8 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state)
setlocale(LC_NUMERIC, "C");
MString *geometry_shader_code = pgraph_gen_geom_glsl(
state->polygon_front_mode, state->polygon_back_mode,
state->primitive_mode, state->smooth_shading, true);
state->vsh.polygon_front_mode, state->vsh.polygon_back_mode,
state->vsh.primitive_mode, state->vsh.smooth_shading, true);
if (geometry_shader_code) {
NV2A_VK_DPRINTF("geometry shader: \n%s",
mstring_get_str(geometry_shader_code));
@ -419,7 +419,7 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state)
}
MString *vertex_shader_code =
pgraph_gen_vsh_glsl(state, geometry_shader_code != NULL);
pgraph_gen_vsh_glsl(&state->vsh, geometry_shader_code != NULL);
NV2A_VK_DPRINTF("vertex shader: \n%s",
mstring_get_str(vertex_shader_code));
snode->vertex = pgraph_vk_create_shader_module_from_glsl(
@ -453,7 +453,7 @@ static void update_uniform_attr_values(PGRAPHState *pg, ShaderBinding *binding)
float values[NV2A_VERTEXSHADER_ATTRIBUTES][4];
int num_uniform_attrs = 0;
pgraph_get_inline_values(pg, binding->state.uniform_attrs, values,
pgraph_get_inline_values(pg, binding->state.vsh.uniform_attrs, values,
&num_uniform_attrs);
if (num_uniform_attrs > 0) {
@ -463,9 +463,7 @@ static void update_uniform_attr_values(PGRAPHState *pg, ShaderBinding *binding)
}
// FIXME: Move to common
static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
bool binding_changed, bool vertex_program,
bool fixed_function)
static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding)
{
ShaderState *state = &binding->state;
@ -548,7 +546,10 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
if (loc != -1) {
assert(pg->vk_renderer_state->texture_bindings[i] != NULL);
float scale = pg->vk_renderer_state->texture_bindings[i]->key.scale;
BasicColorFormatInfo f_basic = kelvin_color_format_info_map[pg->vk_renderer_state->texture_bindings[i]->key.state.color_format];
BasicColorFormatInfo f_basic =
kelvin_color_format_info_map[pg->vk_renderer_state
->texture_bindings[i]
->key.state.color_format];
if (!f_basic.linear) {
scale = 1.0;
}
@ -592,7 +593,7 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
assert(0);
}
if (fixed_function) {
if (binding->state.vsh.is_fixed_function) {
/* update lighting constants */
struct {
uint32_t *v;
@ -733,7 +734,8 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
pg->material_alpha);
}
if (!state->use_push_constants_for_uniform_attrs && state->uniform_attrs) {
if (!state->vsh.use_push_constants_for_uniform_attrs &&
state->vsh.uniform_attrs) {
update_uniform_attr_values(pg, binding);
}
}
@ -786,22 +788,29 @@ static bool check_shaders_dirty(PGRAPHState *pg)
}
ShaderState *state = &r->shader_binding->state;
if (pg->uniform_attrs != state->uniform_attrs ||
pg->swizzle_attrs != state->swizzle_attrs ||
pg->compressed_attrs != state->compressed_attrs ||
pg->primitive_mode != state->primitive_mode ||
pg->surface_scale_factor != state->surface_scale_factor) {
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 (pg->texture_matrix_enable[i] != pg->vk_renderer_state->shader_binding->state.texture_matrix_enable[i] ||
pgraph_is_reg_dirty(pg, NV_PGRAPH_TEXCTL0_0 + i * 4) ||
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);
@ -821,11 +830,11 @@ void pgraph_vk_bind_shaders(PGRAPHState *pg)
ShaderState new_state;
memset(&new_state, 0, sizeof(ShaderState));
new_state = pgraph_get_shader_state(pg);
new_state.vulkan = true;
new_state.psh.vulkan = true;
new_state.use_push_constants_for_uniform_attrs =
new_state.vsh.vulkan = true;
new_state.vsh.use_push_constants_for_uniform_attrs =
(r->device_props.limits.maxPushConstantsSize >=
MAX_UNIFORM_ATTR_VALUES_SIZE);
new_state.psh.vulkan = true;
if (!r->shader_binding || memcmp(&r->shader_binding->state, &new_state, sizeof(ShaderState))) {
r->shader_binding = gen_shaders(pg, &new_state);
@ -849,9 +858,7 @@ void pgraph_vk_update_shader_uniforms(PGRAPHState *pg)
ShaderBinding *binding = r->shader_binding;
ShaderUniformLayout *layouts[] = { &binding->vertex->uniforms,
&binding->fragment->uniforms };
shader_update_constants(pg, r->shader_binding, true,
r->shader_binding->state.vertex_program,
r->shader_binding->state.fixed_function);
shader_update_constants(pg, r->shader_binding);
for (int i = 0; i < ARRAY_SIZE(layouts); i++) {
uint64_t hash = fast_hash(layouts[i]->allocation, layouts[i]->total_size);

View File

@ -20,8 +20,8 @@
#ifndef HW_NV2A_VSH_H
#define HW_NV2A_VSH_H
#include <stdbool.h>
#include "qemu/mstring.h"
#include "qemu/osdep.h"
#include "hw/xbox/nv2a/nv2a_regs.h"
enum VshLight {
LIGHT_OFF,
@ -128,4 +128,82 @@ typedef enum {
uint8_t vsh_get_field(const uint32_t *shader_token, VshFieldName field_name);
enum ShaderPrimitiveMode {
PRIM_TYPE_INVALID,
PRIM_TYPE_POINTS,
PRIM_TYPE_LINES,
PRIM_TYPE_LINE_LOOP,
PRIM_TYPE_LINE_STRIP,
PRIM_TYPE_TRIANGLES,
PRIM_TYPE_TRIANGLE_STRIP,
PRIM_TYPE_TRIANGLE_FAN,
PRIM_TYPE_QUADS,
PRIM_TYPE_QUAD_STRIP,
PRIM_TYPE_POLYGON,
};
enum ShaderPolygonMode {
POLY_MODE_FILL,
POLY_MODE_POINT,
POLY_MODE_LINE,
};
enum MaterialColorSource {
MATERIAL_COLOR_SRC_MATERIAL,
MATERIAL_COLOR_SRC_DIFFUSE,
MATERIAL_COLOR_SRC_SPECULAR,
};
typedef struct {
bool vulkan;
bool use_push_constants_for_uniform_attrs;
unsigned int surface_scale_factor; // FIXME: Remove
uint16_t compressed_attrs;
uint16_t uniform_attrs;
uint16_t swizzle_attrs;
/* primitive format for geometry shader */
enum ShaderPolygonMode polygon_front_mode;
enum ShaderPolygonMode polygon_back_mode;
enum ShaderPrimitiveMode primitive_mode;
bool is_fixed_function;
struct {
bool normalization;
bool texture_matrix_enable[4];
enum VshTexgen texgen[4][4];
enum VshFoggen foggen;
enum VshSkinning skinning;
bool lighting;
enum VshLight light[NV2A_MAX_LIGHTS];
enum MaterialColorSource emission_src;
enum MaterialColorSource ambient_src;
enum MaterialColorSource diffuse_src;
enum MaterialColorSource specular_src;
bool local_eye;
} fixed_function;
struct {
uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH]
[VSH_TOKEN_SIZE];
int program_length;
} programmable;
bool fog_enable;
enum VshFogMode fog_mode;
bool specular_enable;
bool separate_specular;
bool ignore_specular_alpha;
float specular_power;
float specular_power_back;
bool z_perspective;
bool point_params_enable;
float point_size;
float point_params[8];
bool smooth_shading;
} VshState;
#endif