Skip to content
Open
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
155 changes: 90 additions & 65 deletions src/core/qml/Effects/Blur.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import QtQuick.Shapes
import Waylib.Server
import Treeland

RenderBufferBlitter {
id: blitter
Item {
id: root
smooth: true

property real radius: 0
Expand All @@ -25,85 +25,110 @@ RenderBufferBlitter {
z: parent.z ? parent.z - 1 : -1
anchors.fill: parent

// Dispatch between Liquid Glass and traditional blur via a Loader so only
// the active branch is instantiated. Toggling the DConfig key unloads one
// Component and loads the other.
// On Vulkan the RenderBufferBlitter backdrop-capture path is broken, so
// skip creating it (and all dependent effect components) entirely and
// fall back to a plain semi-transparent rectangle.
Loader {
anchors.fill: parent
sourceComponent: blitter.glassEnabled ? glassComponent : blurComponent
sourceComponent: WaylibHelper.isVulkanBackend ? vulkanFallback : blitterContent
}

Component {
id: glassComponent
GlassEffect {
id: blitterContent
RenderBufferBlitter {
id: blitter
smooth: true
anchors.fill: parent
source: blitter.content
radius: blitter.radius
blurEnabled: blitter.blurEnabled
blurMax: blitter.blurMax
blurAmount: blitter.blurAmount
blurMultiplier: blitter.multiplier
brightness: blitter.brightness
highlightEnabled: blitter.highlightEnabled
lightAngle: blitter.lightAngle

bezelWidth: Helper.config.glassBezel
thickness: Helper.config.glassThickness
displacementFactor: Helper.config.glassDisplacementFactor
ior: Helper.config.glassIor
dispersion: Helper.config.glassDispersion
contrast: -0.12
saturation: 0.4
colorization: 0.12
edgeSaturation: Helper.config.glassEdgeSaturation
highlightColor: Qt.rgba(1, 1, 1, 0.3)
strokeWidth: 0.5
strokeStrength: 1.5
specularOpacity: 0.82
rimReflectionEnabled: true
lightPower: 3.0
reflectionOffset: Helper.config.glassReflectionOffset
}
}
// Dispatch between Liquid Glass and traditional blur via a Loader so only
// the active branch is instantiated. Toggling the DConfig key unloads one
// Component and loads the other.
Loader {
anchors.fill: parent
sourceComponent: blitter.glassEnabled ? glassComponent : blurComponent
}

Component {
id: blurComponent
Item {
anchors.fill: parent
Component {
id: glassComponent
GlassEffect {
anchors.fill: parent
source: blitter.content
radius: root.radius
blurEnabled: root.blurEnabled
blurMax: root.blurMax
blurAmount: root.blurAmount
blurMultiplier: root.multiplier
brightness: root.brightness
highlightEnabled: root.highlightEnabled
lightAngle: root.lightAngle

MultiEffect {
id: blur
anchors.fill: parent
layer.enabled: blitter.radiusEnabled
smooth: blitter.radiusEnabled
opacity: blitter.radiusEnabled ? 0 : blitter.opacity
source: blitter.content
autoPaddingEnabled: false
blurEnabled: blitter.blurEnabled
blur: blitter.blurAmount
blurMax: blitter.blurMax
blurMultiplier: blitter.multiplier
saturation: 0.2
bezelWidth: Helper.config.glassBezel
thickness: Helper.config.glassThickness
displacementFactor: Helper.config.glassDisplacementFactor
ior: Helper.config.glassIor
dispersion: Helper.config.glassDispersion
contrast: -0.12
saturation: 0.4
colorization: 0.12
edgeSaturation: Helper.config.glassEdgeSaturation
highlightColor: Qt.rgba(1, 1, 1, 0.3)
strokeWidth: 0.5
strokeStrength: 1.5
specularOpacity: 0.82
rimReflectionEnabled: true
lightPower: 3.0
reflectionOffset: Helper.config.glassReflectionOffset
}
}

Loader {
x: blur.x
y: blur.y
active: blitter.radiusEnabled
sourceComponent: Shape {
Component {
id: blurComponent
Item {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
strokeWidth: 0
fillItem: blur
PathRectangle {
width: blur.width
height: blur.height
radius: blitter.radius

MultiEffect {
id: blur
anchors.fill: parent
layer.enabled: root.radiusEnabled
smooth: root.radiusEnabled
opacity: root.radiusEnabled ? 0 : root.opacity
source: blitter.content
autoPaddingEnabled: false
blurEnabled: root.blurEnabled
blur: root.blurAmount
blurMax: root.blurMax
blurMultiplier: root.multiplier
saturation: 0.2
}

Loader {
x: blur.x
y: blur.y
active: root.radiusEnabled
sourceComponent: Shape {
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
strokeWidth: 0
fillItem: blur
PathRectangle {
width: blur.width
height: blur.height
radius: root.radius
}
}
}
}
}
}
}
}

Component {
id: vulkanFallback
Rectangle {
radius: root.radius
color: Qt.rgba(0, 0, 0, 0.3)
}
}
}
8 changes: 8 additions & 0 deletions waylib/src/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ pkg_search_module(PIXMAN REQUIRED IMPORTED_TARGET pixman-1)
pkg_search_module(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon)
pkg_search_module(XCB REQUIRED IMPORTED_TARGET xcb)
pkg_search_module(EGL REQUIRED IMPORTED_TARGET egl)
# Optional: wvulkandmabufimport.cpp calls Vulkan loader functions directly.
# Only linked when present; the code is compiled out without ENABLE_VULKAN_RENDER.
pkg_search_module(VULKAN IMPORTED_TARGET vulkan)

add_compile_definitions(WLR_PRIVATE=)

Expand Down Expand Up @@ -151,6 +154,7 @@ set(SOURCES
qtquick/private/wqmlhelper.cpp
qtquick/private/wbufferrenderer.cpp
qtquick/private/wrenderbuffernode.cpp
qtquick/private/wvulkandmabufimport.cpp

${WAYLAND_PROTOCOLS_OUTPUTDIR}/text-input-unstable-v1-protocol.c
${WAYLAND_PROTOCOLS_OUTPUTDIR}/text-input-unstable-v2-protocol.c
Expand Down Expand Up @@ -332,6 +336,7 @@ set(PRIVATE_HEADERS
qtquick/private/wbufferrenderer_p.h
qtquick/private/wrenderbuffernode_p.h
qtquick/private/wsurfaceitem_p.h
qtquick/private/wvulkandmabufimport_p.h

${WAYLAND_PROTOCOLS_OUTPUTDIR}/text-input-unstable-v1-protocol.h
${WAYLAND_PROTOCOLS_OUTPUTDIR}/text-input-unstable-v2-protocol.h
Expand Down Expand Up @@ -407,6 +412,9 @@ target_link_libraries(${TARGET}
PkgConfig::XCB
PkgConfig::EGL
)
if(TARGET PkgConfig::VULKAN)
target_link_libraries(${TARGET} PRIVATE PkgConfig::VULKAN)
endif()

target_link_libraries(${TARGET}
PUBLIC
Expand Down
14 changes: 14 additions & 0 deletions waylib/src/server/kernel/wglobal.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@
QML_UNCREATABLE("Use for enums")

public:
enum class ColorContentsMode {
DontCare,
Clear,
Preserve,
};
Q_ENUM(ColorContentsMode)

enum class CursorShape {
Default = Qt::CustomCursor + 1,
Invalid,
Expand Down Expand Up @@ -250,6 +257,13 @@
static bool isClientResourceCursor(const QCursor &c);
};

struct Q_DECL_HIDDEN WColorContentsModeQMLProxy {
Comment thread
zccrs marked this conversation as resolved.
Q_GADGET
QML_NAMED_ELEMENT(ColorContentsMode)
QML_FOREIGN_NAMESPACE(WAYLIB_SERVER_NAMESPACE::WGlobal)

Check warning on line 263 in waylib/src/server/kernel/wglobal.h

View workflow job for this annotation

GitHub Actions / cppcheck

There is an unknown macro here somewhere. Configuration is required. If QML_FOREIGN_NAMESPACE is a macro then please configure it.
QML_UNCREATABLE("Use for enums")
};

struct Q_DECL_HIDDEN WCursorShapeQMLProxy {
Q_GADGET
QML_NAMED_ELEMENT(CursorShape)
Expand Down
43 changes: 22 additions & 21 deletions waylib/src/server/qtquick/private/wbufferrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@ QRhiTexture *WBufferRenderer::currentRenderTarget() const
return colorAttachment->texture();
}

bool WBufferRenderer::isColorPreserved() const
{
return state.renderTarget.colorPreserved();
}

const qw_damage_ring *WBufferRenderer::damageRing() const
{
return &m_damageRing;
Expand Down Expand Up @@ -331,7 +336,8 @@ QTransform WBufferRenderer::inputMapToOutput(const QRectF &sourceRect, const QRe
}

qw_buffer *WBufferRenderer::beginRender(const QSize &pixelSize, qreal devicePixelRatio,
uint32_t format, RenderFlags flags)
uint32_t format, RenderFlags flags,
WGlobal::ColorContentsMode mode)
{
Q_ASSERT(!state.buffer);
Q_ASSERT(m_output);
Expand Down Expand Up @@ -378,8 +384,7 @@ qw_buffer *WBufferRenderer::beginRender(const QSize &pixelSize, qreal devicePixe

auto wd = QQuickWindowPrivate::get(window());
Q_ASSERT(wd->renderControl);
auto lastRT = m_renderHelper->lastRenderTarget();
auto rt = m_renderHelper->acquireRenderTarget(wd->renderControl, buffer);
auto rt = m_renderHelper->acquireRenderTarget(wd->renderControl, buffer, mode);
if (rt.isNull()) {
buffer->unlock();
return nullptr;
Expand All @@ -390,7 +395,8 @@ qw_buffer *WBufferRenderer::beginRender(const QSize &pixelSize, qreal devicePixe
m_damageRing.rotate_buffer(wbuffer, damage);
state.dirty = WTools::fromPixmanRegion(damage);

auto rtd = QQuickRenderTargetPrivate::get(&rt);
auto rtValue = rt.rt();
auto rtd = QQuickRenderTargetPrivate::get(&rtValue);
QSGRenderTarget sgRT;

if (rtd->type == QQuickRenderTargetPrivate::Type::PaintDevice) {
Expand Down Expand Up @@ -420,6 +426,7 @@ qw_buffer *WBufferRenderer::beginRender(const QSize &pixelSize, qreal devicePixe
}

state.flags = flags;
state.colorContentsMode = mode;
state.context = wd->context;
state.pixelSize = pixelSize;
state.devicePixelRatio = devicePixelRatio;
Expand All @@ -436,8 +443,7 @@ inline static QRect scaleToRect(const QRectF &s, qreal scale) {
}

void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
const QRectF &sourceRect, const QRectF &targetRect,
bool preserveColorContents)
const QRectF &sourceRect, const QRectF &targetRect)
{
Q_ASSERT(state.buffer);

Expand Down Expand Up @@ -477,16 +483,13 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
auto softwareRenderer = dynamic_cast<QSGSoftwareRenderer*>(renderer);
{ // before render
if (softwareRenderer) {
// Avoid do clear before paint, for the software renderer this
// work is expensive.
if (m_clearColor.alpha() == 0)
preserveColorContents = true;
const bool clearColor = !state.renderTarget.colorPreserved();
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
softwareRenderer->setClearColorEnabled(!preserveColorContents);
softwareRenderer->setClearColorEnabled(clearColor);
#else
auto bn = softwareRenderer->renderableNode(W_PRIVATE_MEMBER(*softwareRenderer, QSGAbsSoftRenderer_m_background_tag{}));
if (bn) {
W_PRIVATE_MEMBER(*bn, QSGSoftRenderableNode_m_opacity_tag{}) = preserveColorContents ? 0 : 1;
W_PRIVATE_MEMBER(*bn, QSGSoftRenderableNode_m_opacity_tag{}) = clearColor ? 1 : 0;
}
#endif
if (!state.dirty.isEmpty()) {
Expand All @@ -501,7 +504,7 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
if (!mapTransform.isIdentity())
state.worldTransform = mapTransform * state.worldTransform;
state.worldTransform.optimize();
auto image = getImageFrom(state.renderTarget);
auto image = getImageFrom(state.renderTarget.rt());
image->setDevicePixelRatio(devicePixelRatio);

// TODO: Should set to QSGSoftwareRenderer, but it's not support specify matrix.
Expand All @@ -523,7 +526,7 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
state.worldTransform.optimize();

bool flipY = wd->rhi ? !wd->rhi->isYUpInNDC() : false;
if (state.renderTarget.mirrorVertically())
if (state.renderTarget.rt().mirrorVertically())
flipY = !flipY;

if (viewportRect.isValid()) {
Expand Down Expand Up @@ -564,16 +567,14 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
renderer->setProjectionMatrix(projectionMatrix);
renderer->setProjectionMatrixWithNativeNDC(projectionMatrixWithNativeNDC);

auto textureRT = static_cast<QRhiTextureRenderTarget*>(state.sgRenderTarget.rt);
if (preserveColorContents) {
textureRT->setFlags(textureRT->flags() | QRhiTextureRenderTarget::PreserveColorContents);
} else {
textureRT->setFlags(textureRT->flags() & ~QRhiTextureRenderTarget::PreserveColorContents);
}
}
}

if (m_renderHelper)
m_renderHelper->prepareVulkanRenderTarget(state.sgRenderTarget.cb, state.renderTarget);
state.context->renderNextFrame(renderer);
if (m_renderHelper)
m_renderHelper->finishVulkanRenderTarget(state.sgRenderTarget.cb, state.renderTarget);

{ // after render
if (!softwareRenderer) {
Expand All @@ -591,7 +592,7 @@ void WBufferRenderer::render(int sourceIndex, const QMatrix4x4 &renderMatrix,
} else {
state.dirty = softwareRenderer->flushRegion();

auto currentImage = getImageFrom(state.renderTarget);
auto currentImage = getImageFrom(state.renderTarget.rt());
Q_ASSERT(currentImage && currentImage == softwareRenderer->renderTarget().paintDevice);
currentImage->setDevicePixelRatio(1.0);
const auto scaleTF = QTransform::fromScale(devicePixelRatio, devicePixelRatio);
Expand Down
Loading
Loading