From 9fdeeb3fb61cf02c39b4dce6fe05a5600cd08d2a Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 19 Jan 2025 16:37:51 +1000 Subject: [PATCH] GPU: Add alpha blending support to overlay --- data/resources/overlays/psx.yml | 1 + src/core/fullscreen_ui.cpp | 9 +- src/core/gpu_presenter.cpp | 112 +++++++++--------- src/core/gpu_presenter.h | 6 +- .../postprocessingoverlayconfigwidget.ui | 55 +++++++-- .../postprocessingsettingswidget.cpp | 56 ++++++++- .../postprocessingsettingswidget.h | 3 +- src/util/shadergen.cpp | 2 +- src/util/shadergen.h | 2 +- 9 files changed, 172 insertions(+), 74 deletions(-) diff --git a/data/resources/overlays/psx.yml b/data/resources/overlays/psx.yml index efd2e93ef..7c4602f6c 100644 --- a/data/resources/overlays/psx.yml +++ b/data/resources/overlays/psx.yml @@ -4,3 +4,4 @@ displayStartY: 260 displayEndX: 2850 displayEndY: 1655 alphaBlend: false +destinationAlphaBlend: false diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index 3c9052b17..b70421610 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -5771,10 +5771,15 @@ void FullscreenUI::DrawPostProcessingSettingsPage() FSUI_CSTR("Determines the area of the overlay image that the display will be drawn within."), "BorderOverlay", "DisplayStartX", 0, "DisplayStartY", 0, "DisplayEndX", 0, "DisplayEndY", 0, 0, 65535, "%dpx"); + reload_pending |= + DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BLENDER, "Alpha Blending"), + FSUI_CSTR("If enabled, the transparency of the overlay image will be applied."), + "BorderOverlay", "AlphaBlend", false); + reload_pending |= DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_BLENDER, "Destination Alpha Blending"), FSUI_CSTR("If enabled, the display will be blended with the transparency of the overlay image."), - "BorderOverlay", "AlphaBlend", false); + "BorderOverlay", "DestinationAlphaBlend", false); } } @@ -8660,6 +8665,7 @@ TRANSLATE_NOOP("FullscreenUI", "Advanced Settings"); TRANSLATE_NOOP("FullscreenUI", "All Time: {}"); TRANSLATE_NOOP("FullscreenUI", "Allow Booting Without SBI File"); TRANSLATE_NOOP("FullscreenUI", "Allows loading protected games without subchannel information."); +TRANSLATE_NOOP("FullscreenUI", "Alpha Blending"); TRANSLATE_NOOP("FullscreenUI", "Always Track Uploads"); TRANSLATE_NOOP("FullscreenUI", "An error occurred while deleting empty game settings:\n{}"); TRANSLATE_NOOP("FullscreenUI", "An error occurred while saving game settings:\n{}"); @@ -8925,6 +8931,7 @@ TRANSLATE_NOOP("FullscreenUI", "How many saves will be kept for rewinding. Highe TRANSLATE_NOOP("FullscreenUI", "How often a rewind state will be created. Higher frequencies have greater system requirements."); TRANSLATE_NOOP("FullscreenUI", "Identifies any new files added to the game directories."); TRANSLATE_NOOP("FullscreenUI", "If enabled, the display will be blended with the transparency of the overlay image."); +TRANSLATE_NOOP("FullscreenUI", "If enabled, the transparency of the overlay image will be applied."); TRANSLATE_NOOP("FullscreenUI", "If not enabled, the current post processing chain will be ignored."); TRANSLATE_NOOP("FullscreenUI", "Image Path"); TRANSLATE_NOOP("FullscreenUI", "Increases the field of view from 4:3 to the chosen display aspect ratio in 3D games."); diff --git a/src/core/gpu_presenter.cpp b/src/core/gpu_presenter.cpp index 91f7be71d..e814a0e2e 100644 --- a/src/core/gpu_presenter.cpp +++ b/src/core/gpu_presenter.cpp @@ -153,66 +153,69 @@ bool GPUPresenter::CompileDisplayPipelines(bool display, bool deinterlace, bool GL_OBJECT_NAME_FMT(m_display_pipeline, "Display Pipeline [{}]", Settings::GetDisplayScalingName(g_gpu_settings.display_scaling)); - std::unique_ptr rotate_copy_fso = g_gpu_device->CreateShader( + std::unique_ptr copy_fso = g_gpu_device->CreateShader( GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateCopyFragmentShader(false), error); - if (!rotate_copy_fso) + if (!copy_fso) return false; - GL_OBJECT_NAME(rotate_copy_fso, "Display Rotate/Copy Fragment Shader"); + GL_OBJECT_NAME(copy_fso, "Display Copy Fragment Shader"); - plconfig.fragment_shader = rotate_copy_fso.get(); + plconfig.fragment_shader = copy_fso.get(); if (!(m_present_copy_pipeline = g_gpu_device->CreatePipeline(plconfig, error))) return false; - GL_OBJECT_NAME(m_present_copy_pipeline, "Display Rotate/Copy Pipeline"); + GL_OBJECT_NAME(m_present_copy_pipeline, "Display Copy Pipeline"); // blended variants if (m_border_overlay_texture) { - std::unique_ptr clear_fso = - g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(), - shadergen.GenerateFillFragmentShader(GSVector4i::zero()), error); + std::unique_ptr clear_fso = g_gpu_device->CreateShader( + GPUShaderStage::Fragment, shadergen.GetLanguage(), + shadergen.GenerateFillFragmentShader(GSVector4::cxpr(0.0f, 0.0f, 0.0f, 1.0f)), 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))) + plconfig.fragment_shader = copy_fso.get(); + plconfig.blend = m_border_overlay_alpha_blend ? GPUPipeline::BlendState::GetAlphaBlendingState() : + GPUPipeline::BlendState::GetNoBlendingState(); + if (!(m_border_overlay_pipeline = g_gpu_device->CreatePipeline(plconfig, error))) return false; - GL_OBJECT_NAME(m_present_clear_pipeline, "Display Clear Pipeline"); + GL_OBJECT_NAME(m_border_overlay_pipeline, "Border Overlay Pipeline"); - if (m_border_overlay_alpha_blend) + plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState(); + if (m_border_overlay_destination_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.src_alpha_blend = GPUPipeline::BlendFunc::Zero; 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))) - return false; - GL_OBJECT_NAME_FMT(m_display_blend_pipeline, "Display Pipeline [Blended, {}]", - Settings::GetDisplayScalingName(g_gpu_settings.display_scaling)); - - plconfig.fragment_shader = rotate_copy_fso.get(); - 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]"); - - plconfig.fragment_shader = clear_fso.get(); - if (!(m_present_clear_blend_pipeline = g_gpu_device->CreatePipeline(plconfig, error))) - return false; - GL_OBJECT_NAME(m_present_clear_blend_pipeline, "Display Clear Pipeline [Blended]"); + plconfig.blend.dst_alpha_blend = GPUPipeline::BlendFunc::One; } + + 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"); + + plconfig.fragment_shader = fso.get(); + if (!(m_display_blend_pipeline = g_gpu_device->CreatePipeline(plconfig, error))) + return false; + GL_OBJECT_NAME_FMT(m_display_blend_pipeline, "Display Pipeline [Blended, {}]", + Settings::GetDisplayScalingName(g_gpu_settings.display_scaling)); + + plconfig.fragment_shader = copy_fso.get(); + if (!(m_present_copy_blend_pipeline = g_gpu_device->CreatePipeline(plconfig, error))) + return false; + GL_OBJECT_NAME(m_present_copy_blend_pipeline, "Display Copy Pipeline [Blended]"); } else { + m_border_overlay_pipeline.reset(); m_present_clear_pipeline.reset(); m_display_blend_pipeline.reset(); m_present_copy_blend_pipeline.reset(); - m_present_clear_blend_pipeline.reset(); } } @@ -483,13 +486,12 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G if (have_overlay) { GL_SCOPE_FMT("Draw overlay and postfx buffer"); - g_gpu_device->SetPipeline(m_present_copy_pipeline.get()); + 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); - g_gpu_device->SetPipeline(m_border_overlay_alpha_blend ? m_present_copy_blend_pipeline.get() : - m_present_copy_pipeline.get()); + 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); @@ -523,7 +525,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G if (have_overlay) { GL_SCOPE_FMT("Draw overlay to {}", overlay_rect); - g_gpu_device->SetPipeline(m_present_copy_pipeline.get()); + 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, @@ -533,15 +535,14 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G { // 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_border_overlay_alpha_blend ? m_present_clear_blend_pipeline.get() : - m_present_clear_pipeline.get()); + 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) { - DrawDisplay(target_size, display_rect, m_border_overlay_alpha_blend, g_gpu_settings.display_rotation, + DrawDisplay(target_size, display_rect, m_border_overlay_destination_alpha_blend, g_gpu_settings.display_rotation, prerotation); } @@ -1127,14 +1128,9 @@ bool GPUPresenter::UpdatePostProcessingSettings(bool force_reload, Error* error) if (LoadOverlaySettings()) { // something changed, need to recompile pipelines, the needed pipelines are based on alpha blend - if (LoadOverlayTexture() && - ((m_border_overlay_alpha_blend && - (!m_present_copy_blend_pipeline || !m_display_blend_pipeline || !m_present_clear_blend_pipeline)) || - !m_present_clear_pipeline) && - !CompileDisplayPipelines(true, false, false, error)) - { + LoadOverlayTexture(); + if (!CompileDisplayPipelines(true, false, false, error)) return false; - } } // Update postfx settings @@ -1245,6 +1241,7 @@ bool GPUPresenter::LoadOverlaySettings() std::string image_path; GSVector4i display_rect = m_border_overlay_display_rect; bool alpha_blend = m_border_overlay_alpha_blend; + bool destination_alpha_blend = m_border_overlay_destination_alpha_blend; if (preset_name == "Custom") { image_path = Host::GetStringSettingValue("BorderOverlay", "ImagePath"); @@ -1253,6 +1250,7 @@ bool GPUPresenter::LoadOverlaySettings() Host::GetIntSettingValue("BorderOverlay", "DisplayEndX", 0), Host::GetIntSettingValue("BorderOverlay", "DisplayEndY", 0)); alpha_blend = Host::GetBoolSettingValue("BorderOverlay", "AlphaBlend", false); + destination_alpha_blend = Host::GetBoolSettingValue("BorderOverlay", "DestinationAlphaBlend", false); } // check rect validity.. ignore everything if it's bogus @@ -1281,15 +1279,16 @@ bool GPUPresenter::LoadOverlaySettings() m_border_overlay_display_rect = display_rect; // but images and alphablend require pipeline/texture changes - if (m_border_overlay_image_path == image_path && (image_path.empty() || alpha_blend == m_border_overlay_alpha_blend)) - { - m_border_overlay_alpha_blend = alpha_blend; - return false; - } + const bool image_changed = (m_border_overlay_image_path != image_path); + const bool changed = + (image_changed || (!image_path.empty() && (alpha_blend == m_border_overlay_alpha_blend || + destination_alpha_blend == m_border_overlay_destination_alpha_blend))); + if (image_changed) + m_border_overlay_image_path = std::move(image_path); - m_border_overlay_image_path = std::move(image_path); m_border_overlay_alpha_blend = alpha_blend; - return true; + m_border_overlay_destination_alpha_blend = destination_alpha_blend; + return changed; } bool GPUPresenter::LoadOverlayTexture() @@ -1371,13 +1370,15 @@ bool GPUPresenter::LoadOverlayPreset(Error* error, Image* image) std::string_view image_filename; GSVector4i display_area = GSVector4i::zero(); - bool display_alpha_blend = false; + bool alpha_blend = false; + bool destination_alpha_blend = false; if (!GetStringFromObject(root, "image", &image_filename) || !GetUIntFromObject(root, "displayStartX", &display_area.x) || !GetUIntFromObject(root, "displayStartY", &display_area.y) || !GetUIntFromObject(root, "displayEndX", &display_area.z) || !GetUIntFromObject(root, "displayEndY", &display_area.w) || - !GetUIntFromObject(root, "alphaBlend", &display_alpha_blend)) + !GetUIntFromObject(root, "alphaBlend", &alpha_blend) || + !GetUIntFromObject(root, "destinationAlphaBlend", &destination_alpha_blend)) { Error::SetStringView(error, "One or more parameters is missing."); return false; @@ -1389,6 +1390,7 @@ bool GPUPresenter::LoadOverlayPreset(Error* error, Image* image) return false; m_border_overlay_display_rect = display_area; - m_border_overlay_alpha_blend = display_alpha_blend; + m_border_overlay_alpha_blend = alpha_blend; + m_border_overlay_destination_alpha_blend = destination_alpha_blend; return true; } diff --git a/src/core/gpu_presenter.h b/src/core/gpu_presenter.h index ee4909780..be1ff2263 100644 --- a/src/core/gpu_presenter.h +++ b/src/core/gpu_presenter.h @@ -147,17 +147,17 @@ private: u32 m_skipped_present_count = 0; GPUTexture::Format m_present_format = GPUTexture::Format::Unknown; bool m_border_overlay_alpha_blend = false; + bool m_border_overlay_destination_alpha_blend = false; std::unique_ptr m_present_copy_pipeline; std::unique_ptr m_display_postfx; std::unique_ptr m_border_overlay_texture; - std::unique_ptr m_present_clear_pipeline; - // blended variants of pipelines, used when overlays are enabled + std::unique_ptr m_border_overlay_pipeline; + std::unique_ptr m_present_clear_pipeline; std::unique_ptr m_display_blend_pipeline; std::unique_ptr m_present_copy_blend_pipeline; - std::unique_ptr m_present_clear_blend_pipeline; GSVector4i m_border_overlay_display_rect = GSVector4i::zero(); diff --git a/src/duckstation-qt/postprocessingoverlayconfigwidget.ui b/src/duckstation-qt/postprocessingoverlayconfigwidget.ui index f84fd65b0..1e84aed87 100644 --- a/src/duckstation-qt/postprocessingoverlayconfigwidget.ui +++ b/src/duckstation-qt/postprocessingoverlayconfigwidget.ui @@ -7,7 +7,7 @@ 0 0 540 - 355 + 381 @@ -115,10 +115,10 @@ - - + + - Destination Alpha Blending + Display End: @@ -160,12 +160,47 @@ - - - - Display End: - - + + + + + + Destination Alpha Blending + + + + + + + Alpha Blending + + + + + + + + + Qt::Orientation::Horizontal + + + + 1 + 1 + + + + + + + + Export + + + + + + diff --git a/src/duckstation-qt/postprocessingsettingswidget.cpp b/src/duckstation-qt/postprocessingsettingswidget.cpp index db363fd41..80ca8098c 100644 --- a/src/duckstation-qt/postprocessingsettingswidget.cpp +++ b/src/duckstation-qt/postprocessingsettingswidget.cpp @@ -511,6 +511,8 @@ PostProcessingOverlayConfigWidget::PostProcessingOverlayConfigWidget(SettingsWin SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.displayEndX, "BorderOverlay", "DisplayEndX", 0); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.displayEndY, "BorderOverlay", "DisplayEndY", 0); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.alphaBlend, "BorderOverlay", "AlphaBlend", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.destinationAlphaBlend, "BorderOverlay", + "DestinationAlphaBlend", false); connect(m_ui.overlayName, &QComboBox::currentIndexChanged, this, &PostProcessingOverlayConfigWidget::onOverlayNameCurrentIndexChanged); @@ -525,12 +527,36 @@ PostProcessingOverlayConfigWidget::PostProcessingOverlayConfigWidget(SettingsWin connect(m_ui.displayEndY, &QSpinBox::textChanged, this, &PostProcessingOverlayConfigWidget::triggerSettingsReload); connect(m_ui.alphaBlend, &QCheckBox::checkStateChanged, this, &PostProcessingOverlayConfigWidget::triggerSettingsReload); + connect(m_ui.destinationAlphaBlend, &QCheckBox::checkStateChanged, this, + &PostProcessingOverlayConfigWidget::triggerSettingsReload); onOverlayNameCurrentIndexChanged(m_ui.overlayName->currentIndex()); + + dialog->registerWidgetHelp(m_ui.imagePath, tr("Image Path"), tr("Unspecified"), + tr("Defines the path of the custom overlay image that will be loaded.")); + const QString display_rect_title = tr("Display Rectangle"); + const QString display_rect_rec_value = tr("Unspecified"); + const QString display_rect_help = tr("Defines the area in the overlay image that the game image will be drawn into."); + dialog->registerWidgetHelp(m_ui.displayStartX, display_rect_title, display_rect_rec_value, display_rect_help); + dialog->registerWidgetHelp(m_ui.displayStartY, display_rect_title, display_rect_rec_value, display_rect_help); + dialog->registerWidgetHelp(m_ui.displayEndX, display_rect_title, display_rect_rec_value, display_rect_help); + dialog->registerWidgetHelp(m_ui.displayEndY, display_rect_title, display_rect_rec_value, display_rect_help); + dialog->registerWidgetHelp( + m_ui.alphaBlend, tr("Alpha Blending"), tr("Unchecked"), + tr("If checked, the overlay image will be alpha blended with the framebuffer, i.e. transparency will be applied.")); + dialog->registerWidgetHelp( + m_ui.destinationAlphaBlend, tr("Destination Alpha Blending"), tr("Unchecked"), + tr("If checked, the game image will be blended with the inverse amount of alpha in the overlay image. For example, " + "an image with alpha of 0.75 will draw the game image at 25% brightness.")); } PostProcessingOverlayConfigWidget::~PostProcessingOverlayConfigWidget() = default; +void PostProcessingOverlayConfigWidget::triggerSettingsReload() +{ + g_emu_thread->updatePostProcessingSettings(true, false, false); +} + void PostProcessingOverlayConfigWidget::onOverlayNameCurrentIndexChanged(int index) { const int custom_idx = m_dialog->isPerGameSettings() ? 2 : 1; @@ -549,7 +575,33 @@ void PostProcessingOverlayConfigWidget::onImagePathBrowseClicked() m_ui.imagePath->setText(QDir::toNativeSeparators(path)); } -void PostProcessingOverlayConfigWidget::triggerSettingsReload() +void PostProcessingOverlayConfigWidget::onExportCustomConfigClicked() { - g_emu_thread->updatePostProcessingSettings(true, false, false); + const QString path = + QFileDialog::getSaveFileName(QtUtils::GetRootWidget(this), tr("Export to YAML"), + QFileInfo(m_ui.imagePath->text()).dir().path(), tr("YAML Files (*.yml)")); + if (path.isEmpty()) + return; + + const QString output = QStringLiteral("imagePath: \"%1\"\n" + "displayStartX: %2\n" + "displayStartY: %3\n" + "displayEndX: %4\n" + "displayEndY: %5\n" + "alphaBlend: %6\n" + "destinationAlphaBlend: %7\n") + .arg(QFileInfo(m_ui.imagePath->text()).fileName(), m_ui.displayStartX->value()) + .arg(m_ui.displayStartY->value()) + .arg(m_ui.displayEndX->value()) + .arg(m_ui.displayEndY->value()) + .arg(m_ui.alphaBlend->isChecked() ? "true" : "false") + .arg(m_ui.destinationAlphaBlend->isChecked() ? "true" : "false"); + + Error error; + if (!FileSystem::WriteStringToFile(QDir::toNativeSeparators(path).toStdString().c_str(), output.toStdString(), + &error)) + { + QMessageBox::critical(this, tr("Export Error"), + tr("Failed to save file: %1").arg(QString::fromStdString(error.GetDescription()))); + } } diff --git a/src/duckstation-qt/postprocessingsettingswidget.h b/src/duckstation-qt/postprocessingsettingswidget.h index c697c16c9..6c2108b28 100644 --- a/src/duckstation-qt/postprocessingsettingswidget.h +++ b/src/duckstation-qt/postprocessingsettingswidget.h @@ -98,9 +98,10 @@ public: ~PostProcessingOverlayConfigWidget(); private Q_SLOTS: + void triggerSettingsReload(); void onOverlayNameCurrentIndexChanged(int index); void onImagePathBrowseClicked(); - void triggerSettingsReload(); + void onExportCustomConfigClicked(); private: Ui::PostProcessingOverlayConfigWidget m_ui; diff --git a/src/util/shadergen.cpp b/src/util/shadergen.cpp index 101d65337..977e2a2b8 100644 --- a/src/util/shadergen.cpp +++ b/src/util/shadergen.cpp @@ -845,7 +845,7 @@ std::string ShaderGen::GenerateFillFragmentShader() const return ss.str(); } -std::string ShaderGen::GenerateFillFragmentShader(const GSVector4i fixed_color) const +std::string ShaderGen::GenerateFillFragmentShader(const GSVector4 fixed_color) const { std::stringstream ss; WriteHeader(ss); diff --git a/src/util/shadergen.h b/src/util/shadergen.h index 79b88de03..478cf530e 100644 --- a/src/util/shadergen.h +++ b/src/util/shadergen.h @@ -30,7 +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 GenerateFillFragmentShader(const GSVector4 fixed_color) const; std::string GenerateCopyFragmentShader(bool offset = true) const; std::string GenerateImGuiVertexShader() const;