Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion 3rdparty/wlroots/include/wlr/render/vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/

#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif

#ifndef WLR_RENDER_VULKAN_H
#define WLR_RENDER_VULKAN_H

#include <stdbool.h>
#include <stdint.h>

#include <vulkan/vulkan_core.h>
#include <wlr/render/wlr_renderer.h>

struct wlr_buffer;

struct wlr_vk_image_attribs {
VkImage image;
VkImageLayout layout;
Expand All @@ -32,5 +38,15 @@ void wlr_vk_texture_get_image_attribs(struct wlr_texture *texture,
struct wlr_vk_image_attribs *attribs);
bool wlr_vk_texture_has_alpha(struct wlr_texture *texture);

#endif
/* waylib extensions (not upstream): Qt Quick RHI bridge helpers.
* Reuse wlroots' own wlr_vk_render_buffer (same path as tinywl/scene),
* instead of creating a parallel VkImage import of the scanout dmabuf. */
bool waylib_vk_renderer_get_render_buffer_attribs(struct wlr_renderer *renderer,
struct wlr_buffer *buffer, struct wlr_vk_image_attribs *attribs);
bool waylib_vk_renderer_record_render_buffer_acquire(struct wlr_renderer *renderer,
struct wlr_buffer *buffer, VkCommandBuffer cb);
bool waylib_vk_renderer_record_render_buffer_release(struct wlr_renderer *renderer,
struct wlr_buffer *buffer, VkCommandBuffer cb, VkImageLayout old_layout);
bool waylib_vk_renderer_flush_stage(struct wlr_renderer *renderer);

#endif
142 changes: 142 additions & 0 deletions 3rdparty/wlroots/render/vulkan/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,17 @@ bool vulkan_submit_stage_wait(struct wlr_vk_renderer *renderer) {
return vulkan_wait_command_buffer(cb, renderer);
}

bool waylib_vk_renderer_flush_stage(struct wlr_renderer *wlr_renderer) {
if (wlr_renderer == NULL || !wlr_renderer_is_vk(wlr_renderer)) {
return false;
}
struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
if (renderer->stage.cb == NULL) {
return true;
}
return vulkan_submit_stage_wait(renderer);
}

struct wlr_vk_format_props *vulkan_format_props_from_drm(
struct wlr_vk_device *dev, uint32_t drm_fmt) {
for (size_t i = 0u; i < dev->format_prop_count; ++i) {
Expand Down Expand Up @@ -947,6 +958,137 @@ static struct wlr_vk_render_buffer *get_render_buffer(
return buffer;
}

static struct wlr_vk_render_buffer *get_or_create_render_buffer(
struct wlr_vk_renderer *renderer, struct wlr_buffer *wlr_buffer) {
struct wlr_vk_render_buffer *render_buffer =
get_render_buffer(renderer, wlr_buffer);
if (render_buffer != NULL) {
return render_buffer;
}
return create_render_buffer(renderer, wlr_buffer);
}

bool waylib_vk_renderer_get_render_buffer_attribs(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *wlr_buffer, struct wlr_vk_image_attribs *attribs) {
if (wlr_renderer == NULL || wlr_buffer == NULL || attribs == NULL) {
return false;
}
if (!wlr_renderer_is_vk(wlr_renderer)) {
return false;
}

struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
struct wlr_vk_render_buffer *render_buffer =
get_or_create_render_buffer(renderer, wlr_buffer);
if (render_buffer == NULL) {
return false;
}

struct wlr_dmabuf_attributes dmabuf = {0};
if (!wlr_buffer_get_dmabuf(wlr_buffer, &dmabuf)) {
wlr_log(WLR_ERROR, "wlr_buffer_get_dmabuf() failed");
return false;
}

const struct wlr_vk_format *format = vulkan_get_format_from_drm(dmabuf.format);
if (format == NULL) {
wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIx32 " (%.4s)",
dmabuf.format, (const char *)&dmabuf.format);
return false;
}

attribs->image = render_buffer->image;
attribs->layout = VK_IMAGE_LAYOUT_GENERAL;
attribs->format = format->vk;
return true;
}

bool waylib_vk_renderer_record_render_buffer_acquire(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *wlr_buffer, VkCommandBuffer cb) {
if (wlr_renderer == NULL || wlr_buffer == NULL || cb == VK_NULL_HANDLE) {
return false;
}
if (!wlr_renderer_is_vk(wlr_renderer)) {
return false;
}

struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
struct wlr_vk_render_buffer *render_buffer =
get_or_create_render_buffer(renderer, wlr_buffer);
if (render_buffer == NULL) {
return false;
}

/* Match wlroots pass.c / tinywl: foreign ownership transfer into the
* graphics queue before writing the scanout image. */
VkImageLayout src_layout = VK_IMAGE_LAYOUT_GENERAL;
if (!render_buffer->srgb.transitioned && !render_buffer->plain.transitioned) {
src_layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
}
// The sRGB and plain pathways share the imported VkImage. Once this
// acquire barrier runs, both pathways observe GENERAL on subsequent use.
render_buffer->srgb.transitioned = true;
render_buffer->plain.transitioned = true;

VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
.dstQueueFamilyIndex = renderer->dev->queue_family,
.image = render_buffer->image,
.oldLayout = src_layout,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.layerCount = 1,
.subresourceRange.levelCount = 1,
};

vkCmdPipelineBarrier(cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, 0, NULL, 0, NULL, 1, &barrier);
return true;
}

bool waylib_vk_renderer_record_render_buffer_release(struct wlr_renderer *wlr_renderer,
struct wlr_buffer *wlr_buffer, VkCommandBuffer cb,
VkImageLayout old_layout) {
if (wlr_renderer == NULL || wlr_buffer == NULL || cb == VK_NULL_HANDLE) {
return false;
}
if (!wlr_renderer_is_vk(wlr_renderer)) {
return false;
}

struct wlr_vk_renderer *renderer = vulkan_get_renderer(wlr_renderer);
struct wlr_vk_render_buffer *render_buffer =
get_render_buffer(renderer, wlr_buffer);
if (render_buffer == NULL) {
return false;
}

VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcQueueFamilyIndex = renderer->dev->queue_family,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
.image = render_buffer->image,
.oldLayout = old_layout,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = 0,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.layerCount = 1,
.subresourceRange.levelCount = 1,
};

vkCmdPipelineBarrier(cb, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0, 0, NULL, 0, NULL, 1, &barrier);
return true;
}

