render: scale background to monitor resolution (#14250)

* render: scale background to monitor resolution

Currently the background is not scaled, e.g. 8k size image always uses
~128Mb of VRAM.
We could reduce the consumption for low-end devices and monitors with
lower resolution:
- ~8Mb for 1080p
- ~16Mb for 2k
- ~32Mb for 4k

* render: use gpu to scale bgtex and fix missing reset on size change
This commit is contained in:
davc0n 2026-05-04 17:08:27 +02:00 committed by GitHub
parent 6d4bcaf075
commit 33044c3816
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 12 deletions

View file

@ -7,12 +7,10 @@
#include "../protocols/ColorManagement.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../config/shared/monitor/MonitorRuleManager.hpp"
#include "../config/shared/workspace/WorkspaceRuleManager.hpp"
#include "../config/shared/animation/AnimationTree.hpp"
#include "../protocols/GammaControl.hpp"
#include "../devices/ITouch.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp"
#include "../protocols/DRMLease.hpp"
@ -34,7 +32,6 @@
#include "../layout/LayoutManager.hpp"
#include "../i18n/Engine.hpp"
#include "../helpers/cm/ColorManagement.hpp"
#include "sync/SyncTimeline.hpp"
#include "time/Time.hpp"
#include "../desktop/view/LayerSurface.hpp"
#include "../desktop/state/FocusState.hpp"
@ -799,9 +796,10 @@ bool CMonitor::applyMonitorRule(Config::CMonitorRule&& pMonitorRule, bool force)
}
}
const auto WAS10B = m_enabled10bit;
const auto OLDRES = m_pixelSize;
bool success = false;
const auto WAS10B = m_enabled10bit;
const auto OLDPIXELSIZE = m_pixelSize;
const auto OLDTRANSFORMEDSIZE = m_transformedSize;
bool success = false;
// Needed in case we are switching from a custom modeline to a standard mode
m_customDrmMode = {};
@ -1067,13 +1065,18 @@ bool CMonitor::applyMonitorRule(Config::CMonitorRule&& pMonitorRule, bool force)
updateMatrix();
if ((WAS10B != m_enabled10bit || OLDRES != m_pixelSize)) {
if ((WAS10B != m_enabled10bit || OLDPIXELSIZE != m_pixelSize)) {
m_resources.reset(); // TODO skip for 10bit change and fp16?
if (g_pHyprRenderer && g_pHyprRenderer->glBackend())
g_pHyprRenderer->glBackend()->destroyMonitorResources(m_self);
}
if (m_background && (OLDPIXELSIZE != m_pixelSize || OLDTRANSFORMEDSIZE != m_transformedSize)) {
Log::logger->log(Log::DEBUG, "{} reset BGTex: pixelSize {} -> {}, transformedSize {} -> {}", m_name, OLDPIXELSIZE, m_pixelSize, OLDTRANSFORMEDSIZE, m_transformedSize);
m_background.reset();
}
g_pCompositor->scheduleMonitorStateRecheck();
m_damage.setSize(m_transformedSize);

View file

@ -23,7 +23,6 @@
#include "../protocols/core/Compositor.hpp"
#include "../protocols/DRMSyncobj.hpp"
#include "../protocols/LinuxDMABUF.hpp"
#include "../helpers/sync/SyncTimeline.hpp"
#include "../errorOverlay/Overlay.hpp"
#include "../debug/Overlay.hpp"
#include "../notification/NotificationOverlay.hpp"
@ -36,7 +35,6 @@
#include "../helpers/MainLoopExecutor.hpp"
#include "../helpers/Monitor.hpp"
#include "macros.hpp"
#include "../managers/screenshare/ScreenshareManager.hpp"
#include "pass/TexPassElement.hpp"
#include "pass/ClearPassElement.hpp"
#include "pass/RectPassElement.hpp"
@ -45,7 +43,6 @@
#include "../debug/log/Logger.hpp"
#include "../protocols/ColorManagement.hpp"
#include "../protocols/types/ContentType.hpp"
#include "../helpers/MiscFunctions.hpp"
#include "AsyncResourceGatherer.hpp"
#include "ElementRenderer.hpp"
#include "Framebuffer.hpp"
@ -1237,9 +1234,58 @@ SP<ITexture> IHyprRenderer::getBackground(PHLMONITOR pMonitor) {
Log::logger->log(Log::DEBUG, "Creating a texture for BGTex");
SP<ITexture> backgroundTexture = createTexture(m_backgroundResource->m_asset.cairoSurface->cairo());
if (!backgroundTexture->ok())
if (!backgroundTexture || !backgroundTexture->ok())
return nullptr;
Log::logger->log(Log::DEBUG, "Background created for monitor {}", pMonitor->m_name);
Log::logger->log(Log::DEBUG, "BGTex created for monitor {}", pMonitor->m_name);
const int monW = (int)std::round(pMonitor->m_transformedSize.x);
const int monH = (int)std::round(pMonitor->m_transformedSize.y);
const int origW = backgroundTexture->m_size.x;
const int origH = backgroundTexture->m_size.y;
if (monW > 0 && monH > 0) {
const double scaleX = (double)monW / origW;
const double scaleY = (double)monH / origH;
const double scale = std::max(scaleX, scaleY);
// scale the background if it's larger than the monitor
if (scale < 1.0) {
auto fb = createFB("BGTex scale");
fb->alloc(monW, monH);
auto guard = bindTempFB(fb);
const auto oldProjType = m_renderData.projectionType;
const auto oldFbSize = m_renderData.fbSize;
const auto oldTransformDmg = m_renderData.transformDamage;
m_renderData.fbSize = Vector2D{monW, monH};
setProjectionType(RPT_EXPORT);
m_renderData.transformDamage = false;
setViewport(0, 0, monW, monH);
draw(CClearPassElement::SClearData{{0.F, 0.F, 0.F, 0.F}});
const double texW = origW * scale;
const double texH = origH * scale;
const double offX = (monW - texW) / 2.0;
const double offY = (monH - texH) / 2.0;
CRegion fullDamage = {0, 0, monW, monH};
draw(CTexPassElement::SRenderData{.tex = backgroundTexture, .box = CBox{offX, offY, texW, texH}, .damage = fullDamage}, fullDamage);
m_renderData.fbSize = oldFbSize;
m_renderData.transformDamage = oldTransformDmg;
setProjectionType(oldProjType);
setViewport(0, 0, (int)pMonitor->m_pixelSize.x, (int)pMonitor->m_pixelSize.y);
backgroundTexture = fb->getTexture();
Log::logger->log(Log::INFO, "BGTex scaled from {}x{} to {}x{} for monitor {}", origW, origH, monW, monH, pMonitor->m_name);
}
}
// clear the resource after we're done using it
g_pEventLoopManager->doLater([this] { m_backgroundResource.reset(); });