backends/wayland: Use linux-dmabuf directly

The main motivation behind this change is to get rid of the dependency
on EGLSurface so the order in which output layers are presented or
updated doesn't matter.

At the moment, if both the cursor and the primary layers are updated
within same frame, the read and draw surfaces in present() will be wrong
for the primary layer.

With fbos, the read and draw surfaces won't matter.
master
Vlad Zahorodnii 2 years ago
parent cb9ffbcd01
commit 182026a4bd

@ -190,20 +190,11 @@ int main() {
mmap(nullptr, size, PROT_WRITE, MAP_SHARED, fd, 0); mmap(nullptr, size, PROT_WRITE, MAP_SHARED, fd, 0);
}" HAVE_MEMFD) }" HAVE_MEMFD)
find_package(Wayland 1.2 OPTIONAL_COMPONENTS Egl) find_package(Wayland 1.21)
set_package_properties(Wayland PROPERTIES set_package_properties(Wayland PROPERTIES
TYPE REQUIRED TYPE REQUIRED
PURPOSE "Required for building KWin with Wayland support" PURPOSE "Required for building KWin with Wayland support"
) )
add_feature_info("Wayland::EGL" Wayland_Egl_FOUND "Enable building of Wayland backend.")
set(HAVE_WAYLAND_EGL FALSE)
if (Wayland_Egl_FOUND)
set(HAVE_WAYLAND_EGL TRUE)
endif()
find_package(Wayland 1.21 REQUIRED COMPONENTS
Server
)
find_package(WaylandProtocols 1.30) find_package(WaylandProtocols 1.30)
set_package_properties(WaylandProtocols PROPERTIES set_package_properties(WaylandProtocols PROPERTIES

@ -1,16 +1,10 @@
target_sources(kwin PRIVATE target_sources(kwin PRIVATE
wayland_backend.cpp wayland_backend.cpp
wayland_display.cpp wayland_display.cpp
wayland_egl_backend.cpp
wayland_logging.cpp wayland_logging.cpp
wayland_output.cpp wayland_output.cpp
wayland_qpainter_backend.cpp wayland_qpainter_backend.cpp
) )
if (HAVE_WAYLAND_EGL) target_link_libraries(kwin KF5::WaylandClient Wayland::Client gbm::gbm)
target_sources(kwin PRIVATE wayland_egl_backend.cpp)
endif()
target_link_libraries(kwin KF5::WaylandClient)
if (HAVE_WAYLAND_EGL)
target_link_libraries(kwin Wayland::Egl gbm::gbm)
endif()

@ -9,11 +9,8 @@
*/ */
#include "wayland_backend.h" #include "wayland_backend.h"
#if HAVE_WAYLAND_EGL
#include "wayland_egl_backend.h"
#include <gbm.h>
#endif
#include "wayland_display.h" #include "wayland_display.h"
#include "wayland_egl_backend.h"
#include "wayland_logging.h" #include "wayland_logging.h"
#include "wayland_output.h" #include "wayland_output.h"
#include "wayland_qpainter_backend.h" #include "wayland_qpainter_backend.h"
@ -31,12 +28,14 @@
#include <QAbstractEventDispatcher> #include <QAbstractEventDispatcher>
#include <drm_fourcc.h>
#include <fcntl.h> #include <fcntl.h>
#include <gbm.h>
#include <linux/input.h> #include <linux/input.h>
#include <unistd.h> #include <unistd.h>
#include <wayland-client-core.h>
#include "../drm/gbm_dmabuf.h" #include "../drm/gbm_dmabuf.h"
#include <drm_fourcc.h>
#define QSIZE_TO_QPOINT(size) QPointF(size.width(), size.height()) #define QSIZE_TO_QPOINT(size) QPointF(size.width(), size.height())
@ -408,7 +407,6 @@ WaylandBackend::WaylandBackend(const WaylandBackendOptions &options, QObject *pa
: OutputBackend(parent) : OutputBackend(parent)
, m_options(options) , m_options(options)
{ {
#if HAVE_WAYLAND_EGL
char const *drm_render_node = "/dev/dri/renderD128"; char const *drm_render_node = "/dev/dri/renderD128";
m_drmFileDescriptor = FileDescriptor(open(drm_render_node, O_RDWR)); m_drmFileDescriptor = FileDescriptor(open(drm_render_node, O_RDWR));
if (!m_drmFileDescriptor.isValid()) { if (!m_drmFileDescriptor.isValid()) {
@ -417,7 +415,6 @@ WaylandBackend::WaylandBackend(const WaylandBackendOptions &options, QObject *pa
return; return;
} }
m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get()); m_gbmDevice = gbm_create_device(m_drmFileDescriptor.get());
#endif
} }
WaylandBackend::~WaylandBackend() WaylandBackend::~WaylandBackend()
@ -431,9 +428,7 @@ WaylandBackend::~WaylandBackend()
m_seat.reset(); m_seat.reset();
m_display.reset(); m_display.reset();
#if HAVE_WAYLAND_EGL
gbm_device_destroy(m_gbmDevice); gbm_device_destroy(m_gbmDevice);
#endif
qCDebug(KWIN_WAYLAND_BACKEND) << "Destroyed Wayland display"; qCDebug(KWIN_WAYLAND_BACKEND) << "Destroyed Wayland display";
} }
@ -508,11 +503,7 @@ std::unique_ptr<InputBackend> WaylandBackend::createInputBackend()
std::unique_ptr<OpenGLBackend> WaylandBackend::createOpenGLBackend() std::unique_ptr<OpenGLBackend> WaylandBackend::createOpenGLBackend()
{ {
#if HAVE_WAYLAND_EGL
return std::make_unique<WaylandEglBackend>(this); return std::make_unique<WaylandEglBackend>(this);
#else
return nullptr;
#endif
} }
std::unique_ptr<QPainterBackend> WaylandBackend::createQPainterBackend() std::unique_ptr<QPainterBackend> WaylandBackend::createQPainterBackend()
@ -559,11 +550,12 @@ void WaylandBackend::togglePointerLock()
QVector<CompositingType> WaylandBackend::supportedCompositors() const QVector<CompositingType> WaylandBackend::supportedCompositors() const
{ {
#if HAVE_WAYLAND_EGL QVector<CompositingType> ret;
return QVector<CompositingType>{OpenGLCompositing, QPainterCompositing}; if (m_display->linuxDmabuf()) {
#else ret.append(OpenGLCompositing);
return QVector<CompositingType>{QPainterCompositing}; }
#endif ret.append(QPainterCompositing);
return ret;
} }
Outputs WaylandBackend::outputs() const Outputs WaylandBackend::outputs() const

@ -245,10 +245,8 @@ private:
QVector<WaylandOutput *> m_outputs; QVector<WaylandOutput *> m_outputs;
std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter; std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter;
bool m_pointerLockRequested = false; bool m_pointerLockRequested = false;
#if HAVE_WAYLAND_EGL
FileDescriptor m_drmFileDescriptor; FileDescriptor m_drmFileDescriptor;
gbm_device *m_gbmDevice; gbm_device *m_gbmDevice;
#endif
}; };
} // namespace Wayland } // namespace Wayland

