backends/x11: Avoid rendering to buffers held by Xorg
Otherwise it's possible to see visual artifacts.
This commit is contained in:
parent
13d1b8b16f
commit
b0bdffe08f
7 changed files with 235 additions and 91 deletions
|
@ -669,6 +669,13 @@ void X11WindowedBackend::handleXinputEvent(xcb_ge_generic_event_t *ge)
|
||||||
void X11WindowedBackend::handlePresentEvent(xcb_ge_generic_event_t *ge)
|
void X11WindowedBackend::handlePresentEvent(xcb_ge_generic_event_t *ge)
|
||||||
{
|
{
|
||||||
switch (ge->event_type) {
|
switch (ge->event_type) {
|
||||||
|
case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
|
||||||
|
xcb_present_idle_notify_event_t *idleNotify = reinterpret_cast<xcb_present_idle_notify_event_t *>(ge);
|
||||||
|
if (X11WindowedOutput *output = findOutput(idleNotify->window)) {
|
||||||
|
output->handlePresentIdleNotify(idleNotify);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
|
case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
|
||||||
xcb_present_complete_notify_event_t *completeNotify = reinterpret_cast<xcb_present_complete_notify_event_t *>(ge);
|
xcb_present_complete_notify_event_t *completeNotify = reinterpret_cast<xcb_present_complete_notify_event_t *>(ge);
|
||||||
if (X11WindowedOutput *output = findOutput(completeNotify->window)) {
|
if (X11WindowedOutput *output = findOutput(completeNotify->window)) {
|
||||||
|
|
|
@ -15,42 +15,14 @@
|
||||||
#include "x11_windowed_output.h"
|
#include "x11_windowed_output.h"
|
||||||
|
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
#include <xcb/dri3.h>
|
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
X11WindowedEglLayerBuffer::X11WindowedEglLayerBuffer(GbmGraphicsBuffer *graphicsBuffer, uint32_t depth, uint32_t bpp, xcb_drawable_t drawable, X11WindowedEglBackend *backend)
|
X11WindowedEglLayerBuffer::X11WindowedEglLayerBuffer(GbmGraphicsBuffer *graphicsBuffer, X11WindowedEglBackend *backend)
|
||||||
: m_backend(backend)
|
: m_graphicsBuffer(graphicsBuffer)
|
||||||
, m_graphicsBuffer(graphicsBuffer)
|
|
||||||
{
|
{
|
||||||
X11WindowedBackend *x11Backend = backend->backend();
|
m_texture = backend->importDmaBufAsTexture(*graphicsBuffer->dmabufAttributes());
|
||||||
const DmaBufAttributes *attributes = graphicsBuffer->dmabufAttributes();
|
|
||||||
|
|
||||||
m_pixmap = xcb_generate_id(x11Backend->connection());
|
|
||||||
if (x11Backend->driMajorVersion() >= 1 || x11Backend->driMinorVersion() >= 2) {
|
|
||||||
// xcb_dri3_pixmap_from_buffers() takes the ownership of the file descriptors.
|
|
||||||
int fds[4] = {
|
|
||||||
attributes->fd[0].duplicate().take(),
|
|
||||||
attributes->fd[1].duplicate().take(),
|
|
||||||
attributes->fd[2].duplicate().take(),
|
|
||||||
attributes->fd[3].duplicate().take(),
|
|
||||||
};
|
|
||||||
xcb_dri3_pixmap_from_buffers(x11Backend->connection(), m_pixmap, drawable, attributes->planeCount,
|
|
||||||
attributes->width, attributes->height,
|
|
||||||
attributes->pitch[0], attributes->offset[0],
|
|
||||||
attributes->pitch[1], attributes->offset[1],
|
|
||||||
attributes->pitch[2], attributes->offset[2],
|
|
||||||
attributes->pitch[3], attributes->offset[3],
|
|
||||||
depth, bpp, attributes->modifier, fds);
|
|
||||||
} else {
|
|
||||||
// xcb_dri3_pixmap_from_buffer() takes the ownership of the file descriptor.
|
|
||||||
xcb_dri3_pixmap_from_buffer(x11Backend->connection(), m_pixmap, drawable,
|
|
||||||
attributes->height * attributes->pitch[0], attributes->width, attributes->height,
|
|
||||||
attributes->pitch[0], depth, bpp, attributes->fd[0].duplicate().take());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_texture = backend->importDmaBufAsTexture(*attributes);
|
|
||||||
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
|
m_framebuffer = std::make_unique<GLFramebuffer>(m_texture.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,14 +30,12 @@ X11WindowedEglLayerBuffer::~X11WindowedEglLayerBuffer()
|
||||||
{
|
{
|
||||||
m_texture.reset();
|
m_texture.reset();
|
||||||
m_framebuffer.reset();
|
m_framebuffer.reset();
|
||||||
|
|
||||||
xcb_free_pixmap(m_backend->backend()->connection(), m_pixmap);
|
|
||||||
m_graphicsBuffer->drop();
|
m_graphicsBuffer->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_pixmap_t X11WindowedEglLayerBuffer::pixmap() const
|
GraphicsBuffer *X11WindowedEglLayerBuffer::graphicsBuffer() const
|
||||||
{
|
{
|
||||||
return m_pixmap;
|
return m_graphicsBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<GLTexture> X11WindowedEglLayerBuffer::texture() const
|
std::shared_ptr<GLTexture> X11WindowedEglLayerBuffer::texture() const
|
||||||
|
@ -83,19 +53,13 @@ int X11WindowedEglLayerBuffer::age() const
|
||||||
return m_age;
|
return m_age;
|
||||||
}
|
}
|
||||||
|
|
||||||
X11WindowedEglLayerSwapchain::X11WindowedEglLayerSwapchain(const QSize &size, uint32_t format, uint32_t depth, uint32_t bpp, const QVector<uint64_t> &modifiers, xcb_drawable_t drawable, X11WindowedEglBackend *backend)
|
X11WindowedEglLayerSwapchain::X11WindowedEglLayerSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, X11WindowedEglBackend *backend)
|
||||||
: m_size(size)
|
: m_backend(backend)
|
||||||
|
, m_allocator(new GbmGraphicsBufferAllocator(backend->backend()->gbmDevice()))
|
||||||
|
, m_size(size)
|
||||||
|
, m_format(format)
|
||||||
|
, m_modifiers(modifiers)
|
||||||
{
|
{
|
||||||
GbmGraphicsBufferAllocator allocator(backend->backend()->gbmDevice());
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i) {
|
|
||||||
GbmGraphicsBuffer *graphicsBuffer = allocator.allocate(size, format, modifiers);
|
|
||||||
if (!graphicsBuffer) {
|
|
||||||
qCCritical(KWIN_X11WINDOWED) << "Failed to allocate a buffer for an output layer";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m_buffers.append(std::make_shared<X11WindowedEglLayerBuffer>(graphicsBuffer, depth, bpp, drawable, backend));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
X11WindowedEglLayerSwapchain::~X11WindowedEglLayerSwapchain()
|
X11WindowedEglLayerSwapchain::~X11WindowedEglLayerSwapchain()
|
||||||
|
@ -109,14 +73,26 @@ QSize X11WindowedEglLayerSwapchain::size() const
|
||||||
|
|
||||||
std::shared_ptr<X11WindowedEglLayerBuffer> X11WindowedEglLayerSwapchain::acquire()
|
std::shared_ptr<X11WindowedEglLayerBuffer> X11WindowedEglLayerSwapchain::acquire()
|
||||||
{
|
{
|
||||||
m_index = (m_index + 1) % m_buffers.count();
|
for (const auto &buffer : std::as_const(m_buffers)) {
|
||||||
return m_buffers[m_index];
|
if (!buffer->graphicsBuffer()->isReferenced()) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GbmGraphicsBuffer *graphicsBuffer = m_allocator->allocate(m_size, m_format, m_modifiers);
|
||||||
|
if (!graphicsBuffer) {
|
||||||
|
qCWarning(KWIN_X11WINDOWED) << "Failed to allocate layer swapchain buffer";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto buffer = std::make_shared<X11WindowedEglLayerBuffer>(graphicsBuffer, m_backend);
|
||||||
|
m_buffers.append(buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11WindowedEglLayerSwapchain::release(std::shared_ptr<X11WindowedEglLayerBuffer> buffer)
|
void X11WindowedEglLayerSwapchain::release(std::shared_ptr<X11WindowedEglLayerBuffer> buffer)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_buffers[m_index] == buffer);
|
|
||||||
|
|
||||||
for (qsizetype i = 0; i < m_buffers.count(); ++i) {
|
for (qsizetype i = 0; i < m_buffers.count(); ++i) {
|
||||||
if (m_buffers[i] == buffer) {
|
if (m_buffers[i] == buffer) {
|
||||||
m_buffers[i]->m_age = 1;
|
m_buffers[i]->m_age = 1;
|
||||||
|
@ -143,7 +119,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame(
|
||||||
if (!formatTable.contains(format)) {
|
if (!formatTable.contains(format)) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
m_swapchain = std::make_unique<X11WindowedEglLayerSwapchain>(bufferSize, format, 24, 32, formatTable[format], m_output->window(), m_backend);
|
m_swapchain = std::make_unique<X11WindowedEglLayerSwapchain>(bufferSize, format, formatTable[format], m_backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_buffer = m_swapchain->acquire();
|
m_buffer = m_swapchain->acquire();
|
||||||
|
@ -168,6 +144,9 @@ bool X11WindowedEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const Q
|
||||||
|
|
||||||
void X11WindowedEglPrimaryLayer::present()
|
void X11WindowedEglPrimaryLayer::present()
|
||||||
{
|
{
|
||||||
|
xcb_pixmap_t pixmap = m_output->importBuffer(m_buffer->graphicsBuffer());
|
||||||
|
Q_ASSERT(pixmap != XCB_PIXMAP_NONE);
|
||||||
|
|
||||||
xcb_xfixes_region_t valid = 0;
|
xcb_xfixes_region_t valid = 0;
|
||||||
xcb_xfixes_region_t update = 0;
|
xcb_xfixes_region_t update = 0;
|
||||||
uint32_t serial = 0;
|
uint32_t serial = 0;
|
||||||
|
@ -176,7 +155,7 @@ void X11WindowedEglPrimaryLayer::present()
|
||||||
|
|
||||||
xcb_present_pixmap(m_output->backend()->connection(),
|
xcb_present_pixmap(m_output->backend()->connection(),
|
||||||
m_output->window(),
|
m_output->window(),
|
||||||
m_buffer->pixmap(),
|
pixmap,
|
||||||
serial,
|
serial,
|
||||||
valid,
|
valid,
|
||||||
update,
|
update,
|
||||||
|
|
|
@ -24,17 +24,15 @@ class X11WindowedEglBackend;
|
||||||
class X11WindowedEglLayerBuffer
|
class X11WindowedEglLayerBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
X11WindowedEglLayerBuffer(GbmGraphicsBuffer *graphicsBuffers, uint32_t depth, uint32_t bpp, xcb_drawable_t drawable, X11WindowedEglBackend *backend);
|
X11WindowedEglLayerBuffer(GbmGraphicsBuffer *graphicsBuffers, X11WindowedEglBackend *backend);
|
||||||
~X11WindowedEglLayerBuffer();
|
~X11WindowedEglLayerBuffer();
|
||||||
|
|
||||||
xcb_pixmap_t pixmap() const;
|
GraphicsBuffer *graphicsBuffer() const;
|
||||||
std::shared_ptr<GLTexture> texture() const;
|
std::shared_ptr<GLTexture> texture() const;
|
||||||
GLFramebuffer *framebuffer() const;
|
GLFramebuffer *framebuffer() const;
|
||||||
int age() const;
|
int age() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
X11WindowedEglBackend *m_backend;
|
|
||||||
xcb_pixmap_t m_pixmap = XCB_PIXMAP_NONE;
|
|
||||||
GbmGraphicsBuffer *m_graphicsBuffer;
|
GbmGraphicsBuffer *m_graphicsBuffer;
|
||||||
std::unique_ptr<GLFramebuffer> m_framebuffer;
|
std::unique_ptr<GLFramebuffer> m_framebuffer;
|
||||||
std::shared_ptr<GLTexture> m_texture;
|
std::shared_ptr<GLTexture> m_texture;
|
||||||
|
@ -45,7 +43,7 @@ private:
|
||||||
class X11WindowedEglLayerSwapchain
|
class X11WindowedEglLayerSwapchain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
X11WindowedEglLayerSwapchain(const QSize &size, uint32_t format, uint32_t depth, uint32_t bpp, const QVector<uint64_t> &modifiers, xcb_drawable_t drawable, X11WindowedEglBackend *backend);
|
X11WindowedEglLayerSwapchain(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers, X11WindowedEglBackend *backend);
|
||||||
~X11WindowedEglLayerSwapchain();
|
~X11WindowedEglLayerSwapchain();
|
||||||
|
|
||||||
QSize size() const;
|
QSize size() const;
|
||||||
|
@ -54,9 +52,12 @@ public:
|
||||||
void release(std::shared_ptr<X11WindowedEglLayerBuffer> buffer);
|
void release(std::shared_ptr<X11WindowedEglLayerBuffer> buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
X11WindowedEglBackend *m_backend;
|
||||||
|
std::unique_ptr<GbmGraphicsBufferAllocator> m_allocator;
|
||||||
QSize m_size;
|
QSize m_size;
|
||||||
|
uint32_t m_format;
|
||||||
|
QVector<uint64_t> m_modifiers;
|
||||||
QVector<std::shared_ptr<X11WindowedEglLayerBuffer>> m_buffers;
|
QVector<std::shared_ptr<X11WindowedEglLayerBuffer>> m_buffers;
|
||||||
int m_index = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class X11WindowedEglPrimaryLayer : public OutputLayer
|
class X11WindowedEglPrimaryLayer : public OutputLayer
|
||||||
|
|
|
@ -9,10 +9,12 @@
|
||||||
#include "x11_windowed_output.h"
|
#include "x11_windowed_output.h"
|
||||||
#include "../common/kwinxrenderutils.h"
|
#include "../common/kwinxrenderutils.h"
|
||||||
#include "x11_windowed_backend.h"
|
#include "x11_windowed_backend.h"
|
||||||
|
#include "x11_windowed_logging.h"
|
||||||
|
|
||||||
#include <config-kwin.h>
|
#include <config-kwin.h>
|
||||||
|
|
||||||
#include "composite.h"
|
#include "composite.h"
|
||||||
|
#include "core/graphicsbuffer.h"
|
||||||
#include "core/renderbackend.h"
|
#include "core/renderbackend.h"
|
||||||
#include "core/renderlayer.h"
|
#include "core/renderlayer.h"
|
||||||
#include "core/renderloop_p.h"
|
#include "core/renderloop_p.h"
|
||||||
|
@ -29,9 +31,54 @@
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
#include <xcb/dri3.h>
|
||||||
|
#include <xcb/shm.h>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
X11WindowedBuffer::X11WindowedBuffer(X11WindowedOutput *output, xcb_pixmap_t pixmap, GraphicsBuffer *graphicsBuffer)
|
||||||
|
: m_output(output)
|
||||||
|
, m_buffer(graphicsBuffer)
|
||||||
|
, m_pixmap(pixmap)
|
||||||
|
{
|
||||||
|
connect(graphicsBuffer, &GraphicsBuffer::destroyed, this, &X11WindowedBuffer::defunct);
|
||||||
|
}
|
||||||
|
|
||||||
|
X11WindowedBuffer::~X11WindowedBuffer()
|
||||||
|
{
|
||||||
|
m_buffer->disconnect(this);
|
||||||
|
xcb_free_pixmap(m_output->backend()->connection(), m_pixmap);
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphicsBuffer *X11WindowedBuffer::buffer() const
|
||||||
|
{
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_pixmap_t X11WindowedBuffer::pixmap() const
|
||||||
|
{
|
||||||
|
return m_pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11WindowedBuffer::lock()
|
||||||
|
{
|
||||||
|
if (!m_locked) {
|
||||||
|
m_locked = true;
|
||||||
|
m_buffer->ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11WindowedBuffer::unlock()
|
||||||
|
{
|
||||||
|
if (m_locked) {
|
||||||
|
m_locked = false;
|
||||||
|
m_buffer->unref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
X11WindowedCursor::X11WindowedCursor(X11WindowedOutput *output)
|
X11WindowedCursor::X11WindowedCursor(X11WindowedOutput *output)
|
||||||
: m_output(output)
|
: m_output(output)
|
||||||
{
|
{
|
||||||
|
@ -105,6 +152,8 @@ X11WindowedOutput::X11WindowedOutput(X11WindowedBackend *backend)
|
||||||
|
|
||||||
X11WindowedOutput::~X11WindowedOutput()
|
X11WindowedOutput::~X11WindowedOutput()
|
||||||
{
|
{
|
||||||
|
m_buffers.clear();
|
||||||
|
|
||||||
xcb_present_select_input(m_backend->connection(), m_presentEvent, m_window, 0);
|
xcb_present_select_input(m_backend->connection(), m_presentEvent, m_window, 0);
|
||||||
xcb_unmap_window(m_backend->connection(), m_window);
|
xcb_unmap_window(m_backend->connection(), m_window);
|
||||||
xcb_destroy_window(m_backend->connection(), m_window);
|
xcb_destroy_window(m_backend->connection(), m_window);
|
||||||
|
@ -198,7 +247,7 @@ void X11WindowedOutput::init(const QSize &pixelSize, qreal scale)
|
||||||
// select xinput 2 events
|
// select xinput 2 events
|
||||||
initXInputForWindow();
|
initXInputForWindow();
|
||||||
|
|
||||||
const uint32_t presentEventMask = XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY;
|
const uint32_t presentEventMask = XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY;
|
||||||
m_presentEvent = xcb_generate_id(m_backend->connection());
|
m_presentEvent = xcb_generate_id(m_backend->connection());
|
||||||
xcb_present_select_input(m_backend->connection(), m_presentEvent, m_window, presentEventMask);
|
xcb_present_select_input(m_backend->connection(), m_presentEvent, m_window, presentEventMask);
|
||||||
|
|
||||||
|
@ -265,6 +314,16 @@ void X11WindowedOutput::handlePresentCompleteNotify(xcb_present_complete_notify_
|
||||||
RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp);
|
RenderLoopPrivate::get(m_renderLoop.get())->notifyFrameCompleted(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void X11WindowedOutput::handlePresentIdleNotify(xcb_present_idle_notify_event_t *event)
|
||||||
|
{
|
||||||
|
for (auto &[graphicsBuffer, x11Buffer] : m_buffers) {
|
||||||
|
if (x11Buffer->pixmap() == event->pixmap) {
|
||||||
|
x11Buffer->unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void X11WindowedOutput::setWindowTitle(const QString &title)
|
void X11WindowedOutput::setWindowTitle(const QString &title)
|
||||||
{
|
{
|
||||||
m_winInfo->setName(title.toUtf8().constData());
|
m_winInfo->setName(title.toUtf8().constData());
|
||||||
|
@ -327,4 +386,91 @@ void X11WindowedOutput::updateEnabled(bool enabled)
|
||||||
setState(next);
|
setState(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb_pixmap_t X11WindowedOutput::importDmaBufBuffer(const DmaBufAttributes *attributes)
|
||||||
|
{
|
||||||
|
uint8_t depth;
|
||||||
|
uint8_t bpp;
|
||||||
|
switch (attributes->format) {
|
||||||
|
case DRM_FORMAT_ARGB8888:
|
||||||
|
depth = 32;
|
||||||
|
bpp = 32;
|
||||||
|
break;
|
||||||
|
case DRM_FORMAT_XRGB8888:
|
||||||
|
depth = 24;
|
||||||
|
bpp = 32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qCWarning(KWIN_X11WINDOWED) << "Cannot import a buffer with unsupported format";
|
||||||
|
return XCB_PIXMAP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_pixmap_t pixmap = xcb_generate_id(m_backend->connection());
|
||||||
|
if (m_backend->driMajorVersion() >= 1 || m_backend->driMinorVersion() >= 2) {
|
||||||
|
// xcb_dri3_pixmap_from_buffers() takes the ownership of the file descriptors.
|
||||||
|
int fds[4] = {
|
||||||
|
attributes->fd[0].duplicate().take(),
|
||||||
|
attributes->fd[1].duplicate().take(),
|
||||||
|
attributes->fd[2].duplicate().take(),
|
||||||
|
attributes->fd[3].duplicate().take(),
|
||||||
|
};
|
||||||
|
xcb_dri3_pixmap_from_buffers(m_backend->connection(), pixmap, m_window, attributes->planeCount,
|
||||||
|
attributes->width, attributes->height,
|
||||||
|
attributes->pitch[0], attributes->offset[0],
|
||||||
|
attributes->pitch[1], attributes->offset[1],
|
||||||
|
attributes->pitch[2], attributes->offset[2],
|
||||||
|
attributes->pitch[3], attributes->offset[3],
|
||||||
|
depth, bpp, attributes->modifier, fds);
|
||||||
|
} else {
|
||||||
|
// xcb_dri3_pixmap_from_buffer() takes the ownership of the file descriptor.
|
||||||
|
xcb_dri3_pixmap_from_buffer(m_backend->connection(), pixmap, m_window,
|
||||||
|
attributes->height * attributes->pitch[0], attributes->width, attributes->height,
|
||||||
|
attributes->pitch[0], depth, bpp, attributes->fd[0].duplicate().take());
|
||||||
|
}
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_pixmap_t X11WindowedOutput::importShmBuffer(const ShmAttributes *attributes)
|
||||||
|
{
|
||||||
|
// xcb_shm_attach_fd() takes the ownership of the passed shm file descriptor.
|
||||||
|
FileDescriptor poolFileDescriptor = attributes->fd.duplicate();
|
||||||
|
if (!poolFileDescriptor.isValid()) {
|
||||||
|
qCWarning(KWIN_X11WINDOWED) << "Failed to duplicate shm file descriptor";
|
||||||
|
return XCB_PIXMAP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_shm_seg_t segment = xcb_generate_id(m_backend->connection());
|
||||||
|
xcb_shm_attach_fd(m_backend->connection(), segment, poolFileDescriptor.take(), 0);
|
||||||
|
|
||||||
|
xcb_pixmap_t pixmap = xcb_generate_id(m_backend->connection());
|
||||||
|
xcb_shm_create_pixmap(m_backend->connection(), pixmap, m_window, attributes->size.width(), attributes->size.height(), depth(), segment, 0);
|
||||||
|
xcb_shm_detach(m_backend->connection(), segment);
|
||||||
|
|
||||||
|
return pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_pixmap_t X11WindowedOutput::importBuffer(GraphicsBuffer *graphicsBuffer)
|
||||||
|
{
|
||||||
|
std::unique_ptr<X11WindowedBuffer> &x11Buffer = m_buffers[graphicsBuffer];
|
||||||
|
if (!x11Buffer) {
|
||||||
|
xcb_pixmap_t pixmap = XCB_PIXMAP_NONE;
|
||||||
|
if (const DmaBufAttributes *attributes = graphicsBuffer->dmabufAttributes()) {
|
||||||
|
pixmap = importDmaBufBuffer(attributes);
|
||||||
|
} else if (const ShmAttributes *attributes = graphicsBuffer->shmAttributes()) {
|
||||||
|
pixmap = importShmBuffer(attributes);
|
||||||
|
}
|
||||||
|
if (pixmap == XCB_PIXMAP_NONE) {
|
||||||
|
return XCB_PIXMAP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
x11Buffer = std::make_unique<X11WindowedBuffer>(this, pixmap, graphicsBuffer);
|
||||||
|
connect(x11Buffer.get(), &X11WindowedBuffer::defunct, this, [this, graphicsBuffer]() {
|
||||||
|
m_buffers.erase(graphicsBuffer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
x11Buffer->lock();
|
||||||
|
return x11Buffer->pixmap();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace KWin
|
} // namespace KWin
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/present.h>
|
#include <xcb/present.h>
|
||||||
|
|
||||||
|
@ -23,9 +25,37 @@ class NETWinInfo;
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class GraphicsBuffer;
|
||||||
class X11WindowedBackend;
|
class X11WindowedBackend;
|
||||||
class X11WindowedOutput;
|
class X11WindowedOutput;
|
||||||
|
|
||||||
|
struct DmaBufAttributes;
|
||||||
|
struct ShmAttributes;
|
||||||
|
|
||||||
|
class X11WindowedBuffer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
X11WindowedBuffer(X11WindowedOutput *output, xcb_pixmap_t pixmap, GraphicsBuffer *buffer);
|
||||||
|
~X11WindowedBuffer() override;
|
||||||
|
|
||||||
|
GraphicsBuffer *buffer() const;
|
||||||
|
xcb_pixmap_t pixmap() const;
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void defunct();
|
||||||
|
|
||||||
|
private:
|
||||||
|
X11WindowedOutput *m_output;
|
||||||
|
GraphicsBuffer *m_buffer;
|
||||||
|
xcb_pixmap_t m_pixmap;
|
||||||
|
bool m_locked = false;
|
||||||
|
};
|
||||||
|
|
||||||
class X11WindowedCursor
|
class X11WindowedCursor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -59,6 +89,8 @@ public:
|
||||||
xcb_window_t window() const;
|
xcb_window_t window() const;
|
||||||
int depth() const;
|
int depth() const;
|
||||||
|
|
||||||
|
xcb_pixmap_t importBuffer(GraphicsBuffer *buffer);
|
||||||
|
|
||||||
QPoint internalPosition() const;
|
QPoint internalPosition() const;
|
||||||
QPoint hostPosition() const;
|
QPoint hostPosition() const;
|
||||||
void setHostPosition(const QPoint &pos);
|
void setHostPosition(const QPoint &pos);
|
||||||
|
@ -80,15 +112,20 @@ public:
|
||||||
void updateEnabled(bool enabled);
|
void updateEnabled(bool enabled);
|
||||||
|
|
||||||
void handlePresentCompleteNotify(xcb_present_complete_notify_event_t *event);
|
void handlePresentCompleteNotify(xcb_present_complete_notify_event_t *event);
|
||||||
|
void handlePresentIdleNotify(xcb_present_idle_notify_event_t *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initXInputForWindow();
|
void initXInputForWindow();
|
||||||
|
|
||||||
|
xcb_pixmap_t importDmaBufBuffer(const DmaBufAttributes *attributes);
|
||||||
|
xcb_pixmap_t importShmBuffer(const ShmAttributes *attributes);
|
||||||
|
|
||||||
xcb_window_t m_window = XCB_WINDOW_NONE;
|
xcb_window_t m_window = XCB_WINDOW_NONE;
|
||||||
xcb_present_event_t m_presentEvent = XCB_NONE;
|
xcb_present_event_t m_presentEvent = XCB_NONE;
|
||||||
std::unique_ptr<NETWinInfo> m_winInfo;
|
std::unique_ptr<NETWinInfo> m_winInfo;
|
||||||
std::unique_ptr<RenderLoop> m_renderLoop;
|
std::unique_ptr<RenderLoop> m_renderLoop;
|
||||||
std::unique_ptr<X11WindowedCursor> m_cursor;
|
std::unique_ptr<X11WindowedCursor> m_cursor;
|
||||||
|
std::unordered_map<GraphicsBuffer *, std::unique_ptr<X11WindowedBuffer>> m_buffers;
|
||||||
QPoint m_hostPosition;
|
QPoint m_hostPosition;
|
||||||
QRegion m_exposedArea;
|
QRegion m_exposedArea;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <xcb/present.h>
|
#include <xcb/present.h>
|
||||||
#include <xcb/shm.h>
|
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
@ -36,25 +35,10 @@ static QImage::Format drmFormatToQImageFormat(uint32_t drmFormat)
|
||||||
}
|
}
|
||||||
|
|
||||||
X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer *buffer, X11WindowedOutput *output)
|
X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer *buffer, X11WindowedOutput *output)
|
||||||
: m_connection(output->backend()->connection())
|
: m_graphicsBuffer(buffer)
|
||||||
, m_graphicsBuffer(buffer)
|
|
||||||
{
|
{
|
||||||
const ShmAttributes *attributes = buffer->shmAttributes();
|
const ShmAttributes *attributes = buffer->shmAttributes();
|
||||||
|
|
||||||
// xcb_shm_attach_fd() takes the ownership of the passed shm file descriptor.
|
|
||||||
FileDescriptor poolFileDescriptor = attributes->fd.duplicate();
|
|
||||||
if (!poolFileDescriptor.isValid()) {
|
|
||||||
qCWarning(KWIN_X11WINDOWED) << "Failed to duplicate shm file descriptor";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xcb_shm_seg_t segment = xcb_generate_id(m_connection);
|
|
||||||
xcb_shm_attach_fd(m_connection, segment, poolFileDescriptor.take(), 0);
|
|
||||||
|
|
||||||
m_pixmap = xcb_generate_id(m_connection);
|
|
||||||
xcb_shm_create_pixmap(m_connection, m_pixmap, output->window(), attributes->size.width(), attributes->size.height(), output->depth(), segment, 0);
|
|
||||||
xcb_shm_detach(m_connection, segment);
|
|
||||||
|
|
||||||
m_size = attributes->size.height() * attributes->stride;
|
m_size = attributes->size.height() * attributes->stride;
|
||||||
m_data = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, attributes->fd.get(), 0);
|
m_data = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, attributes->fd.get(), 0);
|
||||||
if (m_data == MAP_FAILED) {
|
if (m_data == MAP_FAILED) {
|
||||||
|
@ -67,9 +51,6 @@ X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer
|
||||||
|
|
||||||
X11WindowedQPainterLayerBuffer::~X11WindowedQPainterLayerBuffer()
|
X11WindowedQPainterLayerBuffer::~X11WindowedQPainterLayerBuffer()
|
||||||
{
|
{
|
||||||
if (m_pixmap != XCB_PIXMAP_NONE) {
|
|
||||||
xcb_free_pixmap(m_connection, m_pixmap);
|
|
||||||
}
|
|
||||||
if (m_data) {
|
if (m_data) {
|
||||||
munmap(m_data, m_size);
|
munmap(m_data, m_size);
|
||||||
}
|
}
|
||||||
|
@ -82,11 +63,6 @@ ShmGraphicsBuffer *X11WindowedQPainterLayerBuffer::graphicsBuffer() const
|
||||||
return m_graphicsBuffer;
|
return m_graphicsBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_pixmap_t X11WindowedQPainterLayerBuffer::pixmap() const
|
|
||||||
{
|
|
||||||
return m_pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage *X11WindowedQPainterLayerBuffer::view() const
|
QImage *X11WindowedQPainterLayerBuffer::view() const
|
||||||
{
|
{
|
||||||
return m_view.get();
|
return m_view.get();
|
||||||
|
@ -158,6 +134,9 @@ bool X11WindowedQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, co
|
||||||
|
|
||||||
void X11WindowedQPainterPrimaryLayer::present()
|
void X11WindowedQPainterPrimaryLayer::present()
|
||||||
{
|
{
|
||||||
|
xcb_pixmap_t pixmap = m_output->importBuffer(m_current->graphicsBuffer());
|
||||||
|
Q_ASSERT(pixmap != XCB_PIXMAP_NONE);
|
||||||
|
|
||||||
xcb_xfixes_region_t valid = 0;
|
xcb_xfixes_region_t valid = 0;
|
||||||
xcb_xfixes_region_t update = 0;
|
xcb_xfixes_region_t update = 0;
|
||||||
uint32_t serial = 0;
|
uint32_t serial = 0;
|
||||||
|
@ -166,7 +145,7 @@ void X11WindowedQPainterPrimaryLayer::present()
|
||||||
|
|
||||||
xcb_present_pixmap(m_output->backend()->connection(),
|
xcb_present_pixmap(m_output->backend()->connection(),
|
||||||
m_output->window(),
|
m_output->window(),
|
||||||
m_current->pixmap(),
|
pixmap,
|
||||||
serial,
|
serial,
|
||||||
valid,
|
valid,
|
||||||
update,
|
update,
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -34,16 +32,13 @@ public:
|
||||||
~X11WindowedQPainterLayerBuffer();
|
~X11WindowedQPainterLayerBuffer();
|
||||||
|
|
||||||
ShmGraphicsBuffer *graphicsBuffer() const;
|
ShmGraphicsBuffer *graphicsBuffer() const;
|
||||||
xcb_pixmap_t pixmap() const;
|
|
||||||
QImage *view() const;
|
QImage *view() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
xcb_connection_t *m_connection;
|
|
||||||
ShmGraphicsBuffer *m_graphicsBuffer;
|
ShmGraphicsBuffer *m_graphicsBuffer;
|
||||||
void *m_data = nullptr;
|
void *m_data = nullptr;
|
||||||
int m_size = 0;
|
int m_size = 0;
|
||||||
std::unique_ptr<QImage> m_view;
|
std::unique_ptr<QImage> m_view;
|
||||||
xcb_pixmap_t m_pixmap = XCB_PIXMAP_NONE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class X11WindowedQPainterLayerSwapchain
|
class X11WindowedQPainterLayerSwapchain
|
||||||
|
|
Loading…
Reference in a new issue