mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	VideoCore: Split framebuffer regs from Regs struct
This commit is contained in:
		
							parent
							
								
									9017093f58
								
							
						
					
					
						commit
						23713d5dee
					
				
					 11 changed files with 503 additions and 457 deletions
				
			
		|  | @ -414,30 +414,30 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
|         // TODO: Store a reference to the registers in the debug context instead of accessing them
 | ||||
|         // directly...
 | ||||
| 
 | ||||
|         const auto& framebuffer = Pica::g_state.regs.framebuffer; | ||||
|         const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer; | ||||
| 
 | ||||
|         surface_address = framebuffer.GetColorBufferPhysicalAddress(); | ||||
|         surface_width = framebuffer.GetWidth(); | ||||
|         surface_height = framebuffer.GetHeight(); | ||||
| 
 | ||||
|         switch (framebuffer.color_format) { | ||||
|         case Pica::Regs::ColorFormat::RGBA8: | ||||
|         case Pica::FramebufferRegs::ColorFormat::RGBA8: | ||||
|             surface_format = Format::RGBA8; | ||||
|             break; | ||||
| 
 | ||||
|         case Pica::Regs::ColorFormat::RGB8: | ||||
|         case Pica::FramebufferRegs::ColorFormat::RGB8: | ||||
|             surface_format = Format::RGB8; | ||||
|             break; | ||||
| 
 | ||||
|         case Pica::Regs::ColorFormat::RGB5A1: | ||||
|         case Pica::FramebufferRegs::ColorFormat::RGB5A1: | ||||
|             surface_format = Format::RGB5A1; | ||||
|             break; | ||||
| 
 | ||||
|         case Pica::Regs::ColorFormat::RGB565: | ||||
|         case Pica::FramebufferRegs::ColorFormat::RGB565: | ||||
|             surface_format = Format::RGB565; | ||||
|             break; | ||||
| 
 | ||||
|         case Pica::Regs::ColorFormat::RGBA4: | ||||
|         case Pica::FramebufferRegs::ColorFormat::RGBA4: | ||||
|             surface_format = Format::RGBA4; | ||||
|             break; | ||||
| 
 | ||||
|  | @ -450,22 +450,22 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
|     } | ||||
| 
 | ||||
|     case Source::DepthBuffer: { | ||||
|         const auto& framebuffer = Pica::g_state.regs.framebuffer; | ||||
|         const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer; | ||||
| 
 | ||||
|         surface_address = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|         surface_width = framebuffer.GetWidth(); | ||||
|         surface_height = framebuffer.GetHeight(); | ||||
| 
 | ||||
|         switch (framebuffer.depth_format) { | ||||
|         case Pica::Regs::DepthFormat::D16: | ||||
|         case Pica::FramebufferRegs::DepthFormat::D16: | ||||
|             surface_format = Format::D16; | ||||
|             break; | ||||
| 
 | ||||
|         case Pica::Regs::DepthFormat::D24: | ||||
|         case Pica::FramebufferRegs::DepthFormat::D24: | ||||
|             surface_format = Format::D24; | ||||
|             break; | ||||
| 
 | ||||
|         case Pica::Regs::DepthFormat::D24S8: | ||||
|         case Pica::FramebufferRegs::DepthFormat::D24S8: | ||||
|             surface_format = Format::D24X8; | ||||
|             break; | ||||
| 
 | ||||
|  | @ -478,14 +478,14 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
|     } | ||||
| 
 | ||||
|     case Source::StencilBuffer: { | ||||
|         const auto& framebuffer = Pica::g_state.regs.framebuffer; | ||||
|         const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer; | ||||
| 
 | ||||
|         surface_address = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|         surface_width = framebuffer.GetWidth(); | ||||
|         surface_height = framebuffer.GetHeight(); | ||||
| 
 | ||||
|         switch (framebuffer.depth_format) { | ||||
|         case Pica::Regs::DepthFormat::D24S8: | ||||
|         case Pica::FramebufferRegs::DepthFormat::D24S8: | ||||
|             surface_format = Format::X24S8; | ||||
|             break; | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ set(HEADERS | |||
|             primitive_assembly.h | ||||
|             rasterizer.h | ||||
|             rasterizer_interface.h | ||||
|             regs_framebuffer.h | ||||
|             regs_rasterizer.h | ||||
|             regs_texturing.h | ||||
|             renderer_base.h | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ | |||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "video_core/regs_framebuffer.h" | ||||
| #include "video_core/regs_rasterizer.h" | ||||
| #include "video_core/regs_texturing.h" | ||||
| 
 | ||||
|  | @ -51,268 +52,7 @@ struct Regs { | |||
|     INSERT_PADDING_WORDS(0x2f); | ||||
|     RasterizerRegs rasterizer; | ||||
|     TexturingRegs texturing; | ||||
| 
 | ||||
|     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, | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendEquation : u32 { | ||||
|         Add = 0, | ||||
|         Subtract = 1, | ||||
|         ReverseSubtract = 2, | ||||
|         Min = 3, | ||||
|         Max = 4, | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendFactor : u32 { | ||||
|         Zero = 0, | ||||
|         One = 1, | ||||
|         SourceColor = 2, | ||||
|         OneMinusSourceColor = 3, | ||||
|         DestColor = 4, | ||||
|         OneMinusDestColor = 5, | ||||
|         SourceAlpha = 6, | ||||
|         OneMinusSourceAlpha = 7, | ||||
|         DestAlpha = 8, | ||||
|         OneMinusDestAlpha = 9, | ||||
|         ConstantColor = 10, | ||||
|         OneMinusConstantColor = 11, | ||||
|         ConstantAlpha = 12, | ||||
|         OneMinusConstantAlpha = 13, | ||||
|         SourceAlphaSaturate = 14, | ||||
|     }; | ||||
| 
 | ||||
|     enum class CompareFunc : u32 { | ||||
|         Never = 0, | ||||
|         Always = 1, | ||||
|         Equal = 2, | ||||
|         NotEqual = 3, | ||||
|         LessThan = 4, | ||||
|         LessThanOrEqual = 5, | ||||
|         GreaterThan = 6, | ||||
|         GreaterThanOrEqual = 7, | ||||
|     }; | ||||
| 
 | ||||
|     enum class StencilAction : u32 { | ||||
|         Keep = 0, | ||||
|         Zero = 1, | ||||
|         Replace = 2, | ||||
|         Increment = 3, | ||||
|         Decrement = 4, | ||||
|         Invert = 5, | ||||
|         IncrementWrap = 6, | ||||
|         DecrementWrap = 7, | ||||
|     }; | ||||
| 
 | ||||
|     struct { | ||||
|         union { | ||||
|             // If false, logic blending is used
 | ||||
|             BitField<8, 1, u32> alphablend_enable; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 8, BlendEquation> blend_equation_rgb; | ||||
|             BitField<8, 8, BlendEquation> blend_equation_a; | ||||
| 
 | ||||
|             BitField<16, 4, BlendFactor> factor_source_rgb; | ||||
|             BitField<20, 4, BlendFactor> factor_dest_rgb; | ||||
| 
 | ||||
|             BitField<24, 4, BlendFactor> factor_source_a; | ||||
|             BitField<28, 4, BlendFactor> factor_dest_a; | ||||
|         } alpha_blending; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 4, LogicOp> logic_op; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 raw; | ||||
|             BitField<0, 8, u32> r; | ||||
|             BitField<8, 8, u32> g; | ||||
|             BitField<16, 8, u32> b; | ||||
|             BitField<24, 8, u32> a; | ||||
|         } blend_const; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> enable; | ||||
|             BitField<4, 3, CompareFunc> func; | ||||
|             BitField<8, 8, u32> ref; | ||||
|         } alpha_test; | ||||
| 
 | ||||
|         struct { | ||||
|             union { | ||||
|                 // Raw value of this register
 | ||||
|                 u32 raw_func; | ||||
| 
 | ||||
|                 // If true, enable stencil testing
 | ||||
|                 BitField<0, 1, u32> enable; | ||||
| 
 | ||||
|                 // Comparison operation for stencil testing
 | ||||
|                 BitField<4, 3, CompareFunc> func; | ||||
| 
 | ||||
|                 // Mask used to control writing to the stencil buffer
 | ||||
|                 BitField<8, 8, u32> write_mask; | ||||
| 
 | ||||
|                 // Value to compare against for stencil testing
 | ||||
|                 BitField<16, 8, u32> reference_value; | ||||
| 
 | ||||
|                 // Mask to apply on stencil test inputs
 | ||||
|                 BitField<24, 8, u32> input_mask; | ||||
|             }; | ||||
| 
 | ||||
|             union { | ||||
|                 // Raw value of this register
 | ||||
|                 u32 raw_op; | ||||
| 
 | ||||
|                 // Action to perform when the stencil test fails
 | ||||
|                 BitField<0, 3, StencilAction> action_stencil_fail; | ||||
| 
 | ||||
|                 // Action to perform when stencil testing passed but depth testing fails
 | ||||
|                 BitField<4, 3, StencilAction> action_depth_fail; | ||||
| 
 | ||||
|                 // Action to perform when both stencil and depth testing pass
 | ||||
|                 BitField<8, 3, StencilAction> action_depth_pass; | ||||
|             }; | ||||
|         } stencil_test; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> depth_test_enable; | ||||
|             BitField<4, 3, CompareFunc> depth_test_func; | ||||
|             BitField<8, 1, u32> red_enable; | ||||
|             BitField<9, 1, u32> green_enable; | ||||
|             BitField<10, 1, u32> blue_enable; | ||||
|             BitField<11, 1, u32> alpha_enable; | ||||
|             BitField<12, 1, u32> depth_write_enable; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x8); | ||||
|     } output_merger; | ||||
| 
 | ||||
|     // Components are laid out in reverse byte order, most significant bits first.
 | ||||
|     enum class ColorFormat : u32 { | ||||
|         RGBA8 = 0, | ||||
|         RGB8 = 1, | ||||
|         RGB5A1 = 2, | ||||
|         RGB565 = 3, | ||||
|         RGBA4 = 4, | ||||
|     }; | ||||
| 
 | ||||
|     enum class DepthFormat : u32 { | ||||
|         D16 = 0, | ||||
|         D24 = 2, | ||||
|         D24S8 = 3, | ||||
|     }; | ||||
| 
 | ||||
|     // Returns the number of bytes in the specified color format
 | ||||
|     static unsigned BytesPerColorPixel(ColorFormat format) { | ||||
|         switch (format) { | ||||
|         case ColorFormat::RGBA8: | ||||
|             return 4; | ||||
|         case ColorFormat::RGB8: | ||||
|             return 3; | ||||
|         case ColorFormat::RGB5A1: | ||||
|         case ColorFormat::RGB565: | ||||
|         case ColorFormat::RGBA4: | ||||
|             return 2; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown color format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     struct FramebufferConfig { | ||||
|         INSERT_PADDING_WORDS(0x3); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
 | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
 | ||||
|         }; | ||||
| 
 | ||||
|         DepthFormat depth_format; // TODO: Should be a BitField!
 | ||||
|         BitField<16, 3, ColorFormat> color_format; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x4); | ||||
| 
 | ||||
|         u32 depth_buffer_address; | ||||
|         u32 color_buffer_address; | ||||
| 
 | ||||
|         union { | ||||
|             // Apparently, the framebuffer width is stored as expected,
 | ||||
|             // while the height is stored as the actual height minus one.
 | ||||
|             // Hence, don't access these fields directly but use the accessors
 | ||||
|             // GetWidth() and GetHeight() instead.
 | ||||
|             BitField<0, 11, u32> width; | ||||
|             BitField<12, 10, u32> height; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         inline u32 GetColorBufferPhysicalAddress() const { | ||||
|             return DecodeAddressRegister(color_buffer_address); | ||||
|         } | ||||
|         inline u32 GetDepthBufferPhysicalAddress() const { | ||||
|             return DecodeAddressRegister(depth_buffer_address); | ||||
|         } | ||||
| 
 | ||||
|         inline u32 GetWidth() const { | ||||
|             return width; | ||||
|         } | ||||
| 
 | ||||
|         inline u32 GetHeight() const { | ||||
|             return height + 1; | ||||
|         } | ||||
|     } framebuffer; | ||||
| 
 | ||||
|     // Returns the number of bytes in the specified depth format
 | ||||
|     static u32 BytesPerDepthPixel(DepthFormat format) { | ||||
|         switch (format) { | ||||
|         case DepthFormat::D16: | ||||
|             return 2; | ||||
|         case DepthFormat::D24: | ||||
|             return 3; | ||||
|         case DepthFormat::D24S8: | ||||
|             return 4; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Returns the number of bits per depth component of the specified depth format
 | ||||
|     static u32 DepthBitsPerPixel(DepthFormat format) { | ||||
|         switch (format) { | ||||
|         case DepthFormat::D16: | ||||
|             return 16; | ||||
|         case DepthFormat::D24: | ||||
|         case DepthFormat::D24S8: | ||||
|             return 24; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x20); | ||||
|     FramebufferRegs framebuffer; | ||||
| 
 | ||||
|     enum class LightingSampler { | ||||
|         Distribution0 = 0, | ||||
|  | @ -957,8 +697,10 @@ ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0); | |||
| ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8); | ||||
| ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(output_merger, 0x100); | ||||
| ASSERT_REG_POSITION(framebuffer, 0x110); | ||||
| ASSERT_REG_POSITION(framebuffer, 0x100); | ||||
| ASSERT_REG_POSITION(framebuffer.output_merger, 0x100); | ||||
| ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110); | ||||
| 
 | ||||
| ASSERT_REG_POSITION(lighting, 0x140); | ||||
| ASSERT_REG_POSITION(vertex_attributes, 0x200); | ||||
| ASSERT_REG_POSITION(index_array, 0x227); | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ namespace Pica { | |||
| namespace Rasterizer { | ||||
| 
 | ||||
| static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); | ||||
| 
 | ||||
|     // Similarly to textures, the render framebuffer is laid out from bottom to top, too.
 | ||||
|  | @ -44,23 +44,23 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
|     u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; | ||||
| 
 | ||||
|     switch (framebuffer.color_format) { | ||||
|     case Regs::ColorFormat::RGBA8: | ||||
|     case FramebufferRegs::ColorFormat::RGBA8: | ||||
|         Color::EncodeRGBA8(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB8: | ||||
|     case FramebufferRegs::ColorFormat::RGB8: | ||||
|         Color::EncodeRGB8(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB5A1: | ||||
|     case FramebufferRegs::ColorFormat::RGB5A1: | ||||
|         Color::EncodeRGB5A1(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB565: | ||||
|     case FramebufferRegs::ColorFormat::RGB565: | ||||
|         Color::EncodeRGB565(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGBA4: | ||||
|     case FramebufferRegs::ColorFormat::RGBA4: | ||||
|         Color::EncodeRGBA4(color, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -72,7 +72,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
| } | ||||
| 
 | ||||
| static const Math::Vec4<u8> GetPixel(int x, int y) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
|  | @ -85,19 +85,19 @@ static const Math::Vec4<u8> GetPixel(int x, int y) { | |||
|     u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; | ||||
| 
 | ||||
|     switch (framebuffer.color_format) { | ||||
|     case Regs::ColorFormat::RGBA8: | ||||
|     case FramebufferRegs::ColorFormat::RGBA8: | ||||
|         return Color::DecodeRGBA8(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB8: | ||||
|     case FramebufferRegs::ColorFormat::RGB8: | ||||
|         return Color::DecodeRGB8(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB5A1: | ||||
|     case FramebufferRegs::ColorFormat::RGB5A1: | ||||
|         return Color::DecodeRGB5A1(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGB565: | ||||
|     case FramebufferRegs::ColorFormat::RGB565: | ||||
|         return Color::DecodeRGB565(src_pixel); | ||||
| 
 | ||||
|     case Regs::ColorFormat::RGBA4: | ||||
|     case FramebufferRegs::ColorFormat::RGBA4: | ||||
|         return Color::DecodeRGBA4(src_pixel); | ||||
| 
 | ||||
|     default: | ||||
|  | @ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) { | |||
| } | ||||
| 
 | ||||
| static u32 GetDepth(int x, int y) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* src_pixel = depth_buffer + src_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Regs::DepthFormat::D16: | ||||
|     case FramebufferRegs::DepthFormat::D16: | ||||
|         return Color::DecodeD16(src_pixel); | ||||
|     case Regs::DepthFormat::D24: | ||||
|     case FramebufferRegs::DepthFormat::D24: | ||||
|         return Color::DecodeD24(src_pixel); | ||||
|     case Regs::DepthFormat::D24S8: | ||||
|     case FramebufferRegs::DepthFormat::D24S8: | ||||
|         return Color::DecodeD24S8(src_pixel).x; | ||||
|     default: | ||||
|         LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); | ||||
|  | @ -138,21 +138,21 @@ static u32 GetDepth(int x, int y) { | |||
| } | ||||
| 
 | ||||
| static u8 GetStencil(int x, int y) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* src_pixel = depth_buffer + src_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Regs::DepthFormat::D24S8: | ||||
|     case FramebufferRegs::DepthFormat::D24S8: | ||||
|         return Color::DecodeD24S8(src_pixel).y; | ||||
| 
 | ||||
|     default: | ||||
|  | @ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) { | |||
| } | ||||
| 
 | ||||
| static void SetDepth(int x, int y, u32 value) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* dst_pixel = depth_buffer + dst_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Regs::DepthFormat::D16: | ||||
|     case FramebufferRegs::DepthFormat::D16: | ||||
|         Color::EncodeD16(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::DepthFormat::D24: | ||||
|     case FramebufferRegs::DepthFormat::D24: | ||||
|         Color::EncodeD24(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|     case Regs::DepthFormat::D24S8: | ||||
|     case FramebufferRegs::DepthFormat::D24S8: | ||||
|         Color::EncodeD24X8(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) { | |||
| } | ||||
| 
 | ||||
| static void SetStencil(int x, int y, u8 value) { | ||||
|     const auto& framebuffer = g_state.regs.framebuffer; | ||||
|     const auto& framebuffer = g_state.regs.framebuffer.framebuffer; | ||||
|     const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | ||||
|     u8* depth_buffer = Memory::GetPhysicalPointer(addr); | ||||
| 
 | ||||
|     y = framebuffer.height - y; | ||||
| 
 | ||||
|     const u32 coarse_y = y & ~7; | ||||
|     u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); | ||||
|     u32 stride = framebuffer.width * bytes_per_pixel; | ||||
| 
 | ||||
|     u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | ||||
|     u8* dst_pixel = depth_buffer + dst_offset; | ||||
| 
 | ||||
|     switch (framebuffer.depth_format) { | ||||
|     case Pica::Regs::DepthFormat::D16: | ||||
|     case Pica::Regs::DepthFormat::D24: | ||||
|     case Pica::FramebufferRegs::DepthFormat::D16: | ||||
|     case Pica::FramebufferRegs::DepthFormat::D24: | ||||
|         // Nothing to do
 | ||||
|         break; | ||||
| 
 | ||||
|     case Pica::Regs::DepthFormat::D24S8: | ||||
|     case Pica::FramebufferRegs::DepthFormat::D24S8: | ||||
|         Color::EncodeX24S8(value, dst_pixel); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -229,32 +229,32 @@ static void SetStencil(int x, int y, u8 value) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) { | ||||
| static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) { | ||||
|     switch (action) { | ||||
|     case Regs::StencilAction::Keep: | ||||
|     case FramebufferRegs::StencilAction::Keep: | ||||
|         return old_stencil; | ||||
| 
 | ||||
|     case Regs::StencilAction::Zero: | ||||
|     case FramebufferRegs::StencilAction::Zero: | ||||
|         return 0; | ||||
| 
 | ||||
|     case Regs::StencilAction::Replace: | ||||
|     case FramebufferRegs::StencilAction::Replace: | ||||
|         return ref; | ||||
| 
 | ||||
|     case Regs::StencilAction::Increment: | ||||
|     case FramebufferRegs::StencilAction::Increment: | ||||
|         // Saturated increment
 | ||||
|         return std::min<u8>(old_stencil, 254) + 1; | ||||
| 
 | ||||
|     case Regs::StencilAction::Decrement: | ||||
|     case FramebufferRegs::StencilAction::Decrement: | ||||
|         // Saturated decrement
 | ||||
|         return std::max<u8>(old_stencil, 1) - 1; | ||||
| 
 | ||||
|     case Regs::StencilAction::Invert: | ||||
|     case FramebufferRegs::StencilAction::Invert: | ||||
|         return ~old_stencil; | ||||
| 
 | ||||
|     case Regs::StencilAction::IncrementWrap: | ||||
|     case FramebufferRegs::StencilAction::IncrementWrap: | ||||
|         return old_stencil + 1; | ||||
| 
 | ||||
|     case Regs::StencilAction::DecrementWrap: | ||||
|     case FramebufferRegs::StencilAction::DecrementWrap: | ||||
|         return old_stencil - 1; | ||||
| 
 | ||||
|     default: | ||||
|  | @ -400,9 +400,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|     auto textures = regs.texturing.GetTextures(); | ||||
|     auto tev_stages = regs.texturing.GetTevStages(); | ||||
| 
 | ||||
|     bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && | ||||
|                                  g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; | ||||
|     const auto stencil_test = g_state.regs.output_merger.stencil_test; | ||||
|     bool stencil_action_enable = | ||||
|         g_state.regs.framebuffer.output_merger.stencil_test.enable && | ||||
|         g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8; | ||||
|     const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test; | ||||
| 
 | ||||
|     // Enter rasterization loop, starting at the center of the topleft bounding box corner.
 | ||||
|     // TODO: Not sure if looping through x first might be faster
 | ||||
|  | @ -879,41 +880,41 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             const auto& output_merger = regs.output_merger; | ||||
|             const auto& output_merger = regs.framebuffer.output_merger; | ||||
|             // TODO: Does alpha testing happen before or after stencil?
 | ||||
|             if (output_merger.alpha_test.enable) { | ||||
|                 bool pass = false; | ||||
| 
 | ||||
|                 switch (output_merger.alpha_test.func) { | ||||
|                 case Regs::CompareFunc::Never: | ||||
|                 case FramebufferRegs::CompareFunc::Never: | ||||
|                     pass = false; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Always: | ||||
|                 case FramebufferRegs::CompareFunc::Always: | ||||
|                     pass = true; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Equal: | ||||
|                 case FramebufferRegs::CompareFunc::Equal: | ||||
|                     pass = combiner_output.a() == output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::NotEqual: | ||||
|                 case FramebufferRegs::CompareFunc::NotEqual: | ||||
|                     pass = combiner_output.a() != output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThan: | ||||
|                 case FramebufferRegs::CompareFunc::LessThan: | ||||
|                     pass = combiner_output.a() < output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::LessThanOrEqual: | ||||
|                     pass = combiner_output.a() <= output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThan: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThan: | ||||
|                     pass = combiner_output.a() > output_merger.alpha_test.ref; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThanOrEqual: | ||||
|                     pass = combiner_output.a() >= output_merger.alpha_test.ref; | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -959,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             u8 old_stencil = 0; | ||||
| 
 | ||||
|             auto UpdateStencil = [stencil_test, x, y, | ||||
|                                   &old_stencil](Pica::Regs::StencilAction action) { | ||||
|                                   &old_stencil](Pica::FramebufferRegs::StencilAction action) { | ||||
|                 u8 new_stencil = | ||||
|                     PerformStencilAction(action, old_stencil, stencil_test.reference_value); | ||||
|                 if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) | ||||
|                 if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) | ||||
|                     SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | | ||||
|                                                    (old_stencil & ~stencil_test.write_mask)); | ||||
|             }; | ||||
|  | @ -974,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 
 | ||||
|                 bool pass = false; | ||||
|                 switch (stencil_test.func) { | ||||
|                 case Regs::CompareFunc::Never: | ||||
|                 case FramebufferRegs::CompareFunc::Never: | ||||
|                     pass = false; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Always: | ||||
|                 case FramebufferRegs::CompareFunc::Always: | ||||
|                     pass = true; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Equal: | ||||
|                 case FramebufferRegs::CompareFunc::Equal: | ||||
|                     pass = (ref == dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::NotEqual: | ||||
|                 case FramebufferRegs::CompareFunc::NotEqual: | ||||
|                     pass = (ref != dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThan: | ||||
|                 case FramebufferRegs::CompareFunc::LessThan: | ||||
|                     pass = (ref < dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::LessThanOrEqual: | ||||
|                     pass = (ref <= dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThan: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThan: | ||||
|                     pass = (ref > dest); | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThanOrEqual: | ||||
|                     pass = (ref >= dest); | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -1014,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             } | ||||
| 
 | ||||
|             // Convert float to integer
 | ||||
|             unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); | ||||
|             unsigned num_bits = | ||||
|                 FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format); | ||||
|             u32 z = (u32)(depth * ((1 << num_bits) - 1)); | ||||
| 
 | ||||
|             if (output_merger.depth_test_enable) { | ||||
|  | @ -1023,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 bool pass = false; | ||||
| 
 | ||||
|                 switch (output_merger.depth_test_func) { | ||||
|                 case Regs::CompareFunc::Never: | ||||
|                 case FramebufferRegs::CompareFunc::Never: | ||||
|                     pass = false; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Always: | ||||
|                 case FramebufferRegs::CompareFunc::Always: | ||||
|                     pass = true; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::Equal: | ||||
|                 case FramebufferRegs::CompareFunc::Equal: | ||||
|                     pass = z == ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::NotEqual: | ||||
|                 case FramebufferRegs::CompareFunc::NotEqual: | ||||
|                     pass = z != ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThan: | ||||
|                 case FramebufferRegs::CompareFunc::LessThan: | ||||
|                     pass = z < ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::LessThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::LessThanOrEqual: | ||||
|                     pass = z <= ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThan: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThan: | ||||
|                     pass = z > ref_z; | ||||
|                     break; | ||||
| 
 | ||||
|                 case Regs::CompareFunc::GreaterThanOrEqual: | ||||
|                 case FramebufferRegs::CompareFunc::GreaterThanOrEqual: | ||||
|                     pass = z >= ref_z; | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -1063,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (regs.framebuffer.allow_depth_stencil_write != 0 && output_merger.depth_write_enable) | ||||
|             if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && | ||||
|                 output_merger.depth_write_enable) { | ||||
| 
 | ||||
|                 SetDepth(x >> 4, y >> 4, z); | ||||
|             } | ||||
| 
 | ||||
|             // The stencil depth_pass action is executed even if depth testing is disabled
 | ||||
|             if (stencil_action_enable) | ||||
|  | @ -1076,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|             if (output_merger.alphablend_enable) { | ||||
|                 auto params = output_merger.alpha_blending; | ||||
| 
 | ||||
|                 auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 { | ||||
|                 auto LookupFactor = [&](unsigned channel, | ||||
|                                         FramebufferRegs::BlendFactor factor) -> u8 { | ||||
|                     DEBUG_ASSERT(channel < 4); | ||||
| 
 | ||||
|                     const Math::Vec4<u8> blend_const = { | ||||
|  | @ -1087,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                     }; | ||||
| 
 | ||||
|                     switch (factor) { | ||||
|                     case Regs::BlendFactor::Zero: | ||||
|                     case FramebufferRegs::BlendFactor::Zero: | ||||
|                         return 0; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::One: | ||||
|                     case FramebufferRegs::BlendFactor::One: | ||||
|                         return 255; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::SourceColor: | ||||
|                     case FramebufferRegs::BlendFactor::SourceColor: | ||||
|                         return combiner_output[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusSourceColor: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusSourceColor: | ||||
|                         return 255 - combiner_output[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::DestColor: | ||||
|                     case FramebufferRegs::BlendFactor::DestColor: | ||||
|                         return dest[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusDestColor: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusDestColor: | ||||
|                         return 255 - dest[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::SourceAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::SourceAlpha: | ||||
|                         return combiner_output.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusSourceAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusSourceAlpha: | ||||
|                         return 255 - combiner_output.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::DestAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::DestAlpha: | ||||
|                         return dest.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusDestAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusDestAlpha: | ||||
|                         return 255 - dest.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::ConstantColor: | ||||
|                     case FramebufferRegs::BlendFactor::ConstantColor: | ||||
|                         return blend_const[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusConstantColor: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusConstantColor: | ||||
|                         return 255 - blend_const[channel]; | ||||
| 
 | ||||
|                     case Regs::BlendFactor::ConstantAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::ConstantAlpha: | ||||
|                         return blend_const.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::OneMinusConstantAlpha: | ||||
|                     case FramebufferRegs::BlendFactor::OneMinusConstantAlpha: | ||||
|                         return 255 - blend_const.a(); | ||||
| 
 | ||||
|                     case Regs::BlendFactor::SourceAlphaSaturate: | ||||
|                     case FramebufferRegs::BlendFactor::SourceAlphaSaturate: | ||||
|                         // Returns 1.0 for the alpha channel
 | ||||
|                         if (channel == 3) | ||||
|                             return 255; | ||||
|  | @ -1147,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 static auto EvaluateBlendEquation = []( | ||||
|                     const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, | ||||
|                     const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, | ||||
|                     Regs::BlendEquation equation) { | ||||
|                     FramebufferRegs::BlendEquation equation) { | ||||
| 
 | ||||
|                     Math::Vec4<int> result; | ||||
| 
 | ||||
|                     auto src_result = (src * srcfactor).Cast<int>(); | ||||
|                     auto dst_result = (dest * destfactor).Cast<int>(); | ||||
| 
 | ||||
|                     switch (equation) { | ||||
|                     case Regs::BlendEquation::Add: | ||||
|                     case FramebufferRegs::BlendEquation::Add: | ||||
|                         result = (src_result + dst_result) / 255; | ||||
|                         break; | ||||
| 
 | ||||
|                     case Regs::BlendEquation::Subtract: | ||||
|                     case FramebufferRegs::BlendEquation::Subtract: | ||||
|                         result = (src_result - dst_result) / 255; | ||||
|                         break; | ||||
| 
 | ||||
|                     case Regs::BlendEquation::ReverseSubtract: | ||||
|                     case FramebufferRegs::BlendEquation::ReverseSubtract: | ||||
|                         result = (dst_result - src_result) / 255; | ||||
|                         break; | ||||
| 
 | ||||
|                     // TODO: How do these two actually work?
 | ||||
|                     //       OpenGL doesn't include the blend factors in the min/max computations,
 | ||||
|                     //       but is this what the 3DS actually does?
 | ||||
|                     case Regs::BlendEquation::Min: | ||||
|                     case FramebufferRegs::BlendEquation::Min: | ||||
|                         result.r() = std::min(src.r(), dest.r()); | ||||
|                         result.g() = std::min(src.g(), dest.g()); | ||||
|                         result.b() = std::min(src.b(), dest.b()); | ||||
|                         result.a() = std::min(src.a(), dest.a()); | ||||
|                         break; | ||||
| 
 | ||||
|                     case Regs::BlendEquation::Max: | ||||
|                     case FramebufferRegs::BlendEquation::Max: | ||||
|                         result.r() = std::max(src.r(), dest.r()); | ||||
|                         result.g() = std::max(src.g(), dest.g()); | ||||
|                         result.b() = std::max(src.b(), dest.b()); | ||||
|  | @ -1209,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                                                          dstfactor, params.blend_equation_a) | ||||
|                                        .a(); | ||||
|             } else { | ||||
|                 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { | ||||
|                 static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 { | ||||
|                     switch (op) { | ||||
|                     case Regs::LogicOp::Clear: | ||||
|                     case FramebufferRegs::LogicOp::Clear: | ||||
|                         return 0; | ||||
| 
 | ||||
|                     case Regs::LogicOp::And: | ||||
|                     case FramebufferRegs::LogicOp::And: | ||||
|                         return src & dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::AndReverse: | ||||
|                     case FramebufferRegs::LogicOp::AndReverse: | ||||
|                         return src & ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Copy: | ||||
|                     case FramebufferRegs::LogicOp::Copy: | ||||
|                         return src; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Set: | ||||
|                     case FramebufferRegs::LogicOp::Set: | ||||
|                         return 255; | ||||
| 
 | ||||
|                     case Regs::LogicOp::CopyInverted: | ||||
|                     case FramebufferRegs::LogicOp::CopyInverted: | ||||
|                         return ~src; | ||||
| 
 | ||||
|                     case Regs::LogicOp::NoOp: | ||||
|                     case FramebufferRegs::LogicOp::NoOp: | ||||
|                         return dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Invert: | ||||
|                     case FramebufferRegs::LogicOp::Invert: | ||||
|                         return ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Nand: | ||||
|                     case FramebufferRegs::LogicOp::Nand: | ||||
|                         return ~(src & dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::Or: | ||||
|                     case FramebufferRegs::LogicOp::Or: | ||||
|                         return src | dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Nor: | ||||
|                     case FramebufferRegs::LogicOp::Nor: | ||||
|                         return ~(src | dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::Xor: | ||||
|                     case FramebufferRegs::LogicOp::Xor: | ||||
|                         return src ^ dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::Equiv: | ||||
|                     case FramebufferRegs::LogicOp::Equiv: | ||||
|                         return ~(src ^ dest); | ||||
| 
 | ||||
|                     case Regs::LogicOp::AndInverted: | ||||
|                     case FramebufferRegs::LogicOp::AndInverted: | ||||
|                         return ~src & dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::OrReverse: | ||||
|                     case FramebufferRegs::LogicOp::OrReverse: | ||||
|                         return src | ~dest; | ||||
| 
 | ||||
|                     case Regs::LogicOp::OrInverted: | ||||
|                     case FramebufferRegs::LogicOp::OrInverted: | ||||
|                         return ~src | dest; | ||||
|                     } | ||||
|                 }; | ||||
|  | @ -1275,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
|                 output_merger.alpha_enable ? blend_output.a() : dest.a(), | ||||
|             }; | ||||
| 
 | ||||
|             if (regs.framebuffer.allow_color_write != 0) | ||||
|             if (regs.framebuffer.framebuffer.allow_color_write != 0) | ||||
|                 DrawPixel(x >> 4, y >> 4, result); | ||||
|         } | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										282
									
								
								src/video_core/regs_framebuffer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								src/video_core/regs_framebuffer.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,282 @@ | |||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| 
 | ||||
| #include "common/bit_field.h" | ||||
| #include "common/common_funcs.h" | ||||
| #include "common/common_types.h" | ||||
| 
 | ||||
| namespace Pica { | ||||
| 
 | ||||
| struct FramebufferRegs { | ||||
|     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, | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendEquation : u32 { | ||||
|         Add = 0, | ||||
|         Subtract = 1, | ||||
|         ReverseSubtract = 2, | ||||
|         Min = 3, | ||||
|         Max = 4, | ||||
|     }; | ||||
| 
 | ||||
|     enum class BlendFactor : u32 { | ||||
|         Zero = 0, | ||||
|         One = 1, | ||||
|         SourceColor = 2, | ||||
|         OneMinusSourceColor = 3, | ||||
|         DestColor = 4, | ||||
|         OneMinusDestColor = 5, | ||||
|         SourceAlpha = 6, | ||||
|         OneMinusSourceAlpha = 7, | ||||
|         DestAlpha = 8, | ||||
|         OneMinusDestAlpha = 9, | ||||
|         ConstantColor = 10, | ||||
|         OneMinusConstantColor = 11, | ||||
|         ConstantAlpha = 12, | ||||
|         OneMinusConstantAlpha = 13, | ||||
|         SourceAlphaSaturate = 14, | ||||
|     }; | ||||
| 
 | ||||
|     enum class CompareFunc : u32 { | ||||
|         Never = 0, | ||||
|         Always = 1, | ||||
|         Equal = 2, | ||||
|         NotEqual = 3, | ||||
|         LessThan = 4, | ||||
|         LessThanOrEqual = 5, | ||||
|         GreaterThan = 6, | ||||
|         GreaterThanOrEqual = 7, | ||||
|     }; | ||||
| 
 | ||||
|     enum class StencilAction : u32 { | ||||
|         Keep = 0, | ||||
|         Zero = 1, | ||||
|         Replace = 2, | ||||
|         Increment = 3, | ||||
|         Decrement = 4, | ||||
|         Invert = 5, | ||||
|         IncrementWrap = 6, | ||||
|         DecrementWrap = 7, | ||||
|     }; | ||||
| 
 | ||||
|     struct { | ||||
|         union { | ||||
|             // If false, logic blending is used
 | ||||
|             BitField<8, 1, u32> alphablend_enable; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 8, BlendEquation> blend_equation_rgb; | ||||
|             BitField<8, 8, BlendEquation> blend_equation_a; | ||||
| 
 | ||||
|             BitField<16, 4, BlendFactor> factor_source_rgb; | ||||
|             BitField<20, 4, BlendFactor> factor_dest_rgb; | ||||
| 
 | ||||
|             BitField<24, 4, BlendFactor> factor_source_a; | ||||
|             BitField<28, 4, BlendFactor> factor_dest_a; | ||||
|         } alpha_blending; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 4, LogicOp> logic_op; | ||||
|         }; | ||||
| 
 | ||||
|         union { | ||||
|             u32 raw; | ||||
|             BitField<0, 8, u32> r; | ||||
|             BitField<8, 8, u32> g; | ||||
|             BitField<16, 8, u32> b; | ||||
|             BitField<24, 8, u32> a; | ||||
|         } blend_const; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> enable; | ||||
|             BitField<4, 3, CompareFunc> func; | ||||
|             BitField<8, 8, u32> ref; | ||||
|         } alpha_test; | ||||
| 
 | ||||
|         struct { | ||||
|             union { | ||||
|                 // Raw value of this register
 | ||||
|                 u32 raw_func; | ||||
| 
 | ||||
|                 // If true, enable stencil testing
 | ||||
|                 BitField<0, 1, u32> enable; | ||||
| 
 | ||||
|                 // Comparison operation for stencil testing
 | ||||
|                 BitField<4, 3, CompareFunc> func; | ||||
| 
 | ||||
|                 // Mask used to control writing to the stencil buffer
 | ||||
|                 BitField<8, 8, u32> write_mask; | ||||
| 
 | ||||
|                 // Value to compare against for stencil testing
 | ||||
|                 BitField<16, 8, u32> reference_value; | ||||
| 
 | ||||
|                 // Mask to apply on stencil test inputs
 | ||||
|                 BitField<24, 8, u32> input_mask; | ||||
|             }; | ||||
| 
 | ||||
|             union { | ||||
|                 // Raw value of this register
 | ||||
|                 u32 raw_op; | ||||
| 
 | ||||
|                 // Action to perform when the stencil test fails
 | ||||
|                 BitField<0, 3, StencilAction> action_stencil_fail; | ||||
| 
 | ||||
|                 // Action to perform when stencil testing passed but depth testing fails
 | ||||
|                 BitField<4, 3, StencilAction> action_depth_fail; | ||||
| 
 | ||||
|                 // Action to perform when both stencil and depth testing pass
 | ||||
|                 BitField<8, 3, StencilAction> action_depth_pass; | ||||
|             }; | ||||
|         } stencil_test; | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 1, u32> depth_test_enable; | ||||
|             BitField<4, 3, CompareFunc> depth_test_func; | ||||
|             BitField<8, 1, u32> red_enable; | ||||
|             BitField<9, 1, u32> green_enable; | ||||
|             BitField<10, 1, u32> blue_enable; | ||||
|             BitField<11, 1, u32> alpha_enable; | ||||
|             BitField<12, 1, u32> depth_write_enable; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x8); | ||||
|     } output_merger; | ||||
| 
 | ||||
|     // Components are laid out in reverse byte order, most significant bits first.
 | ||||
|     enum class ColorFormat : u32 { | ||||
|         RGBA8 = 0, | ||||
|         RGB8 = 1, | ||||
|         RGB5A1 = 2, | ||||
|         RGB565 = 3, | ||||
|         RGBA4 = 4, | ||||
|     }; | ||||
| 
 | ||||
|     enum class DepthFormat : u32 { | ||||
|         D16 = 0, | ||||
|         D24 = 2, | ||||
|         D24S8 = 3, | ||||
|     }; | ||||
| 
 | ||||
|     // Returns the number of bytes in the specified color format
 | ||||
|     static unsigned BytesPerColorPixel(ColorFormat format) { | ||||
|         switch (format) { | ||||
|         case ColorFormat::RGBA8: | ||||
|             return 4; | ||||
|         case ColorFormat::RGB8: | ||||
|             return 3; | ||||
|         case ColorFormat::RGB5A1: | ||||
|         case ColorFormat::RGB565: | ||||
|         case ColorFormat::RGBA4: | ||||
|             return 2; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown color format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     struct FramebufferConfig { | ||||
|         INSERT_PADDING_WORDS(0x3); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
 | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         union { | ||||
|             BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
 | ||||
|         }; | ||||
| 
 | ||||
|         DepthFormat depth_format; // TODO: Should be a BitField!
 | ||||
|         BitField<16, 3, ColorFormat> color_format; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x4); | ||||
| 
 | ||||
|         u32 depth_buffer_address; | ||||
|         u32 color_buffer_address; | ||||
| 
 | ||||
|         union { | ||||
|             // Apparently, the framebuffer width is stored as expected,
 | ||||
|             // while the height is stored as the actual height minus one.
 | ||||
|             // Hence, don't access these fields directly but use the accessors
 | ||||
|             // GetWidth() and GetHeight() instead.
 | ||||
|             BitField<0, 11, u32> width; | ||||
|             BitField<12, 10, u32> height; | ||||
|         }; | ||||
| 
 | ||||
|         INSERT_PADDING_WORDS(0x1); | ||||
| 
 | ||||
|         inline PAddr GetColorBufferPhysicalAddress() const { | ||||
|             return color_buffer_address * 8; | ||||
|         } | ||||
|         inline PAddr GetDepthBufferPhysicalAddress() const { | ||||
|             return depth_buffer_address * 8; | ||||
|         } | ||||
| 
 | ||||
|         inline u32 GetWidth() const { | ||||
|             return width; | ||||
|         } | ||||
| 
 | ||||
|         inline u32 GetHeight() const { | ||||
|             return height + 1; | ||||
|         } | ||||
|     } framebuffer; | ||||
| 
 | ||||
|     // Returns the number of bytes in the specified depth format
 | ||||
|     static u32 BytesPerDepthPixel(DepthFormat format) { | ||||
|         switch (format) { | ||||
|         case DepthFormat::D16: | ||||
|             return 2; | ||||
|         case DepthFormat::D24: | ||||
|             return 3; | ||||
|         case DepthFormat::D24S8: | ||||
|             return 4; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Returns the number of bits per depth component of the specified depth format
 | ||||
|     static u32 DepthBitsPerPixel(DepthFormat format) { | ||||
|         switch (format) { | ||||
|         case DepthFormat::D16: | ||||
|             return 16; | ||||
|         case DepthFormat::D24: | ||||
|         case DepthFormat::D24S8: | ||||
|             return 24; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     INSERT_PADDING_WORDS(0x20); | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32), | ||||
|               "FramebufferRegs struct has incorrect size"); | ||||
| 
 | ||||
| } // namespace Pica
 | ||||
|  | @ -183,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() { | |||
|     CachedSurface* depth_surface; | ||||
|     MathUtil::Rectangle<int> rect; | ||||
|     std::tie(color_surface, depth_surface, rect) = | ||||
|         res_cache.GetFramebufferSurfaces(regs.framebuffer); | ||||
|         res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer); | ||||
| 
 | ||||
|     state.draw.draw_framebuffer = framebuffer.handle; | ||||
|     state.Apply(); | ||||
|  | @ -192,7 +192,8 @@ void RasterizerOpenGL::DrawTriangles() { | |||
|                            color_surface != nullptr ? color_surface->texture.handle : 0, 0); | ||||
|     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | ||||
|                            depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); | ||||
|     bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | ||||
|     bool has_stencil = | ||||
|         regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; | ||||
|     glFramebufferTexture2D( | ||||
|         GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | ||||
|         (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); | ||||
|  | @ -339,13 +340,13 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
|         break; | ||||
| 
 | ||||
|     // Blending
 | ||||
|     case PICA_REG_INDEX(output_merger.alphablend_enable): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable): | ||||
|         SyncBlendEnabled(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(output_merger.alpha_blending): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending): | ||||
|         SyncBlendFuncs(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(output_merger.blend_const): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.blend_const): | ||||
|         SyncBlendColor(); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -365,25 +366,25 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
|         break; | ||||
| 
 | ||||
|     // Alpha test
 | ||||
|     case PICA_REG_INDEX(output_merger.alpha_test): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.alpha_test): | ||||
|         SyncAlphaTest(); | ||||
|         shader_dirty = true; | ||||
|         break; | ||||
| 
 | ||||
|     // Sync GL stencil test + stencil write mask
 | ||||
|     // (Pica stencil test function register also contains a stencil write mask)
 | ||||
|     case PICA_REG_INDEX(output_merger.stencil_test.raw_func): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func): | ||||
|         SyncStencilTest(); | ||||
|         SyncStencilWriteMask(); | ||||
|         break; | ||||
|     case PICA_REG_INDEX(output_merger.stencil_test.raw_op): | ||||
|     case PICA_REG_INDEX(framebuffer.depth_format): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op): | ||||
|     case PICA_REG_INDEX(framebuffer.framebuffer.depth_format): | ||||
|         SyncStencilTest(); | ||||
|         break; | ||||
| 
 | ||||
|     // Sync GL depth test + depth and color write mask
 | ||||
|     // (Pica depth test function register also contains a depth and color write mask)
 | ||||
|     case PICA_REG_INDEX(output_merger.depth_test_enable): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable): | ||||
|         SyncDepthTest(); | ||||
|         SyncDepthWriteMask(); | ||||
|         SyncColorWriteMask(); | ||||
|  | @ -391,14 +392,14 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 
 | ||||
|     // Sync GL depth and stencil write mask
 | ||||
|     // (This is a dedicated combined depth / stencil write-enable register)
 | ||||
|     case PICA_REG_INDEX(framebuffer.allow_depth_stencil_write): | ||||
|     case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write): | ||||
|         SyncDepthWriteMask(); | ||||
|         SyncStencilWriteMask(); | ||||
|         break; | ||||
| 
 | ||||
|     // Sync GL color write mask
 | ||||
|     // (This is a dedicated color write-enable register)
 | ||||
|     case PICA_REG_INDEX(framebuffer.allow_color_write): | ||||
|     case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write): | ||||
|         SyncColorWriteMask(); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -408,7 +409,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
|         break; | ||||
| 
 | ||||
|     // Logic op
 | ||||
|     case PICA_REG_INDEX(output_merger.logic_op): | ||||
|     case PICA_REG_INDEX(framebuffer.output_merger.logic_op): | ||||
|         SyncLogicOp(); | ||||
|         break; | ||||
| 
 | ||||
|  | @ -1158,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() { | |||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendEnabled() { | ||||
|     state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); | ||||
|     state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendFuncs() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.blend.rgb_equation = | ||||
|         PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); | ||||
|         PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb); | ||||
|     state.blend.a_equation = | ||||
|         PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); | ||||
|         PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a); | ||||
|     state.blend.src_rgb_func = | ||||
|         PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb); | ||||
|     state.blend.dst_rgb_func = | ||||
|         PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); | ||||
|     state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); | ||||
|     state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb); | ||||
|     state.blend.src_a_func = | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a); | ||||
|     state.blend.dst_a_func = | ||||
|         PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncBlendColor() { | ||||
|     auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); | ||||
|     auto blend_color = | ||||
|         PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw); | ||||
|     state.blend.color.red = blend_color[0]; | ||||
|     state.blend.color.green = blend_color[1]; | ||||
|     state.blend.color.blue = blend_color[2]; | ||||
|  | @ -1208,66 +1212,73 @@ void RasterizerOpenGL::SyncFogLUT() { | |||
| 
 | ||||
| void RasterizerOpenGL::SyncAlphaTest() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { | ||||
|         uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref; | ||||
|     if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { | ||||
|         uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref; | ||||
|         uniform_block_data.dirty = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncLogicOp() { | ||||
|     state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); | ||||
|     state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncColorWriteMask() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
| 
 | ||||
|     auto IsColorWriteEnabled = [&](u32 value) { | ||||
|         return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; | ||||
|         return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE | ||||
|                                                                                    : GL_FALSE; | ||||
|     }; | ||||
| 
 | ||||
|     state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable); | ||||
|     state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable); | ||||
|     state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable); | ||||
|     state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable); | ||||
|     state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable); | ||||
|     state.color_mask.green_enabled = | ||||
|         IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable); | ||||
|     state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable); | ||||
|     state.color_mask.alpha_enabled = | ||||
|         IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncStencilWriteMask() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) | ||||
|                                    ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) | ||||
|                                    : 0; | ||||
|     state.stencil.write_mask = | ||||
|         (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) | ||||
|             ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask) | ||||
|             : 0; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncDepthWriteMask() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.depth.write_mask = | ||||
|         (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) | ||||
|             ? GL_TRUE | ||||
|             : GL_FALSE; | ||||
|     state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && | ||||
|                               regs.framebuffer.output_merger.depth_write_enable) | ||||
|                                  ? GL_TRUE | ||||
|                                  : GL_FALSE; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncStencilTest() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.stencil.test_enabled = regs.output_merger.stencil_test.enable && | ||||
|                                  regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | ||||
|     state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); | ||||
|     state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; | ||||
|     state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; | ||||
|     state.stencil.test_enabled = | ||||
|         regs.framebuffer.output_merger.stencil_test.enable && | ||||
|         regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; | ||||
|     state.stencil.test_func = | ||||
|         PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func); | ||||
|     state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value; | ||||
|     state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask; | ||||
|     state.stencil.action_stencil_fail = | ||||
|         PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); | ||||
|         PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail); | ||||
|     state.stencil.action_depth_fail = | ||||
|         PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); | ||||
|         PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail); | ||||
|     state.stencil.action_depth_pass = | ||||
|         PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); | ||||
|         PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass); | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncDepthTest() { | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
|     state.depth.test_enabled = | ||||
|         regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; | ||||
|     state.depth.test_func = regs.output_merger.depth_test_enable == 1 | ||||
|                                 ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) | ||||
|                                 : GL_ALWAYS; | ||||
|     state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 || | ||||
|                                regs.framebuffer.output_merger.depth_write_enable == 1; | ||||
|     state.depth.test_func = | ||||
|         regs.framebuffer.output_merger.depth_test_enable == 1 | ||||
|             ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func) | ||||
|             : GL_ALWAYS; | ||||
| } | ||||
| 
 | ||||
| void RasterizerOpenGL::SyncCombinerColor() { | ||||
|  |  | |||
|  | @ -56,9 +56,9 @@ union PicaShaderConfig { | |||
| 
 | ||||
|         state.depthmap_enable = regs.rasterizer.depthmap_enable; | ||||
| 
 | ||||
|         state.alpha_test_func = regs.output_merger.alpha_test.enable | ||||
|                                     ? regs.output_merger.alpha_test.func.Value() | ||||
|                                     : Pica::Regs::CompareFunc::Always; | ||||
|         state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable | ||||
|                                     ? regs.framebuffer.output_merger.alpha_test.func.Value() | ||||
|                                     : Pica::FramebufferRegs::CompareFunc::Always; | ||||
| 
 | ||||
|         state.texture0_type = regs.texturing.texture0.type; | ||||
| 
 | ||||
|  | @ -172,7 +172,7 @@ union PicaShaderConfig { | |||
|     }; | ||||
| 
 | ||||
|     struct State { | ||||
|         Pica::Regs::CompareFunc alpha_test_func; | ||||
|         Pica::FramebufferRegs::CompareFunc alpha_test_func; | ||||
|         Pica::RasterizerRegs::ScissorMode scissor_test_mode; | ||||
|         Pica::TexturingRegs::TextureConfig::TextureType texture0_type; | ||||
|         std::array<TevStageConfigRaw, 6> tev_stages; | ||||
|  |  | |||
|  | @ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface( | |||
| } | ||||
| 
 | ||||
| std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> | ||||
| RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { | ||||
| RasterizerCacheOpenGL::GetFramebufferSurfaces( | ||||
|     const Pica::FramebufferRegs::FramebufferConfig& config) { | ||||
| 
 | ||||
|     const auto& regs = Pica::g_state.regs; | ||||
| 
 | ||||
|     // Make sur that framebuffers don't overlap if both color and depth are being used
 | ||||
|  | @ -537,11 +539,12 @@ RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfi | |||
|             config.GetColorBufferPhysicalAddress(), | ||||
|             fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), | ||||
|             config.GetDepthBufferPhysicalAddress(), | ||||
|             fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); | ||||
|             fb_area * Pica::FramebufferRegs::BytesPerDepthPixel(config.depth_format)); | ||||
|     bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; | ||||
|     bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && | ||||
|                           (regs.output_merger.depth_test_enable || | ||||
|                            regs.output_merger.depth_write_enable || !framebuffers_overlap); | ||||
|     bool using_depth_fb = | ||||
|         config.GetDepthBufferPhysicalAddress() != 0 && | ||||
|         (regs.framebuffer.output_merger.depth_test_enable || | ||||
|          regs.framebuffer.output_merger.depth_write_enable || !framebuffers_overlap); | ||||
| 
 | ||||
|     if (framebuffers_overlap && using_color_fb && using_depth_fb) { | ||||
|         LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " | ||||
|  |  | |||
|  | @ -100,11 +100,11 @@ struct CachedSurface { | |||
|         return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromColorFormat(Pica::Regs::ColorFormat format) { | ||||
|     static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { | ||||
|         return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; | ||||
|     } | ||||
| 
 | ||||
|     static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { | ||||
|     static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { | ||||
|         return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) | ||||
|                                           : PixelFormat::Invalid; | ||||
|     } | ||||
|  | @ -217,7 +217,7 @@ public: | |||
|     /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer
 | ||||
|     /// configuration
 | ||||
|     std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces( | ||||
|         const Pica::Regs::FramebufferConfig& config); | ||||
|         const Pica::FramebufferRegs::FramebufferConfig& config); | ||||
| 
 | ||||
|     /// Attempt to get a surface that exactly matches the fill region and format
 | ||||
|     CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); | ||||
|  |  | |||
|  | @ -277,8 +277,8 @@ static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation oper | |||
| } | ||||
| 
 | ||||
| /// Writes the if-statement condition used to evaluate alpha testing
 | ||||
| static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | ||||
|     using CompareFunc = Regs::CompareFunc; | ||||
| static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) { | ||||
|     using CompareFunc = Pica::FramebufferRegs::CompareFunc; | ||||
|     switch (func) { | ||||
|     case CompareFunc::Never: | ||||
|         out += "true"; | ||||
|  | @ -634,7 +634,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| )"; | ||||
| 
 | ||||
|     // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 | ||||
|     if (state.alpha_test_func == Regs::CompareFunc::Never) { | ||||
|     if (state.alpha_test_func == Pica::FramebufferRegs::CompareFunc::Never) { | ||||
|         out += "discard; }"; | ||||
|         return out; | ||||
|     } | ||||
|  | @ -667,7 +667,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
|     for (size_t index = 0; index < state.tev_stages.size(); ++index) | ||||
|         WriteTevStage(out, config, (unsigned)index); | ||||
| 
 | ||||
|     if (state.alpha_test_func != Regs::CompareFunc::Always) { | ||||
|     if (state.alpha_test_func != Pica::FramebufferRegs::CompareFunc::Always) { | ||||
|         out += "if ("; | ||||
|         AppendAlphaTestCondition(out, state.alpha_test_func); | ||||
|         out += ") discard;\n"; | ||||
|  |  | |||
|  | @ -76,7 +76,7 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) { | |||
|     return gl_mode; | ||||
| } | ||||
| 
 | ||||
| inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { | ||||
| inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) { | ||||
|     static const GLenum blend_equation_table[] = { | ||||
|         GL_FUNC_ADD,              // BlendEquation::Add
 | ||||
|         GL_FUNC_SUBTRACT,         // BlendEquation::Subtract
 | ||||
|  | @ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { | |||
|     return blend_equation_table[(unsigned)equation]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | ||||
| inline GLenum BlendFunc(Pica::FramebufferRegs::BlendFactor factor) { | ||||
|     static const GLenum blend_func_table[] = { | ||||
|         GL_ZERO,                     // BlendFactor::Zero
 | ||||
|         GL_ONE,                      // BlendFactor::One
 | ||||
|  | @ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | |||
|     return blend_func_table[(unsigned)factor]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum LogicOp(Pica::Regs::LogicOp op) { | ||||
| inline GLenum LogicOp(Pica::FramebufferRegs::LogicOp op) { | ||||
|     static const GLenum logic_op_table[] = { | ||||
|         GL_CLEAR,         // Clear
 | ||||
|         GL_AND,           // And
 | ||||
|  | @ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) { | |||
|     return logic_op_table[(unsigned)op]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | ||||
| inline GLenum CompareFunc(Pica::FramebufferRegs::CompareFunc func) { | ||||
|     static const GLenum compare_func_table[] = { | ||||
|         GL_NEVER,    // CompareFunc::Never
 | ||||
|         GL_ALWAYS,   // CompareFunc::Always
 | ||||
|  | @ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | |||
|     return compare_func_table[(unsigned)func]; | ||||
| } | ||||
| 
 | ||||
| inline GLenum StencilOp(Pica::Regs::StencilAction action) { | ||||
| inline GLenum StencilOp(Pica::FramebufferRegs::StencilAction action) { | ||||
|     static const GLenum stencil_op_table[] = { | ||||
|         GL_KEEP,      // StencilAction::Keep
 | ||||
|         GL_ZERO,      // StencilAction::Zero
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue