diff --git a/Userland/Libraries/LibCore/CMakeLists.txt b/Userland/Libraries/LibCore/CMakeLists.txt index 45a859f24fd..6d7711ca773 100644 --- a/Userland/Libraries/LibCore/CMakeLists.txt +++ b/Userland/Libraries/LibCore/CMakeLists.txt @@ -83,6 +83,10 @@ if (APPLE OR CMAKE_SYSTEM_NAME STREQUAL "GNU") list(APPEND SOURCES MachPort.cpp) endif() +if (APPLE) + list(APPEND SOURCES IOSurface.cpp) +endif() + serenity_lib(LibCore core) target_link_libraries(LibCore PRIVATE LibCrypt LibTimeZone LibURL) target_link_libraries(LibCore PUBLIC LibCoreMinimal) @@ -91,6 +95,7 @@ if (APPLE) target_link_libraries(LibCore PUBLIC "-framework CoreFoundation") target_link_libraries(LibCore PUBLIC "-framework CoreServices") target_link_libraries(LibCore PUBLIC "-framework Foundation") + target_link_libraries(LibCore PUBLIC "-framework IOSurface") endif() if (ANDROID) diff --git a/Userland/Libraries/LibCore/IOSurface.cpp b/Userland/Libraries/LibCore/IOSurface.cpp new file mode 100644 index 00000000000..5296e49790e --- /dev/null +++ b/Userland/Libraries/LibCore/IOSurface.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#if !defined(AK_OS_MACOS) +static_assert(false, "This file must only be used for macOS"); +#endif + +#define FixedPoint FixedPointMacOS +#define Duration DurationMacOS +#include +#undef FixedPoint +#undef Duration + +namespace Core { + +template +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&& 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 width_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &width); + RefAutoRelease height_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &height); + RefAutoRelease bytes_per_element_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &bytes_per_element); + RefAutoRelease 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(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(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); +} + +void* IOSurfaceHandle::data() const +{ + return IOSurfaceGetBaseAddress(m_ref_wrapper->ref); +} + +} diff --git a/Userland/Libraries/LibCore/IOSurface.h b/Userland/Libraries/LibCore/IOSurface.h new file mode 100644 index 00000000000..05056884af2 --- /dev/null +++ b/Userland/Libraries/LibCore/IOSurface.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Core { + +class IOSurfaceHandle { + AK_MAKE_NONCOPYABLE(IOSurfaceHandle); + +public: + IOSurfaceHandle(IOSurfaceHandle&& other); + IOSurfaceHandle& operator=(IOSurfaceHandle&& other); + + static IOSurfaceHandle create(int width, int height); + static IOSurfaceHandle from_mach_port(MachPort const& port); + + MachPort create_mach_port() const; + + size_t width() const; + size_t height() const; + size_t bytes_per_element() const; + void* data() const; + + ~IOSurfaceHandle(); + +private: + struct IOSurfaceRefWrapper; + + IOSurfaceHandle(OwnPtr&&); + + OwnPtr m_ref_wrapper; +}; + +} diff --git a/Userland/Libraries/LibCore/MachPort.h b/Userland/Libraries/LibCore/MachPort.h index bd435f0b7b9..82c16652a09 100644 --- a/Userland/Libraries/LibCore/MachPort.h +++ b/Userland/Libraries/LibCore/MachPort.h @@ -69,7 +69,7 @@ public: #endif // FIXME: mach_msg wrapper? For now just let the owner poke into the internals - mach_port_t port() { return m_port; } + mach_port_t port() const { return m_port; } private: MachPort(PortRight, mach_port_t);