diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 962228680..479edfff4 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -14,6 +14,7 @@ set(SRCS shader/shader.cpp shader/shader_interpreter.cpp swrasterizer/clipper.cpp + swrasterizer/framebuffer.cpp swrasterizer/rasterizer.cpp swrasterizer/swrasterizer.cpp texture/etc1.cpp @@ -51,6 +52,7 @@ set(HEADERS shader/shader.h shader/shader_interpreter.h swrasterizer/clipper.h + swrasterizer/framebuffer.h swrasterizer/rasterizer.h swrasterizer/swrasterizer.h texture/etc1.h diff --git a/src/video_core/swrasterizer/framebuffer.cpp b/src/video_core/swrasterizer/framebuffer.cpp new file mode 100644 index 000000000..4b31eda89 --- /dev/null +++ b/src/video_core/swrasterizer/framebuffer.cpp @@ -0,0 +1,259 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/assert.h" +#include "common/color.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/vector_math.h" +#include "core/hw/gpu.h" +#include "core/memory.h" +#include "video_core/pica_state.h" +#include "video_core/regs_framebuffer.h" +#include "video_core/swrasterizer/framebuffer.h" +#include "video_core/utils.h" + +namespace Pica { +namespace Rasterizer { + +void DrawPixel(int x, int y, const Math::Vec4& color) { + 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. + // NOTE: The framebuffer height register contains the actual FB height minus one. + y = framebuffer.height - y; + + const u32 coarse_y = y & ~7; + u32 bytes_per_pixel = + GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value())); + u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + + coarse_y * framebuffer.width * bytes_per_pixel; + u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; + + switch (framebuffer.color_format) { + case FramebufferRegs::ColorFormat::RGBA8: + Color::EncodeRGBA8(color, dst_pixel); + break; + + case FramebufferRegs::ColorFormat::RGB8: + Color::EncodeRGB8(color, dst_pixel); + break; + + case FramebufferRegs::ColorFormat::RGB5A1: + Color::EncodeRGB5A1(color, dst_pixel); + break; + + case FramebufferRegs::ColorFormat::RGB565: + Color::EncodeRGB565(color, dst_pixel); + break; + + case FramebufferRegs::ColorFormat::RGBA4: + Color::EncodeRGBA4(color, dst_pixel); + break; + + default: + LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", + framebuffer.color_format.Value()); + UNIMPLEMENTED(); + } +} + +const Math::Vec4 GetPixel(int x, int y) { + const auto& framebuffer = g_state.regs.framebuffer.framebuffer; + const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); + + y = framebuffer.height - y; + + const u32 coarse_y = y & ~7; + u32 bytes_per_pixel = + GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value())); + u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + + coarse_y * framebuffer.width * bytes_per_pixel; + u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; + + switch (framebuffer.color_format) { + case FramebufferRegs::ColorFormat::RGBA8: + return Color::DecodeRGBA8(src_pixel); + + case FramebufferRegs::ColorFormat::RGB8: + return Color::DecodeRGB8(src_pixel); + + case FramebufferRegs::ColorFormat::RGB5A1: + return Color::DecodeRGB5A1(src_pixel); + + case FramebufferRegs::ColorFormat::RGB565: + return Color::DecodeRGB565(src_pixel); + + case FramebufferRegs::ColorFormat::RGBA4: + return Color::DecodeRGBA4(src_pixel); + + default: + LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", + framebuffer.color_format.Value()); + UNIMPLEMENTED(); + } + + return {0, 0, 0, 0}; +} + +u32 GetDepth(int x, int y) { + 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 = 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 FramebufferRegs::DepthFormat::D16: + return Color::DecodeD16(src_pixel); + case FramebufferRegs::DepthFormat::D24: + return Color::DecodeD24(src_pixel); + case FramebufferRegs::DepthFormat::D24S8: + return Color::DecodeD24S8(src_pixel).x; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); + UNIMPLEMENTED(); + return 0; + } +} + +u8 GetStencil(int x, int y) { + 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::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 FramebufferRegs::DepthFormat::D24S8: + return Color::DecodeD24S8(src_pixel).y; + + default: + LOG_WARNING( + HW_GPU, + "GetStencil called for function which doesn't have a stencil component (format %u)", + framebuffer.depth_format); + return 0; + } +} + +void SetDepth(int x, int y, u32 value) { + 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 = 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 FramebufferRegs::DepthFormat::D16: + Color::EncodeD16(value, dst_pixel); + break; + + case FramebufferRegs::DepthFormat::D24: + Color::EncodeD24(value, dst_pixel); + break; + + case FramebufferRegs::DepthFormat::D24S8: + Color::EncodeD24X8(value, dst_pixel); + break; + + default: + LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); + UNIMPLEMENTED(); + break; + } +} + +void SetStencil(int x, int y, u8 value) { + 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::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::FramebufferRegs::DepthFormat::D16: + case Pica::FramebufferRegs::DepthFormat::D24: + // Nothing to do + break; + + case Pica::FramebufferRegs::DepthFormat::D24S8: + Color::EncodeX24S8(value, dst_pixel); + break; + + default: + LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); + UNIMPLEMENTED(); + break; + } +} + +u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) { + switch (action) { + case FramebufferRegs::StencilAction::Keep: + return old_stencil; + + case FramebufferRegs::StencilAction::Zero: + return 0; + + case FramebufferRegs::StencilAction::Replace: + return ref; + + case FramebufferRegs::StencilAction::Increment: + // Saturated increment + return std::min(old_stencil, 254) + 1; + + case FramebufferRegs::StencilAction::Decrement: + // Saturated decrement + return std::max(old_stencil, 1) - 1; + + case FramebufferRegs::StencilAction::Invert: + return ~old_stencil; + + case FramebufferRegs::StencilAction::IncrementWrap: + return old_stencil + 1; + + case FramebufferRegs::StencilAction::DecrementWrap: + return old_stencil - 1; + + default: + LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action); + UNIMPLEMENTED(); + return 0; + } +} + +} // namespace Rasterizer +} // namespace Pica diff --git a/src/video_core/swrasterizer/framebuffer.h b/src/video_core/swrasterizer/framebuffer.h new file mode 100644 index 000000000..220f7013b --- /dev/null +++ b/src/video_core/swrasterizer/framebuffer.h @@ -0,0 +1,23 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/vector_math.h" +#include "video_core/regs_framebuffer.h" + +namespace Pica { +namespace Rasterizer { + +void DrawPixel(int x, int y, const Math::Vec4& color); +const Math::Vec4 GetPixel(int x, int y); +u32 GetDepth(int x, int y); +u8 GetStencil(int x, int y); +void SetDepth(int x, int y, u32 value); +void SetStencil(int x, int y, u8 value); +u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref); + +} // namespace Rasterizer +} // namespace Pica diff --git a/src/video_core/swrasterizer/rasterizer.cpp b/src/video_core/swrasterizer/rasterizer.cpp index 17ba59144..cb11338b7 100644 --- a/src/video_core/swrasterizer/rasterizer.cpp +++ b/src/video_core/swrasterizer/rasterizer.cpp @@ -22,6 +22,7 @@ #include "video_core/regs_rasterizer.h" #include "video_core/regs_texturing.h" #include "video_core/shader/shader.h" +#include "video_core/swrasterizer/framebuffer.h" #include "video_core/swrasterizer/rasterizer.h" #include "video_core/texture/texture_decode.h" #include "video_core/utils.h" @@ -30,242 +31,6 @@ namespace Pica { namespace Rasterizer { -static void DrawPixel(int x, int y, const Math::Vec4& color) { - 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. - // NOTE: The framebuffer height register contains the actual FB height minus one. - y = framebuffer.height - y; - - const u32 coarse_y = y & ~7; - u32 bytes_per_pixel = - GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value())); - u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + - coarse_y * framebuffer.width * bytes_per_pixel; - u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset; - - switch (framebuffer.color_format) { - case FramebufferRegs::ColorFormat::RGBA8: - Color::EncodeRGBA8(color, dst_pixel); - break; - - case FramebufferRegs::ColorFormat::RGB8: - Color::EncodeRGB8(color, dst_pixel); - break; - - case FramebufferRegs::ColorFormat::RGB5A1: - Color::EncodeRGB5A1(color, dst_pixel); - break; - - case FramebufferRegs::ColorFormat::RGB565: - Color::EncodeRGB565(color, dst_pixel); - break; - - case FramebufferRegs::ColorFormat::RGBA4: - Color::EncodeRGBA4(color, dst_pixel); - break; - - default: - LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", - framebuffer.color_format.Value()); - UNIMPLEMENTED(); - } -} - -static const Math::Vec4 GetPixel(int x, int y) { - const auto& framebuffer = g_state.regs.framebuffer.framebuffer; - const PAddr addr = framebuffer.GetColorBufferPhysicalAddress(); - - y = framebuffer.height - y; - - const u32 coarse_y = y & ~7; - u32 bytes_per_pixel = - GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value())); - u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + - coarse_y * framebuffer.width * bytes_per_pixel; - u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset; - - switch (framebuffer.color_format) { - case FramebufferRegs::ColorFormat::RGBA8: - return Color::DecodeRGBA8(src_pixel); - - case FramebufferRegs::ColorFormat::RGB8: - return Color::DecodeRGB8(src_pixel); - - case FramebufferRegs::ColorFormat::RGB5A1: - return Color::DecodeRGB5A1(src_pixel); - - case FramebufferRegs::ColorFormat::RGB565: - return Color::DecodeRGB565(src_pixel); - - case FramebufferRegs::ColorFormat::RGBA4: - return Color::DecodeRGBA4(src_pixel); - - default: - LOG_CRITICAL(Render_Software, "Unknown framebuffer color format %x", - framebuffer.color_format.Value()); - UNIMPLEMENTED(); - } - - return {0, 0, 0, 0}; -} - -static u32 GetDepth(int x, int y) { - 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 = 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 FramebufferRegs::DepthFormat::D16: - return Color::DecodeD16(src_pixel); - case FramebufferRegs::DepthFormat::D24: - return Color::DecodeD24(src_pixel); - case FramebufferRegs::DepthFormat::D24S8: - return Color::DecodeD24S8(src_pixel).x; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); - UNIMPLEMENTED(); - return 0; - } -} - -static u8 GetStencil(int x, int y) { - 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::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 FramebufferRegs::DepthFormat::D24S8: - return Color::DecodeD24S8(src_pixel).y; - - default: - LOG_WARNING( - HW_GPU, - "GetStencil called for function which doesn't have a stencil component (format %u)", - framebuffer.depth_format); - return 0; - } -} - -static void SetDepth(int x, int y, u32 value) { - 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 = 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 FramebufferRegs::DepthFormat::D16: - Color::EncodeD16(value, dst_pixel); - break; - - case FramebufferRegs::DepthFormat::D24: - Color::EncodeD24(value, dst_pixel); - break; - - case FramebufferRegs::DepthFormat::D24S8: - Color::EncodeD24X8(value, dst_pixel); - break; - - default: - LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); - UNIMPLEMENTED(); - break; - } -} - -static void SetStencil(int x, int y, u8 value) { - 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::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::FramebufferRegs::DepthFormat::D16: - case Pica::FramebufferRegs::DepthFormat::D24: - // Nothing to do - break; - - case Pica::FramebufferRegs::DepthFormat::D24S8: - Color::EncodeX24S8(value, dst_pixel); - break; - - default: - LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); - UNIMPLEMENTED(); - break; - } -} - -static u8 PerformStencilAction(FramebufferRegs::StencilAction action, u8 old_stencil, u8 ref) { - switch (action) { - case FramebufferRegs::StencilAction::Keep: - return old_stencil; - - case FramebufferRegs::StencilAction::Zero: - return 0; - - case FramebufferRegs::StencilAction::Replace: - return ref; - - case FramebufferRegs::StencilAction::Increment: - // Saturated increment - return std::min(old_stencil, 254) + 1; - - case FramebufferRegs::StencilAction::Decrement: - // Saturated decrement - return std::max(old_stencil, 1) - 1; - - case FramebufferRegs::StencilAction::Invert: - return ~old_stencil; - - case FramebufferRegs::StencilAction::IncrementWrap: - return old_stencil + 1; - - case FramebufferRegs::StencilAction::DecrementWrap: - return old_stencil - 1; - - default: - LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action); - UNIMPLEMENTED(); - return 0; - } -} - // NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values struct Fix12P4 { Fix12P4() {}