diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 78a9091eb54..eb14b1914d1 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -461,6 +461,7 @@ # define NV_PGRAPH_CONTROL_2_STENCIL_OP_V_INCR 7 # define NV_PGRAPH_CONTROL_2_STENCIL_OP_V_DECR 8 #define NV_PGRAPH_CONTROL_3 0x00001958 +# define NV_PGRAPH_CONTROL_3_TEXTURE_PERSPECTIVE_ENABLE (1 << 6) # define NV_PGRAPH_CONTROL_3_SHADEMODE (1 << 7) # define NV_PGRAPH_CONTROL_3_SHADEMODE_FLAT 0 # define NV_PGRAPH_CONTROL_3_SHADEMODE_SMOOTH 1 @@ -619,6 +620,7 @@ #define NV_PGRAPH_WINDOWCLIPY6 0x00001A7C #define NV_PGRAPH_WINDOWCLIPY7 0x00001A80 #define NV_PGRAPH_ZCOMPRESSOCCLUDE 0x00001A84 +# define NV_PGRAPH_ZCOMPRESSOCCLUDE_CULL_NEAR_FAR_EN (1 << 0) # define NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN (1 << 4) # define NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CULL 0 # define NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CLAMP 1 @@ -879,6 +881,7 @@ # define NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE (1 << 0) # define NV097_SET_CONTROL0_Z_FORMAT (1 << 12) # define NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE (1 << 16) +# define NV097_SET_CONTROL0_TEXTURE_PERSPECTIVE_ENABLE (1 << 20) # define NV097_SET_COLOR_MATERIAL 0x00000298 # define NV097_SET_FOG_MODE 0x0000029C # define NV097_SET_FOG_MODE_V_LINEAR 0x2601 @@ -1233,6 +1236,7 @@ # define NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN 0x000000F0 # define NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN_CULL 0 # define NV097_SET_ZMIN_MAX_CONTROL_ZCLAMP_EN_CLAMP 1 +# define NV097_SET_ZMIN_MAX_CONTROL_CULL_NEAR_FAR_EN_TRUE (1 << 0) # define NV097_SET_ANTI_ALIASING_CONTROL 0x00001D7C # define NV097_SET_ANTI_ALIASING_CONTROL_ENABLE (1 << 0) # define NV097_SET_ZSTENCIL_CLEAR_VALUE 0x00001D8C diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index ad1c21f4a2f..103bd32444b 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -219,7 +219,9 @@ static void generate_shaders(ShaderBinding *binding) state->polygon_back_mode, state->primitive_mode, state->smooth_shading, - false); + false, + state->z_perspective || state->texture_perspective + ); if (geometry_shader_code) { const char* geometry_shader_code_str = mstring_get_str(geometry_shader_code); @@ -891,6 +893,17 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, float zclip_max = *(float *)&v[1]; glUniform4f(binding->clip_range_loc, 0, zmax, zclip_min, zclip_max); } + if (binding->zbias_loc != -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; + } + glUniform1f(binding->zbias_loc, zbias); + } if (binding->depth_offset_loc != -1) { float zbias = 0.0f; @@ -1029,7 +1042,6 @@ 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; } ShaderBinding *old_binding = r->shader_binding; @@ -1069,7 +1081,6 @@ void pgraph_gl_bind_shaders(PGRAPHState *pg) NV2A_GL_DGROUP_END(); -update_constants: assert(r->shader_binding); assert(r->shader_binding->initialized); shader_update_constants(pg, r->shader_binding, binding_changed); diff --git a/hw/xbox/nv2a/pgraph/glsl/common.c b/hw/xbox/nv2a/pgraph/glsl/common.c index f2745bb7aae..ffe0b700831 100644 --- a/hw/xbox/nv2a/pgraph/glsl/common.c +++ b/hw/xbox/nv2a/pgraph/glsl/common.c @@ -52,5 +52,9 @@ MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bo suffix_s); } + if (location) { + mstring_append(out, " layout(location = 9) "); + } + mstring_append_fmt(out, "%s float %sdepthBuf%s;\n", in_out_s, prefix_s, suffix_s); return out; } 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 df265b96d3a..e5057d928ec 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,14 +175,15 @@ 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, "void emit_vertex(int index, int _unused) {\n" " gl_Position = gl_in[index].gl_Position;\n" " gl_PointSize = gl_in[index].gl_PointSize;\n" + " depthBuf = v_depthBuf[index];\n" " vtxD0 = v_vtxD0[index];\n" " vtxD1 = v_vtxD1[index];\n" " vtxB0 = v_vtxB0[index];\n" @@ -198,6 +200,7 @@ MString *pgraph_gen_geom_glsl(enum ShaderPolygonMode polygon_front_mode, "void emit_vertex(int index, int provoking_index) {\n" " gl_Position = gl_in[index].gl_Position;\n" " gl_PointSize = gl_in[index].gl_PointSize;\n" + " depthBuf = v_depthBuf[index];\n" " vtxD0 = v_vtxD0[provoking_index];\n" " vtxD1 = v_vtxD1[provoking_index];\n" " vtxB0 = v_vtxB0[provoking_index];\n" 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 a664281f09e..ea2dce81d88 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.c +++ b/hw/xbox/nv2a/pgraph/glsl/psh.c @@ -733,11 +733,13 @@ static void apply_convolution_filter(const struct PixelShader *ps, MString *vars static MString* psh_convert(struct PixelShader *ps) { + bool z_perspective = ps->state.z_perspective; + bool tex = ps->state.texture_perspective; const char *u = ps->state.vulkan ? "" : "uniform "; // FIXME: Remove 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, tex || z_perspective); if (ps->state.vulkan) { mstring_append_fmt(preflight, @@ -869,6 +871,43 @@ static MString* psh_convert(struct PixelShader *ps) } /* Depth clipping */ + /* OGL/VK zbias is applied to z coord, so we need to apply it + * to w coord manually when w-buffering is enabled */ + mstring_append(clip, "float w = depthBuf + zbias;\n"); + if (ps->state.vulkan) { + mstring_append(clip, "float z = gl_FragCoord.z;\n"); + } else { + /* Changing clipping range to [-1, 1] here + * prevents floating point precission loss in OGL */ + mstring_append(clip, "float z = gl_FragCoord.z * 2.0 - 1.0;\n"); + } + + const char *z = ps->state.z_perspective ? "w" : "z * clipRange.y"; + if (ps->state.clipping) { + mstring_append_fmt(clip, + "if (%s < clipRange.z || clipRange.w < %s) {\n" + " discard;\n" + "}\n", z, z + ); + } + if (ps->state.near_far) { + /* FIXME: set correct custom clip planes + * (see pgraph ZMinMaxControl tests)*/ + mstring_append(clip, + // near plane + "if (z * clipRange.y < clipRange.z*2.0/3.0) {\n" + " discard;\n" + "}\n" + // z=n->f far plane + //"if (z * clipRange.y > clipRange.w*1.2) {\n" + // z=inc far plane + "if (z * clipRange.y > clipRange.w + 2.0*(clipRange.w + clipRange.z)/(clipRange.w - clipRange.z) - 1) {\n" + " discard;\n" + "}\n" + ); + } + + /* calculate perspective-correct inputs if (ps->state.depth_clipping) { if (ps->state.z_perspective) { mstring_append( @@ -877,7 +916,7 @@ static MString* psh_convert(struct PixelShader *ps) " discard;\n" "}\n"); } else { - /* Take care of floating point precision problems. MS dashboard + Take care of floating point precision problems. MS dashboard * outputs exactly 0.0 z-coordinates and then our fixed function * vertex shader outputs -w as the z-coordinate when OpenGL is * used. Since -w/w = -1, this should give us exactly 0.0 as @@ -893,7 +932,7 @@ static MString* psh_convert(struct PixelShader *ps) * depth buffer.) Radeon OpenGL problem could also be fixed by using * glClipControl(), but it requires OpenGL 4.5. * Above is based on experiments with Linux and Mesa. - */ + if (ps->state.vulkan) { mstring_append( clip, "if (gl_FragCoord.z*clipRange.y < clipRange.z ||\n" @@ -908,7 +947,7 @@ static MString* psh_convert(struct PixelShader *ps) "}\n"); } } - } + } */ MString *vars = mstring_new(); mstring_append(vars, "vec4 pD0 = vtxD0;\n"); @@ -919,6 +958,7 @@ static MString* psh_convert(struct PixelShader *ps) mstring_append(vars, "vec4 pT0 = vtxT0;\n"); mstring_append(vars, "vec4 pT1 = vtxT1;\n"); mstring_append(vars, "vec4 pT2 = vtxT2;\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"); @@ -1245,6 +1285,17 @@ static MString* psh_convert(struct PixelShader *ps) } } + /* NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE enables w-buffering + * not only gl_Position gets divided by the homogeneous coordinate, + * but also all other interpolated variables, which requires + * the division to be after the rasterization */ + if (z_perspective) { + mstring_append(ps->code, "gl_FragDepth = w / clipRange.y;\n"); + } + else if (!ps->state.vulkan) { + mstring_append(ps->code, "gl_FragDepth = z;\n"); + } + for (int 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) { diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 24128266470..5baba844268 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -423,9 +423,19 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, " oPos = tPosition * compositeMat;\n" " oPos.w = clampAwayZeroInf(oPos.w);\n" + " depthBuf = (invViewport * vec4(oPos.xyz/oPos.w, oPos.w)).w;\n" " oPos = invViewport * oPos;\n" ); + if (!state->texture_perspective) { + mstring_append(body, + " if (oPos.w >= 0.0) {\n" + " oPos.xyz /= oPos.w;\n" + " oPos.w = 1.0;\n" + " }\n" + ); + } + mstring_append(body," oPos = invViewport * oPos;\n"); if (state->vulkan) { mstring_append(body, " oPos.y *= -1;\n"); } diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index 0530e7ea7b5..eb8ca2513fc 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -33,6 +33,7 @@ #include #include "hw/xbox/nv2a/pgraph/vsh.h" +#include "hw/xbox/nv2a/pgraph/shaders.h" #include "common.h" #include "vsh-prog.h" @@ -790,11 +791,13 @@ static const char* vsh_header = "}\n"; void pgraph_gen_vsh_prog_glsl(uint16_t version, - const uint32_t *tokens, - unsigned int length, - bool vulkan, + const ShaderState *state, MString *header, MString *body) { + const uint32_t *tokens = (uint32_t *)state->program_data; + unsigned int length = state->program_length; + bool texture = state->texture_perspective; + bool vulkan = state->vulkan; mstring_append(header, vsh_header); @@ -837,6 +840,7 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, } mstring_append(body, + " depthBuf = oPos.w;\n" " oPos.z = oPos.z / clipRange.y;\n" " oPos.w = clampAwayZeroInf(oPos.w);\n" diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.h b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.h index cffb6be3b34..206047c9593 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.h +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.h @@ -28,8 +28,7 @@ #ifndef HW_XBOX_NV2A_PGRAPH_GLSL_VSH_PROG_H #define HW_XBOX_NV2A_PGRAPH_GLSL_VSH_PROG_H -void pgraph_gen_vsh_prog_glsl(uint16_t version, const uint32_t *tokens, - unsigned int length, - bool vulkan, MString *header, MString *body); +void pgraph_gen_vsh_prog_glsl(uint16_t version, const ShaderState *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 d92c8b2fb3d..2c873d9319c 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -85,10 +85,11 @@ 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->texture_perspective || state->z_perspective); if (prefix_outputs) { mstring_append(header, + "#define depthBuf v_depthBuf\n" "#define vtxD0 v_vtxD0\n" "#define vtxD1 v_vtxD1\n" "#define vtxB0 v_vtxB0\n" @@ -148,10 +149,8 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) if (state->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); + pgraph_gen_vsh_prog_glsl(VSH_VERSION_XVS, state, header, body); + } else { assert(false); } @@ -241,6 +240,7 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) } /* Set outputs */ + mstring_append(body, "\n" " vtxD0 = clamp(oD0, 0.0, 1.0);\n" " vtxD1 = clamp(oD1, 0.0, 1.0);\n" @@ -252,19 +252,9 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) " vtxT2 = oT2;\n" " vtxT3 = oT3;\n" " gl_PointSize = oPts.x;\n" - ); - - if (state->vulkan) { - mstring_append(body, " gl_Position = oPos;\n" - ); - } else { - mstring_append(body, - " gl_Position = vec4(oPos.x, oPos.y, 2.0*oPos.z - oPos.w, oPos.w);\n" - ); - } - - mstring_append(body, "}\n"); + "}\n" + ); /* Return combined header + source */ if (state->vulkan) { diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 9db475796e7..94b557de8f3 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -1073,6 +1073,12 @@ DEF_METHOD(NV097, SET_CONTROL0) PG_SET_MASK(NV_PGRAPH_CONTROL_0, NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE, z_perspective); + + bool texture_perspective = + parameter & NV097_SET_CONTROL0_TEXTURE_PERSPECTIVE_ENABLE; + PG_SET_MASK(NV_PGRAPH_CONTROL_3, + NV_PGRAPH_CONTROL_3_TEXTURE_PERSPECTIVE_ENABLE, + texture_perspective); } DEF_METHOD(NV097, SET_COLOR_MATERIAL) @@ -2683,6 +2689,8 @@ DEF_METHOD(NV097, SET_ZMIN_MAX_CONTROL) assert(!"Invalid zclamp value"); break; } + PG_SET_MASK(NV_PGRAPH_ZCOMPRESSOCCLUDE, NV_PGRAPH_ZCOMPRESSOCCLUDE_CULL_NEAR_FAR_EN, + GET_MASK(parameter, NV097_SET_ZMIN_MAX_CONTROL_CULL_NEAR_FAR_EN_TRUE)); } DEF_METHOD(NV097, SET_ANTI_ALIASING_CONTROL) diff --git a/hw/xbox/nv2a/pgraph/psh.h b/hw/xbox/nv2a/pgraph/psh.h index c54e650e994..e9de0cfda52 100644 --- a/hw/xbox/nv2a/pgraph/psh.h +++ b/hw/xbox/nv2a/pgraph/psh.h @@ -85,8 +85,11 @@ typedef struct PshState { bool window_clip_exclusive; bool smooth_shading; + + bool texture_perspective; bool depth_clipping; bool z_perspective; + bool near_far; } PshState; #endif diff --git a/hw/xbox/nv2a/pgraph/shaders.c b/hw/xbox/nv2a/pgraph/shaders.c index 6e13f2084ca..fc2f4c635a5 100644 --- a/hw/xbox/nv2a/pgraph/shaders.c +++ b/hw/xbox/nv2a/pgraph/shaders.c @@ -91,11 +91,15 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) } /* vertex program stuff */ - state.vertex_program = vertex_program, + state.vertex_program = vertex_program; state.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.z_perspective; + state.texture_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3) & + NV_PGRAPH_CONTROL_3_TEXTURE_PERSPECTIVE_ENABLE; + state.psh.texture_perspective = state.texture_perspective; state.point_params_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D), NV_PGRAPH_CSV0_D_POINTPARAMSENABLE); state.point_size = @@ -118,6 +122,9 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) NV_PGRAPH_CONTROL_3_SHADEMODE_SMOOTH; state.psh.smooth_shading = state.smooth_shading; + state.psh.near_far = pgraph_reg_r(pg, NV_PGRAPH_ZCOMPRESSOCCLUDE) & + NV_PGRAPH_ZCOMPRESSOCCLUDE_CULL_NEAR_FAR_EN; + state.psh.depth_clipping = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_ZCOMPRESSOCCLUDE), NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN) == NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CULL; diff --git a/hw/xbox/nv2a/pgraph/shaders.h b/hw/xbox/nv2a/pgraph/shaders.h index 71febe2e2f8..9c216a971b4 100644 --- a/hw/xbox/nv2a/pgraph/shaders.h +++ b/hw/xbox/nv2a/pgraph/shaders.h @@ -89,6 +89,7 @@ typedef struct ShaderState { uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE]; int program_length; bool z_perspective; + bool texture_perspective; /* primitive format for geometry shader */ enum ShaderPolygonMode polygon_front_mode; diff --git a/hw/xbox/nv2a/pgraph/vk/draw.c b/hw/xbox/nv2a/pgraph/vk/draw.c index f34b6aa094f..c5c115a079a 100644 --- a/hw/xbox/nv2a/pgraph/vk/draw.c +++ b/hw/xbox/nv2a/pgraph/vk/draw.c @@ -830,9 +830,7 @@ static void create_pipeline(PGRAPHState *pg) NV_PGRAPH_SETUPRASTER_CULLCTRL); assert(cull_face < ARRAY_SIZE(pgraph_cull_face_vk_map)); rasterizer.cullMode = pgraph_cull_face_vk_map[cull_face]; - } else { - rasterizer.cullMode = VK_CULL_MODE_NONE; - } + } VkPipelineMultisampleStateCreateInfo multisampling = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index eb0726ac2fe..eb67d01aec1 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_floc; int depth_offset_loc; diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index 421a81ba608..f49979ad316 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -313,6 +313,12 @@ 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"); + + binding->zbias_loc = + uniform_index(&binding->fragment->uniforms, "zbias"); } static void shader_cache_entry_init(Lru *lru, LruNode *node, void *state) @@ -396,7 +402,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 || state->texture_perspective); if (geometry_shader_code) { NV2A_VK_DPRINTF("geometry shader: \n%s", mstring_get_str(geometry_shader_code)); @@ -684,6 +690,22 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, zbias); } + if (binding->clip_range_loc_frag != -1) { + uniform4f(&binding->fragment->uniforms, binding->clip_range_loc_frag, 0, + zmax, zclip_min, zclip_max); + } + if (binding->zbias_loc != -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; + } + uniform1f(&binding->fragment->uniforms, binding->zbias_loc, zbias); + } + /* Clipping regions */ unsigned int max_gl_width = pg->surface_binding_dim.width; unsigned int max_gl_height = pg->surface_binding_dim.height;