82 lines
2.9 KiB
C++
82 lines
2.9 KiB
C++
// Copyright 2023 Citra Emulator Project
|
|
// Licensed under GPLv2 or any later version
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "common/color.h"
|
|
#include "core/core.h"
|
|
#include "core/hw/gpu.h"
|
|
#include "core/hw/hw.h"
|
|
#include "core/hw/lcd.h"
|
|
#include "video_core/renderer_software/renderer_software.h"
|
|
|
|
namespace SwRenderer {
|
|
|
|
RendererSoftware::RendererSoftware(Core::System& system, Frontend::EmuWindow& window)
|
|
: VideoCore::RendererBase{system, window, nullptr}, memory{system.Memory()},
|
|
rasterizer{system.Memory()} {}
|
|
|
|
RendererSoftware::~RendererSoftware() = default;
|
|
|
|
void RendererSoftware::SwapBuffers() {
|
|
PrepareRenderTarget();
|
|
EndFrame();
|
|
}
|
|
|
|
void RendererSoftware::PrepareRenderTarget() {
|
|
for (u32 i = 0; i < 3; i++) {
|
|
const int fb_id = i == 2 ? 1 : 0;
|
|
|
|
u32 lcd_color_addr =
|
|
(fb_id == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom);
|
|
lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr;
|
|
LCD::Regs::ColorFill color_fill = {0};
|
|
LCD::Read(color_fill.raw, lcd_color_addr);
|
|
|
|
if (!color_fill.is_enabled) {
|
|
LoadFBToScreenInfo(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RendererSoftware::LoadFBToScreenInfo(int i) {
|
|
const u32 fb_id = i == 2 ? 1 : 0;
|
|
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
|
auto& info = screen_infos[i];
|
|
|
|
const PAddr framebuffer_addr =
|
|
framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
|
|
const s32 bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
|
|
const u8* framebuffer_data = memory.GetPhysicalPointer(framebuffer_addr);
|
|
|
|
const s32 pixel_stride = framebuffer.stride / bpp;
|
|
info.height = framebuffer.height;
|
|
info.width = pixel_stride;
|
|
info.pixels.resize(info.width * info.height * 4);
|
|
|
|
for (u32 y = 0; y < info.height; y++) {
|
|
for (u32 x = 0; x < info.width; x++) {
|
|
const u8* pixel = framebuffer_data + (y * pixel_stride + pixel_stride - x) * bpp;
|
|
const Common::Vec4 color = [&] {
|
|
switch (framebuffer.color_format) {
|
|
case GPU::Regs::PixelFormat::RGBA8:
|
|
return Common::Color::DecodeRGBA8(pixel);
|
|
case GPU::Regs::PixelFormat::RGB8:
|
|
return Common::Color::DecodeRGB8(pixel);
|
|
case GPU::Regs::PixelFormat::RGB565:
|
|
return Common::Color::DecodeRGB565(pixel);
|
|
case GPU::Regs::PixelFormat::RGB5A1:
|
|
return Common::Color::DecodeRGB5A1(pixel);
|
|
case GPU::Regs::PixelFormat::RGBA4:
|
|
return Common::Color::DecodeRGBA4(pixel);
|
|
}
|
|
UNREACHABLE();
|
|
}();
|
|
const u32 output_offset = (x * info.height + y) * 4;
|
|
u8* dest = info.pixels.data() + output_offset;
|
|
std::memcpy(dest, color.AsArray(), sizeof(color));
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace SwRenderer
|