diff options
author | Vaxry <[email protected]> | 2024-11-01 15:52:03 +0000 |
---|---|---|
committer | Vaxry <[email protected]> | 2024-11-01 15:52:09 +0000 |
commit | d8b865366af9d5ed30d2ee0a437b9a3ed43c10bd (patch) | |
tree | 5d9ee0ea740c97dbcbdfddc2073a19ad7df17d25 /src/render/OpenGL.cpp | |
parent | 3852418d2446555509738bf1486940042107afe7 (diff) | |
download | Hyprland-d8b865366af9d5ed30d2ee0a437b9a3ed43c10bd.tar.gz Hyprland-d8b865366af9d5ed30d2ee0a437b9a3ed43c10bd.zip |
renderer: Add a missing texture asset and a user check
When an asset is missing, instead of a black screen, render an obnoxious, yet standard, missing texture.
Additionally, warn the user assets failed to load.
Shoutout to Arch for having their assets broken for months. Fix your shit. I am tired of it, and it's negatively impacting users.
Diffstat (limited to 'src/render/OpenGL.cpp')
-rw-r--r-- | src/render/OpenGL.cpp | 147 |
1 files changed, 103 insertions, 44 deletions
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 9e524fa4..20963707 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -13,6 +13,13 @@ #include <gbm.h> #include <filesystem> +const std::vector<const char*> ASSET_PATHS = { +#ifdef DATAROOTDIR + DATAROOTDIR, +#endif + "/usr/share", +}; + inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); if (proc == NULL) { @@ -2595,11 +2602,32 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const cairo_surface_flush(CAIROSURFACE); } -SP<CTexture> CHyprOpenGLImpl::loadAsset(const std::string& file) { - const auto CAIROSURFACE = cairo_image_surface_create_from_png(file.c_str()); +SP<CTexture> CHyprOpenGLImpl::loadAsset(const std::string& filename) { - if (!CAIROSURFACE) - return nullptr; + std::string fullPath; + for (auto& e : ASSET_PATHS) { + std::string p = std::string{e} + "/hypr/" + filename; + std::error_code ec; + if (std::filesystem::exists(p, ec)) { + fullPath = p; + break; + } else + Debug::log(LOG, "loadAsset: looking at {} unsuccessful: ec {}", filename, ec.message()); + } + + if (fullPath.empty()) { + failedAssetsNo++; + Debug::log(ERR, "loadAsset: looking for {} failed (no provider found)", filename); + return m_pMissingAssetTexture; + } + + const auto CAIROSURFACE = cairo_image_surface_create_from_png(fullPath.c_str()); + + if (!CAIROSURFACE) { + failedAssetsNo++; + Debug::log(ERR, "loadAsset: failed to load {} (corrupt / inaccessible / not png)", fullPath); + return m_pMissingAssetTexture; + } const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); auto tex = makeShared<CTexture>(); @@ -2710,51 +2738,68 @@ SP<CTexture> CHyprOpenGLImpl::renderText(const std::string& text, CColor col, in return tex; } -void CHyprOpenGLImpl::initAssets() { - std::string assetsPath = ""; -#ifndef DATAROOTDIR - assetsPath = "/usr/share/hypr/"; -#else - assetsPath = std::format("{}{}", DATAROOTDIR, "/hypr/"); +void CHyprOpenGLImpl::initMissingAssetTexture() { + SP<CTexture> tex = makeShared<CTexture>(); + tex->allocate(); + + const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512); + const auto CAIRO = cairo_create(CAIROSURFACE); + + cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_NONE); + cairo_save(CAIRO); + cairo_set_source_rgba(CAIRO, 0, 0, 0, 1); + cairo_set_operator(CAIRO, CAIRO_OPERATOR_SOURCE); + cairo_paint(CAIRO); + cairo_set_source_rgba(CAIRO, 1, 0, 1, 1); + cairo_rectangle(CAIRO, 256, 0, 256, 256); + cairo_fill(CAIRO); + cairo_rectangle(CAIRO, 0, 256, 256, 256); + cairo_fill(CAIRO); + cairo_restore(CAIRO); + + cairo_surface_flush(CAIROSURFACE); + + tex->m_vSize = {512, 512}; + + // copy the data to an OpenGL texture we have + const GLint glFormat = GL_RGBA; + const GLint glType = GL_UNSIGNED_BYTE; + + const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifndef GLES2 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); #endif + glTexImage2D(GL_TEXTURE_2D, 0, glFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); - m_pLockDeadTexture = loadAsset(assetsPath + "lockdead.png"); - m_pLockDead2Texture = loadAsset(assetsPath + "lockdead2.png"); + cairo_surface_destroy(CAIROSURFACE); + cairo_destroy(CAIRO); - m_pLockTtyTextTexture = renderText(std::format("Running on tty {}", - g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ? - std::to_string(g_pCompositor->m_pAqBackend->session->vt) : - "unknown"), - CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); + m_pMissingAssetTexture = tex; } -void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { - RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); - - Debug::log(LOG, "Creating a texture for BGTex"); +void CHyprOpenGLImpl::initAssets() { + initMissingAssetTexture(); - static auto PRENDERTEX = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_logo"); - static auto PNOSPLASH = CConfigValue<Hyprlang::INT>("misc:disable_splash_rendering"); static auto PFORCEWALLPAPER = CConfigValue<Hyprlang::INT>("misc:force_default_wallpaper"); const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast<int64_t>(-1L), static_cast<int64_t>(2L)); - if (*PRENDERTEX) - return; + m_pLockDeadTexture = loadAsset("lockdead.png"); + m_pLockDead2Texture = loadAsset("lockdead2.png"); - // release the last tex if exists - const auto PFB = &m_mMonitorBGFBs[pMonitor]; - PFB->release(); - - PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_pLockTtyTextTexture = renderText(std::format("Running on tty {}", + g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ? + std::to_string(g_pCompositor->m_pAqBackend->session->vt) : + "unknown"), + CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); - if (!m_pBackgroundTexture) { - std::string texPath = ""; -#ifndef DATAROOTDIR - texPath = "/usr/share/hypr/wall"; -#else - texPath = std::format("{}{}", DATAROOTDIR, "/hypr/wall"); -#endif + // create the default background texture + { + std::string texPath = std::format("{}", "wall"); // get the adequate tex if (FORCEWALLPAPER == -1) { @@ -2767,15 +2812,29 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { texPath += ".png"; - // check if wallpapers exist - std::error_code err; - if (!std::filesystem::exists(texPath, err)) { - Debug::log(ERR, "createBGTextureForMonitor: failed, file \"{}\" doesn't exist or access denied, ec: {}", texPath, err.message()); - return; // the texture will be empty, oh well. We'll clear with a solid color anyways. - } - m_pBackgroundTexture = loadAsset(texPath); } +} + +void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { + RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); + + Debug::log(LOG, "Creating a texture for BGTex"); + + static auto PRENDERTEX = CConfigValue<Hyprlang::INT>("misc:disable_hyprland_logo"); + static auto PNOSPLASH = CConfigValue<Hyprlang::INT>("misc:disable_splash_rendering"); + + if (*PRENDERTEX) + return; + + // release the last tex if exists + const auto PFB = &m_mMonitorBGFBs[pMonitor]; + PFB->release(); + + PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + + if (!m_pBackgroundTexture) // ?!?!?! + return; // create a new one with cairo SP<CTexture> tex = makeShared<CTexture>(); |