| 
									
										
										
										
											2016-12-29 17:31:51 +01:00
										 |  |  | // Copyright 2016 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2+
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "VideoCommon/RenderState.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // If the framebuffer format has no alpha channel, it is assumed to
 | 
					
						
							|  |  |  | // ONE on blending. As the backends may emulate this framebuffer
 | 
					
						
							|  |  |  | // configuration with an alpha channel, we just drop all references
 | 
					
						
							|  |  |  | // to the destination alpha channel.
 | 
					
						
							|  |  |  | static BlendMode::BlendFactor RemoveDstAlphaUsage(BlendMode::BlendFactor factor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (factor) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case BlendMode::DSTALPHA: | 
					
						
							|  |  |  |     return BlendMode::ONE; | 
					
						
							|  |  |  |   case BlendMode::INVDSTALPHA: | 
					
						
							|  |  |  |     return BlendMode::ZERO; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     return factor; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // We separate the blending parameter for rgb and alpha. For blending
 | 
					
						
							|  |  |  | // the alpha component, CLR and ALPHA are indentical. So just always
 | 
					
						
							|  |  |  | // use ALPHA as this makes it easier for the backends to use the second
 | 
					
						
							|  |  |  | // alpha value of dual source blending.
 | 
					
						
							|  |  |  | static BlendMode::BlendFactor RemoveSrcColorUsage(BlendMode::BlendFactor factor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (factor) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case BlendMode::SRCCLR: | 
					
						
							|  |  |  |     return BlendMode::SRCALPHA; | 
					
						
							|  |  |  |   case BlendMode::INVSRCCLR: | 
					
						
							|  |  |  |     return BlendMode::INVSRCALPHA; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     return factor; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Same as RemoveSrcColorUsage, but because of the overlapping enum,
 | 
					
						
							|  |  |  | // this must be written as another function.
 | 
					
						
							|  |  |  | static BlendMode::BlendFactor RemoveDstColorUsage(BlendMode::BlendFactor factor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   switch (factor) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case BlendMode::DSTCLR: | 
					
						
							|  |  |  |     return BlendMode::DSTALPHA; | 
					
						
							|  |  |  |   case BlendMode::INVDSTCLR: | 
					
						
							|  |  |  |     return BlendMode::INVDSTALPHA; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     return factor; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BlendingState::Generate(const BPMemory& bp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // Start with everything disabled.
 | 
					
						
							|  |  |  |   hex = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool target_has_alpha = bp.zcontrol.pixel_format == PEControl::RGBA6_Z24; | 
					
						
							|  |  |  |   bool alpha_test_may_success = bp.alpha_test.TestResult() != AlphaTest::FAIL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dither = bp.blendmode.dither; | 
					
						
							|  |  |  |   colorupdate = bp.blendmode.colorupdate && alpha_test_may_success; | 
					
						
							|  |  |  |   alphaupdate = bp.blendmode.alphaupdate && target_has_alpha && alpha_test_may_success; | 
					
						
							|  |  |  |   dstalpha = bp.dstalpha.enable && alphaupdate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The subtract bit has the highest priority
 | 
					
						
							|  |  |  |   if (bp.blendmode.subtract) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     blendenable = true; | 
					
						
							|  |  |  |     subtractAlpha = subtract = true; | 
					
						
							|  |  |  |     srcfactoralpha = srcfactor = BlendMode::ONE; | 
					
						
							|  |  |  |     dstfactoralpha = dstfactor = BlendMode::ONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (dstalpha) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       subtractAlpha = false; | 
					
						
							|  |  |  |       srcfactoralpha = BlendMode::ONE; | 
					
						
							|  |  |  |       dstfactoralpha = BlendMode::ZERO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The blendenable bit has the middle priority
 | 
					
						
							|  |  |  |   else if (bp.blendmode.blendenable) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     blendenable = true; | 
					
						
							|  |  |  |     srcfactor = bp.blendmode.srcfactor; | 
					
						
							|  |  |  |     dstfactor = bp.blendmode.dstfactor; | 
					
						
							|  |  |  |     if (!target_has_alpha) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // uses ONE instead of DSTALPHA
 | 
					
						
							|  |  |  |       srcfactor = RemoveDstAlphaUsage(srcfactor); | 
					
						
							|  |  |  |       dstfactor = RemoveDstAlphaUsage(dstfactor); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // replaces SRCCLR with SRCALPHA
 | 
					
						
							|  |  |  |     srcfactoralpha = RemoveSrcColorUsage(srcfactor); | 
					
						
							|  |  |  |     dstfactoralpha = RemoveDstColorUsage(dstfactor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (dstalpha) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       srcfactoralpha = BlendMode::ONE; | 
					
						
							|  |  |  |       dstfactoralpha = BlendMode::ZERO; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // The logicop bit has the lowest priority
 | 
					
						
							|  |  |  |   else if (bp.blendmode.logicopenable) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-12-29 18:15:41 +01:00
										 |  |  |     if (bp.blendmode.logicmode == BlendMode::NOOP) | 
					
						
							| 
									
										
										
										
											2016-12-29 17:31:51 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-12-29 18:15:41 +01:00
										 |  |  |       // Fast path for Kirby's Return to Dreamland, they use it with dstAlpha.
 | 
					
						
							|  |  |  |       colorupdate = false; | 
					
						
							|  |  |  |       alphaupdate = alphaupdate && dstalpha; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       logicopenable = true; | 
					
						
							|  |  |  |       logicmode = bp.blendmode.logicmode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (dstalpha) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // TODO: Not supported by backends.
 | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-12-29 17:31:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |