diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d19f58..66c3691 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,6 @@ jobs: wayland-protocols \ wayland \ libdrm \ - vulkan-headers \ libxcb \ libpipewire \ cli11 \ diff --git a/BUILD.md b/BUILD.md index c9459b5..fdea27e 100644 --- a/BUILD.md +++ b/BUILD.md @@ -146,7 +146,6 @@ To disable: `-DSCREENCOPY=OFF` Dependencies: - `libdrm` - `libgbm` -- `vulkan-headers` (build-time) Specific protocols can also be disabled: - `DSCREENCOPY_ICC=OFF` - Disable screencopy via [ext-image-copy-capture-v1] diff --git a/changelog/next.md b/changelog/next.md index 7180d53..30e998b 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -24,8 +24,6 @@ set shell id. - Added support for grabbing focus from popup windows. - Added support for IPC signal listeners. - Added Quickshell version checking and version gated preprocessing. -- Added a way to detect if an icon is from the system icon theme or not. -- Added vulkan support to screencopy. ## Other Changes @@ -37,7 +35,6 @@ set shell id. - Fixed volume control breaking with pipewire pro audio mode. - Fixed volume control breaking with bluez streams and potentially others. -- Fixed volume control breaking for devices without route definitions. - Fixed escape sequence handling in desktop entries. - Fixed volumes not initializing if a pipewire device was already loaded before its node. - Fixed hyprland active toplevel not resetting after window closes. @@ -46,10 +43,7 @@ set shell id. - Fixed asynchronous loaders not working after reload. - Fixed asynchronous loaders not working before window creation. - Fixed memory leak in IPC handlers. -- Fixed ClippingRectangle related crashes. -- Fixed crashes when monitors are unplugged. ## Packaging Changes `glib` and `polkit` have been added as dependencies when compiling with polkit agent support. -`vulkan-headers` has been added as a build-time dependency for screencopy (Vulkan backend support). diff --git a/default.nix b/default.nix index 7783774..0b6f303 100644 --- a/default.nix +++ b/default.nix @@ -19,7 +19,6 @@ xorg, libdrm, libgbm ? null, - vulkan-headers, pipewire, pam, polkit, @@ -78,7 +77,7 @@ ++ lib.optional withJemalloc jemalloc ++ lib.optional (withWayland && lib.strings.compareVersions qt6.qtbase.version "6.10.0" == -1) qt6.qtwayland ++ lib.optionals withWayland [ wayland wayland-protocols ] - ++ lib.optionals (withWayland && libgbm != null) [ libdrm libgbm vulkan-headers ] + ++ lib.optionals (withWayland && libgbm != null) [ libdrm libgbm ] ++ lib.optional withX11 xorg.libxcb ++ lib.optional withPam pam ++ lib.optional withPipewire pipewire diff --git a/src/core/qmlglobal.cpp b/src/core/qmlglobal.cpp index 6c26609..03fb818 100644 --- a/src/core/qmlglobal.cpp +++ b/src/core/qmlglobal.cpp @@ -314,8 +314,6 @@ QString QuickshellGlobal::iconPath(const QString& icon, const QString& fallback) return IconImageProvider::requestString(icon, "", fallback); } -bool QuickshellGlobal::hasThemeIcon(const QString& icon) { return QIcon::hasThemeIcon(icon); } - bool QuickshellGlobal::hasVersion(qint32 major, qint32 minor, const QStringList& features) { return qs::scan::env::PreprocEnv::hasVersion(major, minor, features); } diff --git a/src/core/qmlglobal.hpp b/src/core/qmlglobal.hpp index 94b42f6..3ca70be 100644 --- a/src/core/qmlglobal.hpp +++ b/src/core/qmlglobal.hpp @@ -202,8 +202,6 @@ public: /// Setting the `fallback` parameter of `iconPath` will attempt to load the fallback /// icon if the requested one could not be loaded. Q_INVOKABLE static QString iconPath(const QString& icon, const QString& fallback); - /// Check if specified icon has an available icon in your icon theme - Q_INVOKABLE static bool hasThemeIcon(const QString& icon); /// Equivalent to `${Quickshell.configDir}/${path}` Q_INVOKABLE [[nodiscard]] QString shellPath(const QString& path) const; /// > [!WARNING] Deprecated: Renamed to @@shellPath() for clarity. diff --git a/src/core/scan.cpp b/src/core/scan.cpp index 37b0fac..8ca1f51 100644 --- a/src/core/scan.cpp +++ b/src/core/scan.cpp @@ -118,7 +118,7 @@ bool QmlScanner::scanQmlFile(const QString& path, bool& singleton, bool& interna auto stream = QTextStream(&file); auto imports = QVector(); - bool inHeader = true; + bool inHeader = false; auto ifScopes = QVector(); bool sourceMasked = false; int lineNum = 0; @@ -177,7 +177,7 @@ bool QmlScanner::scanQmlFile(const QString& path, bool& singleton, bool& interna } else if (!internal && line == "//@ pragma Internal") { internal = true; } else if (line.contains('{')) { - inHeader = false; + inHeader = true; } } diff --git a/src/core/scanenv.cpp b/src/core/scanenv.cpp index 047f472..b8c514c 100644 --- a/src/core/scanenv.cpp +++ b/src/core/scanenv.cpp @@ -1,7 +1,6 @@ #include "scanenv.hpp" #include -#include #include "build.hpp" @@ -20,12 +19,4 @@ bool PreprocEnv::hasVersion(int major, int minor, const QStringList& features) { return QS_VERSION_MAJOR == major && QS_VERSION_MINOR == minor; } -QString PreprocEnv::env(const QString& variable) { - return qEnvironmentVariable(variable.toStdString().c_str()); -} - -bool PreprocEnv::isEnvSet(const QString& variable) { - return qEnvironmentVariableIsSet(variable.toStdString().c_str()); -} - } // namespace qs::scan::env diff --git a/src/core/scanenv.hpp b/src/core/scanenv.hpp index c1c6814..0abde2e 100644 --- a/src/core/scanenv.hpp +++ b/src/core/scanenv.hpp @@ -12,9 +12,6 @@ class PreprocEnv: public QObject { public: Q_INVOKABLE static bool hasVersion(int major, int minor, const QStringList& features = QStringList()); - - Q_INVOKABLE static QString env(const QString& variable); - Q_INVOKABLE static bool isEnvSet(const QString& variable); }; } // namespace qs::scan::env diff --git a/src/ipc/ipc.cpp b/src/ipc/ipc.cpp index 40e8f0c..32d8482 100644 --- a/src/ipc/ipc.cpp +++ b/src/ipc/ipc.cpp @@ -61,7 +61,7 @@ IpcServerConnection::IpcServerConnection(QLocalSocket* socket, IpcServer* server void IpcServerConnection::onDisconnected() { qCInfo(logIpc) << "IPC connection disconnected" << this; - this->deleteLater(); + delete this; } void IpcServerConnection::onReadyRead() { @@ -88,7 +88,7 @@ void IpcServerConnection::onReadyRead() { // async connections reparent if (dynamic_cast(this->parent()) != nullptr) { - this->deleteLater(); + delete this; } } diff --git a/src/services/pipewire/device.cpp b/src/services/pipewire/device.cpp index 61079a1..e3bc967 100644 --- a/src/services/pipewire/device.cpp +++ b/src/services/pipewire/device.cpp @@ -141,10 +141,6 @@ bool PwDevice::tryLoadVolumeProps(qint32 routeDevice, PwVolumeProps& volumeProps return true; } -bool PwDevice::hasRouteDevice(qint32 routeDevice) const { - return this->routeDeviceIndexes.contains(routeDevice); -} - void PwDevice::polled() { // It is far more likely that the list content has not come in yet than it having no entries, // and there isn't a way to check in the case that there *aren't* actually any entries. diff --git a/src/services/pipewire/device.hpp b/src/services/pipewire/device.hpp index cd61709..22af699 100644 --- a/src/services/pipewire/device.hpp +++ b/src/services/pipewire/device.hpp @@ -12,15 +12,13 @@ #include #include "core.hpp" +#include "node.hpp" #include "registry.hpp" namespace qs::service::pipewire { class PwDevice; -// Forward declare to avoid circular dependency with node.hpp -struct PwVolumeProps; - class PwDevice: public PwBindable { Q_OBJECT; @@ -35,7 +33,6 @@ public: [[nodiscard]] bool waitingForDevice() const; [[nodiscard]] bool tryLoadVolumeProps(qint32 routeDevice, PwVolumeProps& volumeProps); - [[nodiscard]] bool hasRouteDevice(qint32 routeDevice) const; signals: void deviceReady(); diff --git a/src/services/pipewire/node.cpp b/src/services/pipewire/node.cpp index 075a7ec..b6f0529 100644 --- a/src/services/pipewire/node.cpp +++ b/src/services/pipewire/node.cpp @@ -429,10 +429,6 @@ void PwNodeBoundAudio::setMuted(bool muted) { } float PwNodeBoundAudio::averageVolume() const { - if (this->mVolumes.isEmpty()) { - return 0.0f; - } - float total = 0; for (auto volume: this->mVolumes) { @@ -576,28 +572,22 @@ PwVolumeProps PwVolumeProps::parseSpaPod(const spa_pod* param) { const auto* muteProp = spa_pod_find_prop(param, nullptr, SPA_PROP_mute); const auto* volumeStepProp = spa_pod_find_prop(param, nullptr, SPA_PROP_volumeStep); - if (volumesProp) { - const auto* volumes = reinterpret_cast(&volumesProp->value); - spa_pod* iter = nullptr; - SPA_POD_ARRAY_FOREACH(volumes, iter) { - // Cubing behavior found in MPD source, and appears to corrospond to everyone else's measurements correctly. - auto linear = *reinterpret_cast(iter); - auto visual = std::cbrt(linear); - props.volumes.push_back(visual); - } + const auto* volumes = reinterpret_cast(&volumesProp->value); + const auto* channels = reinterpret_cast(&channelsProp->value); + + spa_pod* iter = nullptr; + SPA_POD_ARRAY_FOREACH(volumes, iter) { + // Cubing behavior found in MPD source, and appears to corrospond to everyone else's measurements correctly. + auto linear = *reinterpret_cast(iter); + auto visual = std::cbrt(linear); + props.volumes.push_back(visual); } - if (channelsProp) { - const auto* channels = reinterpret_cast(&channelsProp->value); - spa_pod* iter = nullptr; - SPA_POD_ARRAY_FOREACH(channels, iter) { - props.channels.push_back(*reinterpret_cast(iter)); - } + SPA_POD_ARRAY_FOREACH(channels, iter) { + props.channels.push_back(*reinterpret_cast(iter)); } - if (muteProp) { - spa_pod_get_bool(&muteProp->value, &props.mute); - } + spa_pod_get_bool(&muteProp->value, &props.mute); if (volumeStepProp) { spa_pod_get_float(&volumeStepProp->value, &props.volumeStep); diff --git a/src/services/pipewire/node.hpp b/src/services/pipewire/node.hpp index efc819c..fdec72d 100644 --- a/src/services/pipewire/node.hpp +++ b/src/services/pipewire/node.hpp @@ -15,7 +15,6 @@ #include #include "core.hpp" -#include "device.hpp" #include "registry.hpp" namespace qs::service::pipewire { @@ -250,9 +249,7 @@ public: bool proAudio = false; [[nodiscard]] bool shouldUseDevice() const { - if (!this->device || this->proAudio || this->routeDevice == -1) return false; - // Only use device control if the device actually has route indexes for this routeDevice - return this->device->hasRouteDevice(this->routeDevice); + return this->device && !this->proAudio && this->routeDevice != -1; } signals: diff --git a/src/wayland/buffer/CMakeLists.txt b/src/wayland/buffer/CMakeLists.txt index 15818fc..f80c53a 100644 --- a/src/wayland/buffer/CMakeLists.txt +++ b/src/wayland/buffer/CMakeLists.txt @@ -1,8 +1,6 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(dmabuf-deps REQUIRED IMPORTED_TARGET libdrm gbm egl) -find_package(VulkanHeaders REQUIRED) - qt_add_library(quickshell-wayland-buffer STATIC manager.cpp dmabuf.cpp @@ -12,10 +10,9 @@ qt_add_library(quickshell-wayland-buffer STATIC wl_proto(wlp-linux-dmabuf linux-dmabuf-v1 "${WAYLAND_PROTOCOLS}/stable/linux-dmabuf") target_link_libraries(quickshell-wayland-buffer PRIVATE - Qt::Quick Qt::QuickPrivate Qt::GuiPrivate Qt::WaylandClient Qt::WaylandClientPrivate wayland-client + Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client PkgConfig::dmabuf-deps wlp-linux-dmabuf - Vulkan::Headers ) qs_pch(quickshell-wayland-buffer SET large) diff --git a/src/wayland/buffer/dmabuf.cpp b/src/wayland/buffer/dmabuf.cpp index ed9dbeb..e51a1d0 100644 --- a/src/wayland/buffer/dmabuf.cpp +++ b/src/wayland/buffer/dmabuf.cpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -26,17 +24,12 @@ #include #include #include -#include #include -#include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -55,36 +48,6 @@ QS_LOGGING_CATEGORY(logDmabuf, "quickshell.wayland.buffer.dmabuf", QtWarningMsg) LinuxDmabufManager* MANAGER = nullptr; // NOLINT -VkFormat drmFormatToVkFormat(uint32_t drmFormat) { - // NOLINTBEGIN(bugprone-branch-clone): XRGB/ARGB intentionally map to the same VK format - switch (drmFormat) { - case DRM_FORMAT_ARGB8888: return VK_FORMAT_B8G8R8A8_UNORM; - case DRM_FORMAT_XRGB8888: return VK_FORMAT_B8G8R8A8_UNORM; - case DRM_FORMAT_ABGR8888: return VK_FORMAT_R8G8B8A8_UNORM; - case DRM_FORMAT_XBGR8888: return VK_FORMAT_R8G8B8A8_UNORM; - case DRM_FORMAT_ARGB2101010: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; - case DRM_FORMAT_XRGB2101010: return VK_FORMAT_A2R10G10B10_UNORM_PACK32; - case DRM_FORMAT_ABGR2101010: return VK_FORMAT_A2B10G10R10_UNORM_PACK32; - case DRM_FORMAT_XBGR2101010: return VK_FORMAT_A2B10G10R10_UNORM_PACK32; - case DRM_FORMAT_ABGR16161616F: return VK_FORMAT_R16G16B16A16_SFLOAT; - case DRM_FORMAT_RGB565: return VK_FORMAT_R5G6B5_UNORM_PACK16; - case DRM_FORMAT_BGR565: return VK_FORMAT_B5G6R5_UNORM_PACK16; - default: return VK_FORMAT_UNDEFINED; - } - // NOLINTEND(bugprone-branch-clone) -} - -bool drmFormatHasAlpha(uint32_t drmFormat) { - switch (drmFormat) { - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_ABGR16161616F: return true; - default: return false; - } -} - } // namespace QDebug& operator<<(QDebug& debug, const FourCCStr& fourcc) { @@ -118,27 +81,25 @@ GbmDeviceHandle::~GbmDeviceHandle() { } } -// Prefer ARGB over XRGB: XRGB has undefined alpha bytes which cause -// transparency artifacts on Vulkan (notably Intel GPUs) since Vulkan -// doesn't auto-fill alpha=1.0 for X formats like EGL does. +// This will definitely backfire later void LinuxDmabufFormatSelection::ensureSorted() { if (this->sorted) return; auto beginIter = this->formats.begin(); - auto argbIter = std::ranges::find_if(this->formats, [](const auto& format) { - return format.first == DRM_FORMAT_ARGB8888; - }); - - if (argbIter != this->formats.end()) { - std::swap(*beginIter, *argbIter); - ++beginIter; - } - auto xrgbIter = std::ranges::find_if(this->formats, [](const auto& format) { return format.first == DRM_FORMAT_XRGB8888; }); - if (xrgbIter != this->formats.end()) std::swap(*beginIter, *xrgbIter); + if (xrgbIter != this->formats.end()) { + std::swap(*beginIter, *xrgbIter); + ++beginIter; + } + + auto argbIter = std::ranges::find_if(this->formats, [](const auto& format) { + return format.first == DRM_FORMAT_ARGB8888; + }); + + if (argbIter != this->formats.end()) std::swap(*beginIter, *argbIter); this->sorted = true; } @@ -571,15 +532,6 @@ bool WlDmaBuffer::isCompatible(const WlBufferRequest& request) const { } WlBufferQSGTexture* WlDmaBuffer::createQsgTexture(QQuickWindow* window) const { - auto* ri = window->rendererInterface(); - if (ri && ri->graphicsApi() == QSGRendererInterface::Vulkan) { - return this->createQsgTextureVulkan(window); - } - - return this->createQsgTextureGl(window); -} - -WlBufferQSGTexture* WlDmaBuffer::createQsgTextureGl(QQuickWindow* window) const { static auto* glEGLImageTargetTexture2DOES = []() { auto* fn = reinterpret_cast( eglGetProcAddress("glEGLImageTargetTexture2DOES") @@ -710,313 +662,6 @@ WlBufferQSGTexture* WlDmaBuffer::createQsgTextureGl(QQuickWindow* window) const return tex; } -WlBufferQSGTexture* WlDmaBuffer::createQsgTextureVulkan(QQuickWindow* window) const { - auto* ri = window->rendererInterface(); - auto* vkInst = window->vulkanInstance(); - - if (!vkInst) { - qCWarning(logDmabuf) << "Failed to create Vulkan QSG texture: no QVulkanInstance."; - return nullptr; - } - - auto* vkDevicePtr = - static_cast(ri->getResource(window, QSGRendererInterface::DeviceResource)); - auto* vkPhysDevicePtr = static_cast( - ri->getResource(window, QSGRendererInterface::PhysicalDeviceResource) - ); - - if (!vkDevicePtr || !vkPhysDevicePtr) { - qCWarning(logDmabuf) << "Failed to create Vulkan QSG texture: could not get Vulkan device."; - return nullptr; - } - - VkDevice device = *vkDevicePtr; - VkPhysicalDevice physDevice = *vkPhysDevicePtr; - - auto* devFuncs = vkInst->deviceFunctions(device); - auto* instFuncs = vkInst->functions(); - - if (!devFuncs || !instFuncs) { - qCWarning(logDmabuf) << "Failed to create Vulkan QSG texture: " - "could not get Vulkan functions."; - return nullptr; - } - - auto getMemoryFdPropertiesKHR = reinterpret_cast( - instFuncs->vkGetDeviceProcAddr(device, "vkGetMemoryFdPropertiesKHR") - ); - - if (!getMemoryFdPropertiesKHR) { - qCWarning(logDmabuf) << "Failed to create Vulkan QSG texture: " - "vkGetMemoryFdPropertiesKHR not available. " - "Missing VK_KHR_external_memory_fd extension."; - return nullptr; - } - - const VkFormat vkFormat = drmFormatToVkFormat(this->format); - if (vkFormat == VK_FORMAT_UNDEFINED) { - qCWarning(logDmabuf) << "Failed to create Vulkan QSG texture: unsupported DRM format" - << FourCCStr(this->format); - return nullptr; - } - - if (this->planeCount > 4) { - qCWarning(logDmabuf) << "Failed to create Vulkan QSG texture: too many planes" - << this->planeCount; - return nullptr; - } - - std::array planeLayouts = {}; - for (int i = 0; i < this->planeCount; ++i) { - planeLayouts[i].offset = this->planes[i].offset; // NOLINT - planeLayouts[i].rowPitch = this->planes[i].stride; // NOLINT - planeLayouts[i].size = 0; - planeLayouts[i].arrayPitch = 0; - planeLayouts[i].depthPitch = 0; - } - - const bool useModifier = this->modifier != DRM_FORMAT_MOD_INVALID; - - VkExternalMemoryImageCreateInfo externalInfo = {}; - externalInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; - externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - - VkImageDrmFormatModifierExplicitCreateInfoEXT modifierInfo = {}; - modifierInfo.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; - modifierInfo.drmFormatModifier = this->modifier; - modifierInfo.drmFormatModifierPlaneCount = static_cast(this->planeCount); - modifierInfo.pPlaneLayouts = planeLayouts.data(); - - if (useModifier) { - externalInfo.pNext = &modifierInfo; - } - - VkImageCreateInfo imageInfo = {}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.pNext = &externalInfo; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.format = vkFormat; - imageInfo.extent = {.width = this->width, .height = this->height, .depth = 1}; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.tiling = useModifier ? VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT : VK_IMAGE_TILING_LINEAR; - imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - VkImage image = VK_NULL_HANDLE; - VkResult result = devFuncs->vkCreateImage(device, &imageInfo, nullptr, &image); - if (result != VK_SUCCESS) { - qCWarning(logDmabuf) << "Failed to create VkImage for DMA-BUF import, result:" << result; - return nullptr; - } - - VkDeviceMemory memory = VK_NULL_HANDLE; - - // dup() is required because vkAllocateMemory with VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT - // takes ownership of the fd on succcess. Without dup, WlDmaBuffer would double-close. - const int dupFd = - dup(this->planes[0].fd); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - if (dupFd < 0) { - qCWarning(logDmabuf) << "Failed to dup() fd for DMA-BUF import"; - goto cleanup_fail; // NOLINT - } - - { - VkMemoryRequirements memReqs = {}; - devFuncs->vkGetImageMemoryRequirements(device, image, &memReqs); - - VkMemoryFdPropertiesKHR fdProps = {}; - fdProps.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR; - - result = getMemoryFdPropertiesKHR( - device, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - dupFd, - &fdProps - ); - - if (result != VK_SUCCESS) { - close(dupFd); - qCWarning(logDmabuf) << "vkGetMemoryFdPropertiesKHR failed, result:" << result; - goto cleanup_fail; // NOLINT - } - - const uint32_t memTypeBits = memReqs.memoryTypeBits & fdProps.memoryTypeBits; - - VkPhysicalDeviceMemoryProperties memProps = {}; - instFuncs->vkGetPhysicalDeviceMemoryProperties(physDevice, &memProps); - - uint32_t memTypeIndex = UINT32_MAX; - for (uint32_t j = 0; j < memProps.memoryTypeCount; ++j) { - if (memTypeBits & (1u << j)) { - memTypeIndex = j; - break; - } - } - - if (memTypeIndex == UINT32_MAX) { - close(dupFd); - qCWarning(logDmabuf) << "No compatible memory type for DMA-BUF import"; - goto cleanup_fail; // NOLINT - } - - VkImportMemoryFdInfoKHR importInfo = {}; - importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; - importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - importInfo.fd = dupFd; - - VkMemoryDedicatedAllocateInfo dedicatedInfo = {}; - dedicatedInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; - dedicatedInfo.image = image; - dedicatedInfo.pNext = &importInfo; - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.pNext = &dedicatedInfo; - allocInfo.allocationSize = memReqs.size; - allocInfo.memoryTypeIndex = memTypeIndex; - - result = devFuncs->vkAllocateMemory(device, &allocInfo, nullptr, &memory); - if (result != VK_SUCCESS) { - close(dupFd); - qCWarning(logDmabuf) << "vkAllocateMemory failed, result:" << result; - goto cleanup_fail; // NOLINT - } - - result = devFuncs->vkBindImageMemory(device, image, memory, 0); - if (result != VK_SUCCESS) { - qCWarning(logDmabuf) << "vkBindImageMemory failed, result:" << result; - goto cleanup_fail; // NOLINT - } - } - - { - // acquire the DMA-BUF from the foreign (compositor) queue and transition - // to shader-read layout. oldLayout must be GENERAL (not UNDEFINED) to - // preserve the DMA-BUF contents written by the external producer. Hopefully. - window->beginExternalCommands(); - - auto* cmdBufPtr = static_cast( - ri->getResource(window, QSGRendererInterface::CommandListResource) - ); - - if (cmdBufPtr && *cmdBufPtr) { - VkCommandBuffer cmdBuf = *cmdBufPtr; - - // find the graphics queue family index for the ownrship transfer. - uint32_t graphicsQueueFamily = 0; - uint32_t queueFamilyCount = 0; - instFuncs->vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, nullptr); - std::vector queueFamilies(queueFamilyCount); - instFuncs->vkGetPhysicalDeviceQueueFamilyProperties( - physDevice, - &queueFamilyCount, - queueFamilies.data() - ); - for (uint32_t i = 0; i < queueFamilyCount; ++i) { - if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - graphicsQueueFamily = i; - break; - } - } - - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT; - barrier.dstQueueFamilyIndex = graphicsQueueFamily; - barrier.image = image; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.srcAccessMask = 0; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - devFuncs->vkCmdPipelineBarrier( - cmdBuf, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, - nullptr, - 0, - nullptr, - 1, - &barrier - ); - } - - window->endExternalCommands(); - - auto* qsgTexture = QQuickWindowPrivate::get(window)->createTextureFromNativeTexture( - reinterpret_cast(image), - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - static_cast(vkFormat), - QSize(static_cast(this->width), static_cast(this->height)), - {} - ); - - // For opaque DRM formats (XRGB, XBGR, etc.), the alpha bytes are underfined. - // EGL silently forces alpha=1.0 for these, but Vulkan doesn't. Replace Qt's - // default identity-swizzle VkImageView with one that maps alpha to ONE. - if (!drmFormatHasAlpha(this->format)) { - auto* vkTexture = static_cast(qsgTexture->rhiTexture()); // NOLINT - - devFuncs->vkDestroyImageView(device, vkTexture->imageView, nullptr); - - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = vkFormat; - viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.layerCount = 1; - - result = devFuncs->vkCreateImageView(device, &viewInfo, nullptr, &vkTexture->imageView); - if (result != VK_SUCCESS) { - qCWarning(logDmabuf) << "Failed to create alpha-swizzled VkImageView, result:" << result; - } - } - - auto* tex = new WlDmaBufferVulkanQSGTexture(devFuncs, device, image, memory, qsgTexture); - qCDebug(logDmabuf) << "Created WlDmaBufferVulkanQSGTexture" << tex << "from" << this; - return tex; - } - -cleanup_fail: - if (image != VK_NULL_HANDLE) { - devFuncs->vkDestroyImage(device, image, nullptr); - } - if (memory != VK_NULL_HANDLE) { - devFuncs->vkFreeMemory(device, memory, nullptr); - } - return nullptr; -} - -WlDmaBufferVulkanQSGTexture::~WlDmaBufferVulkanQSGTexture() { - delete this->qsgTexture; - - if (this->image != VK_NULL_HANDLE) { - this->devFuncs->vkDestroyImage(this->device, this->image, nullptr); - } - - if (this->memory != VK_NULL_HANDLE) { - this->devFuncs->vkFreeMemory(this->device, this->memory, nullptr); - } - - qCDebug(logDmabuf) << "WlDmaBufferVulkanQSGTexture" << this << "destroyed."; -} - WlDmaBufferQSGTexture::~WlDmaBufferQSGTexture() { auto* context = QOpenGLContext::currentContext(); auto* display = context->nativeInterface()->display(); diff --git a/src/wayland/buffer/dmabuf.hpp b/src/wayland/buffer/dmabuf.hpp index ffe5d02..1e4ef1a 100644 --- a/src/wayland/buffer/dmabuf.hpp +++ b/src/wayland/buffer/dmabuf.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -13,11 +12,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -117,36 +114,6 @@ private: friend class WlDmaBuffer; }; -class WlDmaBufferVulkanQSGTexture: public WlBufferQSGTexture { -public: - ~WlDmaBufferVulkanQSGTexture() override; - Q_DISABLE_COPY_MOVE(WlDmaBufferVulkanQSGTexture); - - [[nodiscard]] QSGTexture* texture() const override { return this->qsgTexture; } - -private: - WlDmaBufferVulkanQSGTexture( - QVulkanDeviceFunctions* devFuncs, - VkDevice device, - VkImage image, - VkDeviceMemory memory, - QSGTexture* qsgTexture - ) - : devFuncs(devFuncs) - , device(device) - , image(image) - , memory(memory) - , qsgTexture(qsgTexture) {} - - QVulkanDeviceFunctions* devFuncs = nullptr; - VkDevice device = VK_NULL_HANDLE; - VkImage image = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; - QSGTexture* qsgTexture = nullptr; - - friend class WlDmaBuffer; -}; - class WlDmaBuffer: public WlBuffer { public: ~WlDmaBuffer() override; @@ -184,9 +151,6 @@ private: friend class LinuxDmabufManager; friend QDebug& operator<<(QDebug& debug, const WlDmaBuffer* buffer); - - [[nodiscard]] WlBufferQSGTexture* createQsgTextureGl(QQuickWindow* window) const; - [[nodiscard]] WlBufferQSGTexture* createQsgTextureVulkan(QQuickWindow* window) const; }; QDebug& operator<<(QDebug& debug, const WlDmaBuffer* buffer); diff --git a/src/wayland/session_lock.cpp b/src/wayland/session_lock.cpp index 2ebe3fd..d5a3e53 100644 --- a/src/wayland/session_lock.cpp +++ b/src/wayland/session_lock.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -217,15 +216,6 @@ void WlSessionLockSurface::onReload(QObject* oldInstance) { if (this->window == nullptr) { this->window = new QQuickWindow(); - - // needed for vulkan dmabuf import, qt ignores these if not applicable - auto graphicsConfig = this->window->graphicsConfiguration(); - graphicsConfig.setDeviceExtensions({ - "VK_KHR_external_memory_fd", - "VK_EXT_external_memory_dma_buf", - "VK_EXT_image_drm_format_modifier", - }); - this->window->setGraphicsConfiguration(graphicsConfig); } this->mContentItem->setParentItem(this->window->contentItem()); diff --git a/src/wayland/session_lock/surface.cpp b/src/wayland/session_lock/surface.cpp index c73f459..6ec4eb6 100644 --- a/src/wayland/session_lock/surface.cpp +++ b/src/wayland/session_lock/surface.cpp @@ -28,7 +28,7 @@ QSWaylandSessionLockSurface::QSWaylandSessionLockSurface(QtWaylandClient::QWayla wl_output* output = nullptr; // NOLINT (include) auto* waylandScreen = dynamic_cast(qwindow->screen()->handle()); - if (waylandScreen != nullptr && !waylandScreen->isPlaceholder() && waylandScreen->output()) { + if (waylandScreen != nullptr) { output = waylandScreen->output(); } else { qFatal() << "Session lock screen does not corrospond to a real screen. Force closing window"; diff --git a/src/wayland/wlr_layershell/surface.cpp b/src/wayland/wlr_layershell/surface.cpp index 4a5015e..3c71ff9 100644 --- a/src/wayland/wlr_layershell/surface.cpp +++ b/src/wayland/wlr_layershell/surface.cpp @@ -143,11 +143,11 @@ LayerSurface::LayerSurface(LayerShellIntegration* shell, QtWaylandClient::QWayla auto* waylandScreen = dynamic_cast(qwindow->screen()->handle()); - if (waylandScreen != nullptr && !waylandScreen->isPlaceholder() && waylandScreen->output()) { + if (waylandScreen != nullptr) { output = waylandScreen->output(); } else { qWarning() - << "Layershell screen does not correspond to a real screen. Letting the compositor pick."; + << "Layershell screen does not corrospond to a real screen. Letting the compositor pick."; } } diff --git a/src/widgets/ClippingRectangle.qml b/src/widgets/ClippingRectangle.qml index 604f346..86fe601 100644 --- a/src/widgets/ClippingRectangle.qml +++ b/src/widgets/ClippingRectangle.qml @@ -1,5 +1,3 @@ -pragma ComponentBehavior: Bound - import QtQuick ///! Rectangle capable of clipping content inside its border. @@ -74,12 +72,6 @@ Item { } } - ShaderEffectSource { - id: shaderSource - hideSource: true - sourceItem: contentItemContainer - } - ShaderEffect { id: shader anchors.fill: root @@ -87,6 +79,10 @@ Item { property Rectangle rect: rectangle property color backgroundColor: "white" property color borderColor: root.border.color - property ShaderEffectSource content: shaderSource + + property ShaderEffectSource content: ShaderEffectSource { + hideSource: true + sourceItem: contentItemContainer + } } } diff --git a/src/window/proxywindow.cpp b/src/window/proxywindow.cpp index 62126bd..3cc4378 100644 --- a/src/window/proxywindow.cpp +++ b/src/window/proxywindow.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -148,15 +147,6 @@ void ProxyWindowBase::ensureQWindow() { this->window = nullptr; // createQQuickWindow may indirectly reference this->window this->window = this->createQQuickWindow(); this->window->setFormat(format); - - // needed for vulkan dmabuf import, qt ignores these if not applicable - auto graphicsConfig = this->window->graphicsConfiguration(); - graphicsConfig.setDeviceExtensions({ - "VK_KHR_external_memory_fd", - "VK_EXT_external_memory_dma_buf", - "VK_EXT_image_drm_format_modifier", - }); - this->window->setGraphicsConfiguration(graphicsConfig); } void ProxyWindowBase::createWindow() { @@ -223,7 +213,6 @@ void ProxyWindowBase::completeWindow() { this->trySetHeight(this->implicitHeight()); this->setColor(this->mColor); this->updateMask(); - QQuickWindowPrivate::get(this->window)->updatesEnabled = this->mUpdatesEnabled; // notify initial / post-connection geometry emit this->xChanged(); @@ -299,16 +288,10 @@ void ProxyWindowBase::setVisibleDirect(bool visible) { this->bBackerVisibility = false; this->deleteWindow(); } - } else { - if (visible && this->window == nullptr) { - this->createWindow(); - } - - if (this->window != nullptr) { - if (visible) this->polishItems(); - this->window->setVisible(visible); - this->bBackerVisibility = visible; - } + } else if (this->window != nullptr) { + if (visible) this->polishItems(); + this->window->setVisible(visible); + this->bBackerVisibility = visible; } } @@ -480,19 +463,6 @@ void ProxyWindowBase::setSurfaceFormat(QsSurfaceFormat format) { emit this->surfaceFormatChanged(); } -bool ProxyWindowBase::updatesEnabled() const { return this->mUpdatesEnabled; } - -void ProxyWindowBase::setUpdatesEnabled(bool updatesEnabled) { - if (updatesEnabled == this->mUpdatesEnabled) return; - this->mUpdatesEnabled = updatesEnabled; - - if (this->window != nullptr) { - QQuickWindowPrivate::get(this->window)->updatesEnabled = updatesEnabled; - } - - emit this->updatesEnabledChanged(); -} - qreal ProxyWindowBase::devicePixelRatio() const { if (this->window != nullptr) return this->window->devicePixelRatio(); if (this->mScreen != nullptr) return this->mScreen->devicePixelRatio(); diff --git a/src/window/proxywindow.hpp b/src/window/proxywindow.hpp index aec821e..86d66f8 100644 --- a/src/window/proxywindow.hpp +++ b/src/window/proxywindow.hpp @@ -57,7 +57,6 @@ class ProxyWindowBase: public Reloadable { Q_PROPERTY(QObject* windowTransform READ windowTransform NOTIFY windowTransformChanged); Q_PROPERTY(bool backingWindowVisible READ isVisibleDirect NOTIFY backerVisibilityChanged); Q_PROPERTY(QsSurfaceFormat surfaceFormat READ surfaceFormat WRITE setSurfaceFormat NOTIFY surfaceFormatChanged); - Q_PROPERTY(bool updatesEnabled READ updatesEnabled WRITE setUpdatesEnabled NOTIFY updatesEnabledChanged); Q_PROPERTY(QQmlListProperty data READ data); // clang-format on Q_CLASSINFO("DefaultProperty", "data"); @@ -141,9 +140,6 @@ public: [[nodiscard]] QsSurfaceFormat surfaceFormat() const { return this->qsSurfaceFormat; } void setSurfaceFormat(QsSurfaceFormat format); - [[nodiscard]] bool updatesEnabled() const; - void setUpdatesEnabled(bool updatesEnabled); - [[nodiscard]] QObject* windowTransform() const { return nullptr; } // NOLINT [[nodiscard]] QQmlListProperty data(); @@ -167,7 +163,6 @@ signals: void colorChanged(); void maskChanged(); void surfaceFormatChanged(); - void updatesEnabledChanged(); void polished(); protected slots: @@ -192,7 +187,6 @@ protected: ProxyWindowContentItem* mContentItem = nullptr; bool reloadComplete = false; bool ranLints = false; - bool mUpdatesEnabled = true; QsSurfaceFormat qsSurfaceFormat; QSurfaceFormat mSurfaceFormat; diff --git a/src/window/windowinterface.cpp b/src/window/windowinterface.cpp index e41afc2..8917f12 100644 --- a/src/window/windowinterface.cpp +++ b/src/window/windowinterface.cpp @@ -127,9 +127,6 @@ void WindowInterface::setMask(PendingRegion* mask) const { this->proxyWindow()-> QsSurfaceFormat WindowInterface::surfaceFormat() const { return this->proxyWindow()->surfaceFormat(); }; void WindowInterface::setSurfaceFormat(QsSurfaceFormat format) const { this->proxyWindow()->setSurfaceFormat(format); }; -bool WindowInterface::updatesEnabled() const { return this->proxyWindow()->updatesEnabled(); }; -void WindowInterface::setUpdatesEnabled(bool updatesEnabled) const { this->proxyWindow()->setUpdatesEnabled(updatesEnabled); }; - QQmlListProperty WindowInterface::data() const { return this->proxyWindow()->data(); }; // clang-format on @@ -151,7 +148,6 @@ void WindowInterface::connectSignals() const { QObject::connect(window, &ProxyWindowBase::colorChanged, this, &WindowInterface::colorChanged); QObject::connect(window, &ProxyWindowBase::maskChanged, this, &WindowInterface::maskChanged); QObject::connect(window, &ProxyWindowBase::surfaceFormatChanged, this, &WindowInterface::surfaceFormatChanged); - QObject::connect(window, &ProxyWindowBase::updatesEnabledChanged, this, &WindowInterface::updatesEnabledChanged); // clang-format on } diff --git a/src/window/windowinterface.hpp b/src/window/windowinterface.hpp index 6f3db20..9e917b9 100644 --- a/src/window/windowinterface.hpp +++ b/src/window/windowinterface.hpp @@ -143,12 +143,6 @@ class WindowInterface: public Reloadable { /// /// > [!NOTE] The surface format cannot be changed after the window is created. Q_PROPERTY(QsSurfaceFormat surfaceFormat READ surfaceFormat WRITE setSurfaceFormat NOTIFY surfaceFormatChanged); - /// If the window should receive render updates. Defaults to true. - /// - /// When set to false, the window will not re-render in response to animations - /// or other visual updates from other windows. This is useful for static windows - /// such as wallpapers that do not need to update frequently, saving GPU cycles. - Q_PROPERTY(bool updatesEnabled READ updatesEnabled WRITE setUpdatesEnabled NOTIFY updatesEnabledChanged); Q_PROPERTY(QQmlListProperty data READ data); // clang-format on Q_CLASSINFO("DefaultProperty", "data"); @@ -237,9 +231,6 @@ public: [[nodiscard]] QsSurfaceFormat surfaceFormat() const; void setSurfaceFormat(QsSurfaceFormat format) const; - [[nodiscard]] bool updatesEnabled() const; - void setUpdatesEnabled(bool updatesEnabled) const; - [[nodiscard]] QQmlListProperty data() const; static QsWindowAttached* qmlAttachedProperties(QObject* object); @@ -267,7 +258,6 @@ signals: void colorChanged(); void maskChanged(); void surfaceFormatChanged(); - void updatesEnabledChanged(); protected: void connectSignals() const;