mirror of
https://github.com/hyprwm/hyprlock.git
synced 2025-12-20 00:40:03 +01:00
background: fix mismatched asset sizes and transforms (#830)
This commit is contained in:
parent
d993bdc105
commit
1e5e62d6e3
2 changed files with 125 additions and 84 deletions
|
|
@ -16,6 +16,7 @@
|
||||||
CBackground::CBackground() {
|
CBackground::CBackground() {
|
||||||
blurredFB = makeUnique<CFramebuffer>();
|
blurredFB = makeUnique<CFramebuffer>();
|
||||||
pendingBlurredFB = makeUnique<CFramebuffer>();
|
pendingBlurredFB = makeUnique<CFramebuffer>();
|
||||||
|
transformedScFB = makeUnique<CFramebuffer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
CBackground::~CBackground() {
|
CBackground::~CBackground() {
|
||||||
|
|
@ -52,25 +53,25 @@ void CBackground::configure(const std::unordered_map<std::string, std::any>& pro
|
||||||
|
|
||||||
viewport = pOutput->getViewport();
|
viewport = pOutput->getViewport();
|
||||||
outputPort = pOutput->stringPort;
|
outputPort = pOutput->stringPort;
|
||||||
transform = isScreenshot ? wlTransformToHyprutils(invertTransform(pOutput->transform)) : HYPRUTILS_TRANSFORM_NORMAL;
|
transform = wlTransformToHyprutils(invertTransform(pOutput->transform));
|
||||||
scResourceID = CScreencopyFrame::getResourceId(pOutput);
|
scResourceID = CScreencopyFrame::getResourceId(pOutput);
|
||||||
|
|
||||||
g_pAnimationManager->createAnimation(0.f, crossFadeProgress, g_pConfigManager->m_AnimationTree.getConfig("fadeIn"));
|
g_pAnimationManager->createAnimation(0.f, crossFadeProgress, g_pConfigManager->m_AnimationTree.getConfig("fadeIn"));
|
||||||
|
|
||||||
|
// When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available.
|
||||||
|
// Dynamic ones are tricky, because a screencopy would copy hyprlock itself.
|
||||||
|
if (g_pRenderer->asyncResourceGatherer->gathered && !g_pRenderer->asyncResourceGatherer->getAssetByID(scResourceID)) {
|
||||||
|
Debug::log(LOG, "Missing screenshot for output {}", outputPort);
|
||||||
|
scResourceID = "";
|
||||||
|
}
|
||||||
|
|
||||||
if (isScreenshot) {
|
if (isScreenshot) {
|
||||||
resourceID = scResourceID;
|
resourceID = scResourceID; // Fallback to solid background:color when scResourceID==""
|
||||||
// When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available.
|
|
||||||
// Dynamic ones are tricky, because a screencopy would copy hyprlock itself.
|
|
||||||
if (g_pRenderer->asyncResourceGatherer->gathered) {
|
|
||||||
if (!g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID))
|
|
||||||
resourceID = ""; // Fallback to solid color (background:color)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_pHyprlock->getScreencopy()) {
|
if (!g_pHyprlock->getScreencopy()) {
|
||||||
Debug::log(ERR, "No screencopy support! path=screenshot won't work. Falling back to background color.");
|
Debug::log(ERR, "No screencopy support! path=screenshot won't work. Falling back to background color.");
|
||||||
resourceID = "";
|
resourceID = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!path.empty())
|
} else if (!path.empty())
|
||||||
resourceID = "background:" + path;
|
resourceID = "background:" + path;
|
||||||
|
|
||||||
|
|
@ -93,6 +94,57 @@ void CBackground::reset() {
|
||||||
pendingBlurredFB->destroyBuffer();
|
pendingBlurredFB->destroyBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBackground::updatePrimaryAsset() {
|
||||||
|
if (asset || resourceID.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID);
|
||||||
|
if (!asset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool NEEDFB = (isScreenshot || blurPasses > 0 || asset->texture.m_vSize != viewport) && (!blurredFB->isAllocated() || firstRender);
|
||||||
|
if (NEEDFB)
|
||||||
|
renderToFB(asset->texture, *blurredFB, blurPasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::updatePendingAsset() {
|
||||||
|
// For crossfading a new asset
|
||||||
|
if (!pendingAsset || blurPasses == 0 || pendingBlurredFB->isAllocated())
|
||||||
|
return;
|
||||||
|
|
||||||
|
renderToFB(pendingAsset->texture, *pendingBlurredFB, blurPasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::updateScAsset() {
|
||||||
|
if (scAsset || scResourceID.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// path=screenshot -> scAsset = asset
|
||||||
|
scAsset = (asset && isScreenshot) ? asset : g_pRenderer->asyncResourceGatherer->getAssetByID(scResourceID);
|
||||||
|
if (!scAsset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool NEEDSCTRANSFORM = transform != HYPRUTILS_TRANSFORM_NORMAL;
|
||||||
|
if (NEEDSCTRANSFORM)
|
||||||
|
renderToFB(scAsset->texture, *transformedScFB, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CTexture& CBackground::getPrimaryAssetTex() const {
|
||||||
|
// This case is only for background:path=screenshot with blurPasses=0
|
||||||
|
if (isScreenshot && blurPasses == 0 && transformedScFB->isAllocated())
|
||||||
|
return transformedScFB->m_cTex;
|
||||||
|
|
||||||
|
return (blurredFB->isAllocated()) ? blurredFB->m_cTex : asset->texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CTexture& CBackground::getPendingAssetTex() const {
|
||||||
|
return (pendingBlurredFB->isAllocated()) ? pendingBlurredFB->m_cTex : pendingAsset->texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CTexture& CBackground::getScAssetTex() const {
|
||||||
|
return (transformedScFB->isAllocated()) ? transformedScFB->m_cTex : scAsset->texture;
|
||||||
|
}
|
||||||
|
|
||||||
void CBackground::renderRect(CHyprColor color) {
|
void CBackground::renderRect(CHyprColor color) {
|
||||||
CBox monbox = {0, 0, viewport.x, viewport.y};
|
CBox monbox = {0, 0, viewport.x, viewport.y};
|
||||||
g_pRenderer->renderRect(monbox, color, 0);
|
g_pRenderer->renderRect(monbox, color, 0);
|
||||||
|
|
@ -110,17 +162,7 @@ static void onAssetCallback(AWP<CBackground> ref) {
|
||||||
PBG->startCrossFade();
|
PBG->startCrossFade();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBackground::renderBlur(const CTexture& tex, CFramebuffer& fb) {
|
static CBox getScaledBoxForTextureSize(const Vector2D& size, const Vector2D& viewport) {
|
||||||
if (firstRender)
|
|
||||||
firstRender = false;
|
|
||||||
|
|
||||||
// make it brah
|
|
||||||
Vector2D size = asset->texture.m_vSize;
|
|
||||||
if (transform % 2 == 1 && isScreenshot) {
|
|
||||||
size.x = asset->texture.m_vSize.y;
|
|
||||||
size.y = asset->texture.m_vSize.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
CBox texbox = {{}, size};
|
CBox texbox = {{}, size};
|
||||||
|
|
||||||
float scaleX = viewport.x / size.x;
|
float scaleX = viewport.x / size.x;
|
||||||
|
|
@ -135,57 +177,61 @@ void CBackground::renderBlur(const CTexture& tex, CFramebuffer& fb) {
|
||||||
texbox.x = -(texbox.w - viewport.x) / 2.f;
|
texbox.x = -(texbox.w - viewport.x) / 2.f;
|
||||||
texbox.round();
|
texbox.round();
|
||||||
|
|
||||||
|
return texbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBackground::renderToFB(const CTexture& tex, CFramebuffer& fb, int passes, bool applyTransform) {
|
||||||
|
if (firstRender)
|
||||||
|
firstRender = false;
|
||||||
|
|
||||||
|
// make it brah
|
||||||
|
Vector2D size = tex.m_vSize;
|
||||||
|
if (applyTransform && transform % 2 == 1) {
|
||||||
|
size.x = tex.m_vSize.y;
|
||||||
|
size.y = tex.m_vSize.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto TEXBOX = getScaledBoxForTextureSize(size, viewport);
|
||||||
|
|
||||||
if (!fb.isAllocated())
|
if (!fb.isAllocated())
|
||||||
fb.alloc(viewport.x, viewport.y); // TODO 10 bit
|
fb.alloc(viewport.x, viewport.y); // TODO 10 bit
|
||||||
|
|
||||||
fb.bind();
|
fb.bind();
|
||||||
|
|
||||||
g_pRenderer->renderTexture(texbox, tex, 1.0, 0, transform);
|
g_pRenderer->renderTexture(TEXBOX, tex, 1.0, 0, applyTransform ? transform : HYPRUTILS_TRANSFORM_NORMAL);
|
||||||
|
|
||||||
if (blurPasses > 0)
|
if (blurPasses > 0)
|
||||||
g_pRenderer->blurFB(fb,
|
g_pRenderer->blurFB(fb,
|
||||||
CRenderer::SBlurParams{.size = blurSize,
|
CRenderer::SBlurParams{
|
||||||
.passes = blurPasses,
|
.size = blurSize,
|
||||||
.noise = noise,
|
.passes = passes,
|
||||||
.contrast = contrast,
|
.noise = noise,
|
||||||
.brightness = brightness,
|
.contrast = contrast,
|
||||||
.vibrancy = vibrancy,
|
.brightness = brightness,
|
||||||
.vibrancy_darkness = vibrancy_darkness});
|
.vibrancy = vibrancy,
|
||||||
|
.vibrancy_darkness = vibrancy_darkness,
|
||||||
|
});
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CBox getScaledBoxForTexture(const CTexture& tex, const Vector2D& viewport) {
|
|
||||||
CBox texbox = {{}, tex.m_vSize};
|
|
||||||
|
|
||||||
Vector2D size = tex.m_vSize;
|
|
||||||
float scaleX = viewport.x / tex.m_vSize.x;
|
|
||||||
float scaleY = viewport.y / tex.m_vSize.y;
|
|
||||||
|
|
||||||
texbox.w *= std::max(scaleX, scaleY);
|
|
||||||
texbox.h *= std::max(scaleX, scaleY);
|
|
||||||
|
|
||||||
if (scaleX > scaleY)
|
|
||||||
texbox.y = -(texbox.h - viewport.y) / 2.f;
|
|
||||||
else
|
|
||||||
texbox.x = -(texbox.w - viewport.x) / 2.f;
|
|
||||||
texbox.round();
|
|
||||||
|
|
||||||
return texbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CBackground::draw(const SRenderData& data) {
|
bool CBackground::draw(const SRenderData& data) {
|
||||||
if (!asset && !resourceID.empty())
|
updatePrimaryAsset();
|
||||||
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID);
|
updatePendingAsset();
|
||||||
|
updateScAsset();
|
||||||
|
|
||||||
// path=screenshot -> scAsset = asset
|
if (asset && asset->texture.m_iType == TEXTURE_INVALID) {
|
||||||
if (!scAsset)
|
g_pRenderer->asyncResourceGatherer->unloadAsset(asset);
|
||||||
scAsset = (asset && isScreenshot) ? asset : g_pRenderer->asyncResourceGatherer->getAssetByID(scResourceID);
|
resourceID = "";
|
||||||
|
renderRect(color);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!asset || resourceID.empty()) {
|
if (!asset || resourceID.empty()) {
|
||||||
// fade in/out with a solid color
|
// fade in/out with a solid color
|
||||||
if (data.opacity < 1.0 && scAsset) {
|
if (data.opacity < 1.0 && scAsset) {
|
||||||
const auto SCTEXBOX = getScaledBoxForTexture(scAsset->texture, viewport);
|
const auto& SCTEX = getScAssetTex();
|
||||||
g_pRenderer->renderTexture(SCTEXBOX, scAsset->texture, 1, 0, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
const auto SCTEXBOX = getScaledBoxForTextureSize(SCTEX.m_vSize, viewport);
|
||||||
|
g_pRenderer->renderTexture(SCTEXBOX, SCTEX, 1, 0, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
||||||
CHyprColor col = color;
|
CHyprColor col = color;
|
||||||
col.a *= data.opacity;
|
col.a *= data.opacity;
|
||||||
renderRect(col);
|
renderRect(col);
|
||||||
|
|
@ -196,27 +242,13 @@ bool CBackground::draw(const SRenderData& data) {
|
||||||
return !asset && !resourceID.empty(); // resource not ready
|
return !asset && !resourceID.empty(); // resource not ready
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->texture.m_iType == TEXTURE_INVALID) {
|
const auto& TEX = getPrimaryAssetTex();
|
||||||
g_pRenderer->asyncResourceGatherer->unloadAsset(asset);
|
const auto TEXBOX = getScaledBoxForTextureSize(TEX.m_vSize, viewport);
|
||||||
resourceID = "";
|
if (data.opacity < 1.0 && scAsset) {
|
||||||
renderRect(color);
|
const auto& SCTEX = getScAssetTex();
|
||||||
return false;
|
g_pRenderer->renderTextureMix(TEXBOX, SCTEX, TEX, 1.0, data.opacity, 0);
|
||||||
}
|
} else if (crossFadeProgress->isBeingAnimated()) {
|
||||||
|
const auto& PENDINGTEX = getPendingAssetTex();
|
||||||
if (asset && (blurPasses > 0 || isScreenshot) && (!blurredFB->isAllocated() || firstRender))
|
|
||||||
renderBlur(asset->texture, *blurredFB);
|
|
||||||
|
|
||||||
// For crossfading a new asset
|
|
||||||
if (pendingAsset && blurPasses > 0 && !pendingBlurredFB->isAllocated())
|
|
||||||
renderBlur(pendingAsset->texture, *pendingBlurredFB);
|
|
||||||
|
|
||||||
const auto& TEX = blurredFB->isAllocated() ? blurredFB->m_cTex : asset->texture;
|
|
||||||
const auto TEXBOX = getScaledBoxForTexture(TEX, viewport);
|
|
||||||
|
|
||||||
if (data.opacity < 1.0 && scAsset)
|
|
||||||
g_pRenderer->renderTextureMix(TEXBOX, scAsset->texture, TEX, 1.0, data.opacity, 0);
|
|
||||||
else if (crossFadeProgress->isBeingAnimated()) {
|
|
||||||
const auto& PENDINGTEX = pendingBlurredFB->isAllocated() ? pendingBlurredFB->m_cTex : pendingAsset->texture;
|
|
||||||
g_pRenderer->renderTextureMix(TEXBOX, TEX, PENDINGTEX, 1.0, crossFadeProgress->value(), 0);
|
g_pRenderer->renderTextureMix(TEXBOX, TEX, PENDINGTEX, 1.0, crossFadeProgress->value(), 0);
|
||||||
} else
|
} else
|
||||||
g_pRenderer->renderTexture(TEXBOX, TEX, 1, 0, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
g_pRenderer->renderTexture(TEXBOX, TEX, 1, 0, HYPRUTILS_TRANSFORM_FLIPPED_180);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "../../core/Timer.hpp"
|
#include "../../core/Timer.hpp"
|
||||||
#include "../Framebuffer.hpp"
|
#include "../Framebuffer.hpp"
|
||||||
#include "../AsyncResourceGatherer.hpp"
|
#include "../AsyncResourceGatherer.hpp"
|
||||||
|
#include <cstdint>
|
||||||
#include <hyprutils/math/Misc.hpp>
|
#include <hyprutils/math/Misc.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
@ -22,20 +23,27 @@ class CBackground : public IWidget {
|
||||||
CBackground();
|
CBackground();
|
||||||
~CBackground();
|
~CBackground();
|
||||||
|
|
||||||
void registerSelf(const ASP<CBackground>& self);
|
void registerSelf(const ASP<CBackground>& self);
|
||||||
|
|
||||||
virtual void configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput);
|
virtual void configure(const std::unordered_map<std::string, std::any>& props, const SP<COutput>& pOutput);
|
||||||
virtual bool draw(const SRenderData& data);
|
virtual bool draw(const SRenderData& data);
|
||||||
|
|
||||||
void reset(); // Unload assets, remove timers, etc.
|
void reset(); // Unload assets, remove timers, etc.
|
||||||
|
|
||||||
void renderRect(CHyprColor color);
|
void updatePrimaryAsset();
|
||||||
|
void updatePendingAsset();
|
||||||
|
void updateScAsset();
|
||||||
|
|
||||||
void renderBlur(const CTexture& text, CFramebuffer& fb);
|
const CTexture& getPrimaryAssetTex() const;
|
||||||
|
const CTexture& getPendingAssetTex() const;
|
||||||
|
const CTexture& getScAssetTex() const;
|
||||||
|
|
||||||
void onReloadTimerUpdate();
|
void renderRect(CHyprColor color);
|
||||||
void plantReloadTimer();
|
void renderToFB(const CTexture& text, CFramebuffer& fb, int passes, bool applyTransform = false);
|
||||||
void startCrossFade();
|
|
||||||
|
void onReloadTimerUpdate();
|
||||||
|
void plantReloadTimer();
|
||||||
|
void startCrossFade();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AWP<CBackground> m_self;
|
AWP<CBackground> m_self;
|
||||||
|
|
@ -43,6 +51,7 @@ class CBackground : public IWidget {
|
||||||
// if needed
|
// if needed
|
||||||
UP<CFramebuffer> blurredFB;
|
UP<CFramebuffer> blurredFB;
|
||||||
UP<CFramebuffer> pendingBlurredFB;
|
UP<CFramebuffer> pendingBlurredFB;
|
||||||
|
UP<CFramebuffer> transformedScFB;
|
||||||
|
|
||||||
int blurSize = 10;
|
int blurSize = 10;
|
||||||
int blurPasses = 3;
|
int blurPasses = 3;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue