feat: use custom wayland layer-shell to render wallpaper to reduce vram
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
#include "wallpapersurface.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "wallpaperservice.hpp"
|
||||
|
||||
namespace ZShell::internal {
|
||||
|
||||
const QString kNamespace = "ZShell-Wallpaper";
|
||||
|
||||
void setQueue(void* proxy, struct wl_event_queue* queue) {
|
||||
wl_proxy_set_queue(static_cast<struct wl_proxy*>(proxy), queue);
|
||||
}
|
||||
|
||||
WallpaperSurface::WallpaperSurface(
|
||||
WallpaperService* service,
|
||||
wl_surface* surface,
|
||||
wl_output* output,
|
||||
const QString& screen)
|
||||
: m_service(service), m_screen(screen), m_surface(surface) {
|
||||
if (!surface) {
|
||||
qWarning() << "WallpaperSurface: no surface for" << screen;
|
||||
return;
|
||||
}
|
||||
|
||||
setQueue(m_surface, m_service->eventQueue());
|
||||
|
||||
auto* layer = m_service->m_layerShell->get_layer_surface(
|
||||
m_surface,
|
||||
output,
|
||||
QtWayland::zwlr_layer_shell_v1::layer_background,
|
||||
kNamespace);
|
||||
setQueue(layer, m_service->eventQueue());
|
||||
QtWayland::zwlr_layer_surface_v1::init(layer);
|
||||
|
||||
set_size(0, 0);
|
||||
set_anchor(anchor_top | anchor_bottom | anchor_left | anchor_right);
|
||||
set_exclusive_zone(-1);
|
||||
set_keyboard_interactivity(keyboard_interactivity_none);
|
||||
set_margin(0, 0, 0, 0);
|
||||
|
||||
auto* viewport = m_service->m_viewporter->get_viewport(m_surface);
|
||||
setQueue(viewport, m_service->eventQueue());
|
||||
QtWayland::wp_viewport::init(viewport);
|
||||
|
||||
auto* scale = m_service->m_scaleManager->get_fractional_scale(m_surface);
|
||||
setQueue(scale, m_service->eventQueue());
|
||||
QtWayland::wp_fractional_scale_v1::init(scale);
|
||||
|
||||
wl_surface_commit(m_surface);
|
||||
}
|
||||
|
||||
WallpaperSurface::~WallpaperSurface() {
|
||||
if (m_eglSurface != EGL_NO_SURFACE)
|
||||
eglDestroySurface(m_service->m_eglDisplay, m_eglSurface);
|
||||
|
||||
if (m_window) wl_egl_window_destroy(m_window);
|
||||
|
||||
if (QtWayland::wp_viewport::isInitialized())
|
||||
QtWayland::wp_viewport::destroy();
|
||||
if (QtWayland::wp_fractional_scale_v1::isInitialized())
|
||||
QtWayland::wp_fractional_scale_v1::destroy();
|
||||
if (QtWayland::zwlr_layer_surface_v1::isInitialized())
|
||||
QtWayland::zwlr_layer_surface_v1::destroy();
|
||||
|
||||
if (m_surface) wl_surface_destroy(m_surface);
|
||||
}
|
||||
|
||||
void WallpaperSurface::redraw() {
|
||||
m_service->queue(this);
|
||||
}
|
||||
|
||||
void WallpaperSurface::zwlr_layer_surface_v1_configure(
|
||||
uint32_t serial, uint32_t width, uint32_t height) {
|
||||
ack_configure(serial);
|
||||
|
||||
if (width == 0 || height == 0) return;
|
||||
|
||||
m_size = QSize(int(width), int(height));
|
||||
|
||||
if (!configured) configured = true;
|
||||
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
void WallpaperSurface::wp_fractional_scale_v1_preferred_scale(uint32_t scale) {
|
||||
if (scale == 0) return;
|
||||
|
||||
qreal newScale = qreal(scale) / 120.0;
|
||||
if (qFuzzyCompare(newScale, m_scale)) return;
|
||||
|
||||
m_scale = newScale;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
void WallpaperSurface::zwlr_layer_surface_v1_closed() {}
|
||||
|
||||
void WallpaperSurface::updateBuffer() {
|
||||
if (m_size.isEmpty()) return;
|
||||
|
||||
QSize buffer = QSize(
|
||||
int(std::llround(m_size.width() * m_scale)),
|
||||
int(std::llround(m_size.height() * m_scale)));
|
||||
|
||||
if (buffer.isEmpty()) return;
|
||||
|
||||
if (m_bufferSize != buffer) {
|
||||
m_bufferSize = buffer;
|
||||
|
||||
if (m_window) {
|
||||
wl_egl_window_resize(
|
||||
m_window, buffer.width(), buffer.height(), 0, 0);
|
||||
} else {
|
||||
m_window =
|
||||
wl_egl_window_create(m_surface, buffer.width(), buffer.height());
|
||||
if (!m_window) {
|
||||
qWarning()
|
||||
<< "WallpaperSurface: could not make a window surface for"
|
||||
<< m_screen;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_eglSurface == EGL_NO_SURFACE) {
|
||||
m_eglSurface = eglCreateWindowSurface(
|
||||
m_service->m_eglDisplay,
|
||||
m_service->m_config,
|
||||
reinterpret_cast<EGLNativeWindowType>(m_window),
|
||||
nullptr);
|
||||
if (m_eglSurface == EGL_NO_SURFACE) {
|
||||
qWarning()
|
||||
<< "WallpaperSurface: eglCreateWindowSurface failed for"
|
||||
<< m_screen;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (QtWayland::wp_viewport::isInitialized())
|
||||
set_destination(m_size.width(), m_size.height());
|
||||
|
||||
m_service->queue(this);
|
||||
}
|
||||
|
||||
} // namespace ZShell::internal
|
||||
Reference in New Issue
Block a user