wayland: implement the alpha-modifier protocol

The alpha modifier protocol allows clients to set a multiplier for the opacity
of a surface, which allows them to offload some operations to KWin, which
in turn may offload them to KMS in the future
This commit is contained in:
Xaver Hugl 2024-03-18 16:07:16 +01:00
parent 370c9c8953
commit 4759ec6089
11 changed files with 160 additions and 2 deletions

View file

@ -211,7 +211,7 @@ else()
set(HAVE_WL_DISPLAY_SET_DEFAULT_MAX_BUFFER_SIZE 0)
endif()
find_package(WaylandProtocols 1.34)
find_package(WaylandProtocols 1.36)
set_package_properties(WaylandProtocols PROPERTIES
TYPE REQUIRED
PURPOSE "Collection of Wayland protocols that add functionality not available in the Wayland core protocol"

View file

@ -47,6 +47,7 @@ SurfaceItemWayland::SurfaceItemWayland(SurfaceInterface *surface, Item *parent)
connect(surface, &SurfaceInterface::presentationModeHintChanged,
this, &SurfaceItemWayland::handlePresentationModeHintChanged);
connect(surface, &SurfaceInterface::bufferReleasePointChanged, this, &SurfaceItemWayland::handleReleasePointChanged);
connect(surface, &SurfaceInterface::alphaMultiplierChanged, this, &SurfaceItemWayland::handleAlphaMultiplierChanged);
SubSurfaceInterface *subsurface = surface->subSurface();
if (subsurface) {
@ -66,6 +67,7 @@ SurfaceItemWayland::SurfaceItemWayland(SurfaceInterface *surface, Item *parent)
setBufferSourceBox(surface->bufferSourceBox());
setBufferSize(surface->bufferSize());
setColorDescription(surface->colorDescription());
setOpacity(surface->alphaMultiplier());
}
QList<QRectF> SurfaceItemWayland::shape() const
@ -216,6 +218,11 @@ void SurfaceItemWayland::handleReleasePointChanged()
m_bufferReleasePoint = m_surface->bufferReleasePoint();
}
void SurfaceItemWayland::handleAlphaMultiplierChanged()
{
setOpacity(m_surface->alphaMultiplier());
}
SurfacePixmapWayland::SurfacePixmapWayland(SurfaceItemWayland *item, QObject *parent)
: SurfacePixmap(Compositor::self()->backend()->createSurfaceTextureWayland(this), parent)
, m_item(item)

View file

@ -50,6 +50,7 @@ private Q_SLOTS:
void handleColorDescriptionChanged();
void handlePresentationModeHintChanged();
void handleReleasePointChanged();
void handleAlphaMultiplierChanged();
protected:
std::unique_ptr<SurfacePixmap> createPixmap() override;

View file