@ -22,11 +22,13 @@
#include <QThread> #include <QThread>
#include <QWaitCondition> #include <QWaitCondition>
#include <drm_fourcc.h>
#include <poll.h> #include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <wayland-client.h> #include <wayland-client.h>
// Generated in src/wayland. // Generated in src/wayland.
#include "wayland-linux-dmabuf-unstable-v1-client-protocol.h"
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h" #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
#include "wayland-pointer-gestures-unstable-v1-server-protocol.h" #include "wayland-pointer-gestures-unstable-v1-server-protocol.h"
#include "wayland-relative-pointer-unstable-v1-client-protocol.h" #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
@ -146,6 +148,44 @@ private:
bool m_quitting; bool m_quitting;
}; };
WaylandLinuxDmabufV1::WaylandLinuxDmabufV1(wl_registry *registry, uint32_t name, uint32_t version)
{
m_dmabuf = static_cast<zwp_linux_dmabuf_v1 *>(wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version));
static const struct zwp_linux_dmabuf_v1_listener dmabufListener = {
.format = format,
.modifier = modifier,
};
zwp_linux_dmabuf_v1_add_listener(m_dmabuf, &dmabufListener, this);
}
WaylandLinuxDmabufV1::~WaylandLinuxDmabufV1()
{
zwp_linux_dmabuf_v1_destroy(m_dmabuf);
}
zwp_linux_dmabuf_v1 *WaylandLinuxDmabufV1::handle() const
{
return m_dmabuf;
}
QHash<uint32_t, QVector<uint64_t>> WaylandLinuxDmabufV1::formats() const
{
return m_formats;
}
void WaylandLinuxDmabufV1::format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format)
{
WaylandLinuxDmabufV1 *dmabuf = static_cast<WaylandLinuxDmabufV1 *>(data);
dmabuf->m_formats[format].append(DRM_FORMAT_MOD_INVALID);
}
void WaylandLinuxDmabufV1::modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
{
WaylandLinuxDmabufV1 *dmabuf = static_cast<WaylandLinuxDmabufV1 *>(data);
dmabuf->m_formats[format].append((static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo);
}
WaylandDisplay::WaylandDisplay() WaylandDisplay::WaylandDisplay()
{ {
} }
@ -163,6 +203,7 @@ WaylandDisplay::~WaylandDisplay()
m_xdgDecorationManager.reset(); m_xdgDecorationManager.reset();
m_shmPool.reset(); m_shmPool.reset();
m_xdgShell.reset(); m_xdgShell.reset();
m_linuxDmabuf.reset();
if (m_registry) { if (m_registry) {
wl_registry_destroy(m_registry); wl_registry_destroy(m_registry);
@ -195,6 +236,7 @@ bool WaylandDisplay::initialize(const QString &socketName)
m_registry = wl_display_get_registry(m_display); m_registry = wl_display_get_registry(m_display);
wl_registry_add_listener(m_registry, &registryListener, this); wl_registry_add_listener(m_registry, &registryListener, this);
wl_display_roundtrip(m_display); wl_display_roundtrip(m_display);
wl_display_roundtrip(m_display); // get dmabuf formats
return true; return true;
} }
@ -244,6 +286,11 @@ KWayland::Client::XdgDecorationManager *WaylandDisplay::xdgDecorationManager() c
return m_xdgDecorationManager.get(); return m_xdgDecorationManager.get();
} }
WaylandLinuxDmabufV1 *WaylandDisplay::linuxDmabuf() const
{
return m_linuxDmabuf.get();
}
void WaylandDisplay::registry_global(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) void WaylandDisplay::registry_global(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
{ {
WaylandDisplay *display = static_cast<WaylandDisplay *>(data); WaylandDisplay *display = static_cast<WaylandDisplay *>(data);
@ -275,6 +322,8 @@ void WaylandDisplay::registry_global(void *data, wl_registry *registry, uint32_t
} else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
display->m_xdgDecorationManager = std::make_unique<KWayland::Client::XdgDecorationManager>(); display->m_xdgDecorationManager = std::make_unique<KWayland::Client::XdgDecorationManager>();
display->m_xdgDecorationManager->setup(static_cast<zxdg_decoration_manager_v1 *>(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, std::min(version, 1u)))); display->m_xdgDecorationManager->setup(static_cast<zxdg_decoration_manager_v1 *>(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, std::min(version, 1u))));
} else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
display->m_linuxDmabuf = std::make_unique<WaylandLinuxDmabufV1>(registry, name, std::min(version, 3u));
} }
} }

