renderer_software: Fix screen rendering (#6664)
This commit is contained in:
parent
cf9bb90ae3
commit
80033b84cb
|
@ -23,10 +23,8 @@ void RendererSoftware::SwapBuffers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererSoftware::PrepareRenderTarget() {
|
void RendererSoftware::PrepareRenderTarget() {
|
||||||
for (int i : {0, 1, 2}) {
|
for (u32 i = 0; i < 3; i++) {
|
||||||
const int fb_id = i == 2 ? 1 : 0;
|
const int fb_id = i == 2 ? 1 : 0;
|
||||||
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
|
||||||
auto& info = screen_infos[i];
|
|
||||||
|
|
||||||
u32 lcd_color_addr =
|
u32 lcd_color_addr =
|
||||||
(fb_id == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom);
|
(fb_id == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom);
|
||||||
|
@ -35,33 +33,29 @@ void RendererSoftware::PrepareRenderTarget() {
|
||||||
LCD::Read(color_fill.raw, lcd_color_addr);
|
LCD::Read(color_fill.raw, lcd_color_addr);
|
||||||
|
|
||||||
if (!color_fill.is_enabled) {
|
if (!color_fill.is_enabled) {
|
||||||
const u32 old_width = std::exchange(info.width, framebuffer.width);
|
LoadFBToScreenInfo(i);
|
||||||
const u32 old_height = std::exchange(info.height, framebuffer.height);
|
|
||||||
if (framebuffer.width != old_width || framebuffer.height != old_height) [[unlikely]] {
|
|
||||||
info.pixels.resize(framebuffer.width * framebuffer.height * 4);
|
|
||||||
}
|
|
||||||
CopyPixels(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererSoftware::CopyPixels(int i) {
|
void RendererSoftware::LoadFBToScreenInfo(int i) {
|
||||||
const u32 fb_id = i == 2 ? 1 : 0;
|
const u32 fb_id = i == 2 ? 1 : 0;
|
||||||
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
|
||||||
|
auto& info = screen_infos[i];
|
||||||
|
|
||||||
const PAddr framebuffer_addr =
|
const PAddr framebuffer_addr =
|
||||||
framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
|
framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
|
||||||
const s32 bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
|
const s32 bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
|
||||||
const u8* framebuffer_data = memory.GetPhysicalPointer(framebuffer_addr);
|
const u8* framebuffer_data = memory.GetPhysicalPointer(framebuffer_addr);
|
||||||
|
|
||||||
const s32 stride = framebuffer.stride;
|
const s32 pixel_stride = framebuffer.stride / bpp;
|
||||||
const s32 height = framebuffer.height;
|
info.height = framebuffer.height;
|
||||||
ASSERT(stride * height != 0);
|
info.width = pixel_stride;
|
||||||
|
info.pixels.resize(info.width * info.height * 4);
|
||||||
|
|
||||||
u32 output_offset = 0;
|
for (u32 y = 0; y < info.height; y++) {
|
||||||
for (u32 y = 0; y < framebuffer.height; y++) {
|
for (u32 x = 0; x < info.width; x++) {
|
||||||
for (u32 x = 0; x < framebuffer.width; x++) {
|
const u8* pixel = framebuffer_data + (y * pixel_stride + pixel_stride - x) * bpp;
|
||||||
const u8* pixel = framebuffer_data + (y * stride + x) * bpp;
|
|
||||||
const Common::Vec4 color = [&] {
|
const Common::Vec4 color = [&] {
|
||||||
switch (framebuffer.color_format) {
|
switch (framebuffer.color_format) {
|
||||||
case GPU::Regs::PixelFormat::RGBA8:
|
case GPU::Regs::PixelFormat::RGBA8:
|
||||||
|
@ -77,9 +71,9 @@ void RendererSoftware::CopyPixels(int i) {
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}();
|
}();
|
||||||
u8* dest = screen_infos[i].pixels.data() + output_offset;
|
const u32 output_offset = (x * info.height + y) * 4;
|
||||||
|
u8* dest = info.pixels.data() + output_offset;
|
||||||
std::memcpy(dest, color.AsArray(), sizeof(color));
|
std::memcpy(dest, color.AsArray(), sizeof(color));
|
||||||
output_offset += sizeof(color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PrepareRenderTarget();
|
void PrepareRenderTarget();
|
||||||
void CopyPixels(int i);
|
void LoadFBToScreenInfo(int i);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
|
|
|
@ -399,8 +399,9 @@ void RasterizerSoftware::ProcessTriangle(const Vertex& v0, const Vertex& v1, con
|
||||||
const f24 tc0_w = get_interpolated_attribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
|
const f24 tc0_w = get_interpolated_attribute(v0.tc0_w, v1.tc0_w, v2.tc0_w);
|
||||||
const auto texture_color = TextureColor(uv, textures, tc0_w);
|
const auto texture_color = TextureColor(uv, textures, tc0_w);
|
||||||
|
|
||||||
Common::Vec4<u8> primary_fragment_color{0, 0, 0, 0};
|
Common::Vec4<u8> primary_fragment_color = {0, 0, 0, 0};
|
||||||
Common::Vec4<u8> secondary_fragment_color{0, 0, 0, 0};
|
Common::Vec4<u8> secondary_fragment_color = {0, 0, 0, 0};
|
||||||
|
|
||||||
if (!regs.lighting.disable) {
|
if (!regs.lighting.disable) {
|
||||||
const auto normquat =
|
const auto normquat =
|
||||||
Common::Quaternion<f32>{
|
Common::Quaternion<f32>{
|
||||||
|
@ -421,9 +422,8 @@ void RasterizerSoftware::ProcessTriangle(const Vertex& v0, const Vertex& v1, con
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the TEV stages.
|
// Write the TEV stages.
|
||||||
Common::Vec4<u8> combiner_output =
|
WriteTevConfig(texture_color, tev_stages, primary_color, primary_fragment_color,
|
||||||
WriteTevConfig(texture_color, tev_stages, primary_color, primary_fragment_color,
|
secondary_fragment_color);
|
||||||
secondary_fragment_color);
|
|
||||||
|
|
||||||
const auto& output_merger = regs.framebuffer.output_merger;
|
const auto& output_merger = regs.framebuffer.output_merger;
|
||||||
if (output_merger.fragment_operation_mode ==
|
if (output_merger.fragment_operation_mode ==
|
||||||
|
@ -663,11 +663,11 @@ Common::Vec4<u8> RasterizerSoftware::PixelColor(u16 x, u16 y,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Vec4<u8> RasterizerSoftware::WriteTevConfig(
|
void RasterizerSoftware::WriteTevConfig(
|
||||||
std::span<const Common::Vec4<u8>, 4> texture_color,
|
std::span<const Common::Vec4<u8>, 4> texture_color,
|
||||||
std::span<const Pica::TexturingRegs::TevStageConfig, 6> tev_stages,
|
std::span<const Pica::TexturingRegs::TevStageConfig, 6> tev_stages,
|
||||||
Common::Vec4<u8> primary_color, Common::Vec4<u8> primary_fragment_color,
|
Common::Vec4<u8> primary_color, Common::Vec4<u8> primary_fragment_color,
|
||||||
Common::Vec4<u8> secondary_fragment_color) const {
|
Common::Vec4<u8> secondary_fragment_color) {
|
||||||
/**
|
/**
|
||||||
* Texture environment - consists of 6 stages of color and alpha combining.
|
* Texture environment - consists of 6 stages of color and alpha combining.
|
||||||
* Color combiners take three input color values from some source (e.g. interpolated
|
* Color combiners take three input color values from some source (e.g. interpolated
|
||||||
|
@ -676,7 +676,6 @@ Common::Vec4<u8> RasterizerSoftware::WriteTevConfig(
|
||||||
* with some basic arithmetic. Alpha combiners can be configured separately but work
|
* with some basic arithmetic. Alpha combiners can be configured separately but work
|
||||||
* analogously.
|
* analogously.
|
||||||
**/
|
**/
|
||||||
Common::Vec4<u8> combiner_output;
|
|
||||||
Common::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
Common::Vec4<u8> combiner_buffer = {0, 0, 0, 0};
|
||||||
Common::Vec4<u8> next_combiner_buffer =
|
Common::Vec4<u8> next_combiner_buffer =
|
||||||
Common::MakeVec(regs.texturing.tev_combiner_buffer_color.r.Value(),
|
Common::MakeVec(regs.texturing.tev_combiner_buffer_color.r.Value(),
|
||||||
|
@ -767,7 +766,6 @@ Common::Vec4<u8> RasterizerSoftware::WriteTevConfig(
|
||||||
next_combiner_buffer.a() = combiner_output.a();
|
next_combiner_buffer.a() = combiner_output.a();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return combiner_output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerSoftware::WriteFog(Common::Vec4<u8>& combiner_output, float depth) const {
|
void RasterizerSoftware::WriteFog(Common::Vec4<u8>& combiner_output, float depth) const {
|
||||||
|
|
|
@ -55,11 +55,10 @@ private:
|
||||||
Common::Vec4<u8> PixelColor(u16 x, u16 y, Common::Vec4<u8>& combiner_output) const;
|
Common::Vec4<u8> PixelColor(u16 x, u16 y, Common::Vec4<u8>& combiner_output) const;
|
||||||
|
|
||||||
/// Emulates the TEV configuration and returns the combiner output.
|
/// Emulates the TEV configuration and returns the combiner output.
|
||||||
Common::Vec4<u8> WriteTevConfig(
|
void WriteTevConfig(std::span<const Common::Vec4<u8>, 4> texture_color,
|
||||||
std::span<const Common::Vec4<u8>, 4> texture_color,
|
std::span<const Pica::TexturingRegs::TevStageConfig, 6> tev_stages,
|
||||||
std::span<const Pica::TexturingRegs::TevStageConfig, 6> tev_stages,
|
Common::Vec4<u8> primary_color, Common::Vec4<u8> primary_fragment_color,
|
||||||
Common::Vec4<u8> primary_color, Common::Vec4<u8> primary_fragment_color,
|
Common::Vec4<u8> secondary_fragment_color);
|
||||||
Common::Vec4<u8> secondary_fragment_color) const;
|
|
||||||
|
|
||||||
/// Blends fog to the combiner output if enabled.
|
/// Blends fog to the combiner output if enabled.
|
||||||
void WriteFog(Common::Vec4<u8>& combiner_output, float depth) const;
|
void WriteFog(Common::Vec4<u8>& combiner_output, float depth) const;
|
||||||
|
@ -75,6 +74,9 @@ private:
|
||||||
Pica::State& state;
|
Pica::State& state;
|
||||||
const Pica::Regs& regs;
|
const Pica::Regs& regs;
|
||||||
Framebuffer fb;
|
Framebuffer fb;
|
||||||
|
// Kirby Blowout Blast relies on the combiner output of a previous draw
|
||||||
|
// in order to render the sky correctly.
|
||||||
|
Common::Vec4<u8> combiner_output{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace SwRenderer
|
} // namespace SwRenderer
|
||||||
|
|
Reference in New Issue