renderer: move asyncResourceGatherer out of the renderer (#863)

* lockSurface: cleanup some resources

* renderer: move asyncResourceGatherer out of CRenderer

In preperation to recreate the rendering context.
This commit is contained in:
Maximilian Seidler 2025-09-03 09:32:12 +00:00 committed by GitHub
parent 8d0e56998e
commit cedbb24472
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 67 additions and 48 deletions

View file

@ -7,8 +7,20 @@
#include "../renderer/Renderer.hpp" #include "../renderer/Renderer.hpp"
CSessionLockSurface::~CSessionLockSurface() { CSessionLockSurface::~CSessionLockSurface() {
if (frameCallback)
frameCallback.reset();
if (eglSurface)
eglDestroySurface(g_pEGL->eglDisplay, eglSurface);
if (eglWindow) if (eglWindow)
wl_egl_window_destroy(eglWindow); wl_egl_window_destroy(eglWindow);
if (lockSurface)
lockSurface->sendDestroy();
if (surface)
surface->sendDestroy();
} }
CSessionLockSurface::CSessionLockSurface(const SP<COutput>& pOutput) : m_outputRef(pOutput), m_outputID(pOutput->m_ID) { CSessionLockSurface::CSessionLockSurface(const SP<COutput>& pOutput) : m_outputRef(pOutput), m_outputID(pOutput->m_ID) {

View file

@ -3,6 +3,7 @@
#include "../helpers/Log.hpp" #include "../helpers/Log.hpp"
#include "../config/ConfigManager.hpp" #include "../config/ConfigManager.hpp"
#include "../renderer/Renderer.hpp" #include "../renderer/Renderer.hpp"
#include "../renderer/AsyncResourceGatherer.hpp"
#include "../auth/Auth.hpp" #include "../auth/Auth.hpp"
#include "../auth/Fingerprint.hpp" #include "../auth/Fingerprint.hpp"
#include "Egl.hpp" #include "Egl.hpp"
@ -320,6 +321,7 @@ void CHyprlock::run() {
wl_display_roundtrip(m_sWaylandState.display); wl_display_roundtrip(m_sWaylandState.display);
g_pRenderer = makeUnique<CRenderer>(); g_pRenderer = makeUnique<CRenderer>();
g_pAsyncResourceGatherer = makeUnique<CAsyncResourceGatherer>();
g_pAuth = makeUnique<CAuth>(); g_pAuth = makeUnique<CAuth>();
g_pAuth->start(); g_pAuth->start();
@ -339,16 +341,16 @@ void CHyprlock::run() {
.events = POLLIN, .events = POLLIN,
}; };
if (g_pRenderer->asyncResourceGatherer->gatheredEventfd.isValid()) { if (g_pAsyncResourceGatherer->gatheredEventfd.isValid()) {
pollfds[1] = { pollfds[1] = {
.fd = g_pRenderer->asyncResourceGatherer->gatheredEventfd.get(), .fd = g_pAsyncResourceGatherer->gatheredEventfd.get(),
.events = POLLIN, .events = POLLIN,
}; };
fdcount++; fdcount++;
} }
while (!g_pRenderer->asyncResourceGatherer->gathered) { while (!g_pAsyncResourceGatherer->gathered) {
wl_display_flush(m_sWaylandState.display); wl_display_flush(m_sWaylandState.display);
if (wl_display_prepare_read(m_sWaylandState.display) == 0) { if (wl_display_prepare_read(m_sWaylandState.display) == 0) {
if (poll(pollfds, fdcount, /* 100ms timeout */ 100) < 0) { if (poll(pollfds, fdcount, /* 100ms timeout */ 100) < 0) {
@ -377,8 +379,6 @@ void CHyprlock::run() {
if (!acquireSessionLock()) { if (!acquireSessionLock()) {
m_sLoopState.timerEvent = true; m_sLoopState.timerEvent = true;
m_sLoopState.timerCV.notify_all(); m_sLoopState.timerCV.notify_all();
g_pRenderer->asyncResourceGatherer->notify();
g_pRenderer->asyncResourceGatherer->await();
g_pAuth->terminate(); g_pAuth->terminate();
exit(1); exit(1);
} }
@ -516,15 +516,14 @@ void CHyprlock::run() {
m_sLoopState.timerEvent = true; m_sLoopState.timerEvent = true;
m_sLoopState.timerCV.notify_all(); m_sLoopState.timerCV.notify_all();
g_pRenderer->asyncResourceGatherer->notify();
g_pRenderer->asyncResourceGatherer->await();
m_sWaylandState = {}; m_sWaylandState = {};
dma = {}; dma = {};
m_vOutputs.clear(); m_vOutputs.clear();
g_pEGL.reset();
g_pRenderer.reset();
g_pSeatManager.reset(); g_pSeatManager.reset();
g_pAsyncResourceGatherer.reset();
g_pRenderer.reset();
g_pEGL.reset();
wl_display_disconnect(DPY); wl_display_disconnect(DPY);

View file

@ -27,7 +27,15 @@ CAsyncResourceGatherer::CAsyncResourceGatherer() {
Debug::log(ERR, "Failed to create eventfd: {}", strerror(errno)); Debug::log(ERR, "Failed to create eventfd: {}", strerror(errno));
} }
CAsyncResourceGatherer::~CAsyncResourceGatherer() {
notify();
await();
}
void CAsyncResourceGatherer::enqueueScreencopyFrames() { void CAsyncResourceGatherer::enqueueScreencopyFrames() {
if (g_pHyprlock->m_vOutputs.empty())
return;
static const auto ANIMATIONSENABLED = g_pConfigManager->getValue<Hyprlang::INT>("animations:enabled"); static const auto ANIMATIONSENABLED = g_pConfigManager->getValue<Hyprlang::INT>("animations:enabled");
const auto FADEINCFG = g_pConfigManager->m_AnimationTree.getConfig("fadeIn"); const auto FADEINCFG = g_pConfigManager->m_AnimationTree.getConfig("fadeIn");

View file

@ -14,6 +14,7 @@
class CAsyncResourceGatherer { class CAsyncResourceGatherer {
public: public:
CAsyncResourceGatherer(); CAsyncResourceGatherer();
~CAsyncResourceGatherer();
std::atomic<bool> gathered = false; std::atomic<bool> gathered = false;
Hyprutils::OS::CFileDescriptor gatheredEventfd; Hyprutils::OS::CFileDescriptor gatheredEventfd;
@ -44,10 +45,11 @@ class CAsyncResourceGatherer {
void requestAsyncAssetPreload(const SPreloadRequest& request); void requestAsyncAssetPreload(const SPreloadRequest& request);
void unloadAsset(SPreloadedAsset* asset); void unloadAsset(SPreloadedAsset* asset);
private:
void notify(); void notify();
void await(); void await();
private:
std::thread asyncLoopThread; std::thread asyncLoopThread;
std::thread initialGatherThread; std::thread initialGatherThread;
@ -86,3 +88,5 @@ class CAsyncResourceGatherer {
void gather(); void gather();
void enqueueScreencopyFrames(); void enqueueScreencopyFrames();
}; };
inline UP<CAsyncResourceGatherer> g_pAsyncResourceGatherer;

View file

@ -25,7 +25,7 @@ inline const float fullVerts[] = {
0, 1, // bottom left 0, 1, // bottom left
}; };
GLuint compileShader(const GLuint& type, std::string src) { static GLuint compileShader(const GLuint& type, std::string src) {
auto shader = glCreateShader(type); auto shader = glCreateShader(type);
auto shaderSource = src.c_str(); auto shaderSource = src.c_str();
@ -41,7 +41,7 @@ GLuint compileShader(const GLuint& type, std::string src) {
return shader; return shader;
} }
GLuint createProgram(const std::string& vert, const std::string& frag) { static GLuint createProgram(const std::string& vert, const std::string& frag) {
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert); auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert);
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n{}", vert); RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n{}", vert);
@ -194,8 +194,6 @@ CRenderer::CRenderer() {
borderShader.gradientLerp = glGetUniformLocation(prog, "gradientLerp"); borderShader.gradientLerp = glGetUniformLocation(prog, "gradientLerp");
borderShader.alpha = glGetUniformLocation(prog, "alpha"); borderShader.alpha = glGetUniformLocation(prog, "alpha");
asyncResourceGatherer = makeUnique<CAsyncResourceGatherer>();
g_pAnimationManager->createAnimation(0.f, opacity, g_pConfigManager->m_AnimationTree.getConfig("fadeIn")); g_pAnimationManager->createAnimation(0.f, opacity, g_pConfigManager->m_AnimationTree.getConfig("fadeIn"));
} }
@ -217,7 +215,7 @@ CRenderer::SRenderFeedback CRenderer::renderLock(const CSessionLockSurface& surf
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
SRenderFeedback feedback; SRenderFeedback feedback;
const bool WAITFORASSETS = !g_pHyprlock->m_bImmediateRender && !asyncResourceGatherer->gathered; const bool WAITFORASSETS = !g_pHyprlock->m_bImmediateRender && !g_pAsyncResourceGatherer->gathered;
if (!WAITFORASSETS) { if (!WAITFORASSETS) {
// render widgets // render widgets
@ -227,7 +225,7 @@ CRenderer::SRenderFeedback CRenderer::renderLock(const CSessionLockSurface& surf
} }
} }
feedback.needsFrame = feedback.needsFrame || !asyncResourceGatherer->gathered; feedback.needsFrame = feedback.needsFrame || !g_pAsyncResourceGatherer->gathered;
glDisable(GL_BLEND); glDisable(GL_BLEND);

View file

@ -37,7 +37,6 @@ class CRenderer {
void renderTextureMix(const CBox& box, const CTexture& tex, const CTexture& tex2, float a = 1.0, float mixFactor = 0.0, int rounding = 0, std::optional<eTransform> tr = {}); void renderTextureMix(const CBox& box, const CTexture& tex, const CTexture& tex2, float a = 1.0, float mixFactor = 0.0, int rounding = 0, std::optional<eTransform> tr = {});
void blurFB(const CFramebuffer& outfb, SBlurParams params); void blurFB(const CFramebuffer& outfb, SBlurParams params);
UP<CAsyncResourceGatherer> asyncResourceGatherer;
std::chrono::system_clock::time_point firstFullFrameTime; std::chrono::system_clock::time_point firstFullFrameTime;
void pushFb(GLint fb); void pushFb(GLint fb);

View file

@ -10,7 +10,6 @@
#include <chrono> #include <chrono>
#include <hyprlang.hpp> #include <hyprlang.hpp>
#include <filesystem> #include <filesystem>
#include <memory>
#include <GLES3/gl32.h> #include <GLES3/gl32.h>
CBackground::CBackground() { CBackground::CBackground() {
@ -60,7 +59,7 @@ void CBackground::configure(const std::unordered_map<std::string, std::any>& pro
// When the initial gather of the asyncResourceGatherer is completed (ready), all DMAFrames are available. // 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. // Dynamic ones are tricky, because a screencopy would copy hyprlock itself.
if (g_pRenderer->asyncResourceGatherer->gathered && !g_pRenderer->asyncResourceGatherer->getAssetByID(scResourceID)) { if (g_pAsyncResourceGatherer->gathered && !g_pAsyncResourceGatherer->getAssetByID(scResourceID)) {
Debug::log(LOG, "Missing screenshot for output {}", outputPort); Debug::log(LOG, "Missing screenshot for output {}", outputPort);
scResourceID = ""; scResourceID = "";
} }
@ -98,7 +97,7 @@ void CBackground::updatePrimaryAsset() {
if (asset || resourceID.empty()) if (asset || resourceID.empty())
return; return;
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID); asset = g_pAsyncResourceGatherer->getAssetByID(resourceID);
if (!asset) if (!asset)
return; return;
@ -121,7 +120,7 @@ void CBackground::updateScAsset() {
return; return;
// path=screenshot -> scAsset = asset // path=screenshot -> scAsset = asset
scAsset = (asset && isScreenshot) ? asset : g_pRenderer->asyncResourceGatherer->getAssetByID(scResourceID); scAsset = (asset && isScreenshot) ? asset : g_pAsyncResourceGatherer->getAssetByID(scResourceID);
if (!scAsset) if (!scAsset)
return; return;
@ -221,7 +220,7 @@ bool CBackground::draw(const SRenderData& data) {
updateScAsset(); updateScAsset();
if (asset && asset->texture.m_iType == TEXTURE_INVALID) { if (asset && asset->texture.m_iType == TEXTURE_INVALID) {
g_pRenderer->asyncResourceGatherer->unloadAsset(asset); g_pAsyncResourceGatherer->unloadAsset(asset);
resourceID = ""; resourceID = "";
renderRect(color); renderRect(color);
return false; return false;
@ -307,14 +306,14 @@ void CBackground::onReloadTimerUpdate() {
request.callback = [REF = m_self]() { onAssetCallback(REF); }; request.callback = [REF = m_self]() { onAssetCallback(REF); };
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pAsyncResourceGatherer->requestAsyncAssetPreload(request);
} }
void CBackground::startCrossFade() { void CBackground::startCrossFade() {
auto newAsset = g_pRenderer->asyncResourceGatherer->getAssetByID(pendingResourceID); auto newAsset = g_pAsyncResourceGatherer->getAssetByID(pendingResourceID);
if (newAsset) { if (newAsset) {
if (newAsset->texture.m_iType == TEXTURE_INVALID) { if (newAsset->texture.m_iType == TEXTURE_INVALID) {
g_pRenderer->asyncResourceGatherer->unloadAsset(newAsset); g_pAsyncResourceGatherer->unloadAsset(newAsset);
Debug::log(ERR, "New asset had an invalid texture!"); Debug::log(ERR, "New asset had an invalid texture!");
pendingResourceID = ""; pendingResourceID = "";
} else if (resourceID != pendingResourceID) { } else if (resourceID != pendingResourceID) {
@ -327,7 +326,7 @@ void CBackground::startCrossFade() {
if (const auto PSELF = REF.lock()) { if (const auto PSELF = REF.lock()) {
PSELF->asset = PSELF->pendingAsset; PSELF->asset = PSELF->pendingAsset;
PSELF->pendingAsset = nullptr; PSELF->pendingAsset = nullptr;
g_pRenderer->asyncResourceGatherer->unloadAsset(PSELF->pendingAsset); g_pAsyncResourceGatherer->unloadAsset(PSELF->pendingAsset);
PSELF->resourceID = PSELF->pendingResourceID; PSELF->resourceID = PSELF->pendingResourceID;
PSELF->pendingResourceID = ""; PSELF->pendingResourceID = "";

View file

@ -65,7 +65,7 @@ void CImage::onTimerUpdate() {
request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE; request.type = CAsyncResourceGatherer::eTargetType::TARGET_IMAGE;
request.callback = [REF = m_self]() { onAssetCallback(REF); }; request.callback = [REF = m_self]() { onAssetCallback(REF); };
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pAsyncResourceGatherer->requestAsyncAssetPreload(request);
} }
void CImage::plantTimer() { void CImage::plantTimer() {
@ -128,7 +128,7 @@ void CImage::reset() {
imageFB.destroyBuffer(); imageFB.destroyBuffer();
if (asset && reloadTime > -1) // Don't unload asset if it's a static image if (asset && reloadTime > -1) // Don't unload asset if it's a static image
g_pRenderer->asyncResourceGatherer->unloadAsset(asset); g_pAsyncResourceGatherer->unloadAsset(asset);
asset = nullptr; asset = nullptr;
pendingResourceID = ""; pendingResourceID = "";
@ -141,13 +141,13 @@ bool CImage::draw(const SRenderData& data) {
return false; return false;
if (!asset) if (!asset)
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID); asset = g_pAsyncResourceGatherer->getAssetByID(resourceID);
if (!asset) if (!asset)
return true; return true;
if (asset->texture.m_iType == TEXTURE_INVALID) { if (asset->texture.m_iType == TEXTURE_INVALID) {
g_pRenderer->asyncResourceGatherer->unloadAsset(asset); g_pAsyncResourceGatherer->unloadAsset(asset);
resourceID = ""; resourceID = "";
return false; return false;
} }
@ -211,12 +211,12 @@ bool CImage::draw(const SRenderData& data) {
} }
void CImage::renderUpdate() { void CImage::renderUpdate() {
auto newAsset = g_pRenderer->asyncResourceGatherer->getAssetByID(pendingResourceID); auto newAsset = g_pAsyncResourceGatherer->getAssetByID(pendingResourceID);
if (newAsset) { if (newAsset) {
if (newAsset->texture.m_iType == TEXTURE_INVALID) { if (newAsset->texture.m_iType == TEXTURE_INVALID) {
g_pRenderer->asyncResourceGatherer->unloadAsset(newAsset); g_pAsyncResourceGatherer->unloadAsset(newAsset);
} else if (resourceID != pendingResourceID) { } else if (resourceID != pendingResourceID) {
g_pRenderer->asyncResourceGatherer->unloadAsset(asset); g_pAsyncResourceGatherer->unloadAsset(asset);
imageFB.destroyBuffer(); imageFB.destroyBuffer();
asset = newAsset; asset = newAsset;

View file

@ -54,7 +54,7 @@ void CLabel::onTimerUpdate() {
request.callback = [REF = m_self]() { onAssetCallback(REF); }; request.callback = [REF = m_self]() { onAssetCallback(REF); };
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pAsyncResourceGatherer->requestAsyncAssetPreload(request);
} }
void CLabel::plantTimer() { void CLabel::plantTimer() {
@ -109,7 +109,7 @@ void CLabel::configure(const std::unordered_map<std::string, std::any>& props, c
pos = configPos; // Label size not known yet pos = configPos; // Label size not known yet
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pAsyncResourceGatherer->requestAsyncAssetPreload(request);
plantTimer(); plantTimer();
} }
@ -124,7 +124,7 @@ void CLabel::reset() {
return; return;
if (asset) if (asset)
g_pRenderer->asyncResourceGatherer->unloadAsset(asset); g_pAsyncResourceGatherer->unloadAsset(asset);
asset = nullptr; asset = nullptr;
pendingResourceID.clear(); pendingResourceID.clear();
@ -133,7 +133,7 @@ void CLabel::reset() {
bool CLabel::draw(const SRenderData& data) { bool CLabel::draw(const SRenderData& data) {
if (!asset) { if (!asset) {
asset = g_pRenderer->asyncResourceGatherer->getAssetByID(resourceID); asset = g_pAsyncResourceGatherer->getAssetByID(resourceID);
if (!asset) if (!asset)
return true; return true;
@ -157,10 +157,10 @@ bool CLabel::draw(const SRenderData& data) {
} }
void CLabel::renderUpdate() { void CLabel::renderUpdate() {
auto newAsset = g_pRenderer->asyncResourceGatherer->getAssetByID(pendingResourceID); auto newAsset = g_pAsyncResourceGatherer->getAssetByID(pendingResourceID);
if (newAsset) { if (newAsset) {
// new asset is ready :D // new asset is ready :D
g_pRenderer->asyncResourceGatherer->unloadAsset(asset); g_pAsyncResourceGatherer->unloadAsset(asset);
asset = newAsset; asset = newAsset;
resourceID = pendingResourceID; resourceID = pendingResourceID;
pendingResourceID = ""; pendingResourceID = "";

View file

@ -95,7 +95,7 @@ void CPasswordInputField::configure(const std::unordered_map<std::string, std::a
request.props["color"] = colorConfig.font; request.props["color"] = colorConfig.font;
request.props["font_size"] = (int)(std::nearbyint(configSize.y * dots.size * 0.5f) * 2.f); request.props["font_size"] = (int)(std::nearbyint(configSize.y * dots.size * 0.5f) * 2.f);
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pAsyncResourceGatherer->requestAsyncAssetPreload(request);
} }
// request the inital placeholder asset // request the inital placeholder asset
@ -112,7 +112,7 @@ void CPasswordInputField::reset() {
return; return;
if (placeholder.asset) if (placeholder.asset)
g_pRenderer->asyncResourceGatherer->unloadAsset(placeholder.asset); g_pAsyncResourceGatherer->unloadAsset(placeholder.asset);
placeholder.asset = nullptr; placeholder.asset = nullptr;
placeholder.resourceID.clear(); placeholder.resourceID.clear();
@ -242,7 +242,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
if (!dots.textFormat.empty()) { if (!dots.textFormat.empty()) {
if (!dots.textAsset) if (!dots.textAsset)
dots.textAsset = g_pRenderer->asyncResourceGatherer->getAssetByID(dots.textResourceID); dots.textAsset = g_pAsyncResourceGatherer->getAssetByID(dots.textResourceID);
if (!dots.textAsset) if (!dots.textAsset)
forceReload = true; forceReload = true;
@ -305,7 +305,7 @@ bool CPasswordInputField::draw(const SRenderData& data) {
SPreloadedAsset* currAsset = nullptr; SPreloadedAsset* currAsset = nullptr;
if (!placeholder.asset) if (!placeholder.asset)
placeholder.asset = g_pRenderer->asyncResourceGatherer->getAssetByID(placeholder.resourceID); placeholder.asset = g_pAsyncResourceGatherer->getAssetByID(placeholder.resourceID);
currAsset = placeholder.asset; currAsset = placeholder.asset;
@ -330,7 +330,7 @@ void CPasswordInputField::updatePlaceholder() {
if (passwordLength != 0) { if (passwordLength != 0) {
if (placeholder.asset && /* keep prompt asset cause it is likely to be used again */ displayFail) { if (placeholder.asset && /* keep prompt asset cause it is likely to be used again */ displayFail) {
std::erase(placeholder.registeredResourceIDs, placeholder.resourceID); std::erase(placeholder.registeredResourceIDs, placeholder.resourceID);
g_pRenderer->asyncResourceGatherer->unloadAsset(placeholder.asset); g_pAsyncResourceGatherer->unloadAsset(placeholder.asset);
placeholder.asset = nullptr; placeholder.asset = nullptr;
placeholder.resourceID = ""; placeholder.resourceID = "";
redrawShadow = true; redrawShadow = true;
@ -379,7 +379,7 @@ void CPasswordInputField::updatePlaceholder() {
if (const auto SELF = REF.lock(); SELF) if (const auto SELF = REF.lock(); SELF)
g_pHyprlock->renderOutput(SELF->outputStringPort); g_pHyprlock->renderOutput(SELF->outputStringPort);
}; };
g_pRenderer->asyncResourceGatherer->requestAsyncAssetPreload(request); g_pAsyncResourceGatherer->requestAsyncAssetPreload(request);
} }
void CPasswordInputField::updateWidth() { void CPasswordInputField::updateWidth() {