@ -6,12 +6,14 @@
#pragma once #pragma once
#include <QHash>
#include <QObject> #include <QObject>
#include <memory> #include <memory>
struct wl_display; struct wl_display;
struct wl_registry; struct wl_registry;
struct zwp_linux_dmabuf_v1;
namespace KWayland namespace KWayland
{ {
@ -35,6 +37,23 @@ namespace Wayland
class WaylandEventThread; class WaylandEventThread;
class WaylandLinuxDmabufV1
{
public:
WaylandLinuxDmabufV1(wl_registry *registry, uint32_t name, uint32_t version);
~WaylandLinuxDmabufV1();
zwp_linux_dmabuf_v1 *handle() const;
QHash<uint32_t, QVector<uint64_t>> formats() const;
private:
static void format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format);
static void modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo);
zwp_linux_dmabuf_v1 *m_dmabuf;
QHash<uint32_t, QVector<uint64_t>> m_formats;
};
class WaylandDisplay : public QObject class WaylandDisplay : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -54,6 +73,7 @@ public:
KWayland::Client::XdgDecorationManager *xdgDecorationManager() const; KWayland::Client::XdgDecorationManager *xdgDecorationManager() const;
KWayland::Client::ShmPool *shmPool() const; KWayland::Client::ShmPool *shmPool() const;
KWayland::Client::XdgShell *xdgShell() const; KWayland::Client::XdgShell *xdgShell() const;
WaylandLinuxDmabufV1 *linuxDmabuf() const;
public Q_SLOTS: public Q_SLOTS:
void flush(); void flush();
@ -65,6 +85,7 @@ private:
wl_display *m_display = nullptr; wl_display *m_display = nullptr;
wl_registry *m_registry = nullptr; wl_registry *m_registry = nullptr;
std::unique_ptr<WaylandEventThread> m_eventThread; std::unique_ptr<WaylandEventThread> m_eventThread;
std::unique_ptr<WaylandLinuxDmabufV1> m_linuxDmabuf;
std::unique_ptr<KWayland::Client::Compositor> m_compositor; std::unique_ptr<KWayland::Client::Compositor> m_compositor;
std::unique_ptr<KWayland::Client::PointerConstraints> m_pointerConstraints; std::unique_ptr<KWayland::Client::PointerConstraints> m_pointerConstraints;
std::unique_ptr<KWayland::Client::PointerGestures> m_pointerGestures; std::unique_ptr<KWayland::Client::PointerGestures> m_pointerGestures;

