ladybird/Libraries/LibGfx/SharedImageBuffer.cpp
Andreas Kling f619caf621 LibGfx: Preserve imported Linux DMABUF handles
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.
2026-06-12 21:45:22 +02:00

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
}
}