diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 0475986ef1..f50f592b10 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -34,6 +34,8 @@ #include "hw/xbox/nv2a/pgraph/surface.h" #include "hw/xbox/nv2a/pgraph/texture.h" #include "hw/xbox/nv2a/pgraph/shaders.h" +#include "hw/xbox/nv2a/pgraph/glsl/vsh.h" +#include "hw/xbox/nv2a/pgraph/glsl/psh.h" #include "gloffscreen.h" #include "constants.h" @@ -96,39 +98,9 @@ typedef struct ShaderBinding { GLuint gl_program; GLenum gl_primitive_mode; - uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; - struct { - struct { - GLint alpha_ref; - GLint bump_mat[NV2A_MAX_TEXTURES]; - GLint bump_offset[NV2A_MAX_TEXTURES]; - GLint bump_scale[NV2A_MAX_TEXTURES]; - GLint clip_range; - GLint clip_region[8]; - GLint color_key[4]; - GLint color_key_mask[4]; - GLint depth_offset; - GLint fog_color; - GLint psh_constant[9][2]; - GLint surface_size; - GLint tex_scale[NV2A_MAX_TEXTURES]; - } psh; - - struct { - GLint fog_param; - GLint light_infinite_direction[NV2A_MAX_LIGHTS]; - GLint light_infinite_half_vector[NV2A_MAX_LIGHTS]; - GLint light_local_attenuation[NV2A_MAX_LIGHTS]; - GLint light_local_position[NV2A_MAX_LIGHTS]; - GLint ltc1[NV2A_LTC1_COUNT]; - GLint ltctxa[NV2A_LTCTXA_COUNT]; - GLint ltctxb[NV2A_LTCTXB_COUNT]; - GLint material_alpha; - GLint point_params[8]; - GLint vsh_constant[NV2A_VERTEXSHADER_CONSTANTS]; - int specular_power; - } vsh; + PshUniformLocs psh; + VshUniformLocs vsh; } uniform_locs; } ShaderBinding; diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index 080ee48817..9c162b93b2 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -115,112 +115,22 @@ static void update_shader_constant_locations(ShaderBinding *binding) } } - /* lookup fragment shader uniforms */ - for (int i = 0; i < 9; i++) { - for (int j = 0; j < 2; j++) { - snprintf(tmp, sizeof(tmp), "c%d_%d", j, i); - binding->uniform_locs.psh.psh_constant[i][j] = - glGetUniformLocation(binding->gl_program, tmp); + for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.vsh); i++) { + const char *name = VshUniformInfo[i].name; + if (VshUniformInfo[i].count > 1) { + snprintf(tmp, sizeof(tmp), "%s[0]", name); + name = tmp; } - } - binding->uniform_locs.psh.alpha_ref = - glGetUniformLocation(binding->gl_program, "alphaRef"); - - for (int i = 1; i < NV2A_MAX_TEXTURES; i++) { - snprintf(tmp, sizeof(tmp), "bumpMat%d", i); - binding->uniform_locs.psh.bump_mat[i] = - glGetUniformLocation(binding->gl_program, tmp); - snprintf(tmp, sizeof(tmp), "bumpScale%d", i); - binding->uniform_locs.psh.bump_scale[i] = - glGetUniformLocation(binding->gl_program, tmp); - snprintf(tmp, sizeof(tmp), "bumpOffset%d", i); - binding->uniform_locs.psh.bump_offset[i] = - glGetUniformLocation(binding->gl_program, tmp); + binding->uniform_locs.vsh[i] = glGetUniformLocation(binding->gl_program, name); } - for (int i = 0; i < NV2A_MAX_TEXTURES; i++) { - snprintf(tmp, sizeof(tmp), "texScale%d", i); - binding->uniform_locs.psh.tex_scale[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - - /* lookup vertex shader uniforms */ - for (int i = 0; i < NV2A_VERTEXSHADER_CONSTANTS; i++) { - snprintf(tmp, sizeof(tmp), "c[%d]", i); - binding->uniform_locs.vsh.vsh_constant[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - binding->uniform_locs.psh.surface_size = - glGetUniformLocation(binding->gl_program, "surfaceSize"); - binding->uniform_locs.psh.clip_range = - glGetUniformLocation(binding->gl_program, "clipRange"); - binding->uniform_locs.psh.depth_offset = - glGetUniformLocation(binding->gl_program, "depthOffset"); - binding->uniform_locs.psh.fog_color = - glGetUniformLocation(binding->gl_program, "fogColor"); - binding->uniform_locs.vsh.fog_param = - glGetUniformLocation(binding->gl_program, "fogParam"); - - for (int i = 0; i < NV2A_LTCTXA_COUNT; i++) { - snprintf(tmp, sizeof(tmp), "ltctxa[%d]", i); - binding->uniform_locs.vsh.ltctxa[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - for (int i = 0; i < NV2A_LTCTXB_COUNT; i++) { - snprintf(tmp, sizeof(tmp), "ltctxb[%d]", i); - binding->uniform_locs.vsh.ltctxb[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - for (int i = 0; i < NV2A_LTC1_COUNT; i++) { - snprintf(tmp, sizeof(tmp), "ltc1[%d]", i); - binding->uniform_locs.vsh.ltc1[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - for (int i = 0; i < NV2A_MAX_LIGHTS; i++) { - snprintf(tmp, sizeof(tmp), "lightInfiniteHalfVector%d", i); - binding->uniform_locs.vsh.light_infinite_half_vector[i] = - glGetUniformLocation(binding->gl_program, tmp); - snprintf(tmp, sizeof(tmp), "lightInfiniteDirection%d", i); - binding->uniform_locs.vsh.light_infinite_direction[i] = - glGetUniformLocation(binding->gl_program, tmp); - - snprintf(tmp, sizeof(tmp), "lightLocalPosition%d", i); - binding->uniform_locs.vsh.light_local_position[i] = - glGetUniformLocation(binding->gl_program, tmp); - snprintf(tmp, sizeof(tmp), "lightLocalAttenuation%d", i); - binding->uniform_locs.vsh.light_local_attenuation[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - for (int i = 0; i < 8; i++) { - snprintf(tmp, sizeof(tmp), "clipRegion[%d]", i); - binding->uniform_locs.psh.clip_region[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - - for (int i = 0; i < 8; ++i) { - snprintf(tmp, sizeof(tmp), "pointParams[%d]", i); - binding->uniform_locs.vsh.point_params[i] = - glGetUniformLocation(binding->gl_program, tmp); - } - - if (binding->state.vsh.is_fixed_function) { - binding->uniform_locs.vsh.material_alpha = - glGetUniformLocation(binding->gl_program, "material_alpha"); - binding->uniform_locs.vsh.specular_power = - glGetUniformLocation(binding->gl_program, "specularPower"); - } else { - binding->uniform_locs.vsh.material_alpha = -1; - binding->uniform_locs.vsh.specular_power = -1; - } - - for (int i = 0; i < 4; ++i) { - snprintf(tmp, sizeof(tmp), "colorKey[%d]", i); - binding->uniform_locs.psh.color_key[i] = - glGetUniformLocation(binding->gl_program, tmp); - - snprintf(tmp, sizeof(tmp), "colorKeyMask[%d]", i); - binding->uniform_locs.psh.color_key_mask[i] = - glGetUniformLocation(binding->gl_program, tmp); + for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.psh); i++) { + const char *name = PshUniformInfo[i].name; + if (PshUniformInfo[i].count > 1) { + snprintf(tmp, sizeof(tmp), "%s[0]", name); + name = tmp; + } + binding->uniform_locs.psh[i] = glGetUniformLocation(binding->gl_program, name); } } @@ -723,270 +633,72 @@ void pgraph_gl_shader_cache_to_disk(ShaderBinding *binding) qemu_thread_create(binding->save_thread, name, shader_write_to_disk, binding, QEMU_THREAD_JOINABLE); } -static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, - bool binding_changed) +static void apply_uniform_updates(const UniformInfo *info, int *locs, + void *values, size_t count) +{ + for (int i = 0; i < count; i++) { + if (locs[i] == -1) { + continue; + } + + void *value = (char*)values + info[i].val_offs; + + switch (info[i].type) { + case UniformElementType_uint: + glUniform1uiv(locs[i], info[i].count, value); + break; + case UniformElementType_int: + glUniform1iv(locs[i], info[i].count, value); + break; + case UniformElementType_ivec4: + glUniform4iv(locs[i], info[i].count, value); + break; + case UniformElementType_float: + glUniform1fv(locs[i], info[i].count, value); + break; + case UniformElementType_vec2: + glUniform2fv(locs[i], info[i].count, value); + break; + case UniformElementType_vec3: + glUniform3fv(locs[i], info[i].count, value); + break; + case UniformElementType_vec4: + glUniform4fv(locs[i], info[i].count, value); + break; + case UniformElementType_mat2: + glUniformMatrix2fv(locs[i], info[i].count, GL_FALSE, value); + break; + default: + g_assert_not_reached(); + } + } + + assert(glGetError() == GL_NO_ERROR); +} + +// FIXME: Dirty tracking +// FIXME: Consider UBO to align with VK renderer +static void update_shader_uniforms(PGRAPHState *pg, ShaderBinding *binding) { PGRAPHGLState *r = pg->gl_renderer_state; - ShaderState *state = &binding->state; - int i, j; - /* update combiner constants */ - for (i = 0; i < 9; i++) { - uint32_t constant[2]; - if (i == 8) { - /* final combiner */ - constant[0] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR0); - constant[1] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR1); - } else { - constant[0] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4); - constant[1] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4); - } + VshUniformValues vsh_values; + pgraph_set_vsh_uniform_values(pg, &binding->state.vsh, + binding->uniform_locs.vsh, &vsh_values); + apply_uniform_updates(VshUniformInfo, binding->uniform_locs.vsh, + &vsh_values, VshUniform__COUNT); - for (j = 0; j < 2; j++) { - GLint loc = binding->uniform_locs.psh.psh_constant[i][j]; - if (loc != -1) { - float value[4]; - pgraph_argb_pack32_to_rgba_float(constant[j], value); - glUniform4fv(loc, 1, value); - } + PshUniformValues psh_values; + pgraph_set_psh_uniform_values(pg, binding->uniform_locs.psh, &psh_values); + + for (int i = 0; i < 4; i++) { + if (r->texture_binding[i] != NULL) { + float scale = r->texture_binding[i]->scale; + psh_values.texScale[i] = scale; } } - if (binding->uniform_locs.psh.alpha_ref != -1) { - int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0), - NV_PGRAPH_CONTROL_0_ALPHAREF); - glUniform1i(binding->uniform_locs.psh.alpha_ref, alpha_ref); - } - - /* For each texture stage */ - for (i = 0; i < NV2A_MAX_TEXTURES; i++) { - GLint loc; - - /* Bump luminance only during stages 1 - 3 */ - if (i > 0) { - loc = binding->uniform_locs.psh.bump_mat[i]; - if (loc != -1) { - uint32_t m_u32[4]; - m_u32[0] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT00 + 4 * (i - 1)); - m_u32[1] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT01 + 4 * (i - 1)); - m_u32[2] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT10 + 4 * (i - 1)); - m_u32[3] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT11 + 4 * (i - 1)); - float m[4]; - m[0] = *(float *)&m_u32[0]; - m[1] = *(float *)&m_u32[1]; - m[2] = *(float *)&m_u32[2]; - m[3] = *(float *)&m_u32[3]; - glUniformMatrix2fv(loc, 1, GL_FALSE, m); - } - loc = binding->uniform_locs.psh.bump_scale[i]; - if (loc != -1) { - uint32_t v = - pgraph_reg_r(pg, NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4); - glUniform1f(loc, *(float *)&v); - } - loc = binding->uniform_locs.psh.bump_offset[i]; - if (loc != -1) { - uint32_t v = - pgraph_reg_r(pg, NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4); - glUniform1f(loc, *(float *)&v); - } - } - - loc = r->shader_binding->uniform_locs.psh.tex_scale[i]; - if (loc != -1) { - assert(r->texture_binding[i] != NULL); - glUniform1f(loc, (float)r->texture_binding[i]->scale); - } - - if (binding->uniform_locs.psh.color_key[i] != -1) { - glUniform1ui(binding->uniform_locs.psh.color_key[i], - pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR0 + i * 4)); - } - if (binding->uniform_locs.psh.color_key_mask[i] != -1) { - glUniform1ui(binding->uniform_locs.psh.color_key_mask[i], - pgraph_get_color_key_mask_for_texture(pg, i)); - } - } - - if (binding->uniform_locs.psh.fog_color != -1) { - uint32_t fog_color = pgraph_reg_r(pg, NV_PGRAPH_FOGCOLOR); - glUniform4f(binding->uniform_locs.psh.fog_color, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_RED) / 255.0, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_GREEN) / 255.0, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_BLUE) / 255.0, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_ALPHA) / 255.0); - } - if (binding->uniform_locs.vsh.fog_param != -1) { - uint32_t v[2]; - v[0] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM0); - v[1] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM1); - glUniform2f(binding->uniform_locs.vsh.fog_param, *(float *)&v[0], - *(float *)&v[1]); - } - - float zmax; - switch (pg->surface_shape.zeta_format) { - case NV097_SET_SURFACE_FORMAT_ZETA_Z16: - zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF; - break; - case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8: - zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF; - break; - default: - assert(0); - } - - if (state->vsh.is_fixed_function) { - /* update lighting constants */ - struct { - uint32_t *v; - bool *dirty; - GLint *locs; - size_t len; - } lighting_arrays[] = { - { &pg->ltctxa[0][0], &pg->ltctxa_dirty[0], - binding->uniform_locs.vsh.ltctxa, NV2A_LTCTXA_COUNT }, - { &pg->ltctxb[0][0], &pg->ltctxb_dirty[0], - binding->uniform_locs.vsh.ltctxb, NV2A_LTCTXB_COUNT }, - { &pg->ltc1[0][0], &pg->ltc1_dirty[0], - binding->uniform_locs.vsh.ltc1, NV2A_LTC1_COUNT }, - }; - - for (i = 0; i < ARRAY_SIZE(lighting_arrays); i++) { - uint32_t *lighting_v = lighting_arrays[i].v; - bool *lighting_dirty = lighting_arrays[i].dirty; - GLint *lighting_locs = lighting_arrays[i].locs; - size_t lighting_len = lighting_arrays[i].len; - for (j = 0; j < lighting_len; j++) { - if (!lighting_dirty[j] && !binding_changed) - continue; - GLint loc = lighting_locs[j]; - if (loc != -1) { - glUniform4fv(loc, 1, (const GLfloat *)&lighting_v[j * 4]); - } - lighting_dirty[j] = false; - } - } - - for (i = 0; i < NV2A_MAX_LIGHTS; i++) { - GLint loc; - loc = binding->uniform_locs.vsh.light_infinite_half_vector[i]; - if (loc != -1) { - glUniform3fv(loc, 1, pg->light_infinite_half_vector[i]); - } - loc = binding->uniform_locs.vsh.light_infinite_direction[i]; - if (loc != -1) { - glUniform3fv(loc, 1, pg->light_infinite_direction[i]); - } - - loc = binding->uniform_locs.vsh.light_local_position[i]; - if (loc != -1) { - glUniform3fv(loc, 1, pg->light_local_position[i]); - } - loc = binding->uniform_locs.vsh.light_local_attenuation[i]; - if (loc != -1) { - glUniform3fv(loc, 1, pg->light_local_attenuation[i]); - } - } - - if (binding->uniform_locs.vsh.specular_power != -1) { - glUniform1f(binding->uniform_locs.vsh.specular_power, - pg->specular_power); - } - } - - /* update vertex program constants */ - for (i = 0; i < NV2A_VERTEXSHADER_CONSTANTS; i++) { - if (!pg->vsh_constants_dirty[i] && !binding_changed) - continue; - - GLint loc = binding->uniform_locs.vsh.vsh_constant[i]; - if ((loc != -1) && - memcmp(binding->vsh_constants[i], pg->vsh_constants[i], - sizeof(pg->vsh_constants[1]))) { - glUniform4fv(loc, 1, (const GLfloat *)pg->vsh_constants[i]); - memcpy(binding->vsh_constants[i], pg->vsh_constants[i], - sizeof(pg->vsh_constants[i])); - } - - pg->vsh_constants_dirty[i] = false; - } - - if (binding->uniform_locs.psh.surface_size != -1) { - unsigned int aa_width = 1, aa_height = 1; - pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); - glUniform2f(binding->uniform_locs.psh.surface_size, - pg->surface_binding_dim.width / aa_width, - pg->surface_binding_dim.height / aa_height); - } - - if (binding->uniform_locs.psh.clip_range != -1) { - uint32_t v[2]; - v[0] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN); - v[1] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX); - float zclip_min = *(float *)&v[0]; - float zclip_max = *(float *)&v[1]; - glUniform4f(binding->uniform_locs.psh.clip_range, 0, zmax, zclip_min, - zclip_max); - } - - if (binding->uniform_locs.psh.depth_offset != -1) { - float zbias = 0.0f; - - if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) & - (NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE | - NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE | - NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) { - uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS); - zbias = *(float *)&zbias_u32; - - if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 && - (pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & - NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) { - /* TODO: emulate zfactor when z_perspective true, i.e. - * w-buffering. Perhaps calculate an additional offset based on - * triangle orientation in geometry shader and pass the result - * to fragment shader and add it to gl_FragDepth as well. - */ - NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering"); - } - } - - glUniform1f(binding->uniform_locs.psh.depth_offset, zbias); - } - - /* Clipping regions */ - unsigned int max_gl_width = pg->surface_binding_dim.width; - unsigned int max_gl_height = pg->surface_binding_dim.height; - pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height); - - for (i = 0; i < 8; i++) { - uint32_t x = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPX0 + i * 4); - unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN); - unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX) + 1; - uint32_t y = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPY0 + i * 4); - unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN); - unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX) + 1; - pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min); - pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max); - - pgraph_apply_scaling_factor(pg, &x_min, &y_min); - pgraph_apply_scaling_factor(pg, &x_max, &y_max); - - glUniform4i(r->shader_binding->uniform_locs.psh.clip_region[i], x_min, - y_min, x_max, y_max); - } - - for (i = 0; i < 8; ++i) { - GLint loc = binding->uniform_locs.vsh.point_params[i]; - if (loc != -1) { - glUniform1f(loc, pg->point_params[i]); - } - } - - if (binding->uniform_locs.vsh.material_alpha != -1) { - glUniform1f(binding->uniform_locs.vsh.material_alpha, - pg->material_alpha); - } + apply_uniform_updates(PshUniformInfo, binding->uniform_locs.psh, + &psh_values, PshUniform__COUNT); } static bool test_shaders_dirty(PGRAPHState *pg) @@ -1071,7 +783,7 @@ void pgraph_gl_bind_shaders(PGRAPHState *pg) bool binding_changed = false; if (r->shader_binding && !test_shaders_dirty(pg) && !pg->program_data_dirty) { nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND_NOTDIRTY); - goto update_constants; + goto update_uniforms; } ShaderBinding *old_binding = r->shader_binding; @@ -1110,10 +822,10 @@ void pgraph_gl_bind_shaders(PGRAPHState *pg) NV2A_GL_DGROUP_END(); -update_constants: +update_uniforms: assert(r->shader_binding); assert(r->shader_binding->initialized); - shader_update_constants(pg, r->shader_binding, binding_changed); + update_shader_uniforms(pg, r->shader_binding); } GLuint pgraph_gl_compile_shader(const char *vs_src, const char *fs_src) diff --git a/hw/xbox/nv2a/pgraph/glsl/common.c b/hw/xbox/nv2a/pgraph/glsl/common.c index 8a609a2ed0..d62c491161 100644 --- a/hw/xbox/nv2a/pgraph/glsl/common.c +++ b/hw/xbox/nv2a/pgraph/glsl/common.c @@ -19,6 +19,11 @@ #include "common.h" +#define DECL_UNIFORM_ELEMENT_NAME(type) #type, +const char *uniform_element_type_to_str[] = { + UNIFORM_ELEMENT_TYPE_X(DECL_UNIFORM_ELEMENT_NAME) +}; + MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array) { const char *smooth_s = ""; diff --git a/hw/xbox/nv2a/pgraph/glsl/common.h b/hw/xbox/nv2a/pgraph/glsl/common.h index eb7b7f45e6..8f5ea5e269 100644 --- a/hw/xbox/nv2a/pgraph/glsl/common.h +++ b/hw/xbox/nv2a/pgraph/glsl/common.h @@ -22,8 +22,69 @@ #ifndef HW_NV2A_SHADERS_COMMON_H #define HW_NV2A_SHADERS_COMMON_H +#include "qemu/osdep.h" #include "qemu/mstring.h" -#include + +typedef int ivec4[4]; +typedef float mat2[2 * 2]; +typedef unsigned int uint; +typedef float vec2[2]; +typedef float vec3[3]; +typedef float vec4[4]; + +#define UNIFORM_ELEMENT_TYPE_X(DECL) \ + DECL(float) \ + DECL(int) \ + DECL(ivec4) \ + DECL(mat2) \ + DECL(uint) \ + DECL(vec2) \ + DECL(vec3) \ + DECL(vec4) + +enum UniformElementType { +#define DECL_UNIFORM_ELEMENT_TYPE(type) UniformElementType_##type, + UNIFORM_ELEMENT_TYPE_X(DECL_UNIFORM_ELEMENT_TYPE) +}; + +extern const char *uniform_element_type_to_str[]; + +#define DECL_UNIFORM_ENUM_VALUE(s, name, type, count) s##_##name, +#define DECL_UNIFORM_ENUM_TYPE(name, decls) \ + enum name##Indices{ \ + decls(name, DECL_UNIFORM_ENUM_VALUE) name##__COUNT, \ + }; + +#define DECL_UNIFORM_LOC_STRUCT_TYPE(name, decls) \ + typedef int name##Locs[name##__COUNT]; + +#define DECL_UNIFORM_VAL_STRUCT_FIELD(s, name, type, count) type name[count]; +#define DECL_UNIFORM_VAL_STRUCT_TYPE(name, decls) \ + typedef struct name##Values { \ + decls(name, DECL_UNIFORM_VAL_STRUCT_FIELD) \ + } name##Values; + +typedef struct UniformInfo { + const char *name; + enum UniformElementType type; + size_t size; + size_t count; + size_t val_offs; +} UniformInfo; + +#define DECL_UNIFORM_INFO_ITEM(s, name, type, count) \ + { #name, UniformElementType_##type, sizeof(type), count, \ + offsetof(s##Values, name) }, +#define DECL_UNIFORM_INFO_ARR(name, decls) \ + extern const UniformInfo name##Info[]; +#define DEF_UNIFORM_INFO_ARR(name, decls) \ + const UniformInfo name##Info[] = { decls(name, DECL_UNIFORM_INFO_ITEM) }; + +#define DECL_UNIFORM_TYPES(name, decls) \ + DECL_UNIFORM_ENUM_TYPE(name, decls) \ + DECL_UNIFORM_LOC_STRUCT_TYPE(name, decls) \ + DECL_UNIFORM_VAL_STRUCT_TYPE(name, decls) \ + DECL_UNIFORM_INFO_ARR(name, decls) #define GLSL_C(idx) "c[" stringify(idx) "]" #define GLSL_LTCTXA(idx) "ltctxa[" stringify(idx) "]" diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.c b/hw/xbox/nv2a/pgraph/glsl/psh.c index a35a99be5e..1651b0d06c 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.c +++ b/hw/xbox/nv2a/pgraph/glsl/psh.c @@ -34,11 +34,12 @@ #include #include -#include "common.h" #include "hw/xbox/nv2a/debug.h" -#include "hw/xbox/nv2a/pgraph/psh.h" +#include "hw/xbox/nv2a/pgraph/pgraph.h" #include "psh.h" +DEF_UNIFORM_INFO_ARR(PshUniform, PSH_UNIFORM_DECL_X) + /* * This implements translation of register combiners into glsl * fragment shaders, but all terminology is in terms of Xbox DirectX @@ -755,8 +756,6 @@ static void define_colorkey_comparator(MString *preflight) static MString* psh_convert(struct PixelShader *ps) { - const char *u = ps->opts.vulkan ? "" : "uniform "; // FIXME: Remove - MString *preflight = mstring_new(); pgraph_get_glsl_vtx_header(preflight, ps->opts.vulkan, ps->state.smooth_shading, true, false, false); @@ -772,25 +771,22 @@ static MString* psh_convert(struct PixelShader *ps) "layout(location = 0) out vec4 fragColor;\n"); } - mstring_append_fmt(preflight, - "%sint alphaRef;\n" - "%svec4 fogColor;\n" - "%sivec4 clipRegion[8];\n" - "%svec4 clipRange;\n" - "%sfloat depthOffset;\n" - "%suint colorKey[4];\n" - "%suint colorKeyMask[4];\n", - u, u, u, u, u, u, u); - for (int i = 0; i < 4; i++) { - mstring_append_fmt(preflight, "%smat2 bumpMat%d;\n" - "%sfloat bumpScale%d;\n" - "%sfloat bumpOffset%d;\n" - "%sfloat texScale%d;\n", - u, i, u, i, u, i, u, i); + const char *u = ps->opts.vulkan ? "" : "uniform "; + for (int i = 0; i < ARRAY_SIZE(PshUniformInfo); i++) { + const UniformInfo *info = &PshUniformInfo[i]; + const char *type_str = uniform_element_type_to_str[info->type]; + if (info->count == 1) { + mstring_append_fmt(preflight, "%s%s %s;\n", u, type_str, + info->name); + } else { + mstring_append_fmt(preflight, "%s%s %s[%zd];\n", u, type_str, + info->name, info->count); + } } + for (int i = 0; i < 9; i++) { for (int j = 0; j < 2; j++) { - mstring_append_fmt(preflight, "%svec4 c%d_%d;\n", u, j, i); + mstring_append_fmt(preflight, "#define c%d_%d consts[%d]\n", j, i, i*2+j); } } @@ -1044,7 +1040,7 @@ static MString* psh_convert(struct PixelShader *ps) i, ps->input_tex[i], ps->input_tex[i]); } - mstring_append_fmt(vars, "dsdt%d = bumpMat%d * dsdt%d;\n", i, i, i); + mstring_append_fmt(vars, "dsdt%d = bumpMat[%d] * dsdt%d;\n", i, i, i); if (ps->state.dim_tex[i] == 2) { mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, %s(pT%d.xy + dsdt%d));\n", @@ -1070,7 +1066,7 @@ static MString* psh_convert(struct PixelShader *ps) i, ps->input_tex[i], ps->input_tex[i], ps->input_tex[i]); } - mstring_append_fmt(vars, "dsdtl%d.st = bumpMat%d * dsdtl%d.st;\n", + mstring_append_fmt(vars, "dsdtl%d.st = bumpMat[%d] * dsdtl%d.st;\n", i, i, i); if (ps->state.dim_tex[i] == 2) { @@ -1084,7 +1080,7 @@ static MString* psh_convert(struct PixelShader *ps) assert(!"Unhandled texture dimensions"); } - mstring_append_fmt(vars, "t%d = t%d * (bumpScale%d * dsdtl%d.p + bumpOffset%d);\n", + mstring_append_fmt(vars, "t%d = t%d * (bumpScale[%d] * dsdtl%d.p + bumpOffset[%d]);\n", i, i, i, i, i); break; case PS_TEXTUREMODES_BRDF: @@ -1250,7 +1246,7 @@ static MString* psh_convert(struct PixelShader *ps) if (ps->state.rect_tex[i]) { mstring_append_fmt(preflight, "vec2 norm%d(vec2 coord) {\n" - " return coord / (textureSize(texSamp%d, 0) / texScale%d);\n" + " return coord / (textureSize(texSamp%d, 0) / texScale[%d]);\n" "}\n", i, i, i); mstring_append_fmt(preflight, @@ -1437,3 +1433,164 @@ MString *pgraph_gen_psh_glsl(const PshState state, GenPshGlslOptions opts) return psh_convert(&ps); } + +void pgraph_set_psh_uniform_values(PGRAPHState *pg, const PshUniformLocs locs, + PshUniformValues *values) +{ + /* update combiner constants */ + if (locs[PshUniform_consts] != -1) { + for (int i = 0; i < 9; i++) { + uint32_t constant[2]; + if (i == 8) { + /* final combiner */ + constant[0] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR0); + constant[1] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR1); + } else { + constant[0] = + pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4); + constant[1] = + pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4); + } + + for (int j = 0; j < 2; j++) { + int idx = i * 2 + j; + pgraph_argb_pack32_to_rgba_float(constant[j], + values->consts[idx]); + } + } + } + if (locs[PshUniform_alphaRef] != -1) { + int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0), + NV_PGRAPH_CONTROL_0_ALPHAREF); + values->alphaRef[0] = alpha_ref; + } + if (locs[PshUniform_colorKey] != -1) { + values->colorKey[0] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR0); + values->colorKey[1] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR1); + values->colorKey[2] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR2); + values->colorKey[3] = pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR3); + } + if (locs[PshUniform_colorKeyMask] != -1) { + for (int i = 0; i < NV2A_MAX_TEXTURES; i++) { + values->colorKeyMask[i] = + pgraph_get_color_key_mask_for_texture(pg, i); + } + } + + /* For each texture stage */ + for (int i = 0; i < NV2A_MAX_TEXTURES; i++) { + /* Bump luminance only during stages 1 - 3 */ + if (i > 0) { + if (locs[PshUniform_bumpMat] != -1) { + uint32_t m_u32[4]; + m_u32[0] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT00 + 4 * (i - 1)); + m_u32[1] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT01 + 4 * (i - 1)); + m_u32[2] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT10 + 4 * (i - 1)); + m_u32[3] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT11 + 4 * (i - 1)); + values->bumpMat[i][0] = *(float *)&m_u32[0]; + values->bumpMat[i][1] = *(float *)&m_u32[1]; + values->bumpMat[i][2] = *(float *)&m_u32[2]; + values->bumpMat[i][3] = *(float *)&m_u32[3]; + } + if (locs[PshUniform_bumpScale] != -1) { + uint32_t v = + pgraph_reg_r(pg, NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4); + values->bumpScale[i] = *(float *)&v; + } + if (locs[PshUniform_bumpOffset] != -1) { + uint32_t v = + pgraph_reg_r(pg, NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4); + values->bumpOffset[i] = *(float *)&v; + } + } + if (locs[PshUniform_texScale] != -1) { + values->texScale[0] = 1.0; /* Renderer will override this */ + } + } + + if (locs[PshUniform_fogColor] != -1) { + uint32_t fog_color = pgraph_reg_r(pg, NV_PGRAPH_FOGCOLOR); + values->fogColor[0][0] = + GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_RED) / 255.0; + values->fogColor[0][1] = + GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_GREEN) / 255.0; + values->fogColor[0][2] = + GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_BLUE) / 255.0; + values->fogColor[0][3] = + GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_ALPHA) / 255.0; + } + + + float zmax; + switch (pg->surface_shape.zeta_format) { + case NV097_SET_SURFACE_FORMAT_ZETA_Z16: + zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF; + break; + case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8: + zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF; + break; + default: + assert(0); + } + + if (locs[PshUniform_clipRange] != -1) { + uint32_t zclip_min = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN); + uint32_t zclip_max = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX); + + values->clipRange[0][0] = 0; + values->clipRange[0][1] = zmax; + values->clipRange[0][2] = *(float *)&zclip_min; + values->clipRange[0][3] = *(float *)&zclip_max; + } + + if (locs[PshUniform_depthOffset] != -1) { + float zbias = 0.0f; + + if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) & + (NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE | + NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE | + NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) { + uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS); + zbias = *(float *)&zbias_u32; + + if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 && + (pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & + NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) { + /* TODO: emulate zfactor when z_perspective true, i.e. + * w-buffering. Perhaps calculate an additional offset based on + * triangle orientation in geometry shader and pass the result + * to fragment shader and add it to gl_FragDepth as well. + */ + NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering"); + } + } + + values->depthOffset[0] = zbias; + } + + /* Clipping regions */ + unsigned int max_gl_width = pg->surface_binding_dim.width; + unsigned int max_gl_height = pg->surface_binding_dim.height; + pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height); + + for (int i = 0; i < 8; i++) { + uint32_t x = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPX0 + i * 4); + unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN); + unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX) + 1; + + uint32_t y = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPY0 + i * 4); + unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN); + unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX) + 1; + + pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min); + pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max); + + pgraph_apply_scaling_factor(pg, &x_min, &y_min); + pgraph_apply_scaling_factor(pg, &x_max, &y_max); + + values->clipRegion[i][0] = x_min; + values->clipRegion[i][1] = y_min; + values->clipRegion[i][2] = x_max; + values->clipRegion[i][3] = y_max; + } +} diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.h b/hw/xbox/nv2a/pgraph/glsl/psh.h index 8f76096f44..fbe2c09786 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.h +++ b/hw/xbox/nv2a/pgraph/glsl/psh.h @@ -24,6 +24,23 @@ #include "qemu/mstring.h" #include "hw/xbox/nv2a/pgraph/psh.h" +#include "common.h" + +#define PSH_UNIFORM_DECL_X(S, DECL) \ + DECL(S, alphaRef, int, 1) \ + DECL(S, bumpMat, mat2, 4) \ + DECL(S, bumpOffset, float, 4) \ + DECL(S, bumpScale, float, 4) \ + DECL(S, clipRange, vec4, 1) \ + DECL(S, clipRegion, ivec4, 8) \ + DECL(S, colorKey, uint, 4) \ + DECL(S, colorKeyMask, uint, 4) \ + DECL(S, consts, vec4, 18) \ + DECL(S, depthOffset, float, 1) \ + DECL(S, fogColor, vec4, 1) \ + DECL(S, texScale, float, 4) + +DECL_UNIFORM_TYPES(PshUniform, PSH_UNIFORM_DECL_X) typedef struct GenPshGlslOptions { bool vulkan; @@ -31,6 +48,12 @@ typedef struct GenPshGlslOptions { int tex_binding; } GenPshGlslOptions; +typedef struct PGRAPHState PGRAPHState; + MString *pgraph_gen_psh_glsl(const PshState state, GenPshGlslOptions opts); +void pgraph_set_psh_uniform_values(PGRAPHState *pg, + const PshUniformLocs locs, + PshUniformValues *values); + #endif diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 2131fcc082..609eec6f26 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -30,11 +30,10 @@ 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(GenVshGlslOptions opts, const VshState *state, - MString *header, MString *body, MString *uniforms) +void pgraph_gen_vsh_ff_glsl(const VshState *state, MString *header, + MString *body) { int i, j; - const char *u = opts.vulkan ? "" : "uniform "; // FIXME: Remove /* generate vertex shader mimicking fixed function */ mstring_append(header, @@ -55,11 +54,6 @@ void pgraph_gen_vsh_ff_glsl(GenVshGlslOptions opts, const VshState *state, "#define reserved2 v14\n" "#define reserved3 v15\n" "\n"); - mstring_append_fmt(uniforms, -"%svec4 ltctxa[" stringify(NV2A_LTCTXA_COUNT) "];\n" -"%svec4 ltctxb[" stringify(NV2A_LTCTXB_COUNT) "];\n" -"%svec4 ltc1[" stringify(NV2A_LTC1_COUNT) "];\n", u, u, u -); mstring_append(header, "\n" GLSL_DEFINE(projectionMat, GLSL_C_MAT4(NV_IGRAPH_XF_XFCTX_PMAT0)) @@ -236,15 +230,11 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, " oB1 = backSpecular;\n"); } else { //FIXME: Do 2 passes if we want 2 sided-lighting? - - mstring_append_fmt(uniforms, "%sfloat specularPower;\n", u); - static char alpha_source_diffuse[] = "diffuse.a"; static char alpha_source_specular[] = "specular.a"; static char alpha_source_material[] = "material_alpha"; const char *alpha_source = alpha_source_diffuse; 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->fixed_function.diffuse_src == MATERIAL_COLOR_SRC_SPECULAR) { alpha_source = alpha_source_specular; @@ -285,19 +275,15 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz if (state->fixed_function.light[i] == LIGHT_LOCAL || state->fixed_function.light[i] == LIGHT_SPOT) { - mstring_append_fmt(uniforms, - "%svec3 lightLocalPosition%d;\n" - "%svec3 lightLocalAttenuation%d;\n", - u, i, u, i); mstring_append_fmt(body, " vec3 tPos = tPosition.xyz/tPosition.w;\n" - " vec3 VP = lightLocalPosition%d - tPos;\n" + " vec3 VP = lightLocalPosition[%d] - tPos;\n" " float d = length(VP);\n" " if (d <= lightLocalRange(%d)) {\n" /* FIXME: Double check that range is inclusive */ " VP = normalize(VP);\n" - " float attenuation = 1.0 / (lightLocalAttenuation%d.x\n" - " + lightLocalAttenuation%d.y * d\n" - " + lightLocalAttenuation%d.z * d * d);\n" + " float attenuation = 1.0 / (lightLocalAttenuation[%d].x\n" + " + lightLocalAttenuation[%d].y * d\n" + " + lightLocalAttenuation[%d].z * d * d);\n" " vec3 halfVector = normalize(VP + %s);\n" " float nDotVP = max(0.0, dot(tNormal, VP));\n" " float nDotHV = max(0.0, dot(tNormal, halfVector));\n", @@ -311,14 +297,10 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz /* lightLocalRange will be 1e+30 here */ - mstring_append_fmt(uniforms, - "%svec3 lightInfiniteHalfVector%d;\n" - "%svec3 lightInfiniteDirection%d;\n", - u, i, u, i); mstring_append_fmt(body, " {\n" " float attenuation = 1.0;\n" - " vec3 lightDirection = normalize(lightInfiniteDirection%d);\n" + " vec3 lightDirection = normalize(lightInfiniteDirection[%d]);\n" " float nDotVP = max(0.0, dot(tNormal, lightDirection));\n", i); if (state->fixed_function.local_eye) { @@ -327,7 +309,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz ); } else { mstring_append_fmt(body, - " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", + " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector[%d]));\n", i ); } @@ -482,7 +464,6 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz /* FIXME: Testing */ if (state->point_params_enable) { - mstring_append_fmt(uniforms, "%sfloat pointParams[8];\n", u); mstring_append( body, " float d_e = length(position * modelViewMat0);\n" diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.h b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.h index 8081ce52dc..40927de745 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.h +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.h @@ -25,7 +25,7 @@ #include "qemu/mstring.h" #include "vsh.h" -void pgraph_gen_vsh_ff_glsl(GenVshGlslOptions opts, const VshState *state, - MString *header, MString *body, MString *uniforms); +void pgraph_gen_vsh_ff_glsl(const VshState *state, MString *header, + MString *body); #endif diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index 4381348b8f..ea61b851e9 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -20,32 +20,40 @@ */ #include "qemu/osdep.h" -#include "hw/xbox/nv2a/pgraph/shaders.h" +#include "hw/xbox/nv2a/pgraph/pgraph.h" #include "common.h" #include "vsh.h" #include "vsh-ff.h" #include "vsh-prog.h" #include +DEF_UNIFORM_INFO_ARR(VshUniform, VSH_UNIFORM_DECL_X) + MString *pgraph_gen_vsh_glsl(const VshState *state, GenVshGlslOptions opts) { - int i; - MString *output = mstring_new(); - mstring_append_fmt(output, "#version %d\n\n", opts.vulkan ? 450 : 400); + MString *output = + mstring_from_fmt("#version %d\n\n", opts.vulkan ? 450 : 400); MString *header = mstring_from_str(""); + MString *uniforms = mstring_from_str(""); - - const char *u = opts.vulkan ? "" : "uniform "; // FIXME: Remove - - mstring_append_fmt(uniforms, - "%svec4 clipRange;\n" - "%svec2 surfaceSize;\n" - "%svec4 c[" stringify(NV2A_VERTEXSHADER_CONSTANTS) "];\n" - "%svec2 fogParam;\n", - u, u, u, u - ); + const char *u = opts.vulkan ? "" : "uniform "; + for (int i = 0; i < ARRAY_SIZE(VshUniformInfo); i++) { + const UniformInfo *info = &VshUniformInfo[i]; + const char *type_str = uniform_element_type_to_str[info->type]; + if (i == VshUniform_inlineValue && + opts.use_push_constants_for_uniform_attrs) { + continue; + } + if (info->count == 1) { + mstring_append_fmt(uniforms, "%s%s %s;\n", u, type_str, + info->name); + } else { + mstring_append_fmt(uniforms, "%s%s %s[%zd];\n", u, type_str, + info->name, info->count); + } + } mstring_append(header, GLSL_DEFINE(fogPlane, GLSL_C(NV_IGRAPH_XF_XFCTX_FOG)) @@ -117,7 +125,7 @@ MString *pgraph_gen_vsh_glsl(const VshState *state, int num_uniform_attrs = 0; - for (i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) { + for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) { bool is_uniform = state->uniform_attrs & (1 << i); bool is_swizzled = state->swizzle_attrs & (1 << i); bool is_compressed = state->compressed_attrs & (1 << i); @@ -147,7 +155,7 @@ MString *pgraph_gen_vsh_glsl(const VshState *state, MString *body = mstring_from_str("void main() {\n"); - for (i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) { + for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) { if (state->compressed_attrs & (1 << i)) { mstring_append_fmt( body, "vec4 v%d = decompress_11_11_10(v%d_cmp);\n", i, i); @@ -160,7 +168,7 @@ MString *pgraph_gen_vsh_glsl(const VshState *state, } if (state->is_fixed_function) { - pgraph_gen_vsh_ff_glsl(opts, state, header, body, uniforms); + pgraph_gen_vsh_ff_glsl(state, header, body); } else { pgraph_gen_vsh_prog_glsl( VSH_VERSION_XVS, (uint32_t *)state->programmable.program_data, @@ -307,10 +315,10 @@ MString *pgraph_gen_vsh_glsl(const VshState *state, mstring_append_fmt(output, "layout(push_constant) uniform PushConstants {\n" " vec4 inlineValue[%d];\n" - "};\n\n", num_uniform_attrs); + "};\n\n", NV2A_VERTEXSHADER_ATTRIBUTES); } else { mstring_append_fmt(uniforms, " vec4 inlineValue[%d];\n", - num_uniform_attrs); + NV2A_VERTEXSHADER_ATTRIBUTES); } } mstring_append_fmt( @@ -331,3 +339,126 @@ MString *pgraph_gen_vsh_glsl(const VshState *state, mstring_unref(body); return output; } + +void pgraph_set_vsh_uniform_values(PGRAPHState *pg, const VshState *state, + const VshUniformLocs locs, + VshUniformValues *values) +{ + if (locs[VshUniform_c] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->c) != sizeof(pg->vsh_constants), + "Uniform value size inconsistency"); + memcpy(values->c, pg->vsh_constants, sizeof(pg->vsh_constants)); + } + + if (locs[VshUniform_clipRange] != -1) { + float zmax; + switch (pg->surface_shape.zeta_format) { + case NV097_SET_SURFACE_FORMAT_ZETA_Z16: + zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF; + break; + case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8: + zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF; + break; + default: + assert(0); + } + + uint32_t zclip_min = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN); + uint32_t zclip_max = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX); + + values->clipRange[0][0] = 0; + values->clipRange[0][1] = zmax; + values->clipRange[0][2] = *(float *)&zclip_min; + values->clipRange[0][3] = *(float *)&zclip_max; + } + + if (locs[VshUniform_fogParam] != -1) { + uint32_t param_0 = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM0); + uint32_t param_1 = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM1); + values->fogParam[0][0] = *(float *)¶m_0; + values->fogParam[0][1] = *(float *)¶m_1; + } + + if (locs[VshUniform_pointParams] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->pointParams) != + sizeof(pg->point_params), + "Uniform value size inconsistency"); + memcpy(values->pointParams, pg->point_params, sizeof(pg->point_params)); + } + + if (locs[VshUniform_material_alpha] != -1) { + values->material_alpha[0] = pg->material_alpha; + } + + if (locs[VshUniform_inlineValue] != -1) { + pgraph_get_inline_values(pg, state->uniform_attrs, values->inlineValue, + NULL); + } + + if (locs[VshUniform_surfaceSize] != -1) { + unsigned int aa_width = 1, aa_height = 1; + pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); + float width = (float)pg->surface_binding_dim.width / aa_width; + float height = (float)pg->surface_binding_dim.height / aa_height; + values->surfaceSize[0][0] = width; + values->surfaceSize[0][1] = height; + } + + if (state->is_fixed_function) { + /* update lighting constants */ + if (locs[VshUniform_ltctxa] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->ltctxa) != sizeof(pg->ltctxa), + "Uniform value size inconsistency"); + memcpy(values->ltctxa, pg->ltctxa, sizeof(pg->ltctxa)); + } + + if (locs[VshUniform_ltctxb] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->ltctxb) != sizeof(pg->ltctxb), + "Uniform value size inconsistency"); + memcpy(values->ltctxb, pg->ltctxb, sizeof(pg->ltctxb)); + } + + if (locs[VshUniform_ltc1] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->ltc1) != sizeof(pg->ltc1), + "Uniform value size inconsistency"); + memcpy(values->ltc1, pg->ltc1, sizeof(pg->ltc1)); + } + + if (locs[VshUniform_lightInfiniteHalfVector] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->lightInfiniteHalfVector) != + sizeof(pg->light_infinite_half_vector), + "Uniform value size inconsistency"); + memcpy(values->lightInfiniteHalfVector, + pg->light_infinite_half_vector, + sizeof(pg->light_infinite_half_vector)); + } + + if (locs[VshUniform_lightInfiniteDirection] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->lightInfiniteDirection) != + sizeof(pg->light_infinite_direction), + "Uniform value size inconsistency"); + memcpy(values->lightInfiniteDirection, pg->light_infinite_direction, + sizeof(pg->light_infinite_direction)); + } + + if (locs[VshUniform_lightLocalPosition] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->lightLocalPosition) != + sizeof(pg->light_local_position), + "Uniform value size inconsistency"); + memcpy(values->lightLocalPosition, pg->light_local_position, + sizeof(pg->light_local_position)); + } + + if (locs[VshUniform_lightLocalAttenuation] != -1) { + QEMU_BUILD_BUG_MSG(sizeof(values->lightLocalAttenuation) != + sizeof(pg->light_local_attenuation), + "Uniform value size inconsistency"); + memcpy(values->lightLocalAttenuation, pg->light_local_attenuation, + sizeof(pg->light_local_attenuation)); + } + + if (locs[VshUniform_specularPower] != -1) { + values->specularPower[0] = pg->specular_power; + } + } +} diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.h b/hw/xbox/nv2a/pgraph/glsl/vsh.h index de8826e8b9..d5166fb9d3 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.h +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.h @@ -24,6 +24,26 @@ #include "qemu/mstring.h" #include "hw/xbox/nv2a/pgraph/vsh.h" +#include "common.h" + +#define VSH_UNIFORM_DECL_X(S, DECL) \ + DECL(S, c, vec4, NV2A_VERTEXSHADER_CONSTANTS) \ + DECL(S, clipRange, vec4, 1) \ + DECL(S, fogParam, vec2, 1) \ + DECL(S, inlineValue, vec4, NV2A_VERTEXSHADER_ATTRIBUTES) \ + DECL(S, lightInfiniteDirection, vec3, NV2A_MAX_LIGHTS) \ + DECL(S, lightInfiniteHalfVector, vec3, NV2A_MAX_LIGHTS) \ + DECL(S, lightLocalAttenuation, vec3, NV2A_MAX_LIGHTS) \ + DECL(S, lightLocalPosition, vec3, NV2A_MAX_LIGHTS) \ + DECL(S, ltc1, vec4, NV2A_LTC1_COUNT) \ + DECL(S, ltctxa, vec4, NV2A_LTCTXA_COUNT) \ + DECL(S, ltctxb, vec4, NV2A_LTCTXB_COUNT) \ + DECL(S, material_alpha, float, 1) \ + DECL(S, pointParams, float, 8) \ + DECL(S, specularPower, float, 1) \ + DECL(S, surfaceSize, vec2, 1) + +DECL_UNIFORM_TYPES(VshUniform, VSH_UNIFORM_DECL_X) typedef struct GenVshGlslOptions { bool vulkan; @@ -32,7 +52,13 @@ typedef struct GenVshGlslOptions { int ubo_binding; } GenVshGlslOptions; +typedef struct PGRAPHState PGRAPHState; + MString *pgraph_gen_vsh_glsl(const VshState *state, GenVshGlslOptions glsl_opts); +void pgraph_set_vsh_uniform_values(PGRAPHState *pg, const VshState *state, + const VshUniformLocs locs, + VshUniformValues *values); + #endif diff --git a/hw/xbox/nv2a/pgraph/vk/glsl.c b/hw/xbox/nv2a/pgraph/vk/glsl.c index dd324b42ae..634bfb60c8 100644 --- a/hw/xbox/nv2a/pgraph/vk/glsl.c +++ b/hw/xbox/nv2a/pgraph/vk/glsl.c @@ -269,12 +269,24 @@ static void block_to_uniforms(const SpvReflectBlockVariable *block, ShaderUnifor assert(member->array.dims_count < 2); + int dim = 1; + for (int i = 0; i < member->array.dims_count; i++) { + dim *= member->array.dims[i]; + } + int stride = MAX(member->array.stride, member->numeric.matrix.stride); + if (member->numeric.matrix.column_count) { + dim *= member->numeric.matrix.column_count; + if (member->array.stride) { + stride = + member->array.stride / member->numeric.matrix.column_count; + } + } layout->uniforms[k] = (ShaderUniform){ .name = strdup(member->name), .offset = member->offset, .dim_v = MAX(1, member->numeric.vector.component_count), - .dim_a = MAX(member->array.dims_count ? member->array.dims[0] : 1, member->numeric.matrix.column_count), - .stride = MAX(member->array.stride, member->numeric.matrix.stride), + .dim_a = dim, + .stride = stride, }; // fprintf(stderr, "<%s offset=%zd dim_v=%zd dim_a=%zd stride=%zd>\n", diff --git a/hw/xbox/nv2a/pgraph/vk/glsl.h b/hw/xbox/nv2a/pgraph/vk/glsl.h index 115cee2ad2..75ab7082e5 100644 --- a/hw/xbox/nv2a/pgraph/vk/glsl.h +++ b/hw/xbox/nv2a/pgraph/vk/glsl.h @@ -63,7 +63,7 @@ static inline void uniform_std140(ShaderUniformLayout *layout) align = size; stride = 0; } - + offset = ROUND_UP(offset, align); u->align = align; @@ -87,7 +87,7 @@ static inline void uniform_std430(ShaderUniformLayout *layout) size *= u->dim_v; size_t align = size; size *= u->dim_a; - + offset = ROUND_UP(offset, align); u->align = align; @@ -120,10 +120,10 @@ void *uniform_ptr(ShaderUniformLayout *layout, int idx) return (char *)layout->allocation + layout->uniforms[idx - 1].offset; } -static inline -void uniform_copy(ShaderUniformLayout *layout, int idx, void *values, size_t value_size, size_t count) +static inline void uniform_copy(ShaderUniformLayout *layout, int idx, + void *values, size_t value_size, size_t count) { - assert(idx > 0 && "invalid uniform index"); + assert(idx > 0 && "invalid uniform index"); ShaderUniform *u = &layout->uniforms[idx - 1]; const size_t element_size = value_size * u->dim_v; @@ -135,14 +135,14 @@ void uniform_copy(ShaderUniformLayout *layout, int idx, void *values, size_t val int index = 0; while (bytes_remaining) { - assert(p_out < p_max); - assert(index < u->dim_a); + assert((p_out + element_size) <= p_max); + assert(index < u->dim_a); memcpy(p_out, p_in, element_size); bytes_remaining -= element_size; p_out += u->stride; p_in += element_size; index += 1; - } + } } static inline diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 84057f2273..10a385e147 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -30,6 +30,8 @@ #include "hw/xbox/nv2a/pgraph/surface.h" #include "hw/xbox/nv2a/pgraph/texture.h" #include "hw/xbox/nv2a/pgraph/shaders.h" +#include "hw/xbox/nv2a/pgraph/glsl/vsh.h" +#include "hw/xbox/nv2a/pgraph/glsl/psh.h" #include #include @@ -165,39 +167,8 @@ typedef struct ShaderBinding { ShaderModuleInfo *fragment; struct { - struct { - int alpha_ref; - int bump_mat[NV2A_MAX_TEXTURES]; - int bump_offset[NV2A_MAX_TEXTURES]; - int bump_scale[NV2A_MAX_TEXTURES]; - int clip_range; - int clip_region; - int color_key; - int color_key_mask; - int depth_offset; - int fog_color; - int psh_constant[9][2]; - int surface_size; - int tex_scale[NV2A_MAX_TEXTURES]; - } psh; - - struct { - int clip_range; - int fog_param; - int light_infinite_direction[NV2A_MAX_LIGHTS]; - int light_infinite_half_vector[NV2A_MAX_LIGHTS]; - int light_local_attenuation[NV2A_MAX_LIGHTS]; - int light_local_position[NV2A_MAX_LIGHTS]; - int ltc1; - int ltctxa; - int ltctxb; - int material_alpha; - int point_params; - int specular_power; - int uniform_attrs; - int vsh_constant; - uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; - } vsh; + PshUniformLocs psh; + VshUniformLocs vsh; } uniform_locs; } ShaderBinding; @@ -555,7 +526,6 @@ void pgraph_vk_init_shaders(PGRAPHState *pg); void pgraph_vk_finalize_shaders(PGRAPHState *pg); void pgraph_vk_update_descriptor_sets(PGRAPHState *pg); void pgraph_vk_bind_shaders(PGRAPHState *pg); -void pgraph_vk_update_shader_uniforms(PGRAPHState *pg); // reports.c void pgraph_vk_init_reports(PGRAPHState *pg); diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index a03fad5f16..6eff4cdf24 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -242,95 +242,15 @@ void pgraph_vk_update_descriptor_sets(PGRAPHState *pg) static void update_shader_constant_locations(ShaderBinding *binding) { - char tmp[64]; - - /* lookup fragment shader uniforms */ - for (int i = 0; i < 9; i++) { - for (int j = 0; j < 2; j++) { - snprintf(tmp, sizeof(tmp), "c%d_%d", j, i); - binding->uniform_locs.psh.psh_constant[i][j] = - uniform_index(&binding->fragment->uniforms, tmp); - } - } - binding->uniform_locs.psh.alpha_ref = - uniform_index(&binding->fragment->uniforms, "alphaRef"); - binding->uniform_locs.psh.fog_color = - uniform_index(&binding->fragment->uniforms, "fogColor"); - for (int i = 1; i < NV2A_MAX_TEXTURES; i++) { - snprintf(tmp, sizeof(tmp), "bumpMat%d", i); - binding->uniform_locs.psh.bump_mat[i] = - uniform_index(&binding->fragment->uniforms, tmp); - snprintf(tmp, sizeof(tmp), "bumpScale%d", i); - binding->uniform_locs.psh.bump_scale[i] = - uniform_index(&binding->fragment->uniforms, tmp); - snprintf(tmp, sizeof(tmp), "bumpOffset%d", i); - binding->uniform_locs.psh.bump_offset[i] = - uniform_index(&binding->fragment->uniforms, tmp); + for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.vsh); i++) { + binding->uniform_locs.vsh[i] = + uniform_index(&binding->vertex->uniforms, VshUniformInfo[i].name); } - for (int i = 0; i < NV2A_MAX_TEXTURES; i++) { - snprintf(tmp, sizeof(tmp), "texScale%d", i); - binding->uniform_locs.psh.tex_scale[i] = - uniform_index(&binding->fragment->uniforms, tmp); + for (int i = 0; i < ARRAY_SIZE(binding->uniform_locs.psh); i++) { + binding->uniform_locs.psh[i] = + uniform_index(&binding->fragment->uniforms, PshUniformInfo[i].name); } - - /* lookup vertex shader uniforms */ - binding->uniform_locs.vsh.vsh_constant = - uniform_index(&binding->vertex->uniforms, "c"); - binding->uniform_locs.psh.surface_size = - uniform_index(&binding->vertex->uniforms, "surfaceSize"); - binding->uniform_locs.vsh.clip_range = - uniform_index(&binding->vertex->uniforms, "clipRange"); - binding->uniform_locs.psh.clip_range = - uniform_index(&binding->fragment->uniforms, "clipRange"); - binding->uniform_locs.psh.depth_offset = - uniform_index(&binding->fragment->uniforms, "depthOffset"); - binding->uniform_locs.vsh.fog_param = - uniform_index(&binding->vertex->uniforms, "fogParam"); - - binding->uniform_locs.vsh.ltctxa = - uniform_index(&binding->vertex->uniforms, "ltctxa"); - binding->uniform_locs.vsh.ltctxb = - uniform_index(&binding->vertex->uniforms, "ltctxb"); - binding->uniform_locs.vsh.ltc1 = - uniform_index(&binding->vertex->uniforms, "ltc1"); - - for (int i = 0; i < NV2A_MAX_LIGHTS; i++) { - snprintf(tmp, sizeof(tmp), "lightInfiniteHalfVector%d", i); - binding->uniform_locs.vsh.light_infinite_half_vector[i] = - uniform_index(&binding->vertex->uniforms, tmp); - snprintf(tmp, sizeof(tmp), "lightInfiniteDirection%d", i); - binding->uniform_locs.vsh.light_infinite_direction[i] = - uniform_index(&binding->vertex->uniforms, tmp); - - snprintf(tmp, sizeof(tmp), "lightLocalPosition%d", i); - binding->uniform_locs.vsh.light_local_position[i] = - uniform_index(&binding->vertex->uniforms, tmp); - snprintf(tmp, sizeof(tmp), "lightLocalAttenuation%d", i); - binding->uniform_locs.vsh.light_local_attenuation[i] = - uniform_index(&binding->vertex->uniforms, tmp); - } - - binding->uniform_locs.psh.clip_region = - uniform_index(&binding->fragment->uniforms, "clipRegion"); - - binding->uniform_locs.vsh.point_params = - uniform_index(&binding->vertex->uniforms, "pointParams"); - - binding->uniform_locs.vsh.material_alpha = - uniform_index(&binding->vertex->uniforms, "material_alpha"); - - binding->uniform_locs.psh.color_key = - uniform_index(&binding->fragment->uniforms, "colorKey"); - - binding->uniform_locs.psh.color_key_mask = - uniform_index(&binding->fragment->uniforms, "colorKeyMask"); - - binding->uniform_locs.vsh.uniform_attrs = - uniform_index(&binding->vertex->uniforms, "inlineValue"); - - binding->uniform_locs.vsh.specular_power = - uniform_index(&binding->vertex->uniforms, "specularPower"); } static void shader_cache_entry_init(Lru *lru, LruNode *node, void *state) @@ -467,310 +387,6 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state) return snode; } -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.vsh.uniform_attrs, values, - &num_uniform_attrs); - - if (num_uniform_attrs > 0) { - uniform1fv(&binding->vertex->uniforms, - binding->uniform_locs.vsh.uniform_attrs, - num_uniform_attrs * 4, &values[0][0]); - } -} - -// FIXME: Move to common -static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding) -{ - PGRAPHVkState *r = pg->vk_renderer_state; - ShaderState *state = &binding->state; - - /* update combiner constants */ - for (int i = 0; i < 9; i++) { - uint32_t constant[2]; - if (i == 8) { - /* final combiner */ - constant[0] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR0); - constant[1] = pgraph_reg_r(pg, NV_PGRAPH_SPECFOGFACTOR1); - } else { - constant[0] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR0 + i * 4); - constant[1] = pgraph_reg_r(pg, NV_PGRAPH_COMBINEFACTOR1 + i * 4); - } - - for (int j = 0; j < 2; j++) { - GLint loc = binding->uniform_locs.psh.psh_constant[i][j]; - if (loc != -1) { - float value[4]; - pgraph_argb_pack32_to_rgba_float(constant[j], value); - uniform1fv(&binding->fragment->uniforms, loc, 4, value); - } - } - } - if (binding->uniform_locs.psh.alpha_ref != -1) { - int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0), - NV_PGRAPH_CONTROL_0_ALPHAREF); - uniform1i(&binding->fragment->uniforms, - binding->uniform_locs.psh.alpha_ref, alpha_ref); - } - if (binding->uniform_locs.psh.color_key != -1) { - uint32_t color_key_colors[4] = { - pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR0), - pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR1), - pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR2), - pgraph_reg_r(pg, NV_PGRAPH_COLORKEYCOLOR3), - }; - uniform1uiv(&binding->fragment->uniforms, - binding->uniform_locs.psh.color_key, 4, color_key_colors); - } - uint32_t color_key_mask[4] = { 0 }; - - /* For each texture stage */ - for (int i = 0; i < NV2A_MAX_TEXTURES; i++) { - int loc; - - /* Bump luminance only during stages 1 - 3 */ - if (i > 0) { - loc = binding->uniform_locs.psh.bump_mat[i]; - if (loc != -1) { - uint32_t m_u32[4]; - m_u32[0] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT00 + 4 * (i - 1)); - m_u32[1] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT01 + 4 * (i - 1)); - m_u32[2] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT10 + 4 * (i - 1)); - m_u32[3] = pgraph_reg_r(pg, NV_PGRAPH_BUMPMAT11 + 4 * (i - 1)); - float m[4]; - m[0] = *(float *)&m_u32[0]; - m[1] = *(float *)&m_u32[1]; - m[2] = *(float *)&m_u32[2]; - m[3] = *(float *)&m_u32[3]; - uniformMatrix2fv(&binding->fragment->uniforms, loc, m); - } - loc = binding->uniform_locs.psh.bump_scale[i]; - if (loc != -1) { - uint32_t v = - pgraph_reg_r(pg, NV_PGRAPH_BUMPSCALE1 + (i - 1) * 4); - uniform1f(&binding->fragment->uniforms, loc, *(float *)&v); - } - loc = binding->uniform_locs.psh.bump_offset[i]; - if (loc != -1) { - uint32_t v = - pgraph_reg_r(pg, NV_PGRAPH_BUMPOFFSET1 + (i - 1) * 4); - uniform1f(&binding->fragment->uniforms, loc, *(float *)&v); - } - } - - loc = binding->uniform_locs.psh.tex_scale[i]; - 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]; - if (!f_basic.linear) { - scale = 1.0; - } - uniform1f(&binding->fragment->uniforms, loc, scale); - } - - color_key_mask[i] = pgraph_get_color_key_mask_for_texture(pg, i); - } - - if (binding->uniform_locs.psh.color_key_mask != -1) { - uniform1uiv(&binding->fragment->uniforms, - binding->uniform_locs.psh.color_key_mask, 4, - color_key_mask); - } - - if (binding->uniform_locs.psh.fog_color != -1) { - uint32_t fog_color = pgraph_reg_r(pg, NV_PGRAPH_FOGCOLOR); - uniform4f(&binding->fragment->uniforms, - binding->uniform_locs.psh.fog_color, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_RED) / 255.0, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_GREEN) / 255.0, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_BLUE) / 255.0, - GET_MASK(fog_color, NV_PGRAPH_FOGCOLOR_ALPHA) / 255.0); - } - if (binding->uniform_locs.vsh.fog_param != -1) { - uint32_t v[2]; - v[0] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM0); - v[1] = pgraph_reg_r(pg, NV_PGRAPH_FOGPARAM1); - uniform2f(&binding->vertex->uniforms, - binding->uniform_locs.vsh.fog_param, *(float *)&v[0], - *(float *)&v[1]); - } - - float zmax; - switch (pg->surface_shape.zeta_format) { - case NV097_SET_SURFACE_FORMAT_ZETA_Z16: - zmax = pg->surface_shape.z_format ? f16_max : (float)0xFFFF; - break; - case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8: - zmax = pg->surface_shape.z_format ? f24_max : (float)0xFFFFFF; - break; - default: - assert(0); - } - - if (binding->state.vsh.is_fixed_function) { - /* update lighting constants */ - struct { - uint32_t *v; - int locs; - size_t len; - } lighting_arrays[] = { - { &pg->ltctxa[0][0], binding->uniform_locs.vsh.ltctxa, - NV2A_LTCTXA_COUNT }, - { &pg->ltctxb[0][0], binding->uniform_locs.vsh.ltctxb, - NV2A_LTCTXB_COUNT }, - { &pg->ltc1[0][0], binding->uniform_locs.vsh.ltc1, - NV2A_LTC1_COUNT }, - }; - - for (int i = 0; i < ARRAY_SIZE(lighting_arrays); i++) { - uniform1iv(&binding->vertex->uniforms, lighting_arrays[i].locs, - lighting_arrays[i].len * 4, - (void *)lighting_arrays[i].v); - } - - for (int i = 0; i < NV2A_MAX_LIGHTS; i++) { - int loc = binding->uniform_locs.vsh.light_infinite_half_vector[i]; - if (loc != -1) { - uniform1fv(&binding->vertex->uniforms, loc, 3, - pg->light_infinite_half_vector[i]); - } - loc = binding->uniform_locs.vsh.light_infinite_direction[i]; - if (loc != -1) { - uniform1fv(&binding->vertex->uniforms, loc, 3, - pg->light_infinite_direction[i]); - } - - loc = binding->uniform_locs.vsh.light_local_position[i]; - if (loc != -1) { - uniform1fv(&binding->vertex->uniforms, loc, 3, - pg->light_local_position[i]); - } - loc = binding->uniform_locs.vsh.light_local_attenuation[i]; - if (loc != -1) { - uniform1fv(&binding->vertex->uniforms, loc, 3, - pg->light_local_attenuation[i]); - } - } - - if (binding->uniform_locs.vsh.specular_power != -1) { - uniform1f(&binding->vertex->uniforms, - binding->uniform_locs.vsh.specular_power, - pg->specular_power); - } - } - - /* update vertex program constants */ - uniform1iv(&binding->vertex->uniforms, - binding->uniform_locs.vsh.vsh_constant, - NV2A_VERTEXSHADER_CONSTANTS * 4, (void *)pg->vsh_constants); - - if (binding->uniform_locs.psh.surface_size != -1) { - unsigned int aa_width = 1, aa_height = 1; - pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); - uniform2f(&binding->vertex->uniforms, - binding->uniform_locs.psh.surface_size, - pg->surface_binding_dim.width / aa_width, - pg->surface_binding_dim.height / aa_height); - } - - if (binding->uniform_locs.vsh.clip_range != -1 || - binding->uniform_locs.psh.clip_range != -1) { - uint32_t v[2]; - v[0] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN); - v[1] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX); - float zclip_min = *(float *)&v[0]; - float zclip_max = *(float *)&v[1]; - - if (binding->uniform_locs.vsh.clip_range != -1) { - uniform4f(&binding->vertex->uniforms, - binding->uniform_locs.vsh.clip_range, 0, zmax, zclip_min, - zclip_max); - } - if (binding->uniform_locs.psh.clip_range != -1) { - uniform4f(&binding->fragment->uniforms, - binding->uniform_locs.psh.clip_range, 0, zmax, zclip_min, - zclip_max); - } - } - - if (binding->uniform_locs.psh.depth_offset != -1) { - float zbias = 0.0f; - - if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) & - (NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE | - NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE | - NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) { - uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS); - zbias = *(float *)&zbias_u32; - - if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 && - (pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & - NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) { - /* TODO: emulate zfactor when z_perspective true, i.e. - * w-buffering. Perhaps calculate an additional offset based on - * triangle orientation in geometry shader and pass the result - * to fragment shader and add it to gl_FragDepth as well. - */ - NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering"); - } - } - - uniform1f(&binding->fragment->uniforms, - binding->uniform_locs.psh.depth_offset, zbias); - } - - /* Clipping regions */ - unsigned int max_gl_width = pg->surface_binding_dim.width; - unsigned int max_gl_height = pg->surface_binding_dim.height; - pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height); - - uint32_t clip_regions[8][4]; - - for (int i = 0; i < 8; i++) { - uint32_t x = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPX0 + i * 4); - unsigned int x_min = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMIN); - unsigned int x_max = GET_MASK(x, NV_PGRAPH_WINDOWCLIPX0_XMAX) + 1; - uint32_t y = pgraph_reg_r(pg, NV_PGRAPH_WINDOWCLIPY0 + i * 4); - unsigned int y_min = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMIN); - unsigned int y_max = GET_MASK(y, NV_PGRAPH_WINDOWCLIPY0_YMAX) + 1; - pgraph_apply_anti_aliasing_factor(pg, &x_min, &y_min); - pgraph_apply_anti_aliasing_factor(pg, &x_max, &y_max); - - pgraph_apply_scaling_factor(pg, &x_min, &y_min); - pgraph_apply_scaling_factor(pg, &x_max, &y_max); - - clip_regions[i][0] = x_min; - clip_regions[i][1] = y_min; - clip_regions[i][2] = x_max; - clip_regions[i][3] = y_max; - } - uniform1iv(&binding->fragment->uniforms, - binding->uniform_locs.psh.clip_region, 8 * 4, - (void *)clip_regions); - - if (binding->uniform_locs.vsh.point_params != -1) { - uniform1iv(&binding->vertex->uniforms, - binding->uniform_locs.vsh.point_params, - ARRAY_SIZE(pg->point_params), (void *)pg->point_params); - } - - if (binding->uniform_locs.vsh.material_alpha != -1) { - uniform1f(&binding->vertex->uniforms, - binding->uniform_locs.vsh.material_alpha, pg->material_alpha); - } - - if (!r->use_push_constants_for_uniform_attrs && state->vsh.uniform_attrs) { - update_uniform_attr_values(pg, binding); - } -} - // 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) @@ -849,6 +465,71 @@ static bool check_shaders_dirty(PGRAPHState *pg) return false; } +static void apply_uniform_updates(ShaderUniformLayout *layout, + const UniformInfo *info, int *locs, + void *values, size_t count) +{ + for (int i = 0; i < count; i++) { + if (locs[i] != -1) { + uniform_copy(layout, locs[i], (char*)values + info[i].val_offs, + 4, (info[i].size * info[i].count) / 4); + } + } +} + +// FIXME: Dirty tracking +static void update_shader_uniforms(PGRAPHState *pg) +{ + PGRAPHVkState *r = pg->vk_renderer_state; + NV2A_VK_DGROUP_BEGIN("%s", __func__); + nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND); + + assert(r->shader_binding); + ShaderBinding *binding = r->shader_binding; + ShaderUniformLayout *layouts[] = { &binding->vertex->uniforms, + &binding->fragment->uniforms }; + + VshUniformValues vsh_values; + pgraph_set_vsh_uniform_values(pg, &binding->state.vsh, + binding->uniform_locs.vsh, &vsh_values); + apply_uniform_updates(&binding->vertex->uniforms, VshUniformInfo, + binding->uniform_locs.vsh, &vsh_values, + VshUniform__COUNT); + + PshUniformValues psh_values; + pgraph_set_psh_uniform_values(pg, binding->uniform_locs.psh, &psh_values); + for (int i = 0; i < 4; i++) { + assert(r->texture_bindings[i] != NULL); + float scale = r->texture_bindings[i]->key.scale; + + 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; + } + + psh_values.texScale[i] = scale; + } + apply_uniform_updates(&binding->fragment->uniforms, PshUniformInfo, + binding->uniform_locs.psh, &psh_values, + PshUniform__COUNT); + + for (int i = 0; i < ARRAY_SIZE(layouts); i++) { + uint64_t hash = + fast_hash(layouts[i]->allocation, layouts[i]->total_size); + r->uniforms_changed |= (hash != r->uniform_buffer_hashes[i]); + r->uniform_buffer_hashes[i] = hash; + } + + nv2a_profile_inc_counter(r->uniforms_changed ? + NV2A_PROF_SHADER_UBO_DIRTY : + NV2A_PROF_SHADER_UBO_NOTDIRTY); + + NV2A_VK_DGROUP_END(); +} + void pgraph_vk_bind_shaders(PGRAPHState *pg) { NV2A_VK_DGROUP_BEGIN("%s", __func__); @@ -865,33 +546,7 @@ void pgraph_vk_bind_shaders(PGRAPHState *pg) } } - // FIXME: Use dirty bits - pgraph_vk_update_shader_uniforms(pg); - - NV2A_VK_DGROUP_END(); -} - -void pgraph_vk_update_shader_uniforms(PGRAPHState *pg) -{ - PGRAPHVkState *r = pg->vk_renderer_state; - NV2A_VK_DGROUP_BEGIN("%s", __func__); - nv2a_profile_inc_counter(NV2A_PROF_SHADER_BIND); - - assert(r->shader_binding); - ShaderBinding *binding = r->shader_binding; - ShaderUniformLayout *layouts[] = { &binding->vertex->uniforms, - &binding->fragment->uniforms }; - 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); - r->uniforms_changed |= (hash != r->uniform_buffer_hashes[i]); - r->uniform_buffer_hashes[i] = hash; - } - - nv2a_profile_inc_counter(r->uniforms_changed ? - NV2A_PROF_SHADER_UBO_DIRTY : - NV2A_PROF_SHADER_UBO_NOTDIRTY); + update_shader_uniforms(pg); NV2A_VK_DGROUP_END(); }