backends/x11: Port to ShmGraphicsBufferAllocator

This commit is contained in:
Vlad Zahorodnii 2023-04-24 22:58:47 +03:00
parent f60bcfb646
commit 13d1b8b16f
2 changed files with 76 additions and 63 deletions

View file

@ -7,6 +7,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "x11_windowed_qpainter_backend.h"
#include "core/shmgraphicsbufferallocator.h"
#include "x11_windowed_backend.h"
#include "x11_windowed_logging.h"
#include "x11_windowed_output.h"
@ -15,57 +16,53 @@
#include <cmath>
#include <drm_fourcc.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <xcb/present.h>
#include <xcb/shm.h>
namespace KWin
{
X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(const QSize &size, X11WindowedOutput *output)
: m_connection(output->backend()->connection())
, m_size(size)
static QImage::Format drmFormatToQImageFormat(uint32_t drmFormat)
{
QImage::Format format;
int bytesPerPixel;
switch (output->depth()) {
case 24:
case 32:
format = QImage::Format_ARGB32_Premultiplied;
bytesPerPixel = 4;
break;
case 30:
format = QImage::Format_A2RGB30_Premultiplied;
bytesPerPixel = 4;
break;
switch (drmFormat) {
case DRM_FORMAT_ARGB8888:
return QImage::Format_ARGB32;
case DRM_FORMAT_XRGB8888:
return QImage::Format_RGB32;
default:
qCWarning(KWIN_X11WINDOWED) << "Unsupported output depth:" << output->depth() << ". Falling back to ARGB32";
format = QImage::Format_ARGB32_Premultiplied;
bytesPerPixel = 4;
break;
Q_UNREACHABLE();
}
}
int shmId = shmget(IPC_PRIVATE, size.width() * size.height() * bytesPerPixel, IPC_CREAT | 0600);
if (shmId < 0) {
qCWarning(KWIN_X11WINDOWED) << "shmget() failed:" << strerror(errno);
return;
}
X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer *buffer, X11WindowedOutput *output)
: m_connection(output->backend()->connection())
, m_graphicsBuffer(buffer)
{
const ShmAttributes *attributes = buffer->shmAttributes();
m_buffer = shmat(shmId, nullptr, 0 /*read/write*/);
shmctl(shmId, IPC_RMID, nullptr);
if (reinterpret_cast<long>(m_buffer) == -1) {
qCWarning(KWIN_X11WINDOWED) << "shmat() failed:" << strerror(errno);
// 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(m_connection, segment, shmId, false);
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(), size.width(), size.height(), output->depth(), segment, 0);
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_view = std::make_unique<QImage>(static_cast<uchar *>(m_buffer), size.width(), size.height(), format);
m_size = attributes->size.height() * attributes->stride;
m_data = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, attributes->fd.get(), 0);
if (m_data == MAP_FAILED) {
qCWarning(KWIN_X11WINDOWED) << "Failed to map a shared memory buffer";
return;
}
m_view = std::make_unique<QImage>(static_cast<uchar *>(m_data), attributes->size.width(), attributes->size.height(), drmFormatToQImageFormat(attributes->format));
}
X11WindowedQPainterLayerBuffer::~X11WindowedQPainterLayerBuffer()
@ -73,15 +70,16 @@ X11WindowedQPainterLayerBuffer::~X11WindowedQPainterLayerBuffer()
if (m_pixmap != XCB_PIXMAP_NONE) {
xcb_free_pixmap(m_connection, m_pixmap);
}
m_view.reset();
if (reinterpret_cast<long>(m_buffer) != -1) {
shmdt(m_buffer);
if (m_data) {
munmap(m_data, m_size);
}
m_view.reset();
m_graphicsBuffer->drop();
}
QSize X11WindowedQPainterLayerBuffer::size() const
ShmGraphicsBuffer *X11WindowedQPainterLayerBuffer::graphicsBuffer() const
{
return m_size;
return m_graphicsBuffer;
}
xcb_pixmap_t X11WindowedQPainterLayerBuffer::pixmap() const
@ -94,12 +92,12 @@ QImage *X11WindowedQPainterLayerBuffer::view() const
return m_view.get();
}
X11WindowedQPainterLayerSwapchain::X11WindowedQPainterLayerSwapchain(const QSize &size, X11WindowedOutput *output)
: m_size(size)
X11WindowedQPainterLayerSwapchain::X11WindowedQPainterLayerSwapchain(const QSize &size, uint32_t format, X11WindowedOutput *output)
: m_output(output)
, m_size(size)
, m_format(format)
, m_allocator(std::make_unique<ShmGraphicsBufferAllocator>())
{
for (int i = 0; i < 2; ++i) {
m_buffers.append(std::make_shared<X11WindowedQPainterLayerBuffer>(size, output));
}
}
QSize X11WindowedQPainterLayerSwapchain::size() const
@ -109,13 +107,22 @@ QSize X11WindowedQPainterLayerSwapchain::size() const
std::shared_ptr<X11WindowedQPainterLayerBuffer> X11WindowedQPainterLayerSwapchain::acquire()
{
m_index = (m_index + 1) % m_buffers.count();
return m_buffers[m_index];
}
for (const auto &buffer : m_buffers) {
if (!buffer->graphicsBuffer()->isReferenced()) {
return buffer;
}
}
void X11WindowedQPainterLayerSwapchain::release(std::shared_ptr<X11WindowedQPainterLayerBuffer> buffer)
{
Q_ASSERT(m_buffers[m_index] == buffer);
ShmGraphicsBuffer *graphicsBuffer = m_allocator->allocate(m_size, m_format);
if (!graphicsBuffer) {
qCWarning(KWIN_X11WINDOWED) << "Failed to allocate a shared memory graphics buffer";
return nullptr;
}
auto buffer = std::make_shared<X11WindowedQPainterLayerBuffer>(graphicsBuffer, m_output);
m_buffers.push_back(buffer);
return buffer;
}
X11WindowedQPainterPrimaryLayer::X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output)
@ -127,15 +134,19 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginF
{
const QSize bufferSize = m_output->pixelSize();
if (!m_swapchain || m_swapchain->size() != bufferSize) {
m_swapchain = std::make_unique<X11WindowedQPainterLayerSwapchain>(bufferSize, m_output);
m_swapchain = std::make_unique<X11WindowedQPainterLayerSwapchain>(bufferSize, m_output->backend()->driFormatForDepth(m_output->depth()), m_output);
}
m_current = m_swapchain->acquire();
if (!m_current) {
return std::nullopt;
}
QRegion repaint = m_output->exposedArea() + m_output->rect();
m_output->clearExposedArea();
m_buffer = m_swapchain->acquire();
return OutputLayerBeginFrameInfo{
.renderTarget = RenderTarget(m_buffer->view()),
.renderTarget = RenderTarget(m_current->view()),
.repaint = repaint,
};
}
@ -155,7 +166,7 @@ void X11WindowedQPainterPrimaryLayer::present()
xcb_present_pixmap(m_output->backend()->connection(),
m_output->window(),
m_buffer->pixmap(),
m_current->pixmap(),
serial,
valid,
update,
@ -170,13 +181,11 @@ void X11WindowedQPainterPrimaryLayer::present()
0,
0,
nullptr);
m_swapchain->release(m_buffer);
}
quint32 X11WindowedQPainterPrimaryLayer::format() const
{
switch (m_buffer->view()->format()) {
switch (m_current->view()->format()) {
case QImage::Format_A2RGB30_Premultiplied:
return DRM_FORMAT_ARGB2101010;
case QImage::Format_ARGB32_Premultiplied:

View file

@ -22,23 +22,26 @@
namespace KWin
{
class ShmGraphicsBuffer;
class ShmGraphicsBufferAllocator;
class X11WindowedBackend;
class X11WindowedOutput;
class X11WindowedQPainterLayerBuffer
{
public:
X11WindowedQPainterLayerBuffer(const QSize &size, X11WindowedOutput *output);
X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer *buffer, X11WindowedOutput *output);
~X11WindowedQPainterLayerBuffer();
QSize size() const;
ShmGraphicsBuffer *graphicsBuffer() const;
xcb_pixmap_t pixmap() const;
QImage *view() const;
private:
xcb_connection_t *m_connection;
QSize m_size;
void *m_buffer = nullptr;
ShmGraphicsBuffer *m_graphicsBuffer;
void *m_data = nullptr;
int m_size = 0;
std::unique_ptr<QImage> m_view;
xcb_pixmap_t m_pixmap = XCB_PIXMAP_NONE;
};
@ -46,17 +49,18 @@ private:
class X11WindowedQPainterLayerSwapchain
{
public:
X11WindowedQPainterLayerSwapchain(const QSize &size, X11WindowedOutput *output);
X11WindowedQPainterLayerSwapchain(const QSize &size, uint32_t format, X11WindowedOutput *output);
QSize size() const;
std::shared_ptr<X11WindowedQPainterLayerBuffer> acquire();
void release(std::shared_ptr<X11WindowedQPainterLayerBuffer> buffer);
private:
X11WindowedOutput *m_output;
QSize m_size;
uint32_t m_format;
std::unique_ptr<ShmGraphicsBufferAllocator> m_allocator;
QVector<std::shared_ptr<X11WindowedQPainterLayerBuffer>> m_buffers;
int m_index = 0;
};
class X11WindowedQPainterPrimaryLayer : public OutputLayer
@ -73,7 +77,7 @@ public:
private:
X11WindowedOutput *const m_output;
std::unique_ptr<X11WindowedQPainterLayerSwapchain> m_swapchain;
std::shared_ptr<X11WindowedQPainterLayerBuffer> m_buffer;
std::shared_ptr<X11WindowedQPainterLayerBuffer> m_current;
};
class X11WindowedQPainterCursorLayer : public OutputLayer