diff options
| author | 2017-01-27 21:47:34 -0800 | |
|---|---|---|
| committer | 2017-02-04 13:59:11 -0800 | |
| commit | 23713d5dee8015a73ecab1bf944ebcab908e347c (patch) | |
| tree | 160bdc8411a899f690e51d055ad1213e19abba5c /src | |
| parent | VideoCore: Split texturing regs from Regs struct (diff) | |
| download | yuzu-23713d5dee8015a73ecab1bf944ebcab908e347c.tar.gz yuzu-23713d5dee8015a73ecab1bf944ebcab908e347c.tar.xz yuzu-23713d5dee8015a73ecab1bf944ebcab908e347c.zip | |
VideoCore: Split framebuffer regs from Regs struct
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/debugger/graphics/graphics_surface.cpp | 24 | ||||
| -rw-r--r-- | src/video_core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/video_core/pica.h | 270 | ||||
| -rw-r--r-- | src/video_core/rasterizer.cpp | 229 | ||||
| -rw-r--r-- | src/video_core/regs_framebuffer.h | 282 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 109 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/pica_to_gl.h | 10 |
11 files changed, 503 insertions, 457 deletions
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() { | |||
| 414 | // TODO: Store a reference to the registers in the debug context instead of accessing them | 414 | // TODO: Store a reference to the registers in the debug context instead of accessing them |
| 415 | // directly... | 415 | // directly... |
| 416 | 416 | ||
| 417 | const auto& framebuffer = Pica::g_state.regs.framebuffer; | 417 | const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer; |
| 418 | 418 | ||
| 419 | surface_address = framebuffer.GetColorBufferPhysicalAddress(); | 419 | surface_address = framebuffer.GetColorBufferPhysicalAddress(); |
| 420 | surface_width = framebuffer.GetWidth(); | 420 | surface_width = framebuffer.GetWidth(); |
| 421 | surface_height = framebuffer.GetHeight(); | 421 | surface_height = framebuffer.GetHeight(); |
| 422 | 422 | ||
| 423 | switch (framebuffer.color_format) { | 423 | switch (framebuffer.color_format) { |
| 424 | case Pica::Regs::ColorFormat::RGBA8: | 424 | case Pica::FramebufferRegs::ColorFormat::RGBA8: |
| 425 | surface_format = Format::RGBA8; | 425 | surface_format = Format::RGBA8; |
| 426 | break; | 426 | break; |
| 427 | 427 | ||
| 428 | case Pica::Regs::ColorFormat::RGB8: | 428 | case Pica::FramebufferRegs::ColorFormat::RGB8: |
| 429 | surface_format = Format::RGB8; | 429 | surface_format = Format::RGB8; |
| 430 | break; | 430 | break; |
| 431 | 431 | ||
| 432 | case Pica::Regs::ColorFormat::RGB5A1: | 432 | case Pica::FramebufferRegs::ColorFormat::RGB5A1: |
| 433 | surface_format = Format::RGB5A1; | 433 | surface_format = Format::RGB5A1; |
| 434 | break; | 434 | break; |
| 435 | 435 | ||
| 436 | case Pica::Regs::ColorFormat::RGB565: | 436 | case Pica::FramebufferRegs::ColorFormat::RGB565: |
| 437 | surface_format = Format::RGB565; | 437 | surface_format = Format::RGB565; |
| 438 | break; | 438 | break; |
| 439 | 439 | ||
| 440 | case Pica::Regs::ColorFormat::RGBA4: | 440 | case Pica::FramebufferRegs::ColorFormat::RGBA4: |
| 441 | surface_format = Format::RGBA4; | 441 | surface_format = Format::RGBA4; |
| 442 | break; | 442 | break; |
| 443 | 443 | ||
| @@ -450,22 +450,22 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | case Source::DepthBuffer: { | 452 | case Source::DepthBuffer: { |
| 453 | const auto& framebuffer = Pica::g_state.regs.framebuffer; | 453 | const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer; |
| 454 | 454 | ||
| 455 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); | 455 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); |
| 456 | surface_width = framebuffer.GetWidth(); | 456 | surface_width = framebuffer.GetWidth(); |
| 457 | surface_height = framebuffer.GetHeight(); | 457 | surface_height = framebuffer.GetHeight(); |
| 458 | 458 | ||
| 459 | switch (framebuffer.depth_format) { | 459 | switch (framebuffer.depth_format) { |
| 460 | case Pica::Regs::DepthFormat::D16: | 460 | case Pica::FramebufferRegs::DepthFormat::D16: |
| 461 | surface_format = Format::D16; | 461 | surface_format = Format::D16; |
| 462 | break; | 462 | break; |
| 463 | 463 | ||
| 464 | case Pica::Regs::DepthFormat::D24: | 464 | case Pica::FramebufferRegs::DepthFormat::D24: |
| 465 | surface_format = Format::D24; | 465 | surface_format = Format::D24; |
| 466 | break; | 466 | break; |
| 467 | 467 | ||
| 468 | case Pica::Regs::DepthFormat::D24S8: | 468 | case Pica::FramebufferRegs::DepthFormat::D24S8: |
| 469 | surface_format = Format::D24X8; | 469 | surface_format = Format::D24X8; |
| 470 | break; | 470 | break; |
| 471 | 471 | ||
| @@ -478,14 +478,14 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 478 | } | 478 | } |
| 479 | 479 | ||
| 480 | case Source::StencilBuffer: { | 480 | case Source::StencilBuffer: { |
| 481 | const auto& framebuffer = Pica::g_state.regs.framebuffer; | 481 | const auto& framebuffer = Pica::g_state.regs.framebuffer.framebuffer; |
| 482 | 482 | ||
| 483 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); | 483 | surface_address = framebuffer.GetDepthBufferPhysicalAddress(); |
| 484 | surface_width = framebuffer.GetWidth(); | 484 | surface_width = framebuffer.GetWidth(); |
| 485 | surface_height = framebuffer.GetHeight(); | 485 | surface_height = framebuffer.GetHeight(); |
| 486 | 486 | ||
| 487 | switch (framebuffer.depth_format) { | 487 | switch (framebuffer.depth_format) { |
| 488 | case Pica::Regs::DepthFormat::D24S8: | 488 | case Pica::FramebufferRegs::DepthFormat::D24S8: |
| 489 | surface_format = Format::X24S8; | 489 | surface_format = Format::X24S8; |
| 490 | break; | 490 | break; |
| 491 | 491 | ||
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 | |||
| 32 | primitive_assembly.h | 32 | primitive_assembly.h |
| 33 | rasterizer.h | 33 | rasterizer.h |
| 34 | rasterizer_interface.h | 34 | rasterizer_interface.h |
| 35 | regs_framebuffer.h | ||
| 35 | regs_rasterizer.h | 36 | regs_rasterizer.h |
| 36 | regs_texturing.h | 37 | regs_texturing.h |
| 37 | renderer_base.h | 38 | 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 @@ | |||
| 18 | #include "common/common_types.h" | 18 | #include "common/common_types.h" |
| 19 | #include "common/logging/log.h" | 19 | #include "common/logging/log.h" |
| 20 | #include "common/vector_math.h" | 20 | #include "common/vector_math.h" |
| 21 | #include "video_core/regs_framebuffer.h" | ||
| 21 | #include "video_core/regs_rasterizer.h" | 22 | #include "video_core/regs_rasterizer.h" |
| 22 | #include "video_core/regs_texturing.h" | 23 | #include "video_core/regs_texturing.h" |
| 23 | 24 | ||
| @@ -51,268 +52,7 @@ struct Regs { | |||
| 51 | INSERT_PADDING_WORDS(0x2f); | 52 | INSERT_PADDING_WORDS(0x2f); |
| 52 | RasterizerRegs rasterizer; | 53 | RasterizerRegs rasterizer; |
| 53 | TexturingRegs texturing; | 54 | TexturingRegs texturing; |
| 54 | 55 | FramebufferRegs framebuffer; | |
| 55 | enum class LogicOp : u32 { | ||
| 56 | Clear = 0, | ||
| 57 | And = 1, | ||
| 58 | AndReverse = 2, | ||
| 59 | Copy = 3, | ||
| 60 | Set = 4, | ||
| 61 | CopyInverted = 5, | ||
| 62 | NoOp = 6, | ||
| 63 | Invert = 7, | ||
| 64 | Nand = 8, | ||
| 65 | Or = 9, | ||
| 66 | Nor = 10, | ||
| 67 | Xor = 11, | ||
| 68 | Equiv = 12, | ||
| 69 | AndInverted = 13, | ||
| 70 | OrReverse = 14, | ||
| 71 | OrInverted = 15, | ||
| 72 | }; | ||
| 73 | |||
| 74 | enum class BlendEquation : u32 { | ||
| 75 | Add = 0, | ||
| 76 | Subtract = 1, | ||
| 77 | ReverseSubtract = 2, | ||
| 78 | Min = 3, | ||
| 79 | Max = 4, | ||
| 80 | }; | ||
| 81 | |||
| 82 | enum class BlendFactor : u32 { | ||
| 83 | Zero = 0, | ||
| 84 | One = 1, | ||
| 85 | SourceColor = 2, | ||
| 86 | OneMinusSourceColor = 3, | ||
| 87 | DestColor = 4, | ||
| 88 | OneMinusDestColor = 5, | ||
| 89 | SourceAlpha = 6, | ||
| 90 | OneMinusSourceAlpha = 7, | ||
| 91 | DestAlpha = 8, | ||
| 92 | OneMinusDestAlpha = 9, | ||
| 93 | ConstantColor = 10, | ||
| 94 | OneMinusConstantColor = 11, | ||
| 95 | ConstantAlpha = 12, | ||
| 96 | OneMinusConstantAlpha = 13, | ||
| 97 | SourceAlphaSaturate = 14, | ||
| 98 | }; | ||
| 99 | |||
| 100 | enum class CompareFunc : u32 { | ||
| 101 | Never = 0, | ||
| 102 | Always = 1, | ||
| 103 | Equal = 2, | ||
| 104 | NotEqual = 3, | ||
| 105 | LessThan = 4, | ||
| 106 | LessThanOrEqual = 5, | ||
| 107 | GreaterThan = 6, | ||
| 108 | GreaterThanOrEqual = 7, | ||
| 109 | }; | ||
| 110 | |||
| 111 | enum class StencilAction : u32 { | ||
| 112 | Keep = 0, | ||
| 113 | Zero = 1, | ||
| 114 | Replace = 2, | ||
| 115 | Increment = 3, | ||
| 116 | Decrement = 4, | ||
| 117 | Invert = 5, | ||
| 118 | IncrementWrap = 6, | ||
| 119 | DecrementWrap = 7, | ||
| 120 | }; | ||
| 121 | |||
| 122 | struct { | ||
| 123 | union { | ||
| 124 | // If false, logic blending is used | ||
| 125 | BitField<8, 1, u32> alphablend_enable; | ||
| 126 | }; | ||
| 127 | |||
| 128 | union { | ||
| 129 | BitField<0, 8, BlendEquation> blend_equation_rgb; | ||
| 130 | BitField<8, 8, BlendEquation> blend_equation_a; | ||
| 131 | |||
| 132 | BitField<16, 4, BlendFactor> factor_source_rgb; | ||
| 133 | BitField<20, 4, BlendFactor> factor_dest_rgb; | ||
| 134 | |||
| 135 | BitField<24, 4, BlendFactor> factor_source_a; | ||
| 136 | BitField<28, 4, BlendFactor> factor_dest_a; | ||
| 137 | } alpha_blending; | ||
| 138 | |||
| 139 | union { | ||
| 140 | BitField<0, 4, LogicOp> logic_op; | ||
| 141 | }; | ||
| 142 | |||
| 143 | union { | ||
| 144 | u32 raw; | ||
| 145 | BitField<0, 8, u32> r; | ||
| 146 | BitField<8, 8, u32> g; | ||
| 147 | BitField<16, 8, u32> b; | ||
| 148 | BitField<24, 8, u32> a; | ||
| 149 | } blend_const; | ||
| 150 | |||
| 151 | union { | ||
| 152 | BitField<0, 1, u32> enable; | ||
| 153 | BitField<4, 3, CompareFunc> func; | ||
| 154 | BitField<8, 8, u32> ref; | ||
| 155 | } alpha_test; | ||
| 156 | |||
| 157 | struct { | ||
| 158 | union { | ||
| 159 | // Raw value of this register | ||
| 160 | u32 raw_func; | ||
| 161 | |||
| 162 | // If true, enable stencil testing | ||
| 163 | BitField<0, 1, u32> enable; | ||
| 164 | |||
| 165 | // Comparison operation for stencil testing | ||
| 166 | BitField<4, 3, CompareFunc> func; | ||
| 167 | |||
| 168 | // Mask used to control writing to the stencil buffer | ||
| 169 | BitField<8, 8, u32> write_mask; | ||
| 170 | |||
| 171 | // Value to compare against for stencil testing | ||
| 172 | BitField<16, 8, u32> reference_value; | ||
| 173 | |||
| 174 | // Mask to apply on stencil test inputs | ||
| 175 | BitField<24, 8, u32> input_mask; | ||
| 176 | }; | ||
| 177 | |||
| 178 | union { | ||
| 179 | // Raw value of this register | ||
| 180 | u32 raw_op; | ||
| 181 | |||
| 182 | // Action to perform when the stencil test fails | ||
| 183 | BitField<0, 3, StencilAction> action_stencil_fail; | ||
| 184 | |||
| 185 | // Action to perform when stencil testing passed but depth testing fails | ||
| 186 | BitField<4, 3, StencilAction> action_depth_fail; | ||
| 187 | |||
| 188 | // Action to perform when both stencil and depth testing pass | ||
| 189 | BitField<8, 3, StencilAction> action_depth_pass; | ||
| 190 | }; | ||
| 191 | } stencil_test; | ||
| 192 | |||
| 193 | union { | ||
| 194 | BitField<0, 1, u32> depth_test_enable; | ||
| 195 | BitField<4, 3, CompareFunc> depth_test_func; | ||
| 196 | BitField<8, 1, u32> red_enable; | ||
| 197 | BitField<9, 1, u32> green_enable; | ||
| 198 | BitField<10, 1, u32> blue_enable; | ||
| 199 | BitField<11, 1, u32> alpha_enable; | ||
| 200 | BitField<12, 1, u32> depth_write_enable; | ||
| 201 | }; | ||
| 202 | |||
| 203 | INSERT_PADDING_WORDS(0x8); | ||
| 204 | } output_merger; | ||
| 205 | |||
| 206 | // Components are laid out in reverse byte order, most significant bits first. | ||
| 207 | enum class ColorFormat : u32 { | ||
| 208 | RGBA8 = 0, | ||
| 209 | RGB8 = 1, | ||
| 210 | RGB5A1 = 2, | ||
| 211 | RGB565 = 3, | ||
| 212 | RGBA4 = 4, | ||
| 213 | }; | ||
| 214 | |||
| 215 | enum class DepthFormat : u32 { | ||
| 216 | D16 = 0, | ||
| 217 | D24 = 2, | ||
| 218 | D24S8 = 3, | ||
| 219 | }; | ||
| 220 | |||
| 221 | // Returns the number of bytes in the specified color format | ||
| 222 | static unsigned BytesPerColorPixel(ColorFormat format) { | ||
| 223 | switch (format) { | ||
| 224 | case ColorFormat::RGBA8: | ||
| 225 | return 4; | ||
| 226 | case ColorFormat::RGB8: | ||
| 227 | return 3; | ||
| 228 | case ColorFormat::RGB5A1: | ||
| 229 | case ColorFormat::RGB565: | ||
| 230 | case ColorFormat::RGBA4: | ||
| 231 | return 2; | ||
| 232 | default: | ||
| 233 | LOG_CRITICAL(HW_GPU, "Unknown color format %u", format); | ||
| 234 | UNIMPLEMENTED(); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | struct FramebufferConfig { | ||
| 239 | INSERT_PADDING_WORDS(0x3); | ||
| 240 | |||
| 241 | union { | ||
| 242 | BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable | ||
| 243 | }; | ||
| 244 | |||
| 245 | INSERT_PADDING_WORDS(0x1); | ||
| 246 | |||
| 247 | union { | ||
| 248 | BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable | ||
| 249 | }; | ||
| 250 | |||
| 251 | DepthFormat depth_format; // TODO: Should be a BitField! | ||
| 252 | BitField<16, 3, ColorFormat> color_format; | ||
| 253 | |||
| 254 | INSERT_PADDING_WORDS(0x4); | ||
| 255 | |||
| 256 | u32 depth_buffer_address; | ||
| 257 | u32 color_buffer_address; | ||
| 258 | |||
| 259 | union { | ||
| 260 | // Apparently, the framebuffer width is stored as expected, | ||
| 261 | // while the height is stored as the actual height minus one. | ||
| 262 | // Hence, don't access these fields directly but use the accessors | ||
| 263 | // GetWidth() and GetHeight() instead. | ||
| 264 | BitField<0, 11, u32> width; | ||
| 265 | BitField<12, 10, u32> height; | ||
| 266 | }; | ||
| 267 | |||
| 268 | INSERT_PADDING_WORDS(0x1); | ||
| 269 | |||
| 270 | inline u32 GetColorBufferPhysicalAddress() const { | ||
| 271 | return DecodeAddressRegister(color_buffer_address); | ||
| 272 | } | ||
| 273 | inline u32 GetDepthBufferPhysicalAddress() const { | ||
| 274 | return DecodeAddressRegister(depth_buffer_address); | ||
| 275 | } | ||
| 276 | |||
| 277 | inline u32 GetWidth() const { | ||
| 278 | return width; | ||
| 279 | } | ||
| 280 | |||
| 281 | inline u32 GetHeight() const { | ||
| 282 | return height + 1; | ||
| 283 | } | ||
| 284 | } framebuffer; | ||
| 285 | |||
| 286 | // Returns the number of bytes in the specified depth format | ||
| 287 | static u32 BytesPerDepthPixel(DepthFormat format) { | ||
| 288 | switch (format) { | ||
| 289 | case DepthFormat::D16: | ||
| 290 | return 2; | ||
| 291 | case DepthFormat::D24: | ||
| 292 | return 3; | ||
| 293 | case DepthFormat::D24S8: | ||
| 294 | return 4; | ||
| 295 | default: | ||
| 296 | LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||
| 297 | UNIMPLEMENTED(); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | // Returns the number of bits per depth component of the specified depth format | ||
| 302 | static u32 DepthBitsPerPixel(DepthFormat format) { | ||
| 303 | switch (format) { | ||
| 304 | case DepthFormat::D16: | ||
| 305 | return 16; | ||
| 306 | case DepthFormat::D24: | ||
| 307 | case DepthFormat::D24S8: | ||
| 308 | return 24; | ||
| 309 | default: | ||
| 310 | LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||
| 311 | UNIMPLEMENTED(); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | INSERT_PADDING_WORDS(0x20); | ||
| 316 | 56 | ||
| 317 | enum class LightingSampler { | 57 | enum class LightingSampler { |
| 318 | Distribution0 = 0, | 58 | Distribution0 = 0, |
| @@ -957,8 +697,10 @@ ASSERT_REG_POSITION(texturing.tev_stage4, 0xf0); | |||
| 957 | ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8); | 697 | ASSERT_REG_POSITION(texturing.tev_stage5, 0xf8); |
| 958 | ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd); | 698 | ASSERT_REG_POSITION(texturing.tev_combiner_buffer_color, 0xfd); |
| 959 | 699 | ||
| 960 | ASSERT_REG_POSITION(output_merger, 0x100); | 700 | ASSERT_REG_POSITION(framebuffer, 0x100); |
| 961 | ASSERT_REG_POSITION(framebuffer, 0x110); | 701 | ASSERT_REG_POSITION(framebuffer.output_merger, 0x100); |
| 702 | ASSERT_REG_POSITION(framebuffer.framebuffer, 0x110); | ||
| 703 | |||
| 962 | ASSERT_REG_POSITION(lighting, 0x140); | 704 | ASSERT_REG_POSITION(lighting, 0x140); |
| 963 | ASSERT_REG_POSITION(vertex_attributes, 0x200); | 705 | ASSERT_REG_POSITION(vertex_attributes, 0x200); |
| 964 | ASSERT_REG_POSITION(index_array, 0x227); | 706 | 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 { | |||
| 29 | namespace Rasterizer { | 29 | namespace Rasterizer { |
| 30 | 30 | ||
| 31 | static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | 31 | static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { |
| 32 | const auto& framebuffer = g_state.regs.framebuffer; | 32 | const auto& framebuffer = g_state.regs.framebuffer.framebuffer; |
| 33 | const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); | 33 | const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); |
| 34 | 34 | ||
| 35 | // Similarly to textures, the render framebuffer is laid out from bottom to top, too. | 35 | // 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) { | |||
| 44 | u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; | 44 | u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; |
| 45 | 45 | ||
| 46 | switch (framebuffer.color_format) { | 46 | switch (framebuffer.color_format) { |
| 47 | case Regs::ColorFormat::RGBA8: | 47 | case FramebufferRegs::ColorFormat::RGBA8: |
| 48 | Color::EncodeRGBA8(color, dst_pixel); | 48 | Color::EncodeRGBA8(color, dst_pixel); |
| 49 | break; | 49 | break; |
| 50 | 50 | ||
| 51 | case Regs::ColorFormat::RGB8: | 51 | case FramebufferRegs::ColorFormat::RGB8: |
| 52 | Color::EncodeRGB8(color, dst_pixel); | 52 | Color::EncodeRGB8(color, dst_pixel); |
| 53 | break; | 53 | break; |
| 54 | 54 | ||
| 55 | case Regs::ColorFormat::RGB5A1: | 55 | case FramebufferRegs::ColorFormat::RGB5A1: |
| 56 | Color::EncodeRGB5A1(color, dst_pixel); | 56 | Color::EncodeRGB5A1(color, dst_pixel); |
| 57 | break; | 57 | break; |
| 58 | 58 | ||
| 59 | case Regs::ColorFormat::RGB565: | 59 | case FramebufferRegs::ColorFormat::RGB565: |
| 60 | Color::EncodeRGB565(color, dst_pixel); | 60 | Color::EncodeRGB565(color, dst_pixel); |
| 61 | break; | 61 | break; |
| 62 | 62 | ||
| 63 | case Regs::ColorFormat::RGBA4: | 63 | case FramebufferRegs::ColorFormat::RGBA4: |
| 64 | Color::EncodeRGBA4(color, dst_pixel); | 64 | Color::EncodeRGBA4(color, dst_pixel); |
| 65 | break; | 65 | break; |
| 66 | 66 | ||
| @@ -72,7 +72,7 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { | |||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static const Math::Vec4<u8> GetPixel(int x, int y) { | 74 | static const Math::Vec4<u8> GetPixel(int x, int y) { |
| 75 | const auto& framebuffer = g_state.regs.framebuffer; | 75 | const auto& framebuffer = g_state.regs.framebuffer.framebuffer; |
| 76 | const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); | 76 | const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); |
| 77 | 77 | ||
| 78 | y = framebuffer.height - y; | 78 | y = framebuffer.height - y; |
| @@ -85,19 +85,19 @@ static const Math::Vec4<u8> GetPixel(int x, int y) { | |||
| 85 | u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; | 85 | u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; |
| 86 | 86 | ||
| 87 | switch (framebuffer.color_format) { | 87 | switch (framebuffer.color_format) { |
| 88 | case Regs::ColorFormat::RGBA8: | 88 | case FramebufferRegs::ColorFormat::RGBA8: |
| 89 | return Color::DecodeRGBA8(src_pixel); | 89 | return Color::DecodeRGBA8(src_pixel); |
| 90 | 90 | ||
| 91 | case Regs::ColorFormat::RGB8: | 91 | case FramebufferRegs::ColorFormat::RGB8: |
| 92 | return Color::DecodeRGB8(src_pixel); | 92 | return Color::DecodeRGB8(src_pixel); |
| 93 | 93 | ||
| 94 | case Regs::ColorFormat::RGB5A1: | 94 | case FramebufferRegs::ColorFormat::RGB5A1: |
| 95 | return Color::DecodeRGB5A1(src_pixel); | 95 | return Color::DecodeRGB5A1(src_pixel); |
| 96 | 96 | ||
| 97 | case Regs::ColorFormat::RGB565: | 97 | case FramebufferRegs::ColorFormat::RGB565: |
| 98 | return Color::DecodeRGB565(src_pixel); | 98 | return Color::DecodeRGB565(src_pixel); |
| 99 | 99 | ||
| 100 | case Regs::ColorFormat::RGBA4: | 100 | case FramebufferRegs::ColorFormat::RGBA4: |
| 101 | return Color::DecodeRGBA4(src_pixel); | 101 | return Color::DecodeRGBA4(src_pixel); |
| 102 | 102 | ||
| 103 | default: | 103 | default: |
| @@ -110,25 +110,25 @@ static const Math::Vec4<u8> GetPixel(int x, int y) { | |||
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | static u32 GetDepth(int x, int y) { | 112 | static u32 GetDepth(int x, int y) { |
| 113 | const auto& framebuffer = g_state.regs.framebuffer; | 113 | const auto& framebuffer = g_state.regs.framebuffer.framebuffer; |
| 114 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | 114 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); |
| 115 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); | 115 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); |
| 116 | 116 | ||
| 117 | y = framebuffer.height - y; | 117 | y = framebuffer.height - y; |
| 118 | 118 | ||
| 119 | const u32 coarse_y = y & ~7; | 119 | const u32 coarse_y = y & ~7; |
| 120 | u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); | 120 | u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); |
| 121 | u32 stride = framebuffer.width * bytes_per_pixel; | 121 | u32 stride = framebuffer.width * bytes_per_pixel; |
| 122 | 122 | ||
| 123 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | 123 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; |
| 124 | u8* src_pixel = depth_buffer + src_offset; | 124 | u8* src_pixel = depth_buffer + src_offset; |
| 125 | 125 | ||
| 126 | switch (framebuffer.depth_format) { | 126 | switch (framebuffer.depth_format) { |
| 127 | case Regs::DepthFormat::D16: | 127 | case FramebufferRegs::DepthFormat::D16: |
| 128 | return Color::DecodeD16(src_pixel); | 128 | return Color::DecodeD16(src_pixel); |
| 129 | case Regs::DepthFormat::D24: | 129 | case FramebufferRegs::DepthFormat::D24: |
| 130 | return Color::DecodeD24(src_pixel); | 130 | return Color::DecodeD24(src_pixel); |
| 131 | case Regs::DepthFormat::D24S8: | 131 | case FramebufferRegs::DepthFormat::D24S8: |
| 132 | return Color::DecodeD24S8(src_pixel).x; | 132 | return Color::DecodeD24S8(src_pixel).x; |
| 133 | default: | 133 | default: |
| 134 | LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); | 134 | LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); |
| @@ -138,21 +138,21 @@ static u32 GetDepth(int x, int y) { | |||
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | static u8 GetStencil(int x, int y) { | 140 | static u8 GetStencil(int x, int y) { |
| 141 | const auto& framebuffer = g_state.regs.framebuffer; | 141 | const auto& framebuffer = g_state.regs.framebuffer.framebuffer; |
| 142 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | 142 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); |
| 143 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); | 143 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); |
| 144 | 144 | ||
| 145 | y = framebuffer.height - y; | 145 | y = framebuffer.height - y; |
| 146 | 146 | ||
| 147 | const u32 coarse_y = y & ~7; | 147 | const u32 coarse_y = y & ~7; |
| 148 | u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | 148 | u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); |
| 149 | u32 stride = framebuffer.width * bytes_per_pixel; | 149 | u32 stride = framebuffer.width * bytes_per_pixel; |
| 150 | 150 | ||
| 151 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | 151 | u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; |
| 152 | u8* src_pixel = depth_buffer + src_offset; | 152 | u8* src_pixel = depth_buffer + src_offset; |
| 153 | 153 | ||
| 154 | switch (framebuffer.depth_format) { | 154 | switch (framebuffer.depth_format) { |
| 155 | case Regs::DepthFormat::D24S8: | 155 | case FramebufferRegs::DepthFormat::D24S8: |
| 156 | return Color::DecodeD24S8(src_pixel).y; | 156 | return Color::DecodeD24S8(src_pixel).y; |
| 157 | 157 | ||
| 158 | default: | 158 | default: |
| @@ -165,29 +165,29 @@ static u8 GetStencil(int x, int y) { | |||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static void SetDepth(int x, int y, u32 value) { | 167 | static void SetDepth(int x, int y, u32 value) { |
| 168 | const auto& framebuffer = g_state.regs.framebuffer; | 168 | const auto& framebuffer = g_state.regs.framebuffer.framebuffer; |
| 169 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | 169 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); |
| 170 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); | 170 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); |
| 171 | 171 | ||
| 172 | y = framebuffer.height - y; | 172 | y = framebuffer.height - y; |
| 173 | 173 | ||
| 174 | const u32 coarse_y = y & ~7; | 174 | const u32 coarse_y = y & ~7; |
| 175 | u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); | 175 | u32 bytes_per_pixel = FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); |
| 176 | u32 stride = framebuffer.width * bytes_per_pixel; | 176 | u32 stride = framebuffer.width * bytes_per_pixel; |
| 177 | 177 | ||
| 178 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | 178 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; |
| 179 | u8* dst_pixel = depth_buffer + dst_offset; | 179 | u8* dst_pixel = depth_buffer + dst_offset; |
| 180 | 180 | ||
| 181 | switch (framebuffer.depth_format) { | 181 | switch (framebuffer.depth_format) { |
| 182 | case Regs::DepthFormat::D16: | 182 | case FramebufferRegs::DepthFormat::D16: |
| 183 | Color::EncodeD16(value, dst_pixel); | 183 | Color::EncodeD16(value, dst_pixel); |
| 184 | break; | 184 | break; |
| 185 | 185 | ||
| 186 | case Regs::DepthFormat::D24: | 186 | case FramebufferRegs::DepthFormat::D24: |
| 187 | Color::EncodeD24(value, dst_pixel); | 187 | Color::EncodeD24(value, dst_pixel); |
| 188 | break; | 188 | break; |
| 189 | 189 | ||
| 190 | case Regs::DepthFormat::D24S8: | 190 | case FramebufferRegs::DepthFormat::D24S8: |
| 191 | Color::EncodeD24X8(value, dst_pixel); | 191 | Color::EncodeD24X8(value, dst_pixel); |
| 192 | break; | 192 | break; |
| 193 | 193 | ||
| @@ -199,26 +199,26 @@ static void SetDepth(int x, int y, u32 value) { | |||
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | static void SetStencil(int x, int y, u8 value) { | 201 | static void SetStencil(int x, int y, u8 value) { |
| 202 | const auto& framebuffer = g_state.regs.framebuffer; | 202 | const auto& framebuffer = g_state.regs.framebuffer.framebuffer; |
| 203 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); | 203 | const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); |
| 204 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); | 204 | u8* depth_buffer = Memory::GetPhysicalPointer(addr); |
| 205 | 205 | ||
| 206 | y = framebuffer.height - y; | 206 | y = framebuffer.height - y; |
| 207 | 207 | ||
| 208 | const u32 coarse_y = y & ~7; | 208 | const u32 coarse_y = y & ~7; |
| 209 | u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format); | 209 | u32 bytes_per_pixel = Pica::FramebufferRegs::BytesPerDepthPixel(framebuffer.depth_format); |
| 210 | u32 stride = framebuffer.width * bytes_per_pixel; | 210 | u32 stride = framebuffer.width * bytes_per_pixel; |
| 211 | 211 | ||
| 212 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; | 212 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride; |
| 213 | u8* dst_pixel = depth_buffer + dst_offset; | 213 | u8* dst_pixel = depth_buffer + dst_offset; |
| 214 | 214 | ||
| 215 | switch (framebuffer.depth_format) { | 215 | switch (framebuffer.depth_format) { |
| 216 | case Pica::Regs::DepthFormat::D16: | 216 | case Pica::FramebufferRegs::DepthFormat::D16: |
| 217 | case Pica::Regs::DepthFormat::D24: | 217 | case Pica::FramebufferRegs::DepthFormat::D24: |
| 218 | // Nothing to do | 218 | // Nothing to do |
| 219 | break; | 219 | break; |
| 220 | 220 | ||
| 221 | case Pica::Regs::DepthFormat::D24S8: | 221 | case Pica::FramebufferRegs::DepthFormat::D24S8: |
| 222 | Color::EncodeX24S8(value, dst_pixel); | 222 | Color::EncodeX24S8(value, dst_pixel); |
| 223 | break; | 223 | break; |
| 224 | 224 | ||
| @@ -229,32 +229,32 @@ static void SetStencil(int x, int y, u8 value) { | |||
| 229 | } | 229 | } |
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | static u8 PerformStencilAction(Regs::StencilAction action, u8 old_stencil, u8 ref) { | 232 | static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) { |
| 233 | switch (action) { | 233 | switch (action) { |
| 234 | case Regs::StencilAction::Keep: | 234 | case FramebufferRegs::StencilAction::Keep: |
| 235 | return old_stencil; | 235 | return old_stencil; |
| 236 | 236 | ||
| 237 | case Regs::StencilAction::Zero: | 237 | case FramebufferRegs::StencilAction::Zero: |
| 238 | return 0; | 238 | return 0; |
| 239 | 239 | ||
| 240 | case Regs::StencilAction::Replace: | 240 | case FramebufferRegs::StencilAction::Replace: |
| 241 | return ref; | 241 | return ref; |
| 242 | 242 | ||
| 243 | case Regs::StencilAction::Increment: | 243 | case FramebufferRegs::StencilAction::Increment: |
| 244 | // Saturated increment | 244 | // Saturated increment |
| 245 | return std::min<u8>(old_stencil, 254) + 1; | 245 | return std::min<u8>(old_stencil, 254) + 1; |
| 246 | 246 | ||
| 247 | case Regs::StencilAction::Decrement: | 247 | case FramebufferRegs::StencilAction::Decrement: |
| 248 | // Saturated decrement | 248 | // Saturated decrement |
| 249 | return std::max<u8>(old_stencil, 1) - 1; | 249 | return std::max<u8>(old_stencil, 1) - 1; |
| 250 | 250 | ||
| 251 | case Regs::StencilAction::Invert: | 251 | case FramebufferRegs::StencilAction::Invert: |
| 252 | return ~old_stencil; | 252 | return ~old_stencil; |
| 253 | 253 | ||
| 254 | case Regs::StencilAction::IncrementWrap: | 254 | case FramebufferRegs::StencilAction::IncrementWrap: |
| 255 | return old_stencil + 1; | 255 | return old_stencil + 1; |
| 256 | 256 | ||
| 257 | case Regs::StencilAction::DecrementWrap: | 257 | case FramebufferRegs::StencilAction::DecrementWrap: |
| 258 | return old_stencil - 1; | 258 | return old_stencil - 1; |
| 259 | 259 | ||
| 260 | default: | 260 | default: |
| @@ -400,9 +400,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 400 | auto textures = regs.texturing.GetTextures(); | 400 | auto textures = regs.texturing.GetTextures(); |
| 401 | auto tev_stages = regs.texturing.GetTevStages(); | 401 | auto tev_stages = regs.texturing.GetTevStages(); |
| 402 | 402 | ||
| 403 | bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && | 403 | bool stencil_action_enable = |
| 404 | g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8; | 404 | g_state.regs.framebuffer.output_merger.stencil_test.enable && |
| 405 | const auto stencil_test = g_state.regs.output_merger.stencil_test; | 405 | g_state.regs.framebuffer.framebuffer.depth_format == FramebufferRegs::DepthFormat::D24S8; |
| 406 | const auto stencil_test = g_state.regs.framebuffer.output_merger.stencil_test; | ||
| 406 | 407 | ||
| 407 | // Enter rasterization loop, starting at the center of the topleft bounding box corner. | 408 | // Enter rasterization loop, starting at the center of the topleft bounding box corner. |
| 408 | // TODO: Not sure if looping through x first might be faster | 409 | // 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 | |||
| 879 | } | 880 | } |
| 880 | } | 881 | } |
| 881 | 882 | ||
| 882 | const auto& output_merger = regs.output_merger; | 883 | const auto& output_merger = regs.framebuffer.output_merger; |
| 883 | // TODO: Does alpha testing happen before or after stencil? | 884 | // TODO: Does alpha testing happen before or after stencil? |
| 884 | if (output_merger.alpha_test.enable) { | 885 | if (output_merger.alpha_test.enable) { |
| 885 | bool pass = false; | 886 | bool pass = false; |
| 886 | 887 | ||
| 887 | switch (output_merger.alpha_test.func) { | 888 | switch (output_merger.alpha_test.func) { |
| 888 | case Regs::CompareFunc::Never: | 889 | case FramebufferRegs::CompareFunc::Never: |
| 889 | pass = false; | 890 | pass = false; |
| 890 | break; | 891 | break; |
| 891 | 892 | ||
| 892 | case Regs::CompareFunc::Always: | 893 | case FramebufferRegs::CompareFunc::Always: |
| 893 | pass = true; | 894 | pass = true; |
| 894 | break; | 895 | break; |
| 895 | 896 | ||
| 896 | case Regs::CompareFunc::Equal: | 897 | case FramebufferRegs::CompareFunc::Equal: |
| 897 | pass = combiner_output.a() == output_merger.alpha_test.ref; | 898 | pass = combiner_output.a() == output_merger.alpha_test.ref; |
| 898 | break; | 899 | break; |
| 899 | 900 | ||
| 900 | case Regs::CompareFunc::NotEqual: | 901 | case FramebufferRegs::CompareFunc::NotEqual: |
| 901 | pass = combiner_output.a() != output_merger.alpha_test.ref; | 902 | pass = combiner_output.a() != output_merger.alpha_test.ref; |
| 902 | break; | 903 | break; |
| 903 | 904 | ||
| 904 | case Regs::CompareFunc::LessThan: | 905 | case FramebufferRegs::CompareFunc::LessThan: |
| 905 | pass = combiner_output.a() < output_merger.alpha_test.ref; | 906 | pass = combiner_output.a() < output_merger.alpha_test.ref; |
| 906 | break; | 907 | break; |
| 907 | 908 | ||
| 908 | case Regs::CompareFunc::LessThanOrEqual: | 909 | case FramebufferRegs::CompareFunc::LessThanOrEqual: |
| 909 | pass = combiner_output.a() <= output_merger.alpha_test.ref; | 910 | pass = combiner_output.a() <= output_merger.alpha_test.ref; |
| 910 | break; | 911 | break; |
| 911 | 912 | ||
| 912 | case Regs::CompareFunc::GreaterThan: | 913 | case FramebufferRegs::CompareFunc::GreaterThan: |
| 913 | pass = combiner_output.a() > output_merger.alpha_test.ref; | 914 | pass = combiner_output.a() > output_merger.alpha_test.ref; |
| 914 | break; | 915 | break; |
| 915 | 916 | ||
| 916 | case Regs::CompareFunc::GreaterThanOrEqual: | 917 | case FramebufferRegs::CompareFunc::GreaterThanOrEqual: |
| 917 | pass = combiner_output.a() >= output_merger.alpha_test.ref; | 918 | pass = combiner_output.a() >= output_merger.alpha_test.ref; |
| 918 | break; | 919 | break; |
| 919 | } | 920 | } |
| @@ -959,10 +960,10 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 959 | u8 old_stencil = 0; | 960 | u8 old_stencil = 0; |
| 960 | 961 | ||
| 961 | auto UpdateStencil = [stencil_test, x, y, | 962 | auto UpdateStencil = [stencil_test, x, y, |
| 962 | &old_stencil](Pica::Regs::StencilAction action) { | 963 | &old_stencil](Pica::FramebufferRegs::StencilAction action) { |
| 963 | u8 new_stencil = | 964 | u8 new_stencil = |
| 964 | PerformStencilAction(action, old_stencil, stencil_test.reference_value); | 965 | PerformStencilAction(action, old_stencil, stencil_test.reference_value); |
| 965 | if (g_state.regs.framebuffer.allow_depth_stencil_write != 0) | 966 | if (g_state.regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) |
| 966 | SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | | 967 | SetStencil(x >> 4, y >> 4, (new_stencil & stencil_test.write_mask) | |
| 967 | (old_stencil & ~stencil_test.write_mask)); | 968 | (old_stencil & ~stencil_test.write_mask)); |
| 968 | }; | 969 | }; |
| @@ -974,35 +975,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 974 | 975 | ||
| 975 | bool pass = false; | 976 | bool pass = false; |
| 976 | switch (stencil_test.func) { | 977 | switch (stencil_test.func) { |
| 977 | case Regs::CompareFunc::Never: | 978 | case FramebufferRegs::CompareFunc::Never: |
| 978 | pass = false; | 979 | pass = false; |
| 979 | break; | 980 | break; |
| 980 | 981 | ||
| 981 | case Regs::CompareFunc::Always: | 982 | case FramebufferRegs::CompareFunc::Always: |
| 982 | pass = true; | 983 | pass = true; |
| 983 | break; | 984 | break; |
| 984 | 985 | ||
| 985 | case Regs::CompareFunc::Equal: | 986 | case FramebufferRegs::CompareFunc::Equal: |
| 986 | pass = (ref == dest); | 987 | pass = (ref == dest); |
| 987 | break; | 988 | break; |
| 988 | 989 | ||
| 989 | case Regs::CompareFunc::NotEqual: | 990 | case FramebufferRegs::CompareFunc::NotEqual: |
| 990 | pass = (ref != dest); | 991 | pass = (ref != dest); |
| 991 | break; | 992 | break; |
| 992 | 993 | ||
| 993 | case Regs::CompareFunc::LessThan: | 994 | case FramebufferRegs::CompareFunc::LessThan: |
| 994 | pass = (ref < dest); | 995 | pass = (ref < dest); |
| 995 | break; | 996 | break; |
| 996 | 997 | ||
| 997 | case Regs::CompareFunc::LessThanOrEqual: | 998 | case FramebufferRegs::CompareFunc::LessThanOrEqual: |
| 998 | pass = (ref <= dest); | 999 | pass = (ref <= dest); |
| 999 | break; | 1000 | break; |
| 1000 | 1001 | ||
| 1001 | case Regs::CompareFunc::GreaterThan: | 1002 | case FramebufferRegs::CompareFunc::GreaterThan: |
| 1002 | pass = (ref > dest); | 1003 | pass = (ref > dest); |
| 1003 | break; | 1004 | break; |
| 1004 | 1005 | ||
| 1005 | case Regs::CompareFunc::GreaterThanOrEqual: | 1006 | case FramebufferRegs::CompareFunc::GreaterThanOrEqual: |
| 1006 | pass = (ref >= dest); | 1007 | pass = (ref >= dest); |
| 1007 | break; | 1008 | break; |
| 1008 | } | 1009 | } |
| @@ -1014,7 +1015,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1014 | } | 1015 | } |
| 1015 | 1016 | ||
| 1016 | // Convert float to integer | 1017 | // Convert float to integer |
| 1017 | unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); | 1018 | unsigned num_bits = |
| 1019 | FramebufferRegs::DepthBitsPerPixel(regs.framebuffer.framebuffer.depth_format); | ||
| 1018 | u32 z = (u32)(depth * ((1 << num_bits) - 1)); | 1020 | u32 z = (u32)(depth * ((1 << num_bits) - 1)); |
| 1019 | 1021 | ||
| 1020 | if (output_merger.depth_test_enable) { | 1022 | if (output_merger.depth_test_enable) { |
| @@ -1023,35 +1025,35 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1023 | bool pass = false; | 1025 | bool pass = false; |
| 1024 | 1026 | ||
| 1025 | switch (output_merger.depth_test_func) { | 1027 | switch (output_merger.depth_test_func) { |
| 1026 | case Regs::CompareFunc::Never: | 1028 | case FramebufferRegs::CompareFunc::Never: |
| 1027 | pass = false; | 1029 | pass = false; |
| 1028 | break; | 1030 | break; |
| 1029 | 1031 | ||
| 1030 | case Regs::CompareFunc::Always: | 1032 | case FramebufferRegs::CompareFunc::Always: |
| 1031 | pass = true; | 1033 | pass = true; |
| 1032 | break; | 1034 | break; |
| 1033 | 1035 | ||
| 1034 | case Regs::CompareFunc::Equal: | 1036 | case FramebufferRegs::CompareFunc::Equal: |
| 1035 | pass = z == ref_z; | 1037 | pass = z == ref_z; |
| 1036 | break; | 1038 | break; |
| 1037 | 1039 | ||
| 1038 | case Regs::CompareFunc::NotEqual: | 1040 | case FramebufferRegs::CompareFunc::NotEqual: |
| 1039 | pass = z != ref_z; | 1041 | pass = z != ref_z; |
| 1040 | break; | 1042 | break; |
| 1041 | 1043 | ||
| 1042 | case Regs::CompareFunc::LessThan: | 1044 | case FramebufferRegs::CompareFunc::LessThan: |
| 1043 | pass = z < ref_z; | 1045 | pass = z < ref_z; |
| 1044 | break; | 1046 | break; |
| 1045 | 1047 | ||
| 1046 | case Regs::CompareFunc::LessThanOrEqual: | 1048 | case FramebufferRegs::CompareFunc::LessThanOrEqual: |
| 1047 | pass = z <= ref_z; | 1049 | pass = z <= ref_z; |
| 1048 | break; | 1050 | break; |
| 1049 | 1051 | ||
| 1050 | case Regs::CompareFunc::GreaterThan: | 1052 | case FramebufferRegs::CompareFunc::GreaterThan: |
| 1051 | pass = z > ref_z; | 1053 | pass = z > ref_z; |
| 1052 | break; | 1054 | break; |
| 1053 | 1055 | ||
| 1054 | case Regs::CompareFunc::GreaterThanOrEqual: | 1056 | case FramebufferRegs::CompareFunc::GreaterThanOrEqual: |
| 1055 | pass = z >= ref_z; | 1057 | pass = z >= ref_z; |
| 1056 | break; | 1058 | break; |
| 1057 | } | 1059 | } |
| @@ -1063,8 +1065,11 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1063 | } | 1065 | } |
| 1064 | } | 1066 | } |
| 1065 | 1067 | ||
| 1066 | if (regs.framebuffer.allow_depth_stencil_write != 0 && output_merger.depth_write_enable) | 1068 | if (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && |
| 1069 | output_merger.depth_write_enable) { | ||
| 1070 | |||
| 1067 | SetDepth(x >> 4, y >> 4, z); | 1071 | SetDepth(x >> 4, y >> 4, z); |
| 1072 | } | ||
| 1068 | 1073 | ||
| 1069 | // The stencil depth_pass action is executed even if depth testing is disabled | 1074 | // The stencil depth_pass action is executed even if depth testing is disabled |
| 1070 | if (stencil_action_enable) | 1075 | if (stencil_action_enable) |
| @@ -1076,7 +1081,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1076 | if (output_merger.alphablend_enable) { | 1081 | if (output_merger.alphablend_enable) { |
| 1077 | auto params = output_merger.alpha_blending; | 1082 | auto params = output_merger.alpha_blending; |
| 1078 | 1083 | ||
| 1079 | auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 { | 1084 | auto LookupFactor = [&](unsigned channel, |
| 1085 | FramebufferRegs::BlendFactor factor) -> u8 { | ||
| 1080 | DEBUG_ASSERT(channel < 4); | 1086 | DEBUG_ASSERT(channel < 4); |
| 1081 | 1087 | ||
| 1082 | const Math::Vec4<u8> blend_const = { | 1088 | const Math::Vec4<u8> blend_const = { |
| @@ -1087,49 +1093,49 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1087 | }; | 1093 | }; |
| 1088 | 1094 | ||
| 1089 | switch (factor) { | 1095 | switch (factor) { |
| 1090 | case Regs::BlendFactor::Zero: | 1096 | case FramebufferRegs::BlendFactor::Zero: |
| 1091 | return 0; | 1097 | return 0; |
| 1092 | 1098 | ||
| 1093 | case Regs::BlendFactor::One: | 1099 | case FramebufferRegs::BlendFactor::One: |
| 1094 | return 255; | 1100 | return 255; |
| 1095 | 1101 | ||
| 1096 | case Regs::BlendFactor::SourceColor: | 1102 | case FramebufferRegs::BlendFactor::SourceColor: |
| 1097 | return combiner_output[channel]; | 1103 | return combiner_output[channel]; |
| 1098 | 1104 | ||
| 1099 | case Regs::BlendFactor::OneMinusSourceColor: | 1105 | case FramebufferRegs::BlendFactor::OneMinusSourceColor: |
| 1100 | return 255 - combiner_output[channel]; | 1106 | return 255 - combiner_output[channel]; |
| 1101 | 1107 | ||
| 1102 | case Regs::BlendFactor::DestColor: | 1108 | case FramebufferRegs::BlendFactor::DestColor: |
| 1103 | return dest[channel]; | 1109 | return dest[channel]; |
| 1104 | 1110 | ||
| 1105 | case Regs::BlendFactor::OneMinusDestColor: | 1111 | case FramebufferRegs::BlendFactor::OneMinusDestColor: |
| 1106 | return 255 - dest[channel]; | 1112 | return 255 - dest[channel]; |
| 1107 | 1113 | ||
| 1108 | case Regs::BlendFactor::SourceAlpha: | 1114 | case FramebufferRegs::BlendFactor::SourceAlpha: |
| 1109 | return combiner_output.a(); | 1115 | return combiner_output.a(); |
| 1110 | 1116 | ||
| 1111 | case Regs::BlendFactor::OneMinusSourceAlpha: | 1117 | case FramebufferRegs::BlendFactor::OneMinusSourceAlpha: |
| 1112 | return 255 - combiner_output.a(); | 1118 | return 255 - combiner_output.a(); |
| 1113 | 1119 | ||
| 1114 | case Regs::BlendFactor::DestAlpha: | 1120 | case FramebufferRegs::BlendFactor::DestAlpha: |
| 1115 | return dest.a(); | 1121 | return dest.a(); |
| 1116 | 1122 | ||
| 1117 | case Regs::BlendFactor::OneMinusDestAlpha: | 1123 | case FramebufferRegs::BlendFactor::OneMinusDestAlpha: |
| 1118 | return 255 - dest.a(); | 1124 | return 255 - dest.a(); |
| 1119 | 1125 | ||
| 1120 | case Regs::BlendFactor::ConstantColor: | 1126 | case FramebufferRegs::BlendFactor::ConstantColor: |
| 1121 | return blend_const[channel]; | 1127 | return blend_const[channel]; |
| 1122 | 1128 | ||
| 1123 | case Regs::BlendFactor::OneMinusConstantColor: | 1129 | case FramebufferRegs::BlendFactor::OneMinusConstantColor: |
| 1124 | return 255 - blend_const[channel]; | 1130 | return 255 - blend_const[channel]; |
| 1125 | 1131 | ||
| 1126 | case Regs::BlendFactor::ConstantAlpha: | 1132 | case FramebufferRegs::BlendFactor::ConstantAlpha: |
| 1127 | return blend_const.a(); | 1133 | return blend_const.a(); |
| 1128 | 1134 | ||
| 1129 | case Regs::BlendFactor::OneMinusConstantAlpha: | 1135 | case FramebufferRegs::BlendFactor::OneMinusConstantAlpha: |
| 1130 | return 255 - blend_const.a(); | 1136 | return 255 - blend_const.a(); |
| 1131 | 1137 | ||
| 1132 | case Regs::BlendFactor::SourceAlphaSaturate: | 1138 | case FramebufferRegs::BlendFactor::SourceAlphaSaturate: |
| 1133 | // Returns 1.0 for the alpha channel | 1139 | // Returns 1.0 for the alpha channel |
| 1134 | if (channel == 3) | 1140 | if (channel == 3) |
| 1135 | return 255; | 1141 | return 255; |
| @@ -1147,36 +1153,37 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1147 | static auto EvaluateBlendEquation = []( | 1153 | static auto EvaluateBlendEquation = []( |
| 1148 | const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, | 1154 | const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, |
| 1149 | const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, | 1155 | const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, |
| 1150 | Regs::BlendEquation equation) { | 1156 | FramebufferRegs::BlendEquation equation) { |
| 1157 | |||
| 1151 | Math::Vec4<int> result; | 1158 | Math::Vec4<int> result; |
| 1152 | 1159 | ||
| 1153 | auto src_result = (src * srcfactor).Cast<int>(); | 1160 | auto src_result = (src * srcfactor).Cast<int>(); |
| 1154 | auto dst_result = (dest * destfactor).Cast<int>(); | 1161 | auto dst_result = (dest * destfactor).Cast<int>(); |
| 1155 | 1162 | ||
| 1156 | switch (equation) { | 1163 | switch (equation) { |
| 1157 | case Regs::BlendEquation::Add: | 1164 | case FramebufferRegs::BlendEquation::Add: |
| 1158 | result = (src_result + dst_result) / 255; | 1165 | result = (src_result + dst_result) / 255; |
| 1159 | break; | 1166 | break; |
| 1160 | 1167 | ||
| 1161 | case Regs::BlendEquation::Subtract: | 1168 | case FramebufferRegs::BlendEquation::Subtract: |
| 1162 | result = (src_result - dst_result) / 255; | 1169 | result = (src_result - dst_result) / 255; |
| 1163 | break; | 1170 | break; |
| 1164 | 1171 | ||
| 1165 | case Regs::BlendEquation::ReverseSubtract: | 1172 | case FramebufferRegs::BlendEquation::ReverseSubtract: |
| 1166 | result = (dst_result - src_result) / 255; | 1173 | result = (dst_result - src_result) / 255; |
| 1167 | break; | 1174 | break; |
| 1168 | 1175 | ||
| 1169 | // TODO: How do these two actually work? | 1176 | // TODO: How do these two actually work? |
| 1170 | // OpenGL doesn't include the blend factors in the min/max computations, | 1177 | // OpenGL doesn't include the blend factors in the min/max computations, |
| 1171 | // but is this what the 3DS actually does? | 1178 | // but is this what the 3DS actually does? |
| 1172 | case Regs::BlendEquation::Min: | 1179 | case FramebufferRegs::BlendEquation::Min: |
| 1173 | result.r() = std::min(src.r(), dest.r()); | 1180 | result.r() = std::min(src.r(), dest.r()); |
| 1174 | result.g() = std::min(src.g(), dest.g()); | 1181 | result.g() = std::min(src.g(), dest.g()); |
| 1175 | result.b() = std::min(src.b(), dest.b()); | 1182 | result.b() = std::min(src.b(), dest.b()); |
| 1176 | result.a() = std::min(src.a(), dest.a()); | 1183 | result.a() = std::min(src.a(), dest.a()); |
| 1177 | break; | 1184 | break; |
| 1178 | 1185 | ||
| 1179 | case Regs::BlendEquation::Max: | 1186 | case FramebufferRegs::BlendEquation::Max: |
| 1180 | result.r() = std::max(src.r(), dest.r()); | 1187 | result.r() = std::max(src.r(), dest.r()); |
| 1181 | result.g() = std::max(src.g(), dest.g()); | 1188 | result.g() = std::max(src.g(), dest.g()); |
| 1182 | result.b() = std::max(src.b(), dest.b()); | 1189 | result.b() = std::max(src.b(), dest.b()); |
| @@ -1209,54 +1216,54 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1209 | dstfactor, params.blend_equation_a) | 1216 | dstfactor, params.blend_equation_a) |
| 1210 | .a(); | 1217 | .a(); |
| 1211 | } else { | 1218 | } else { |
| 1212 | static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { | 1219 | static auto LogicOp = [](u8 src, u8 dest, FramebufferRegs::LogicOp op) -> u8 { |
| 1213 | switch (op) { | 1220 | switch (op) { |
| 1214 | case Regs::LogicOp::Clear: | 1221 | case FramebufferRegs::LogicOp::Clear: |
| 1215 | return 0; | 1222 | return 0; |
| 1216 | 1223 | ||
| 1217 | case Regs::LogicOp::And: | 1224 | case FramebufferRegs::LogicOp::And: |
| 1218 | return src & dest; | 1225 | return src & dest; |
| 1219 | 1226 | ||
| 1220 | case Regs::LogicOp::AndReverse: | 1227 | case FramebufferRegs::LogicOp::AndReverse: |
| 1221 | return src & ~dest; | 1228 | return src & ~dest; |
| 1222 | 1229 | ||
| 1223 | case Regs::LogicOp::Copy: | 1230 | case FramebufferRegs::LogicOp::Copy: |
| 1224 | return src; | 1231 | return src; |
| 1225 | 1232 | ||
| 1226 | case Regs::LogicOp::Set: | 1233 | case FramebufferRegs::LogicOp::Set: |
| 1227 | return 255; | 1234 | return 255; |
| 1228 | 1235 | ||
| 1229 | case Regs::LogicOp::CopyInverted: | 1236 | case FramebufferRegs::LogicOp::CopyInverted: |
| 1230 | return ~src; | 1237 | return ~src; |
| 1231 | 1238 | ||
| 1232 | case Regs::LogicOp::NoOp: | 1239 | case FramebufferRegs::LogicOp::NoOp: |
| 1233 | return dest; | 1240 | return dest; |
| 1234 | 1241 | ||
| 1235 | case Regs::LogicOp::Invert: | 1242 | case FramebufferRegs::LogicOp::Invert: |
| 1236 | return ~dest; | 1243 | return ~dest; |
| 1237 | 1244 | ||
| 1238 | case Regs::LogicOp::Nand: | 1245 | case FramebufferRegs::LogicOp::Nand: |
| 1239 | return ~(src & dest); | 1246 | return ~(src & dest); |
| 1240 | 1247 | ||
| 1241 | case Regs::LogicOp::Or: | 1248 | case FramebufferRegs::LogicOp::Or: |
| 1242 | return src | dest; | 1249 | return src | dest; |
| 1243 | 1250 | ||
| 1244 | case Regs::LogicOp::Nor: | 1251 | case FramebufferRegs::LogicOp::Nor: |
| 1245 | return ~(src | dest); | 1252 | return ~(src | dest); |
| 1246 | 1253 | ||
| 1247 | case Regs::LogicOp::Xor: | 1254 | case FramebufferRegs::LogicOp::Xor: |
| 1248 | return src ^ dest; | 1255 | return src ^ dest; |
| 1249 | 1256 | ||
| 1250 | case Regs::LogicOp::Equiv: | 1257 | case FramebufferRegs::LogicOp::Equiv: |
| 1251 | return ~(src ^ dest); | 1258 | return ~(src ^ dest); |
| 1252 | 1259 | ||
| 1253 | case Regs::LogicOp::AndInverted: | 1260 | case FramebufferRegs::LogicOp::AndInverted: |
| 1254 | return ~src & dest; | 1261 | return ~src & dest; |
| 1255 | 1262 | ||
| 1256 | case Regs::LogicOp::OrReverse: | 1263 | case FramebufferRegs::LogicOp::OrReverse: |
| 1257 | return src | ~dest; | 1264 | return src | ~dest; |
| 1258 | 1265 | ||
| 1259 | case Regs::LogicOp::OrInverted: | 1266 | case FramebufferRegs::LogicOp::OrInverted: |
| 1260 | return ~src | dest; | 1267 | return ~src | dest; |
| 1261 | } | 1268 | } |
| 1262 | }; | 1269 | }; |
| @@ -1275,7 +1282,7 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve | |||
| 1275 | output_merger.alpha_enable ? blend_output.a() : dest.a(), | 1282 | output_merger.alpha_enable ? blend_output.a() : dest.a(), |
| 1276 | }; | 1283 | }; |
| 1277 | 1284 | ||
| 1278 | if (regs.framebuffer.allow_color_write != 0) | 1285 | if (regs.framebuffer.framebuffer.allow_color_write != 0) |
| 1279 | DrawPixel(x >> 4, y >> 4, result); | 1286 | DrawPixel(x >> 4, y >> 4, result); |
| 1280 | } | 1287 | } |
| 1281 | } | 1288 | } |
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 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/bit_field.h" | ||
| 10 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | namespace Pica { | ||
| 14 | |||
| 15 | struct FramebufferRegs { | ||
| 16 | enum class LogicOp : u32 { | ||
| 17 | Clear = 0, | ||
| 18 | And = 1, | ||
| 19 | AndReverse = 2, | ||
| 20 | Copy = 3, | ||
| 21 | Set = 4, | ||
| 22 | CopyInverted = 5, | ||
| 23 | NoOp = 6, | ||
| 24 | Invert = 7, | ||
| 25 | Nand = 8, | ||
| 26 | Or = 9, | ||
| 27 | Nor = 10, | ||
| 28 | Xor = 11, | ||
| 29 | Equiv = 12, | ||
| 30 | AndInverted = 13, | ||
| 31 | OrReverse = 14, | ||
| 32 | OrInverted = 15, | ||
| 33 | }; | ||
| 34 | |||
| 35 | enum class BlendEquation : u32 { | ||
| 36 | Add = 0, | ||
| 37 | Subtract = 1, | ||
| 38 | ReverseSubtract = 2, | ||
| 39 | Min = 3, | ||
| 40 | Max = 4, | ||
| 41 | }; | ||
| 42 | |||
| 43 | enum class BlendFactor : u32 { | ||
| 44 | Zero = 0, | ||
| 45 | One = 1, | ||
| 46 | SourceColor = 2, | ||
| 47 | OneMinusSourceColor = 3, | ||
| 48 | DestColor = 4, | ||
| 49 | OneMinusDestColor = 5, | ||
| 50 | SourceAlpha = 6, | ||
| 51 | OneMinusSourceAlpha = 7, | ||
| 52 | DestAlpha = 8, | ||
| 53 | OneMinusDestAlpha = 9, | ||
| 54 | ConstantColor = 10, | ||
| 55 | OneMinusConstantColor = 11, | ||
| 56 | ConstantAlpha = 12, | ||
| 57 | OneMinusConstantAlpha = 13, | ||
| 58 | SourceAlphaSaturate = 14, | ||
| 59 | }; | ||
| 60 | |||
| 61 | enum class CompareFunc : u32 { | ||
| 62 | Never = 0, | ||
| 63 | Always = 1, | ||
| 64 | Equal = 2, | ||
| 65 | NotEqual = 3, | ||
| 66 | LessThan = 4, | ||
| 67 | LessThanOrEqual = 5, | ||
| 68 | GreaterThan = 6, | ||
| 69 | GreaterThanOrEqual = 7, | ||
| 70 | }; | ||
| 71 | |||
| 72 | enum class StencilAction : u32 { | ||
| 73 | Keep = 0, | ||
| 74 | Zero = 1, | ||
| 75 | Replace = 2, | ||
| 76 | Increment = 3, | ||
| 77 | Decrement = 4, | ||
| 78 | Invert = 5, | ||
| 79 | IncrementWrap = 6, | ||
| 80 | DecrementWrap = 7, | ||
| 81 | }; | ||
| 82 | |||
| 83 | struct { | ||
| 84 | union { | ||
| 85 | // If false, logic blending is used | ||
| 86 | BitField<8, 1, u32> alphablend_enable; | ||
| 87 | }; | ||
| 88 | |||
| 89 | union { | ||
| 90 | BitField<0, 8, BlendEquation> blend_equation_rgb; | ||
| 91 | BitField<8, 8, BlendEquation> blend_equation_a; | ||
| 92 | |||
| 93 | BitField<16, 4, BlendFactor> factor_source_rgb; | ||
| 94 | BitField<20, 4, BlendFactor> factor_dest_rgb; | ||
| 95 | |||
| 96 | BitField<24, 4, BlendFactor> factor_source_a; | ||
| 97 | BitField<28, 4, BlendFactor> factor_dest_a; | ||
| 98 | } alpha_blending; | ||
| 99 | |||
| 100 | union { | ||
| 101 | BitField<0, 4, LogicOp> logic_op; | ||
| 102 | }; | ||
| 103 | |||
| 104 | union { | ||
| 105 | u32 raw; | ||
| 106 | BitField<0, 8, u32> r; | ||
| 107 | BitField<8, 8, u32> g; | ||
| 108 | BitField<16, 8, u32> b; | ||
| 109 | BitField<24, 8, u32> a; | ||
| 110 | } blend_const; | ||
| 111 | |||
| 112 | union { | ||
| 113 | BitField<0, 1, u32> enable; | ||
| 114 | BitField<4, 3, CompareFunc> func; | ||
| 115 | BitField<8, 8, u32> ref; | ||
| 116 | } alpha_test; | ||
| 117 | |||
| 118 | struct { | ||
| 119 | union { | ||
| 120 | // Raw value of this register | ||
| 121 | u32 raw_func; | ||
| 122 | |||
| 123 | // If true, enable stencil testing | ||
| 124 | BitField<0, 1, u32> enable; | ||
| 125 | |||
| 126 | // Comparison operation for stencil testing | ||
| 127 | BitField<4, 3, CompareFunc> func; | ||
| 128 | |||
| 129 | // Mask used to control writing to the stencil buffer | ||
| 130 | BitField<8, 8, u32> write_mask; | ||
| 131 | |||
| 132 | // Value to compare against for stencil testing | ||
| 133 | BitField<16, 8, u32> reference_value; | ||
| 134 | |||
| 135 | // Mask to apply on stencil test inputs | ||
| 136 | BitField<24, 8, u32> input_mask; | ||
| 137 | }; | ||
| 138 | |||
| 139 | union { | ||
| 140 | // Raw value of this register | ||
| 141 | u32 raw_op; | ||
| 142 | |||
| 143 | // Action to perform when the stencil test fails | ||
| 144 | BitField<0, 3, StencilAction> action_stencil_fail; | ||
| 145 | |||
| 146 | // Action to perform when stencil testing passed but depth testing fails | ||
| 147 | BitField<4, 3, StencilAction> action_depth_fail; | ||
| 148 | |||
| 149 | // Action to perform when both stencil and depth testing pass | ||
| 150 | BitField<8, 3, StencilAction> action_depth_pass; | ||
| 151 | }; | ||
| 152 | } stencil_test; | ||
| 153 | |||
| 154 | union { | ||
| 155 | BitField<0, 1, u32> depth_test_enable; | ||
| 156 | BitField<4, 3, CompareFunc> depth_test_func; | ||
| 157 | BitField<8, 1, u32> red_enable; | ||
| 158 | BitField<9, 1, u32> green_enable; | ||
| 159 | BitField<10, 1, u32> blue_enable; | ||
| 160 | BitField<11, 1, u32> alpha_enable; | ||
| 161 | BitField<12, 1, u32> depth_write_enable; | ||
| 162 | }; | ||
| 163 | |||
| 164 | INSERT_PADDING_WORDS(0x8); | ||
| 165 | } output_merger; | ||
| 166 | |||
| 167 | // Components are laid out in reverse byte order, most significant bits first. | ||
| 168 | enum class ColorFormat : u32 { | ||
| 169 | RGBA8 = 0, | ||
| 170 | RGB8 = 1, | ||
| 171 | RGB5A1 = 2, | ||
| 172 | RGB565 = 3, | ||
| 173 | RGBA4 = 4, | ||
| 174 | }; | ||
| 175 | |||
| 176 | enum class DepthFormat : u32 { | ||
| 177 | D16 = 0, | ||
| 178 | D24 = 2, | ||
| 179 | D24S8 = 3, | ||
| 180 | }; | ||
| 181 | |||
| 182 | // Returns the number of bytes in the specified color format | ||
| 183 | static unsigned BytesPerColorPixel(ColorFormat format) { | ||
| 184 | switch (format) { | ||
| 185 | case ColorFormat::RGBA8: | ||
| 186 | return 4; | ||
| 187 | case ColorFormat::RGB8: | ||
| 188 | return 3; | ||
| 189 | case ColorFormat::RGB5A1: | ||
| 190 | case ColorFormat::RGB565: | ||
| 191 | case ColorFormat::RGBA4: | ||
| 192 | return 2; | ||
| 193 | default: | ||
| 194 | LOG_CRITICAL(HW_GPU, "Unknown color format %u", format); | ||
| 195 | UNIMPLEMENTED(); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | struct FramebufferConfig { | ||
| 200 | INSERT_PADDING_WORDS(0x3); | ||
| 201 | |||
| 202 | union { | ||
| 203 | BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable | ||
| 204 | }; | ||
| 205 | |||
| 206 | INSERT_PADDING_WORDS(0x1); | ||
| 207 | |||
| 208 | union { | ||
| 209 | BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable | ||
| 210 | }; | ||
| 211 | |||
| 212 | DepthFormat depth_format; // TODO: Should be a BitField! | ||
| 213 | BitField<16, 3, ColorFormat> color_format; | ||
| 214 | |||
| 215 | INSERT_PADDING_WORDS(0x4); | ||
| 216 | |||
| 217 | u32 depth_buffer_address; | ||
| 218 | u32 color_buffer_address; | ||
| 219 | |||
| 220 | union { | ||
| 221 | // Apparently, the framebuffer width is stored as expected, | ||
| 222 | // while the height is stored as the actual height minus one. | ||
| 223 | // Hence, don't access these fields directly but use the accessors | ||
| 224 | // GetWidth() and GetHeight() instead. | ||
| 225 | BitField<0, 11, u32> width; | ||
| 226 | BitField<12, 10, u32> height; | ||
| 227 | }; | ||
| 228 | |||
| 229 | INSERT_PADDING_WORDS(0x1); | ||
| 230 | |||
| 231 | inline PAddr GetColorBufferPhysicalAddress() const { | ||
| 232 | return color_buffer_address * 8; | ||
| 233 | } | ||
| 234 | inline PAddr GetDepthBufferPhysicalAddress() const { | ||
| 235 | return depth_buffer_address * 8; | ||
| 236 | } | ||
| 237 | |||
| 238 | inline u32 GetWidth() const { | ||
| 239 | return width; | ||
| 240 | } | ||
| 241 | |||
| 242 | inline u32 GetHeight() const { | ||
| 243 | return height + 1; | ||
| 244 | } | ||
| 245 | } framebuffer; | ||
| 246 | |||
| 247 | // Returns the number of bytes in the specified depth format | ||
| 248 | static u32 BytesPerDepthPixel(DepthFormat format) { | ||
| 249 | switch (format) { | ||
| 250 | case DepthFormat::D16: | ||
| 251 | return 2; | ||
| 252 | case DepthFormat::D24: | ||
| 253 | return 3; | ||
| 254 | case DepthFormat::D24S8: | ||
| 255 | return 4; | ||
| 256 | default: | ||
| 257 | LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||
| 258 | UNIMPLEMENTED(); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | // Returns the number of bits per depth component of the specified depth format | ||
| 263 | static u32 DepthBitsPerPixel(DepthFormat format) { | ||
| 264 | switch (format) { | ||
| 265 | case DepthFormat::D16: | ||
| 266 | return 16; | ||
| 267 | case DepthFormat::D24: | ||
| 268 | case DepthFormat::D24S8: | ||
| 269 | return 24; | ||
| 270 | default: | ||
| 271 | LOG_CRITICAL(HW_GPU, "Unknown depth format %u", format); | ||
| 272 | UNIMPLEMENTED(); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | INSERT_PADDING_WORDS(0x20); | ||
| 277 | }; | ||
| 278 | |||
| 279 | static_assert(sizeof(FramebufferRegs) == 0x40 * sizeof(u32), | ||
| 280 | "FramebufferRegs struct has incorrect size"); | ||
| 281 | |||
| 282 | } // 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() { | |||
| 183 | CachedSurface* depth_surface; | 183 | CachedSurface* depth_surface; |
| 184 | MathUtil::Rectangle<int> rect; | 184 | MathUtil::Rectangle<int> rect; |
| 185 | std::tie(color_surface, depth_surface, rect) = | 185 | std::tie(color_surface, depth_surface, rect) = |
| 186 | res_cache.GetFramebufferSurfaces(regs.framebuffer); | 186 | res_cache.GetFramebufferSurfaces(regs.framebuffer.framebuffer); |
| 187 | 187 | ||
| 188 | state.draw.draw_framebuffer = framebuffer.handle; | 188 | state.draw.draw_framebuffer = framebuffer.handle; |
| 189 | state.Apply(); | 189 | state.Apply(); |
| @@ -192,7 +192,8 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 192 | color_surface != nullptr ? color_surface->texture.handle : 0, 0); | 192 | color_surface != nullptr ? color_surface->texture.handle : 0, 0); |
| 193 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, | 193 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, |
| 194 | depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); | 194 | depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); |
| 195 | bool has_stencil = regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | 195 | bool has_stencil = |
| 196 | regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; | ||
| 196 | glFramebufferTexture2D( | 197 | glFramebufferTexture2D( |
| 197 | GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 198 | GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 198 | (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); | 199 | (has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0); |
| @@ -339,13 +340,13 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 339 | break; | 340 | break; |
| 340 | 341 | ||
| 341 | // Blending | 342 | // Blending |
| 342 | case PICA_REG_INDEX(output_merger.alphablend_enable): | 343 | case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable): |
| 343 | SyncBlendEnabled(); | 344 | SyncBlendEnabled(); |
| 344 | break; | 345 | break; |
| 345 | case PICA_REG_INDEX(output_merger.alpha_blending): | 346 | case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending): |
| 346 | SyncBlendFuncs(); | 347 | SyncBlendFuncs(); |
| 347 | break; | 348 | break; |
| 348 | case PICA_REG_INDEX(output_merger.blend_const): | 349 | case PICA_REG_INDEX(framebuffer.output_merger.blend_const): |
| 349 | SyncBlendColor(); | 350 | SyncBlendColor(); |
| 350 | break; | 351 | break; |
| 351 | 352 | ||
| @@ -365,25 +366,25 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 365 | break; | 366 | break; |
| 366 | 367 | ||
| 367 | // Alpha test | 368 | // Alpha test |
| 368 | case PICA_REG_INDEX(output_merger.alpha_test): | 369 | case PICA_REG_INDEX(framebuffer.output_merger.alpha_test): |
| 369 | SyncAlphaTest(); | 370 | SyncAlphaTest(); |
| 370 | shader_dirty = true; | 371 | shader_dirty = true; |
| 371 | break; | 372 | break; |
| 372 | 373 | ||
| 373 | // Sync GL stencil test + stencil write mask | 374 | // Sync GL stencil test + stencil write mask |
| 374 | // (Pica stencil test function register also contains a stencil write mask) | 375 | // (Pica stencil test function register also contains a stencil write mask) |
| 375 | case PICA_REG_INDEX(output_merger.stencil_test.raw_func): | 376 | case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_func): |
| 376 | SyncStencilTest(); | 377 | SyncStencilTest(); |
| 377 | SyncStencilWriteMask(); | 378 | SyncStencilWriteMask(); |
| 378 | break; | 379 | break; |
| 379 | case PICA_REG_INDEX(output_merger.stencil_test.raw_op): | 380 | case PICA_REG_INDEX(framebuffer.output_merger.stencil_test.raw_op): |
| 380 | case PICA_REG_INDEX(framebuffer.depth_format): | 381 | case PICA_REG_INDEX(framebuffer.framebuffer.depth_format): |
| 381 | SyncStencilTest(); | 382 | SyncStencilTest(); |
| 382 | break; | 383 | break; |
| 383 | 384 | ||
| 384 | // Sync GL depth test + depth and color write mask | 385 | // Sync GL depth test + depth and color write mask |
| 385 | // (Pica depth test function register also contains a depth and color write mask) | 386 | // (Pica depth test function register also contains a depth and color write mask) |
| 386 | case PICA_REG_INDEX(output_merger.depth_test_enable): | 387 | case PICA_REG_INDEX(framebuffer.output_merger.depth_test_enable): |
| 387 | SyncDepthTest(); | 388 | SyncDepthTest(); |
| 388 | SyncDepthWriteMask(); | 389 | SyncDepthWriteMask(); |
| 389 | SyncColorWriteMask(); | 390 | SyncColorWriteMask(); |
| @@ -391,14 +392,14 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 391 | 392 | ||
| 392 | // Sync GL depth and stencil write mask | 393 | // Sync GL depth and stencil write mask |
| 393 | // (This is a dedicated combined depth / stencil write-enable register) | 394 | // (This is a dedicated combined depth / stencil write-enable register) |
| 394 | case PICA_REG_INDEX(framebuffer.allow_depth_stencil_write): | 395 | case PICA_REG_INDEX(framebuffer.framebuffer.allow_depth_stencil_write): |
| 395 | SyncDepthWriteMask(); | 396 | SyncDepthWriteMask(); |
| 396 | SyncStencilWriteMask(); | 397 | SyncStencilWriteMask(); |
| 397 | break; | 398 | break; |
| 398 | 399 | ||
| 399 | // Sync GL color write mask | 400 | // Sync GL color write mask |
| 400 | // (This is a dedicated color write-enable register) | 401 | // (This is a dedicated color write-enable register) |
| 401 | case PICA_REG_INDEX(framebuffer.allow_color_write): | 402 | case PICA_REG_INDEX(framebuffer.framebuffer.allow_color_write): |
| 402 | SyncColorWriteMask(); | 403 | SyncColorWriteMask(); |
| 403 | break; | 404 | break; |
| 404 | 405 | ||
| @@ -408,7 +409,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 408 | break; | 409 | break; |
| 409 | 410 | ||
| 410 | // Logic op | 411 | // Logic op |
| 411 | case PICA_REG_INDEX(output_merger.logic_op): | 412 | case PICA_REG_INDEX(framebuffer.output_merger.logic_op): |
| 412 | SyncLogicOp(); | 413 | SyncLogicOp(); |
| 413 | break; | 414 | break; |
| 414 | 415 | ||
| @@ -1158,25 +1159,28 @@ void RasterizerOpenGL::SyncDepthOffset() { | |||
| 1158 | } | 1159 | } |
| 1159 | 1160 | ||
| 1160 | void RasterizerOpenGL::SyncBlendEnabled() { | 1161 | void RasterizerOpenGL::SyncBlendEnabled() { |
| 1161 | state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); | 1162 | state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1); |
| 1162 | } | 1163 | } |
| 1163 | 1164 | ||
| 1164 | void RasterizerOpenGL::SyncBlendFuncs() { | 1165 | void RasterizerOpenGL::SyncBlendFuncs() { |
| 1165 | const auto& regs = Pica::g_state.regs; | 1166 | const auto& regs = Pica::g_state.regs; |
| 1166 | state.blend.rgb_equation = | 1167 | state.blend.rgb_equation = |
| 1167 | PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_rgb); | 1168 | PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_rgb); |
| 1168 | state.blend.a_equation = | 1169 | state.blend.a_equation = |
| 1169 | PicaToGL::BlendEquation(regs.output_merger.alpha_blending.blend_equation_a); | 1170 | PicaToGL::BlendEquation(regs.framebuffer.output_merger.alpha_blending.blend_equation_a); |
| 1170 | state.blend.src_rgb_func = | 1171 | state.blend.src_rgb_func = |
| 1171 | PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); | 1172 | PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_rgb); |
| 1172 | state.blend.dst_rgb_func = | 1173 | state.blend.dst_rgb_func = |
| 1173 | PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); | 1174 | PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_rgb); |
| 1174 | state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); | 1175 | state.blend.src_a_func = |
| 1175 | state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); | 1176 | PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_source_a); |
| 1177 | state.blend.dst_a_func = | ||
| 1178 | PicaToGL::BlendFunc(regs.framebuffer.output_merger.alpha_blending.factor_dest_a); | ||
| 1176 | } | 1179 | } |
| 1177 | 1180 | ||
| 1178 | void RasterizerOpenGL::SyncBlendColor() { | 1181 | void RasterizerOpenGL::SyncBlendColor() { |
| 1179 | auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); | 1182 | auto blend_color = |
| 1183 | PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw); | ||
| 1180 | state.blend.color.red = blend_color[0]; | 1184 | state.blend.color.red = blend_color[0]; |
| 1181 | state.blend.color.green = blend_color[1]; | 1185 | state.blend.color.green = blend_color[1]; |
| 1182 | state.blend.color.blue = blend_color[2]; | 1186 | state.blend.color.blue = blend_color[2]; |
| @@ -1208,66 +1212,73 @@ void RasterizerOpenGL::SyncFogLUT() { | |||
| 1208 | 1212 | ||
| 1209 | void RasterizerOpenGL::SyncAlphaTest() { | 1213 | void RasterizerOpenGL::SyncAlphaTest() { |
| 1210 | const auto& regs = Pica::g_state.regs; | 1214 | const auto& regs = Pica::g_state.regs; |
| 1211 | if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { | 1215 | if (regs.framebuffer.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { |
| 1212 | uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref; | 1216 | uniform_block_data.data.alphatest_ref = regs.framebuffer.output_merger.alpha_test.ref; |
| 1213 | uniform_block_data.dirty = true; | 1217 | uniform_block_data.dirty = true; |
| 1214 | } | 1218 | } |
| 1215 | } | 1219 | } |
| 1216 | 1220 | ||
| 1217 | void RasterizerOpenGL::SyncLogicOp() { | 1221 | void RasterizerOpenGL::SyncLogicOp() { |
| 1218 | state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); | 1222 | state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op); |
| 1219 | } | 1223 | } |
| 1220 | 1224 | ||
| 1221 | void RasterizerOpenGL::SyncColorWriteMask() { | 1225 | void RasterizerOpenGL::SyncColorWriteMask() { |
| 1222 | const auto& regs = Pica::g_state.regs; | 1226 | const auto& regs = Pica::g_state.regs; |
| 1223 | 1227 | ||
| 1224 | auto IsColorWriteEnabled = [&](u32 value) { | 1228 | auto IsColorWriteEnabled = [&](u32 value) { |
| 1225 | return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; | 1229 | return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE |
| 1230 | : GL_FALSE; | ||
| 1226 | }; | 1231 | }; |
| 1227 | 1232 | ||
| 1228 | state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable); | 1233 | state.color_mask.red_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.red_enable); |
| 1229 | state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable); | 1234 | state.color_mask.green_enabled = |
| 1230 | state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable); | 1235 | IsColorWriteEnabled(regs.framebuffer.output_merger.green_enable); |
| 1231 | state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable); | 1236 | state.color_mask.blue_enabled = IsColorWriteEnabled(regs.framebuffer.output_merger.blue_enable); |
| 1237 | state.color_mask.alpha_enabled = | ||
| 1238 | IsColorWriteEnabled(regs.framebuffer.output_merger.alpha_enable); | ||
| 1232 | } | 1239 | } |
| 1233 | 1240 | ||
| 1234 | void RasterizerOpenGL::SyncStencilWriteMask() { | 1241 | void RasterizerOpenGL::SyncStencilWriteMask() { |
| 1235 | const auto& regs = Pica::g_state.regs; | 1242 | const auto& regs = Pica::g_state.regs; |
| 1236 | state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) | 1243 | state.stencil.write_mask = |
| 1237 | ? static_cast<GLuint>(regs.output_merger.stencil_test.write_mask) | 1244 | (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0) |
| 1238 | : 0; | 1245 | ? static_cast<GLuint>(regs.framebuffer.output_merger.stencil_test.write_mask) |
| 1246 | : 0; | ||
| 1239 | } | 1247 | } |
| 1240 | 1248 | ||
| 1241 | void RasterizerOpenGL::SyncDepthWriteMask() { | 1249 | void RasterizerOpenGL::SyncDepthWriteMask() { |
| 1242 | const auto& regs = Pica::g_state.regs; | 1250 | const auto& regs = Pica::g_state.regs; |
| 1243 | state.depth.write_mask = | 1251 | state.depth.write_mask = (regs.framebuffer.framebuffer.allow_depth_stencil_write != 0 && |
| 1244 | (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) | 1252 | regs.framebuffer.output_merger.depth_write_enable) |
| 1245 | ? GL_TRUE | 1253 | ? GL_TRUE |
| 1246 | : GL_FALSE; | 1254 | : GL_FALSE; |
| 1247 | } | 1255 | } |
| 1248 | 1256 | ||
| 1249 | void RasterizerOpenGL::SyncStencilTest() { | 1257 | void RasterizerOpenGL::SyncStencilTest() { |
| 1250 | const auto& regs = Pica::g_state.regs; | 1258 | const auto& regs = Pica::g_state.regs; |
| 1251 | state.stencil.test_enabled = regs.output_merger.stencil_test.enable && | 1259 | state.stencil.test_enabled = |
| 1252 | regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; | 1260 | regs.framebuffer.output_merger.stencil_test.enable && |
| 1253 | state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); | 1261 | regs.framebuffer.framebuffer.depth_format == Pica::FramebufferRegs::DepthFormat::D24S8; |
| 1254 | state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; | 1262 | state.stencil.test_func = |
| 1255 | state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; | 1263 | PicaToGL::CompareFunc(regs.framebuffer.output_merger.stencil_test.func); |
| 1264 | state.stencil.test_ref = regs.framebuffer.output_merger.stencil_test.reference_value; | ||
| 1265 | state.stencil.test_mask = regs.framebuffer.output_merger.stencil_test.input_mask; | ||
| 1256 | state.stencil.action_stencil_fail = | 1266 | state.stencil.action_stencil_fail = |
| 1257 | PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); | 1267 | PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_stencil_fail); |
| 1258 | state.stencil.action_depth_fail = | 1268 | state.stencil.action_depth_fail = |
| 1259 | PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); | 1269 | PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_fail); |
| 1260 | state.stencil.action_depth_pass = | 1270 | state.stencil.action_depth_pass = |
| 1261 | PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); | 1271 | PicaToGL::StencilOp(regs.framebuffer.output_merger.stencil_test.action_depth_pass); |
| 1262 | } | 1272 | } |
| 1263 | 1273 | ||
| 1264 | void RasterizerOpenGL::SyncDepthTest() { | 1274 | void RasterizerOpenGL::SyncDepthTest() { |
| 1265 | const auto& regs = Pica::g_state.regs; | 1275 | const auto& regs = Pica::g_state.regs; |
| 1266 | state.depth.test_enabled = | 1276 | state.depth.test_enabled = regs.framebuffer.output_merger.depth_test_enable == 1 || |
| 1267 | regs.output_merger.depth_test_enable == 1 || regs.output_merger.depth_write_enable == 1; | 1277 | regs.framebuffer.output_merger.depth_write_enable == 1; |
| 1268 | state.depth.test_func = regs.output_merger.depth_test_enable == 1 | 1278 | state.depth.test_func = |
| 1269 | ? PicaToGL::CompareFunc(regs.output_merger.depth_test_func) | 1279 | regs.framebuffer.output_merger.depth_test_enable == 1 |
| 1270 | : GL_ALWAYS; | 1280 | ? PicaToGL::CompareFunc(regs.framebuffer.output_merger.depth_test_func) |
| 1281 | : GL_ALWAYS; | ||
| 1271 | } | 1282 | } |
| 1272 | 1283 | ||
| 1273 | void RasterizerOpenGL::SyncCombinerColor() { | 1284 | 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 { | |||
| 56 | 56 | ||
| 57 | state.depthmap_enable = regs.rasterizer.depthmap_enable; | 57 | state.depthmap_enable = regs.rasterizer.depthmap_enable; |
| 58 | 58 | ||
| 59 | state.alpha_test_func = regs.output_merger.alpha_test.enable | 59 | state.alpha_test_func = regs.framebuffer.output_merger.alpha_test.enable |
| 60 | ? regs.output_merger.alpha_test.func.Value() | 60 | ? regs.framebuffer.output_merger.alpha_test.func.Value() |
| 61 | : Pica::Regs::CompareFunc::Always; | 61 | : Pica::FramebufferRegs::CompareFunc::Always; |
| 62 | 62 | ||
| 63 | state.texture0_type = regs.texturing.texture0.type; | 63 | state.texture0_type = regs.texturing.texture0.type; |
| 64 | 64 | ||
| @@ -172,7 +172,7 @@ union PicaShaderConfig { | |||
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | struct State { | 174 | struct State { |
| 175 | Pica::Regs::CompareFunc alpha_test_func; | 175 | Pica::FramebufferRegs::CompareFunc alpha_test_func; |
| 176 | Pica::RasterizerRegs::ScissorMode scissor_test_mode; | 176 | Pica::RasterizerRegs::ScissorMode scissor_test_mode; |
| 177 | Pica::TexturingRegs::TextureConfig::TextureType texture0_type; | 177 | Pica::TexturingRegs::TextureConfig::TextureType texture0_type; |
| 178 | std::array<TevStageConfigRaw, 6> tev_stages; | 178 | std::array<TevStageConfigRaw, 6> 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( | |||
| 525 | } | 525 | } |
| 526 | 526 | ||
| 527 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> | 527 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> |
| 528 | RasterizerCacheOpenGL::GetFramebufferSurfaces(const Pica::Regs::FramebufferConfig& config) { | 528 | RasterizerCacheOpenGL::GetFramebufferSurfaces( |
| 529 | const Pica::FramebufferRegs::FramebufferConfig& config) { | ||
| 530 | |||
| 529 | const auto& regs = Pica::g_state.regs; | 531 | const auto& regs = Pica::g_state.regs; |
| 530 | 532 | ||
| 531 | // Make sur that framebuffers don't overlap if both color and depth are being used | 533 | // 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 | |||
| 537 | config.GetColorBufferPhysicalAddress(), | 539 | config.GetColorBufferPhysicalAddress(), |
| 538 | fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), | 540 | fb_area * GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(config.color_format.Value())), |
| 539 | config.GetDepthBufferPhysicalAddress(), | 541 | config.GetDepthBufferPhysicalAddress(), |
| 540 | fb_area * Pica::Regs::BytesPerDepthPixel(config.depth_format)); | 542 | fb_area * Pica::FramebufferRegs::BytesPerDepthPixel(config.depth_format)); |
| 541 | bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; | 543 | bool using_color_fb = config.GetColorBufferPhysicalAddress() != 0; |
| 542 | bool using_depth_fb = config.GetDepthBufferPhysicalAddress() != 0 && | 544 | bool using_depth_fb = |
| 543 | (regs.output_merger.depth_test_enable || | 545 | config.GetDepthBufferPhysicalAddress() != 0 && |
| 544 | regs.output_merger.depth_write_enable || !framebuffers_overlap); | 546 | (regs.framebuffer.output_merger.depth_test_enable || |
| 547 | regs.framebuffer.output_merger.depth_write_enable || !framebuffers_overlap); | ||
| 545 | 548 | ||
| 546 | if (framebuffers_overlap && using_color_fb && using_depth_fb) { | 549 | if (framebuffers_overlap && using_color_fb && using_depth_fb) { |
| 547 | LOG_CRITICAL(Render_OpenGL, "Color and depth framebuffer memory regions overlap; " | 550 | 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 { | |||
| 100 | return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; | 100 | return ((unsigned int)format < 14) ? (PixelFormat)format : PixelFormat::Invalid; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | static PixelFormat PixelFormatFromColorFormat(Pica::Regs::ColorFormat format) { | 103 | static PixelFormat PixelFormatFromColorFormat(Pica::FramebufferRegs::ColorFormat format) { |
| 104 | return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; | 104 | return ((unsigned int)format < 5) ? (PixelFormat)format : PixelFormat::Invalid; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static PixelFormat PixelFormatFromDepthFormat(Pica::Regs::DepthFormat format) { | 107 | static PixelFormat PixelFormatFromDepthFormat(Pica::FramebufferRegs::DepthFormat format) { |
| 108 | return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) | 108 | return ((unsigned int)format < 4) ? (PixelFormat)((unsigned int)format + 14) |
| 109 | : PixelFormat::Invalid; | 109 | : PixelFormat::Invalid; |
| 110 | } | 110 | } |
| @@ -217,7 +217,7 @@ public: | |||
| 217 | /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer | 217 | /// Gets the color and depth surfaces and rect (resolution scaled) based on the framebuffer |
| 218 | /// configuration | 218 | /// configuration |
| 219 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces( | 219 | std::tuple<CachedSurface*, CachedSurface*, MathUtil::Rectangle<int>> GetFramebufferSurfaces( |
| 220 | const Pica::Regs::FramebufferConfig& config); | 220 | const Pica::FramebufferRegs::FramebufferConfig& config); |
| 221 | 221 | ||
| 222 | /// Attempt to get a surface that exactly matches the fill region and format | 222 | /// Attempt to get a surface that exactly matches the fill region and format |
| 223 | CachedSurface* TryGetFillSurface(const GPU::Regs::MemoryFillConfig& config); | 223 | 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 | |||
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | /// Writes the if-statement condition used to evaluate alpha testing | 279 | /// Writes the if-statement condition used to evaluate alpha testing |
| 280 | static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | 280 | static void AppendAlphaTestCondition(std::string& out, Pica::FramebufferRegs::CompareFunc func) { |
| 281 | using CompareFunc = Regs::CompareFunc; | 281 | using CompareFunc = Pica::FramebufferRegs::CompareFunc; |
| 282 | switch (func) { | 282 | switch (func) { |
| 283 | case CompareFunc::Never: | 283 | case CompareFunc::Never: |
| 284 | out += "true"; | 284 | out += "true"; |
| @@ -634,7 +634,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 634 | )"; | 634 | )"; |
| 635 | 635 | ||
| 636 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | 636 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test |
| 637 | if (state.alpha_test_func == Regs::CompareFunc::Never) { | 637 | if (state.alpha_test_func == Pica::FramebufferRegs::CompareFunc::Never) { |
| 638 | out += "discard; }"; | 638 | out += "discard; }"; |
| 639 | return out; | 639 | return out; |
| 640 | } | 640 | } |
| @@ -667,7 +667,7 @@ vec4 secondary_fragment_color = vec4(0.0); | |||
| 667 | for (size_t index = 0; index < state.tev_stages.size(); ++index) | 667 | for (size_t index = 0; index < state.tev_stages.size(); ++index) |
| 668 | WriteTevStage(out, config, (unsigned)index); | 668 | WriteTevStage(out, config, (unsigned)index); |
| 669 | 669 | ||
| 670 | if (state.alpha_test_func != Regs::CompareFunc::Always) { | 670 | if (state.alpha_test_func != Pica::FramebufferRegs::CompareFunc::Always) { |
| 671 | out += "if ("; | 671 | out += "if ("; |
| 672 | AppendAlphaTestCondition(out, state.alpha_test_func); | 672 | AppendAlphaTestCondition(out, state.alpha_test_func); |
| 673 | out += ") discard;\n"; | 673 | 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) { | |||
| 76 | return gl_mode; | 76 | return gl_mode; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { | 79 | inline GLenum BlendEquation(Pica::FramebufferRegs::BlendEquation equation) { |
| 80 | static const GLenum blend_equation_table[] = { | 80 | static const GLenum blend_equation_table[] = { |
| 81 | GL_FUNC_ADD, // BlendEquation::Add | 81 | GL_FUNC_ADD, // BlendEquation::Add |
| 82 | GL_FUNC_SUBTRACT, // BlendEquation::Subtract | 82 | GL_FUNC_SUBTRACT, // BlendEquation::Subtract |
| @@ -96,7 +96,7 @@ inline GLenum BlendEquation(Pica::Regs::BlendEquation equation) { | |||
| 96 | return blend_equation_table[(unsigned)equation]; | 96 | return blend_equation_table[(unsigned)equation]; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | 99 | inline GLenum BlendFunc(Pica::FramebufferRegs::BlendFactor factor) { |
| 100 | static const GLenum blend_func_table[] = { | 100 | static const GLenum blend_func_table[] = { |
| 101 | GL_ZERO, // BlendFactor::Zero | 101 | GL_ZERO, // BlendFactor::Zero |
| 102 | GL_ONE, // BlendFactor::One | 102 | GL_ONE, // BlendFactor::One |
| @@ -126,7 +126,7 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) { | |||
| 126 | return blend_func_table[(unsigned)factor]; | 126 | return blend_func_table[(unsigned)factor]; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | inline GLenum LogicOp(Pica::Regs::LogicOp op) { | 129 | inline GLenum LogicOp(Pica::FramebufferRegs::LogicOp op) { |
| 130 | static const GLenum logic_op_table[] = { | 130 | static const GLenum logic_op_table[] = { |
| 131 | GL_CLEAR, // Clear | 131 | GL_CLEAR, // Clear |
| 132 | GL_AND, // And | 132 | GL_AND, // And |
| @@ -157,7 +157,7 @@ inline GLenum LogicOp(Pica::Regs::LogicOp op) { | |||
| 157 | return logic_op_table[(unsigned)op]; | 157 | return logic_op_table[(unsigned)op]; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | 160 | inline GLenum CompareFunc(Pica::FramebufferRegs::CompareFunc func) { |
| 161 | static const GLenum compare_func_table[] = { | 161 | static const GLenum compare_func_table[] = { |
| 162 | GL_NEVER, // CompareFunc::Never | 162 | GL_NEVER, // CompareFunc::Never |
| 163 | GL_ALWAYS, // CompareFunc::Always | 163 | GL_ALWAYS, // CompareFunc::Always |
| @@ -180,7 +180,7 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { | |||
| 180 | return compare_func_table[(unsigned)func]; | 180 | return compare_func_table[(unsigned)func]; |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | inline GLenum StencilOp(Pica::Regs::StencilAction action) { | 183 | inline GLenum StencilOp(Pica::FramebufferRegs::StencilAction action) { |
| 184 | static const GLenum stencil_op_table[] = { | 184 | static const GLenum stencil_op_table[] = { |
| 185 | GL_KEEP, // StencilAction::Keep | 185 | GL_KEEP, // StencilAction::Keep |
| 186 | GL_ZERO, // StencilAction::Zero | 186 | GL_ZERO, // StencilAction::Zero |