Keep the Linux DMABUF handle alongside the bitmap wrapper when imported shared images reach the UI process. This lets consumers import the same GPU backing store directly instead of only reading it through the mapped bitmap. Also require exported Vulkan shared images to be sampleable, since the Qt Vulkan presentation path needs to sample compositor backing stores.
117 lines
4.2 KiB
C++
117 lines
4.2 KiB
C++
/*
|
|
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGfx/Bitmap.h>
|
|
#include <LibGfx/SharedImageBuffer.h>
|
|
|
|
#ifdef USE_VULKAN_DMABUF_IMAGES
|
|
# include <libdrm/drm_fourcc.h>
|
|
# include <sys/mman.h>
|
|
#endif
|
|
|
|
namespace Gfx {
|
|
|
|
#ifdef AK_OS_MACOS
|
|
static constexpr auto shared_image_buffer_format = BitmapFormat::BGRA8888;
|
|
static constexpr auto shared_image_buffer_alpha_type = AlphaType::Premultiplied;
|
|
|
|
static NonnullRefPtr<Bitmap> create_bitmap_from_iosurface(Core::IOSurfaceHandle const& iosurface_handle)
|
|
{
|
|
auto size = IntSize(static_cast<int>(iosurface_handle.width()), static_cast<int>(iosurface_handle.height()));
|
|
auto bitmap_handle = Core::IOSurfaceHandle::from_mach_port(iosurface_handle.create_mach_port());
|
|
return MUST(Bitmap::create_wrapper(shared_image_buffer_format, shared_image_buffer_alpha_type, size, iosurface_handle.bytes_per_row(), iosurface_handle.data(), [handle = move(bitmap_handle)] { }));
|
|
}
|
|
|
|
SharedImageBuffer::SharedImageBuffer(Core::IOSurfaceHandle&& iosurface_handle, NonnullRefPtr<Bitmap> bitmap)
|
|
: m_iosurface_handle(move(iosurface_handle))
|
|
, m_bitmap(move(bitmap))
|
|
{
|
|
}
|
|
#else
|
|
static constexpr auto shared_image_buffer_format = BitmapFormat::BGRA8888;
|
|
static constexpr auto shared_image_buffer_alpha_type = AlphaType::Premultiplied;
|
|
# ifdef USE_VULKAN_DMABUF_IMAGES
|
|
static constexpr auto shared_image_buffer_drm_format = DRM_FORMAT_ARGB8888;
|
|
|
|
static NonnullRefPtr<Bitmap> create_bitmap_from_linux_dmabuf(LinuxDmaBufHandle const& dmabuf)
|
|
{
|
|
VERIFY(dmabuf.bitmap_format == shared_image_buffer_format);
|
|
VERIFY(dmabuf.alpha_type == shared_image_buffer_alpha_type);
|
|
VERIFY(dmabuf.drm_format == shared_image_buffer_drm_format);
|
|
VERIFY(dmabuf.modifier == DRM_FORMAT_MOD_LINEAR);
|
|
auto data_size = Bitmap::size_in_bytes(dmabuf.pitch, dmabuf.size.height());
|
|
auto* data = ::mmap(nullptr, data_size, PROT_READ, MAP_SHARED, dmabuf.file.fd(), 0);
|
|
VERIFY(data != MAP_FAILED);
|
|
return MUST(Bitmap::create_wrapper(dmabuf.bitmap_format, dmabuf.alpha_type, dmabuf.size, dmabuf.pitch, data, [data, data_size] {
|
|
VERIFY(::munmap(data, data_size) == 0);
|
|
}));
|
|
}
|
|
# endif
|
|
|
|
SharedImageBuffer::SharedImageBuffer(NonnullRefPtr<Bitmap> bitmap)
|
|
: m_bitmap(move(bitmap))
|
|
{
|
|
}
|
|
|
|
# ifdef USE_VULKAN_DMABUF_IMAGES
|
|
SharedImageBuffer::SharedImageBuffer(NonnullRefPtr<Bitmap> bitmap, LinuxDmaBufHandle&& dmabuf)
|
|
: m_linux_dmabuf_handle(move(dmabuf))
|
|
, m_bitmap(move(bitmap))
|
|
{
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
SharedImageBuffer SharedImageBuffer::create(IntSize size)
|
|
{
|
|
#ifdef AK_OS_MACOS
|
|
auto iosurface_handle = Core::IOSurfaceHandle::create(size.width(), size.height());
|
|
auto bitmap = create_bitmap_from_iosurface(iosurface_handle);
|
|
return SharedImageBuffer(move(iosurface_handle), move(bitmap));
|
|
#else
|
|
return SharedImageBuffer(MUST(Bitmap::create_shareable(shared_image_buffer_format, shared_image_buffer_alpha_type, size)));
|
|
#endif
|
|
}
|
|
|
|
SharedImageBuffer SharedImageBuffer::import_from_shared_image(SharedImage shared_image)
|
|
{
|
|
#ifdef AK_OS_MACOS
|
|
auto iosurface_handle = Core::IOSurfaceHandle::from_mach_port(shared_image.m_port);
|
|
auto bitmap = create_bitmap_from_iosurface(iosurface_handle);
|
|
return SharedImageBuffer(move(iosurface_handle), move(bitmap));
|
|
#else
|
|
return shared_image.m_data.visit(
|
|
[](ShareableBitmap& shareable_bitmap) -> SharedImageBuffer {
|
|
return SharedImageBuffer(*shareable_bitmap.bitmap());
|
|
},
|
|
[](LinuxDmaBufHandle& dmabuf) -> SharedImageBuffer {
|
|
# ifdef USE_VULKAN_DMABUF_IMAGES
|
|
auto bitmap = create_bitmap_from_linux_dmabuf(dmabuf);
|
|
return SharedImageBuffer(move(bitmap), move(dmabuf));
|
|
# else
|
|
(void)dmabuf;
|
|
VERIFY_NOT_REACHED();
|
|
# endif
|
|
});
|
|
#endif
|
|
}
|
|
|
|
SharedImageBuffer::SharedImageBuffer(SharedImageBuffer&&) = default;
|
|
|
|
SharedImageBuffer& SharedImageBuffer::operator=(SharedImageBuffer&&) = default;
|
|
|
|
SharedImageBuffer::~SharedImageBuffer() = default;
|
|
|
|
SharedImage SharedImageBuffer::export_shared_image() const
|
|
{
|
|
#ifdef AK_OS_MACOS
|
|
return SharedImage { m_iosurface_handle.create_mach_port() };
|
|
#else
|
|
return SharedImage { ShareableBitmap { m_bitmap, ShareableBitmap::ConstructWithKnownGoodBitmap } };
|
|
#endif
|
|
}
|
|
|
|
}
|