@ -7,11 +7,11 @@
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
*/ */
#define WL_EGL_PLATFORM 1
#include "wayland_egl_backend.h" #include "wayland_egl_backend.h"
#include "basiceglsurfacetexture_internal.h" #include "basiceglsurfacetexture_internal.h"
#include "basiceglsurfacetexture_wayland.h" #include "basiceglsurfacetexture_wayland.h"
#include "../drm/gbm_dmabuf.h"
#include "wayland_backend.h" #include "wayland_backend.h"
#include "wayland_display.h" #include "wayland_display.h"
@ -37,85 +37,168 @@
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <gbm.h> #include <gbm.h>
#include "wayland-linux-dmabuf-unstable-v1-client-protocol.h"
namespace KWin namespace KWin
{ {
namespace Wayland namespace Wayland
{ {
static QVector<EGLint> regionToRects(const QRegion &region, Output *output) WaylandEglLayerBuffer::WaylandEglLayerBuffer(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, WaylandEglBackend *backend)
: m_backend(backend)
{ {
const int height = output->modeSize().height(); gbm_device *gbmDevice = backend->backend()->gbmDevice();
const QMatrix4x4 matrix = WaylandOutput::logicalToNativeMatrix(output->rect(),
output->scale(),
output->transform());
QVector<EGLint> rects; if (modifiers.isEmpty()) {
rects.reserve(region.rectCount() * 4); m_bo = gbm_bo_create(gbmDevice,
for (const QRect &_rect : region) { size.width(),
const QRect rect = matrix.mapRect(_rect); size.height(),
format,
GBM_BO_USE_RENDERING);
} else {
m_bo = gbm_bo_create_with_modifiers2(gbmDevice,
size.width(),
size.height(),
format,
modifiers.constData(),
modifiers.size(),
GBM_BO_USE_RENDERING);
}
rects << rect.left(); if (!m_bo) {
rects << height - (rect.y() + rect.height()); qCCritical(KWIN_WAYLAND_BACKEND) << "Failed to allocate a buffer for an output layer";
rects << rect.width(); return;
rects << rect.height();
} }
return rects;
DmaBufAttributes attributes = dmaBufAttributesForBo(m_bo);
zwp_linux_buffer_params_v1 *params = zwp_linux_dmabuf_v1_create_params(backend->backend()->display()->linuxDmabuf()->handle());
for (int i = 0; i < attributes.planeCount; ++i) {
zwp_linux_buffer_params_v1_add(params,
attributes.fd[i].get(),
i,
attributes.offset[i],
attributes.pitch[i],
attributes.modifier >> 32,
attributes.modifier & 0xffffffff);
}
m_buffer = zwp_linux_buffer_params_v1_create_immed(params, size.width(), size.height(), format, ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
zwp_linux_buffer_params_v1_destroy(params);
m_texture = backend->importDmaBufAsTexture(std::move(attributes));
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
} }
WaylandEglPrimaryLayer::WaylandEglPrimaryLayer(WaylandOutput *output, WaylandEglBackend *backend) WaylandEglLayerBuffer::~WaylandEglLayerBuffer()
: m_waylandOutput(output)
, m_backend(backend)
{ {
const QSize nativeSize = m_waylandOutput->pixelSize(); m_texture.reset();
m_eglWindow = wl_egl_window_create(*m_waylandOutput->surface(), nativeSize.width(), nativeSize.height()); m_framebuffer.reset();
if (!m_eglWindow) {
qCCritical(KWIN_WAYLAND_BACKEND) << "Creating Wayland Egl window failed"; if (m_buffer) {
return; wl_buffer_destroy(m_buffer);
}
if (m_bo) {
gbm_bo_destroy(m_bo);
} }
m_fbo = std::make_unique<GLFramebuffer>(0, nativeSize); }
if (m_backend->havePlatformBase()) { wl_buffer *WaylandEglLayerBuffer::buffer() const
m_eglSurface = eglCreatePlatformWindowSurfaceEXT(m_backend->eglDisplay(), m_backend->config(), (void *)m_eglWindow, nullptr); {
} else { return m_buffer;
m_eglSurface = eglCreateWindowSurface(m_backend->eglDisplay(), m_backend->config(), m_eglWindow, nullptr); }
GLFramebuffer *WaylandEglLayerBuffer::framebuffer() const
{
return m_framebuffer.get();
}
int WaylandEglLayerBuffer::age() const
{
return m_age;
}
WaylandEglLayerSwapchain::WaylandEglLayerSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, WaylandEglBackend *backend)
: m_backend(backend)
, m_size(size)
{
for (int i = 0; i < 2; ++i) {
m_buffers.append(std::make_shared<WaylandEglLayerBuffer>(size, format, modifiers, backend));
} }
if (m_eglSurface == EGL_NO_SURFACE) { }
qCCritical(KWIN_WAYLAND_BACKEND) << "Create Window Surface failed";
WaylandEglLayerSwapchain::~WaylandEglLayerSwapchain()
{
}
QSize WaylandEglLayerSwapchain::size() const
{
return m_size;
}
std::shared_ptr<WaylandEglLayerBuffer> WaylandEglLayerSwapchain::acquire()
{
m_index = (m_index + 1) % m_buffers.count();
return m_buffers[m_index];
}
void WaylandEglLayerSwapchain::release(std::shared_ptr<WaylandEglLayerBuffer> buffer)
{
Q_ASSERT(m_buffers[m_index] == buffer);
for (qsizetype i = 0; i < m_buffers.count(); ++i) {
if (m_buffers[i] == buffer) {
m_buffers[i]->m_age = 1;
} else if (m_buffers[i]->m_age > 0) {
m_buffers[i]->m_age++;
}
} }
} }
WaylandEglPrimaryLayer::WaylandEglPrimaryLayer(WaylandOutput *output, WaylandEglBackend *backend)
: m_waylandOutput(output)
, m_backend(backend)
{
}
WaylandEglPrimaryLayer::~WaylandEglPrimaryLayer() WaylandEglPrimaryLayer::~WaylandEglPrimaryLayer()
{ {
wl_egl_window_destroy(m_eglWindow);
} }
GLFramebuffer *WaylandEglPrimaryLayer::fbo() const GLFramebuffer *WaylandEglPrimaryLayer::fbo() const
{ {
return m_fbo.get(); return m_buffer->framebuffer();
} }
std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::beginFrame() std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::beginFrame()
{ {
if (eglMakeCurrent(m_backend->eglDisplay(), m_eglSurface, m_eglSurface, m_backend->context()) == EGL_FALSE) { if (eglMakeCurrent(m_backend->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_backend->context()) == EGL_FALSE) {
qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed"; qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed";
return std::nullopt; return std::nullopt;
} }
const QSize nativeSize = m_waylandOutput->pixelSize(); const QSize nativeSize = m_waylandOutput->pixelSize();
if (!m_fbo || m_fbo->size() != nativeSize) { if (!m_swapchain || m_swapchain->size() != nativeSize) {
m_fbo = std::make_unique<GLFramebuffer>(0, nativeSize); const WaylandLinuxDmabufV1 *dmabuf = m_backend->backend()->display()->linuxDmabuf();
m_bufferAge = 0; const uint32_t format = DRM_FORMAT_XRGB8888;
wl_egl_window_resize(m_eglWindow, nativeSize.width(), nativeSize.height(), 0, 0); if (!dmabuf->formats().contains(format)) {
qCCritical(KWIN_WAYLAND_BACKEND) << "DRM_FORMAT_XRGB8888 is unsupported";
return std::nullopt;
}
const QVector<uint64_t> modifiers = dmabuf->formats().value(format);
m_swapchain = std::make_unique<WaylandEglLayerSwapchain>(nativeSize, format, modifiers, m_backend);
} }
m_buffer = m_swapchain->acquire();
QRegion repair; QRegion repair;
if (m_backend->supportsBufferAge()) { if (m_backend->supportsBufferAge()) {
repair = m_damageJournal.accumulate(m_bufferAge, infiniteRegion()); repair = m_damageJournal.accumulate(m_buffer->age(), infiniteRegion());
} }
GLFramebuffer::pushFramebuffer(m_fbo.get()); GLFramebuffer::pushFramebuffer(m_buffer->framebuffer());
return OutputLayerBeginFrameInfo{ return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_fbo.get()), .renderTarget = RenderTarget(m_buffer->framebuffer()),
.repaint = repair, .repaint = repair,
}; };
} }
@ -127,39 +210,16 @@ bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegi
return true; return true;
} }
void WaylandEglPrimaryLayer::aboutToStartPainting(const QRegion &damage)
{
if (m_bufferAge > 0 && !damage.isEmpty() && m_backend->supportsPartialUpdate()) {
QVector<EGLint> rects = regionToRects(damage, m_waylandOutput);
const bool correct = eglSetDamageRegionKHR(m_backend->eglDisplay(), m_eglSurface,
rects.data(), rects.count() / 4);
if (!correct) {
qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError();
}
}
}
void WaylandEglPrimaryLayer::present() void WaylandEglPrimaryLayer::present()
{ {
m_waylandOutput->surface()->setupFrameCallback(); KWayland::Client::Surface *surface = m_waylandOutput->surface();
m_waylandOutput->surface()->setScale(std::ceil(m_waylandOutput->scale())); surface->attachBuffer(m_buffer->buffer());
surface->damage(m_damageJournal.lastDamage());
surface->setScale(std::ceil(m_waylandOutput->scale()));
surface->commit();
Q_EMIT m_waylandOutput->outputChange(m_damageJournal.lastDamage()); Q_EMIT m_waylandOutput->outputChange(m_damageJournal.lastDamage());
if (m_backend->supportsSwapBuffersWithDamage()) { m_swapchain->release(m_buffer);
QVector<EGLint> rects = regionToRects(m_damageJournal.lastDamage(), m_waylandOutput);
if (!eglSwapBuffersWithDamageEXT(m_backend->eglDisplay(), m_eglSurface,
rects.data(), rects.count() / 4)) {
qCCritical(KWIN_WAYLAND_BACKEND, "eglSwapBuffersWithDamage() failed: %x", eglGetError());
}
} else {
if (!eglSwapBuffers(m_backend->eglDisplay(), m_eglSurface)) {
qCCritical(KWIN_WAYLAND_BACKEND, "eglSwapBuffers() failed: %x", eglGetError());
}
}
if (m_backend->supportsBufferAge()) {
eglQuerySurface(m_backend->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
}
} }
WaylandEglCursorLayer::WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend) WaylandEglCursorLayer::WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend)
@ -257,6 +317,11 @@ WaylandEglBackend::~WaylandEglBackend()
cleanup(); cleanup();
} }
WaylandBackend *WaylandEglBackend::backend() const
{
return m_backend;
}
void WaylandEglBackend::cleanupSurfaces() void WaylandEglBackend::cleanupSurfaces()
{ {
m_outputs.clear(); m_outputs.clear();

@ -12,10 +12,6 @@
#include "abstract_egl_backend.h" #include "abstract_egl_backend.h"
#include "core/outputlayer.h" #include "core/outputlayer.h"
#include "utils/damagejournal.h" #include "utils/damagejournal.h"
// wayland
#include <dmabuftexture.h>
#include <optional>
#include <wayland-egl.h>
#include <KWayland/Client/buffer.h> #include <KWayland/Client/buffer.h>
@ -36,6 +32,44 @@ class WaylandBackend;
class WaylandOutput; class WaylandOutput;
class WaylandEglBackend; class WaylandEglBackend;
class WaylandEglLayerBuffer
{
public:
WaylandEglLayerBuffer(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, WaylandEglBackend *backend);
~WaylandEglLayerBuffer();
wl_buffer *buffer() const;
GLFramebuffer *framebuffer() const;
int age() const;
private:
WaylandEglBackend *m_backend;
wl_buffer *m_buffer = nullptr;
gbm_bo *m_bo = nullptr;
std::unique_ptr<GLFramebuffer> m_framebuffer;
std::shared_ptr<GLTexture> m_texture;
int m_age = 0;
friend class WaylandEglLayerSwapchain;
};
class WaylandEglLayerSwapchain
{
public:
WaylandEglLayerSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, WaylandEglBackend *backend);
~WaylandEglLayerSwapchain();
QSize size() const;
std::shared_ptr<WaylandEglLayerBuffer> acquire();
void release(std::shared_ptr<WaylandEglLayerBuffer> buffer);
private:
WaylandEglBackend *m_backend;
QSize m_size;
QVector<std::shared_ptr<WaylandEglLayerBuffer>> m_buffers;
int m_index = 0;
};
class WaylandEglPrimaryLayer : public OutputLayer class WaylandEglPrimaryLayer : public OutputLayer
{ {
public: public:
@ -47,15 +81,12 @@ public:
std::optional<OutputLayerBeginFrameInfo> beginFrame() override; std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void aboutToStartPainting(const QRegion &damage) override;
private: private:
WaylandOutput *m_waylandOutput; WaylandOutput *m_waylandOutput;
wl_egl_window *m_eglWindow = nullptr;
EGLSurface m_eglSurface = EGL_NO_SURFACE;
int m_bufferAge = 0;
DamageJournal m_damageJournal; DamageJournal m_damageJournal;
std::unique_ptr<GLFramebuffer> m_fbo; std::unique_ptr<WaylandEglLayerSwapchain> m_swapchain;
std::shared_ptr<WaylandEglLayerBuffer> m_buffer;
WaylandEglBackend *const m_backend; WaylandEglBackend *const m_backend;
friend class WaylandEglBackend; friend class WaylandEglBackend;
@ -110,6 +141,8 @@ public:
WaylandEglBackend(WaylandBackend *b); WaylandEglBackend(WaylandBackend *b);
~WaylandEglBackend() override; ~WaylandEglBackend() override;
WaylandBackend *backend() const;
std::unique_ptr<SurfaceTexture> createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; std::unique_ptr<SurfaceTexture> createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
std::unique_ptr<SurfaceTexture> createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; std::unique_ptr<SurfaceTexture> createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
@ -118,11 +151,6 @@ public:
OutputLayer *primaryLayer(Output *output) override; OutputLayer *primaryLayer(Output *output) override;
WaylandEglCursorLayer *cursorLayer(Output *output); WaylandEglCursorLayer *cursorLayer(Output *output);
bool havePlatformBase() const
{
return m_havePlatformBase;
}
std::shared_ptr<KWin::GLTexture> textureForOutput(KWin::Output *output) const override; std::shared_ptr<KWin::GLTexture> textureForOutput(KWin::Output *output) const override;
private: private:

@ -15,7 +15,6 @@
#cmakedefine01 HAVE_X11_XINPUT #cmakedefine01 HAVE_X11_XINPUT
#cmakedefine01 HAVE_GBM_BO_GET_FD_FOR_PLANE #cmakedefine01 HAVE_GBM_BO_GET_FD_FOR_PLANE
#cmakedefine01 HAVE_MEMFD #cmakedefine01 HAVE_MEMFD
#cmakedefine01 HAVE_WAYLAND_EGL
#cmakedefine01 HAVE_BREEZE_DECO #cmakedefine01 HAVE_BREEZE_DECO
#cmakedefine01 HAVE_SCHED_RESET_ON_FORK #cmakedefine01 HAVE_SCHED_RESET_ON_FORK
#cmakedefine01 HAVE_ACCESSIBILITY #cmakedefine01 HAVE_ACCESSIBILITY

@ -1777,8 +1777,6 @@ QString Workspace::supportInformation() const
support.append(HAVE_X11_XCB ? yes : no); support.append(HAVE_X11_XCB ? yes : no);
support.append(QStringLiteral("HAVE_EPOXY_GLX: ")); support.append(QStringLiteral("HAVE_EPOXY_GLX: "));
support.append(HAVE_EPOXY_GLX ? yes : no); support.append(HAVE_EPOXY_GLX ? yes : no);
support.append(QStringLiteral("HAVE_WAYLAND_EGL: "));
support.append(HAVE_WAYLAND_EGL ? yes : no);
support.append(QStringLiteral("\n")); support.append(QStringLiteral("\n"));
if (auto c = kwinApp()->x11Connection()) { if (auto c = kwinApp()->x11Connection()) {

Loading…
Cancel
Save