mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Pica: Implement LogicOp function.
This commit is contained in:
		
							parent
							
								
									3b5ff61201
								
							
						
					
					
						commit
						e6ace38815
					
				
					 7 changed files with 135 additions and 8 deletions
				
			
		|  | @ -162,6 +162,25 @@ struct Regs { | |||
|         ETC1A4       = 13,  // compressed
 | ||||
|     }; | ||||
| 
 | ||||
|     enum class LogicOp : u32 { | ||||
|         Clear        =  0, | ||||
|         And          =  1, | ||||
|         AndReverse   =  2, | ||||
|         Copy         =  3, | ||||
|         Set          =  4, | ||||
|         CopyInverted =  5, | ||||
|         NoOp         =  6, | ||||
|         Invert       =  7, | ||||
|         Nand         =  8, | ||||
|         Or           =  9, | ||||
|         Nor          = 10, | ||||
|         Xor          = 11, | ||||
|         Equiv        = 12, | ||||
|         AndInverted  = 13, | ||||
|         OrReverse    = 14, | ||||
|         OrInverted   = 15, | ||||
|     }; | ||||
| 
 | ||||
|     static unsigned NibblesPerPixel(TextureFormat format) { | ||||
|         switch (format) { | ||||
|         case TextureFormat::RGBA8: | ||||
|  | @ -413,12 +432,8 @@ struct Regs { | |||
|         } alpha_blending; | ||||
| 
 | ||||
|         union { | ||||
|             enum Op { | ||||
|                 Set = 4, | ||||
|             }; | ||||
| 
 | ||||
|             BitField<0, 4, Op> op; | ||||
|         } logic_op; | ||||
|             BitField<0, 4, LogicOp> logic_op; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             BitField< 0, 8, u32> r; | ||||
|  |  | |||
|  | @ -873,8 +873,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, | |||
|                 blend_output     = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); | ||||
|                 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); | ||||
|             } else { | ||||
|                 LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); | ||||
|                 UNIMPLEMENTED(); | ||||
|                 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { | ||||
|                     switch (op) { | ||||
|                     case Regs::LogicOp::Clear: | ||||
|                         return 0; | ||||
| 
 | ||||
|                     case Regs::LogicOp::And: | ||||
|                         return src & dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::AndReverse: | ||||
|                         return src & ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Copy: | ||||
|                         return src; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Set: | ||||
|                         return 255; | ||||
| 
 | ||||
|                     case Regs::LogicOp::CopyInverted: | ||||
|                         return ~src; | ||||
| 
 | ||||
|                     case Regs::LogicOp::NoOp: | ||||
|                         return dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Invert: | ||||
|                         return ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Nand: | ||||
|                         return ~(src & dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::Or: | ||||
|                         return src | dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Nor: | ||||
|                         return ~(src | dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::Xor: | ||||
|                         return src ^ dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Equiv: | ||||
|                         return ~(src ^ dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::AndInverted: | ||||
|                         return ~src & dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::OrReverse: | ||||
|                         return src | ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::OrInverted: | ||||
|                         return ~src | dest; | ||||
|                     } | ||||
|                 }; | ||||
| 
 | ||||
|                 blend_output = Math::MakeVec( | ||||
|                     LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op), | ||||
|                     LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op), | ||||
|                     LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op), | ||||
|                     LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op)); | ||||
|             } | ||||
| 
 | ||||
