diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 6dfa6bce2c..61964c911d 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -330,8 +330,11 @@ #define NV_PGRAPH_COMBINESPECFOG0 0x00001944 #define NV_PGRAPH_COMBINESPECFOG1 0x00001948 #define NV_PGRAPH_CONTROL_0 0x0000194C +# define NV_PGRAPH_CONTROL_0_ALPHAREF 0x000000FF +# define NV_PGRAPH_CONTROL_0_ALPHAFUNC 0x00000F00 +# define NV_PGRAPH_CONTROL_0_ALPHATESTENABLE (1 << 12) # define NV_PGRAPH_CONTROL_0_ZENABLE (1 << 14) -# define NV_PGRAPH_CONTROL_0_ZFUNC 0x000F0000 +# define NV_PGRAPH_CONTROL_0_ZFUNC 0x000F0000 # define NV_PGRAPH_CONTROL_0_ZFUNC_NEVER 0 # define NV_PGRAPH_CONTROL_0_ZFUNC_LESS 1 # define NV_PGRAPH_CONTROL_0_ZFUNC_EQUAL 2 @@ -637,9 +640,12 @@ # define NV097_SET_CONTROL0 0x00970290 # define NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE (1 << 0) # define NV097_SET_CONTROL0_Z_FORMAT (1 << 12) +# define NV097_SET_ALPHA_TEST_ENABLE 0x00970300 # define NV097_SET_BLEND_ENABLE 0x00970304 # define NV097_SET_DEPTH_TEST_ENABLE 0x0097030C -# define NV097_SET_STENCIL_TEST_ENABLE 0x0097032c +# define NV097_SET_STENCIL_TEST_ENABLE 0x0097032C +# define NV097_SET_ALPHA_FUNC 0x0097033C +# define NV097_SET_ALPHA_REF 0x00970340 # define NV097_SET_BLEND_FUNC_SFACTOR 0x00970344 # define NV097_SET_BLEND_FUNC_SFACTOR_V_ZERO 0x0000 # define NV097_SET_BLEND_FUNC_SFACTOR_V_ONE 0x0001 @@ -921,6 +927,7 @@ static const GLenum pgraph_stencil_func_map[] = { }; static const GLenum pgraph_stencil_op_map[] = { + 0, GL_KEEP, GL_ZERO, GL_REPLACE, @@ -1122,6 +1129,9 @@ typedef struct ShaderState { bool rect_tex[4]; + bool alpha_test; + enum AlphaFunc alpha_func; + bool fixed_function; @@ -2191,7 +2201,8 @@ static ShaderBinding* generate_shaders(const ShaderState state) /* constant_0, constant_1, */ state.final_inputs_0, state.final_inputs_1, /* final_constant_0, final_constant_1, */ - state.rect_tex); + state.rect_tex, + state.alpha_test, state.alpha_func); const char *fragment_shader_code_str = qstring_get_str(fragment_shader_code); @@ -2296,6 +2307,11 @@ static void pgraph_bind_shaders(PGRAPHState *pg) .final_inputs_0 = pg->regs[NV_PGRAPH_COMBINESPECFOG0], .final_inputs_1 = pg->regs[NV_PGRAPH_COMBINESPECFOG1], + .alpha_test = pg->regs[NV_PGRAPH_CONTROL_0] + & NV_PGRAPH_CONTROL_0_ALPHATESTENABLE, + .alpha_func = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAFUNC), + /* fixed function stuff */ .fixed_function = fixed_function, @@ -2390,6 +2406,13 @@ static void pgraph_bind_shaders(PGRAPHState *pg) } } } + GLint alpha_ref_loc = glGetUniformLocation(pg->shader_binding->gl_program, + "alphaRef"); + if (alpha_ref_loc != -1) { + float alpha_ref = GET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAREF) / 255.0; + glUniform1f(alpha_ref_loc, alpha_ref); + } @@ -2423,9 +2446,10 @@ static void pgraph_bind_shaders(PGRAPHState *pg) -1.0, 1.0, -m43/m33, 1.0 }; - GLint viewLoc = glGetUniformLocation(pg->shader_binding->gl_program, "invViewport"); - assert(viewLoc != -1); - glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &invViewport[0]); + GLint view_loc = glGetUniformLocation(pg->shader_binding->gl_program, + "invViewport"); + assert(view_loc != -1); + glUniformMatrix4fv(view_loc, 1, GL_FALSE, &invViewport[0]); } else if (vertex_program) { /* update vertex program constants */ @@ -2442,7 +2466,8 @@ static void pgraph_bind_shaders(PGRAPHState *pg) constant->dirty = false; } - GLint loc = glGetUniformLocation(pg->shader_binding->gl_program, "clipRange"); + GLint loc = glGetUniformLocation(pg->shader_binding->gl_program, + "clipRange"); if (loc != -1) { glUniform2f(loc, zclip_min, zclip_max); } @@ -2860,8 +2885,6 @@ static void pgraph_init(PGRAPHState *pg) /* Check context capabilities */ assert(glo_check_extension("GL_EXT_texture_compression_s3tc")); - assert(glo_check_extension("GL_EXT_framebuffer_object")); - assert(glo_check_extension("GL_ARB_texture_rectangle")); assert(glo_check_extension("GL_ARB_vertex_array_bgra")); @@ -2870,20 +2893,21 @@ static void pgraph_init(PGRAPHState *pg) glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &max_vertex_attributes); assert(max_vertex_attributes >= NV2A_VERTEXSHADER_ATTRIBUTES); + glGenFramebuffers(1, &pg->gl_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, pg->gl_framebuffer); + /* need a valid framebuffer to start with */ glGenTextures(1, &pg->gl_color_buffer); glBindTexture(GL_TEXTURE_2D, pg->gl_color_buffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pg->gl_color_buffer, 0); + assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); - glViewport(0, 0, 640, 480); - //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); pg->shaders_dirty = true; @@ -2934,10 +2958,10 @@ static unsigned int kelvin_map_stencil_op(uint32_t parameter) case NV097_SET_STENCIL_OP_V_KEEP: op = NV_PGRAPH_CONTROL_2_STENCIL_OP_V_KEEP; break; case NV097_SET_STENCIL_OP_V_ZERO: - op = NV097_SET_STENCIL_OP_V_ZERO; break; + op = NV_PGRAPH_CONTROL_2_STENCIL_OP_V_ZERO; break; case NV097_SET_STENCIL_OP_V_REPLACE: op = NV_PGRAPH_CONTROL_2_STENCIL_OP_V_REPLACE; break; - case NV_PGRAPH_CONTROL_2_STENCIL_OP_V_INCRSAT: + case NV097_SET_STENCIL_OP_V_INCRSAT: op = NV_PGRAPH_CONTROL_2_STENCIL_OP_V_INCRSAT; break; case NV097_SET_STENCIL_OP_V_DECRSAT: op = NV_PGRAPH_CONTROL_2_STENCIL_OP_V_DECRSAT; break; @@ -3285,6 +3309,11 @@ static void pgraph_method(NV2AState *d, NV_PGRAPH_SETUPRASTER_Z_FORMAT, z_format); } + case NV097_SET_ALPHA_TEST_ENABLE: + SET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHATESTENABLE, parameter); + pg->shaders_dirty = true; + break; case NV097_SET_BLEND_ENABLE: SET_MASK(pg->regs[NV_PGRAPH_BLEND], NV_PGRAPH_BLEND_EN, parameter); break; @@ -3297,7 +3326,15 @@ static void pgraph_method(NV2AState *d, SET_MASK(pg->regs[NV_PGRAPH_CONTROL_1], NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE, parameter); break; - + case NV097_SET_ALPHA_FUNC: + SET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAFUNC, parameter & 0xF); + pg->shaders_dirty = true; + break; + case NV097_SET_ALPHA_REF: + SET_MASK(pg->regs[NV_PGRAPH_CONTROL_0], + NV_PGRAPH_CONTROL_0_ALPHAREF, parameter); + break; case NV097_SET_BLEND_FUNC_SFACTOR: { unsigned int factor; switch (parameter) { @@ -4008,13 +4045,13 @@ static void pgraph_method(NV2AState *d, glEnable(GL_SCISSOR_TEST); - unsigned int xmin = GET_MASK(d->pgraph.regs[NV_PGRAPH_CLEARRECTX], + unsigned int xmin = GET_MASK(pg->regs[NV_PGRAPH_CLEARRECTX], NV_PGRAPH_CLEARRECTX_XMIN); - unsigned int xmax = GET_MASK(d->pgraph.regs[NV_PGRAPH_CLEARRECTX], + unsigned int xmax = GET_MASK(pg->regs[NV_PGRAPH_CLEARRECTX], NV_PGRAPH_CLEARRECTX_XMAX); - unsigned int ymin = GET_MASK(d->pgraph.regs[NV_PGRAPH_CLEARRECTY], + unsigned int ymin = GET_MASK(pg->regs[NV_PGRAPH_CLEARRECTY], NV_PGRAPH_CLEARRECTY_YMIN); - unsigned int ymax = GET_MASK(d->pgraph.regs[NV_PGRAPH_CLEARRECTY], + unsigned int ymax = GET_MASK(pg->regs[NV_PGRAPH_CLEARRECTY], NV_PGRAPH_CLEARRECTY_YMAX); glScissor(xmin, pg->surface_shape.clip_height-ymax, xmax-xmin, ymax-ymin); diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index fd8e964ea8..f19f484bbe 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -200,6 +200,8 @@ struct PixelShader { //uint32_t compare_mode, dot_mapping, input_texture; bool rect_tex[4]; + bool alpha_test; + enum AlphaFunc alpha_func; QString *varE, *varF; QString *code; @@ -603,7 +605,27 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append_fmt(preflight, "uniform vec4 %s;\n", ps->const_refs[i]); } - + if (ps->alpha_test && ps->alpha_func != ALPHA_FUNC_ALWAYS) { + qstring_append_fmt(preflight, "uniform float alphaRef;\n"); + if (ps->alpha_func == ALPHA_FUNC_NEVER) { + qstring_append(ps->code, "discard;\n"); + } else { + const char* alpha_op; + switch (ps->alpha_func) { + case ALPHA_FUNC_LESS: alpha_op = "<"; break; + case ALPHA_FUNC_EQUAL: alpha_op = "=="; break; + case ALPHA_FUNC_LEQUAL: alpha_op = "<="; break; + case ALPHA_FUNC_GREATER: alpha_op = ">"; break; + case ALPHA_FUNC_NOTEQUAL: alpha_op = "!="; break; + case ALPHA_FUNC_GEQUAL: alpha_op = ">="; break; + default: + assert(false); + break; + } + qstring_append_fmt(ps->code, "if (!(r0.a %s alphaRef)) discard;\n", + alpha_op); + } + } QString *final = qstring_new(); qstring_append(final, qstring_get_str(preflight)); @@ -661,7 +683,8 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, /*uint32_t constant_0[8], uint32_t constant_1[8],*/ uint32_t final_inputs_0, uint32_t final_inputs_1, /*uint32_t final_constant_0, uint32_t final_constant_1,*/ - const bool rect_tex[4]) + const bool rect_tex[4], + bool alpha_test, enum AlphaFunc alpha_func) { int i; struct PixelShader ps; @@ -674,6 +697,9 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, ps.rect_tex[i] = rect_tex[i]; } + ps.alpha_test = alpha_test; + ps.alpha_func = alpha_func; + ps.input_tex[0] = -1; ps.input_tex[1] = 0; ps.input_tex[2] = (other_stage_input >> 16) & 0xF; diff --git a/hw/xbox/nv2a_psh.h b/hw/xbox/nv2a_psh.h index 7cd6771f94..51d2623f82 100644 --- a/hw/xbox/nv2a_psh.h +++ b/hw/xbox/nv2a_psh.h @@ -24,6 +24,17 @@ #include "qapi/qmp/qstring.h" +enum AlphaFunc { + ALPHA_FUNC_NEVER, + ALPHA_FUNC_LESS, + ALPHA_FUNC_EQUAL, + ALPHA_FUNC_LEQUAL, + ALPHA_FUNC_GREATER, + ALPHA_FUNC_NOTEQUAL, + ALPHA_FUNC_GEQUAL, + ALPHA_FUNC_ALWAYS, +}; + QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, uint32_t other_stage_input, const uint32_t rgb_inputs[8], @@ -33,6 +44,7 @@ QString *psh_translate(uint32_t combiner_control, uint32_t shader_stage_program, /*uint32_t constant_0[8], uint32_t constant_1[8],*/ uint32_t final_inputs_0, uint32_t final_inputs_1, /*uint32_t final_constant_0, uint32_t final_constant_1,*/ - const bool rect_tex[4]); + const bool rect_tex[4], + bool alpha_test, enum AlphaFunc alpha_func); #endif \ No newline at end of file