1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "SharedSurfaceDMABUF.h"
8 #include "gfxPlatform.h"
9 #include "GLContextEGL.h"
10 #include "MozFramebuffer.h"
11 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
12 #include "mozilla/gfx/gfxVars.h"
13 #include "mozilla/widget/DMABufLibWrapper.h"
15 namespace mozilla::gl
{
17 static bool HasDmaBufExtensions(const GLContextEGL
* gl
) {
18 const auto& egl
= *(gl
->mEgl
);
19 return egl
.IsExtensionSupported(EGLExtension::EXT_image_dma_buf_import
) &&
20 egl
.IsExtensionSupported(
21 EGLExtension::EXT_image_dma_buf_import_modifiers
) &&
22 egl
.IsExtensionSupported(EGLExtension::MESA_image_dma_buf_export
);
26 UniquePtr
<SharedSurface_DMABUF
> SharedSurface_DMABUF::Create(
27 const SharedSurfaceDesc
& desc
) {
28 const auto& gle
= GLContextEGL::Cast(desc
.gl
);
29 const auto& context
= gle
->mContext
;
30 const auto& egl
= *(gle
->mEgl
);
32 RefPtr
<DMABufSurface
> surface
;
33 UniquePtr
<MozFramebuffer
> fb
;
35 if (!HasDmaBufExtensions(gle
) || !gfx::gfxVars::UseDMABufSurfaceExport()) {
36 // Using MESA_image_dma_buf_export is not supported or it's broken.
37 // Create dmabuf surface directly via GBM and create
38 // EGLImage/framebuffer over it.
39 const auto flags
= static_cast<DMABufSurfaceFlags
>(
40 DMABUF_TEXTURE
| DMABUF_USE_MODIFIERS
| DMABUF_ALPHA
);
41 surface
= DMABufSurfaceRGBA::CreateDMABufSurface(desc
.size
.width
,
42 desc
.size
.height
, flags
);
43 if (!surface
|| !surface
->CreateTexture(desc
.gl
)) {
46 const auto tex
= surface
->GetTexture();
47 fb
= MozFramebuffer::CreateForBacking(desc
.gl
, desc
.size
, 0, false,
48 LOCAL_GL_TEXTURE_2D
, tex
);
49 if (!fb
) return nullptr;
51 // Use MESA_image_dma_buf_export to create EGLImage/framebuffer directly
52 // and derive dmabuf from it.
53 fb
= MozFramebuffer::Create(desc
.gl
, desc
.size
, 0, false);
54 if (!fb
) return nullptr;
56 const auto buffer
= reinterpret_cast<EGLClientBuffer
>(fb
->ColorTex());
58 egl
.fCreateImage(context
, LOCAL_EGL_GL_TEXTURE_2D
, buffer
, nullptr);
59 if (!image
) return nullptr;
61 surface
= DMABufSurfaceRGBA::CreateDMABufSurface(
62 desc
.gl
, image
, desc
.size
.width
, desc
.size
.height
);
63 if (!surface
) return nullptr;
65 return AsUnique(new SharedSurface_DMABUF(desc
, std::move(fb
), surface
));
68 SharedSurface_DMABUF::SharedSurface_DMABUF(const SharedSurfaceDesc
& desc
,
69 UniquePtr
<MozFramebuffer
> fb
,
70 const RefPtr
<DMABufSurface
> surface
)
71 : SharedSurface(desc
, std::move(fb
)), mSurface(surface
) {}
73 SharedSurface_DMABUF::~SharedSurface_DMABUF() {
74 const auto& gl
= mDesc
.gl
;
75 if (!gl
|| !gl
->MakeCurrent()) {
78 mSurface
->ReleaseTextures();
81 void SharedSurface_DMABUF::ProducerReleaseImpl() { mSurface
->FenceSet(); }
83 void SharedSurface_DMABUF::WaitForBufferOwnership() { mSurface
->FenceWait(); }
85 Maybe
<layers::SurfaceDescriptor
> SharedSurface_DMABUF::ToSurfaceDescriptor() {
86 layers::SurfaceDescriptor desc
;
87 if (!mSurface
->Serialize(desc
)) return {};
92 UniquePtr
<SurfaceFactory_DMABUF
> SurfaceFactory_DMABUF::Create(GLContext
& gl
) {
93 if (!widget::DMABufDevice::IsDMABufWebGLEnabled()) {
97 auto dmabufFactory
= MakeUnique
<SurfaceFactory_DMABUF
>(gl
);
98 if (dmabufFactory
->CanCreateSurface(gl
)) {
103 ("SurfaceFactory_DMABUF::Create() failed, fallback to SW buffers.\n"));
104 widget::DMABufDevice::DisableDMABufWebGL();
108 bool SurfaceFactory_DMABUF::CanCreateSurface(GLContext
& gl
) {
109 UniquePtr
<SharedSurface
> test
=
110 CreateShared(gfx::IntSize(1, 1), gfx::ColorSpace2::SRGB
);
113 "SurfaceFactory_DMABUF::CanCreateSurface() failed to create surface."));
116 auto desc
= test
->ToSurfaceDescriptor();
119 ("SurfaceFactory_DMABUF::CanCreateSurface() failed to serialize "
123 RefPtr
<DMABufSurface
> importedSurface
=
124 DMABufSurface::CreateDMABufSurface(*desc
);
125 if (!importedSurface
) {
127 "SurfaceFactory_DMABUF::CanCreateSurface() failed to import surface."));
130 if (!importedSurface
->CreateTexture(&gl
)) {
132 ("SurfaceFactory_DMABUF::CanCreateSurface() failed to create texture "
139 SurfaceFactory_DMABUF::SurfaceFactory_DMABUF(GLContext
& gl
)
140 : SurfaceFactory({&gl
, SharedSurfaceType::EGLSurfaceDMABUF
,
141 layers::TextureType::DMABUF
, true}) {}
142 } // namespace mozilla::gl