renderer: Add new background infrastructure

Adds new backgrounds from the winners of the contest
Rewrites how it works
Allows high color precision PNGs (RGB32F precisely)
Fixes a small bug in renderTextureInternalWithDamage
Nukes misc:force_hypr_chan
This commit is contained in:
Vaxry 2024-01-29 23:11:00 +00:00
parent 91e8c42843
commit 2e3f0d5991
18 changed files with 95 additions and 80 deletions

View File

@ -45,7 +45,7 @@ install:
cd ${PREFIX}/bin && ln -sf Hyprland hyprland cd ${PREFIX}/bin && ln -sf Hyprland hyprland
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
mkdir -p ${PREFIX}/share/hyprland mkdir -p ${PREFIX}/share/hyprland
cp ./assets/wall_* ${PREFIX}/share/hyprland cp ./assets/wall* ${PREFIX}/share/hyprland
mkdir -p ${PREFIX}/share/xdg-desktop-portal mkdir -p ${PREFIX}/share/xdg-desktop-portal
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal

BIN
assets/wall0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

BIN
assets/wall1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 MiB

BIN
assets/wall2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -112,7 +112,7 @@ gestures {
misc { misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
} }
# Example per-device config # Example per-device config

View File

@ -99,7 +99,6 @@ void CConfigManager::setDefaultVars() {
configValues["misc:disable_hyprland_logo"].intValue = 0; configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0; configValues["misc:disable_splash_rendering"].intValue = 0;
configValues["misc:force_hypr_chan"].intValue = 0;
configValues["misc:force_default_wallpaper"].intValue = -1; configValues["misc:force_default_wallpaper"].intValue = -1;
configValues["misc:vfr"].intValue = 1; configValues["misc:vfr"].intValue = 1;
configValues["misc:vrr"].intValue = 0; configValues["misc:vrr"].intValue = 0;

View File

@ -119,7 +119,7 @@ gestures {
misc { misc {
# See https://wiki.hyprland.org/Configuring/Variables/ for more # See https://wiki.hyprland.org/Configuring/Variables/ for more
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
} }
# Example per-device config # Example per-device config

View File

@ -214,6 +214,9 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer*
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
// ensure a framebuffer for the monitor exists // ensure a framebuffer for the monitor exists
if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) { if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
m_RenderData.pCurrentMonData->stencilTex.allocate(); m_RenderData.pCurrentMonData->stencilTex.allocate();
@ -234,9 +237,6 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer*
if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty())
m_RenderData.pCurrentMonData->monitorMirrorFB.release(); m_RenderData.pCurrentMonData->monitorMirrorFB.release();
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
m_RenderData.damage.set(*pDamage); m_RenderData.damage.set(*pDamage);
m_bFakeFrame = fb; m_bFakeFrame = fb;
@ -744,7 +744,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
alpha = std::clamp(alpha, 0.f, 1.f); alpha = std::clamp(alpha, 0.f, 1.f);
if (m_RenderData.damage.empty()) if (damage->empty())
return; return;
CBox newBox = *pBox; CBox newBox = *pBox;
@ -1901,10 +1901,10 @@ void CHyprOpenGLImpl::renderMirrored() {
renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false); renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false);
} }
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY) { void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {
cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
const auto FONTSIZE = (int)(m_RenderData.pMonitor->vecPixelSize.y / 76); const auto FONTSIZE = (int)(size.y / 76);
cairo_set_font_size(CAIRO, FONTSIZE); cairo_set_font_size(CAIRO, FONTSIZE);
cairo_set_source_rgba(CAIRO, 1.0, 1.0, 1.0, 0.32); cairo_set_source_rgba(CAIRO, 1.0, 1.0, 1.0, 0.32);
@ -1912,7 +1912,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const
cairo_text_extents_t textExtents; cairo_text_extents_t textExtents;
cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents); cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents);
cairo_move_to(CAIRO, (m_RenderData.pMonitor->vecPixelSize.x - textExtents.width) / 2.0, m_RenderData.pMonitor->vecPixelSize.y - textExtents.height + offsetY); cairo_move_to(CAIRO, (size.x - textExtents.width) / 2.0, size.y - textExtents.height + offsetY);
cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str()); cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str());
@ -1924,51 +1924,37 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue; static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
static auto* const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue; static auto* const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue;
static auto* const PFORCEHYPRCHAN = &g_pConfigManager->getConfigValuePtr("misc:force_hypr_chan")->intValue;
static auto* const PFORCEWALLPAPER = &g_pConfigManager->getConfigValuePtr("misc:force_default_wallpaper")->intValue; static auto* const PFORCEWALLPAPER = &g_pConfigManager->getConfigValuePtr("misc:force_default_wallpaper")->intValue;
const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast<int64_t>(-1L), static_cast<int64_t>(2L)); const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast<int64_t>(-1L), static_cast<int64_t>(2L));
static std::string texPath = "";
if (*PRENDERTEX) if (*PRENDERTEX)
return; return;
// release the last tex if exists // release the last tex if exists
const auto PTEX = &m_mMonitorBGTextures[pMonitor]; const auto PFB = &m_mMonitorBGFBs[pMonitor];
PTEX->destroyTexture(); PFB->release();
PTEX->allocate(); PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
Debug::log(LOG, "Allocated texture for BGTex"); Debug::log(LOG, "Allocated texture for BGTex");
// TODO: use relative paths to the installation // TODO: use relative paths to the installation
// or configure the paths at build time // or configure the paths at build time
std::string texPath = "/usr/share/hyprland/wall_"; if (texPath.empty()) {
std::string prefixes[] = {"", "anime_", "anime2_"}; texPath = "/usr/share/hyprland/wall";
// get the adequate tex // get the adequate tex
if (FORCEWALLPAPER == -1) { if (FORCEWALLPAPER == -1) {
std::random_device dev; std::mt19937_64 engine(time(nullptr));
std::mt19937 engine(dev());
std::uniform_int_distribution<> distribution(0, 2); std::uniform_int_distribution<> distribution(0, 2);
std::uniform_int_distribution<> distribution_anime(1, 2);
if (PFORCEHYPRCHAN) texPath += std::to_string(distribution(engine));
texPath += prefixes[distribution_anime(engine)];
else
texPath += prefixes[distribution(engine)];
} else } else
texPath += prefixes[FORCEWALLPAPER]; texPath += std::to_string(std::clamp(*PFORCEWALLPAPER, (int64_t)0, (int64_t)2));
Vector2D textureSize; texPath += ".png";
if (pMonitor->vecTransformedSize.x > 3850) {
textureSize = Vector2D(7680, 4320);
texPath += "8K.png";
} else if (pMonitor->vecTransformedSize.x > 1930) {
textureSize = Vector2D(3840, 2160);
texPath += "4K.png";
} else {
textureSize = Vector2D(1920, 1080);
texPath += "2K.png";
}
// check if wallpapers exist // check if wallpapers exist
if (!std::filesystem::exists(texPath)) { if (!std::filesystem::exists(texPath)) {
@ -1978,55 +1964,83 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
if (!std::filesystem::exists(texPath)) if (!std::filesystem::exists(texPath))
return; // the texture will be empty, oh well. We'll clear with a solid color anyways. return; // the texture will be empty, oh well. We'll clear with a solid color anyways.
} }
}
PTEX->m_vSize = textureSize; // create a new one with cairo
CTexture tex;
const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str());
const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE);
tex.allocate();
const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)};
// calc the target box // calc the target box
const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y; const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y;
const double WPRATIO = 1.77; const double WPRATIO = IMAGESIZE.x / IMAGESIZE.y;
Vector2D origin; Vector2D origin;
double scale; double scale;
if (MONRATIO > WPRATIO) { if (MONRATIO > WPRATIO) {
scale = m_RenderData.pMonitor->vecTransformedSize.x / PTEX->m_vSize.x; scale = m_RenderData.pMonitor->vecTransformedSize.x / IMAGESIZE.x;
origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - PTEX->m_vSize.y * scale) / 2.0; origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - IMAGESIZE.y * scale) / 2.0;
} else { } else {
scale = m_RenderData.pMonitor->vecTransformedSize.y / PTEX->m_vSize.y; scale = m_RenderData.pMonitor->vecTransformedSize.y / IMAGESIZE.y;
origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - PTEX->m_vSize.x * scale) / 2.0; origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - IMAGESIZE.x * scale) / 2.0;
} }
CBox box = {origin.x, origin.y, PTEX->m_vSize.x * scale, PTEX->m_vSize.y * scale}; const Vector2D scaledSize = IMAGESIZE * scale;
m_mMonitorRenderResources[pMonitor].backgroundTexBox = box; const auto CAIROSURFACE = cairo_image_surface_create(CAIROFORMAT, scaledSize.x, scaledSize.y);
// create a new one with cairo
const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str());
const auto CAIRO = cairo_create(CAIROSURFACE); const auto CAIRO = cairo_create(CAIROSURFACE);
// scale it to fit the current monitor cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_BEST);
cairo_scale(CAIRO, textureSize.x / pMonitor->vecTransformedSize.x, textureSize.y / pMonitor->vecTransformedSize.y); cairo_scale(CAIRO, scale, scale);
cairo_rectangle(CAIRO, 0, 0, 100, 100);
cairo_set_source_surface(CAIRO, CAIROISURFACE, 0, 0);
cairo_paint(CAIRO);
// render splash on wallpaper
if (!*PNOSPLASH) if (!*PNOSPLASH)
renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO); renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO * scale, IMAGESIZE);
cairo_surface_flush(CAIROSURFACE);
CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale};
tex.m_vSize = IMAGESIZE * scale;
// copy the data to an OpenGL texture we have // copy the data to an OpenGL texture we have
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(CAIROSURFACE);
glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID); glBindTexture(GL_TEXTURE_2D, tex.m_iTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
#ifndef GLES2 #ifndef GLES2
if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
}
#endif #endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize.x, textureSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA);
cairo_surface_destroy(CAIROSURFACE); cairo_surface_destroy(CAIROSURFACE);
cairo_surface_destroy(CAIROISURFACE);
cairo_destroy(CAIRO); cairo_destroy(CAIRO);
// render the texture to our fb
PFB->bind();
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
renderTextureInternalWithDamage(tex, &box, 1.0, &fakeDamage);
// bind back
if (m_RenderData.currentFB)
m_RenderData.currentFB->bind();
Debug::log(LOG, "Background created for monitor {}", pMonitor->szName); Debug::log(LOG, "Background created for monitor {}", pMonitor->szName);
} }
@ -2035,15 +2049,19 @@ void CHyprOpenGLImpl::clearWithTex() {
TRACY_GPU_ZONE("RenderClearWithTex"); TRACY_GPU_ZONE("RenderClearWithTex");
auto TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor); auto TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
if (TEXIT == m_mMonitorBGTextures.end()) { if (TEXIT == m_mMonitorBGFBs.end()) {
createBGTextureForMonitor(m_RenderData.pMonitor); createBGTextureForMonitor(m_RenderData.pMonitor);
TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor); TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
} }
if (TEXIT != m_mMonitorBGTextures.end()) if (TEXIT != m_mMonitorBGFBs.end()) {
renderTexture(TEXIT->second, &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox, 1); CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
m_bEndFrame = true;
renderTexture(TEXIT->second.m_cTex, &monbox, 1);
m_bEndFrame = false;
}
} }
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
@ -2061,10 +2079,10 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT); g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT);
} }
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGTextures.find(pMonitor); auto TEXIT = g_pHyprOpenGL->m_mMonitorBGFBs.find(pMonitor);
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGTextures.end()) { if (TEXIT != g_pHyprOpenGL->m_mMonitorBGFBs.end()) {
TEXIT->second.destroyTexture(); TEXIT->second.release();
g_pHyprOpenGL->m_mMonitorBGTextures.erase(TEXIT); g_pHyprOpenGL->m_mMonitorBGFBs.erase(TEXIT);
} }
Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName); Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName);

View File

@ -71,8 +71,6 @@ struct SMonitorRenderData {
bool blurFBDirty = true; bool blurFBDirty = true;
bool blurFBShouldRender = false; bool blurFBShouldRender = false;
CBox backgroundTexBox;
// Shaders // Shaders
bool m_bShadersInitialized = false; bool m_bShadersInitialized = false;
CShader m_shQUAD; CShader m_shQUAD;
@ -191,7 +189,7 @@ class CHyprOpenGLImpl {
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers; std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers; std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources; std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures; std::unordered_map<CMonitor*, CFramebuffer> m_mMonitorBGFBs;
struct { struct {
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
@ -229,7 +227,7 @@ class CHyprOpenGLImpl {
void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
bool allowCustomUV = false, bool allowDim = false); bool allowCustomUV = false, bool allowDim = false);
void renderTexturePrimitive(const CTexture& tex, CBox* pBox); void renderTexturePrimitive(const CTexture& tex, CBox* pBox);
void renderSplash(cairo_t* const, cairo_surface_t* const, double); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
void preBlurForCurrentMonitor(); void preBlurForCurrentMonitor();