Diff
Modified: trunk/Source/WebCore/ChangeLog (291342 => 291343)
--- trunk/Source/WebCore/ChangeLog 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/ChangeLog 2022-03-16 13:12:30 UTC (rev 291343)
@@ -1,3 +1,138 @@
+2022-03-16 Zan Dobersek <zdober...@igalia.com>
+
+ [GTK][WPE] Provide DMABuf-based composition layers, DMABufVideoSink integration
+ https://bugs.webkit.org/show_bug.cgi?id=237328
+ <rdar://problem/90295492>
+
+ Reviewed by Alejandro G. Castro.
+
+ Introduce TextureMapperPlatformLayerProxyDMABuf, a TextureMapper proxy
+ implementation that handles platform layers backed by dmabuf objects.
+ This will be used to handle display of dmabuf producers like GStreamer
+ pipelines or ANGLE-backed WebGL contexts. The DMABufLayer class is the
+ platform layer object, handling display of the actual dmabuf. The proxy
+ itself is tasked with creating and caching such layers for any dmabuf
+ object that originates from the producer.
+
+ For each dmabuf object pushed into the proxy, the according DMABufLayer
+ object is spawned and cached for future reuse, expecting the producer
+ to be able to provide dmabufs from a pool or swapchain of these objects.
+ The cache is emptied whenever dmabufs go unused for a certain amount of
+ swaps, or if the size of the provided dmabufs changes.
+
+ DMABufFormat provides information for different DRM formats, for
+ instance how different planes for specific formats are formatted and
+ sized.
+
+ DMABufObject is a class that handles a given grouping of dmabufs
+ according to the specified format. It has an associated handle value,
+ size, and per-plane dmabuf file descriptors, offsets, strides and
+ modifiers, along with a DMABufReleaseFlag instance.
+
+ DMABufReleaseFlag objects are used as an eventfd-based release mechanism
+ that indicates to the producer that the given DMABufObject has been
+ presented and subsequently released and is thus available for reuse.
+
+ GBMBufferSwapchain provides a custom swapchain implementation that's
+ based on libgbm functionality. Each such swapchain has a capacity
+ specified during construction, with the capacities of four or eight
+ currently supported. getBuffer() is called by the producer to obtain a
+ buffer object that's then used for backing of specific content like
+ ANGLE execution or media's software-decoded video frames. Buffers
+ obtained this way are moved over to the end of the buffer array, with
+ the expectation of reusing them once they are released by the
+ composition engine.
+
+ MediaPlayerPrivateGStreamer implementation is enhanced to use the
+ recently-added WebKitDMABufVideoSink element if its use is enabled
+ through the development-purpose environment variable and if the
+ necessary GStreamer facilities are present on the system. When these
+ conditions are met, the Nicosia::ContentLayer instance is also
+ constructed with a TextureMapperPlatformLayerProxyDMABuf instance, since
+ we expect to present the dmabufs through that functionality.
+
+ With the WebKitDMABufVideoSink, the incoming samples are either based
+ on dmabufs (in case of dmabuf-capable hardware decoder) or are just raw
+ data (most likely coming from a software-based decoder). In case of
+ dmabufs we can use the GstMemory pointer as the handle through which
+ the relevant data is cached in TextureMapperPlatformLayerProxyDMABuf,
+ and upon the first occurrence we retrieve all the relevant dmabuf data
+ so that it can be used by that proxy implementation to construct a
+ renderable EGLImage.
+
+ In case of software-decoded raw data, we have to use the swapchain
+ object and copy the data on a per-plane basis for each such sample,
+ finally pushing the dmabuf data of that swapchain buffer into the
+ TextureMapperPlatformLayerProxyDMABuf instance.
+
+ Changes around TextureMapperPlatformLayerProxyDMABuf and GStreamer
+ integration are guarded with USE(TEXTURE_MAPPER_DMABUF). No port yet
+ enables this build guard, but this will be handled later. Similarly,
+ the code specific to libgbm will also be guarded in a separate set of
+ changes.
+
+ * SourcesGTK.txt:
+ * SourcesWPE.txt:
+ * platform/TextureMapper.cmake:
+ * platform/graphics/gbm/DMABufFormat.h: Added.
+ (WebCore::DMABufFormatImpl::createFourCC):
+ (WebCore::DMABufFormat::planeWidth const):
+ (WebCore::DMABufFormat::planeHeight const):
+ (WebCore::DMABufFormat::Plane::Plane):
+ (WebCore::DMABufFormatImpl::createSinglePlaneRGBA):
+ (WebCore::DMABufFormatImpl::definePlane):
+ (WebCore::DMABufFormat::instantiate):
+ (WebCore::DMABufFormat::create):
+ * platform/graphics/gbm/DMABufObject.h: Added.
+ (WebCore::DMABufObject::DMABufObject):
+ (WebCore::DMABufObject::~DMABufObject):
+ (WebCore::DMABufObject::operator=):
+ * platform/graphics/gbm/DMABufReleaseFlag.h: Added.
+ (WebCore::DMABufReleaseFlag::DMABufReleaseFlag):
+ (WebCore::DMABufReleaseFlag::~DMABufReleaseFlag):
+ (WebCore::DMABufReleaseFlag::operator=):
+ (WebCore::DMABufReleaseFlag::dup const):
+ (WebCore::DMABufReleaseFlag::released const):
+ (WebCore::DMABufReleaseFlag::release):
+ * platform/graphics/gbm/GBMBufferSwapchain.cpp: Added.
+ (WebCore::GBMBufferSwapchain::GBMBufferSwapchain):
+ (WebCore::GBMBufferSwapchain::getBuffer):
+ (WebCore::GBMBufferSwapchain::Buffer::Buffer):
+ (WebCore::GBMBufferSwapchain::Buffer::createDMABufObject const):
+ (WebCore::GBMBufferSwapchain::Buffer::PlaneData::~PlaneData):
+ * platform/graphics/gbm/GBMBufferSwapchain.h: Added.
+ (WebCore::GBMBufferSwapchain::Buffer::handle const):
+ (WebCore::GBMBufferSwapchain::Buffer::numPlanes const):
+ (WebCore::GBMBufferSwapchain::Buffer::planeData const):
+ * platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp:
+ (webKitDMABufVideoSinkIsEnabled):
+ (webKitDMABufVideoSinkSetMediaPlayerPrivate):
+ * platform/graphics/gstreamer/DMABufVideoSinkGStreamer.h:
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+ (WebCore::MediaPlayerPrivateGStreamer::MediaPlayerPrivateGStreamer):
+ (WebCore::MediaPlayerPrivateGStreamer::platformLayer const):
+ (WebCore::fourccValue):
+ (WebCore::MediaPlayerPrivateGStreamer::pushDMABufToCompositor):
+ (WebCore::MediaPlayerPrivateGStreamer::triggerRepaint):
+ (WebCore::MediaPlayerPrivateGStreamer::createVideoSinkDMABuf):
+ (WebCore::MediaPlayerPrivateGStreamer::createVideoSink):
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
+ * platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.cpp:
+ (Nicosia::ContentLayerTextureMapperImpl::createFactory):
+ * platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.h:
+ * platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.cpp: Added.
+ (WebCore::createImageKHR):
+ (WebCore::destroyImageKHR):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::EGLImageData::~EGLImageData):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::activateOnCompositingThread):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::invalidate):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::swapBuffer):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::pushDMABuf):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::DMABufLayer):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::paintToTextureMapper):
+ (WebCore::TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::createEGLImageData):
+ * platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.h: Added.
+
2022-03-16 Alejandro G. Castro <a...@igalia.com>
[GTK][WPE] Debug build assertion, TextureMapperPlatformLayerProxyGL asserts when going back in the minibrowser
Modified: trunk/Source/WebCore/SourcesGTK.txt (291342 => 291343)
--- trunk/Source/WebCore/SourcesGTK.txt 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/SourcesGTK.txt 2022-03-16 13:12:30 UTC (rev 291343)
@@ -101,6 +101,7 @@
platform/graphics/egl/GLContextEGLWayland.cpp @no-unify
platform/graphics/egl/GLContextEGLX11.cpp @no-unify
+platform/graphics/gbm/GBMBufferSwapchain.cpp
platform/graphics/gbm/GBMDevice.cpp
platform/graphics/glx/GLContextGLX.cpp @no-unify
Modified: trunk/Source/WebCore/SourcesWPE.txt (291342 => 291343)
--- trunk/Source/WebCore/SourcesWPE.txt 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/SourcesWPE.txt 2022-03-16 13:12:30 UTC (rev 291343)
@@ -89,6 +89,7 @@
platform/graphics/egl/GLContextEGL.cpp
platform/graphics/egl/GLContextEGLLibWPE.cpp
+platform/graphics/gbm/GBMBufferSwapchain.cpp
platform/graphics/gbm/GBMDevice.cpp
platform/graphics/libwpe/PlatformDisplayLibWPE.cpp
Modified: trunk/Source/WebCore/platform/TextureMapper.cmake (291342 => 291343)
--- trunk/Source/WebCore/platform/TextureMapper.cmake 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/TextureMapper.cmake 2022-03-16 13:12:30 UTC (rev 291343)
@@ -51,6 +51,16 @@
)
endif ()
+if (USE_TEXTURE_MAPPER_DMABUF)
+ list(APPEND WebCore_SOURCES
+ platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.cpp
+ )
+
+ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
+ platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.h
+ )
+endif ()
+
if (USE_COORDINATED_GRAPHICS)
list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES
"${WEBCORE_DIR}/page/scrolling/nicosia"
Added: trunk/Source/WebCore/platform/graphics/gbm/DMABufFormat.h (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/gbm/DMABufFormat.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gbm/DMABufFormat.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <cstdint>
+
+namespace WebCore {
+
+namespace DMABufFormatImpl {
+
+static constexpr uint32_t createFourCC(char a, char b, char c, char d)
+{
+ return uint32_t(a) | (uint32_t(b) << 8) | (uint32_t(c) << 16) | (uint32_t(d) << 24);
+}
+
+}
+
+struct DMABufFormat {
+ enum class FourCC : uint32_t {
+ Invalid = 0,
+
+ R8 = DMABufFormatImpl::createFourCC('R', '8', ' ', ' '),
+ GR88 = DMABufFormatImpl::createFourCC('G', 'R', '8', '8'),
+
+ XRGB8888 = DMABufFormatImpl::createFourCC('X', 'R', '2', '4'),
+ XBGR8888 = DMABufFormatImpl::createFourCC('X', 'B', '2', '4'),
+ RGBX8888 = DMABufFormatImpl::createFourCC('R', 'X', '2', '4'),
+ BGRX8888 = DMABufFormatImpl::createFourCC('B', 'X', '2', '4'),
+ ARGB8888 = DMABufFormatImpl::createFourCC('A', 'R', '2', '4'),
+ ABGR8888 = DMABufFormatImpl::createFourCC('A', 'B', '2', '4'),
+ RGBA8888 = DMABufFormatImpl::createFourCC('R', 'A', '2', '4'),
+ BGRA8888 = DMABufFormatImpl::createFourCC('B', 'A', '2', '4'),
+ RGB888 = DMABufFormatImpl::createFourCC('R', 'G', '2', '4'),
+ BGR888 = DMABufFormatImpl::createFourCC('B', 'G', '2', '4'),
+
+ I420 = DMABufFormatImpl::createFourCC('I', '4', '2', '0'),
+ YV12 = DMABufFormatImpl::createFourCC('Y', 'V', '1', '2'),
+ A420 = DMABufFormatImpl::createFourCC('A', '4', '2', '0'),
+ NV12 = DMABufFormatImpl::createFourCC('N', 'V', '1', '2'),
+ NV21 = DMABufFormatImpl::createFourCC('N', 'V', '2', '1'),
+
+ YUY2 = DMABufFormatImpl::createFourCC('Y', 'U', 'Y', '2'),
+ YVYU = DMABufFormatImpl::createFourCC('Y', 'V', 'Y', 'U'),
+ UYVY = DMABufFormatImpl::createFourCC('U', 'Y', 'V', 'Y'),
+ VYUY = DMABufFormatImpl::createFourCC('V', 'Y', 'U', 'Y'),
+ VUYA = DMABufFormatImpl::createFourCC('V', 'U', 'Y', 'A'),
+ AYUV = DMABufFormatImpl::createFourCC('A', 'Y', 'U', 'V'),
+
+ Y444 = DMABufFormatImpl::createFourCC('Y', '4', '4', '4'),
+ Y41B = DMABufFormatImpl::createFourCC('Y', '4', '1', 'B'),
+ Y42B = DMABufFormatImpl::createFourCC('Y', '4', '2', 'B'),
+ };
+
+ static constexpr unsigned c_maxPlanes = 4;
+
+ template<FourCC> static DMABufFormat create() = delete;
+ static DMABufFormat create(uint32_t);
+
+ template<FourCC fourccValue, typename... PlaneDefinitionTypes>
+ static DMABufFormat instantiate();
+
+ FourCC fourcc { FourCC::Invalid };
+ unsigned numPlanes { 0 };
+
+ uint32_t planeWidth(unsigned planeIndex, uint32_t width) const
+ {
+ ASSERT(planeIndex < c_maxPlanes);
+ return (width >> planes[planeIndex].horizontalSubsampling);
+ }
+
+ uint32_t planeHeight(unsigned planeIndex, uint32_t height) const
+ {
+ ASSERT(planeIndex < c_maxPlanes);
+ return (height >> planes[planeIndex].verticalSubsampling);
+ }
+
+ template<FourCC fourccValue, unsigned hsValue, unsigned vsValue>
+ struct PlaneDefinition {
+ static constexpr FourCC fourcc = fourccValue;
+ static constexpr unsigned horizontalSubsampling = hsValue;
+ static constexpr unsigned verticalSubsampling = vsValue;
+ };
+
+ struct Plane {
+ Plane() = default;
+
+ template<typename PlaneDefitionType>
+ Plane(const PlaneDefitionType&)
+ : fourcc(PlaneDefitionType::fourcc)
+ , horizontalSubsampling(PlaneDefitionType::horizontalSubsampling)
+ , verticalSubsampling(PlaneDefitionType::verticalSubsampling)
+ { }
+
+ FourCC fourcc { FourCC::Invalid };
+ unsigned horizontalSubsampling { 0 };
+ unsigned verticalSubsampling { 0 };
+ };
+ std::array<Plane, c_maxPlanes> planes;
+};
+
+namespace DMABufFormatImpl {
+
+template<DMABufFormat::FourCC fourccValue>
+inline DMABufFormat createSinglePlaneRGBA()
+{
+ return DMABufFormat::instantiate<fourccValue,
+ DMABufFormat::PlaneDefinition<fourccValue, 0, 0>>();
+}
+
+template<size_t Index, size_t Size, typename PlaneDefinitionType, typename... PlaneDefinitionTypes>
+void definePlane(std::array<DMABufFormat::Plane, DMABufFormat::c_maxPlanes>& planes)
+{
+ new (&planes[Index]) DMABufFormat::Plane(PlaneDefinitionType { });
+ if constexpr ((Index + 1) < Size)
+ definePlane<Index + 1, Size, PlaneDefinitionTypes...>(planes);
+}
+
+}
+
+template<DMABufFormat::FourCC fourccValue, typename... PlaneDefinitionTypes>
+inline DMABufFormat DMABufFormat::instantiate()
+{
+ static_assert(sizeof...(PlaneDefinitionTypes) <= 4);
+
+ DMABufFormat format;
+ format.fourcc = fourccValue;
+ format.numPlanes = sizeof...(PlaneDefinitionTypes);
+ DMABufFormatImpl::definePlane<0, sizeof...(PlaneDefinitionTypes), PlaneDefinitionTypes...>(format.planes);
+ return format;
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::XRGB8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::XRGB8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::XBGR8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::XBGR8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::RGBX8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::RGBX8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::BGRX8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::BGRX8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::ARGB8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::ARGB8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::ABGR8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::ABGR8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::RGBA8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::RGBA8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::BGRA8888>()
+{
+ return DMABufFormatImpl::createSinglePlaneRGBA<FourCC::BGRA8888>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::I420>()
+{
+ return DMABufFormat::instantiate<FourCC::I420,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 1, 1>,
+ PlaneDefinition<FourCC::R8, 1, 1>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::YV12>()
+{
+ return DMABufFormat::instantiate<FourCC::YV12,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 1, 1>,
+ PlaneDefinition<FourCC::R8, 1, 1>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::A420>()
+{
+ return DMABufFormat::instantiate<FourCC::A420,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 1, 1>,
+ PlaneDefinition<FourCC::R8, 1, 1>,
+ PlaneDefinition<FourCC::R8, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::NV12>()
+{
+ return DMABufFormat::instantiate<FourCC::NV12,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::GR88, 1, 1>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::NV21>()
+{
+ return DMABufFormat::instantiate<FourCC::NV21,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::GR88, 1, 1>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::YUY2>()
+{
+ return DMABufFormat::instantiate<FourCC::YUY2,
+ PlaneDefinition<FourCC::GR88, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::YVYU>()
+{
+ return DMABufFormat::instantiate<FourCC::YVYU,
+ PlaneDefinition<FourCC::GR88, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::UYVY>()
+{
+ return DMABufFormat::instantiate<FourCC::UYVY,
+ PlaneDefinition<FourCC::GR88, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::VYUY>()
+{
+ return DMABufFormat::instantiate<FourCC::YVYU,
+ PlaneDefinition<FourCC::GR88, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::VUYA>()
+{
+ return DMABufFormat::instantiate<FourCC::VUYA,
+ PlaneDefinition<FourCC::ABGR8888, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::AYUV>()
+{
+ return DMABufFormat::instantiate<FourCC::VUYA,
+ PlaneDefinition<FourCC::ABGR8888, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::Y444>()
+{
+ return DMABufFormat::instantiate<FourCC::Y444,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 0, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::Y41B>()
+{
+ return DMABufFormat::instantiate<FourCC::Y41B,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 2, 0>,
+ PlaneDefinition<FourCC::R8, 2, 0>>();
+}
+
+template<>
+inline DMABufFormat DMABufFormat::create<DMABufFormat::FourCC::Y42B>()
+{
+ return DMABufFormat::instantiate<FourCC::Y42B,
+ PlaneDefinition<FourCC::R8, 0, 0>,
+ PlaneDefinition<FourCC::R8, 1, 0>,
+ PlaneDefinition<FourCC::R8, 1, 0>>();
+}
+
+inline DMABufFormat DMABufFormat::create(uint32_t fourccValue)
+{
+ switch (fourccValue) {
+ case uint32_t(FourCC::XRGB8888):
+ return create<FourCC::XRGB8888>();
+ case uint32_t(FourCC::XBGR8888):
+ return create<FourCC::XBGR8888>();
+ case uint32_t(FourCC::RGBX8888):
+ return create<FourCC::RGBX8888>();
+ case uint32_t(FourCC::BGRX8888):
+ return create<FourCC::BGRX8888>();
+ case uint32_t(FourCC::ARGB8888):
+ return create<FourCC::ARGB8888>();
+ case uint32_t(FourCC::ABGR8888):
+ return create<FourCC::ABGR8888>();
+ case uint32_t(FourCC::RGBA8888):
+ return create<FourCC::RGBA8888>();
+ case uint32_t(FourCC::BGRA8888):
+ return create<FourCC::BGRA8888>();
+ case uint32_t(FourCC::I420):
+ return create<FourCC::I420>();
+ case uint32_t(FourCC::YV12):
+ return create<FourCC::YV12>();
+ case uint32_t(FourCC::A420):
+ return create<FourCC::A420>();
+ case uint32_t(FourCC::NV12):
+ return create<FourCC::NV12>();
+ case uint32_t(FourCC::NV21):
+ return create<FourCC::NV21>();
+ case uint32_t(FourCC::YUY2):
+ return create<FourCC::YUY2>();
+ case uint32_t(FourCC::YVYU):
+ return create<FourCC::YVYU>();
+ case uint32_t(FourCC::UYVY):
+ return create<FourCC::UYVY>();
+ case uint32_t(FourCC::VYUY):
+ return create<FourCC::UYVY>();
+ case uint32_t(FourCC::VUYA):
+ return create<FourCC::VUYA>();
+ case uint32_t(FourCC::AYUV):
+ return create<FourCC::AYUV>();
+ case uint32_t(FourCC::Y444):
+ return create<FourCC::Y444>();
+ case uint32_t(FourCC::Y41B):
+ return create<FourCC::Y41B>();
+ case uint32_t(FourCC::Y42B):
+ return create<FourCC::Y42B>();
+ default:
+ break;
+ }
+
+ return { };
+}
+
+} // namespace WebCore
Added: trunk/Source/WebCore/platform/graphics/gbm/DMABufObject.h (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/gbm/DMABufObject.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gbm/DMABufObject.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "DMABufFormat.h"
+#include "DMABufReleaseFlag.h"
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <unistd.h>
+
+namespace WebCore {
+
+struct DMABufObject {
+ DMABufObject(uintptr_t handle)
+ : handle(handle)
+ { }
+
+ ~DMABufObject()
+ {
+ for (unsigned i = 0; i < format.numPlanes; ++i) {
+ if (fd[i] != -1)
+ close(fd[i]);
+ }
+ }
+
+ DMABufObject(const DMABufObject&) = delete;
+ DMABufObject& operator=(const DMABufObject&) = delete;
+
+ DMABufObject(DMABufObject&& o)
+ : handle(o.handle)
+ , format(o.format)
+ , width(o.width)
+ , height(o.height)
+ , releaseFlag(WTFMove(o.releaseFlag))
+ {
+ for (unsigned i = 0; i < format.numPlanes; ++i) {
+ fd[i] = o.fd[i];
+ o.fd[i] = -1;
+
+ offset[i] = o.offset[i];
+ stride[i] = o.stride[i];
+ modifier[i] = o.modifier[i];
+ }
+ }
+
+ DMABufObject& operator=(DMABufObject&& o)
+ {
+ if (this == &o)
+ return *this;
+
+ this->~DMABufObject();
+ new (this) DMABufObject(WTFMove(o));
+ return *this;
+ }
+
+ uintptr_t handle { 0 };
+ DMABufFormat format { };
+ uint32_t width { 0 };
+ uint32_t height { 0 };
+ DMABufReleaseFlag releaseFlag { };
+ std::array<int, DMABufFormat::c_maxPlanes> fd { -1, -1, -1, -1 };
+ std::array<size_t, DMABufFormat::c_maxPlanes> offset { 0, 0, 0, 0 };
+ std::array<uint32_t, DMABufFormat::c_maxPlanes> stride { 0, 0, 0, 0 };
+ std::array<uint64_t, DMABufFormat::c_maxPlanes> modifier { 0, 0, 0, 0 };
+};
+
+} // namespace WebCore
Added: trunk/Source/WebCore/platform/graphics/gbm/DMABufReleaseFlag.h (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/gbm/DMABufReleaseFlag.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gbm/DMABufReleaseFlag.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <sys/eventfd.h>
+#include <wtf/UniStdExtras.h>
+
+namespace WebCore {
+
+struct DMABufReleaseFlag {
+ DMABufReleaseFlag() = default;
+
+ enum InitializeTag { Initialize };
+ DMABufReleaseFlag(InitializeTag)
+ {
+ fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+ }
+
+ ~DMABufReleaseFlag()
+ {
+ if (fd != -1)
+ close(fd);
+ fd = -1;
+ }
+
+ DMABufReleaseFlag(const DMABufReleaseFlag&) = delete;
+ DMABufReleaseFlag& operator=(const DMABufReleaseFlag&) = delete;
+
+ DMABufReleaseFlag(DMABufReleaseFlag&& o)
+ {
+ fd = o.fd;
+ o.fd = -1;
+ }
+
+ DMABufReleaseFlag& operator=(DMABufReleaseFlag&& o)
+ {
+ if (this == &o)
+ return *this;
+
+ this->~DMABufReleaseFlag();
+ new (this) DMABufReleaseFlag(WTFMove(o));
+ return *this;
+ }
+
+ DMABufReleaseFlag dup() const
+ {
+ if (fd == -1)
+ return { };
+
+ DMABufReleaseFlag flag;
+ flag.fd = dupCloseOnExec(fd);
+ return flag;
+ }
+
+ bool released() const
+ {
+ if (fd == -1)
+ return true;
+
+ uint64_t value { 0 };
+ if (read(fd, &value, sizeof(uint64_t)) == sizeof(uint64_t))
+ return !!value;
+ return false;
+ }
+
+ void release()
+ {
+ if (fd == -1)
+ return;
+
+ uint64_t value { 1 };
+ write(fd, &value, sizeof(uint64_t));
+ }
+
+ int fd { -1 };
+};
+
+} // namespace WebCore
Added: trunk/Source/WebCore/platform/graphics/gbm/GBMBufferSwapchain.cpp (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/gbm/GBMBufferSwapchain.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gbm/GBMBufferSwapchain.cpp 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GBMBufferSwapchain.h"
+
+#include "GBMDevice.h"
+#include <gbm.h>
+
+namespace WebCore {
+
+GBMBufferSwapchain::GBMBufferSwapchain(BufferSwapchainSize size)
+{
+ ASSERT(unsigned(size) < c_maxBuffers);
+ m_array.size = unsigned(size);
+}
+
+GBMBufferSwapchain::~GBMBufferSwapchain() = default;
+
+RefPtr<GBMBufferSwapchain::Buffer> GBMBufferSwapchain::getBuffer(const BufferDescription& description)
+{
+ auto& device = GBMDevice::get();
+
+ // If the description of the requested buffers has changed, update the description to the new one and wreck the existing buffers.
+ // This should handle changes in format or dimension of the buffers.
+ if (description.format.fourcc != m_array.description.format.fourcc || description.width != m_array.description.width || description.height != m_array.description.height) {
+ m_array.description = description;
+ m_array.object = { };
+ }
+
+ // Swapchain was asked to provide a buffer. The buffer array is traversed to find one.
+ for (unsigned i = 0; i < m_array.size; ++i) {
+ if (!m_array.object[i]) {
+ // If no buffer was spawned yet at this location, we do that, and return it.
+ auto buffer = adoptRef(*new Buffer(m_handleGenerator++, description));
+ m_array.object[i] = buffer.copyRef();
+
+ // Fill out the buffer's description and plane information for known and supported formats.
+ switch (description.format.fourcc) {
+ case DMABufFormat::FourCC::XRGB8888:
+ case DMABufFormat::FourCC::XBGR8888:
+ case DMABufFormat::FourCC::RGBX8888:
+ case DMABufFormat::FourCC::BGRX8888:
+ case DMABufFormat::FourCC::ARGB8888:
+ case DMABufFormat::FourCC::ABGR8888:
+ case DMABufFormat::FourCC::RGBA8888:
+ case DMABufFormat::FourCC::BGRA8888:
+ case DMABufFormat::FourCC::I420:
+ case DMABufFormat::FourCC::YV12:
+ case DMABufFormat::FourCC::A420:
+ case DMABufFormat::FourCC::NV12:
+ case DMABufFormat::FourCC::NV21:
+ case DMABufFormat::FourCC::YUY2:
+ case DMABufFormat::FourCC::YVYU:
+ case DMABufFormat::FourCC::UYVY:
+ case DMABufFormat::FourCC::VYUY:
+ case DMABufFormat::FourCC::VUYA:
+ case DMABufFormat::FourCC::AYUV:
+ case DMABufFormat::FourCC::Y444:
+ case DMABufFormat::FourCC::Y41B:
+ case DMABufFormat::FourCC::Y42B:
+ buffer->m_description.format.numPlanes = description.format.numPlanes;
+ for (unsigned i = 0; i < buffer->m_description.format.numPlanes; ++i) {
+ buffer->m_planes[i].fourcc = description.format.planes[i].fourcc;
+ buffer->m_planes[i].width = description.format.planeWidth(i, description.width);
+ buffer->m_planes[i].height = description.format.planeHeight(i, description.height);
+ }
+ break;
+ default:
+ return nullptr;
+ }
+
+ // For each plane, we spawn a gbm_bo object of the appropriate size and format.
+ // TODO: GBM_BO_USE_LINEAR will be needed when transferring memory into the bo (e.g. copying
+ // over the software-decoded video data), but might not be required for backing e.g. ANGLE rendering.
+ for (unsigned i = 0; i < buffer->m_description.format.numPlanes; ++i) {
+ auto& plane = buffer->m_planes[i];
+ plane.bo = gbm_bo_create(device.device(), plane.width, plane.height, uint32_t(plane.fourcc), GBM_BO_USE_LINEAR);
+ plane.stride = gbm_bo_get_stride(plane.bo);
+ }
+
+ // Lock the buffer and return it.
+ buffer->m_state.locked = true;
+ return buffer;
+ }
+
+ // There is already an existing buffer at this location. If marked as locked, update its state by reading
+ // the release flag. If still locked after that, we have to continue over to the next candidate.
+ {
+ auto& buffer = m_array.object[i];
+ if (buffer->m_state.locked)
+ buffer->m_state.locked = !buffer->m_state.releaseFlag.released();
+
+ if (buffer->m_state.locked)
+ continue;
+ }
+
+ // This buffer was unlocked, so it can be used. Lock and return it.
+ auto buffer = m_array.object[i].copyRef();
+ buffer->m_state.locked = true;
+
+ // Swap out the located buffer to the end of the buffer queue. When the next buffer is requested from this
+ // swapchain, the previously-used buffers will be traversed and tested for release first, meaning there's a
+ // higher chance we will be able to reuse them, without the penalty of having to traverse to deep into the
+ // swapchain array.
+ for (++i; i < m_array.size && !!m_array.object[i]; ++i)
+ std::swap(m_array.object[i - 1], m_array.object[i]);
+
+ return buffer;
+ }
+
+ return nullptr;
+}
+
+GBMBufferSwapchain::Buffer::Buffer(uint32_t handle, const BufferDescription& description)
+ : m_handle(handle)
+ , m_description(description)
+{
+ m_state.releaseFlag = DMABufReleaseFlag(DMABufReleaseFlag::Initialize);
+}
+
+GBMBufferSwapchain::Buffer::~Buffer() = default;
+
+DMABufObject GBMBufferSwapchain::Buffer::createDMABufObject(uintptr_t handle) const
+{
+ DMABufObject object(handle);
+ object.format = m_description.format;
+ object.width = m_description.width;
+ object.height = m_description.height;
+ object.releaseFlag = m_state.releaseFlag.dup();
+
+ for (unsigned i = 0; i < m_description.format.numPlanes; ++i) {
+ object.fd[i] = gbm_bo_get_fd(m_planes[i].bo);
+ object.offset[i] = 0;
+ object.stride[i] = m_planes[i].stride;
+ // TODO: these should be the plane-specific modifiers. We don't use them yet.
+ object.modifier[i] = 0;
+ }
+
+ return object;
+}
+
+GBMBufferSwapchain::Buffer::PlaneData::~PlaneData()
+{
+ if (bo)
+ gbm_bo_destroy(bo);
+}
+
+} // namespace WebCore
Added: trunk/Source/WebCore/platform/graphics/gbm/GBMBufferSwapchain.h (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/gbm/GBMBufferSwapchain.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gbm/GBMBufferSwapchain.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "DMABufFormat.h"
+#include "DMABufObject.h"
+#include "DMABufReleaseFlag.h"
+#include <array>
+#include <cstdint>
+#include <wtf/Noncopyable.h>
+#include <wtf/Nonmovable.h>
+#include <wtf/RefPtr.h>
+#include <wtf/ThreadSafeRefCounted.h>
+
+struct gbm_bo;
+
+namespace WebCore {
+
+class GBMBufferSwapchain : public ThreadSafeRefCounted<GBMBufferSwapchain> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ // The size should be adjusted to the use-case.
+ // For cyclical rendering (e.g. WebGL), Four should be ideal since we'll rely on
+ // something like vsync to maintain a constant framerate and subsequent buffer churn.
+ // There are other sporadic producers like software-based media decoders that will
+ // be requesting and filling in buffers in bursts but still have them displayed on
+ // a cyclical basis. Eight should be enough to cover that.
+ // In any case, the swapchain will do whatever it can to reuse released buffers
+ // and not unnecessarily spawn new ones, meaning the limit shouldn't be reached.
+ // If it is, getBuffer() will return a null object and the producer has to
+ // handle that somehow.
+ enum class BufferSwapchainSize : unsigned {
+ Four = 4,
+ Eight = 8
+ };
+
+ GBMBufferSwapchain(BufferSwapchainSize);
+ ~GBMBufferSwapchain();
+
+ struct BufferDescription {
+ DMABufFormat format { };
+ uint32_t width { 0 };
+ uint32_t height { 0 };
+ };
+
+ class Buffer : public ThreadSafeRefCounted<Buffer> {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ Buffer(uint32_t, const BufferDescription&);
+ ~Buffer();
+
+ DMABufObject createDMABufObject(uintptr_t) const;
+
+ struct PlaneData {
+ WTF_MAKE_NONCOPYABLE(PlaneData);
+ WTF_MAKE_NONMOVABLE(PlaneData);
+
+ PlaneData() = default;
+ ~PlaneData();
+
+ DMABufFormat::FourCC fourcc { DMABufFormat::FourCC::Invalid };
+ uint32_t width { 0 };
+ uint32_t height { 0 };
+ uint32_t stride { 0 };
+ struct gbm_bo* bo { nullptr };
+ };
+
+ uint32_t handle() const { return m_handle; }
+
+ unsigned numPlanes() const { return m_description.format.numPlanes; }
+ const PlaneData& planeData(unsigned index) const
+ {
+ ASSERT(index < DMABufFormat::c_maxPlanes);
+ return m_planes[index];
+ }
+
+ private:
+ friend class GBMBufferSwapchain;
+
+ uint32_t m_handle { 0 };
+ struct {
+ bool locked { false };
+ DMABufReleaseFlag releaseFlag;
+ } m_state;
+
+ BufferDescription m_description;
+ std::array<PlaneData, DMABufFormat::c_maxPlanes> m_planes;
+ };
+
+ RefPtr<Buffer> getBuffer(const BufferDescription&);
+
+private:
+ static constexpr unsigned c_maxBuffers = 8;
+
+ uint32_t m_handleGenerator { 0 };
+ struct {
+ BufferDescription description;
+ unsigned size { 0 };
+ std::array<RefPtr<Buffer>, c_maxBuffers> object { };
+ } m_array;
+};
+
+} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp (291342 => 291343)
--- trunk/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.cpp 2022-03-16 13:12:30 UTC (rev 291343)
@@ -160,6 +160,23 @@
"Sink Statistics", GST_TYPE_STRUCTURE, static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
}
+bool webKitDMABufVideoSinkIsEnabled()
+{
+ static bool s_enabled = false;
+ static std::once_flag s_flag;
+ std::call_once(s_flag,
+ [&] {
+ const char* value = g_getenv("WEBKIT_GST_DMABUF_SINK_ENABLED");
+ s_enabled = value && (equalIgnoringASCIICase(value, "true") || equalIgnoringASCIICase(value, "1"));
+ });
+ return s_enabled;
+}
+
+bool webKitDMABufVideoSinkProbePlatform()
+{
+ return isGStreamerPluginAvailable("app");
+}
+
void webKitDMABufVideoSinkSetMediaPlayerPrivate(WebKitDMABufVideoSink* sink, MediaPlayerPrivateGStreamer* player)
{
WebKitDMABufVideoSinkPrivate* priv = sink->priv;
@@ -168,9 +185,4 @@
webKitVideoSinkSetMediaPlayerPrivate(priv->appSink.get(), priv->mediaPlayerPrivate);
}
-bool webKitDMABufVideoSinkProbePlatform()
-{
- return isGStreamerPluginAvailable("app");
-}
-
#endif // ENABLE(VIDEO)
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.h (291342 => 291343)
--- trunk/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.h 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/DMABufVideoSinkGStreamer.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -50,6 +50,7 @@
GType webkit_dmabuf_video_sink_get_type(void);
+bool webKitDMABufVideoSinkIsEnabled();
bool webKitDMABufVideoSinkProbePlatform();
void webKitDMABufVideoSinkSetMediaPlayerPrivate(WebKitDMABufVideoSink*, WebCore::MediaPlayerPrivateGStreamer*);
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (291342 => 291343)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2022-03-16 13:12:30 UTC (rev 291343)
@@ -92,6 +92,7 @@
#include <wtf/text/AtomString.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringConcatenateNumbers.h>
+#include <wtf/UniStdExtras.h>
#include <wtf/URL.h>
#include <wtf/WallTime.h>
@@ -117,6 +118,17 @@
#include "TextureMapperPlatformLayerProxyGL.h"
#endif // USE(TEXTURE_MAPPER_GL)
+#if USE(TEXTURE_MAPPER_DMABUF)
+#include "DMABufFormat.h"
+#include "DMABufObject.h"
+#include "DMABufVideoSinkGStreamer.h"
+#include "GBMBufferSwapchain.h"
+#include "GBMDevice.h"
+#include "TextureMapperPlatformLayerProxyDMABuf.h"
+#include <gbm.h>
+#include <gst/allocators/gstdmabuf.h>
+#endif // USE(TEXTURE_MAPPER_DMABUF)
+
#if USE(WPE_VIDEO_PLANE_DISPLAY_DMABUF)
#include "PlatformDisplayLibWPE.h"
#include <gst/gl/egl/gsteglimage.h>
@@ -155,17 +167,16 @@
, m_maxTimeLoadedAtLastDidLoadingProgress(MediaTime::zeroTime())
, m_drawTimer(RunLoop::main(), this, &MediaPlayerPrivateGStreamer::repaint)
, m_readyTimerHandler(RunLoop::main(), this, &MediaPlayerPrivateGStreamer::readyTimerFired)
-#if USE(TEXTURE_MAPPER_GL)
-#if USE(NICOSIA)
- , m_nicosiaLayer(Nicosia::ContentLayer::create(Nicosia::ContentLayerTextureMapperImpl::createFactory(*this)))
-#else
+#if USE(TEXTURE_MAPPER_GL) && !USE(NICOSIA)
, m_platformLayerProxy(adoptRef(new TextureMapperPlatformLayerProxyGL))
#endif
-#endif
#if !RELEASE_LOG_DISABLED
, m_logger(player->mediaPlayerLogger())
, m_logIdentifier(player->mediaPlayerLogIdentifier())
#endif
+#if USE(TEXTURE_MAPPER_DMABUF)
+ , m_swapchain(adoptRef(new GBMBufferSwapchain(GBMBufferSwapchain::BufferSwapchainSize::Eight)))
+#endif
{
#if USE(GLIB)
m_readyTimerHandler.setPriority(G_PRIORITY_DEFAULT_IDLE);
@@ -172,6 +183,17 @@
#endif
m_isPlayerShuttingDown.store(false);
+#if USE(TEXTURE_MAPPER_GL) && USE(NICOSIA)
+ m_nicosiaLayer = Nicosia::ContentLayer::create(Nicosia::ContentLayerTextureMapperImpl::createFactory(*this,
+ [&]() -> Ref<TextureMapperPlatformLayerProxy> {
+#if USE(TEXTURE_MAPPER_DMABUF)
+ if (webKitDMABufVideoSinkIsEnabled() && webKitDMABufVideoSinkProbePlatform())
+ return adoptRef(*new TextureMapperPlatformLayerProxyDMABuf);
+#endif
+ return adoptRef(*new TextureMapperPlatformLayerProxyGL);
+ }()));
+#endif
+
ensureGStreamerInitialized();
m_audioSink = createAudioSink();
@@ -2871,7 +2893,7 @@
PlatformLayer* MediaPlayerPrivateGStreamer::platformLayer() const
{
#if USE(NICOSIA)
- return m_nicosiaLayer.ptr();
+ return m_nicosiaLayer.get();
#else
return const_cast<MediaPlayerPrivateGStreamer*>(this);
#endif
@@ -2985,6 +3007,233 @@
}
#endif // USE(TEXTURE_MAPPER_GL)
+#if USE(TEXTURE_MAPPER_DMABUF)
+// GStreamer's gst_video_format_to_fourcc() doesn't cover RGB-like formats, so we
+// provide the appropriate FourCC values for those through this funcion.
+static uint32_t fourccValue(GstVideoFormat format)
+{
+ switch (format) {
+ case GST_VIDEO_FORMAT_RGBx:
+ return uint32_t(DMABufFormat::FourCC::XBGR8888);
+ case GST_VIDEO_FORMAT_BGRx:
+ return uint32_t(DMABufFormat::FourCC::XRGB8888);
+ case GST_VIDEO_FORMAT_xRGB:
+ return uint32_t(DMABufFormat::FourCC::BGRX8888);
+ case GST_VIDEO_FORMAT_xBGR:
+ return uint32_t(DMABufFormat::FourCC::RGBX8888);
+ case GST_VIDEO_FORMAT_RGBA:
+ return uint32_t(DMABufFormat::FourCC::ABGR8888);
+ case GST_VIDEO_FORMAT_BGRA:
+ return uint32_t(DMABufFormat::FourCC::ARGB8888);
+ case GST_VIDEO_FORMAT_ARGB:
+ return uint32_t(DMABufFormat::FourCC::BGRA8888);
+ case GST_VIDEO_FORMAT_ABGR:
+ return uint32_t(DMABufFormat::FourCC::RGBA8888);
+ default:
+ break;
+ }
+
+ return gst_video_format_to_fourcc(format);
+}
+
+void MediaPlayerPrivateGStreamer::pushDMABufToCompositor()
+{
+ Locker sampleLocker { m_sampleMutex };
+ if (!GST_IS_SAMPLE(m_sample.get()))
+ return;
+
+ auto* caps = gst_sample_get_caps(m_sample.get());
+ if (!caps)
+ return;
+
+ GstVideoInfo videoInfo;
+ gst_video_info_init(&videoInfo);
+ if (!gst_video_info_from_caps(&videoInfo, caps))
+ return;
+
+ auto* buffer = gst_sample_get_buffer(m_sample.get());
+ if (!buffer)
+ return;
+
+ auto* meta = gst_buffer_get_video_meta(buffer);
+ if (meta) {
+ GST_VIDEO_INFO_WIDTH(&videoInfo) = meta->width;
+ GST_VIDEO_INFO_HEIGHT(&videoInfo) = meta->height;
+
+ for (unsigned i = 0; i < meta->n_planes; ++i) {
+ GST_VIDEO_INFO_PLANE_OFFSET(&videoInfo, i) = meta->offset[i];
+ GST_VIDEO_INFO_PLANE_STRIDE(&videoInfo, i) = meta->stride[i];
+ }
+ }
+
+ auto& proxy = downcast<Nicosia::ContentLayerTextureMapperImpl>(m_nicosiaLayer->impl()).proxy();
+ ASSERT(is<TextureMapperPlatformLayerProxyDMABuf>(proxy));
+
+ auto* features = gst_caps_get_features(caps, 0);
+ if (gst_caps_features_contains(features, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
+ // In case of a hardware decoder that's yielding dmabuf memory, we can take the relevant data and
+ // push it into the composition process.
+
+ ++m_sampleCount;
+ Locker locker { proxy.lock() };
+ if (!proxy.isActive())
+ return;
+
+ // Provide the DMABufObject with a relevant handle (memory address). When provided for the first time,
+ // the lambda will be invoked and all dmabuf data is filled in.
+ downcast<TextureMapperPlatformLayerProxyDMABuf>(proxy).pushDMABuf(
+ DMABufObject(reinterpret_cast<uintptr_t>(gst_buffer_peek_memory(buffer, 0))),
+ [&](auto&& object) {
+ object.format = DMABufFormat::create(fourccValue(GST_VIDEO_INFO_FORMAT(&videoInfo)));
+ object.width = GST_VIDEO_INFO_WIDTH(&videoInfo);
+ object.height = GST_VIDEO_INFO_HEIGHT(&videoInfo);
+
+ // TODO: release mechanism for a decoder-provided dmabuf is a bit tricky. The dmabuf object
+ // itself doesn't provide anything useful, but the decoder won't reuse the dmabuf until the
+ // relevant GstSample reference is dropped by the downstream pipeline. So for this to work,
+ // there's a need to somehow associate the GstSample reference with this release flag so that
+ // the reference is dropped once the release flag is signalled. There's ways to achieve that,
+ // but left for later.
+ object.releaseFlag = DMABufReleaseFlag { };
+
+ // For each plane, the relevant data (stride, offset, skip, dmabuf fd) is retrieved and assigned
+ // as appropriate. Modifier values are zeroed out for now, since GStreamer doesn't yet provide
+ // the information.
+ for (unsigned i = 0; i < object.format.numPlanes; ++i) {
+ gsize offset = GST_VIDEO_INFO_PLANE_OFFSET(&videoInfo, i);
+ guint memid = 0;
+ guint length = 0;
+ gsize skip = 0;
+ if (gst_buffer_find_memory(buffer, offset, 1, &memid, &length, &skip)) {
+ auto* mem = gst_buffer_peek_memory(buffer, memid);
+ object.fd[i] = dupCloseOnExec(gst_dmabuf_memory_get_fd(mem));
+ offset = mem->offset + skip;
+ } else
+ object.fd[i] = -1;
+
+ gint comp[GST_VIDEO_MAX_COMPONENTS];
+ gst_video_format_info_component(videoInfo.finfo, i, comp);
+ object.offset[i] = offset;
+ object.stride[i] = GST_VIDEO_INFO_PLANE_STRIDE(&videoInfo, i);
+ object.modifier[i] = 0;
+ }
+ return object;
+ });
+ return;
+ }
+
+ // If the decoder is exporting raw memory, we have to use the swapchain to allocate appropriate buffers
+ // and copy over the data for each plane.
+ GBMBufferSwapchain::BufferDescription bufferDescription {
+ DMABufFormat::create(fourccValue(GST_VIDEO_INFO_FORMAT(&videoInfo))),
+ GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo),
+ };
+ if (bufferDescription.format.fourcc == DMABufFormat::FourCC::Invalid)
+ return;
+
+ auto swapchainBuffer = m_swapchain->getBuffer(bufferDescription);
+
+ // Source helper struct, maps the raw memory and exposes the mapped data for copying.
+ struct Source {
+ Source(GstMemory* memory, gsize offset, uint32_t stride, uint32_t height)
+ : memory(memory)
+ , stride(stride)
+ , height(height)
+ {
+ if (!gst_memory_map(memory, &mapInfo, GST_MAP_READ))
+ return;
+
+ valid = true;
+ data = ""
+ }
+
+ ~Source()
+ {
+ if (valid)
+ gst_memory_unmap(memory, &mapInfo);
+ }
+
+ bool valid { false };
+ GstMemory* memory { nullptr };
+ GstMapInfo mapInfo;
+ uint8_t* data { nullptr };
+ uint32_t stride { 0 };
+ uint32_t height { 0 };
+ };
+
+ // Destination helper struct, maps the gbm_bo object into CPU-memory space and copies from the accompanying Source in fill().
+ struct Destination {
+ Destination(struct gbm_bo* bo, uint32_t width, uint32_t height)
+ : bo(bo)
+ {
+ map = gbm_bo_map(bo, 0, 0, width, height, GBM_BO_TRANSFER_WRITE, &stride, &mapData);
+ if (!map)
+ return;
+
+ valid = true;
+ data = ""
+ }
+
+ ~Destination()
+ {
+ if (valid)
+ gbm_bo_unmap(bo, mapData);
+ }
+
+ void fill(const Source& source)
+ {
+ for (uint32_t y = 0; y < source.height; ++y) {
+ auto* sourceData = &source.data[y * source.stride];
+ auto* destinationData = &data[y * stride];
+ memcpy(destinationData, sourceData, std::min(source.stride, stride));
+ }
+ }
+
+ bool valid { false };
+ struct gbm_bo* bo { nullptr };
+ void* map { nullptr };
+ void* mapData { nullptr };
+ uint8_t* data { nullptr };
+ uint32_t stride { 0 };
+ };
+
+ for (unsigned i = 0; i < GST_VIDEO_INFO_N_PLANES(&videoInfo); ++i) {
+ gint comp[GST_VIDEO_MAX_COMPONENTS];
+ gst_video_format_info_component(videoInfo.finfo, i, comp);
+
+ auto& planeData = swapchainBuffer->planeData(i);
+ gsize offset = GST_VIDEO_INFO_PLANE_OFFSET(&videoInfo, i);
+ guint stride = GST_VIDEO_INFO_PLANE_STRIDE(&videoInfo, i);
+
+ guint memid, length;
+ gsize skip;
+ if (gst_buffer_find_memory(buffer, offset, 1, &memid, &length, &skip)) {
+ auto* mem = gst_buffer_peek_memory(buffer, memid);
+
+ Source source(mem, offset, stride, planeData.height);
+ Destination destination(planeData.bo, planeData.width, planeData.height);
+
+ if (source.valid && destination.valid)
+ destination.fill(source);
+ }
+ }
+
+ ++m_sampleCount;
+ Locker locker { proxy.lock() };
+ if (!proxy.isActive())
+ return;
+
+ // The updated buffer is pushed into the composition stage. The DMABufObject handle uses the swapchain address as the handle base.
+ // When the buffer is pushed for the first time, the lambda will be invoked to retrieve a more complete DMABufObject for the
+ // given GBMBufferSwapchain::Buffer object.
+ downcast<TextureMapperPlatformLayerProxyDMABuf>(proxy).pushDMABuf(
+ DMABufObject(reinterpret_cast<uintptr_t>(m_swapchain.get()) + swapchainBuffer->handle()),
+ [&](auto&& object) {
+ return swapchainBuffer->createDMABufObject(object.handle);
+ });
+}
+#endif // USE(TEXTURE_MAPPER_DMABUF)
+
void MediaPlayerPrivateGStreamer::repaint()
{
ASSERT(m_sample);
@@ -3189,8 +3438,16 @@
#endif
m_drawTimer.startOneShot(0_s);
m_drawCondition.wait(m_drawLock);
- } else
+ } else {
+#if USE(NICOSIA) && USE(TEXTURE_MAPPER_DMABUF)
+ if (is<TextureMapperPlatformLayerProxyDMABuf>(downcast<Nicosia::ContentLayerTextureMapperImpl>(m_nicosiaLayer->impl()).proxy())) {
+ pushDMABufToCompositor();
+ return;
+ }
+#endif
+
pushTextureToCompositor();
+ }
#endif // USE(TEXTURE_MAPPER_GL)
}
@@ -3430,6 +3687,23 @@
return MediaPlayer::MovieLoadType::Download;
}
+#if USE(TEXTURE_MAPPER_DMABUF)
+GstElement* MediaPlayerPrivateGStreamer::createVideoSinkDMABuf()
+{
+ if (!webKitDMABufVideoSinkIsEnabled())
+ return nullptr;
+ if (!webKitDMABufVideoSinkProbePlatform()) {
+ g_warning("WebKit wasn't able to find the DMABuf video sink dependencies. Hardware-accelerated zero-copy video rendering won't be achievable with this plugin.");
+ return nullptr;
+ }
+
+ GstElement* sink = gst_element_factory_make("webkitdmabufvideosink", nullptr);
+ ASSERT(sink);
+ webKitDMABufVideoSinkSetMediaPlayerPrivate(WEBKIT_DMABUF_VIDEO_SINK(sink), this);
+ return sink;
+}
+#endif
+
#if USE(GSTREAMER_GL)
GstElement* MediaPlayerPrivateGStreamer::createVideoSinkGL()
{
@@ -3521,8 +3795,12 @@
return m_videoSink.get();
#endif
+#if USE(TEXTURE_MAPPER_DMABUF)
+ if (!m_videoSink && m_canRenderingBeAccelerated)
+ m_videoSink = createVideoSinkDMABuf();
+#endif
#if USE(GSTREAMER_GL)
- if (m_canRenderingBeAccelerated)
+ if (!m_videoSink && m_canRenderingBeAccelerated)
m_videoSink = createVideoSinkGL();
#endif
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h (291342 => 291343)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -105,6 +105,10 @@
class MediaPlayerRequestInstallMissingPluginsCallback;
class VideoTrackPrivateGStreamer;
+#if USE(TEXTURE_MAPPER_DMABUF)
+class GBMBufferSwapchain;
+#endif
+
void registerWebKitGStreamerElements();
// Use eager initialization for the WeakPtrFactory since we construct WeakPtrs on another thread.
@@ -267,6 +271,9 @@
bool shouldIgnoreIntrinsicSize() final { return true; }
#endif
+#if USE(TEXTURE_MAPPER_DMABUF)
+ GstElement* createVideoSinkDMABuf();
+#endif
#if USE(GSTREAMER_GL)
GstElement* createVideoSinkGL();
#endif
@@ -281,6 +288,10 @@
#endif
#endif
+#if USE(TEXTURE_MAPPER_DMABUF)
+ void pushDMABufToCompositor();
+#endif
+
GstElement* videoSink() const { return m_videoSink.get(); }
void setStreamVolumeElement(GstStreamVolume*);
@@ -510,7 +521,7 @@
RunLoop::Timer<MediaPlayerPrivateGStreamer> m_readyTimerHandler;
#if USE(TEXTURE_MAPPER_GL)
#if USE(NICOSIA)
- Ref<Nicosia::ContentLayer> m_nicosiaLayer;
+ RefPtr<Nicosia::ContentLayer> m_nicosiaLayer;
#else
RefPtr<TextureMapperPlatformLayerProxy> m_platformLayerProxy;
#endif
@@ -577,6 +588,10 @@
#endif
String m_errorMessage;
+
+#if USE(TEXTURE_MAPPER_DMABUF)
+ RefPtr<GBMBufferSwapchain> m_swapchain;
+#endif
};
}
Modified: trunk/Source/WebCore/platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.cpp (291342 => 291343)
--- trunk/Source/WebCore/platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.cpp 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.cpp 2022-03-16 13:12:30 UTC (rev 291343)
@@ -37,9 +37,14 @@
auto ContentLayerTextureMapperImpl::createFactory(Client& client) -> Factory
{
+ return createFactory(client, adoptRef(*new WebCore::TextureMapperPlatformLayerProxyGL));
+}
+
+auto ContentLayerTextureMapperImpl::createFactory(Client& client, Ref<WebCore::TextureMapperPlatformLayerProxy>&& proxy) -> Factory
+{
return Factory(
- [&client](ContentLayer&) {
- return makeUnique<ContentLayerTextureMapperImpl>(client, adoptRef(*new WebCore::TextureMapperPlatformLayerProxyGL));
+ [&client, proxy = WTFMove(proxy)](ContentLayer&) mutable {
+ return makeUnique<ContentLayerTextureMapperImpl>(client, WTFMove(proxy));
});
}
Modified: trunk/Source/WebCore/platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.h (291342 => 291343)
--- trunk/Source/WebCore/platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.h 2022-03-16 13:03:44 UTC (rev 291342)
+++ trunk/Source/WebCore/platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -50,6 +50,7 @@
};
static Factory createFactory(Client&);
+ static Factory createFactory(Client&, Ref<WebCore::TextureMapperPlatformLayerProxy>&&);
explicit ContentLayerTextureMapperImpl(Client&, Ref<WebCore::TextureMapperPlatformLayerProxy>&&);
virtual ~ContentLayerTextureMapperImpl();
Added: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.cpp (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.cpp 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextureMapperPlatformLayerProxyDMABuf.h"
+
+#if USE(COORDINATED_GRAPHICS) && USE(TEXTURE_MAPPER_DMABUF)
+
+#include "PlatformDisplay.h"
+#include "TextureMapperGL.h"
+#include "TextureMapperGLHeaders.h"
+#include "TextureMapperLayer.h"
+#include <fcntl.h>
+#include <initializer_list>
+#include <unistd.h>
+
+#if USE(LIBEPOXY)
+#include "EpoxyEGL.h"
+#else
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
+namespace WebCore {
+
+static PFNEGLCREATEIMAGEKHRPROC createImageKHR()
+{
+ static PFNEGLCREATEIMAGEKHRPROC s_createImageKHR;
+ static std::once_flag s_flag;
+ std::call_once(s_flag,
+ [&] {
+ s_createImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
+ });
+ return s_createImageKHR;
+}
+
+static PFNEGLDESTROYIMAGEKHRPROC destroyImageKHR()
+{
+ static PFNEGLDESTROYIMAGEKHRPROC s_destroyImageKHR;
+ static std::once_flag s_flag;
+ std::call_once(s_flag,
+ [&] {
+ s_destroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
+ });
+ return s_destroyImageKHR;
+}
+
+struct TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::EGLImageData {
+ WTF_MAKE_STRUCT_FAST_ALLOCATED;
+
+ ~EGLImageData()
+ {
+ if (numImages) {
+ glDeleteTextures(numImages, texture.data());
+
+ for (unsigned i = 0; i < numImages; ++i) {
+ if (image[i] != EGL_NO_IMAGE_KHR)
+ destroyImageKHR()(PlatformDisplay::sharedDisplayForCompositing().eglDisplay(), image[i]);
+ }
+ }
+ }
+
+ uint32_t width { 0 };
+ uint32_t height { 0 };
+ unsigned numImages { 0 };
+ std::array<GLuint, DMABufFormat::c_maxPlanes> texture { 0, 0, 0, 0 };
+ std::array<EGLImageKHR, DMABufFormat::c_maxPlanes> image { EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR, EGL_NO_IMAGE_KHR };
+};
+
+TextureMapperPlatformLayerProxyDMABuf::TextureMapperPlatformLayerProxyDMABuf() = default;
+TextureMapperPlatformLayerProxyDMABuf::~TextureMapperPlatformLayerProxyDMABuf() = default;
+
+void TextureMapperPlatformLayerProxyDMABuf::activateOnCompositingThread(Compositor* compositor, TextureMapperLayer* targetLayer)
+{
+#ifndef NDEBUG
+ if (!m_compositorThread)
+ m_compositorThread = &Thread::current();
+#endif
+ ASSERT(m_compositorThread == &Thread::current());
+ ASSERT(compositor);
+ ASSERT(targetLayer);
+
+ {
+ Locker locker { m_lock };
+ m_compositor = compositor;
+ m_targetLayer = targetLayer;
+ }
+}
+
+void TextureMapperPlatformLayerProxyDMABuf::invalidate()
+{
+ ASSERT(m_compositorThread == &Thread::current());
+#ifndef NDEBUG
+ m_compositorThread = nullptr;
+#endif
+
+ Locker locker { m_lock };
+
+ m_pendingLayer = nullptr;
+ m_committedLayer = nullptr;
+ m_layers = { };
+
+ m_compositor = nullptr;
+ m_targetLayer = nullptr;
+}
+
+void TextureMapperPlatformLayerProxyDMABuf::swapBuffer()
+{
+ Locker locker { m_lock };
+ if (!m_targetLayer || !m_pendingLayer)
+ return;
+
+ auto previousLayer = WTFMove(m_committedLayer);
+ m_committedLayer = WTFMove(m_pendingLayer);
+ m_targetLayer->setContentsLayer(m_committedLayer.get());
+
+ // The previous and just-committed layers shouldn't be the same. But if they are, don't perform a release.
+ ASSERT(!previousLayer || previousLayer != m_committedLayer);
+ if (previousLayer && previousLayer != m_committedLayer)
+ previousLayer->release();
+
+ if (!m_committedLayer->m_imageData)
+ m_committedLayer->m_imageData = DMABufLayer::createEGLImageData(m_committedLayer->m_object);
+ m_committedLayer->m_age = 0;
+
+ // Remove any stale layers, e.g. if a layer has gone unused for >c_maximumAge swaps or doesn't match the latest size.
+ auto& committedObject = m_committedLayer->m_object;
+ auto isStaleLayer =
+ [&](auto& it)
+ {
+ auto& layer = it.value.get();
+ return layer.m_age > DMABufLayer::c_maximumAge
+ || !(layer.m_object.width == committedObject.width && layer.m_object.height == committedObject.height);
+ };
+
+ bool hasStaleLayers = false;
+ for (auto it = m_layers.begin(); it != m_layers.end(); ++it) {
+ ++it->value->m_age;
+ hasStaleLayers |= isStaleLayer(*it);
+ }
+
+ if (hasStaleLayers)
+ m_layers.removeIf(isStaleLayer);
+}
+
+void TextureMapperPlatformLayerProxyDMABuf::pushDMABuf(Ref<DMABufLayer>&& dmabufLayer)
+{
+ ASSERT(m_lock.isHeld());
+
+ // The pending and just-pushed layers shouldn't be the same. But if they are, don't perform a release.
+ ASSERT(!m_pendingLayer || m_pendingLayer != dmabufLayer.ptr());
+ if (m_pendingLayer && m_pendingLayer != dmabufLayer.ptr())
+ m_pendingLayer->release();
+
+ m_pendingLayer = WTFMove(dmabufLayer);
+ if (m_compositor)
+ m_compositor->onNewBufferAvailable();
+}
+
+TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::DMABufLayer(DMABufObject&& object, TextureMapperGL::Flags flags)
+ : m_object(WTFMove(object))
+ , m_flags(flags)
+{ }
+
+TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::~DMABufLayer() = default;
+
+void TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity)
+{
+ if (!m_imageData)
+ return;
+
+ // TODO: this is the BT.601 colorspace conversion matrix. The exact desired colorspace should be included
+ // in the DMABufObject, and the relevant matrix decided based on it. BT.601 should remain the default.
+ static constexpr std::array<GLfloat, 9> s_yuvToRGB {
+ 1.164f, 0.0f, 1.596f,
+ 1.164f, -0.391f, -0.813f,
+ 1.164f, 2.018f, 0.0f
+ };
+
+ TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper);
+ auto& data = ""
+
+ switch (m_object.format.fourcc) {
+ case DMABufFormat::FourCC::XRGB8888:
+ case DMABufFormat::FourCC::XBGR8888:
+ case DMABufFormat::FourCC::ARGB8888:
+ case DMABufFormat::FourCC::ABGR8888:
+ texmapGL.drawTexture(data.texture[0], m_flags, IntSize(data.width, data.height), targetRect, modelViewMatrix, opacity);
+ break;
+ case DMABufFormat::FourCC::I420:
+ case DMABufFormat::FourCC::Y444:
+ case DMABufFormat::FourCC::Y41B:
+ case DMABufFormat::FourCC::Y42B:
+ texmapGL.drawTexturePlanarYUV(std::array<GLuint, 3> { data.texture[0], data.texture[1], data.texture[2] },
+ s_yuvToRGB, m_flags, IntSize(data.width, data.height), targetRect, modelViewMatrix, opacity, std::nullopt);
+ break;
+ case DMABufFormat::FourCC::YV12:
+ texmapGL.drawTexturePlanarYUV(std::array<GLuint, 3> { data.texture[0], data.texture[2], data.texture[1] },
+ s_yuvToRGB, m_flags, IntSize(data.width, data.height), targetRect, modelViewMatrix, opacity, std::nullopt);
+ break;
+ case DMABufFormat::FourCC::A420:
+ texmapGL.drawTexturePlanarYUV(std::array<GLuint, 3> { data.texture[0], data.texture[1], data.texture[2] },
+ s_yuvToRGB, m_flags, IntSize(data.width, data.height), targetRect, modelViewMatrix, opacity, data.texture[3]);
+ break;
+ case DMABufFormat::FourCC::NV12:
+ case DMABufFormat::FourCC::NV21:
+ texmapGL.drawTextureSemiPlanarYUV(std::array<GLuint, 2> { data.texture[0], data.texture[1] },
+ (m_object.format.fourcc == DMABufFormat::FourCC::NV21),
+ s_yuvToRGB, m_flags, IntSize(data.width, data.height), targetRect, modelViewMatrix, opacity);
+ break;
+ case DMABufFormat::FourCC::YUY2:
+ case DMABufFormat::FourCC::UYVY:
+ case DMABufFormat::FourCC::VUYA:
+ case DMABufFormat::FourCC::YVYU:
+ texmapGL.drawTexturePackedYUV(data.texture[0],
+ s_yuvToRGB, m_flags, IntSize(data.width, data.height), targetRect, modelViewMatrix, opacity);
+ break;
+ default:
+ break;
+ }
+}
+
+std::unique_ptr<TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::EGLImageData> TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::createEGLImageData(DMABufObject& object)
+{
+ using EGLImageData = TextureMapperPlatformLayerProxyDMABuf::DMABufLayer::EGLImageData;
+
+ EGLDisplay eglDisplay = PlatformDisplay::sharedDisplayForCompositing().eglDisplay();
+
+ EGLImageKHR image[DMABufFormat::c_maxPlanes];
+ for (unsigned i = 0; i < object.format.numPlanes; ++i) {
+ std::initializer_list<EGLint> attributes {
+ EGL_WIDTH, EGLint(object.format.planeWidth(i, object.width)),
+ EGL_HEIGHT, EGLint(object.format.planeHeight(i, object.height)),
+ EGL_LINUX_DRM_FOURCC_EXT, EGLint(object.format.planes[i].fourcc),
+ EGL_DMA_BUF_PLANE0_FD_EXT, object.fd[i],
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(object.offset[i]),
+ EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(object.stride[i]),
+ EGL_NONE,
+ };
+ image[i] = createImageKHR()(eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, std::data(attributes));
+ }
+
+ auto imageData = makeUnique<EGLImageData>();
+ auto& data = ""
+ data.width = object.width;
+ data.height = object.height;
+ data.numImages = object.format.numPlanes;
+ glGenTextures(data.numImages, data.texture.data());
+ for (unsigned i = 0; i < data.numImages; ++i) {
+ data.image[i] = image[i];
+
+ glBindTexture(GL_TEXTURE_2D, data.texture[i]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, data.image[i]);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ return imageData;
+}
+
+} // namespace WebCore
+
+#endif // USE(COORDINATED_GRAPHICS) && USE(TEXTURE_MAPPER_DMABUF)
Added: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.h (0 => 291343)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxyDMABuf.h 2022-03-16 13:12:30 UTC (rev 291343)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 Metrological Group B.V.
+ * Copyright (C) 2022 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "TextureMapperPlatformLayerProxy.h"
+
+#if USE(COORDINATED_GRAPHICS) && USE(TEXTURE_MAPPER_DMABUF)
+
+#include "DMABufFormat.h"
+#include "DMABufObject.h"
+#include "TextureMapperGL.h"
+#include "TextureMapperPlatformLayer.h"
+#include <cstdint>
+#include <memory>
+
+namespace WebCore {
+
+class TextureMapperPlatformLayerProxyDMABuf final : public TextureMapperPlatformLayerProxy {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ TextureMapperPlatformLayerProxyDMABuf();
+ virtual ~TextureMapperPlatformLayerProxyDMABuf();
+
+ bool isDMABufBased() const override { return true; }
+
+ WEBCORE_EXPORT void activateOnCompositingThread(Compositor*, TextureMapperLayer*) override;
+ WEBCORE_EXPORT void invalidate() override;
+ WEBCORE_EXPORT void swapBuffer() override;
+
+ class DMABufLayer : public ThreadSafeRefCounted<DMABufLayer>, public TextureMapperPlatformLayer {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ DMABufLayer(DMABufObject&&, TextureMapperGL::Flags = 0);
+ virtual ~DMABufLayer();
+
+ void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix& modelViewMatrix = { }, float opacity = 1.0) final;
+
+ void release()
+ {
+ m_object.releaseFlag.release();
+ }
+
+ private:
+ friend class TextureMapperPlatformLayerProxyDMABuf;
+
+ struct EGLImageData;
+ static std::unique_ptr<EGLImageData> createEGLImageData(DMABufObject&);
+
+ DMABufObject m_object;
+ std::unique_ptr<EGLImageData> m_imageData;
+ TextureMapperGL::Flags m_flags;
+
+ static constexpr unsigned c_maximumAge { 16 };
+ unsigned m_age { 0 };
+ };
+
+ template<typename F>
+ void pushDMABuf(DMABufObject&& dmabufObject, const F& constructor, TextureMapperGL::Flags flags = 0)
+ {
+ ASSERT(m_lock.isHeld());
+
+ auto result = m_layers.ensure(dmabufObject.handle,
+ [&] {
+ return adoptRef(*new DMABufLayer(constructor(WTFMove(dmabufObject)), flags));
+ });
+ pushDMABuf(result.iterator->value.copyRef());
+ }
+
+private:
+ void pushDMABuf(Ref<DMABufLayer>&&);
+
+#ifndef NDEBUG
+ RefPtr<Thread> m_compositorThread;
+#endif
+
+ using LayerMap = HashMap<uintptr_t, Ref<DMABufLayer>, WTF::DefaultHash<uintptr_t>, WTF::UnsignedWithZeroKeyHashTraits<uintptr_t>>;
+ LayerMap m_layers;
+
+ RefPtr<DMABufLayer> m_pendingLayer;
+ RefPtr<DMABufLayer> m_committedLayer;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_TEXTUREMAPPER_PLATFORMLAYERPROXY(TextureMapperPlatformLayerProxyDMABuf, isDMABufBased());
+
+#endif // USE(COORDINATED_GRAPHICS) && USE(TEXTURE_MAPPER_DMABUF)