Files
ladybird/Libraries/LibGfx/SharedImageBuffer.cpp
Tim Ledbetter caac0eea04 LibGfx: Map imported Linux dmabuf backing stores read-only
The UI process only reads these pixels to composite them - all writes
happen in WebContent via Vulkan. Some dmabuf exporters refuse writable
mappings on re-imported fds even when the Vulkan memory is
`HOST_VISIBLE`.
2026-04-17 00:39:04 +02:00

109 lines
4.0 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))
{
}
#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
return SharedImageBuffer(create_bitmap_from_linux_dmabuf(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
}
}