{core,backends/wayland}: Refactor shm buffer allocator
This commit is contained in:
parent
2288f39469
commit
ce2b4c0bee
11 changed files with 364 additions and 186 deletions
|
@ -58,6 +58,7 @@ target_sources(kwin PRIVATE
|
|||
core/session_consolekit.cpp
|
||||
core/session_logind.cpp
|
||||
core/session_noop.cpp
|
||||
core/shmgraphicsbufferallocator.cpp
|
||||
cursor.cpp
|
||||
cursordelegate_opengl.cpp
|
||||
cursordelegate_qpainter.cpp
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <KWayland/Client/registry.h>
|
||||
#include <KWayland/Client/relativepointer.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/subcompositor.h>
|
||||
#include <KWayland/Client/xdgdecoration.h>
|
||||
#include <KWayland/Client/xdgshell.h>
|
||||
|
@ -202,10 +201,12 @@ WaylandDisplay::~WaylandDisplay()
|
|||
m_relativePointerManager.reset();
|
||||
m_seat.reset();
|
||||
m_xdgDecorationManager.reset();
|
||||
m_shmPool.reset();
|
||||
m_xdgShell.reset();
|
||||
m_linuxDmabuf.reset();
|
||||
|
||||
if (m_shm) {
|
||||
wl_shm_destroy(m_shm);
|
||||
}
|
||||
if (m_registry) {
|
||||
wl_registry_destroy(m_registry);
|
||||
}
|
||||
|
@ -267,9 +268,9 @@ KWayland::Client::RelativePointerManager *WaylandDisplay::relativePointerManager
|
|||
return m_relativePointerManager.get();
|
||||
}
|
||||
|
||||
KWayland::Client::ShmPool *WaylandDisplay::shmPool() const
|
||||
wl_shm *WaylandDisplay::shm() const
|
||||
{
|
||||
return m_shmPool.get();
|
||||
return m_shm;
|
||||
}
|
||||
|
||||
KWayland::Client::Seat *WaylandDisplay::seat() const
|
||||
|
@ -303,8 +304,7 @@ void WaylandDisplay::registry_global(void *data, wl_registry *registry, uint32_t
|
|||
display->m_compositor = std::make_unique<KWayland::Client::Compositor>();
|
||||
display->m_compositor->setup(static_cast<wl_compositor *>(wl_registry_bind(registry, name, &wl_compositor_interface, std::min(version, 4u))));
|
||||
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
display->m_shmPool = std::make_unique<KWayland::Client::ShmPool>();
|
||||
display->m_shmPool->setup(static_cast<wl_shm *>(wl_registry_bind(registry, name, &wl_shm_interface, std::min(version, 1u))));
|
||||
display->m_shm = static_cast<wl_shm *>(wl_registry_bind(registry, name, &wl_shm_interface, std::min(version, 1u)));
|
||||
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
display->m_seat = std::make_unique<KWayland::Client::Seat>();
|
||||
display->m_seat->setup(static_cast<wl_seat *>(wl_registry_bind(registry, name, &wl_seat_interface, std::min(version, 2u))));
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
struct wl_display;
|
||||
struct wl_registry;
|
||||
struct wl_shm;
|
||||
struct zwp_linux_dmabuf_v1;
|
||||
|
||||
namespace KWayland
|
||||
|
@ -24,7 +25,6 @@ class PointerConstraints;
|
|||
class PointerGestures;
|
||||
class RelativePointerManager;
|
||||
class Seat;
|
||||
class ShmPool;
|
||||
class XdgDecorationManager;
|
||||
class XdgShell;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
KWayland::Client::RelativePointerManager *relativePointerManager() const;
|
||||
KWayland::Client::Seat *seat() const;
|
||||
KWayland::Client::XdgDecorationManager *xdgDecorationManager() const;
|
||||
KWayland::Client::ShmPool *shmPool() const;
|
||||
wl_shm *shm() const;
|
||||
KWayland::Client::XdgShell *xdgShell() const;
|
||||
WaylandLinuxDmabufV1 *linuxDmabuf() const;
|
||||
|
||||
|
@ -84,6 +84,7 @@ private:
|
|||
|
||||
wl_display *m_display = nullptr;
|
||||
wl_registry *m_registry = nullptr;
|
||||
wl_shm *m_shm = nullptr;
|
||||
std::unique_ptr<WaylandEventThread> m_eventThread;
|
||||
std::unique_ptr<WaylandLinuxDmabufV1> m_linuxDmabuf;
|
||||
std::unique_ptr<KWayland::Client::Compositor> m_compositor;
|
||||
|
@ -92,7 +93,6 @@ private:
|
|||
std::unique_ptr<KWayland::Client::RelativePointerManager> m_relativePointerManager;
|
||||
std::unique_ptr<KWayland::Client::Seat> m_seat;
|
||||
std::unique_ptr<KWayland::Client::XdgDecorationManager> m_xdgDecorationManager;
|
||||
std::unique_ptr<KWayland::Client::ShmPool> m_shmPool;
|
||||
std::unique_ptr<KWayland::Client::XdgShell> m_xdgShell;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,106 +8,149 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "wayland_qpainter_backend.h"
|
||||
#include "core/shmgraphicsbufferallocator.h"
|
||||
#include "wayland_backend.h"
|
||||
#include "wayland_display.h"
|
||||
#include "wayland_logging.h"
|
||||
#include "wayland_output.h"
|
||||
|
||||
#include <KWayland/Client/buffer.h>
|
||||
#include <KWayland/Client/shm_pool.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <drm_fourcc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
namespace Wayland
|
||||
{
|
||||
|
||||
WaylandQPainterBufferSlot::WaylandQPainterBufferSlot(QSharedPointer<KWayland::Client::Buffer> buffer)
|
||||
: buffer(buffer)
|
||||
, image(buffer->address(), buffer->size().width(), buffer->size().height(), QImage::Format_RGB32)
|
||||
static uint32_t drmFormatToShmFormat(uint32_t drmFormat)
|
||||
{
|
||||
buffer->setUsed(true);
|
||||
switch (drmFormat) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return WL_SHM_FORMAT_ARGB8888;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return WL_SHM_FORMAT_XRGB8888;
|
||||
default:
|
||||
return static_cast<wl_shm_format>(drmFormat);
|
||||
}
|
||||
}
|
||||
|
||||
static QImage::Format drmFormatToQImageFormat(uint32_t drmFormat)
|
||||
{
|
||||
switch (drmFormat) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return QImage::Format_ARGB32;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return QImage::Format_RGB32;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot::WaylandQPainterBufferSlot(WaylandDisplay *display, ShmGraphicsBuffer *graphicsBuffer)
|
||||
: graphicsBuffer(graphicsBuffer)
|
||||
{
|
||||
const ShmAttributes *attributes = graphicsBuffer->shmAttributes();
|
||||
size = attributes->size.height() * attributes->stride;
|
||||
|
||||
wl_shm_pool *pool = wl_shm_create_pool(display->shm(), attributes->fd.get(), size);
|
||||
buffer = wl_shm_pool_create_buffer(pool,
|
||||
attributes->offset,
|
||||
attributes->size.width(),
|
||||
attributes->size.height(),
|
||||
attributes->stride,
|
||||
drmFormatToShmFormat(attributes->format));
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
static const wl_buffer_listener listener = {
|
||||
.release = [](void *userData, wl_buffer *buffer) {
|
||||
WaylandQPainterBufferSlot *slot = static_cast<WaylandQPainterBufferSlot *>(userData);
|
||||
slot->used = false;
|
||||
},
|
||||
};
|
||||
wl_buffer_add_listener(buffer, &listener, this);
|
||||
|
||||
data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, attributes->fd.get(), attributes->offset);
|
||||
if (data == MAP_FAILED) {
|
||||
qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to map a shared memory buffer";
|
||||
return;
|
||||
}
|
||||
|
||||
image = QImage(static_cast<uchar *>(data), attributes->size.width(), attributes->size.height(), drmFormatToQImageFormat(attributes->format));
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot::~WaylandQPainterBufferSlot()
|
||||
{
|
||||
buffer->setUsed(false);
|
||||
}
|
||||
|
||||
WaylandQPainterPrimaryLayer::WaylandQPainterPrimaryLayer(WaylandOutput *output)
|
||||
: m_waylandOutput(output)
|
||||
, m_pool(output->backend()->display()->shmPool())
|
||||
{
|
||||
connect(m_pool, &KWayland::Client::ShmPool::poolResized, this, &WaylandQPainterPrimaryLayer::remapBuffer);
|
||||
}
|
||||
|
||||
WaylandQPainterPrimaryLayer::~WaylandQPainterPrimaryLayer()
|
||||
{
|
||||
m_slots.clear();
|
||||
}
|
||||
|
||||
void WaylandQPainterPrimaryLayer::remapBuffer()
|
||||
{
|
||||
qCDebug(KWIN_WAYLAND_BACKEND) << "Remapped back buffer of surface" << m_waylandOutput->surface();
|
||||
|
||||
const QSize nativeSize(m_waylandOutput->geometry().size() * m_waylandOutput->scale());
|
||||
for (const auto &slot : m_slots) {
|
||||
slot->image = QImage(slot->buffer->address(), nativeSize.width(), nativeSize.height(), QImage::Format_RGB32);
|
||||
if (data) {
|
||||
munmap(data, size);
|
||||
}
|
||||
|
||||
wl_buffer_destroy(buffer);
|
||||
graphicsBuffer->drop();
|
||||
}
|
||||
|
||||
void WaylandQPainterPrimaryLayer::present()
|
||||
WaylandQPainterSwapchain::WaylandQPainterSwapchain(WaylandOutput *output, const QSize &size, uint32_t format)
|
||||
: m_allocator(std::make_unique<ShmGraphicsBufferAllocator>())
|
||||
, m_output(output)
|
||||
, m_size(size)
|
||||
, m_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
QSize WaylandQPainterSwapchain::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
std::shared_ptr<WaylandQPainterBufferSlot> WaylandQPainterSwapchain::acquire()
|
||||
{
|
||||
for (const auto &slot : m_slots) {
|
||||
if (slot.get() == m_back) {
|
||||
slot->age = 1;
|
||||
} else if (slot->age > 0) {
|
||||
slot->age++;
|
||||
if (!slot->used) {
|
||||
slot->used = true;
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
|
||||
auto s = m_waylandOutput->surface();
|
||||
s->attachBuffer(m_back->buffer);
|
||||
s->damage(m_damageJournal.lastDamage());
|
||||
s->setScale(std::ceil(m_waylandOutput->scale()));
|
||||
s->commit();
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot *WaylandQPainterPrimaryLayer::back() const
|
||||
{
|
||||
return m_back;
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot *WaylandQPainterPrimaryLayer::acquire()
|
||||
{
|
||||
const QSize nativeSize(m_waylandOutput->pixelSize());
|
||||
if (m_swapchainSize != nativeSize) {
|
||||
m_swapchainSize = nativeSize;
|
||||
m_slots.clear();
|
||||
}
|
||||
|
||||
for (const auto &slot : m_slots) {
|
||||
if (slot->buffer->isReleased()) {
|
||||
m_back = slot.get();
|
||||
slot->buffer->setReleased(false);
|
||||
return m_back;
|
||||
}
|
||||
}
|
||||
|
||||
auto buffer = m_pool->getBuffer(nativeSize, nativeSize.width() * 4, KWayland::Client::Buffer::Format::RGB32).toStrongRef();
|
||||
ShmGraphicsBuffer *buffer = m_allocator->allocate(m_size, m_format);
|
||||
if (!buffer) {
|
||||
qCDebug(KWIN_WAYLAND_BACKEND) << "Did not get a new Buffer from Shm Pool";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_slots.push_back(std::make_unique<WaylandQPainterBufferSlot>(buffer));
|
||||
m_back = m_slots.back().get();
|
||||
auto slot = std::make_shared<WaylandQPainterBufferSlot>(m_output->backend()->display(), buffer);
|
||||
m_slots.push_back(slot);
|
||||
|
||||
// qCDebug(KWIN_WAYLAND_BACKEND) << "Created a new back buffer for output surface" << m_waylandOutput->surface();
|
||||
return m_back;
|
||||
return slot;
|
||||
}
|
||||
|
||||
void WaylandQPainterSwapchain::release(std::shared_ptr<WaylandQPainterBufferSlot> buffer)
|
||||
{
|
||||
for (const auto &slot : m_slots) {
|
||||
if (slot == buffer) {
|
||||
slot->age = 1;
|
||||
} else if (slot->age > 0) {
|
||||
slot->age++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WaylandQPainterPrimaryLayer::WaylandQPainterPrimaryLayer(WaylandOutput *output)
|
||||
: m_waylandOutput(output)
|
||||
{
|
||||
}
|
||||
|
||||
void WaylandQPainterPrimaryLayer::present()
|
||||
{
|
||||
auto s = m_waylandOutput->surface();
|
||||
s->attachBuffer(m_back->buffer);
|
||||
s->damage(m_damageJournal.lastDamage());
|
||||
s->setScale(std::ceil(m_waylandOutput->scale()));
|
||||
s->commit();
|
||||
|
||||
m_swapchain->release(m_back);
|
||||
}
|
||||
|
||||
QRegion WaylandQPainterPrimaryLayer::accumulateDamage(int bufferAge) const
|
||||
|
@ -117,10 +160,19 @@ QRegion WaylandQPainterPrimaryLayer::accumulateDamage(int bufferAge) const
|
|||
|
||||
std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::beginFrame()
|
||||
{
|
||||
WaylandQPainterBufferSlot *slot = acquire();
|
||||
const QSize nativeSize(m_waylandOutput->pixelSize());
|
||||
if (!m_swapchain || m_swapchain->size() != nativeSize) {
|
||||
m_swapchain = std::make_unique<WaylandQPainterSwapchain>(m_waylandOutput, nativeSize, DRM_FORMAT_XRGB8888);
|
||||
}
|
||||
|
||||
m_back = m_swapchain->acquire();
|
||||
if (!m_back) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return OutputLayerBeginFrameInfo{
|
||||
.renderTarget = RenderTarget(&slot->image),
|
||||
.repaint = accumulateDamage(slot->age),
|
||||
.renderTarget = RenderTarget(&m_back->image),
|
||||
.repaint = accumulateDamage(m_back->age),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -140,28 +192,29 @@ WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output)
|
|||
{
|
||||
}
|
||||
|
||||
WaylandQPainterCursorLayer::~WaylandQPainterCursorLayer()
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::beginFrame()
|
||||
{
|
||||
const auto tmp = size().expandedTo(QSize(64, 64));
|
||||
const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
|
||||
if (m_backingStore.size() != bufferSize) {
|
||||
m_backingStore = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied);
|
||||
if (!m_swapchain || m_swapchain->size() != bufferSize) {
|
||||
m_swapchain = std::make_unique<WaylandQPainterSwapchain>(m_output, bufferSize, DRM_FORMAT_ARGB8888);
|
||||
}
|
||||
|
||||
m_back = m_swapchain->acquire();
|
||||
if (!m_back) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return OutputLayerBeginFrameInfo{
|
||||
.renderTarget = RenderTarget(&m_backingStore),
|
||||
.renderTarget = RenderTarget(&m_back->image),
|
||||
.repaint = infiniteRegion(),
|
||||
};
|
||||
}
|
||||
|
||||
bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
KWayland::Client::Buffer::Ptr buffer = m_output->backend()->display()->shmPool()->createBuffer(m_backingStore);
|
||||
m_output->cursor()->update(*buffer.lock(), scale(), hotspot().toPoint());
|
||||
m_output->cursor()->update(m_back->buffer, scale(), hotspot().toPoint());
|
||||
m_swapchain->release(m_back);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,67 +13,76 @@
|
|||
#include "platformsupport/scenes/qpainter/qpainterbackend.h"
|
||||
#include "utils/damagejournal.h"
|
||||
|
||||
#include <KWayland/Client/buffer.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <QObject>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class ShmPool;
|
||||
class Buffer;
|
||||
}
|
||||
}
|
||||
struct wl_buffer;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class Output;
|
||||
class ShmGraphicsBuffer;
|
||||
class ShmGraphicsBufferAllocator;
|
||||
|
||||
namespace Wayland
|
||||
{
|
||||
class WaylandBackend;
|
||||
class WaylandDisplay;
|
||||
class WaylandOutput;
|
||||
class WaylandQPainterBackend;
|
||||
|
||||
class WaylandQPainterBufferSlot
|
||||
{
|
||||
public:
|
||||
WaylandQPainterBufferSlot(QSharedPointer<KWayland::Client::Buffer> buffer);
|
||||
WaylandQPainterBufferSlot(WaylandDisplay *display, ShmGraphicsBuffer *graphicsBuffer);
|
||||
~WaylandQPainterBufferSlot();
|
||||
|
||||
QSharedPointer<KWayland::Client::Buffer> buffer;
|
||||
ShmGraphicsBuffer *graphicsBuffer;
|
||||
wl_buffer *buffer;
|
||||
QImage image;
|
||||
void *data = nullptr;
|
||||
int size;
|
||||
int age = 0;
|
||||
bool used = false;
|
||||
};
|
||||
|
||||
class WaylandQPainterSwapchain
|
||||
{
|
||||
public:
|
||||
WaylandQPainterSwapchain(WaylandOutput *output, const QSize &size, uint32_t format);
|
||||
|
||||
QSize size() const;
|
||||
|
||||
std::shared_ptr<WaylandQPainterBufferSlot> acquire();
|
||||
void release(std::shared_ptr<WaylandQPainterBufferSlot> buffer);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ShmGraphicsBufferAllocator> m_allocator;
|
||||
WaylandOutput *m_output;
|
||||
QSize m_size;
|
||||
uint32_t m_format;
|
||||
std::vector<std::shared_ptr<WaylandQPainterBufferSlot>> m_slots;
|
||||
};
|
||||
|
||||
class WaylandQPainterPrimaryLayer : public OutputLayer
|
||||
{
|
||||
public:
|
||||
WaylandQPainterPrimaryLayer(WaylandOutput *output);
|
||||
~WaylandQPainterPrimaryLayer() override;
|
||||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
quint32 format() const override;
|
||||
|
||||
void remapBuffer();
|
||||
|
||||
WaylandQPainterBufferSlot *back() const;
|
||||
|
||||
WaylandQPainterBufferSlot *acquire();
|
||||
void present();
|
||||
|
||||
QRegion accumulateDamage(int bufferAge) const;
|
||||
|
||||
private:
|
||||
WaylandOutput *m_waylandOutput;
|
||||
KWayland::Client::ShmPool *m_pool;
|
||||
DamageJournal m_damageJournal;
|
||||
|
||||
std::vector<std::unique_ptr<WaylandQPainterBufferSlot>> m_slots;
|
||||
WaylandQPainterBufferSlot *m_back = nullptr;
|
||||
QSize m_swapchainSize;
|
||||
std::unique_ptr<WaylandQPainterSwapchain> m_swapchain;
|
||||
std::shared_ptr<WaylandQPainterBufferSlot> m_back;
|
||||
|
||||
friend class WaylandQPainterBackend;
|
||||
};
|
||||
|
@ -84,7 +93,6 @@ class WaylandQPainterCursorLayer : public OutputLayer
|
|||
|
||||
public:
|
||||
explicit WaylandQPainterCursorLayer(WaylandOutput *output);
|
||||
~WaylandQPainterCursorLayer() override;
|
||||
|
||||
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
|
||||
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
@ -92,7 +100,8 @@ public:
|
|||
|
||||
private:
|
||||
WaylandOutput *m_output;
|
||||
QImage m_backingStore;
|
||||
std::unique_ptr<WaylandQPainterSwapchain> m_swapchain;
|
||||
std::shared_ptr<WaylandQPainterBufferSlot> m_back;
|
||||
};
|
||||
|
||||
class WaylandQPainterBackend : public QPainterBackend
|
||||
|
|
|
@ -56,43 +56,6 @@ GbmGraphicsBuffer *GbmGraphicsBufferAllocator::allocate(const QSize &size, uint3
|
|||
return new GbmGraphicsBuffer(std::move(attributes.value()), bo);
|
||||
}
|
||||
|
||||
static bool alphaChannelFromDrmFormat(uint32_t drmFormat)
|
||||
{
|
||||
switch (drmFormat) {
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
case DRM_FORMAT_ABGR4444:
|
||||
case DRM_FORMAT_RGBA4444:
|
||||
case DRM_FORMAT_BGRA4444:
|
||||
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
case DRM_FORMAT_ABGR1555:
|
||||
case DRM_FORMAT_RGBA5551:
|
||||
case DRM_FORMAT_BGRA5551:
|
||||
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
case DRM_FORMAT_ABGR2101010:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
case DRM_FORMAT_BGRA1010102:
|
||||
|
||||
case DRM_FORMAT_XRGB8888_A8:
|
||||
case DRM_FORMAT_XBGR8888_A8:
|
||||
case DRM_FORMAT_RGBX8888_A8:
|
||||
case DRM_FORMAT_BGRX8888_A8:
|
||||
case DRM_FORMAT_RGB888_A8:
|
||||
case DRM_FORMAT_BGR888_A8:
|
||||
case DRM_FORMAT_RGB565_A8:
|
||||
case DRM_FORMAT_BGR565_A8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GbmGraphicsBuffer::GbmGraphicsBuffer(DmaBufAttributes attributes, gbm_bo *handle)
|
||||
: m_bo(handle)
|
||||
, m_dmabufAttributes(std::move(attributes))
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "core/graphicsbuffer.h"
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
|
@ -57,4 +59,46 @@ const DmaBufAttributes *GraphicsBuffer::dmabufAttributes() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const ShmAttributes *GraphicsBuffer::shmAttributes() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GraphicsBuffer::alphaChannelFromDrmFormat(uint32_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
case DRM_FORMAT_ABGR4444:
|
||||
case DRM_FORMAT_RGBA4444:
|
||||
case DRM_FORMAT_BGRA4444:
|
||||
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
case DRM_FORMAT_ABGR1555:
|
||||
case DRM_FORMAT_RGBA5551:
|
||||
case DRM_FORMAT_BGRA5551:
|
||||
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
case DRM_FORMAT_ABGR2101010:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
case DRM_FORMAT_BGRA1010102:
|
||||
|
||||
case DRM_FORMAT_XRGB8888_A8:
|
||||
case DRM_FORMAT_XBGR8888_A8:
|
||||
case DRM_FORMAT_RGBX8888_A8:
|
||||
case DRM_FORMAT_BGRX8888_A8:
|
||||
case DRM_FORMAT_RGB888_A8:
|
||||
case DRM_FORMAT_BGR888_A8:
|
||||
case DRM_FORMAT_RGB565_A8:
|
||||
case DRM_FORMAT_BGR565_A8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "utils/filedescriptor.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -27,6 +28,15 @@ struct DmaBufAttributes
|
|||
int pitch[4] = {0, 0, 0, 0};
|
||||
};
|
||||
|
||||
struct ShmAttributes
|
||||
{
|
||||
FileDescriptor fd;
|
||||
int stride;
|
||||
off_t offset;
|
||||
QSize size;
|
||||
uint32_t format;
|
||||
};
|
||||
|
||||
/**
|
||||
* The GraphicsBuffer class represents a chunk of memory containing graphics data.
|
||||
*
|
||||
|
@ -52,6 +62,9 @@ public:
|
|||
virtual bool hasAlphaChannel() const = 0;
|
||||
|
||||
virtual const DmaBufAttributes *dmabufAttributes() const;
|
||||
virtual const ShmAttributes *shmAttributes() const;
|
||||
|
||||
static bool alphaChannelFromDrmFormat(uint32_t format);
|
||||
|
||||
Q_SIGNALS:
|
||||
void released();
|
||||
|
|
94
src/core/shmgraphicsbufferallocator.cpp
Normal file
94
src/core/shmgraphicsbufferallocator.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "core/shmgraphicsbufferallocator.h"
|
||||
|
||||
#include "config-kwin.h"
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
ShmGraphicsBuffer::ShmGraphicsBuffer(ShmAttributes &&attributes)
|
||||
: m_attributes(std::move(attributes))
|
||||
, m_hasAlphaChannel(alphaChannelFromDrmFormat(attributes.format))
|
||||
{
|
||||
}
|
||||
|
||||
QSize ShmGraphicsBuffer::size() const
|
||||
{
|
||||
return m_attributes.size;
|
||||
}
|
||||
|
||||
bool ShmGraphicsBuffer::hasAlphaChannel() const
|
||||
{
|
||||
return m_hasAlphaChannel;
|
||||
}
|
||||
|
||||
const ShmAttributes *ShmGraphicsBuffer::shmAttributes() const
|
||||
{
|
||||
return &m_attributes;
|
||||
}
|
||||
|
||||
ShmGraphicsBuffer *ShmGraphicsBufferAllocator::allocate(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers)
|
||||
{
|
||||
if (!modifiers.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int stride = size.width() * 4;
|
||||
const int bufferSize = size.height() * stride;
|
||||
|
||||
#if HAVE_MEMFD
|
||||
FileDescriptor fd = FileDescriptor(memfd_create("shm", MFD_CLOEXEC | MFD_ALLOW_SEALING));
|
||||
if (!fd.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ftruncate(fd.get(), bufferSize) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fcntl(fd.get(), F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL);
|
||||
#else
|
||||
char templateName[] = "/tmp/kwin-shm-XXXXXX";
|
||||
FileDescriptor fd{mkstemp(templateName)};
|
||||
if (!fd.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unlink(templateName);
|
||||
int flags = fcntl(fd.get(), F_GETFD);
|
||||
if (flags == -1 || fcntl(fd.get(), F_SETFD, flags | FD_CLOEXEC) == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (ftruncate(fd.get(), bufferSize) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return new ShmGraphicsBuffer(ShmAttributes{
|
||||
.fd = std::move(fd),
|
||||
.stride = stride,
|
||||
.offset = 0,
|
||||
.size = size,
|
||||
.format = format,
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace KWin
|
38
src/core/shmgraphicsbufferallocator.h
Normal file
38
src/core/shmgraphicsbufferallocator.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/graphicsbuffer.h"
|
||||
#include "core/graphicsbufferallocator.h"
|
||||
#include "utils/filedescriptor.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class KWIN_EXPORT ShmGraphicsBuffer : public GraphicsBuffer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ShmGraphicsBuffer(ShmAttributes &&attributes);
|
||||
|
||||
QSize size() const override;
|
||||
bool hasAlphaChannel() const override;
|
||||
const ShmAttributes *shmAttributes() const override;
|
||||
|
||||
private:
|
||||
ShmAttributes m_attributes;
|
||||
bool m_hasAlphaChannel;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT ShmGraphicsBufferAllocator : public GraphicsBufferAllocator
|
||||
{
|
||||
public:
|
||||
ShmGraphicsBuffer *allocate(const QSize &size, uint32_t format, const QVector<uint64_t> &modifiers = {}) override;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
|
@ -327,43 +327,6 @@ void LinuxDmaBufV1ClientBufferIntegration::setSupportedFormatsWithModifiers(cons
|
|||
}
|
||||
}
|
||||
|
||||
static bool testAlphaChannel(uint32_t drmFormat)
|
||||
{
|
||||
switch (drmFormat) {
|
||||
case DRM_FORMAT_ARGB4444:
|
||||
case DRM_FORMAT_ABGR4444:
|
||||
case DRM_FORMAT_RGBA4444:
|
||||
case DRM_FORMAT_BGRA4444:
|
||||
|
||||
case DRM_FORMAT_ARGB1555:
|
||||
case DRM_FORMAT_ABGR1555:
|
||||
case DRM_FORMAT_RGBA5551:
|
||||
case DRM_FORMAT_BGRA5551:
|
||||
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
case DRM_FORMAT_ABGR2101010:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
case DRM_FORMAT_BGRA1010102:
|
||||
|
||||
case DRM_FORMAT_XRGB8888_A8:
|
||||
case DRM_FORMAT_XBGR8888_A8:
|
||||
case DRM_FORMAT_RGBX8888_A8:
|
||||
case DRM_FORMAT_BGRX8888_A8:
|
||||
case DRM_FORMAT_RGB888_A8:
|
||||
case DRM_FORMAT_BGR888_A8:
|
||||
case DRM_FORMAT_RGB565_A8:
|
||||
case DRM_FORMAT_BGR565_A8:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxDmaBufV1ClientBuffer::buffer_destroy_resource(wl_resource *resource)
|
||||
{
|
||||
if (LinuxDmaBufV1ClientBuffer *buffer = LinuxDmaBufV1ClientBuffer::get(resource)) {
|
||||
|
@ -384,7 +347,7 @@ const struct wl_buffer_interface LinuxDmaBufV1ClientBuffer::implementation = {
|
|||
LinuxDmaBufV1ClientBuffer::LinuxDmaBufV1ClientBuffer(KWin::DmaBufAttributes &&attrs)
|
||||
{
|
||||
m_attrs = std::move(attrs);
|
||||
m_hasAlphaChannel = testAlphaChannel(m_attrs.format);
|
||||
m_hasAlphaChannel = alphaChannelFromDrmFormat(m_attrs.format);
|
||||
}
|
||||
|
||||
void LinuxDmaBufV1ClientBuffer::initialize(wl_resource *resource)
|
||||
|
|
Loading…
Reference in a new issue