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
2
Makefile
|
@ -45,7 +45,7 @@ install:
|
|||
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
|
||||
mkdir -p ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall* ${PREFIX}/share/hyprland
|
||||
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
||||
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
|
||||
|
||||
|
|
BIN
assets/wall0.png
Normal file
After Width: | Height: | Size: 14 MiB |
BIN
assets/wall1.png
Normal file
After Width: | Height: | Size: 5.4 MiB |
BIN
assets/wall2.png
Normal file
After Width: | Height: | Size: 27 MiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 511 KiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 502 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.6 MiB |
|
@ -112,7 +112,7 @@ gestures {
|
|||
|
||||
misc {
|
||||
# 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
|
||||
|
|
|
@ -99,7 +99,6 @@ void CConfigManager::setDefaultVars() {
|
|||
|
||||
configValues["misc:disable_hyprland_logo"].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:vfr"].intValue = 1;
|
||||
configValues["misc:vrr"].intValue = 0;
|
||||
|
|
|
@ -119,7 +119,7 @@ gestures {
|
|||
|
||||
misc {
|
||||
# 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
|
||||
|
|
|
@ -214,6 +214,9 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer*
|
|||
|
||||
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
|
||||
initShaders();
|
||||
|
||||
// ensure a framebuffer for the monitor exists
|
||||
if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
|
||||
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())
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.release();
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
|
||||
initShaders();
|
||||
|
||||
m_RenderData.damage.set(*pDamage);
|
||||
|
||||
m_bFakeFrame = fb;
|
||||
|
@ -744,7 +744,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
|
|||
|
||||
alpha = std::clamp(alpha, 0.f, 1.f);
|
||||
|
||||
if (m_RenderData.damage.empty())
|
||||
if (damage->empty())
|
||||
return;
|
||||
|
||||
CBox newBox = *pBox;
|
||||
|
@ -1901,10 +1901,10 @@ void CHyprOpenGLImpl::renderMirrored() {
|
|||
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);
|
||||
|
||||
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_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(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());
|
||||
|
||||
|
@ -1924,51 +1924,37 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
|||
|
||||
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 PFORCEHYPRCHAN = &g_pConfigManager->getConfigValuePtr("misc:force_hypr_chan")->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));
|
||||
|
||||
static std::string texPath = "";
|
||||
|
||||
if (*PRENDERTEX)
|
||||
return;
|
||||
|
||||
// release the last tex if exists
|
||||
const auto PTEX = &m_mMonitorBGTextures[pMonitor];
|
||||
PTEX->destroyTexture();
|
||||
const auto PFB = &m_mMonitorBGFBs[pMonitor];
|
||||
PFB->release();
|
||||
|
||||
PTEX->allocate();
|
||||
PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
Debug::log(LOG, "Allocated texture for BGTex");
|
||||
|
||||
// TODO: use relative paths to the installation
|
||||
// or configure the paths at build time
|
||||
std::string texPath = "/usr/share/hyprland/wall_";
|
||||
std::string prefixes[] = {"", "anime_", "anime2_"};
|
||||
if (texPath.empty()) {
|
||||
texPath = "/usr/share/hyprland/wall";
|
||||
|
||||
// get the adequate tex
|
||||
if (FORCEWALLPAPER == -1) {
|
||||
std::random_device dev;
|
||||
std::mt19937 engine(dev());
|
||||
std::mt19937_64 engine(time(nullptr));
|
||||
std::uniform_int_distribution<> distribution(0, 2);
|
||||
std::uniform_int_distribution<> distribution_anime(1, 2);
|
||||
|
||||
if (PFORCEHYPRCHAN)
|
||||
texPath += prefixes[distribution_anime(engine)];
|
||||
else
|
||||
texPath += prefixes[distribution(engine)];
|
||||
texPath += std::to_string(distribution(engine));
|
||||
} else
|
||||
texPath += prefixes[FORCEWALLPAPER];
|
||||
texPath += std::to_string(std::clamp(*PFORCEWALLPAPER, (int64_t)0, (int64_t)2));
|
||||
|
||||
Vector2D textureSize;
|
||||
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";
|
||||
}
|
||||
texPath += ".png";
|
||||
|
||||
// check if wallpapers exist
|
||||
if (!std::filesystem::exists(texPath)) {
|
||||
|
@ -1978,55 +1964,83 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
|||
if (!std::filesystem::exists(texPath))
|
||||
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
|
||||
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;
|
||||
double scale;
|
||||
|
||||
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 {
|
||||
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;
|
||||
|
||||
// create a new one with cairo
|
||||
const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str());
|
||||
const auto CAIROSURFACE = cairo_image_surface_create(CAIROFORMAT, scaledSize.x, scaledSize.y);
|
||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||
|
||||
// scale it to fit the current monitor
|
||||
cairo_scale(CAIRO, textureSize.x / pMonitor->vecTransformedSize.x, textureSize.y / pMonitor->vecTransformedSize.y);
|
||||
cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_BEST);
|
||||
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)
|
||||
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
|
||||
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);
|
||||
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_MIN_FILTER, GL_LINEAR);
|
||||
#ifndef GLES2
|
||||
if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
|
||||
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, 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(CAIROISURFACE);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2035,15 +2049,19 @@ void CHyprOpenGLImpl::clearWithTex() {
|
|||
|
||||
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);
|
||||
TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor);
|
||||
TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
|
||||
}
|
||||
|
||||
if (TEXIT != m_mMonitorBGTextures.end())
|
||||
renderTexture(TEXIT->second, &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox, 1);
|
||||
if (TEXIT != m_mMonitorBGFBs.end()) {
|
||||
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) {
|
||||
|
@ -2061,10 +2079,10 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
|
|||
g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT);
|
||||
}
|
||||
|
||||
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGTextures.find(pMonitor);
|
||||
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGTextures.end()) {
|
||||
TEXIT->second.destroyTexture();
|
||||
g_pHyprOpenGL->m_mMonitorBGTextures.erase(TEXIT);
|
||||
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGFBs.find(pMonitor);
|
||||
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGFBs.end()) {
|
||||
TEXIT->second.release();
|
||||
g_pHyprOpenGL->m_mMonitorBGFBs.erase(TEXIT);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName);
|
||||
|
|
|
@ -71,8 +71,6 @@ struct SMonitorRenderData {
|
|||
bool blurFBDirty = true;
|
||||
bool blurFBShouldRender = false;
|
||||
|
||||
CBox backgroundTexBox;
|
||||
|
||||
// Shaders
|
||||
bool m_bShadersInitialized = false;
|
||||
CShader m_shQUAD;
|
||||
|
@ -191,7 +189,7 @@ class CHyprOpenGLImpl {
|
|||
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
|
||||
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
|
||||
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
|
||||
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures;
|
||||
std::unordered_map<CMonitor*, CFramebuffer> m_mMonitorBGFBs;
|
||||
|
||||
struct {
|
||||
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,
|
||||
bool allowCustomUV = false, bool allowDim = false);
|
||||
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();
|
||||
|
||||
|
|