diff --git a/rpcs3/Emu/RSX/GL/GLDraw.cpp b/rpcs3/Emu/RSX/GL/GLDraw.cpp index 213275b9c4..51bf257aef 100644 --- a/rpcs3/Emu/RSX/GL/GLDraw.cpp +++ b/rpcs3/Emu/RSX/GL/GLDraw.cpp @@ -7,36 +7,14 @@ namespace gl { - GLenum comparison_op(rsx::comparison_function op) + inline GLenum comparison_op(rsx::comparison_function op) { - switch (op) - { - case rsx::comparison_function::never: return GL_NEVER; - case rsx::comparison_function::less: return GL_LESS; - case rsx::comparison_function::equal: return GL_EQUAL; - case rsx::comparison_function::less_or_equal: return GL_LEQUAL; - case rsx::comparison_function::greater: return GL_GREATER; - case rsx::comparison_function::not_equal: return GL_NOTEQUAL; - case rsx::comparison_function::greater_or_equal: return GL_GEQUAL; - case rsx::comparison_function::always: return GL_ALWAYS; - } - fmt::throw_exception("Unsupported comparison op 0x%X", static_cast(op)); + return static_cast(op); } - GLenum stencil_op(rsx::stencil_op op) + inline GLenum stencil_op(rsx::stencil_op op) { - switch (op) - { - case rsx::stencil_op::invert: return GL_INVERT; - case rsx::stencil_op::keep: return GL_KEEP; - case rsx::stencil_op::zero: return GL_ZERO; - case rsx::stencil_op::replace: return GL_REPLACE; - case rsx::stencil_op::incr: return GL_INCR; - case rsx::stencil_op::decr: return GL_DECR; - case rsx::stencil_op::incr_wrap: return GL_INCR_WRAP; - case rsx::stencil_op::decr_wrap: return GL_DECR_WRAP; - } - fmt::throw_exception("Unsupported stencil op 0x%X", static_cast(op)); + return static_cast(op); } GLenum blend_equation(rsx::blend_equation op) @@ -62,76 +40,33 @@ namespace gl } } - GLenum blend_factor(rsx::blend_factor op) + inline GLenum blend_factor(rsx::blend_factor op) { - switch (op) - { - case rsx::blend_factor::zero: return GL_ZERO; - case rsx::blend_factor::one: return GL_ONE; - case rsx::blend_factor::src_color: return GL_SRC_COLOR; - case rsx::blend_factor::one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR; - case rsx::blend_factor::dst_color: return GL_DST_COLOR; - case rsx::blend_factor::one_minus_dst_color: return GL_ONE_MINUS_DST_COLOR; - case rsx::blend_factor::src_alpha: return GL_SRC_ALPHA; - case rsx::blend_factor::one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA; - case rsx::blend_factor::dst_alpha: return GL_DST_ALPHA; - case rsx::blend_factor::one_minus_dst_alpha: return GL_ONE_MINUS_DST_ALPHA; - case rsx::blend_factor::src_alpha_saturate: return GL_SRC_ALPHA_SATURATE; - case rsx::blend_factor::constant_color: return GL_CONSTANT_COLOR; - case rsx::blend_factor::one_minus_constant_color: return GL_ONE_MINUS_CONSTANT_COLOR; - case rsx::blend_factor::constant_alpha: return GL_CONSTANT_ALPHA; - case rsx::blend_factor::one_minus_constant_alpha: return GL_ONE_MINUS_CONSTANT_ALPHA; - } - fmt::throw_exception("Unsupported blend factor 0x%X", static_cast(op)); + return static_cast(op); } - GLenum logic_op(rsx::logic_op op) + inline GLenum logic_op(rsx::logic_op op) { - switch (op) - { - case rsx::logic_op::logic_clear: return GL_CLEAR; - case rsx::logic_op::logic_and: return GL_AND; - case rsx::logic_op::logic_and_reverse: return GL_AND_REVERSE; - case rsx::logic_op::logic_copy: return GL_COPY; - case rsx::logic_op::logic_and_inverted: return GL_AND_INVERTED; - case rsx::logic_op::logic_noop: return GL_NOOP; - case rsx::logic_op::logic_xor: return GL_XOR; - case rsx::logic_op::logic_or: return GL_OR; - case rsx::logic_op::logic_nor: return GL_NOR; - case rsx::logic_op::logic_equiv: return GL_EQUIV; - case rsx::logic_op::logic_invert: return GL_INVERT; - case rsx::logic_op::logic_or_reverse: return GL_OR_REVERSE; - case rsx::logic_op::logic_copy_inverted: return GL_COPY_INVERTED; - case rsx::logic_op::logic_or_inverted: return GL_OR_INVERTED; - case rsx::logic_op::logic_nand: return GL_NAND; - case rsx::logic_op::logic_set: return GL_SET; - } - fmt::throw_exception("Unsupported logic op 0x%X", static_cast(op)); + return static_cast(op); } - GLenum front_face(rsx::front_face op) + inline GLenum front_face(rsx::front_face op) { - //NOTE: RSX face winding is always based off of upper-left corner like vulkan, but GL is bottom left - //shader_window_origin register does not affect this - //verified with Outrun Online Arcade (window_origin::top) and DS2 (window_origin::bottom) - //correctness of face winding checked using stencil test (GOW collection shadows) - switch (op) - { - case rsx::front_face::cw: return GL_CCW; - case rsx::front_face::ccw: return GL_CW; - } - fmt::throw_exception("Unsupported front face 0x%X", static_cast(op)); + // NOTE: RSX face winding is always based off of upper-left corner like vulkan, but GL is bottom left + // shader_window_origin register does not affect this + // verified with Outrun Online Arcade (window_origin::top) and DS2 (window_origin::bottom) + // correctness of face winding checked using stencil test (GOW collection shadows) + return static_cast(op) ^ 1u; } - GLenum cull_face(rsx::cull_face op) + inline GLenum cull_face(rsx::cull_face op) { - switch (op) - { - case rsx::cull_face::front: return GL_FRONT; - case rsx::cull_face::back: return GL_BACK; - case rsx::cull_face::front_and_back: return GL_FRONT_AND_BACK; - } - fmt::throw_exception("Unsupported cull face 0x%X", static_cast(op)); + return static_cast(op); + } + + inline GLenum polygon_mode(rsx::polygon_mode mode) + { + return static_cast(mode); } } @@ -335,6 +270,10 @@ void GLGSRender::update_draw_state() // Clip planes gl_state.clip_planes((current_vertex_program.output_mask >> CELL_GCM_ATTRIB_OUTPUT_UC0) & 0x3F); + // Polygon mode. We can only have one polygon mode active at one time, so we need to determine if any face is currently culled. + const bool show_back = REGS(m_ctx)->cull_face_enabled() && REGS(m_ctx)->cull_face_mode() == rsx::cull_face::front; + gl_state.polygon_mode(gl::polygon_mode(show_back ? REGS(m_ctx)->polygon_mode_back() : REGS(m_ctx)->polygon_mode_front())); + //TODO //NV4097_SET_ANISO_SPREAD //NV4097_SET_SPECULAR_ENABLE @@ -342,9 +281,6 @@ void GLGSRender::update_draw_state() //NV4097_SET_FLAT_SHADE_OP //NV4097_SET_EDGE_FLAG //NV4097_SET_COLOR_KEY_COLOR - //NV4097_SET_SHADER_CONTROL - //NV4097_SET_ZMIN_MAX_CONTROL - //NV4097_SET_ANTI_ALIASING_CONTROL //NV4097_SET_CLIP_ID_TEST_ENABLE // For OGL Z range is updated every draw as it is separate from viewport config diff --git a/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp b/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp index ffc4fe38f1..9835a5891f 100644 --- a/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp +++ b/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp @@ -17,6 +17,7 @@ namespace gl const u32 STENCIL_FRONT_OP = 0xFFFF0007; const u32 STENCIL_BACK_OP = 0xFFFF0008; const u32 STENCIL_BACK_MASK = 0xFFFF0009; + const u32 POLYGON_MODE = 0xFFFF000A; std::unordered_map properties = {}; std::unordered_map> indexed_properties = {}; @@ -353,6 +354,15 @@ namespace gl } } + void polygon_mode(GLenum mode) + { + if (!test_and_set_property(POLYGON_MODE, mode)) + { + // Note: GL4+ does not support separate polygon mode per-face-type + glPolygonMode(GL_FRONT_AND_BACK, mode); + } + } + void use_program(GLuint program) { if (current_program == program) diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index c9621c3282..8e1dd698fe 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -1321,6 +1321,16 @@ namespace rsx { return decode().enabled(); } + + polygon_mode polygon_mode_front() const + { + return decode().front_polygon_mode(); + } + + polygon_mode polygon_mode_back() const + { + return decode().back_polygon_mode(); + } }; extern rsx_state method_registers;