video_core: Fix LCD color fill (#1198)

This commit is contained in:
PabloMK7 2025-06-29 13:51:29 +02:00 committed by GitHub
parent 4447a5c9f2
commit a15af9b550
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 47 additions and 42 deletions

View File

@ -165,15 +165,16 @@ void RendererOpenGL::PrepareRendertarget() {
const auto color_fill = fb_id == 0 ? regs_lcd.color_fill_top : regs_lcd.color_fill_bottom;
if (color_fill.is_enabled) {
FillScreen(color_fill.AsVector(), texture);
continue;
// Resize the texture to let it be reconfigured
texture.width = 1;
texture.height = 1;
}
if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
texture.format != framebuffer.color_format) {
ConfigureFramebufferTexture(texture, framebuffer);
ConfigureFramebufferTexture(texture, framebuffer, color_fill);
}
LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1);
LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1, color_fill);
}
}
@ -231,7 +232,8 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout,
* Loads framebuffer from emulated memory into the active OpenGL texture.
*/
void RendererOpenGL::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer,
ScreenInfo& screen_info, bool right_eye) {
ScreenInfo& screen_info, bool right_eye,
const Pica::ColorFill& color_fill) {
if (framebuffer.address_right1 == 0 || framebuffer.address_right2 == 0)
right_eye = false;
@ -255,15 +257,27 @@ void RendererOpenGL::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuff
// only allows rows to have a memory alignement of 4.
ASSERT(pixel_stride % 4 == 0);
if (!rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride),
if (color_fill.is_enabled ||
!rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, static_cast<u32>(pixel_stride),
screen_info)) {
u32 width = framebuffer.width;
u32 height = framebuffer.height;
u8 fill_pixel[3];
// Reset the screen info's display texture to its own permanent texture
screen_info.display_texture = screen_info.texture.resource.handle;
screen_info.display_texcoords = Common::Rectangle<f32>(0.f, 0.f, 1.f, 1.f);
rasterizer.FlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
const u8* framebuffer_data = system.Memory().GetPhysicalPointer(framebuffer_addr);
u8* framebuffer_data = system.Memory().GetPhysicalPointer(framebuffer_addr);
if (color_fill.is_enabled) {
memcpy(fill_pixel, color_fill.AsVector().AsArray(), sizeof(fill_pixel));
framebuffer_data = fill_pixel;
width = 1;
height = 1;
pixel_stride = 0;
}
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
state.Apply();
@ -276,9 +290,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuff
// they differ from the LCD resolution.
// TODO: Applications could theoretically crash Citra here by specifying too large
// framebuffer sizes. We should make sure that this cannot happen.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
screen_info.texture.gl_format, screen_info.texture.gl_type,
framebuffer_data);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, screen_info.texture.gl_format,
screen_info.texture.gl_type, framebuffer_data);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@ -287,23 +300,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuff
}
}
void RendererOpenGL::FillScreen(Common::Vec3<u8> color, TextureInfo& texture) {
state.texture_units[0].texture_2d = texture.resource.handle;
state.Apply();
glActiveTexture(GL_TEXTURE0);
// Update existing texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, color.AsArray());
state.texture_units[0].texture_2d = 0;
state.Apply();
// Resize the texture in case the framebuffer size has changed
texture.width = 1;
texture.height = 1;
}
/**
* Initializes the OpenGL state and creates persistent objects.
*/
@ -429,13 +425,20 @@ void RendererOpenGL::ReloadShader() {
}
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
const Pica::FramebufferConfig& framebuffer) {
const Pica::FramebufferConfig& framebuffer,
const Pica::ColorFill& color_fill) {
Pica::PixelFormat format = framebuffer.color_format;
GLint internal_format{};
u32 width, height;
texture.format = format;
texture.width = framebuffer.width;
texture.height = framebuffer.height;
width = texture.width = framebuffer.width;
height = texture.height = framebuffer.height;
if (color_fill.is_enabled) {
width = 1;
height = 1;
format = Pica::PixelFormat::RGB8;
}
switch (format) {
case Pica::PixelFormat::RGBA8:
@ -482,8 +485,8 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
state.Apply();
glActiveTexture(GL_TEXTURE0);
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
texture.gl_format, texture.gl_type, nullptr);
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, texture.gl_format,
texture.gl_type, nullptr);
state.texture_units[0].texture_2d = 0;
state.Apply();

View File

@ -62,7 +62,8 @@ private:
void RenderToMailbox(const Layout::FramebufferLayout& layout,
std::unique_ptr<Frontend::TextureMailbox>& mailbox, bool flipped);
void ConfigureFramebufferTexture(TextureInfo& texture,
const Pica::FramebufferConfig& framebuffer);
const Pica::FramebufferConfig& framebuffer,
const Pica::ColorFill& color_fill);
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
void ApplySecondLayerOpacity(bool isPortrait = false);
void ResetSecondLayerOpacity(bool isPortrait = false);
@ -78,8 +79,7 @@ private:
// Loads framebuffer from emulated memory into the display information structure
void LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer, ScreenInfo& screen_info,
bool right_eye);
void FillScreen(Common::Vec3<u8> color, TextureInfo& texture);
bool right_eye, const Pica::ColorFill& color_fill);
private:
Pica::PicaCore& pica;

View File

@ -30,13 +30,11 @@ void RendererSoftware::PrepareRenderTarget() {
const u32 fb_id = i == 2 ? 1 : 0;
const auto color_fill = fb_id == 0 ? regs_lcd.color_fill_top : regs_lcd.color_fill_bottom;
if (!color_fill.is_enabled) {
LoadFBToScreenInfo(i);
}
LoadFBToScreenInfo(i, color_fill);
}
}
void RendererSoftware::LoadFBToScreenInfo(int i) {
void RendererSoftware::LoadFBToScreenInfo(int i, const Pica::ColorFill& color_fill) {
const u32 fb_id = i == 2 ? 1 : 0;
const auto& framebuffer = pica.regs.framebuffer_config[fb_id];
auto& info = screen_infos[i];
@ -54,7 +52,12 @@ void RendererSoftware::LoadFBToScreenInfo(int i) {
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 = [&] {
Common::Vec4 color = [&] {
if (color_fill.is_enabled) {
return Common::Vec4<u8>(color_fill.color_r, color_fill.color_g,
color_fill.color_b, 255);
}
switch (framebuffer.color_format) {
case Pica::PixelFormat::RGBA8:
return Common::Color::DecodeRGBA8(pixel);

View File

@ -38,7 +38,7 @@ public:
private:
void PrepareRenderTarget();
void LoadFBToScreenInfo(int i);
void LoadFBToScreenInfo(int i, const Pica::ColorFill& color_fill);
private:
Memory::MemorySystem& memory;

View File

@ -455,7 +455,6 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
}
void RendererVulkan::FillScreen(Common::Vec3<u8> color, const TextureInfo& texture) {
return;
const vk::ClearColorValue clear_color = {
.float32 =
std::array{