|             const Math::Vec4<u8> result = { | ||||
|  |  | |||
|  | @ -135,6 +135,7 @@ void RasterizerOpenGL::Reset() { | |||
|     SyncBlendFuncs(); | ||||
|     SyncBlendColor(); | ||||
|     SyncAlphaTest(); | ||||
|     SyncLogicOp(); | ||||
|     SyncStencilTest(); | ||||
|     SyncDepthTest(); | ||||
| 
 | ||||
|  | @ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
|         SyncDepthTest(); | ||||
|         break; | ||||
| 
 | ||||
|     // Logic op
 | ||||
|     case PICA_REG_INDEX(output_merger.logic_op): | ||||
|         SyncLogicOp(); | ||||
|         break; | ||||
| 
 | ||||
|     // TEV stage 0
 | ||||
|     case PICA_REG_INDEX(tev_stage0.color_source1): | ||||
|         SyncTevSources(0, regs.tev_stage0); | ||||
|  | @ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() { | |||
|     glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncLogicOp() { | ||||
|     state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncStencilTest() { | ||||
|     // TODO: Implement stencil test, mask, and op
 | ||||
| } | ||||
|  |  | |||
|  | @ -125,6 +125,9 @@ private: | |||
|     /// Syncs the alpha test states to match the PICA register
 | ||||
|     void SyncAlphaTest(); | ||||
| 
 | ||||
|     /// Syncs the logic op states to match the PICA register
 | ||||
|     void SyncLogicOp(); | ||||
| 
 | ||||
|     /// Syncs the stencil test states to match the PICA register
 | ||||
|     void SyncStencilTest(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,6 +32,8 @@ OpenGLState::OpenGLState() { | |||
|     blend.color.blue = 0.0f; | ||||
|     blend.color.alpha = 0.0f; | ||||
| 
 | ||||
|     logic_op = GL_COPY; | ||||
| 
 | ||||
|     for (auto& texture_unit : texture_units) { | ||||
|         texture_unit.enabled_2d = false; | ||||
|         texture_unit.texture_2d = 0; | ||||
|  | @ -99,8 +101,13 @@ void OpenGLState::Apply() { | |||
|     if (blend.enabled != cur_state.blend.enabled) { | ||||
|         if (blend.enabled) { | ||||
|             glEnable(GL_BLEND); | ||||
| 
 | ||||
|             cur_state.logic_op = GL_COPY; | ||||
|             glLogicOp(cur_state.logic_op); | ||||
|             glDisable(GL_COLOR_LOGIC_OP); | ||||
|         } else { | ||||
|             glDisable(GL_BLEND); | ||||
|             glEnable(GL_COLOR_LOGIC_OP); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -118,6 +125,10 @@ void OpenGLState::Apply() { | |||
|         glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); | ||||
|     } | ||||
| 
 | ||||
|     if (logic_op != cur_state.logic_op) { | ||||
|         glLogicOp(logic_op); | ||||
|     } | ||||
| 
 | ||||
|     // Textures
 | ||||
|     for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { | ||||
|         if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { | ||||
|  |  | |||
|  | @ -42,6 +42,8 @@ public: | |||
|         } color; // GL_BLEND_COLOR
 | ||||
|     } blend; | ||||
| 
 | ||||
|     GLenum logic_op; // GL_LOGIC_OP_MODE
 | ||||
| 
 | ||||
|     // 3 texture units - one for each that is used in PICA fragment shader emulation
 | ||||
|     struct { | ||||
|         bool enabled_2d; // GL_TEXTURE_2D
 | ||||
|  |  | |||
|  | @ -71,6 +71,37 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | |||
|     return blend_func_table[(unsigned)factor]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum LogicOp(Pica::Regs::LogicOp op) { | ||||
|     static const GLenum logic_op_table[] = { | ||||
|         GL_CLEAR,           // Clear
 | ||||
|         GL_AND,             // And
 | ||||
|         GL_AND_REVERSE,     // AndReverse
 | ||||
|         GL_COPY,            // Copy
 | ||||
|         GL_SET,             // Set
 | ||||
|         GL_COPY_INVERTED,   // CopyInverted
 | ||||
|         GL_NOOP,            // NoOp
 | ||||
|         GL_INVERT,          // Invert
 | ||||
|         GL_NAND,            // Nand
 | ||||
|         GL_OR,              // Or
 | ||||
|         GL_NOR,             // Nor
 | ||||
|         GL_XOR,             // Xor
 | ||||
|         GL_EQUIV,           // Equiv
 | ||||
|         GL_AND_INVERTED,    // AndInverted
 | ||||
|         GL_OR_REVERSE,      // OrReverse
 | ||||
|         GL_OR_INVERTED,     // OrInverted
 | ||||
|     }; | ||||
| 
 | ||||
|     // Range check table for input
 | ||||
|     if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) { | ||||
|         LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op); | ||||
|         UNREACHABLE(); | ||||
| 
 | ||||
|         return GL_COPY; | ||||
|     } | ||||
| 
 | ||||
|     return logic_op_table[(unsigned)op]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | ||||
|     static const GLenum compare_func_table[] = { | ||||
|         GL_NEVER,    // CompareFunc::Never
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue