From 23713d5dee8015a73ecab1bf944ebcab908e347c Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Fri, 27 Jan 2017 21:47:34 -0800 Subject: [PATCH] VideoCore: Split framebuffer regs from Regs struct --- .../debugger/graphics/graphics_surface.cpp | 24 +- src/video_core/CMakeLists.txt | 1 + src/video_core/pica.h | 270 +---------------- src/video_core/rasterizer.cpp | 229 +++++++------- src/video_core/regs_framebuffer.h | 282 ++++++++++++++++++ .../renderer_opengl/gl_rasterizer.cpp | 109 ++++--- .../renderer_opengl/gl_rasterizer.h | 8 +- .../renderer_opengl/gl_rasterizer_cache.cpp | 13 +- .../renderer_opengl/gl_rasterizer_cache.h | 6 +- .../renderer_opengl/gl_shader_gen.cpp | 8 +- src/video_core/renderer_opengl/pica_to_gl.h | 10 +- 11 files changed, 503 insertions(+), 457 deletions(-) create mode 100644 src/video_core/regs_framebuffer.h diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp index 406a49f42..78156d5ec 100644 --- a/src/citra_qt/debugger/graphics/graphics_surface.cpp +++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp @@ -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; diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index c0358fc20..718c709e5 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -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 diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 71194198a..50a549c42 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.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); diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 48bc26571..f053143f1 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -29,7 +29,7 @@ namespace Pica { namespace Rasterizer { static void DrawPixel(int x, int y, const Math::Vec4& 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& 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& color) { } static const Math::Vec4 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 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 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(old_stencil, 254) + 1; - case Regs::StencilAction::Decrement: + case FramebufferRegs::StencilAction::Decrement: // Saturated decrement return std::max(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 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& src, const Math::Vec4& srcfactor, const Math::Vec4& dest, const Math::Vec4& destfactor, - Regs::BlendEquation equation) { + FramebufferRegs::BlendEquation equation) { + Math::Vec4 result; auto src_result = (src * srcfactor).Cast(); auto dst_result = (dest * destfactor).Cast(); 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); } } diff --git a/src/video_core/regs_framebuffer.h b/src/video_core/regs_framebuffer.h new file mode 100644 index 000000000..40d8aea0c --- /dev/null +++ b/src/video_core/regs_framebuffer.h @@ -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 + +#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 diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index f7eaa17e2..967c3159f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -183,7 +183,7 @@ void RasterizerOpenGL::DrawTriangles() { CachedSurface* depth_surface; MathUtil::Rectangle 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(regs.output_merger.stencil_test.write_mask) - : 0; + state.stencil.write_mask = + (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) + ? static_cast(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() { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 519df6478..bfdc0c8a4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -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 tev_stages; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 6d08d1a67..0818a87b3 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -525,7 +525,9 @@ CachedSurface* RasterizerCacheOpenGL::GetTextureSurface( } std::tuple> -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; " diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index c354dfa33..2812b4bf6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -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> 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); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index c3b0fdcee..9c7687f62 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -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"; diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index 37cfbd45a..c1bf3dc24 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h @@ -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