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/Justfile b/Justfile index 801eb2a..2d6377e 100644 --- a/Justfile +++ b/Justfile @@ -13,7 +13,7 @@ lint-changed: git diff --name-only HEAD | grep "^.*\.cpp\$" | parallel -j$(nproc) --no-notice --will-cite --tty --bar clang-tidy --load={{ env_var("TIDYFOX") }} lint-staged: - git diff --staged --name-only --diff-filter=d HEAD | grep "^.*\.cpp\$" | parallel -j$(nproc) --no-notice --will-cite --tty --bar clang-tidy --load={{ env_var("TIDYFOX") }} + git diff --staged --name-only HEAD | grep "^.*\.cpp\$" | parallel -j$(nproc) --no-notice --will-cite --tty --bar clang-tidy --load={{ env_var("TIDYFOX") }} configure target='debug' *FLAGS='': cmake -GNinja -B {{builddir}} \ diff --git a/changelog/next.md b/changelog/next.md index b9000c2..66f87c1 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -25,7 +25,6 @@ set shell id. - 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 @@ -47,10 +46,7 @@ set shell id. - Fixed asynchronous loaders not working before window creation. - Fixed memory leak in IPC handlers. - Fixed ClippingRectangle related crashes. -- Fixed crashes when monitors are unplugged. -- Fixed crashes when default pipewire devices are lost. ## 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/util.hpp b/src/core/util.hpp index bb8dd85..3b86d28 100644 --- a/src/core/util.hpp +++ b/src/core/util.hpp @@ -251,6 +251,37 @@ public: GuardedEmitBlocker block() { return GuardedEmitBlocker(&this->blocked); } }; +template +class SimpleObjectHandleOps { + using Traits = MemberPointerTraits; + +public: + static bool setObject(Traits::Class* parent, Traits::Type value) { + if (value == parent->*member) return false; + + if (parent->*member != nullptr) { + QObject::disconnect(parent->*member, &QObject::destroyed, parent, destroyedSlot); + } + + parent->*member = value; + + if (value != nullptr) { + QObject::connect(parent->*member, &QObject::destroyed, parent, destroyedSlot); + } + + if constexpr (changedSignal != nullptr) { + emit(parent->*changedSignal)(); + } + + return true; + } +}; + +template +bool setSimpleObjectHandle(auto* parent, auto* value) { + return SimpleObjectHandleOps::setObject(parent, value); +} + template class MethodFunctor { using PtrMeta = MemberPointerTraits; diff --git a/src/services/pipewire/defaults.cpp b/src/services/pipewire/defaults.cpp index 7a24a65..02463f4 100644 --- a/src/services/pipewire/defaults.cpp +++ b/src/services/pipewire/defaults.cpp @@ -12,6 +12,7 @@ #include #include "../../core/logcat.hpp" +#include "../../core/util.hpp" #include "metadata.hpp" #include "node.hpp" #include "registry.hpp" @@ -137,6 +138,32 @@ void PwDefaultTracker::onNodeAdded(PwNode* node) { } } +void PwDefaultTracker::onNodeDestroyed(QObject* node) { + if (node == this->mDefaultSink) { + qCInfo(logDefaults) << "Default sink destroyed."; + this->mDefaultSink = nullptr; + emit this->defaultSinkChanged(); + } + + if (node == this->mDefaultSource) { + qCInfo(logDefaults) << "Default source destroyed."; + this->mDefaultSource = nullptr; + emit this->defaultSourceChanged(); + } + + if (node == this->mDefaultConfiguredSink) { + qCInfo(logDefaults) << "Default configured sink destroyed."; + this->mDefaultConfiguredSink = nullptr; + emit this->defaultConfiguredSinkChanged(); + } + + if (node == this->mDefaultConfiguredSource) { + qCInfo(logDefaults) << "Default configured source destroyed."; + this->mDefaultConfiguredSource = nullptr; + emit this->defaultConfiguredSourceChanged(); + } +} + void PwDefaultTracker::changeConfiguredSink(PwNode* node) { if (node != nullptr) { if (!node->type.testFlags(PwNodeType::AudioSink)) { @@ -213,23 +240,10 @@ void PwDefaultTracker::setDefaultSink(PwNode* node) { if (node == this->mDefaultSink) return; qCInfo(logDefaults) << "Default sink changed to" << node; - if (this->mDefaultSink != nullptr) { - QObject::disconnect(this->mDefaultSink, nullptr, this, nullptr); - } - - this->mDefaultSink = node; - - if (node != nullptr) { - QObject::connect(node, &QObject::destroyed, this, &PwDefaultTracker::onDefaultSinkDestroyed); - } - - emit this->defaultSinkChanged(); -} - -void PwDefaultTracker::onDefaultSinkDestroyed() { - qCInfo(logDefaults) << "Default sink destroyed."; - this->mDefaultSink = nullptr; - emit this->defaultSinkChanged(); + setSimpleObjectHandle< + &PwDefaultTracker::mDefaultSink, + &PwDefaultTracker::onNodeDestroyed, + &PwDefaultTracker::defaultSinkChanged>(this, node); } void PwDefaultTracker::setDefaultSinkName(const QString& name) { @@ -243,23 +257,10 @@ void PwDefaultTracker::setDefaultSource(PwNode* node) { if (node == this->mDefaultSource) return; qCInfo(logDefaults) << "Default source changed to" << node; - if (this->mDefaultSource != nullptr) { - QObject::disconnect(this->mDefaultSource, nullptr, this, nullptr); - } - - this->mDefaultSource = node; - - if (node != nullptr) { - QObject::connect(node, &QObject::destroyed, this, &PwDefaultTracker::onDefaultSourceDestroyed); - } - - emit this->defaultSourceChanged(); -} - -void PwDefaultTracker::onDefaultSourceDestroyed() { - qCInfo(logDefaults) << "Default source destroyed."; - this->mDefaultSource = nullptr; - emit this->defaultSourceChanged(); + setSimpleObjectHandle< + &PwDefaultTracker::mDefaultSource, + &PwDefaultTracker::onNodeDestroyed, + &PwDefaultTracker::defaultSourceChanged>(this, node); } void PwDefaultTracker::setDefaultSourceName(const QString& name) { @@ -273,28 +274,10 @@ void PwDefaultTracker::setDefaultConfiguredSink(PwNode* node) { if (node == this->mDefaultConfiguredSink) return; qCInfo(logDefaults) << "Default configured sink changed to" << node; - if (this->mDefaultConfiguredSink != nullptr) { - QObject::disconnect(this->mDefaultConfiguredSink, nullptr, this, nullptr); - } - - this->mDefaultConfiguredSink = node; - - if (node != nullptr) { - QObject::connect( - node, - &QObject::destroyed, - this, - &PwDefaultTracker::onDefaultConfiguredSinkDestroyed - ); - } - - emit this->defaultConfiguredSinkChanged(); -} - -void PwDefaultTracker::onDefaultConfiguredSinkDestroyed() { - qCInfo(logDefaults) << "Default configured sink destroyed."; - this->mDefaultConfiguredSink = nullptr; - emit this->defaultConfiguredSinkChanged(); + setSimpleObjectHandle< + &PwDefaultTracker::mDefaultConfiguredSink, + &PwDefaultTracker::onNodeDestroyed, + &PwDefaultTracker::defaultConfiguredSinkChanged>(this, node); } void PwDefaultTracker::setDefaultConfiguredSinkName(const QString& name) { @@ -308,28 +291,10 @@ void PwDefaultTracker::setDefaultConfiguredSource(PwNode* node) { if (node == this->mDefaultConfiguredSource) return; qCInfo(logDefaults) << "Default configured source changed to" << node; - if (this->mDefaultConfiguredSource != nullptr) { - QObject::disconnect(this->mDefaultConfiguredSource, nullptr, this, nullptr); - } - - this->mDefaultConfiguredSource = node; - - if (node != nullptr) { - QObject::connect( - node, - &QObject::destroyed, - this, - &PwDefaultTracker::onDefaultConfiguredSourceDestroyed - ); - } - - emit this->defaultConfiguredSourceChanged(); -} - -void PwDefaultTracker::onDefaultConfiguredSourceDestroyed() { - qCInfo(logDefaults) << "Default configured source destroyed."; - this->mDefaultConfiguredSource = nullptr; - emit this->defaultConfiguredSourceChanged(); + setSimpleObjectHandle< + &PwDefaultTracker::mDefaultConfiguredSource, + &PwDefaultTracker::onNodeDestroyed, + &PwDefaultTracker::defaultConfiguredSourceChanged>(this, node); } void PwDefaultTracker::setDefaultConfiguredSourceName(const QString& name) { diff --git a/src/services/pipewire/defaults.hpp b/src/services/pipewire/defaults.hpp index f31669e..591c4fd 100644 --- a/src/services/pipewire/defaults.hpp +++ b/src/services/pipewire/defaults.hpp @@ -44,10 +44,7 @@ private slots: void onMetadataAdded(PwMetadata* metadata); void onMetadataProperty(const char* key, const char* type, const char* value); void onNodeAdded(PwNode* node); - void onDefaultSinkDestroyed(); - void onDefaultSourceDestroyed(); - void onDefaultConfiguredSinkDestroyed(); - void onDefaultConfiguredSourceDestroyed(); + void onNodeDestroyed(QObject* node); private: void setDefaultSink(PwNode* node); 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/window/proxywindow.cpp b/src/window/proxywindow.cpp index 62126bd..4423547 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(); @@ -480,19 +469,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;