#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "manager.hpp" #include "qsg.hpp" namespace qs::wayland::buffer { class WlBufferManagerPrivate; } namespace qs::wayland::buffer::dmabuf { class LinuxDmabufManager; class FourCCStr { public: explicit FourCCStr(uint32_t code) : chars( {static_cast(code >> 0 & 0xff), static_cast(code >> 8 & 0xff), static_cast(code >> 16 & 0xff), static_cast(code >> 24 & 0xff), '\0'} ) { for (auto i = 3; i != 0; i--) { if (this->chars[i] == ' ') this->chars[i] = '\0'; else break; } } [[nodiscard]] const char* cStr() const { return this->chars.data(); } private: std::array chars {}; }; class FourCCModStr { public: explicit FourCCModStr(uint64_t code): drmStr(drmGetFormatModifierName(code)) {} ~FourCCModStr() { if (this->drmStr) drmFree(this->drmStr); } Q_DISABLE_COPY_MOVE(FourCCModStr); [[nodiscard]] const char* cStr() const { return this->drmStr; } private: char* drmStr; }; QDebug& operator<<(QDebug& debug, const FourCCStr& fourcc); QDebug& operator<<(QDebug& debug, const FourCCModStr& fourcc); class GbmDeviceHandle { public: GbmDeviceHandle() = default; GbmDeviceHandle(gbm_device* device): device(device) {} GbmDeviceHandle(GbmDeviceHandle&& other) noexcept: device(other.device) { other.device = nullptr; } ~GbmDeviceHandle(); Q_DISABLE_COPY(GbmDeviceHandle); GbmDeviceHandle& operator=(GbmDeviceHandle&& other) noexcept { this->device = other.device; other.device = nullptr; return *this; } [[nodiscard]] gbm_device* operator*() const { return this->device; } [[nodiscard]] operator bool() const { return this->device; } private: gbm_device* device = nullptr; }; class WlDmaBufferQSGTexture: public WlBufferQSGTexture { public: ~WlDmaBufferQSGTexture() override; Q_DISABLE_COPY_MOVE(WlDmaBufferQSGTexture); [[nodiscard]] QSGTexture* texture() const override { return this->qsgTexture; } private: WlDmaBufferQSGTexture(EGLImage eglImage, GLuint glTexture, QSGTexture* qsgTexture) : eglImage(eglImage) , glTexture(glTexture) , qsgTexture(qsgTexture) {} EGLImage eglImage; GLuint glTexture; QSGTexture* qsgTexture; friend class WlDmaBuffer; }; class WlDmaBuffer: public WlBuffer { public: ~WlDmaBuffer() override; Q_DISABLE_COPY(WlDmaBuffer); WlDmaBuffer(WlDmaBuffer&& other) noexcept; WlDmaBuffer& operator=(WlDmaBuffer&& other) noexcept; [[nodiscard]] wl_buffer* buffer() const override { return this->mBuffer; } [[nodiscard]] QSize size() const override { return QSize(static_cast(this->width), static_cast(this->height)); } [[nodiscard]] bool isCompatible(const WlBufferRequest& request) const override; [[nodiscard]] WlBufferQSGTexture* createQsgTexture(QQuickWindow* window) const override; private: WlDmaBuffer() noexcept = default; struct Plane { int fd = 0; uint32_t offset = 0; uint32_t stride = 0; }; GbmDeviceHandle device; gbm_bo* bo = nullptr; wl_buffer* mBuffer = nullptr; int planeCount = 0; Plane* planes = nullptr; uint32_t format = 0; uint64_t modifier = 0; uint32_t width = 0; uint32_t height = 0; friend class LinuxDmabufManager; friend QDebug& operator<<(QDebug& debug, const WlDmaBuffer* buffer); }; QDebug& operator<<(QDebug& debug, const WlDmaBuffer* buffer); struct LinuxDmabufModifiers { StackList modifiers; bool implicit = false; }; struct LinuxDmabufFormatSelection { bool sorted = false; StackList, 2> formats; void ensureSorted(); }; struct LinuxDmabufTranche { dev_t device = 0; uint32_t flags = 0; LinuxDmabufFormatSelection formats; }; class LinuxDmabufFeedback: public QtWayland::zwp_linux_dmabuf_feedback_v1 { public: explicit LinuxDmabufFeedback(::zwp_linux_dmabuf_feedback_v1* feedback); ~LinuxDmabufFeedback() override; Q_DISABLE_COPY_MOVE(LinuxDmabufFeedback); protected: void zwp_linux_dmabuf_feedback_v1_main_device(wl_array* device) override; void zwp_linux_dmabuf_feedback_v1_format_table(int32_t fd, uint32_t size) override; void zwp_linux_dmabuf_feedback_v1_tranche_target_device(wl_array* device) override; void zwp_linux_dmabuf_feedback_v1_tranche_flags(uint32_t flags) override; void zwp_linux_dmabuf_feedback_v1_tranche_formats(wl_array* indices) override; void zwp_linux_dmabuf_feedback_v1_tranche_done() override; void zwp_linux_dmabuf_feedback_v1_done() override; private: dev_t mainDevice = 0; QList tranches; void* formatTable = nullptr; uint32_t formatTableSize = 0; }; class LinuxDmabufManager : public QWaylandClientExtensionTemplate , public QtWayland::zwp_linux_dmabuf_v1 { public: explicit LinuxDmabufManager(WlBufferManagerPrivate* manager); [[nodiscard]] WlBuffer* createDmabuf(const WlBufferRequest& request); [[nodiscard]] WlBuffer* createDmabuf( GbmDeviceHandle& device, uint32_t format, const LinuxDmabufModifiers& modifiers, uint32_t width, uint32_t height ); private: struct SharedGbmDevice { dev_t handle = 0; std::string renderNode; gbm_device* device = nullptr; qsizetype refcount = 0; }; void feedbackDone(); GbmDeviceHandle getGbmDevice(dev_t handle); void unrefGbmDevice(gbm_device* device); GbmDeviceHandle dupHandle(const GbmDeviceHandle& handle); QList tranches; QList gbmDevices; WlBufferManagerPrivate* manager; friend class LinuxDmabufFeedback; friend class GbmDeviceHandle; }; } // namespace qs::wayland::buffer::dmabuf