@ -315,10 +315,15 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-external-brightness-v1.xml
BASENAME kde-external-brightness-v1
)
ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
PROTOCOL ${WaylandProtocols_DATADIR}/staging/alpha-modifier/alpha-modifier-v1.xml
BASENAME alpha-modifier-v1
)
target_sources(kwin PRIVATE
abstract_data_source.cpp
abstract_drop_handler.cpp
alphamodifier_v1.cpp
appmenu.cpp
blur.cpp
clientconnection.cpp
@ -403,6 +408,7 @@ target_sources(kwin PRIVATE
)
install(FILES
alphamodifier_v1.h
appmenu.h
blur.h
clientconnection.h
@ -478,12 +484,14 @@ install(FILES
xwaylandshell_v1.h
xx_colormanagement_v4.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-alpha-modifier-v1.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-content-type-v1.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-frog-color-management-v1.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-kde-external-brightness-v1.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-linux-drm-syncobj-v1.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-presentation-time.h
${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-xx-color-management-v4.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-alpha-modifier-v1-server-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-content-type-v1-server-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-frog-color-management-v1-server-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-kde-external-brightness-v1-server-protocol.h

View file

@ -0,0 +1,75 @@
/*
SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "alphamodifier_v1.h"
#include "display.h"
#include "surface.h"
#include "surface_p.h"
namespace KWin
{
static constexpr uint32_t s_version = 1;
AlphaModifierManagerV1::AlphaModifierManagerV1(Display *display, QObject *parent)
: QObject(parent)
, QtWaylandServer::wp_alpha_modifier_v1(*display, s_version)
{
}
void AlphaModifierManagerV1::wp_alpha_modifier_v1_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void AlphaModifierManagerV1::wp_alpha_modifier_v1_get_surface(Resource *resource, uint32_t id, ::wl_resource *surface)
{
SurfaceInterface *surf = SurfaceInterface::get(surface);
SurfaceInterfacePrivate *priv = SurfaceInterfacePrivate::get(surf);
if (priv->alphaModifier) {
wl_resource_post_error(surface, error_already_constructed, "wl_surface already has an alpha modifier surface");
return;
}
new AlphaModifierSurfaceV1(resource->client(), id, resource->version(), surf);
}
AlphaModifierSurfaceV1::AlphaModifierSurfaceV1(wl_client *client, uint32_t id, uint32_t version, SurfaceInterface *surface)
: QtWaylandServer::wp_alpha_modifier_surface_v1(client, id, version)
, m_surface(surface)
{
}
AlphaModifierSurfaceV1::~AlphaModifierSurfaceV1()
{
if (m_surface) {
const auto priv = SurfaceInterfacePrivate::get(m_surface);
priv->pending->alphaMultiplier = 1;
priv->pending->alphaMultiplierIsSet = true;
}
}
void AlphaModifierSurfaceV1::wp_alpha_modifier_surface_v1_destroy_resource(Resource *resource)
{
delete this;
}
void AlphaModifierSurfaceV1::wp_alpha_modifier_surface_v1_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void AlphaModifierSurfaceV1::wp_alpha_modifier_surface_v1_set_multiplier(Resource *resource, uint32_t factor)
{
if (!m_surface) {
wl_resource_post_error(resource->handle, error_no_surface, "wl_surface was destroyed before a set_multiplier request");
return;
}
const auto priv = SurfaceInterfacePrivate::get(m_surface);
priv->pending->alphaMultiplier = factor / double(std::numeric_limits<uint32_t>::max());
priv->pending->alphaMultiplierIsSet = true;
}
}

View file

@ -0,0 +1,44 @@
/*
SPDX-FileCopyrightText: 2024 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include "kwin_export.h"
#include "wayland/qwayland-server-alpha-modifier-v1.h"
#include <QObject>
#include <QPointer>
namespace KWin
{
class Display;
class SurfaceInterface;
class KWIN_EXPORT AlphaModifierManagerV1 : public QObject, private QtWaylandServer::wp_alpha_modifier_v1
{
public:
explicit AlphaModifierManagerV1(Display *display, QObject *parent);
private:
void wp_alpha_modifier_v1_destroy(Resource *resource) override;
void wp_alpha_modifier_v1_get_surface(Resource *resource, uint32_t id, ::wl_resource *surface) override;
};
class AlphaModifierSurfaceV1 : private QtWaylandServer::wp_alpha_modifier_surface_v1
{
public:
explicit AlphaModifierSurfaceV1(wl_client *client, uint32_t id, uint32_t version, SurfaceInterface *surface);
~AlphaModifierSurfaceV1() override;
private:
void wp_alpha_modifier_surface_v1_destroy_resource(Resource *resource) override;
void wp_alpha_modifier_surface_v1_destroy(Resource *resource) override;
void wp_alpha_modifier_surface_v1_set_multiplier(Resource *resource, uint32_t factor) override;
const QPointer<SurfaceInterface> m_surface;
};
}

View file

@ -589,6 +589,10 @@ void SurfaceState::mergeInto(SurfaceState *target)
target->colorDescription = colorDescription;
target->colorDescriptionIsSet = true;
}
if (alphaMultiplierIsSet) {
target->alphaMultiplier = alphaMultiplier;
target->alphaMultiplierIsSet = true;
}
target->presentationFeedback = std::move(presentationFeedback);
*this = SurfaceState{};
@ -611,6 +615,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
const bool colorDescriptionChanged = next->colorDescriptionIsSet;
const bool presentationModeHintChanged = next->presentationModeHintIsSet;
const bool bufferReleasePointChanged = next->bufferIsSet && current->releasePoint != next->releasePoint;
const bool alphaMultiplierChanged = next->alphaMultiplierIsSet;
const QSizeF oldSurfaceSize = surfaceSize;
const QSize oldBufferSize = bufferSize;
@ -706,6 +711,9 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
if (bufferReleasePointChanged) {
Q_EMIT q->bufferReleasePointChanged();
}
if (alphaMultiplierChanged) {
Q_EMIT q->alphaMultiplierChanged();
}
if (bufferChanged) {
if (current->buffer && (!current->damage.isEmpty() || !current->bufferDamage.isEmpty())) {
@ -1210,6 +1218,11 @@ std::shared_ptr<SyncReleasePoint> SurfaceInterface::bufferReleasePoint() const
return d->current->releasePoint;
}
double SurfaceInterface::alphaMultiplier() const
{
return d->current->alphaMultiplier;
}
} // namespace KWin
#include "moc_surface.cpp"

View file

@ -344,6 +344,8 @@ public:
void setPreferredColorDescription(const ColorDescription &descr);
double alphaMultiplier() const;
/**
* Returns the current release point for the buffer on this surface. The buffer keeps the
* release point referenced as long as it's referenced itself; for synchronization on the
@ -437,6 +439,7 @@ Q_SIGNALS:
void colorDescriptionChanged();
void presentationModeHintChanged();
void bufferReleasePointChanged();
void alphaMultiplierChanged();
/**
* Emitted when the Surface has been committed.

View file

@ -30,6 +30,7 @@ class PresentationTimeFeedback;
class XXColorSurfaceV4;
class XXColorFeedbackSurfaceV4;
class LinuxDrmSyncObjSurfaceV1;
class AlphaModifierSurfaceV1;
struct SurfaceState
{
@ -60,6 +61,7 @@ struct SurfaceState
bool contentTypeIsSet = false;
bool presentationModeHintIsSet = false;
bool colorDescriptionIsSet = false;
bool alphaMultiplierIsSet = false;
qint32 bufferScale = 1;
OutputTransform bufferTransform = OutputTransform::Normal;
wl_list frameCallbacks;
@ -80,6 +82,7 @@ struct SurfaceState
uint64_t point = 0;
} acquirePoint;
std::shared_ptr<SyncReleasePoint> releasePoint;
double alphaMultiplier = 1;
struct
{
@ -181,6 +184,7 @@ public:
XXColorSurfaceV4 *xxColorSurface = nullptr;
QList<XXColorFeedbackSurfaceV4 *> xxColorFeedbacks;
LinuxDrmSyncObjSurfaceV1 *syncObjV1 = nullptr;
AlphaModifierSurfaceV1 *alphaModifier = nullptr;
struct
{

View file

@ -23,6 +23,7 @@
#include "utils/kernel.h"
#include "utils/serviceutils.h"
#include "virtualdesktops.h"
#include "wayland/alphamodifier_v1.h"
#include "wayland/appmenu.h"
#include "wayland/clientconnection.h"
#include "wayland/compositor.h"
@ -525,7 +526,7 @@ bool WaylandServer::init()
});
m_externalBrightness = new ExternalBrightnessV1(m_display, m_display);
m_alphaModifierManager = new AlphaModifierManagerV1(m_display, m_display);
return true;
}

View file

@ -63,6 +63,7 @@ class PresentationTime;
class XXColorManagerV4;
class LinuxDrmSyncObjV1Interface;
class RenderBackend;
class AlphaModifierManagerV1;
class KWIN_EXPORT WaylandServer : public QObject
{
@ -291,6 +292,7 @@ private:
XXColorManagerV4 *m_xxColorManager = nullptr;
XdgDialogWmV1Interface *m_xdgDialogWm = nullptr;
ExternalBrightnessV1 *m_externalBrightness = nullptr;
AlphaModifierManagerV1 *m_alphaModifierManager = nullptr;
KWIN_SINGLETON(WaylandServer)
};