diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index 5da89e10e3e..84fef5ea6ab 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -219,7 +219,9 @@ static ShaderBinding *generate_shaders(const ShaderState *state) state->polygon_back_mode, state->primitive_mode, state->smooth_shading, - false); + false, + state->z_perspective + ); if (geometry_shader_code) { const char* geometry_shader_code_str = mstring_get_str(geometry_shader_code); @@ -240,7 +242,7 @@ static ShaderBinding *generate_shaders(const ShaderState *state) mstring_unref(vertex_shader_code); /* generate a fragment shader from register combiners */ - MString *fragment_shader_code = pgraph_gen_psh_glsl(state->psh); + MString *fragment_shader_code = pgraph_gen_psh_glsl(state->psh, state->z_perspective); const char *fragment_shader_code_str = mstring_get_str(fragment_shader_code); GLuint fragment_shader = create_gl_shader(GL_FRAGMENT_SHADER, diff --git a/hw/xbox/nv2a/pgraph/glsl/common.c b/hw/xbox/nv2a/pgraph/glsl/common.c index 7059880373d..78ff2d30101 100644 --- a/hw/xbox/nv2a/pgraph/glsl/common.c +++ b/hw/xbox/nv2a/pgraph/glsl/common.c @@ -21,13 +21,13 @@ #include "common.h" -MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array) +MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array, bool z_perspective) { const char *flat_s = "flat"; - const char *noperspective_s = "noperspective"; + const char *noperspective_s = z_perspective ? "" : "noperspective"; const char *qualifier_s = smooth ? noperspective_s : flat_s; const char *qualifiers[11] = { - noperspective_s, flat_s, qualifier_s, qualifier_s, + "noperspective", flat_s, qualifier_s, qualifier_s, qualifier_s, qualifier_s, noperspective_s, noperspective_s, noperspective_s, noperspective_s, noperspective_s }; diff --git a/hw/xbox/nv2a/pgraph/glsl/common.h b/hw/xbox/nv2a/pgraph/glsl/common.h index 6820a1dcb19..573d87d2239 100644 --- a/hw/xbox/nv2a/pgraph/glsl/common.h +++ b/hw/xbox/nv2a/pgraph/glsl/common.h @@ -33,6 +33,6 @@ #define GLSL_DEFINE(a, b) "#define " stringify(a) " " b "\n" -MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array); +MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array, bool z_perspective); #endif diff --git a/hw/xbox/nv2a/pgraph/glsl/geom.c b/hw/xbox/nv2a/pgraph/glsl/geom.c index 0e738f02806..17ed1637872 100644 --- a/hw/xbox/nv2a/pgraph/glsl/geom.c +++ b/hw/xbox/nv2a/pgraph/glsl/geom.c @@ -27,7 +27,8 @@ MString *pgraph_gen_geom_glsl(enum ShaderPolygonMode polygon_front_mode, enum ShaderPolygonMode polygon_back_mode, enum ShaderPrimitiveMode primitive_mode, bool smooth_shading, - bool vulkan) + bool vulkan, + bool z_perspective) { /* FIXME: Missing support for 2-sided-poly mode */ assert(polygon_front_mode == polygon_back_mode); @@ -174,8 +175,8 @@ MString *pgraph_gen_geom_glsl(enum ShaderPolygonMode polygon_front_mode, mstring_append(s, layout_in); mstring_append(s, layout_out); mstring_append(s, "\n"); - pgraph_get_glsl_vtx_header(s, vulkan, smooth_shading, true, true, true); - pgraph_get_glsl_vtx_header(s, vulkan, smooth_shading, false, false, false); + pgraph_get_glsl_vtx_header(s, vulkan, smooth_shading, true, true, true, z_perspective); + pgraph_get_glsl_vtx_header(s, vulkan, smooth_shading, false, false, false, z_perspective); if (smooth_shading) { mstring_append(s, diff --git a/hw/xbox/nv2a/pgraph/glsl/geom.h b/hw/xbox/nv2a/pgraph/glsl/geom.h index 9ca605be71b..0deaecc4f5e 100644 --- a/hw/xbox/nv2a/pgraph/glsl/geom.h +++ b/hw/xbox/nv2a/pgraph/glsl/geom.h @@ -29,6 +29,7 @@ MString *pgraph_gen_geom_glsl(enum ShaderPolygonMode polygon_front_mode, enum ShaderPolygonMode polygon_back_mode, enum ShaderPrimitiveMode primitive_mode, bool smooth_shading, - bool vulkan); + bool vulkan, + bool z_perspective); #endif diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.c b/hw/xbox/nv2a/pgraph/glsl/psh.c index fcb594d5009..bb830b6528f 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.c +++ b/hw/xbox/nv2a/pgraph/glsl/psh.c @@ -726,7 +726,7 @@ static void apply_convolution_filter(const struct PixelShader *ps, MString *vars "}\n", tex, tex, tex, tex, tex_remap, tex); } -static MString* psh_convert(struct PixelShader *ps) +static MString *psh_convert(struct PixelShader *ps, bool z_perspective) { int i; @@ -734,7 +734,7 @@ static MString* psh_convert(struct PixelShader *ps) MString *preflight = mstring_new(); pgraph_get_glsl_vtx_header(preflight, ps->state.vulkan, - ps->state.smooth_shading, true, false, false); + ps->state.smooth_shading, true, false, false, z_perspective); if (ps->state.vulkan) { mstring_append_fmt(preflight, @@ -744,7 +744,11 @@ static MString* psh_convert(struct PixelShader *ps) mstring_append_fmt(preflight, "layout(location = 0) out vec4 fragColor;\n"); } - + if (z_perspective) { + mstring_append_fmt(preflight, + "%svec4 clipRange;\n", + u); + } mstring_append_fmt(preflight, "%sfloat alphaRef;\n" "%svec4 fogColor;\n" "%sivec4 clipRegion[8];\n", @@ -865,26 +869,42 @@ static MString* psh_convert(struct PixelShader *ps) /* calculate perspective-correct inputs */ MString *vars = mstring_new(); - if (ps->state.smooth_shading) { - mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w;\n"); - mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w;\n"); - mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w;\n"); - mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w;\n"); + if (!z_perspective) { + if (ps->state.smooth_shading) { + mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w;\n"); + mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w;\n"); + mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w;\n"); + mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w;\n"); + } else { + mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w_flat;\n"); + mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w_flat;\n"); + mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w_flat;\n"); + mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w_flat;\n"); + } + mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtxFog / vtx_inv_w, 0.0, 1.0));\n"); + mstring_append(vars, "vec4 pT0 = vtxT0 / vtx_inv_w;\n"); + mstring_append(vars, "vec4 pT1 = vtxT1 / vtx_inv_w;\n"); + mstring_append(vars, "vec4 pT2 = vtxT2 / vtx_inv_w;\n"); } else { - mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w_flat;\n"); - mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w_flat;\n"); - mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w_flat;\n"); - mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w_flat;\n"); + mstring_append(vars, "vec4 pD0 = vtxD0;\n"); + mstring_append(vars, "vec4 pD1 = vtxD1;\n"); + mstring_append(vars, "vec4 pB0 = vtxB0;\n"); + mstring_append(vars, "vec4 pB1 = vtxB1;\n"); + mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtxFog, 0.0, 1.0));\n"); + mstring_append(vars, "vec4 pT0 = vtxT0;\n"); + mstring_append(vars, "vec4 pT1 = vtxT1;\n"); + mstring_append(vars, "vec4 pT2 = vtxT2;\n"); } - mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtxFog / vtx_inv_w, 0.0, 1.0));\n"); - mstring_append(vars, "vec4 pT0 = vtxT0 / vtx_inv_w;\n"); - mstring_append(vars, "vec4 pT1 = vtxT1 / vtx_inv_w;\n"); - mstring_append(vars, "vec4 pT2 = vtxT2 / vtx_inv_w;\n"); + if (ps->state.point_sprite) { assert(!ps->state.rect_tex[3]); mstring_append(vars, "vec4 pT3 = vec4(gl_PointCoord, 1.0, 1.0);\n"); } else { - mstring_append(vars, "vec4 pT3 = vtxT3 / vtx_inv_w;\n"); + if (!z_perspective) { + mstring_append(vars, "vec4 pT3 = vtxT3 / vtx_inv_w;\n"); + } else { + mstring_append(vars, "vec4 pT3 = vtxT3;\n"); + } } mstring_append(vars, "\n"); mstring_append(vars, "vec4 v0 = pD0;\n"); @@ -1198,6 +1218,10 @@ static MString* psh_convert(struct PixelShader *ps) } } + if (z_perspective) { + mstring_append(ps->code, "gl_FragDepth = (1.0/gl_FragCoord.w)/clipRange.y;\n"); + } + for (i = 0; i < ps->num_var_refs; i++) { mstring_append_fmt(vars, "vec4 %s = vec4(0);\n", ps->var_refs[i]); if (strcmp(ps->var_refs[i], "r0") == 0) { @@ -1257,7 +1281,7 @@ static void parse_combiner_output(uint32_t value, struct OutputInfo *out) out->cd_alphablue = flags & 0x40; } -MString *pgraph_gen_psh_glsl(const PshState state) +MString *pgraph_gen_psh_glsl(const PshState state, bool z_perspective) { int i; struct PixelShader ps; @@ -1307,5 +1331,5 @@ MString *pgraph_gen_psh_glsl(const PshState state) ps.final_input.inv_r0 = flags & PS_FINALCOMBINERSETTING_COMPLEMENT_R0; } - return psh_convert(&ps); + return psh_convert(&ps, z_perspective); } diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.h b/hw/xbox/nv2a/pgraph/glsl/psh.h index 1ae0b0db7ed..89f376fd72f 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.h +++ b/hw/xbox/nv2a/pgraph/glsl/psh.h @@ -36,6 +36,6 @@ #define PSH_UBO_BINDING 1 #define PSH_TEX_BINDING 2 -MString *pgraph_gen_psh_glsl(const PshState state); +MString *pgraph_gen_psh_glsl(const PshState state, bool z_perspective); #endif diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index 7bebed71e85..6fa76b6ae7c 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -831,11 +831,12 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, * interpolation manually. OpenGL can't, since we give it a W of 1 to work * around the perspective divide */ mstring_append(body, - " if (oPos.w == 0.0 || isinf(oPos.w)) {\n" - " vtx_inv_w = 1.0;\n" + " if (oPos.w < 0.0) {\n" + " oPos.w = clamp(oPos.w, -1.884467e+019, -5.421011e-20);\n" " } else {\n" - " vtx_inv_w = 1.0 / oPos.w;\n" + " oPos.w = clamp(oPos.w, 5.421011e-20, 1.884467e+019);\n" " }\n" + " vtx_inv_w = 1.0 / oPos.w;\n" " vtx_inv_w_flat = vtx_inv_w;\n" ); @@ -855,10 +856,6 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, "/ surfaceSize.y;\n"); } - if (z_perspective) { - mstring_append(body, " oPos.z = oPos.w;\n"); - } - mstring_append(body, " if (clipRange.y != clipRange.x) {\n"); if (vulkan) { @@ -870,6 +867,12 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, } mstring_append(body, " }\n" + ); + if(z_perspective) { + mstring_append(body, " oPos.xyz *= oPos.w;\n"); + } else { + mstring_append( + body, /* Correct for the perspective divide */ " if (oPos.w < 0.0) {\n" @@ -882,5 +885,5 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, " oPos.w = 1.0;\n" " }\n" ); - + } } diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index a60fbe265dd..6cf76505942 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -75,7 +75,7 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) "}\n"); pgraph_get_glsl_vtx_header(header, state->vulkan, state->smooth_shading, - false, prefix_outputs, false); + false, prefix_outputs, false, state->z_perspective); if (prefix_outputs) { mstring_append(header, @@ -233,28 +233,49 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) } /* Set outputs */ - const char *shade_model_mult = state->smooth_shading ? "vtx_inv_w" : "vtx_inv_w_flat"; - mstring_append_fmt(body, "\n" - " vtxD0 = clamp(oD0, 0.0, 1.0) * %s;\n" - " vtxD1 = clamp(oD1, 0.0, 1.0) * %s;\n" - " vtxB0 = clamp(oB0, 0.0, 1.0) * %s;\n" - " vtxB1 = clamp(oB1, 0.0, 1.0) * %s;\n" - " vtxFog = oFog.x * vtx_inv_w;\n" - " vtxT0 = oT0 * vtx_inv_w;\n" - " vtxT1 = oT1 * vtx_inv_w;\n" - " vtxT2 = oT2 * vtx_inv_w;\n" - " vtxT3 = oT3 * vtx_inv_w;\n" - " gl_Position = oPos;\n" - " gl_PointSize = oPts.x;\n" - // " gl_ClipDistance[0] = oPos.z - oPos.w*clipRange.z;\n" // Near - // " gl_ClipDistance[1] = oPos.w*clipRange.w - oPos.z;\n" // Far - "\n" - "}\n", - shade_model_mult, - shade_model_mult, - shade_model_mult, - shade_model_mult); - + if (state->z_perspective == false) { + const char *shade_model_mult = state->smooth_shading ? "vtx_inv_w" : "vtx_inv_w_flat"; + mstring_append_fmt(body, "\n" + " vtxD0 = clamp(oD0, 0.0, 1.0) * %s;\n" + " vtxD1 = clamp(oD1, 0.0, 1.0) * %s;\n" + " vtxB0 = clamp(oB0, 0.0, 1.0) * %s;\n" + " vtxB1 = clamp(oB1, 0.0, 1.0) * %s;\n" + " vtxFog = oFog.x * vtx_inv_w;\n" + " vtxT0 = oT0 * vtx_inv_w;\n" + " vtxT1 = oT1 * vtx_inv_w;\n" + " vtxT2 = oT2 * vtx_inv_w;\n" + " vtxT3 = oT3 * vtx_inv_w;\n" + " gl_Position = oPos;\n" + " gl_PointSize = oPts.x;\n" + // " gl_ClipDistance[0] = oPos.z - oPos.w*clipRange.z;\n" // Near + // " gl_ClipDistance[1] = oPos.w*clipRange.w - oPos.z;\n" // Far + "\n" + "}\n", + shade_model_mult, + shade_model_mult, + shade_model_mult, + shade_model_mult + ); + } else { + mstring_append_fmt( + body, "\n" + " vtxD0 = clamp(oD0, 0.0, 1.0);\n" + " vtxD1 = clamp(oD1, 0.0, 1.0);\n" + " vtxB0 = clamp(oB0, 0.0, 1.0);\n" + " vtxB1 = clamp(oB1, 0.0, 1.0);\n" + " vtxFog = oFog.x;\n" + " vtxT0 = oT0;\n" + " vtxT1 = oT1;\n" + " vtxT2 = oT2;\n" + " vtxT3 = oT3;\n" + " gl_Position = oPos;\n" + " gl_PointSize = oPts.x;\n" + //" gl_ClipDistance[0] = oPos.w - clipRange.z;\n" // Near + //" gl_ClipDistance[1] = clipRange.w - oPos.w;\n" // Far + "\n" + "}\n" + ); + } /* Return combined header + source */ if (state->vulkan) { // FIXME: Optimize uniforms diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 781cc8dc498..8b565b6e63d 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -173,6 +173,7 @@ typedef struct ShaderBinding { int surface_size_loc; int clip_range_loc; + int clip_range_loc_frag; int vsh_constant_loc; uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index f831dece469..69555e4624d 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -310,6 +310,9 @@ static void update_shader_constant_locations(ShaderBinding *binding) binding->uniform_attrs_loc = uniform_index(&binding->vertex->uniforms, "inlineValue"); + + binding->clip_range_loc_frag = + uniform_index(&binding->fragment->uniforms, "clipRange"); } static void shader_cache_entry_init(Lru *lru, LruNode *node, void *state) @@ -393,7 +396,7 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state) MString *geometry_shader_code = pgraph_gen_geom_glsl( state->polygon_front_mode, state->polygon_back_mode, - state->primitive_mode, state->smooth_shading, true); + state->primitive_mode, state->smooth_shading, true, state->z_perspective); if (geometry_shader_code) { NV2A_VK_DPRINTF("geometry shader: \n%s", mstring_get_str(geometry_shader_code)); @@ -414,7 +417,7 @@ static ShaderBinding *gen_shaders(PGRAPHState *pg, ShaderState *state) mstring_get_str(vertex_shader_code)); mstring_unref(vertex_shader_code); - MString *fragment_shader_code = pgraph_gen_psh_glsl(state->psh); + MString *fragment_shader_code = pgraph_gen_psh_glsl(state->psh, state->z_perspective); NV2A_VK_DPRINTF("fragment shader: \n%s", mstring_get_str(fragment_shader_code)); snode->fragment = pgraph_vk_create_shader_module_from_glsl( @@ -640,16 +643,21 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, pg->surface_binding_dim.height / aa_height); } - if (binding->clip_range_loc != -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] / zmax * 2.0 - 1.0; - float zclip_max = *(float *)&v[1] / zmax * 2.0 - 1.0; + 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] / zmax * 2.0 - 1.0; + float zclip_max = *(float *)&v[1] / zmax * 2.0 - 1.0; + + if (binding->clip_range_loc != -1) { uniform4f(&binding->vertex->uniforms, binding->clip_range_loc, 0, zmax, zclip_min, zclip_max); } + if (binding->clip_range_loc_frag != -1) { + uniform4f(&binding->fragment->uniforms, binding->clip_range_loc_frag, 0, + zmax, zclip_min, zclip_max); + } /* Clipping regions */ unsigned int max_gl_width = pg->surface_binding_dim.width; unsigned int max_gl_height = pg->surface_binding_dim.height;