diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9d5779fdb..b2e94a312 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -796,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 = {}; @@ -1064,17 +1065,16 @@ 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); + } - // The background is pre-scaled to each monitor's resolution, so it must be reset whenever the pixel size changes - if (OLDRES != m_pixelSize) { - Log::logger->log(Log::DEBUG, "Pixel size changed from {} to {}, reset background for monitor {}", OLDRES, m_pixelSize, m_name); - m_background.reset(); - } + 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(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index e2a47e9c8..3910c5426 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1233,47 +1233,60 @@ SP IHyprRenderer::getBackground(PHLMONITOR pMonitor) { return nullptr; Log::logger->log(Log::DEBUG, "Creating a texture for BGTex"); + SP backgroundTexture = createTexture(m_backgroundResource->m_asset.cairoSurface->cairo()); - cairo_surface_t* cairoSurface = m_backgroundResource->m_asset.cairoSurface->cairo(); - cairo_surface_t* scaledSurface = nullptr; + if (!backgroundTexture || !backgroundTexture->ok()) + return nullptr; - // If the background is larger than the monitor, scale it down - if (pMonitor->m_transformedSize.x > 0 && pMonitor->m_transformedSize.y > 0) { - const int origW = cairo_image_surface_get_width(cairoSurface); - const int origH = cairo_image_surface_get_height(cairoSurface); - const int monW = (int)std::round(pMonitor->m_transformedSize.x); - const int monH = (int)std::round(pMonitor->m_transformedSize.y); + 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) { - // Center-crop: compute offset in original-image coordinates - const double srcX = (origW - (monW / scale)) / 2.0; - const double srcY = (origH - (monH / scale)) / 2.0; + auto fb = createFB("BGTex scale"); + fb->alloc(monW, monH); - scaledSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, monW, monH); - cairo_t* cr = cairo_create(scaledSurface); - cairo_scale(cr, scale, scale); - cairo_set_source_surface(cr, cairoSurface, -srcX, -srcY); - cairo_paint(cr); - cairo_destroy(cr); - cairo_surface_flush(scaledSurface); + auto guard = bindTempFB(fb); - cairoSurface = scaledSurface; - Log::logger->log(Log::INFO, "Background scaled from {}x{} to {}x{} for monitor {}", origW, origH, monW, monH, pMonitor->m_name); + 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); } } - SP backgroundTexture = createTexture(cairoSurface); - - if (scaledSurface) - cairo_surface_destroy(scaledSurface); - - if (!backgroundTexture->ok()) - return nullptr; - Log::logger->log(Log::DEBUG, "Background created for monitor {}", pMonitor->m_name); - // clear the resource after we're done using it g_pEventLoopManager->doLater([this] { m_backgroundResource.reset(); });