aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-11-01 15:52:03 +0000
committerVaxry <[email protected]>2024-11-01 15:52:09 +0000
commitd8b865366af9d5ed30d2ee0a437b9a3ed43c10bd (patch)
tree5d9ee0ea740c97dbcbdfddc2073a19ad7df17d25
parent3852418d2446555509738bf1486940042107afe7 (diff)
downloadHyprland-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.
-rw-r--r--src/Compositor.cpp6
-rw-r--r--src/render/Framebuffer.cpp15
-rw-r--r--src/render/OpenGL.cpp147
-rw-r--r--src/render/OpenGL.hpp14
-rw-r--r--src/render/Renderer.cpp20
5 files changed, 135 insertions, 67 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 65891633..62612398 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -2738,6 +2738,12 @@ void CCompositor::performUserChecks() {
CColor{}, 15000, ICON_WARNING);
}
}
+
+ if (g_pHyprOpenGL->failedAssetsNo > 0) {
+ g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!",
+ g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""),
+ CColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR);
+ }
}
void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) {
diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp
index c48ff6f3..7e086778 100644
--- a/src/render/Framebuffer.cpp
+++ b/src/render/Framebuffer.cpp
@@ -2,7 +2,7 @@
#include "OpenGL.hpp"
CFramebuffer::CFramebuffer() {
- m_cTex = makeShared<CTexture>();
+ ;
}
bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
@@ -12,6 +12,9 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat);
uint32_t glType = FormatUtils::glFormatToType(glFormat);
+ if (!m_cTex)
+ m_cTex = makeShared<CTexture>();
+
if (!m_iFbAllocated) {
firstAlloc = true;
glGenFramebuffers(1, &m_iFb);
@@ -54,7 +57,8 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) {
}
glBindTexture(GL_TEXTURE_2D, 0);
- glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb);
+ if (g_pHyprOpenGL)
+ glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb);
m_vSize = Vector2D(w, h);
@@ -85,14 +89,17 @@ void CFramebuffer::bind() {
#else
glBindFramebuffer(GL_FRAMEBUFFER, m_iFb);
#endif
- glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
+ if (g_pHyprOpenGL)
+ glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y);
+ else
+ glViewport(0, 0, m_vSize.x, m_vSize.y);
}
void CFramebuffer::release() {
if (m_iFbAllocated)
glDeleteFramebuffers(1, &m_iFb);
- m_cTex->destroyTexture();
+ m_cTex.reset();
m_iFbAllocated = false;
m_vSize = Vector2D();
}
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>();
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 115dcac7..c594a7cc 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -215,11 +215,12 @@ class CHyprOpenGLImpl {
GLint m_iCurrentOutputFb = 0;
- int m_iGBMFD = -1;
- gbm_device* m_pGbmDevice = nullptr;
- EGLContext m_pEglContext = nullptr;
- EGLDisplay m_pEglDisplay = nullptr;
- EGLDeviceEXT m_pEglDevice = nullptr;
+ int m_iGBMFD = -1;
+ gbm_device* m_pGbmDevice = nullptr;
+ EGLContext m_pEglContext = nullptr;
+ EGLDisplay m_pEglDisplay = nullptr;
+ EGLDeviceEXT m_pEglDevice = nullptr;
+ uint failedAssetsNo = 0;
bool m_bReloadScreenShader = true; // at launch it can be set
@@ -277,7 +278,7 @@ class CHyprOpenGLImpl {
CShader m_sFinalScreenShader;
CTimer m_tGlobalTimer;
- SP<CTexture> m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture;
+ SP<CTexture> m_pMissingAssetTexture, m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture;
void logShaderError(const GLuint&, bool program = false);
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
@@ -290,6 +291,7 @@ class CHyprOpenGLImpl {
SP<CTexture> loadAsset(const std::string& file);
SP<CTexture> renderText(const std::string& text, CColor col, int pt, bool italic = false);
void initAssets();
+ void initMissingAssetTexture();
//
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 1dedcc7d..a133899b 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -1063,22 +1063,16 @@ void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) {
if (ANY_PRESENT) {
// render image2, without instructions. Lock still "alive", unless texture dead
- if (g_pHyprOpenGL->m_pLockDead2Texture)
- g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA);
- else
- g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA));
+ g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA);
} else {
// render image, with instructions. Lock is gone.
- if (g_pHyprOpenGL->m_pLockDeadTexture) {
- g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA);
+ g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA);
- // also render text for the tty number
- if (g_pHyprOpenGL->m_pLockTtyTextTexture) {
- CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize};
- g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F);
- }
- } else
- g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA));
+ // also render text for the tty number
+ if (g_pHyprOpenGL->m_pLockTtyTextTexture) {
+ CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize};
+ g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F);
+ }
}
if (ALPHA < 1.f) /* animate */