GPU: Fill in unused/padded area in overlays
This commit is contained in:
parent
88b43370dc
commit
6131ddbefe
|
@ -91,11 +91,6 @@ bool GPUPresenter::UpdateSettings(const GPUSettings& old_settings, Error* error)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GPUPresenter::IsDisplayPostProcessingActive() const
|
||||
{
|
||||
return (m_display_postfx && m_display_postfx->IsActive());
|
||||
}
|
||||
|
||||
bool GPUPresenter::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_smoothing, Error* error)
|
||||
{
|
||||
const GPUShaderGen shadergen(g_gpu_device->GetRenderAPI(), g_gpu_device->GetFeatures().dual_source_blend,
|
||||
|
@ -170,16 +165,19 @@ bool GPUPresenter::CompileDisplayPipelines(bool display, bool deinterlace, bool
|
|||
GL_OBJECT_NAME(m_present_copy_pipeline, "Display Rotate/Copy Pipeline");
|
||||
|
||||
// blended variants
|
||||
if (m_border_overlay_texture && m_border_overlay_alpha_blend)
|
||||
if (m_border_overlay_texture)
|
||||
{
|
||||
// destination blend the main present, not source
|
||||
plconfig.blend.enable = true;
|
||||
plconfig.blend.src_blend = GPUPipeline::BlendFunc::InvDstAlpha;
|
||||
plconfig.blend.blend_op = GPUPipeline::BlendOp::Add;
|
||||
plconfig.blend.dst_blend = GPUPipeline::BlendFunc::One;
|
||||
plconfig.blend.src_alpha_blend = GPUPipeline::BlendFunc::One;
|
||||
plconfig.blend.alpha_blend_op = GPUPipeline::BlendOp::Add;
|
||||
plconfig.blend.dst_alpha_blend = GPUPipeline::BlendFunc::Zero;
|
||||
if (m_border_overlay_alpha_blend)
|
||||
{
|
||||
// destination blend the main present, not source
|
||||
plconfig.blend.enable = true;
|
||||
plconfig.blend.src_blend = GPUPipeline::BlendFunc::InvDstAlpha;
|
||||
plconfig.blend.blend_op = GPUPipeline::BlendOp::Add;
|
||||
plconfig.blend.dst_blend = GPUPipeline::BlendFunc::One;
|
||||
plconfig.blend.src_alpha_blend = GPUPipeline::BlendFunc::One;
|
||||
plconfig.blend.alpha_blend_op = GPUPipeline::BlendOp::Add;
|
||||
plconfig.blend.dst_alpha_blend = GPUPipeline::BlendFunc::Zero;
|
||||
}
|
||||
|
||||
plconfig.fragment_shader = fso.get();
|
||||
if (!(m_display_blend_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
|
||||
|
@ -191,6 +189,18 @@ bool GPUPresenter::CompileDisplayPipelines(bool display, bool deinterlace, bool
|
|||
if (!(m_present_copy_blend_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
|
||||
return false;
|
||||
GL_OBJECT_NAME(m_present_copy_blend_pipeline, "Display Rotate/Copy Pipeline [Blended]");
|
||||
|
||||
std::unique_ptr<GPUShader> clear_fso =
|
||||
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
|
||||
shadergen.GenerateFillFragmentShader(GSVector4i::zero()), error);
|
||||
if (!clear_fso)
|
||||
return false;
|
||||
GL_OBJECT_NAME(clear_fso, "Display Clear Fragment Shader");
|
||||
|
||||
plconfig.fragment_shader = clear_fso.get();
|
||||
if (!(m_present_clear_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
|
||||
return false;
|
||||
GL_OBJECT_NAME(m_present_clear_pipeline, "Display Clear Pipeline");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,10 +393,12 @@ GPUDevice::PresentResult GPUPresenter::PresentDisplay()
|
|||
display_rect = display_rect.add32(overlay_display_rect.xyxy());
|
||||
draw_rect = draw_rect.add32(overlay_display_rect.xyxy());
|
||||
|
||||
return RenderDisplay(nullptr, overlay_rect, display_rect, draw_rect, !g_gpu_settings.gpu_show_vram);
|
||||
return RenderDisplay(nullptr, overlay_rect, overlay_display_rect, display_rect, draw_rect,
|
||||
!g_gpu_settings.gpu_show_vram);
|
||||
}
|
||||
|
||||
GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const GSVector4i overlay_rect,
|
||||
const GSVector4i overlay_display_rect,
|
||||
const GSVector4i display_rect, const GSVector4i draw_rect,
|
||||
bool postfx)
|
||||
{
|
||||
|
@ -409,7 +421,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
|
|||
GL_INS_FMT("Final target size: {}x{}", target_size.x, target_size.y);
|
||||
|
||||
// Postfx active?
|
||||
const GSVector2i postfx_size = have_overlay ? display_rect.rsize() : target_size;
|
||||
const GSVector2i postfx_size = have_overlay ? overlay_display_rect.rsize() : target_size;
|
||||
const bool really_postfx = (postfx && m_display_postfx && m_display_postfx->IsActive() && m_display_postfx &&
|
||||
m_display_postfx->CheckTargets(m_present_format, postfx_size.x, postfx_size.y));
|
||||
GL_INS(really_postfx ? "Post-processing is ENABLED" : "Post-processing is disabled");
|
||||
|
@ -436,7 +448,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
|
|||
if (really_postfx)
|
||||
{
|
||||
// Remove draw offset if we're using an overlay.
|
||||
const GSVector4i real_draw_rect = have_overlay ? draw_rect.sub32(display_rect.xyxy()) : draw_rect;
|
||||
const GSVector4i real_draw_rect = have_overlay ? draw_rect.sub32(overlay_display_rect.xyxy()) : draw_rect;
|
||||
|
||||
// Display is always drawn to the postfx input.
|
||||
GPUTexture* const postfx_input = m_display_postfx->GetInputTexture();
|
||||
|
@ -453,8 +465,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
|
|||
if (have_prerotation || have_overlay)
|
||||
{
|
||||
GPUTexture* const postfx_output = m_display_postfx->GetTextureUnusedAtEndOfChain();
|
||||
const GSVector4i real_display_rect = have_overlay ? display_rect.sub32(display_rect.xyxy()) : display_rect;
|
||||
ApplyDisplayPostProcess(postfx_output, postfx_input, real_display_rect);
|
||||
ApplyDisplayPostProcess(postfx_output, postfx_input, real_draw_rect);
|
||||
postfx_output->MakeReadyForSampling();
|
||||
|
||||
// Start draw to final buffer.
|
||||
|
@ -464,13 +475,26 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
|
|||
// If we have an overlay, draw it, and then copy the postprocessed framebuffer in.
|
||||
if (have_overlay)
|
||||
{
|
||||
DrawTextureCopy(target_size, overlay_rect, m_border_overlay_texture.get(), false, true, prerotation);
|
||||
DrawTextureCopy(target_size, draw_rect, postfx_output, m_border_overlay_alpha_blend, false, prerotation);
|
||||
GL_SCOPE_FMT("Draw overlay and postfx buffer");
|
||||
g_gpu_device->SetPipeline(m_present_copy_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);
|
||||
|
||||
g_gpu_device->SetPipeline(m_border_overlay_alpha_blend ? m_present_copy_blend_pipeline.get() :
|
||||
m_present_copy_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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ohterwise, just copy the framebuffer.
|
||||
DrawTextureCopy(target_size, draw_rect, postfx_output, false, false, prerotation);
|
||||
// Otherwise, just copy the framebuffer.
|
||||
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);
|
||||
}
|
||||
|
||||
// All done
|
||||
|
@ -490,7 +514,22 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
|
|||
return pres;
|
||||
|
||||
if (have_overlay)
|
||||
DrawTextureCopy(target_size, overlay_rect, m_border_overlay_texture.get(), false, true, prerotation);
|
||||
{
|
||||
GL_SCOPE_FMT("Draw overlay to {}", overlay_rect);
|
||||
g_gpu_device->SetPipeline(m_present_copy_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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_display_texture)
|
||||
{
|
||||
|
@ -676,7 +715,8 @@ void GPUPresenter::SendDisplayToMediaCapture(MediaCapture* cap)
|
|||
// Not cleared by RenderDisplay().
|
||||
g_gpu_device->ClearRenderTarget(target, GPUDevice::DEFAULT_CLEAR_COLOR);
|
||||
|
||||
if (RenderDisplay(target, GSVector4i::zero(), display_rect, draw_rect, postfx) != GPUDevice::PresentResult::OK ||
|
||||
if (RenderDisplay(target, GSVector4i::zero(), GSVector4i::zero(), display_rect, draw_rect, postfx) !=
|
||||
GPUDevice::PresentResult::OK ||
|
||||
!cap->DeliverVideoFrame(target)) [[unlikely]]
|
||||
{
|
||||
WARNING_LOG("Failed to render/deliver video capture frame.");
|
||||
|
@ -1003,7 +1043,7 @@ bool GPUPresenter::RenderScreenshotToBuffer(u32 width, u32 height, const GSVecto
|
|||
g_gpu_device->ClearRenderTarget(render_texture.get(), GPUDevice::DEFAULT_CLEAR_COLOR);
|
||||
|
||||
// TODO: this should use copy shader instead.
|
||||
RenderDisplay(render_texture.get(), GSVector4i::zero(), display_rect, draw_rect, postfx);
|
||||
RenderDisplay(render_texture.get(), GSVector4i::zero(), GSVector4i::zero(), display_rect, draw_rect, postfx);
|
||||
|
||||
Image image(width, height, image_format);
|
||||
|
||||
|
@ -1102,7 +1142,7 @@ bool GPUPresenter::UpdatePostProcessingSettings(bool force_reload, Error* error)
|
|||
{
|
||||
// something changed, need to recompile pipelines
|
||||
if (LoadOverlayTexture() && m_border_overlay_alpha_blend &&
|
||||
(!m_present_copy_blend_pipeline || !m_display_blend_pipeline) &&
|
||||
(!m_present_copy_blend_pipeline || !m_display_blend_pipeline || !m_present_clear_pipeline) &&
|
||||
!CompileDisplayPipelines(true, false, false, error))
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -48,8 +48,6 @@ public:
|
|||
bool Initialize(Error* error);
|
||||
|
||||
bool UpdateSettings(const GPUSettings& old_settings, Error* error);
|
||||
|
||||
bool IsDisplayPostProcessingActive() const;
|
||||
bool UpdatePostProcessingSettings(bool force_reload, Error* error);
|
||||
|
||||
void ClearDisplay();
|
||||
|
@ -106,7 +104,8 @@ private:
|
|||
bool CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_smoothing, Error* error);
|
||||
|
||||
GPUDevice::PresentResult RenderDisplay(GPUTexture* target, const GSVector4i overlay_rect,
|
||||
const GSVector4i display_rect, const GSVector4i draw_rect, bool postfx);
|
||||
const GSVector4i overlay_display_rect, const GSVector4i display_rect,
|
||||
const GSVector4i draw_rect, bool postfx);
|
||||
|
||||
void DrawDisplay(const GSVector2i target_size, const GSVector4i display_rect, bool dst_alpha_blend,
|
||||
DisplayRotation rotation, WindowInfo::PreRotation prerotation);
|
||||
|
@ -158,12 +157,13 @@ private:
|
|||
std::unique_ptr<GPUPipeline> m_present_copy_pipeline;
|
||||
|
||||
std::unique_ptr<PostProcessing::Chain> m_display_postfx;
|
||||
std::unique_ptr<GPUTexture> m_border_overlay_texture;
|
||||
|
||||
// blended variants of pipelines, used when overlays are enabled
|
||||
std::unique_ptr<GPUPipeline> m_display_blend_pipeline;
|
||||
std::unique_ptr<GPUPipeline> m_present_copy_blend_pipeline;
|
||||
std::unique_ptr<GPUPipeline> m_present_clear_pipeline;
|
||||
|
||||
std::unique_ptr<GPUTexture> m_border_overlay_texture;
|
||||
GSVector4i m_border_overlay_display_rect = GSVector4i::zero();
|
||||
|
||||
// Low-traffic variables down here.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "common/error.h"
|
||||
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QDialogButtonBox>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
|
@ -539,7 +540,8 @@ void PostProcessingOverlayConfigWidget::onOverlayNameCurrentIndexChanged(int ind
|
|||
|
||||
void PostProcessingOverlayConfigWidget::onImagePathBrowseClicked()
|
||||
{
|
||||
const QString path = QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Select Image"), QString(),
|
||||
const QString path = QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Select Image"),
|
||||
QFileInfo(m_ui.imagePath->text()).dir().path(),
|
||||
tr("All Cover Image Types (*.jpg *.jpeg *.png *.webp)"));
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
|
|
@ -845,6 +845,20 @@ std::string ShaderGen::GenerateFillFragmentShader() const
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ShaderGen::GenerateFillFragmentShader(const GSVector4i fixed_color) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
WriteHeader(ss);
|
||||
DeclareFragmentEntryPoint(ss, 0, 0);
|
||||
|
||||
ss << "{\n";
|
||||
ss << " o_col0 = float4(" << std::fixed << fixed_color.x << ", " << fixed_color.y << ", " << fixed_color.z << ", "
|
||||
<< fixed_color.w << ");\n";
|
||||
ss << "}\n";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ShaderGen::GenerateCopyFragmentShader(bool offset) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
std::string GenerateScreenQuadVertexShader(float z = 0.0f) const;
|
||||
std::string GenerateUVQuadVertexShader() const;
|
||||
std::string GenerateFillFragmentShader() const;
|
||||
std::string GenerateFillFragmentShader(const GSVector4i fixed_color) const;
|
||||
std::string GenerateCopyFragmentShader(bool offset = true) const;
|
||||
|
||||
std::string GenerateImGuiVertexShader() const;
|
||||
|
|
Loading…
Reference in New Issue