ladybird/Userland/Libraries/LibCore/IOSurface.cpp
Aliaksandr Kalenik 79acb998e1 LibCore+LibWeb: Use Metal backend for Skia painter on macOS
If Metal context and IOSurface are available, Skia painter will use
Ganesh GPU backend on macOS, which is noticeably faster than the default
CPU backend.

Painting pipeline:
1. (WebContent) Allocate IOSurface for backing store
2. (WebContent) Allocate MTLTexture that wraps IOSurface
3. (WebContent) Paint into MTLTexture using Skia
4. (Browser) Wrap IOSurface into Gfx::Painter and use
   QPainter/CoreGraphics to blit backing store into viewport.

Things we should improve in the future:
1. Upload textures for images in advance instead of doing that before
   every repaint.
2. Teach AppKit client to read directly from IOSurface instead of
   copying.
2024-06-28 14:25:34 +02:00

132 lines
3.4 KiB
C++

/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/OwnPtr.h>
#include <LibCore/IOSurface.h>
#if !defined(AK_OS_MACOS)
static_assert(false, "This file must only be used for macOS");
#endif
#define FixedPoint FixedPointMacOS
#define Duration DurationMacOS
#include <IOSurface/IOSurface.h>
#undef FixedPoint
#undef Duration
namespace Core {
template<typename T>
class RefAutoRelease {
AK_MAKE_NONCOPYABLE(RefAutoRelease);
public:
RefAutoRelease(T ref)
: m_ref(ref)
{
}
~RefAutoRelease()
{
if (m_ref)
CFRelease(m_ref);
m_ref = nullptr;
}
T ref() const { return m_ref; }
private:
T m_ref { nullptr };
};
struct IOSurfaceHandle::IOSurfaceRefWrapper {
IOSurfaceRef ref;
};
IOSurfaceHandle::IOSurfaceHandle(OwnPtr<IOSurfaceRefWrapper>&& ref_wrapper)
: m_ref_wrapper(move(ref_wrapper))
{
}
IOSurfaceHandle::IOSurfaceHandle(IOSurfaceHandle&& other) = default;
IOSurfaceHandle& IOSurfaceHandle::operator=(IOSurfaceHandle&& other) = default;
IOSurfaceHandle::~IOSurfaceHandle()
{
if (m_ref_wrapper)
CFRelease(m_ref_wrapper->ref);
}
IOSurfaceHandle IOSurfaceHandle::create(int width, int height)
{
size_t bytes_per_element = 4;
uint32_t pixel_format = 'BGRA';
RefAutoRelease<CFNumberRef> width_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &width);
RefAutoRelease<CFNumberRef> height_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &height);
RefAutoRelease<CFNumberRef> bytes_per_element_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &bytes_per_element);
RefAutoRelease<CFNumberRef> pixel_format_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pixel_format);
CFMutableDictionaryRef props = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(props, kIOSurfaceWidth, width_number.ref());
CFDictionarySetValue(props, kIOSurfaceHeight, height_number.ref());
CFDictionarySetValue(props, kIOSurfaceBytesPerElement, bytes_per_element_number.ref());
CFDictionarySetValue(props, kIOSurfacePixelFormat, pixel_format_number.ref());
auto* ref = IOSurfaceCreate(props);
VERIFY(ref);
return IOSurfaceHandle(make<IOSurfaceRefWrapper>(ref));
}
MachPort IOSurfaceHandle::create_mach_port() const
{
auto port = IOSurfaceCreateMachPort(m_ref_wrapper->ref);
return MachPort::adopt_right(port, MachPort::PortRight::Send);
}
IOSurfaceHandle IOSurfaceHandle::from_mach_port(MachPort const& port)
{
// NOTE: This call does not destroy the port
auto* ref = IOSurfaceLookupFromMachPort(port.port());
VERIFY(ref);
return IOSurfaceHandle(make<IOSurfaceRefWrapper>(ref));
}
size_t IOSurfaceHandle::width() const
{
return IOSurfaceGetWidth(m_ref_wrapper->ref);
}
size_t IOSurfaceHandle::height() const
{
return IOSurfaceGetHeight(m_ref_wrapper->ref);
}
size_t IOSurfaceHandle::bytes_per_element() const
{
return IOSurfaceGetBytesPerElement(m_ref_wrapper->ref);
}
size_t IOSurfaceHandle::bytes_per_row() const
{
return IOSurfaceGetBytesPerRow(m_ref_wrapper->ref);
}
void* IOSurfaceHandle::data() const
{
return IOSurfaceGetBaseAddress(m_ref_wrapper->ref);
}
void* IOSurfaceHandle::core_foundation_pointer() const
{
return m_ref_wrapper->ref;
}
}