static bool buffer_export_sync_file(struct wlr_vk_renderer *renderer, struct wlr_buffer *buffer,
uint32_t flags, int sync_file_fds[static WLR_DMABUF_MAX_PLANES]) {
struct wlr_dmabuf_attributes dmabuf = {0};
Expand Down
1 change: 1 addition & 0 deletions 3rdparty/wlroots/wlroots.syms
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
global:
wlr_*;
_wlr_*;
waylib_*;
local:
*;
};
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ add_compile_definitions("QT_FORCE_ASSERTS")

add_compile_definitions("TREELAND_PLUGINS_INSTALL_PATH=\"${TREELAND_FULL_PLUGINS_INSTALL_PATH}\"")
add_compile_definitions("TREELAND_PLUGINS_OUTPUT_PATH=\"${TREELAND_PLUGINS_OUTPUT_PATH}\"")
add_compile_definitions("TREELAND_WALLPAPER_FACTORY_OUTPUT_PATH=\"${CMAKE_BINARY_DIR}/wallpaper-factory/treeland-wallpaper-factory\"")

add_compile_definitions("TREELAND_COMPONENTS_TRANSLATION_DIR=\"${TREELAND_FULL_COMPONENTS_TRANSLATION_DIR}\"")

Expand Down
12 changes: 12 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ qt_add_qml_module(libtreeland
core/qml/Animations/LaunchpadAnimation.qml
core/qml/Animations/LayerShellAnimation.qml
core/qml/Effects/Blur.qml
core/qml/Effects/+vulkan/Blur.qml
core/qml/Effects/GlassEffect.qml
core/qml/Effects/LaunchpadCover.qml
core/qml/TaskSwitcher.qml
Expand Down Expand Up @@ -307,6 +308,16 @@ qt_add_shaders(libtreeland "treeland_liquidglass_shaders"
${PROJECT_RESOURCES_DIR}/shaders/liquidglass.frag
)

set_source_files_properties(core/qml/overridable/InWindowBlur.qml
PROPERTIES
QT_RESOURCE_ALIAS "+treeland/InWindowBlur.qml"
)
qt_add_resources(libtreeland "override_dtkdeclarative_qml"
PREFIX "/dtk/declarative/qml/overridable"
FILES
core/qml/overridable/InWindowBlur.qml
)

qt_add_resources(libtreeland "treeland_assets"
PREFIX "/dsg/icons"
BASE ${PROJECT_RESOURCES_DIR}/icons
Expand Down Expand Up @@ -402,6 +413,7 @@ target_include_directories(${BIN_NAME} PRIVATE
target_link_libraries(${BIN_NAME} PRIVATE
libtreeland
Qt6::GuiPrivate
Qt6::QuickControls2
)

install(TARGETS ${BIN_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
Expand Down
46 changes: 46 additions & 0 deletions src/core/qml/Effects/+vulkan/Blur.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (C) 2026 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

import QtQuick
import Treeland

Rectangle {
id: root

color: Qt.rgba(0.0, 0.0, 0.0, 0.0)

property bool radiusEnabled: radius > 0
property int blurMax: Helper.config.blurStrength
property bool blurEnabled: blurMax > 0 && blurAmount > 0
property real blurAmount: Helper.config.blurAmount
property real multiplier: Helper.config.blurMultiplier
property real brightness: 0.0
property real contrast: 0.0
property real saturation: Helper.config.glassSaturation
property real glassSpecular: Helper.config.glassSpecular
property real glassTint: 0.0
property bool glassEnabled: Helper.config.glassEnabled
property Item effectContent: effectContentItem
property bool contentOffscreen: false
property bool effectEnabled: true
readonly property Item content: contentContainer
property alias offscreen: root.contentOffscreen
default property alias data: contentContainer.data

Item {
id: contentContainer
anchors.fill: parent
}

Rectangle {
id: effectContentItem
anchors.fill: parent
radius: root.radius
color: Qt.rgba(1.0, 1.0, 1.0, 0.15)
visible: root.effectEnabled && !root.contentOffscreen
z: -1
}

z: parent.z ? parent.z - 1 : -1
anchors.fill: parent
}
5 changes: 5 additions & 0 deletions src/core/qml/Effects/Blur.qml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ RenderBufferBlitter {
property real glassSpecular: Helper.config.glassSpecular
property real glassTint: 0.0
property bool glassEnabled: Helper.config.glassEnabled
property Item effectContent: contentLoader
property bool contentOffscreen: false
property bool effectEnabled: true

z: parent.z ? parent.z - 1 : -1
anchors.fill: parent
Expand All @@ -31,8 +34,10 @@ RenderBufferBlitter {
// the active branch is instantiated. Toggling the DConfig key unloads one
// Component and loads the other.
Loader {
id: contentLoader
anchors.fill: parent
sourceComponent: blitter.glassEnabled ? glassComponent : blurComponent
visible: blitter.effectEnabled && !blitter.contentOffscreen
}

Component {
Expand Down
22 changes: 22 additions & 0 deletions src/core/qml/overridable/InWindowBlur.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2026 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

import QtQuick
import Treeland

Item {
id: control

property alias offscreen: blur.contentOffscreen
property alias radius: blur.blurMax
property alias multiplier: blur.multiplier
property alias content: blur.effectContent
default property alias data: blur.data
property alias valid: blur.effectEnabled

Blur {
id: blur
anchors.fill: parent
glassEnabled: false
}
}
18 changes: 18 additions & 0 deletions src/core/qmlengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,31 @@
#include "surface/surfacewrapper.h"
#include "workspace/workspace.h"

#include <woutput.h>

Check warning on line 13 in src/core/qmlengine.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <woutput.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <woutputitem.h>

Check warning on line 14 in src/core/qmlengine.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <woutputitem.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QQmlFileSelector>

Check warning on line 16 in src/core/qmlengine.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQmlFileSelector> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QQuickItem>

Check warning on line 17 in src/core/qmlengine.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickItem> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QQuickWindow>

Check warning on line 18 in src/core/qmlengine.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickWindow> not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace {

QObject *installQmlFileSelector(QQmlEngine *engine)
{
auto selector = new QQmlFileSelector(engine);
const auto api = QQuickWindow::graphicsApi();
selector->setExtraSelectors({
QStringLiteral("treeland"),
api == QSGRendererInterface::Vulkan ? QStringLiteral("vulkan") : QStringLiteral("gles"),
});
return selector;
}

} // namespace

QmlEngine::QmlEngine(QObject *parent)
: QQmlApplicationEngine(parent)
, dtkInWindowBlurFileSelector(installQmlFileSelector(this))
, titleBarComponent(this, "Treeland", "TitleBar")
, decorationComponent(this, "Treeland", "Decoration")
, windowMenuComponent(this, "Treeland", "WindowMenu")
Expand Down
1 change: 1 addition & 0 deletions src/core/qmlengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class QmlEngine : public QQmlApplicationEngine
}

private:
QObject *const dtkInWindowBlurFileSelector;
QQmlComponent titleBarComponent;
QQmlComponent decorationComponent;
QQmlComponent windowMenuComponent;
Expand Down
3 changes: 2 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
#include <DGuiApplicationHelper>
#include <DLog>

#include <QGuiApplication>

Check warning on line 15 in src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QGuiApplication> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QMetaType>

Check warning on line 16 in src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QMetaType> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPalette>

Check warning on line 17 in src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPalette> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QQuickStyle>

Check warning on line 18 in src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickStyle> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
# include <private/qgenericunixtheme_p.h>
Expand Down Expand Up @@ -52,7 +53,7 @@
WServer::initializeQPA({}, [](const QString &) {
return static_cast<QPlatformTheme *>(new QDeepinTheme());
});
// QQuickStyle::setStyle("Material");
QQuickStyle::setStyle("Chameleon");

QGuiApplication::setAttribute(Qt::AA_UseOpenGLES);
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
Expand Down
Loading
Loading