diff --git a/src/core/gbmgraphicsbufferallocator.cpp b/src/core/gbmgraphicsbufferallocator.cpp index 27e2446b04..ddbb93efa7 100644 --- a/src/core/gbmgraphicsbufferallocator.cpp +++ b/src/core/gbmgraphicsbufferallocator.cpp @@ -6,9 +6,13 @@ #include "core/gbmgraphicsbufferallocator.h" #include "backends/drm/gbm_dmabuf.h" // FIXME: move dmaBufAttributesForBo() elsewhere +#include "utils/common.h" #include +#include #include +#include +#include namespace KWin { @@ -22,28 +26,48 @@ GbmGraphicsBufferAllocator::~GbmGraphicsBufferAllocator() { } -GraphicsBuffer *GbmGraphicsBufferAllocator::allocate(const GraphicsBufferOptions &options) +static GraphicsBuffer *allocateDumb(gbm_device *device, const GraphicsBufferOptions &options) { - if (options.software) { - gbm_bo *bo = gbm_bo_create(m_gbmDevice, - options.size.width(), - options.size.height(), - options.format, - GBM_BO_USE_SCANOUT | GBM_BO_USE_WRITE | GBM_BO_USE_LINEAR); - if (bo) { - std::optional attributes = dmaBufAttributesForBo(bo); - if (!attributes.has_value()) { - gbm_bo_destroy(bo); - return nullptr; - } - attributes->modifier = DRM_FORMAT_MOD_LINEAR; - return new GbmGraphicsBuffer(std::move(attributes.value()), bo); - } + if (!options.modifiers.isEmpty()) { return nullptr; } + drm_mode_create_dumb createArgs{ + .height = uint32_t(options.size.height()), + .width = uint32_t(options.size.width()), + .bpp = 32, + }; + if (drmIoctl(gbm_device_get_fd(device), DRM_IOCTL_MODE_CREATE_DUMB, &createArgs) != 0) { + qCWarning(KWIN_CORE) << "DRM_IOCTL_MODE_CREATE_DUMB failed:" << strerror(errno); + return nullptr; + } + + int primeFd; + if (drmPrimeHandleToFD(gbm_device_get_fd(device), createArgs.handle, DRM_CLOEXEC, &primeFd) != 0) { + qCWarning(KWIN_CORE) << "drmPrimeHandleToFD() failed:" << strerror(errno); + drm_mode_destroy_dumb destroyArgs{ + .handle = createArgs.handle, + }; + drmIoctl(gbm_device_get_fd(device), DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); + return nullptr; + } + + return new DumbGraphicsBuffer(gbm_device_get_fd(device), createArgs.handle, DmaBufAttributes{ + .planeCount = 1, + .width = options.size.width(), + .height = options.size.height(), + .format = options.format, + .modifier = DRM_FORMAT_MOD_LINEAR, + .fd = {FileDescriptor(primeFd), FileDescriptor{}, FileDescriptor{}, FileDescriptor{}}, + .offset = {0, 0, 0, 0}, + .pitch = {createArgs.pitch, 0, 0, 0}, + }); +} + +static GraphicsBuffer *allocateDmaBuf(gbm_device *device, const GraphicsBufferOptions &options) +{ if (!options.modifiers.isEmpty() && !(options.modifiers.size() == 1 && options.modifiers.first() == DRM_FORMAT_MOD_INVALID)) { - gbm_bo *bo = gbm_bo_create_with_modifiers(m_gbmDevice, + gbm_bo *bo = gbm_bo_create_with_modifiers(device, options.size.width(), options.size.height(), options.format, @@ -62,11 +86,11 @@ GraphicsBuffer *GbmGraphicsBufferAllocator::allocate(const GraphicsBufferOptions uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; if (options.modifiers.size() == 1 && options.modifiers.first() == DRM_FORMAT_MOD_LINEAR) { flags |= GBM_BO_USE_LINEAR; - } else if (!modifiers.isEmpty() && !modifiers.contains(DRM_FORMAT_MOD_INVALID)) { + } else if (!options.modifiers.isEmpty() && !options.modifiers.contains(DRM_FORMAT_MOD_INVALID)) { return nullptr; } - gbm_bo *bo = gbm_bo_create(m_gbmDevice, + gbm_bo *bo = gbm_bo_create(device, options.size.width(), options.size.height(), options.format, @@ -88,6 +112,15 @@ GraphicsBuffer *GbmGraphicsBufferAllocator::allocate(const GraphicsBufferOptions return nullptr; } +GraphicsBuffer *GbmGraphicsBufferAllocator::allocate(const GraphicsBufferOptions &options) +{ + if (options.software) { + return allocateDumb(m_gbmDevice, options); + } + + return allocateDmaBuf(m_gbmDevice, options); +} + GbmGraphicsBuffer::GbmGraphicsBuffer(DmaBufAttributes attributes, gbm_bo *handle) : m_bo(handle) , m_dmabufAttributes(std::move(attributes)) @@ -145,4 +178,70 @@ void GbmGraphicsBuffer::unmap() } } +DumbGraphicsBuffer::DumbGraphicsBuffer(int drmFd, uint32_t handle, DmaBufAttributes attributes) + : m_drmFd(drmFd) + , m_handle(handle) + , m_size(attributes.pitch[0] * attributes.height) + , m_dmabufAttributes(std::move(attributes)) + , m_hasAlphaChannel(alphaChannelFromDrmFormat(m_dmabufAttributes.format)) +{ +} + +DumbGraphicsBuffer::~DumbGraphicsBuffer() +{ + unmap(); + + drm_mode_destroy_dumb destroyArgs{ + .handle = m_handle, + }; + drmIoctl(m_drmFd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyArgs); +} + +QSize DumbGraphicsBuffer::size() const +{ + return QSize(m_dmabufAttributes.width, m_dmabufAttributes.height); +} + +bool DumbGraphicsBuffer::hasAlphaChannel() const +{ + return m_hasAlphaChannel; +} + +const DmaBufAttributes *DumbGraphicsBuffer::dmabufAttributes() const +{ + return &m_dmabufAttributes; +} + +void *DumbGraphicsBuffer::map(MapFlags flags) +{ + if (m_data) { + return m_data; + } + + drm_mode_map_dumb mapArgs{ + .handle = m_handle, + }; + if (drmIoctl(m_drmFd, DRM_IOCTL_MODE_MAP_DUMB, &mapArgs) != 0) { + qCWarning(KWIN_CORE) << "DRM_IOCTL_MODE_MAP_DUMB failed:" << strerror(errno); + return nullptr; + } + + void *address = mmap(nullptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_drmFd, mapArgs.offset); + if (address == MAP_FAILED) { + qCWarning(KWIN_CORE) << "mmap() failed:" << strerror(errno); + return nullptr; + } + + m_data = address; + return m_data; +} + +void DumbGraphicsBuffer::unmap() +{ + if (m_data) { + munmap(m_data, m_size); + m_data = nullptr; + } +} + } // namespace KWin diff --git a/src/core/gbmgraphicsbufferallocator.h b/src/core/gbmgraphicsbufferallocator.h index 95df0648c4..84b85974e3 100644 --- a/src/core/gbmgraphicsbufferallocator.h +++ b/src/core/gbmgraphicsbufferallocator.h @@ -39,6 +39,30 @@ private: bool m_hasAlphaChannel; }; +class KWIN_EXPORT DumbGraphicsBuffer : public GraphicsBuffer +{ + Q_OBJECT + +public: + DumbGraphicsBuffer(int drmFd, uint32_t handle, DmaBufAttributes attributes); + ~DumbGraphicsBuffer() override; + + void *map(MapFlags flags) override; + void unmap() override; + + QSize size() const override; + bool hasAlphaChannel() const override; + const DmaBufAttributes *dmabufAttributes() const override; + +private: + int m_drmFd; + uint32_t m_handle; + void *m_data = nullptr; + size_t m_size = 0; + DmaBufAttributes m_dmabufAttributes; + bool m_hasAlphaChannel; +}; + class KWIN_EXPORT GbmGraphicsBufferAllocator : public GraphicsBufferAllocator { public: