Title: [291343] trunk/Source/WebCore
Revision
291343
Author
commit-qu...@webkit.org
Date
2022-03-16 06:12:30 -0700 (Wed, 16 Mar 2022)

Log Message

[GTK][WPE] Provide DMABuf-based composition layers, DMABufVideoSink integration
https://bugs.webkit.org/show_bug.cgi?id=237328
<rdar://problem/90295492>

Patch by Zan Dobersek <zdober...@igalia.com> on 2022-03-16
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.

Modified Paths

Added Paths

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)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to