Files
z-bar-qt/Plugins/ZShell/Wallpaper/wallpaperservice.hpp
zach b0cb43f75c
C++ / fmt (pull_request) Failing after 6s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 11s
JS/TS / fmt (pull_request) Successful in 10s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Failing after 32s
Rust / build (pull_request) Successful in 52s
Python / verify (pull_request) Failing after 1m23s
Rust / fmt (pull_request) Successful in 51s
Rust / clippy (pull_request) Successful in 1m2s
feat: add vaapi path for video wallpapers on generic gpus
2026-10-27 02:15:16 +01:00

368 lines
8.1 KiB
C++

#pragma once
#include <EGL/egl.h>
#include <cstdint>
#include <mutex>
#include <thread>
#include <vector>
#include <QImage>
#include <QHash>
#include <QList>
#include <QElapsedTimer>
#include <QRectF>
#include <QSize>
#include <QString>
#include <QStringList>
#include <QVariantMap>
#include <QVector>
#include <QtQml/qqml.h>
#include <qtmetamacros.h>
#include <atomic>
#include <memory>
#include "videodecoder.hpp"
#include "wallpapercache.hpp"
#include "videotranscoder.hpp"
#include <qwayland-wlr-layer-shell-unstable-v1.h>
#include <wayland-client-protocol.h>
#include "wallpapersurface.hpp"
#include "config/enums.hpp"
struct mpv_handle;
struct mpv_render_context;
class QProcess;
namespace ZShell::wallpaper {
class WallpaperSurface;
class WallpaperService : public QObject {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged REQUIRED)
Q_PROPERTY(QVariantMap crops READ crops WRITE setCrops NOTIFY cropsChanged)
Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
Q_PROPERTY(
QSize largestBufferSize READ largestBufferSize NOTIFY
largestBufferSizeChanged)
public:
explicit WallpaperService(QObject* parent = nullptr);
~WallpaperService() override;
[[nodiscard]] QString path() const;
void setPath(const QString& path);
[[nodiscard]] QSize largestBufferSize() const;
[[nodiscard]] QString dbPath() const;
void setDbPath(const QString& path);
void addScreen(const QString& screen);
void removeScreen(const QString& screen);
[[nodiscard]] const QVariantMap& crops() const;
void setCrops(const QVariantMap& crops);
Q_INVOKABLE void redraw();
Q_INVOKABLE void setCrop(const QString& screen, const QVariantMap& crop);
Q_INVOKABLE void invalidateCache();
signals:
void pathChanged();
void cropsChanged();
void dbPathChanged();
void largestBufferSizeChanged();
private:
friend class WallpaperSurface;
static bool isVideoPath(const QString& path);
void applyPath(const QString& path);
void startVideo(const QString& path);
void teardownMpv();
void initMpvRender();
void renderMpvToSurface(const QSize& size);
void pumpMpvEvents();
static void* getMpvProcAddress(void* ctx, const char* name);
static void mpvUpdate(void* ctx);
#ifdef ZHAVE_FFMPEG
bool startDecoderVideo(const QString& path);
void stopDecoderVideo();
[[nodiscard]] uint32_t createVideoProgram();
void drawVideoTexture(
uint32_t lumaTex,
uint32_t chromaTex,
int matrix,
int range,
const QRectF& rect,
float sizeW,
float sizeH,
float srcW,
float srcH,
float alpha);
#endif
void bindGlobals();
static void registryGlobal(
void* data,
struct wl_registry* registry,
uint32_t name,
const char* interface,
uint32_t version);
void storeGlobal(const char* interface, void* proxy);
struct TransProgram {
uint32_t id = 0;
int size = -1;
int progress = -1;
int from = -1;
int to = -1;
int fromCrop = -1;
int toCrop = -1;
int fromFlip = -1;
int toFlip = -1;
};
[[nodiscard]] bool setupGl();
[[nodiscard]] uint32_t createProgram();
[[nodiscard]] TransProgram createTransitionProgram(const QString& file);
[[nodiscard]] TransProgram programFor(const QString& file);
bool ensureTransitionProgram();
QString transitionFileFor(ZShell::config::WallpaperTransition::Enum value);
[[nodiscard]] QString randomTransitionFile();
void ensureCapture(const QSize& size);
uint32_t renderVideoIntoTexture(const QSize& size);
void drawSurfaceTransition(WallpaperSurface* surface);
struct TransitionLayer {
uint32_t tex = 0;
QImage image;
QVariantMap crops;
QString transitionFile;
bool isVideo = false;
bool ready = false;
bool started = false;
QElapsedTimer timer;
qreal progress = 0.0;
};
void ensureBaseFbo();
void ensureAccum(const QSize& size);
void bindRtt(uint32_t fbo, uint32_t tex, const QSize& size);
void drawTransitionPair(
const TransProgram& program,
uint32_t fromTex,
float fromFlip,
const QRectF& fromCrop,
uint32_t toTex,
float toFlip,
const QRectF& toCrop,
qreal progress,
const QSize& size);
uint32_t targetTexFor(const TransitionLayer& layer, int index) const;
QRectF cropForLayer(
const TransitionLayer& layer,
const QString& screen,
const QSize& size) const;
void captureBase(
const QSize& size,
const QString& screen,
uint32_t oldTex,
float oldFlip,
const QRectF& oldCrop);
void renderComposite(
const QSize& size,
const QString& screen,
uint32_t outFbo,
uint32_t outTex,
int first,
int last,
uint32_t videoTex,
uint32_t posterTex);
void uploadTexture(uint32_t& texture, const QImage& image);
void uploadImage();
void createBlackTexture(uint32_t& texture);
void drawTexture(
uint32_t texture,
const QRectF& rect,
float sizeW,
float sizeH,
float alpha);
void ensureImage();
void ensurePoster();
void notifyBufferSizes();
void queue(WallpaperSurface* surface);
void queueAll();
void loop();
void present();
void drawSurface(WallpaperSurface* surface);
void wake();
[[nodiscard]] wl_event_queue* eventQueue() const { return m_queue; }
[[nodiscard]] QRectF sourceRect(
const QVariantMap& crops,
const QString& screen,
const QSize& size,
const QSize& image) const;
void start();
void addSurfaces();
void addSurface(const QString& screen);
QString m_path;
QString m_dbPath;
QStringList m_screens;
QVariantMap m_crops;
WallpaperCache m_cache;
QImage m_image;
bool m_isVideo = false;
bool m_videoReload = false;
mpv_handle* m_mpv = nullptr;
mpv_render_context* m_mpvRender = nullptr;
uint32_t m_blackTex = 0;
std::atomic<bool> m_mpvFrameReady{false};
std::atomic<bool> m_videoReady{false};
std::atomic<bool> m_videoLoaded{false};
VideoTranscoder* m_transcoder = nullptr;
QSize m_decodeSize;
QImage m_stagedImage;
QString m_stagedPath;
bool m_stagedReady = false;
bool m_decoding = false;
QString m_decodePath;
bool m_replacementReady = false;
wl_display* m_display = nullptr;
wl_registry* m_registry = nullptr;
wl_compositor* m_compositor = nullptr;
QtWayland::zwlr_layer_shell_v1* m_layerShell = nullptr;
QtWayland::wp_viewporter* m_viewporter = nullptr;
QtWayland::wp_fractional_scale_manager_v1* m_scaleManager = nullptr;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
EGLConfig m_config = nullptr;
EGLContext m_context = EGL_NO_CONTEXT;
uint32_t m_texture = 0;
uint32_t m_program = 0;
int m_sizeUniform = -1;
int m_cropUniform = -1;
int m_alphaUniform = -1;
int m_sourceUniform = -1;
bool m_randomTransition = false;
QString m_transitionFile;
bool m_transitionDirty = false;
QHash<QString, TransProgram> m_transPrograms;
TransProgram m_neutralProgram;
QVector<int> m_transitionUses;
QString m_lastTransition;
uint32_t m_captureFbo = 0;
uint32_t m_captureTex = 0;
QSize m_captureSize;
uint32_t m_baseFbo = 0;
uint32_t m_baseTex = 0;
QSize m_baseSize;
bool m_baseReady = false;
uint32_t m_accumFbo = 0;
uint32_t m_accumA = 0;
uint32_t m_accumB = 0;
QSize m_accumSize;
std::vector<TransitionLayer> m_transitions;
bool m_needCaptureBase = false;
QImage m_baseImage;
QVariantMap m_baseCrops;
bool m_baseIsVideo = false;
bool m_baseIsBlack = false;
bool m_collapseVideo = false;
bool m_promoteOldest = false;
bool m_newestDone = false;
static constexpr int kMaxTransitions = 4;
uint32_t m_videoProgram = 0;
uint32_t m_vao = 0;
int m_videoSizeUniform = -1;
int m_videoSrcSizeUniform = -1;
int m_videoCropUniform = -1;
int m_videoAlphaUniform = -1;
int m_videoLumaUniform = -1;
int m_videoChromaUniform = -1;
int m_videoMatrixUniform = -1;
int m_videoRangeUniform = -1;
int m_videoChromaOffUniform = -1;
#ifdef ZHAVE_FFMPEG
std::unique_ptr<VideoDecoder> m_decoder;
bool m_useDecoder = true;
#endif
std::vector<uint32_t> m_orphanTextures;
bool m_programsCompiled = false;
QList<WallpaperSurface*> m_surfaces;
std::thread m_thread;
mutable std::recursive_mutex m_mutex;
wl_event_queue* m_queue = nullptr;
int m_wake[2] = {-1, -1};
bool m_stop = false;
bool m_drawing = false;
bool started = false;
bool m_forceDecode = false;
bool m_imageChanged = false;
QImage m_posterImage;
uint32_t m_posterTex = 0;
QString m_posterPath;
bool m_posterReady = false;
bool m_posterLoading = false;
bool m_posterChanged = false;
};
} // namespace ZShell::wallpaper