2026-04-07 13:35:26 -03:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <LibGfx/SharedImage.h>
|
|
|
|
|
#include <LibIPC/Attachment.h>
|
|
|
|
|
#include <LibIPC/Decoder.h>
|
|
|
|
|
#include <LibIPC/Encoder.h>
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
#ifdef USE_VULKAN_DMABUF_IMAGES
|
|
|
|
|
# include <LibGfx/VulkanImage.h>
|
|
|
|
|
#endif
|
2026-04-07 13:35:26 -03:00
|
|
|
|
|
|
|
|
#ifdef AK_OS_MACOS
|
|
|
|
|
static Core::MachPort copy_send_right(Core::MachPort const& port)
|
|
|
|
|
{
|
|
|
|
|
auto result = mach_port_mod_refs(mach_task_self(), port.port(), MACH_PORT_RIGHT_SEND, +1);
|
|
|
|
|
VERIFY(result == KERN_SUCCESS);
|
|
|
|
|
return Core::MachPort::adopt_right(port.port(), Core::MachPort::PortRight::Send);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace Gfx {
|
|
|
|
|
|
|
|
|
|
#ifdef AK_OS_MACOS
|
|
|
|
|
SharedImage::SharedImage(Core::MachPort&& port)
|
|
|
|
|
: m_port(move(port))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
SharedImage::SharedImage(ShareableBitmap shareable_bitmap)
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
: m_data(move(shareable_bitmap))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SharedImage::SharedImage(LinuxDmaBufHandle&& dmabuf)
|
|
|
|
|
: m_data(move(dmabuf))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ifdef USE_VULKAN_DMABUF_IMAGES
|
|
|
|
|
static constexpr auto shared_image_bitmap_format = BitmapFormat::BGRA8888;
|
|
|
|
|
static constexpr auto shared_image_alpha_type = AlphaType::Premultiplied;
|
|
|
|
|
|
|
|
|
|
SharedImage duplicate_shared_image(VulkanImage const& vulkan_image)
|
|
|
|
|
{
|
|
|
|
|
return SharedImage { duplicate_linux_dmabuf_handle(vulkan_image) };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinuxDmaBufHandle duplicate_linux_dmabuf_handle(VulkanImage const& vulkan_image)
|
2026-04-07 13:35:26 -03:00
|
|
|
{
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
VERIFY(vulkan_image.info.format == VK_FORMAT_B8G8R8A8_UNORM);
|
|
|
|
|
auto fd = vulkan_image.get_dma_buf_fd();
|
|
|
|
|
VERIFY(fd >= 0);
|
|
|
|
|
return LinuxDmaBufHandle {
|
|
|
|
|
.bitmap_format = shared_image_bitmap_format,
|
|
|
|
|
.alpha_type = shared_image_alpha_type,
|
|
|
|
|
.size = IntSize(static_cast<int>(vulkan_image.info.extent.width), static_cast<int>(vulkan_image.info.extent.height)),
|
|
|
|
|
.drm_format = vk_format_to_drm_format(vulkan_image.info.format),
|
|
|
|
|
.pitch = static_cast<size_t>(vulkan_image.info.row_pitch),
|
|
|
|
|
.modifier = vulkan_image.info.modifier,
|
|
|
|
|
.file = IPC::File::adopt_fd(fd),
|
|
|
|
|
};
|
2026-04-07 13:35:26 -03:00
|
|
|
}
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
# endif
|
2026-04-07 13:35:26 -03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace IPC {
|
|
|
|
|
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
#ifndef AK_OS_MACOS
|
|
|
|
|
enum class SharedImageBackingType : u8 {
|
|
|
|
|
ShareableBitmap,
|
|
|
|
|
LinuxDmaBuf,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
ErrorOr<void> encode(Encoder& encoder, Gfx::LinuxDmaBufHandle const& dmabuf)
|
|
|
|
|
{
|
|
|
|
|
TRY(encoder.encode(dmabuf.bitmap_format));
|
|
|
|
|
TRY(encoder.encode(dmabuf.alpha_type));
|
|
|
|
|
TRY(encoder.encode(dmabuf.size));
|
|
|
|
|
TRY(encoder.encode(dmabuf.drm_format));
|
|
|
|
|
TRY(encoder.encode(dmabuf.pitch));
|
|
|
|
|
TRY(encoder.encode(dmabuf.modifier));
|
|
|
|
|
TRY(encoder.encode(TRY(IPC::File::clone_fd(dmabuf.file.fd()))));
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
ErrorOr<Gfx::LinuxDmaBufHandle> decode(Decoder& decoder)
|
|
|
|
|
{
|
|
|
|
|
return Gfx::LinuxDmaBufHandle {
|
|
|
|
|
.bitmap_format = TRY(decoder.decode<Gfx::BitmapFormat>()),
|
|
|
|
|
.alpha_type = TRY(decoder.decode<Gfx::AlphaType>()),
|
|
|
|
|
.size = TRY(decoder.decode<Gfx::IntSize>()),
|
|
|
|
|
.drm_format = TRY(decoder.decode<u32>()),
|
|
|
|
|
.pitch = TRY(decoder.decode<size_t>()),
|
|
|
|
|
.modifier = TRY(decoder.decode<u64>()),
|
|
|
|
|
.file = TRY(decoder.decode<IPC::File>()),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-04-07 13:35:26 -03:00
|
|
|
template<>
|
|
|
|
|
ErrorOr<void> encode(Encoder& encoder, Gfx::SharedImage const& shared_image)
|
|
|
|
|
{
|
|
|
|
|
#ifdef AK_OS_MACOS
|
|
|
|
|
TRY(encoder.append_attachment(Attachment::from_mach_port(copy_send_right(shared_image.m_port), Core::MachPort::MessageRight::MoveSend)));
|
|
|
|
|
#else
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
return shared_image.m_data.visit(
|
|
|
|
|
[&](Gfx::ShareableBitmap const& shareable_bitmap) -> ErrorOr<void> {
|
|
|
|
|
TRY(encoder.encode(SharedImageBackingType::ShareableBitmap));
|
|
|
|
|
TRY(encoder.encode(shareable_bitmap));
|
|
|
|
|
return {};
|
|
|
|
|
},
|
|
|
|
|
[&](Gfx::LinuxDmaBufHandle const& dmabuf) -> ErrorOr<void> {
|
|
|
|
|
TRY(encoder.encode(SharedImageBackingType::LinuxDmaBuf));
|
|
|
|
|
TRY(encoder.encode(dmabuf));
|
|
|
|
|
return {};
|
|
|
|
|
});
|
2026-04-07 13:35:26 -03:00
|
|
|
#endif
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
ErrorOr<Gfx::SharedImage> decode(Decoder& decoder)
|
|
|
|
|
{
|
|
|
|
|
#ifdef AK_OS_MACOS
|
|
|
|
|
auto attachment = decoder.attachments().dequeue();
|
|
|
|
|
VERIFY(attachment.message_right() == Core::MachPort::MessageRight::MoveSend);
|
|
|
|
|
return Gfx::SharedImage { attachment.release_mach_port() };
|
|
|
|
|
#else
|
LibGfx+LibWeb: Add Linux dmabuf backing stores to SharedImage
On Linux builds with Vulkan, WebContent already paints into GPU-backed
Skia surfaces, but the backing store shared with the UI process was
still a CPU ShareableBitmap. That forced every flush to read the GPU
image back into a bitmap so the UI could sample it, defeating most of
the benefit of GPU painting.
Teach SharedImage to carry a LinuxDmaBufHandle alongside ShareableBitmap
as a Variant, with a tagged IPC encoding and an fd clone on encode so
both processes own an independent handle. When USE_VULKAN_DMABUF_IMAGES
is enabled, BackingStoreManager now allocates the front/back buffers as
linear-modifier Vulkan images and publishes their dmabuf fds to the UI;
the Skia painting surfaces wrap those Vulkan images directly, so no
readback is needed. The old shareable-bitmap path is preserved as a
fallback for the non-Vulkan case and when image creation fails.
On the receive side, SharedImageBuffer::import_from_shared_image mmaps
a linear dmabuf to reconstruct a CPU Bitmap, keeping existing consumers
that expect CPU access working unchanged.
VulkanImage memory type selection is factored into a small helper, and
linear images now request host-visible (cached if available) memory
rather than device-local, since a linear dmabuf has to be CPU-mappable
on the importer side.
2026-04-07 15:38:22 -03:00
|
|
|
switch (TRY(decoder.decode<SharedImageBackingType>())) {
|
|
|
|
|
case SharedImageBackingType::ShareableBitmap:
|
|
|
|
|
return Gfx::SharedImage { TRY(decoder.decode<Gfx::ShareableBitmap>()) };
|
|
|
|
|
case SharedImageBackingType::LinuxDmaBuf:
|
|
|
|
|
return Gfx::SharedImage { TRY(decoder.decode<Gfx::LinuxDmaBufHandle>()) };
|
|
|
|
|
default:
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
}
|
2026-04-07 13:35:26 -03:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|