backends/x11: Port to ShmGraphicsBufferAllocator
This commit is contained in:
parent
f60bcfb646
commit
13d1b8b16f
2 changed files with 76 additions and 63 deletions
|
@ -7,6 +7,7 @@
|
||||||
SPDX-License-Identifier: GPL-2.0-or-later
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
#include "x11_windowed_qpainter_backend.h"
|
#include "x11_windowed_qpainter_backend.h"
|
||||||
|
#include "core/shmgraphicsbufferallocator.h"
|
||||||
#include "x11_windowed_backend.h"
|
#include "x11_windowed_backend.h"
|
||||||
#include "x11_windowed_logging.h"
|
#include "x11_windowed_logging.h"
|
||||||
#include "x11_windowed_output.h"
|
#include "x11_windowed_output.h"
|
||||||
|
@ -15,57 +16,53 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <drm_fourcc.h>
|
#include <drm_fourcc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/shm.h>
|
#include <sys/mman.h>
|
||||||
#include <xcb/present.h>
|
#include <xcb/present.h>
|
||||||
#include <xcb/shm.h>
|
#include <xcb/shm.h>
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(const QSize &size, X11WindowedOutput *output)
|
static QImage::Format drmFormatToQImageFormat(uint32_t drmFormat)
|
||||||
: m_connection(output->backend()->connection())
|
|
||||||
, m_size(size)
|
|
||||||
{
|
{
|
||||||
QImage::Format format;
|
switch (drmFormat) {
|
||||||
int bytesPerPixel;
|
case DRM_FORMAT_ARGB8888:
|
||||||
switch (output->depth()) {
|
return QImage::Format_ARGB32;
|
||||||
case 24:
|
case DRM_FORMAT_XRGB8888:
|
||||||
case 32:
|
return QImage::Format_RGB32;
|
||||||
format = QImage::Format_ARGB32_Premultiplied;
|
|
||||||
bytesPerPixel = 4;
|
|
||||||
break;
|
|
||||||
case 30:
|
|
||||||
format = QImage::Format_A2RGB30_Premultiplied;
|
|
||||||
bytesPerPixel = 4;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
qCWarning(KWIN_X11WINDOWED) << "Unsupported output depth:" << output->depth() << ". Falling back to ARGB32";
|
Q_UNREACHABLE();
|
||||||
format = QImage::Format_ARGB32_Premultiplied;
|
}
|
||||||
bytesPerPixel = 4;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int shmId = shmget(IPC_PRIVATE, size.width() * size.height() * bytesPerPixel, IPC_CREAT | 0600);
|
X11WindowedQPainterLayerBuffer::X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer *buffer, X11WindowedOutput *output)
|
||||||
if (shmId < 0) {
|
: m_connection(output->backend()->connection())
|
||||||
qCWarning(KWIN_X11WINDOWED) << "shmget() failed:" << strerror(errno);
|
, m_graphicsBuffer(buffer)
|
||||||
return;
|
{
|
||||||
}
|
const ShmAttributes *attributes = buffer->shmAttributes();
|
||||||
|
|
||||||
m_buffer = shmat(shmId, nullptr, 0 /*read/write*/);
|
// xcb_shm_attach_fd() takes the ownership of the passed shm file descriptor.
|
||||||
shmctl(shmId, IPC_RMID, nullptr);
|
FileDescriptor poolFileDescriptor = attributes->fd.duplicate();
|
||||||
if (reinterpret_cast<long>(m_buffer) == -1) {
|
if (!poolFileDescriptor.isValid()) {
|
||||||
qCWarning(KWIN_X11WINDOWED) << "shmat() failed:" << strerror(errno);
|
qCWarning(KWIN_X11WINDOWED) << "Failed to duplicate shm file descriptor";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_shm_seg_t segment = xcb_generate_id(m_connection);
|
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);
|
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);
|
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()
|
X11WindowedQPainterLayerBuffer::~X11WindowedQPainterLayerBuffer()
|
||||||
|
@ -73,15 +70,16 @@ X11WindowedQPainterLayerBuffer::~X11WindowedQPainterLayerBuffer()
|
||||||
if (m_pixmap != XCB_PIXMAP_NONE) {
|
if (m_pixmap != XCB_PIXMAP_NONE) {
|
||||||
xcb_free_pixmap(m_connection, m_pixmap);
|
xcb_free_pixmap(m_connection, m_pixmap);
|
||||||
}
|
}
|
||||||
m_view.reset();
|
if (m_data) {
|
||||||
if (reinterpret_cast<long>(m_buffer) != -1) {
|
munmap(m_data, m_size);
|
||||||
shmdt(m_buffer);
|
|
||||||
}
|
}
|
||||||
|
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
|
xcb_pixmap_t X11WindowedQPainterLayerBuffer::pixmap() const
|
||||||
|
@ -94,12 +92,12 @@ QImage *X11WindowedQPainterLayerBuffer::view() const
|
||||||
return m_view.get();
|
return m_view.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
X11WindowedQPainterLayerSwapchain::X11WindowedQPainterLayerSwapchain(const QSize &size, X11WindowedOutput *output)
|
X11WindowedQPainterLayerSwapchain::X11WindowedQPainterLayerSwapchain(const QSize &size, uint32_t format, X11WindowedOutput *output)
|
||||||
: m_size(size)
|
: 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
|
QSize X11WindowedQPainterLayerSwapchain::size() const
|
||||||
|
@ -109,13 +107,22 @@ QSize X11WindowedQPainterLayerSwapchain::size() const
|
||||||
|
|
||||||
std::shared_ptr<X11WindowedQPainterLayerBuffer> X11WindowedQPainterLayerSwapchain::acquire()
|
std::shared_ptr<X11WindowedQPainterLayerBuffer> X11WindowedQPainterLayerSwapchain::acquire()
|
||||||
{
|
{
|
||||||
m_index = (m_index + 1) % m_buffers.count();
|
for (const auto &buffer : m_buffers) {
|
||||||
return m_buffers[m_index];
|
if (!buffer->graphicsBuffer()->isReferenced()) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11WindowedQPainterLayerSwapchain::release(std::shared_ptr<X11WindowedQPainterLayerBuffer> buffer)
|
ShmGraphicsBuffer *graphicsBuffer = m_allocator->allocate(m_size, m_format);
|
||||||
{
|
if (!graphicsBuffer) {
|
||||||
Q_ASSERT(m_buffers[m_index] == buffer);
|
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)
|
X11WindowedQPainterPrimaryLayer::X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output)
|
||||||
|
@ -127,15 +134,19 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginF
|
||||||
{
|
{
|
||||||
const QSize bufferSize = m_output->pixelSize();
|
const QSize bufferSize = m_output->pixelSize();
|
||||||
if (!m_swapchain || m_swapchain->size() != bufferSize) {
|
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();
|
QRegion repaint = m_output->exposedArea() + m_output->rect();
|
||||||
m_output->clearExposedArea();
|
m_output->clearExposedArea();
|
||||||
|
|
||||||
m_buffer = m_swapchain->acquire();
|
|
||||||
return OutputLayerBeginFrameInfo{
|
return OutputLayerBeginFrameInfo{
|
||||||
.renderTarget = RenderTarget(m_buffer->view()),
|
.renderTarget = RenderTarget(m_current->view()),
|
||||||
.repaint = repaint,
|
.repaint = repaint,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -155,7 +166,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_buffer->pixmap(),
|
m_current->pixmap(),
|
||||||
serial,
|
serial,
|
||||||
valid,
|
valid,
|
||||||
update,
|
update,
|
||||||
|
@ -170,13 +181,11 @@ void X11WindowedQPainterPrimaryLayer::present()
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
m_swapchain->release(m_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 X11WindowedQPainterPrimaryLayer::format() const
|
quint32 X11WindowedQPainterPrimaryLayer::format() const
|
||||||
{
|
{
|
||||||
switch (m_buffer->view()->format()) {
|
switch (m_current->view()->format()) {
|
||||||
case QImage::Format_A2RGB30_Premultiplied:
|
case QImage::Format_A2RGB30_Premultiplied:
|
||||||
return DRM_FORMAT_ARGB2101010;
|
return DRM_FORMAT_ARGB2101010;
|
||||||
case QImage::Format_ARGB32_Premultiplied:
|
case QImage::Format_ARGB32_Premultiplied:
|
||||||
|
|
|
@ -22,23 +22,26 @@
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class ShmGraphicsBuffer;
|
||||||
|
class ShmGraphicsBufferAllocator;
|
||||||
class X11WindowedBackend;
|
class X11WindowedBackend;
|
||||||
class X11WindowedOutput;
|
class X11WindowedOutput;
|
||||||
|
|
||||||
class X11WindowedQPainterLayerBuffer
|
class X11WindowedQPainterLayerBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
X11WindowedQPainterLayerBuffer(const QSize &size, X11WindowedOutput *output);
|
X11WindowedQPainterLayerBuffer(ShmGraphicsBuffer *buffer, X11WindowedOutput *output);
|
||||||
~X11WindowedQPainterLayerBuffer();
|
~X11WindowedQPainterLayerBuffer();
|
||||||
|
|
||||||
QSize size() const;
|
ShmGraphicsBuffer *graphicsBuffer() const;
|
||||||
xcb_pixmap_t pixmap() const;
|
xcb_pixmap_t pixmap() const;
|
||||||
QImage *view() const;
|
QImage *view() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
xcb_connection_t *m_connection;
|
xcb_connection_t *m_connection;
|
||||||
QSize m_size;
|
ShmGraphicsBuffer *m_graphicsBuffer;
|
||||||
void *m_buffer = nullptr;
|
void *m_data = nullptr;
|
||||||
|
int m_size = 0;
|
||||||
std::unique_ptr<QImage> m_view;
|
std::unique_ptr<QImage> m_view;
|
||||||
xcb_pixmap_t m_pixmap = XCB_PIXMAP_NONE;
|
xcb_pixmap_t m_pixmap = XCB_PIXMAP_NONE;
|
||||||
};
|
};
|
||||||
|
@ -46,17 +49,18 @@ private:
|
||||||
class X11WindowedQPainterLayerSwapchain
|
class X11WindowedQPainterLayerSwapchain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
X11WindowedQPainterLayerSwapchain(const QSize &size, X11WindowedOutput *output);
|
X11WindowedQPainterLayerSwapchain(const QSize &size, uint32_t format, X11WindowedOutput *output);
|
||||||
|
|
||||||
QSize size() const;
|
QSize size() const;
|
||||||
|
|
||||||
std::shared_ptr<X11WindowedQPainterLayerBuffer> acquire();
|
std::shared_ptr<X11WindowedQPainterLayerBuffer> acquire();
|
||||||
void release(std::shared_ptr<X11WindowedQPainterLayerBuffer> buffer);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
X11WindowedOutput *m_output;
|
||||||
QSize m_size;
|
QSize m_size;
|
||||||
|
uint32_t m_format;
|
||||||
|
std::unique_ptr<ShmGraphicsBufferAllocator> m_allocator;
|
||||||
QVector<std::shared_ptr<X11WindowedQPainterLayerBuffer>> m_buffers;
|
QVector<std::shared_ptr<X11WindowedQPainterLayerBuffer>> m_buffers;
|
||||||
int m_index = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class X11WindowedQPainterPrimaryLayer : public OutputLayer
|
class X11WindowedQPainterPrimaryLayer : public OutputLayer
|
||||||
|
@ -73,7 +77,7 @@ public:
|
||||||
private:
|
private:
|
||||||
X11WindowedOutput *const m_output;
|
X11WindowedOutput *const m_output;
|
||||||
std::unique_ptr<X11WindowedQPainterLayerSwapchain> m_swapchain;
|
std::unique_ptr<X11WindowedQPainterLayerSwapchain> m_swapchain;
|
||||||
std::shared_ptr<X11WindowedQPainterLayerBuffer> m_buffer;
|
std::shared_ptr<X11WindowedQPainterLayerBuffer> m_current;
|
||||||
};
|
};
|
||||||
|
|
||||||
class X11WindowedQPainterCursorLayer : public OutputLayer
|
class X11WindowedQPainterCursorLayer : public OutputLayer
|
||||||
|
|
Loading…
Reference in a new issue