GPU: Fix overlay+postprocessing combination

This commit is contained in:
Stenzek 2025-01-19 16:45:10 +10:00
parent 9fdeeb3fb6
commit ade8bf7b3b
No known key found for this signature in database
2 changed files with 37 additions and 24 deletions

View File

@ -393,6 +393,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
GPUSwapChain* const swap_chain = g_gpu_device->GetMainSwapChain();
const WindowInfo::PreRotation prerotation = target ? WindowInfo::PreRotation::Identity : swap_chain->GetPreRotation();
const GSVector2i final_target_size = target ? target->GetSizeVec() : swap_chain->GetPostRotatedSizeVec();
const bool is_vram_view = g_gpu_settings.gpu_show_vram;
const bool have_overlay = (postfx && !is_vram_view && HasBorderOverlay());
const bool have_prerotation = (prerotation != WindowInfo::PreRotation::Identity);
@ -438,7 +439,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
GL_INS_FMT("Post-processing render target size: {}x{}", postfx_size.x, postfx_size.y);
// Helper to bind swap chain/final target.
const auto bind_final_target = [target, swap_chain](bool clear) {
const auto bind_final_target = [&target, &swap_chain, &final_target_size](bool clear) {
if (target)
{
if (clear)
@ -446,12 +447,16 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
else
g_gpu_device->InvalidateRenderTarget(target);
g_gpu_device->SetRenderTarget(target);
return GPUDevice::PresentResult::OK;
}
else
{
return g_gpu_device->BeginPresent(swap_chain);
const GPUDevice::PresentResult res = g_gpu_device->BeginPresent(swap_chain);
if (res != GPUDevice::PresentResult::OK)
return res;
}
g_gpu_device->SetViewport(GSVector4i::loadh(final_target_size));
return GPUDevice::PresentResult::OK;
};
// If postfx is enabled, we need to draw to an intermediate buffer first.
@ -464,9 +469,10 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
GPUTexture* const postfx_input = m_display_postfx->GetInputTexture();
g_gpu_device->ClearRenderTarget(postfx_input, GPUDevice::DEFAULT_CLEAR_COLOR);
g_gpu_device->SetRenderTarget(postfx_input);
g_gpu_device->SetViewport(GSVector4i::loadh(postfx_size));
if (m_display_texture)
{
DrawDisplay(postfx_size, real_draw_rect, false, g_gpu_settings.display_rotation,
DrawDisplay(postfx_size, postfx_size, real_draw_rect, false, g_gpu_settings.display_rotation,
WindowInfo::PreRotation::Identity);
}
postfx_input->MakeReadyForSampling();
@ -482,19 +488,23 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
if (const GPUDevice::PresentResult pres = bind_final_target(have_overlay); pres != GPUDevice::PresentResult::OK)
return pres;
// UVs of post-processed/prerotated output are flipped in OpenGL.
const GSVector4 src_uv_rect = g_gpu_device->UsesLowerLeftOrigin() ? GSVector4::cxpr(0.0f, 1.0f, 1.0f, 0.0f) :
GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f);
// If we have an overlay, draw it, and then copy the postprocessed framebuffer in.
if (have_overlay)
{
GL_SCOPE_FMT("Draw overlay and postfx buffer");
g_gpu_device->SetPipeline(m_border_overlay_pipeline.get());
g_gpu_device->SetTextureSampler(0, m_border_overlay_texture.get(), g_gpu_device->GetLinearSampler());
DrawScreenQuad(overlay_rect, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), target_size, DisplayRotation::Normal,
prerotation);
DrawScreenQuad(overlay_rect, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), target_size, final_target_size,
DisplayRotation::Normal, prerotation);
g_gpu_device->SetPipeline(m_border_overlay_pipeline.get());
g_gpu_device->SetTextureSampler(0, postfx_output, g_gpu_device->GetNearestSampler());
DrawScreenQuad(overlay_display_rect, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), target_size,
DisplayRotation::Normal, prerotation);
DrawScreenQuad(overlay_display_rect, src_uv_rect, target_size, final_target_size, DisplayRotation::Normal,
prerotation);
}
else
{
@ -502,8 +512,8 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
GL_SCOPE_FMT("Copy framebuffer for prerotation");
g_gpu_device->SetPipeline(m_present_copy_pipeline.get());
g_gpu_device->SetTextureSampler(0, postfx_output, g_gpu_device->GetNearestSampler());
DrawScreenQuad(draw_rect, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), target_size, DisplayRotation::Normal,
prerotation);
DrawScreenQuad(GSVector4i::loadh(postfx_size), src_uv_rect, target_size, final_target_size,
DisplayRotation::Normal, prerotation);
}
// All done
@ -528,21 +538,23 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
g_gpu_device->SetPipeline(m_border_overlay_pipeline.get());
g_gpu_device->SetTextureSampler(0, m_border_overlay_texture.get(), g_gpu_device->GetLinearSampler());
DrawScreenQuad(overlay_rect, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), target_size, DisplayRotation::Normal,
prerotation);
DrawScreenQuad(overlay_rect, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), target_size, final_target_size,
DisplayRotation::Normal, prerotation);
if (!overlay_display_rect.eq(draw_rect))
{
// Need to fill in the borders.
GL_SCOPE_FMT("Fill in overlay borders - odisplay={}, draw={}", overlay_display_rect, draw_rect);
g_gpu_device->SetPipeline(m_present_clear_pipeline.get());
DrawScreenQuad(overlay_display_rect, GSVector4::zero(), target_size, g_settings.display_rotation, prerotation);
DrawScreenQuad(overlay_display_rect, GSVector4::zero(), target_size, final_target_size,
g_settings.display_rotation, prerotation);
}
}
if (m_display_texture)
{
DrawDisplay(target_size, display_rect, m_border_overlay_destination_alpha_blend, g_gpu_settings.display_rotation,
DrawDisplay(target_size, final_target_size, display_rect,
have_overlay && m_border_overlay_destination_alpha_blend, g_gpu_settings.display_rotation,
prerotation);
}
@ -550,8 +562,9 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
}
}
void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector4i display_rect, bool dst_alpha_blend,
DisplayRotation rotation, WindowInfo::PreRotation prerotation)
void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector2i final_target_size,
const GSVector4i display_rect, bool dst_alpha_blend, DisplayRotation rotation,
WindowInfo::PreRotation prerotation)
{
bool texture_filter_linear = false;
@ -614,14 +627,14 @@ void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector4i di
GSVector4::xyxy(display_texture_size, GSVector2::cxpr(1.0f) / display_texture_size));
g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms));
DrawScreenQuad(display_rect, uv_rect, target_size, rotation, prerotation);
DrawScreenQuad(display_rect, uv_rect, target_size, final_target_size, rotation, prerotation);
}
void GPUPresenter::DrawScreenQuad(const GSVector4i rect, const GSVector4 uv_rect, const GSVector2i target_size,
DisplayRotation rotation, WindowInfo::PreRotation prerotation)
const GSVector2i final_target_size, DisplayRotation rotation,
WindowInfo::PreRotation prerotation)
{
const GSVector4i real_rect = GPUSwapChain::PreRotateClipRect(prerotation, target_size, rect);
g_gpu_device->SetViewport(GSVector4i::loadh(target_size));
g_gpu_device->SetScissor(g_gpu_device->UsesLowerLeftOrigin() ? GPUDevice::FlipToLowerLeft(real_rect, target_size.y) :
real_rect);
@ -631,9 +644,8 @@ void GPUPresenter::DrawScreenQuad(const GSVector4i rect, const GSVector4 uv_rect
g_gpu_device->MapVertexBuffer(sizeof(GPUBackend::ScreenVertex), 4, reinterpret_cast<void**>(&vertices), &space,
&base_vertex);
const GSVector4 xy = GPUBackend::GetScreenQuadClipSpaceCoordinates(real_rect, target_size);
// Combine display rotation and prerotation together, since the rectangle has already been adjusted.
const GSVector4 xy = GPUBackend::GetScreenQuadClipSpaceCoordinates(real_rect, final_target_size);
const DisplayRotation effective_rotation = static_cast<DisplayRotation>(
(static_cast<u32>(rotation) + static_cast<u32>(prerotation)) % static_cast<u32>(DisplayRotation::Count));
switch (effective_rotation)

View File

@ -103,12 +103,13 @@ private:
GPUDevice::PresentResult RenderDisplay(GPUTexture* target, const GSVector2i target_size, bool postfx,
bool apply_aspect_ratio);
void DrawDisplay(const GSVector2i target_size, const GSVector4i display_rect, bool dst_alpha_blend,
DisplayRotation rotation, WindowInfo::PreRotation prerotation);
void DrawDisplay(const GSVector2i target_size, const GSVector2i final_target_size, const GSVector4i display_rect,
bool dst_alpha_blend, DisplayRotation rotation, WindowInfo::PreRotation prerotation);
GPUDevice::PresentResult ApplyDisplayPostProcess(GPUTexture* target, GPUTexture* input,
const GSVector4i display_rect);
void DrawScreenQuad(const GSVector4i rect, const GSVector4 uv_rect, const GSVector2i target_size,
DisplayRotation uv_rotation, WindowInfo::PreRotation prerotation);
const GSVector2i final_target_size, DisplayRotation uv_rotation,
WindowInfo::PreRotation prerotation);
bool DeinterlaceSetTargetSize(u32 width, u32 height, bool preserve);
void DestroyDeinterlaceTextures();