diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c0a24b8f..4822bc691 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.9.3) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.8.2) -pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.3) +pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.6) string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR) diff --git a/flake.lock b/flake.lock index 291d31006..cb355f731 100644 --- a/flake.lock +++ b/flake.lock @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1757542864, - "narHash": "sha256-8i9tsVoOmLQDHJkNgzJWnmxYFGkJNsSndimYpCoqmoA=", + "lastModified": 1758192433, + "narHash": "sha256-CR6RnqEJSTiFgA6KQY4TTLUWbZ8RBnb+hxQqesuQNzQ=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "aa9d14963b94186934fd0715d9a7f0f2719e64bb", + "rev": "c44e749dd611521dee940d00f7c444ee0ae4cfb7", "type": "github" }, "original": { @@ -189,11 +189,11 @@ ] }, "locked": { - "lastModified": 1757508108, - "narHash": "sha256-bTYedtQFqqVBAh42scgX7+S3O6XKLnT6FTC6rpmyCCc=", + "lastModified": 1757694755, + "narHash": "sha256-j+w5QUUr2QT/jkxgVKecGYV8J7fpzXCMgzEEr6LG9ug=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "119bcb9aa742658107b326c50dcd24ab59b309b7", + "rev": "5ffdfc13ed03df1dae5084468d935f0a3f2c9a4c", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1757487488, - "narHash": "sha256-zwE/e7CuPJUWKdvvTCB7iunV4E/+G0lKfv4kk/5Izdg=", + "lastModified": 1758035966, + "narHash": "sha256-qqIJ3yxPiB0ZQTT9//nFGQYn8X/PBoJbofA7hRKZnmE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ab0f3607a6c7486ea22229b92ed2d355f1482ee0", + "rev": "8d4ddb19d03c65a36ad8d189d001dc32ffb0306b", "type": "github" }, "original": { @@ -299,11 +299,11 @@ ] }, "locked": { - "lastModified": 1757588530, - "narHash": "sha256-tJ7A8mID3ct69n9WCvZ3PzIIl3rXTdptn/lZmqSS95U=", + "lastModified": 1758108966, + "narHash": "sha256-ytw7ROXaWZ7OfwHrQ9xvjpUWeGVm86pwnEd1QhzawIo=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "b084b2c2b6bc23e83bbfe583b03664eb0b18c411", + "rev": "54df955a695a84cd47d4a43e08e1feaf90b1fd9b", "type": "github" }, "original": { diff --git a/meson.build b/meson.build index df49b27a0..0a45e91ad 100644 --- a/meson.build +++ b/meson.build @@ -34,7 +34,7 @@ endif aquamarine = dependency('aquamarine', version: '>=0.9.3') hyprcursor = dependency('hyprcursor', version: '>=0.1.7') -hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.3') +hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.6') hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprutils = dependency('hyprutils', version: '>= 0.8.2') aquamarine_version_list = aquamarine.version().split('.') diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c298c37d2..ce549459c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -59,6 +59,7 @@ #include "managers/HookSystemManager.hpp" #include "managers/ProtocolManager.hpp" #include "managers/LayoutManager.hpp" +#include "render/AsyncResourceGatherer.hpp" #include "plugins/PluginSystem.hpp" #include "hyprerror/HyprError.hpp" #include "debug/HyprNotificationOverlay.hpp" @@ -605,6 +606,7 @@ void CCompositor::cleanup() { g_pDonationNagManager.reset(); g_pANRManager.reset(); g_pConfigWatcher.reset(); + g_pAsyncResourceGatherer.reset(); if (m_aqBackend) m_aqBackend.reset(); @@ -655,6 +657,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the EventManager!"); g_pEventManager = makeUnique(); + + Debug::log(LOG, "Creating the AsyncResourceGatherer!"); + g_pAsyncResourceGatherer = makeUnique(); } break; case STAGE_BASICINIT: { Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index d7d29763a..5cfd47f2d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1186,8 +1186,6 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { g_pInputManager->setTabletConfigs(); g_pHyprOpenGL->m_reloadScreenShader = true; - - g_pHyprOpenGL->ensureBackgroundTexturePresence(); } // parseError will be displayed next frame diff --git a/src/helpers/MainLoopExecutor.cpp b/src/helpers/MainLoopExecutor.cpp new file mode 100644 index 000000000..19c495634 --- /dev/null +++ b/src/helpers/MainLoopExecutor.cpp @@ -0,0 +1,47 @@ +#include "MainLoopExecutor.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" +#include "../macros.hpp" + +static int onDataRead(int fd, uint32_t mask, void* data) { + ((CMainLoopExecutor*)data)->onFired(); + return 0; +} + +CMainLoopExecutor::CMainLoopExecutor(std::function&& callback) : m_fn(std::move(callback)) { + + int fds[2]; + pipe(fds); + + RASSERT(fds[0] != 0, "CMainLoopExecutor: failed to open a pipe"); + RASSERT(fds[1] != 0, "CMainLoopExecutor: failed to open a pipe"); + + m_event = wl_event_loop_add_fd(g_pEventLoopManager->m_wayland.loop, fds[0], WL_EVENT_READABLE, ::onDataRead, this); + + m_readFd = Hyprutils::OS::CFileDescriptor(fds[0]); + m_writeFd = Hyprutils::OS::CFileDescriptor(fds[1]); +} + +CMainLoopExecutor::~CMainLoopExecutor() { + if (m_event) // FIXME: potential race in case of a weird destroy on a worker thread + wl_event_source_remove(m_event); +} + +void CMainLoopExecutor::signal() { + const char* amogus = "h"; + write(m_writeFd.get(), amogus, 1); +} + +void CMainLoopExecutor::onFired() { + if (!m_fn) + return; + + m_fn(); + m_fn = nullptr; + + // we need to remove the event here because we're on the main thread + wl_event_source_remove(m_event); + m_event = nullptr; + + m_readFd.reset(); + m_writeFd.reset(); +} diff --git a/src/helpers/MainLoopExecutor.hpp b/src/helpers/MainLoopExecutor.hpp new file mode 100644 index 000000000..b33148f0e --- /dev/null +++ b/src/helpers/MainLoopExecutor.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +class CMainLoopExecutor { + public: + /* + MainLoopExecutor + + Executes a function on the main thread once the writeFd() has some data written to it, + then destroys itself. + + Needs to be kept owned, otherwise will die and kill the fds. + */ + + CMainLoopExecutor(std::function&& callback); + ~CMainLoopExecutor(); + + // Call from your worker thread: signals to the main thread. Destroy afterwards. + void signal(); + + // do not call + void onFired(); + + private: + Hyprutils::OS::CFileDescriptor m_readFd, m_writeFd; + wl_event_source* m_event = nullptr; + std::function m_fn; +}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 4a9f93ffe..1c08faffd 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -55,6 +55,8 @@ CMonitor::CMonitor(SP output_) : m_state(this), m_output(ou m_cursorZoom->setUpdateCallback([this](auto) { g_pHyprRenderer->damageMonitor(m_self.lock()); }); g_pAnimationManager->createAnimation(0.F, m_zoomAnimProgress, g_pConfigManager->getAnimationPropertyConfig("monitorAdded"), AVARDAMAGE_NONE); m_zoomAnimProgress->setUpdateCallback([this](auto) { g_pHyprRenderer->damageMonitor(m_self.lock()); }); + g_pAnimationManager->createAnimation(0.F, m_backgroundOpacity, g_pConfigManager->getAnimationPropertyConfig("monitorAdded"), AVARDAMAGE_NONE); + m_backgroundOpacity->setUpdateCallback([this](auto) { g_pHyprRenderer->damageMonitor(m_self.lock()); }); g_pAnimationManager->createAnimation(0.F, m_dpmsBlackOpacity, g_pConfigManager->getAnimationPropertyConfig("fadeDpms"), AVARDAMAGE_NONE); m_dpmsBlackOpacity->setUpdateCallback([this](auto) { g_pHyprRenderer->damageMonitor(m_self.lock()); }); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 542207b6b..d628ac587 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -188,6 +188,9 @@ class CMonitor { PHLANIMVAR m_cursorZoom; + // for fading in the wallpaper because it doesn't happen instantly (it's loaded async) + PHLANIMVAR m_backgroundOpacity; + // for initial zoom anim PHLANIMVAR m_zoomAnimProgress; CTimer m_newMonitorAnimTimer; diff --git a/src/helpers/memory/Memory.hpp b/src/helpers/memory/Memory.hpp index 7d9d18b14..66ba2c1fd 100644 --- a/src/helpers/memory/Memory.hpp +++ b/src/helpers/memory/Memory.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include using namespace Hyprutils::Memory; @@ -10,3 +11,5 @@ template using WP = Hyprutils::Memory::CWeakPointer; template using UP = Hyprutils::Memory::CUniquePointer; +template +using ASP = Hyprutils::Memory::CAtomicSharedPointer; diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 9963d4ae0..7a3b43143 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -99,6 +99,7 @@ class CEventLoopManager { wl_event_source* m_configWatcherInotifySource = nullptr; friend class CAsyncDialogBox; + friend class CMainLoopExecutor; }; inline UP g_pEventLoopManager; diff --git a/src/render/AsyncResourceGatherer.hpp b/src/render/AsyncResourceGatherer.hpp new file mode 100644 index 000000000..98f7525eb --- /dev/null +++ b/src/render/AsyncResourceGatherer.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +#include "../helpers/memory/Memory.hpp" + +inline UP g_pAsyncResourceGatherer; \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 66bdfa7a9..3cb810e1c 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -21,6 +21,7 @@ #include "../managers/input/InputManager.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" #include "../helpers/fs/FsUtils.hpp" +#include "../helpers/MainLoopExecutor.hpp" #include "debug/HyprNotificationOverlay.hpp" #include "hyprerror/HyprError.hpp" #include "pass/TexPassElement.hpp" @@ -28,6 +29,7 @@ #include "pass/PreBlurElement.hpp" #include "pass/ClearPassElement.hpp" #include "render/Shader.hpp" +#include "AsyncResourceGatherer.hpp" #include #include #include @@ -2660,8 +2662,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const cairo_surface_flush(CAIROSURFACE); } -SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { - +std::string CHyprOpenGLImpl::resolveAssetPath(const std::string& filename) { std::string fullPath; for (auto& e : ASSET_PATHS) { std::string p = std::string{e} + "/hypr/" + filename; @@ -2670,15 +2671,25 @@ SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { fullPath = p; break; } else - Debug::log(LOG, "loadAsset: looking at {} unsuccessful: ec {}", filename, ec.message()); + Debug::log(LOG, "resolveAssetPath: looking at {} unsuccessful: ec {}", filename, ec.message()); } if (fullPath.empty()) { m_failedAssetsNo++; - Debug::log(ERR, "loadAsset: looking for {} failed (no provider found)", filename); - return m_missingAssetTexture; + Debug::log(ERR, "resolveAssetPath: looking for {} failed (no provider found)", filename); + return ""; } + return fullPath; +} + +SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { + + const std::string fullPath = resolveAssetPath(filename); + + if (fullPath.empty()) + return m_missingAssetTexture; + const auto CAIROSURFACE = cairo_image_surface_create_from_png(fullPath.c_str()); if (!CAIROSURFACE) { @@ -2687,17 +2698,25 @@ SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { return m_missingAssetTexture; } - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); + auto tex = texFromCairo(CAIROSURFACE); + + cairo_surface_destroy(CAIROSURFACE); + + return tex; +} + +SP CHyprOpenGLImpl::texFromCairo(cairo_surface_t* cairo) { + const auto CAIROFORMAT = cairo_image_surface_get_format(cairo); auto tex = makeShared(); tex->allocate(); - tex->m_size = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + tex->m_size = {cairo_image_surface_get_width(cairo), cairo_image_surface_get_height(cairo)}; const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA; const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; - const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); + const auto DATA = cairo_image_surface_get_data(cairo); tex->bind(); tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR); tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -2709,8 +2728,6 @@ SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_size.x, tex->m_size.y, 0, glFormat, glType, DATA); - cairo_surface_destroy(CAIROSURFACE); - return tex; } @@ -2847,8 +2864,6 @@ void CHyprOpenGLImpl::initAssets() { initMissingAssetTexture(); m_screencopyDeniedTexture = renderText("Permission denied to share screen", Colors::WHITE, 20); - - ensureBackgroundTexturePresence(); } void CHyprOpenGLImpl::ensureLockTexturesRendered(bool load) { @@ -2874,18 +2889,22 @@ void CHyprOpenGLImpl::ensureLockTexturesRendered(bool load) { } } -void CHyprOpenGLImpl::ensureBackgroundTexturePresence() { +void CHyprOpenGLImpl::requestBackgroundResource() { + if (m_backgroundResource) + return; + static auto PNOWALLPAPER = CConfigValue("misc:disable_hyprland_logo"); static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, sc(-1), sc(2)); if (*PNOWALLPAPER) - m_backgroundTexture.reset(); - else if (!m_backgroundTexture) { - // create the default background texture - std::string texPath = "wall"; + return; + static bool once = true; + static std::string texPath = "wall"; + + if (once) { // get the adequate tex if (FORCEWALLPAPER == -1) { std::mt19937_64 engine(time(nullptr)); @@ -2897,8 +2916,31 @@ void CHyprOpenGLImpl::ensureBackgroundTexturePresence() { texPath += ".png"; - m_backgroundTexture = loadAsset(texPath); + texPath = resolveAssetPath(texPath); + + once = false; } + + if (texPath.empty()) { + m_backgroundResourceFailed = true; + return; + } + + m_backgroundResource = makeAtomicShared(texPath); + + // doesn't have to be ASP as it's passed + SP executor = makeShared([] { + for (const auto& m : g_pCompositor->m_monitors) { + g_pHyprRenderer->damageMonitor(m); + } + }); + + m_backgroundResource->m_events.finished.listenStatic([executor] { + // this is in the worker thread. + executor->signal(); + }); + + g_pAsyncResourceGatherer->enqueue(m_backgroundResource); } void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { @@ -2909,7 +2951,16 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); static auto PNOSPLASH = CConfigValue("misc:disable_splash_rendering"); - if (*PRENDERTEX) + if (*PRENDERTEX || m_backgroundResourceFailed) + return; + + if (!m_backgroundResource) { + // queue the asset to be created + requestBackgroundResource(); + return; + } + + if (!m_backgroundResource->m_ready) return; // release the last tex if exists @@ -2918,9 +2969,6 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { PFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat); - if (!m_backgroundTexture) // ?!?!?! - return; - // create a new one with cairo SP tex = makeShared(); @@ -2966,23 +3014,25 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { blend(true); clear(CHyprColor{0, 0, 0, 1}); + SP backgroundTexture = texFromCairo(m_backgroundResource->m_asset.cairoSurface->cairo()); + // first render the background - if (m_backgroundTexture) { + if (backgroundTexture) { const double MONRATIO = m_renderData.pMonitor->m_transformedSize.x / m_renderData.pMonitor->m_transformedSize.y; - const double WPRATIO = m_backgroundTexture->m_size.x / m_backgroundTexture->m_size.y; + const double WPRATIO = backgroundTexture->m_size.x / backgroundTexture->m_size.y; Vector2D origin; double scale = 1.0; if (MONRATIO > WPRATIO) { - scale = m_renderData.pMonitor->m_transformedSize.x / m_backgroundTexture->m_size.x; - origin.y = (m_renderData.pMonitor->m_transformedSize.y - m_backgroundTexture->m_size.y * scale) / 2.0; + scale = m_renderData.pMonitor->m_transformedSize.x / backgroundTexture->m_size.x; + origin.y = (m_renderData.pMonitor->m_transformedSize.y - backgroundTexture->m_size.y * scale) / 2.0; } else { - scale = m_renderData.pMonitor->m_transformedSize.y / m_backgroundTexture->m_size.y; - origin.x = (m_renderData.pMonitor->m_transformedSize.x - m_backgroundTexture->m_size.x * scale) / 2.0; + scale = m_renderData.pMonitor->m_transformedSize.y / backgroundTexture->m_size.y; + origin.x = (m_renderData.pMonitor->m_transformedSize.x - backgroundTexture->m_size.x * scale) / 2.0; } - CBox texbox = CBox{origin, m_backgroundTexture->m_size * scale}; - renderTextureInternal(m_backgroundTexture, texbox, {.damage = &fakeDamage, .a = 1.0}); + CBox texbox = CBox{origin, backgroundTexture->m_size * scale}; + renderTextureInternal(backgroundTexture, texbox, {.damage = &fakeDamage, .a = 1.0}); } CBox monbox = {{}, pMonitor->m_pixelSize}; @@ -2993,21 +3043,31 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { m_renderData.currentFB->bind(); Debug::log(LOG, "Background created for monitor {}", pMonitor->m_name); + + // clear the resource after we're done using it + g_pEventLoopManager->doLater([this] { m_backgroundResource.reset(); }); + + // set the animation to start for fading this background in nicely + pMonitor->m_backgroundOpacity->setValueAndWarp(0.F); + *pMonitor->m_backgroundOpacity = 1.F; } void CHyprOpenGLImpl::clearWithTex() { RASSERT(m_renderData.pMonitor, "Tried to render BGtex without begin()!"); - auto TEXIT = m_monitorBGFBs.find(m_renderData.pMonitor); + static auto PBACKGROUNDCOLOR = CConfigValue("misc:background_color"); + + auto TEXIT = m_monitorBGFBs.find(m_renderData.pMonitor); if (TEXIT == m_monitorBGFBs.end()) { createBGTextureForMonitor(m_renderData.pMonitor.lock()); - TEXIT = m_monitorBGFBs.find(m_renderData.pMonitor); + g_pHyprRenderer->m_renderPass.add(makeUnique(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)})); } if (TEXIT != m_monitorBGFBs.end()) { CTexPassElement::SRenderData data; data.box = {0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}; + data.a = m_renderData.pMonitor->m_backgroundOpacity->value(); data.flipEndFrame = true; data.tex = TEXIT->second.getTexture(); g_pHyprRenderer->m_renderPass.add(makeUnique(std::move(data))); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 9e61106bd..a69ebbfeb 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "../debug/TracyDefines.hpp" #include "../protocols/core/Compositor.hpp" @@ -261,13 +262,13 @@ class CHyprOpenGLImpl { void renderOffToMain(CFramebuffer* off); void bindBackOnMain(); + std::string resolveAssetPath(const std::string& file); SP loadAsset(const std::string& file); + SP texFromCairo(cairo_surface_t* cairo); SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400); void setDamage(const CRegion& damage, std::optional finalDamage = {}); - void ensureBackgroundTexturePresence(); - uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); @@ -348,38 +349,40 @@ class CHyprOpenGLImpl { GLsizei height = 0; } m_lastViewport; - std::unordered_map m_capStatus; + std::unordered_map m_capStatus; - std::vector m_drmFormats; - bool m_hasModifiers = false; + std::vector m_drmFormats; + bool m_hasModifiers = false; - int m_drmFD = -1; - std::string m_extensions; + int m_drmFD = -1; + std::string m_extensions; - bool m_fakeFrame = false; - bool m_applyFinalShader = false; - bool m_blend = false; - bool m_offloadedFramebuffer = false; - bool m_cmSupported = true; + bool m_fakeFrame = false; + bool m_applyFinalShader = false; + bool m_blend = false; + bool m_offloadedFramebuffer = false; + bool m_cmSupported = true; - bool m_monitorTransformEnabled = false; // do not modify directly - std::stack m_monitorTransformStack; - SP m_missingAssetTexture; - SP m_backgroundTexture; - SP m_lockDeadTexture; - SP m_lockDead2Texture; - SP m_lockTtyTextTexture; - SShader m_finalScreenShader; - CTimer m_globalTimer; - GLuint m_currentProgram; + bool m_monitorTransformEnabled = false; // do not modify directly + std::stack m_monitorTransformStack; + SP m_missingAssetTexture; + SP m_lockDeadTexture; + SP m_lockDead2Texture; + SP m_lockTtyTextTexture; + SShader m_finalScreenShader; + CTimer m_globalTimer; + GLuint m_currentProgram; + ASP m_backgroundResource; + bool m_backgroundResourceFailed = false; - void logShaderError(const GLuint&, bool program = false, bool silent = false); - void createBGTextureForMonitor(PHLMONITOR); - void initDRMFormats(); - void initEGL(bool gbm); - EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); - void initAssets(); - void initMissingAssetTexture(); + void logShaderError(const GLuint&, bool program = false, bool silent = false); + void createBGTextureForMonitor(PHLMONITOR); + void initDRMFormats(); + void initEGL(bool gbm); + EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); + void initAssets(); + void initMissingAssetTexture(); + void requestBackgroundResource(); // std::optional> getModsForFormat(EGLint format); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7efaed0e5..32b571b10 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -846,8 +846,6 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA static auto PDIMSPECIAL = CConfigValue("decoration:dim_special"); static auto PBLURSPECIAL = CConfigValue("decoration:blur:special"); static auto PBLUR = CConfigValue("decoration:blur:enabled"); - static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); - static auto PBACKGROUNDCOLOR = CConfigValue("misc:background_color"); static auto PXPMODE = CConfigValue("render:xp_mode"); static auto PSESSIONLOCKXRAY = CConfigValue("misc:session_lock_xray"); @@ -883,10 +881,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA if (!pWorkspace) { // allow rendering without a workspace. In this case, just render layers. - if (*PRENDERTEX /* inverted cfg flag */) - m_renderPass.add(makeUnique(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)})); - else - g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" + renderBackground(pMonitor); for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); @@ -910,10 +905,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA } if (!*PXPMODE) { - if (*PRENDERTEX /* inverted cfg flag */) - m_renderPass.add(makeUnique(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)})); - else - g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" + renderBackground(pMonitor); for (auto const& ls : pMonitor->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); @@ -1011,6 +1003,17 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA //g_pHyprOpenGL->restoreMatrix(); } +void CHyprRenderer::renderBackground(PHLMONITOR pMonitor) { + static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); + static auto PBACKGROUNDCOLOR = CConfigValue("misc:background_color"); + + if (*PRENDERTEX /* inverted cfg flag */ || pMonitor->m_backgroundOpacity->isBeingAnimated()) + m_renderPass.add(makeUnique(CClearPassElement::SClearData{CHyprColor(*PBACKGROUNDCOLOR)})); + + if (!*PRENDERTEX) + g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" +} + void CHyprRenderer::renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry) { TRACY_GPU_ZONE("RenderLockscreen"); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b1e514f36..511eeb9b1 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -130,6 +130,7 @@ class CHyprRenderer { void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now); // sends frame displayed events but doesn't actually render anything void renderSessionLockPrimer(PHLMONITOR pMonitor); void renderSessionLockMissing(PHLMONITOR pMonitor); + void renderBackground(PHLMONITOR pMonitor); bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor);