diff options
| -rw-r--r-- | src/video_core/pica.h | 27 | ||||
| -rw-r--r-- | src/video_core/rasterizer.cpp | 59 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/pica_to_gl.h | 31 |
7 files changed, 135 insertions, 8 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index fbc95a4b6..f8313d20d 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -162,6 +162,25 @@ struct Regs { | |||
| 162 | ETC1A4 = 13, // compressed | 162 | ETC1A4 = 13, // compressed |
| 163 | }; | 163 | }; |
| 164 | 164 | ||
| 165 | enum class LogicOp : u32 { | ||
| 166 | Clear = 0, | ||
| 167 | And = 1, | ||
| 168 | AndReverse = 2, | ||
| 169 | Copy = 3, | ||
| 170 | Set = 4, | ||
| 171 | CopyInverted = 5, | ||
| 172 | NoOp = 6, | ||
| 173 | Invert = 7, | ||
| 174 | Nand = 8, | ||
| 175 | Or = 9, | ||
| 176 | Nor = 10, | ||
| 177 | Xor = 11, | ||
| 178 | Equiv = 12, | ||
| 179 | AndInverted = 13, | ||
| 180 | OrReverse = 14, | ||
| 181 | OrInverted = 15, | ||
| 182 | }; | ||
| 183 | |||
| 165 | static unsigned NibblesPerPixel(TextureFormat format) { | 184 | static unsigned NibblesPerPixel(TextureFormat format) { |
| 166 | switch (format) { | 185 | switch (format) { |
| 167 | case TextureFormat::RGBA8: | 186 | case TextureFormat::RGBA8: |
| @@ -413,12 +432,8 @@ struct Regs { | |||
| 413 | } alpha_blending; | 432 | } alpha_blending; |
| 414 | 433 | ||
| 415 | union { | 434 | union { |
| 416 | enum Op { | 435 | BitField<0, 4, LogicOp> logic_op; |
| 417 | Set = 4, | 436 | }; |
| 418 | }; | ||
| 419 | |||
| 420 | BitField<0, 4, Op> op; | ||
| 421 | } logic_op; | ||
| 422 | 437 | ||
| 423 | union { | 438 | union { |
| 424 | BitField< 0, 8, u32> r; | 439 | BitField< 0, 8, u32> r; |
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 8f39e609b..2613e398f 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -873,8 +873,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
| 873 | blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); | 873 | blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); |
| 874 | blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); | 874 | blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); |
| 875 | } else { | 875 | } else { |
| 876 | LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); | 876 | static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { |
| 877 | UNIMPLEMENTED(); | 877 | switch (op) { |
| 878 | case Regs::LogicOp::Clear: | ||
| 879 | return 0; | ||
| 880 | |||
| 881 | case Regs::LogicOp::And: | ||
| 882 | return src & dest; | ||
| 883 | |||
| 884 | case Regs::LogicOp::AndReverse: | ||
| 885 | return src & ~dest; | ||
| 886 | |||
| 887 | case Regs::LogicOp::Copy: | ||
| 888 | return src; | ||
| 889 | |||
| 890 | case Regs::LogicOp::Set: | ||
| 891 | return 255; | ||
| 892 | |||
| 893 | case Regs::LogicOp::CopyInverted: | ||
| 894 | return ~src; | ||
| 895 | |||
| 896 | case Regs::LogicOp::NoOp: | ||
| 897 | return dest; | ||
| 898 | |||
| 899 | case Regs::LogicOp::Invert: | ||
| 900 | return ~dest; | ||
| 901 | |||
| 902 | case Regs::LogicOp::Nand: | ||
| 903 | return ~(src & dest); | ||
| 904 | |||
| 905 | case Regs::LogicOp::Or: | ||
| 906 | return src | dest; | ||
| 907 | |||
| 908 | case Regs::LogicOp::Nor: | ||
| 909 | return ~(src | dest); | ||
| 910 | |||
| 911 | case Regs::LogicOp::Xor: | ||
| 912 | return src ^ dest; | ||
| 913 | |||
| 914 | case Regs::LogicOp::Equiv: | ||
| 915 | return ~(src ^ dest); | ||
| 916 | |||
| 917 | case Regs::LogicOp::AndInverted: | ||
| 918 | return ~src & dest; | ||
| 919 | |||
| 920 | case Regs::LogicOp::OrReverse: | ||
| 921 | return src | ~dest; | ||
| 922 | |||
| 923 | case Regs::LogicOp::OrInverted: | ||
| 924 | return ~src | dest; | ||
| 925 | } | ||
| 926 | }; | ||
| 927 | |||
| 928 | blend_output = Math::MakeVec( | ||
| 929 | LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op), | ||
| 930 | LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op), | ||
| 931 | LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op), | ||
| 932 | LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op)); | ||
| 878 | } | 933 | } |
| 879 | 934 | ||
| 880 | const Math::Vec4<u8> result = { | 935 | const Math::Vec4<u8> result = { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index bacdb7172..b51f8efdf 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -135,6 +135,7 @@ void RasterizerOpenGL::Reset() { | |||
| 135 | SyncBlendFuncs(); | 135 | SyncBlendFuncs(); |
| 136 | SyncBlendColor(); | 136 | SyncBlendColor(); |
| 137 | SyncAlphaTest(); | 137 | SyncAlphaTest(); |
| 138 | SyncLogicOp(); | ||
| 138 | SyncStencilTest(); | 139 | SyncStencilTest(); |
| 139 | SyncDepthTest(); | 140 | SyncDepthTest(); |
| 140 | 141 | ||
| @@ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 249 | SyncDepthTest(); | 250 | SyncDepthTest(); |
| 250 | break; | 251 | break; |
| 251 | 252 | ||
| 253 | // Logic op | ||
| 254 | case PICA_REG_INDEX(output_merger.logic_op): | ||
| 255 | SyncLogicOp(); | ||
| 256 | break; | ||
| 257 | |||
| 252 | // TEV stage 0 | 258 | // TEV stage 0 |
| 253 | case PICA_REG_INDEX(tev_stage0.color_source1): | 259 | case PICA_REG_INDEX(tev_stage0.color_source1): |
| 254 | SyncTevSources(0, regs.tev_stage0); | 260 | SyncTevSources(0, regs.tev_stage0); |
| @@ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() { | |||
| 633 | glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); | 639 | glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); |
| 634 | } | 640 | } |
| 635 | 641 | ||
| 642 | void RasterizerOpenGL::SyncLogicOp() { | ||
| 643 | state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); | ||
| 644 | } | ||
| 645 | |||
| 636 | void RasterizerOpenGL::SyncStencilTest() { | 646 | void RasterizerOpenGL::SyncStencilTest() { |
| 637 | // TODO: Implement stencil test, mask, and op | 647 | // TODO: Implement stencil test, mask, and op |
| 638 | } | 648 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 9896f8d04..d7d422b1f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -125,6 +125,9 @@ private: | |||
| 125 | /// Syncs the alpha test states to match the PICA register | 125 | /// Syncs the alpha test states to match the PICA register |
| 126 | void SyncAlphaTest(); | 126 | void SyncAlphaTest(); |
| 127 | 127 | ||
| 128 | /// Syncs the logic op states to match the PICA register | ||
| 129 | void SyncLogicOp(); | ||
| 130 | |||
| 128 | /// Syncs the stencil test states to match the PICA register | 131 | /// Syncs the stencil test states to match the PICA register |
| 129 | void SyncStencilTest(); | 132 | void SyncStencilTest(); |
| 130 | 133 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 0d7ba1983..9c5f38f94 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -32,6 +32,8 @@ OpenGLState::OpenGLState() { | |||
| 32 | blend.color.blue = 0.0f; | 32 | blend.color.blue = 0.0f; |
| 33 | blend.color.alpha = 0.0f; | 33 | blend.color.alpha = 0.0f; |
| 34 | 34 | ||
| 35 | logic_op = GL_COPY; | ||
| 36 | |||
| 35 | for (auto& texture_unit : texture_units) { | 37 | for (auto& texture_unit : texture_units) { |
| 36 | texture_unit.enabled_2d = false; | 38 | texture_unit.enabled_2d = false; |
| 37 | texture_unit.texture_2d = 0; | 39 | texture_unit.texture_2d = 0; |
| @@ -99,8 +101,13 @@ void OpenGLState::Apply() { | |||
| 99 | if (blend.enabled != cur_state.blend.enabled) { | 101 | if (blend.enabled != cur_state.blend.enabled) { |
| 100 | if (blend.enabled) { | 102 | if (blend.enabled) { |
| 101 | glEnable(GL_BLEND); | 103 | glEnable(GL_BLEND); |
| 104 | |||
| 105 | cur_state.logic_op = GL_COPY; | ||
| 106 | glLogicOp(cur_state.logic_op); | ||
| 107 | glDisable(GL_COLOR_LOGIC_OP); | ||
| 102 | } else { | 108 | } else { |
| 103 | glDisable(GL_BLEND); | 109 | glDisable(GL_BLEND); |
| 110 | glEnable(GL_COLOR_LOGIC_OP); | ||
| 104 | } | 111 | } |
| 105 | } | 112 | } |
| 106 | 113 | ||
| @@ -118,6 +125,10 @@ void OpenGLState::Apply() { | |||
| 118 | glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); | 125 | glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); |
| 119 | } | 126 | } |
| 120 | 127 | ||
| 128 | if (logic_op != cur_state.logic_op) { | ||
| 129 | glLogicOp(logic_op); | ||
| 130 | } | ||
| 131 | |||
| 121 | // Textures | 132 | // Textures |
| 122 | for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { | 133 | for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { |
| 123 | if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { | 134 | if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 63dba2761..6b97721d6 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -42,6 +42,8 @@ public: | |||
| 42 | } color; // GL_BLEND_COLOR | 42 | } color; // GL_BLEND_COLOR |
| 43 | } blend; | 43 | } blend; |
| 44 | 44 | ||
| 45 | GLenum logic_op; // GL_LOGIC_OP_MODE | ||
| 46 | |||
| 45 | // 3 texture units - one for each that is used in PICA fragment shader emulation | 47 | // 3 texture units - one for each that is used in PICA fragment shader emulation |
| 46 | struct { | 48 | struct { |
| 47 | bool enabled_2d; // GL_TEXTURE_2D | 49 | bool enabled_2d; // GL_TEXTURE_2D |
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index f8763e71b..e566f9f7a 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h | |||
| @@ -71,6 +71,37 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | |||
| 71 | return blend_func_table[(unsigned)factor]; | 71 | return blend_func_table[(unsigned)factor]; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | inline GLenum LogicOp(Pica::Regs::LogicOp op) { | ||
| 75 | static const GLenum logic_op_table[] = { | ||
| 76 | GL_CLEAR, // Clear | ||
| 77 | GL_AND, // And | ||
| 78 | GL_AND_REVERSE, // AndReverse | ||
| 79 | GL_COPY, // Copy | ||
| 80 | GL_SET, // Set | ||
| 81 | GL_COPY_INVERTED, // CopyInverted | ||
| 82 | GL_NOOP, // NoOp | ||
| 83 | GL_INVERT, // Invert | ||
| 84 | GL_NAND, // Nand | ||
| 85 | GL_OR, // Or | ||
| 86 | GL_NOR, // Nor | ||
| 87 | GL_XOR, // Xor | ||
| 88 | GL_EQUIV, // Equiv | ||
| 89 | GL_AND_INVERTED, // AndInverted | ||
| 90 | GL_OR_REVERSE, // OrReverse | ||
| 91 | GL_OR_INVERTED, // OrInverted | ||
| 92 | }; | ||
| 93 | |||
| 94 | // Range check table for input | ||
| 95 | if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) { | ||
| 96 | LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op); | ||
| 97 | UNREACHABLE(); | ||
| 98 | |||
| 99 | return GL_COPY; | ||
| 100 | } | ||
| 101 | |||
| 102 | return logic_op_table[(unsigned)op]; | ||
| 103 | } | ||
| 104 | |||
| 74 | inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | 105 | inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { |
| 75 | static const GLenum compare_func_table[] = { | 106 | static const GLenum compare_func_table[] = { |
| 76 | GL_NEVER, // CompareFunc::Never | 107 | GL_NEVER, // CompareFunc::Never |