1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DMABufSurface.h"
8 #include "DMABufLibWrapper.h"
9 #include "DMABufFormats.h"
12 # include "nsWaylandDisplay.h"
28 # include <sys/eventfd.h>
31 #ifdef HAVE_SYSIOCCOM_H
32 # include <sys/ioccom.h>
34 #include <sys/ioctl.h>
36 #include "mozilla/widget/gbm.h"
37 #include "mozilla/widget/va_drmcommon.h"
38 #include "YCbCrUtils.h"
39 #include "mozilla/gfx/2D.h"
40 #include "mozilla/gfx/FileHandleWrapper.h"
41 #include "GLContextTypes.h" // for GLContext, etc
42 #include "GLContextEGL.h"
43 #include "GLContextProvider.h"
44 #include "ScopedGLHelpers.h"
45 #include "GLBlitHelper.h"
46 #include "GLReadTexImageHelper.h"
47 #include "nsGtkUtils.h"
49 #include "mozilla/layers/LayersSurfaces.h"
50 #include "mozilla/ScopeExit.h"
54 - DRM device selection:
55 https://lists.freedesktop.org/archives/wayland-devel/2018-November/039660.html
56 - Use uint64_t mBufferModifiers / mGbmBufferObject for RGBA
57 - Remove file descriptors open/close?
60 /* C++ / C typecast macros for special EGL handle values */
61 #if defined(__cplusplus)
62 # define EGL_CAST(type, value) (static_cast<type>(value))
64 # define EGL_CAST(type, value) ((type)(value))
67 using namespace mozilla
;
68 using namespace mozilla::widget
;
69 using namespace mozilla::gl
;
70 using namespace mozilla::layers
;
71 using namespace mozilla::gfx
;
74 # include "mozilla/Logging.h"
75 # include "nsTArray.h"
77 static LazyLogModule
gDmabufRefLog("DmabufRef");
78 # define LOGDMABUFREF(args) \
79 MOZ_LOG(gDmabufRefLog, mozilla::LogLevel::Debug, args)
81 # define LOGDMABUFREF(args)
82 #endif /* MOZ_LOGGING */
84 #define BUFFER_FLAGS 0
86 MOZ_RUNINIT
static RefPtr
<GLContext
> sSnapshotContext
;
87 static StaticMutex sSnapshotContextMutex MOZ_UNANNOTATED
;
88 static Atomic
<int> gNewSurfaceUID(1);
90 RefPtr
<GLContext
> ClaimSnapshotGLContext() {
91 if (!sSnapshotContext
) {
92 nsCString discardFailureId
;
93 sSnapshotContext
= GLContextProvider::CreateHeadless({}, &discardFailureId
);
94 if (!sSnapshotContext
) {
96 ("ClaimSnapshotGLContext: Failed to create snapshot GLContext."));
99 sSnapshotContext
->mOwningThreadId
= Nothing(); // No singular owner.
101 if (!sSnapshotContext
->MakeCurrent()) {
102 LOGDMABUF(("ClaimSnapshotGLContext: Failed to make GLContext current."));
105 return sSnapshotContext
;
108 void ReturnSnapshotGLContext(RefPtr
<GLContext
> aGLContext
) {
109 // direct eglMakeCurrent() call breaks current context caching so make sure
111 MOZ_ASSERT(!aGLContext
->mUseTLSIsCurrent
);
112 if (!aGLContext
->IsCurrent()) {
113 LOGDMABUF(("ReturnSnapshotGLContext() failed, is not current!"));
116 const auto& gle
= gl::GLContextEGL::Cast(aGLContext
);
117 const auto& egl
= gle
->mEgl
;
118 egl
->fMakeCurrent(EGL_NO_SURFACE
, EGL_NO_SURFACE
, EGL_NO_CONTEXT
);
121 bool DMABufSurface::IsGlobalRefSet() const {
122 if (!mGlobalRefCountFd
) {
126 pfd
.fd
= mGlobalRefCountFd
;
128 return poll(&pfd
, 1, 0) == 1;
131 void DMABufSurface::GlobalRefRelease() {
133 if (!mGlobalRefCountFd
) {
136 LOGDMABUFREF(("DMABufSurface::GlobalRefRelease UID %d", mUID
));
138 if (read(mGlobalRefCountFd
, &counter
, sizeof(counter
)) != sizeof(counter
)) {
139 if (errno
== EAGAIN
) {
141 (" GlobalRefRelease failed: already zero reference! UID %d", mUID
));
143 // EAGAIN means the refcount is already zero. It happens when we release
144 // last reference to the surface.
145 if (errno
!= EAGAIN
) {
146 NS_WARNING(nsPrintfCString("Failed to unref dmabuf global ref count: %s",
154 void DMABufSurface::GlobalRefAdd() {
156 LOGDMABUFREF(("DMABufSurface::GlobalRefAdd UID %d", mUID
));
157 MOZ_DIAGNOSTIC_ASSERT(mGlobalRefCountFd
);
158 uint64_t counter
= 1;
159 if (write(mGlobalRefCountFd
, &counter
, sizeof(counter
)) != sizeof(counter
)) {
160 NS_WARNING(nsPrintfCString("Failed to ref dmabuf global ref count: %s",
167 void DMABufSurface::GlobalRefCountCreate() {
169 LOGDMABUFREF(("DMABufSurface::GlobalRefCountCreate UID %d", mUID
));
170 MOZ_DIAGNOSTIC_ASSERT(!mGlobalRefCountFd
);
171 // Create global ref count initialized to 0,
172 // i.e. is not referenced after create.
173 mGlobalRefCountFd
= eventfd(0, EFD_CLOEXEC
| EFD_NONBLOCK
| EFD_SEMAPHORE
);
174 if (mGlobalRefCountFd
< 0) {
175 NS_WARNING(nsPrintfCString("Failed to create dmabuf global ref count: %s",
178 mGlobalRefCountFd
= 0;
184 void DMABufSurface::GlobalRefCountImport(int aFd
) {
186 mGlobalRefCountFd
= aFd
;
187 if (mGlobalRefCountFd
) {
188 LOGDMABUFREF(("DMABufSurface::GlobalRefCountImport UID %d", mUID
));
194 int DMABufSurface::GlobalRefCountExport() {
196 if (mGlobalRefCountFd
) {
197 LOGDMABUFREF(("DMABufSurface::GlobalRefCountExport UID %d", mUID
));
200 return mGlobalRefCountFd
;
203 void DMABufSurface::GlobalRefCountDelete() {
204 if (mGlobalRefCountFd
) {
205 LOGDMABUFREF(("DMABufSurface::GlobalRefCountDelete UID %d", mUID
));
206 close(mGlobalRefCountFd
);
207 mGlobalRefCountFd
= 0;
211 void DMABufSurface::ReleaseDMABuf() {
212 LOGDMABUF(("DMABufSurface::ReleaseDMABuf() UID %d", mUID
));
213 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
217 MutexAutoLock
lockFD(mSurfaceLock
);
218 CloseFileDescriptors(lockFD
, /* aForceClose */ true);
220 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
221 if (mGbmBufferObject
[i
]) {
222 GbmLib::Destroy(mGbmBufferObject
[i
]);
223 mGbmBufferObject
[i
] = nullptr;
226 mBufferPlaneCount
= 0;
229 DMABufSurface::DMABufSurface(SurfaceType aSurfaceType
)
230 : mSurfaceType(aSurfaceType
),
231 mBufferPlaneCount(0),
237 mMappedRegionStride(),
239 mGlobalRefCountFd(0),
240 mUID(gNewSurfaceUID
++),
241 mSurfaceLock("DMABufSurface") {
242 for (auto& modifier
: mBufferModifiers
) {
243 modifier
= DRM_FORMAT_MOD_INVALID
;
247 DMABufSurface::~DMABufSurface() {
250 GlobalRefCountDelete();
253 already_AddRefed
<DMABufSurface
> DMABufSurface::CreateDMABufSurface(
254 const mozilla::layers::SurfaceDescriptor
& aDesc
) {
255 const SurfaceDescriptorDMABuf
& desc
= aDesc
.get_SurfaceDescriptorDMABuf();
256 RefPtr
<DMABufSurface
> surf
;
258 switch (desc
.bufferType()) {
260 surf
= new DMABufSurfaceRGBA();
263 surf
= new DMABufSurfaceYUV();
269 if (!surf
->Create(desc
)) {
272 return surf
.forget();
275 void DMABufSurface::FenceDelete() {
283 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
284 const auto& egl
= gle
->mEgl
;
287 egl
->fDestroySync(mSync
);
292 void DMABufSurface::FenceSet() {
293 if (!mGL
|| !mGL
->MakeCurrent()) {
294 MOZ_DIAGNOSTIC_ASSERT(mGL
,
295 "DMABufSurface::FenceSet(): missing GL context!");
298 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
299 const auto& egl
= gle
->mEgl
;
301 if (egl
->IsExtensionSupported(EGLExtension::KHR_fence_sync
) &&
302 egl
->IsExtensionSupported(EGLExtension::ANDROID_native_fence_sync
)) {
305 mSync
= egl
->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID
, nullptr);
307 auto rawFd
= egl
->fDupNativeFenceFDANDROID(mSync
);
308 mSyncFd
= new gfx::FileHandleWrapper(UniqueFileHandle(rawFd
));
314 // ANDROID_native_fence_sync may not be supported so call glFinish()
319 void DMABufSurface::FenceWait() {
320 if (!mGL
|| !mSyncFd
) {
321 MOZ_DIAGNOSTIC_ASSERT(mGL
,
322 "DMABufSurface::FenceWait() missing GL context!");
326 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
327 const auto& egl
= gle
->mEgl
;
328 auto syncFd
= mSyncFd
->ClonePlatformHandle();
329 // No need to try mSyncFd twice.
332 const EGLint attribs
[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID
,
333 syncFd
.get(), LOCAL_EGL_NONE
};
334 EGLSync sync
= egl
->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID
, attribs
);
336 MOZ_ASSERT(false, "DMABufSurface::FenceWait(): Failed to create GLFence!");
340 // syncFd is owned by GLFence so clear local reference to avoid double.
341 Unused
<< syncFd
.release();
343 egl
->fClientWaitSync(sync
, 0, LOCAL_EGL_FOREVER
);
344 egl
->fDestroySync(sync
);
347 void DMABufSurface::MaybeSemaphoreWait(GLuint aGlTexture
) {
348 MOZ_ASSERT(aGlTexture
);
355 MOZ_DIAGNOSTIC_ASSERT(mGL
,
356 "DMABufSurface::SemaphoreWait() missing GL context!");
360 if (!mGL
->IsExtensionSupported(gl::GLContext::EXT_semaphore
) ||
361 !mGL
->IsExtensionSupported(gl::GLContext::EXT_semaphore_fd
)) {
362 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
363 gfxCriticalNoteOnce
<< "EXT_semaphore_fd is not suppored";
367 auto fd
= mSemaphoreFd
->ClonePlatformHandle();
368 // No need to try mSemaphoreFd twice.
369 mSemaphoreFd
= nullptr;
371 GLuint semaphoreHandle
= 0;
372 mGL
->fGenSemaphoresEXT(1, &semaphoreHandle
);
373 mGL
->fImportSemaphoreFdEXT(semaphoreHandle
,
374 LOCAL_GL_HANDLE_TYPE_OPAQUE_FD_EXT
, fd
.release());
375 auto error
= mGL
->fGetError();
376 if (error
!= LOCAL_GL_NO_ERROR
) {
377 gfxCriticalNoteOnce
<< "glImportSemaphoreFdEXT failed: " << error
;
381 GLenum srcLayout
= LOCAL_GL_LAYOUT_COLOR_ATTACHMENT_EXT
;
382 mGL
->fWaitSemaphoreEXT(semaphoreHandle
, 0, nullptr, 1, &aGlTexture
,
384 error
= mGL
->fGetError();
385 if (error
!= LOCAL_GL_NO_ERROR
) {
386 gfxCriticalNoteOnce
<< "glWaitSemaphoreEXT failed: " << error
;
391 bool DMABufSurface::OpenFileDescriptors(const MutexAutoLock
& aProofOfLock
) {
392 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
393 if (!OpenFileDescriptorForPlane(aProofOfLock
, i
)) {
400 // We can safely close DMABuf file descriptors only when we have a valid
401 // GbmBufferObject. When we don't have a valid GbmBufferObject and a DMABuf
402 // file descriptor is closed, whole surface is released.
403 void DMABufSurface::CloseFileDescriptors(const MutexAutoLock
& aProofOfLock
,
405 for (int i
= 0; i
< DMABUF_BUFFER_PLANES
; i
++) {
406 CloseFileDescriptorForPlane(aProofOfLock
, i
, aForceClose
);
410 nsresult
DMABufSurface::ReadIntoBuffer(uint8_t* aData
, int32_t aStride
,
411 const gfx::IntSize
& aSize
,
412 gfx::SurfaceFormat aFormat
) {
413 LOGDMABUF(("DMABufSurface::ReadIntoBuffer UID %d", mUID
));
415 // We're empty, nothing to copy
416 if (!GetTextureCount()) {
417 return NS_ERROR_FAILURE
;
420 MOZ_ASSERT(aSize
.width
== GetWidth());
421 MOZ_ASSERT(aSize
.height
== GetHeight());
423 StaticMutexAutoLock
lock(sSnapshotContextMutex
);
424 RefPtr
<GLContext
> context
= ClaimSnapshotGLContext();
425 auto releaseTextures
= mozilla::MakeScopeExit([&] {
427 ReturnSnapshotGLContext(context
);
430 for (int i
= 0; i
< GetTextureCount(); i
++) {
431 if (!GetTexture(i
) && !CreateTexture(context
, i
)) {
432 LOGDMABUF(("ReadIntoBuffer: Failed to create DMABuf textures."));
433 return NS_ERROR_FAILURE
;
437 ScopedTexture
scopedTex(context
);
438 ScopedBindTexture
boundTex(context
, scopedTex
.Texture());
440 context
->fTexImage2D(LOCAL_GL_TEXTURE_2D
, 0, LOCAL_GL_RGBA
, aSize
.width
,
441 aSize
.height
, 0, LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
,
444 ScopedFramebufferForTexture
autoFBForTex(context
, scopedTex
.Texture());
445 if (!autoFBForTex
.IsComplete()) {
446 LOGDMABUF(("ReadIntoBuffer: ScopedFramebufferForTexture failed."));
447 return NS_ERROR_FAILURE
;
450 const gl::OriginPos destOrigin
= gl::OriginPos::BottomLeft
;
452 const ScopedBindFramebuffer
bindFB(context
, autoFBForTex
.FB());
453 if (!context
->BlitHelper()->Blit(this, aSize
, destOrigin
)) {
454 LOGDMABUF(("ReadIntoBuffer: Blit failed."));
455 return NS_ERROR_FAILURE
;
459 ScopedBindFramebuffer
bind(context
, autoFBForTex
.FB());
460 ReadPixelsIntoBuffer(context
, aData
, aStride
, aSize
, aFormat
);
464 already_AddRefed
<gfx::DataSourceSurface
> DMABufSurface::GetAsSourceSurface() {
465 LOGDMABUF(("DMABufSurface::GetAsSourceSurface UID %d", mUID
));
467 gfx::IntSize
size(GetWidth(), GetHeight());
468 const auto format
= gfx::SurfaceFormat::B8G8R8A8
;
469 RefPtr
<gfx::DataSourceSurface
> source
=
470 gfx::Factory::CreateDataSourceSurface(size
, format
);
471 if (NS_WARN_IF(!source
)) {
472 LOGDMABUF(("GetAsSourceSurface: CreateDataSourceSurface failed."));
476 gfx::DataSourceSurface::ScopedMap
map(source
,
477 gfx::DataSourceSurface::READ_WRITE
);
478 if (NS_WARN_IF(!map
.IsMapped())) {
479 LOGDMABUF(("GetAsSourceSurface: Mapping surface failed."));
483 if (NS_WARN_IF(NS_FAILED(
484 ReadIntoBuffer(map
.GetData(), map
.GetStride(), size
, format
)))) {
485 LOGDMABUF(("GetAsSourceSurface: Reading into buffer failed."));
489 return source
.forget();
492 DMABufSurfaceRGBA::DMABufSurfaceRGBA()
493 : DMABufSurface(SURFACE_RGBA
),
496 mEGLImage(LOCAL_EGL_NO_IMAGE
),
498 mGbmBufferFlags(0) {}
500 DMABufSurfaceRGBA::~DMABufSurfaceRGBA() { ReleaseSurface(); }
502 bool DMABufSurfaceRGBA::OpenFileDescriptorForPlane(
503 const MutexAutoLock
& aProofOfLock
, int aPlane
) {
504 if (mDmabufFds
[aPlane
]) {
507 gbm_bo
* bo
= mGbmBufferObject
[0];
508 if (NS_WARN_IF(!bo
)) {
510 ("DMABufSurfaceRGBA::OpenFileDescriptorForPlane: Missing "
511 "mGbmBufferObject object!"));
515 if (mBufferPlaneCount
== 1) {
516 MOZ_ASSERT(aPlane
== 0, "DMABuf: wrong surface plane!");
517 auto rawFd
= GbmLib::GetFd(bo
);
519 mDmabufFds
[0] = new gfx::FileHandleWrapper(UniqueFileHandle(rawFd
));
521 gfxCriticalNoteOnce
<< "GbmLib::GetFd() failed";
523 ("DMABufSurfaceRGBA::OpenFileDescriptorForPlane: GbmLib::GetFd() "
527 auto rawFd
= GetDMABufDevice()->GetDmabufFD(
528 GbmLib::GetHandleForPlane(bo
, aPlane
).u32
);
530 mDmabufFds
[aPlane
] = new gfx::FileHandleWrapper(UniqueFileHandle(rawFd
));
532 gfxCriticalNoteOnce
<< "DMABufDevice::GetDmabufFD() failed";
534 ("DMABufSurfaceRGBA::OpenFileDescriptorForPlane: "
535 "DMABufDevice::GetDmabufFD() failed"));
539 if (!mDmabufFds
[aPlane
]) {
540 CloseFileDescriptors(aProofOfLock
);
547 void DMABufSurfaceRGBA::CloseFileDescriptorForPlane(
548 const MutexAutoLock
& aProofOfLock
, int aPlane
, bool aForceClose
= false) {
549 if ((aForceClose
|| mGbmBufferObject
[0]) && mDmabufFds
[aPlane
]) {
550 mDmabufFds
[aPlane
] = nullptr;
554 bool DMABufSurfaceRGBA::Create(int aWidth
, int aHeight
,
555 int aDMABufSurfaceFlags
) {
556 mFOURCCFormat
= aDMABufSurfaceFlags
& DMABUF_ALPHA
? GBM_FORMAT_ARGB8888
557 : GBM_FORMAT_XRGB8888
;
558 RefPtr
<DRMFormat
> format
= GetDMABufDevice()->GetDRMFormat(mFOURCCFormat
);
562 return Create(aWidth
, aHeight
, format
, aDMABufSurfaceFlags
);
565 bool DMABufSurfaceRGBA::Create(int aWidth
, int aHeight
,
566 RefPtr
<DRMFormat
> aFormat
,
567 int aDMABufSurfaceFlags
) {
568 MOZ_ASSERT(mGbmBufferObject
[0] == nullptr, "Already created?");
570 if (!GetDMABufDevice()->GetGbmDevice()) {
571 LOGDMABUF(("DMABufSurfaceRGBA::Create(): Missing GbmDevice!"));
577 mFOURCCFormat
= aFormat
->GetFormat();
580 ("DMABufSurfaceRGBA::Create() UID %d size %d x %d format 0x%x "
582 mUID
, mWidth
, mHeight
, mFOURCCFormat
, aFormat
->UseModifiers()));
584 if (aDMABufSurfaceFlags
& DMABUF_TEXTURE
) {
585 mGbmBufferFlags
= GBM_BO_USE_RENDERING
;
586 } else if (aDMABufSurfaceFlags
& DMABUF_SCANOUT
) {
587 mGbmBufferFlags
= GBM_BO_USE_RENDERING
| GBM_BO_USE_SCANOUT
;
590 aFormat
->UseModifiers() && (aDMABufSurfaceFlags
& DMABUF_USE_MODIFIERS
);
592 LOGDMABUF((" Creating with modifiers\n"));
593 uint32_t modifiersNum
= 0;
594 const uint64_t* modifiers
= aFormat
->GetModifiers(modifiersNum
);
595 mGbmBufferObject
[0] = GbmLib::CreateWithModifiers2(
596 GetDMABufDevice()->GetGbmDevice(), mWidth
, mHeight
, mFOURCCFormat
,
597 modifiers
, modifiersNum
, mGbmBufferFlags
);
598 if (mGbmBufferObject
[0]) {
599 mBufferModifiers
[0] = GbmLib::GetModifier(mGbmBufferObject
[0]);
603 if (!mGbmBufferObject
[0]) {
604 LOGDMABUF((" Creating without modifiers\n"));
605 mGbmBufferFlags
= GBM_BO_USE_RENDERING
| GBM_BO_USE_LINEAR
;
606 mGbmBufferObject
[0] =
607 GbmLib::Create(GetDMABufDevice()->GetGbmDevice(), mWidth
, mHeight
,
608 mFOURCCFormat
, mGbmBufferFlags
);
609 mBufferModifiers
[0] = DRM_FORMAT_MOD_INVALID
;
612 if (!mGbmBufferObject
[0]) {
613 LOGDMABUF((" Failed to create GbmBufferObject\n"));
617 if (mBufferModifiers
[0] != DRM_FORMAT_MOD_INVALID
) {
618 mBufferPlaneCount
= GbmLib::GetPlaneCount(mGbmBufferObject
[0]);
619 LOGDMABUF((" Planes count %d", mBufferPlaneCount
));
620 if (mBufferPlaneCount
> DMABUF_BUFFER_PLANES
) {
622 (" There's too many dmabuf planes! (%d)", mBufferPlaneCount
));
623 mBufferPlaneCount
= DMABUF_BUFFER_PLANES
;
627 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
628 mStrides
[i
] = GbmLib::GetStrideForPlane(mGbmBufferObject
[0], i
);
629 mOffsets
[i
] = GbmLib::GetOffset(mGbmBufferObject
[0], i
);
632 mBufferPlaneCount
= 1;
633 mStrides
[0] = GbmLib::GetStride(mGbmBufferObject
[0]);
636 LOGDMABUF((" Success\n"));
640 bool DMABufSurfaceRGBA::Create(mozilla::gl::GLContext
* aGLContext
,
641 const EGLImageKHR aEGLImage
, int aWidth
,
643 LOGDMABUF(("DMABufSurfaceRGBA::Create() from EGLImage UID = %d\n", mUID
));
647 const auto& gle
= gl::GLContextEGL::Cast(aGLContext
);
648 const auto& egl
= gle
->mEgl
;
653 mEGLImage
= aEGLImage
;
654 if (!egl
->fExportDMABUFImageQuery(mEGLImage
, mDrmFormats
, &mBufferPlaneCount
,
656 LOGDMABUF((" ExportDMABUFImageQueryMESA failed, quit\n"));
659 if (mBufferPlaneCount
> DMABUF_BUFFER_PLANES
) {
660 LOGDMABUF((" wrong plane count %d, quit\n", mBufferPlaneCount
));
661 mBufferPlaneCount
= DMABUF_BUFFER_PLANES
;
664 int fds
[DMABUF_BUFFER_PLANES
] = {-1};
665 if (!egl
->fExportDMABUFImage(mEGLImage
, fds
, mStrides
, mOffsets
)) {
666 LOGDMABUF((" ExportDMABUFImageMESA failed, quit\n"));
670 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
672 mDmabufFds
[i
] = new gfx::FileHandleWrapper(UniqueFileHandle(fds
[i
]));
676 // A broken driver can return dmabuf without valid file descriptors
677 // which leads to fails later so quit now.
678 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
679 if (!mDmabufFds
[i
]) {
681 (" ExportDMABUFImageMESA failed, mDmabufFds[%d] is invalid, quit",
687 LOGDMABUF((" imported size %d x %d format %x planes %d modifiers %" PRIx64
,
688 mWidth
, mHeight
, mFOURCCFormat
, mBufferPlaneCount
,
689 mBufferModifiers
[0]));
693 bool DMABufSurfaceRGBA::Create(
694 RefPtr
<mozilla::gfx::FileHandleWrapper
>&& aFd
,
695 const mozilla::webgpu::ffi::WGPUDMABufInfo
& aDMABufInfo
, int aWidth
,
697 LOGDMABUF(("DMABufSurfaceRGBA::Create() UID %d size %d x %d\n", mUID
, mWidth
,
702 mBufferModifiers
[0] = aDMABufInfo
.modifier
;
704 // TODO: Read Vulkan modifiers from DMABufFormats?
705 mFOURCCFormat
= GBM_FORMAT_ARGB8888
;
706 RefPtr
<DRMFormat
> format
= GetDMABufDevice()->GetDRMFormat(mFOURCCFormat
);
710 mBufferPlaneCount
= aDMABufInfo
.plane_count
;
712 RefPtr
<gfx::FileHandleWrapper
> fd
= std::move(aFd
);
714 for (uint32_t i
= 0; i
< aDMABufInfo
.plane_count
; i
++) {
716 mStrides
[i
] = aDMABufInfo
.strides
[i
];
717 mOffsets
[i
] = aDMABufInfo
.offsets
[i
];
720 LOGDMABUF((" imported size %d x %d format %x planes %d modifiers %" PRIx64
,
721 mWidth
, mHeight
, mFOURCCFormat
, mBufferPlaneCount
,
722 mBufferModifiers
[0]));
726 bool DMABufSurfaceRGBA::ImportSurfaceDescriptor(
727 const SurfaceDescriptor
& aDesc
) {
728 const SurfaceDescriptorDMABuf
& desc
= aDesc
.get_SurfaceDescriptorDMABuf();
730 mFOURCCFormat
= desc
.fourccFormat();
731 mWidth
= desc
.width()[0];
732 mHeight
= desc
.height()[0];
733 mBufferPlaneCount
= desc
.fds().Length();
734 mGbmBufferFlags
= desc
.flags();
735 MOZ_RELEASE_ASSERT(mBufferPlaneCount
<= DMABUF_BUFFER_PLANES
);
739 ("DMABufSurfaceRGBA::ImportSurfaceDescriptor() UID %d size %d x %d\n",
740 mUID
, mWidth
, mHeight
));
742 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
743 mDmabufFds
[i
] = desc
.fds()[i
];
744 mStrides
[i
] = desc
.strides()[i
];
745 mOffsets
[i
] = desc
.offsets()[i
];
746 mDrmFormats
[i
] = desc
.format()[i
];
747 mBufferModifiers
[i
] = desc
.modifier()[i
];
750 if (desc
.fence().Length() > 0) {
751 mSyncFd
= desc
.fence()[0];
754 if (desc
.semaphoreFd()) {
755 mSemaphoreFd
= desc
.semaphoreFd();
758 if (desc
.refCount().Length() > 0) {
759 GlobalRefCountImport(desc
.refCount()[0].ClonePlatformHandle().release());
762 LOGDMABUF((" imported size %d x %d format %x planes %d", mWidth
, mHeight
,
763 mFOURCCFormat
, mBufferPlaneCount
));
767 bool DMABufSurfaceRGBA::Create(const SurfaceDescriptor
& aDesc
) {
768 return ImportSurfaceDescriptor(aDesc
);
771 bool DMABufSurfaceRGBA::Serialize(
772 mozilla::layers::SurfaceDescriptor
& aOutDescriptor
) {
773 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> width
;
774 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> height
;
775 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> format
;
776 AutoTArray
<NotNull
<RefPtr
<gfx::FileHandleWrapper
>>, DMABUF_BUFFER_PLANES
> fds
;
777 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> strides
;
778 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> offsets
;
779 AutoTArray
<uintptr_t, DMABUF_BUFFER_PLANES
> images
;
780 AutoTArray
<uint64_t, DMABUF_BUFFER_PLANES
> modifiers
;
781 AutoTArray
<NotNull
<RefPtr
<gfx::FileHandleWrapper
>>, 1> fenceFDs
;
782 AutoTArray
<ipc::FileDescriptor
, 1> refCountFDs
;
784 LOGDMABUF(("DMABufSurfaceRGBA::Serialize() UID %d\n", mUID
));
786 MutexAutoLock
lockFD(mSurfaceLock
);
787 if (!OpenFileDescriptors(lockFD
)) {
791 width
.AppendElement(mWidth
);
792 height
.AppendElement(mHeight
);
793 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
794 fds
.AppendElement(WrapNotNull(mDmabufFds
[i
]));
795 strides
.AppendElement(mStrides
[i
]);
796 offsets
.AppendElement(mOffsets
[i
]);
797 format
.AppendElement(mDrmFormats
[i
]);
798 modifiers
.AppendElement(mBufferModifiers
[i
]);
801 CloseFileDescriptors(lockFD
);
803 if (mSync
&& mSyncFd
) {
804 fenceFDs
.AppendElement(WrapNotNull(mSyncFd
));
807 if (mGlobalRefCountFd
) {
808 refCountFDs
.AppendElement(ipc::FileDescriptor(GlobalRefCountExport()));
811 aOutDescriptor
= SurfaceDescriptorDMABuf(
812 mSurfaceType
, mFOURCCFormat
, modifiers
, mGbmBufferFlags
, fds
, width
,
813 height
, width
, height
, format
, strides
, offsets
, GetYUVColorSpace(),
814 mColorRange
, mozilla::gfx::ColorSpace2::UNKNOWN
,
815 mozilla::gfx::TransferFunction::Default
, fenceFDs
, mUID
, refCountFDs
,
816 /* semaphoreFd */ nullptr);
820 bool DMABufSurfaceRGBA::CreateTexture(GLContext
* aGLContext
, int aPlane
) {
821 LOGDMABUF(("DMABufSurfaceRGBA::CreateTexture() UID %d\n", mUID
));
822 MOZ_ASSERT(!mEGLImage
&& !mTexture
, "EGLImage is already created!");
824 nsTArray
<EGLint
> attribs
;
825 attribs
.AppendElement(LOCAL_EGL_WIDTH
);
826 attribs
.AppendElement(mWidth
);
827 attribs
.AppendElement(LOCAL_EGL_HEIGHT
);
828 attribs
.AppendElement(mHeight
);
829 attribs
.AppendElement(LOCAL_EGL_LINUX_DRM_FOURCC_EXT
);
830 attribs
.AppendElement(mFOURCCFormat
);
831 #define ADD_PLANE_ATTRIBS(plane_idx) \
833 attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_FD_EXT); \
834 attribs.AppendElement(mDmabufFds[plane_idx]->GetHandle()); \
835 attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_OFFSET_EXT); \
836 attribs.AppendElement((int)mOffsets[plane_idx]); \
837 attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_PITCH_EXT); \
838 attribs.AppendElement((int)mStrides[plane_idx]); \
839 if (mBufferModifiers[0] != DRM_FORMAT_MOD_INVALID) { \
840 attribs.AppendElement( \
841 LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_MODIFIER_LO_EXT); \
842 attribs.AppendElement(mBufferModifiers[0] & 0xFFFFFFFF); \
843 attribs.AppendElement( \
844 LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_MODIFIER_HI_EXT); \
845 attribs.AppendElement(mBufferModifiers[0] >> 32); \
849 MutexAutoLock
lockFD(mSurfaceLock
);
850 if (!OpenFileDescriptors(lockFD
)) {
853 ADD_PLANE_ATTRIBS(0);
854 if (mBufferPlaneCount
> 1) ADD_PLANE_ATTRIBS(1);
855 if (mBufferPlaneCount
> 2) ADD_PLANE_ATTRIBS(2);
856 if (mBufferPlaneCount
> 3) ADD_PLANE_ATTRIBS(3);
857 #undef ADD_PLANE_ATTRIBS
858 attribs
.AppendElement(LOCAL_EGL_NONE
);
860 if (!aGLContext
) return false;
862 if (!aGLContext
->MakeCurrent()) {
864 ("DMABufSurfaceRGBA::CreateTexture(): failed to make GL context "
869 if (!aGLContext
->IsExtensionSupported(gl::GLContext::OES_EGL_image
)) {
870 LOGDMABUF(("DMABufSurfaceRGBA::CreateTexture(): no OES_EGL_image."));
874 const auto& gle
= gl::GLContextEGL::Cast(aGLContext
);
875 const auto& egl
= gle
->mEgl
;
877 egl
->fCreateImage(LOCAL_EGL_NO_CONTEXT
, LOCAL_EGL_LINUX_DMA_BUF_EXT
,
878 nullptr, attribs
.Elements());
880 CloseFileDescriptors(lockFD
);
882 if (mEGLImage
== LOCAL_EGL_NO_IMAGE
) {
883 LOGDMABUF(("EGLImageKHR creation failed"));
887 aGLContext
->fGenTextures(1, &mTexture
);
888 const ScopedBindTexture
savedTex(aGLContext
, mTexture
);
889 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_S
,
890 LOCAL_GL_CLAMP_TO_EDGE
);
891 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_T
,
892 LOCAL_GL_CLAMP_TO_EDGE
);
893 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_MAG_FILTER
,
895 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_MIN_FILTER
,
897 aGLContext
->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D
, mEGLImage
);
903 void DMABufSurfaceRGBA::ReleaseTextures() {
904 LOGDMABUF(("DMABufSurfaceRGBA::ReleaseTextures() UID %d\n", mUID
));
907 if (!mTexture
&& !mEGLImage
) {
913 MOZ_DIAGNOSTIC_ASSERT(mGL
, "Missing GL context!");
916 "DMABufSurfaceRGBA::ReleaseTextures(): Missing GL context! We're "
917 "leaking textures!");
922 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
923 const auto& egl
= gle
->mEgl
;
925 if (mTexture
&& mGL
->MakeCurrent()) {
926 mGL
->fDeleteTextures(1, &mTexture
);
930 if (mEGLImage
!= LOCAL_EGL_NO_IMAGE
) {
931 egl
->fDestroyImage(mEGLImage
);
932 mEGLImage
= LOCAL_EGL_NO_IMAGE
;
937 void DMABufSurfaceRGBA::ReleaseSurface() {
938 MOZ_ASSERT(!IsMapped(), "We can't release mapped buffer!");
945 wl_buffer
* DMABufSurfaceRGBA::CreateWlBuffer() {
946 nsWaylandDisplay
* waylandDisplay
= widget::WaylandDisplayGet();
947 auto* dmabuf
= waylandDisplay
->GetDmabuf();
950 << "DMABufSurfaceRGBA::CreateWlBuffer(): Missing DMABuf support!";
954 MutexAutoLock
lockFD(mSurfaceLock
);
956 ("DMABufSurfaceRGBA::CreateWlBuffer() UID %d format %s size [%d x %d]",
957 mUID
, GetSurfaceTypeName(), GetWidth(), GetHeight()));
959 if (!OpenFileDescriptors(lockFD
)) {
960 LOGDMABUF((" failed to open dmabuf fd"));
964 struct zwp_linux_buffer_params_v1
* params
=
965 zwp_linux_dmabuf_v1_create_params(dmabuf
);
967 LOGDMABUF((" layer [0] modifier %" PRIx64
, mBufferModifiers
[0]));
968 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
969 zwp_linux_buffer_params_v1_add(
970 params
, mDmabufFds
[i
]->GetHandle(), i
, mOffsets
[i
], mStrides
[i
],
971 mBufferModifiers
[0] >> 32, mBufferModifiers
[0] & 0xffffffff);
975 (" zwp_linux_buffer_params_v1_create_immed() [%d x %d], fourcc [%x]",
976 GetWidth(), GetHeight(), GetFOURCCFormat()));
977 wl_buffer
* buffer
= zwp_linux_buffer_params_v1_create_immed(
978 params
, GetWidth(), GetHeight(), GetFOURCCFormat(), 0);
981 (" zwp_linux_buffer_params_v1_create_immed(): failed to create "
984 LOGDMABUF((" created wl_buffer [%p]", buffer
));
986 zwp_linux_buffer_params_v1_destroy(params
);
988 CloseFileDescriptors(lockFD
);
993 // We should synchronize DMA Buffer object access from CPU to avoid potential
994 // cache incoherency and data loss.
996 // https://01.org/linuxgraphics/gfx-docs/drm/driver-api/dma-buf.html#cpu-access-to-dma-buffer-objects
997 struct dma_buf_sync
{
1000 #define DMA_BUF_SYNC_READ (1 << 0)
1001 #define DMA_BUF_SYNC_WRITE (2 << 0)
1002 #define DMA_BUF_SYNC_START (0 << 2)
1003 #define DMA_BUF_SYNC_END (1 << 2)
1004 #define DMA_BUF_BASE 'b'
1005 #define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
1007 static void SyncDmaBuf(int aFd
, uint64_t aFlags
) {
1008 struct dma_buf_sync sync
= {0};
1010 sync
.flags
= aFlags
| DMA_BUF_SYNC_READ
| DMA_BUF_SYNC_WRITE
;
1013 ret
= ioctl(aFd
, DMA_BUF_IOCTL_SYNC
, &sync
);
1014 if (ret
== -1 && errno
== EINTR
) {
1016 } else if (ret
== -1) {
1018 ("Failed to synchronize DMA buffer: %s FD %d", strerror(errno
), aFd
));
1026 void* DMABufSurface::MapInternal(uint32_t aX
, uint32_t aY
, uint32_t aWidth
,
1027 uint32_t aHeight
, uint32_t* aStride
,
1028 int aGbmFlags
, int aPlane
) {
1029 NS_ASSERTION(!IsMapped(aPlane
), "Already mapped!");
1030 if (!mGbmBufferObject
[aPlane
]) {
1031 NS_WARNING("We can't map DMABufSurfaceRGBA without mGbmBufferObject");
1036 ("DMABufSurfaceRGBA::MapInternal() UID %d plane %d size %d x %d -> %d x "
1038 mUID
, aPlane
, aX
, aY
, aWidth
, aHeight
));
1040 mMappedRegionStride
[aPlane
] = 0;
1041 mMappedRegionData
[aPlane
] = nullptr;
1042 mMappedRegion
[aPlane
] =
1043 GbmLib::Map(mGbmBufferObject
[aPlane
], aX
, aY
, aWidth
, aHeight
, aGbmFlags
,
1044 &mMappedRegionStride
[aPlane
], &mMappedRegionData
[aPlane
]);
1045 if (!mMappedRegion
[aPlane
]) {
1046 LOGDMABUF((" Surface mapping failed: %s", strerror(errno
)));
1050 *aStride
= mMappedRegionStride
[aPlane
];
1053 MutexAutoLock
lockFD(mSurfaceLock
);
1054 if (OpenFileDescriptorForPlane(lockFD
, aPlane
)) {
1055 SyncDmaBuf(mDmabufFds
[aPlane
]->GetHandle(), DMA_BUF_SYNC_START
);
1056 CloseFileDescriptorForPlane(lockFD
, aPlane
);
1059 return mMappedRegion
[aPlane
];
1062 void* DMABufSurfaceRGBA::MapReadOnly(uint32_t aX
, uint32_t aY
, uint32_t aWidth
,
1063 uint32_t aHeight
, uint32_t* aStride
) {
1064 return MapInternal(aX
, aY
, aWidth
, aHeight
, aStride
, GBM_BO_TRANSFER_READ
);
1067 void* DMABufSurfaceRGBA::MapReadOnly(uint32_t* aStride
) {
1068 return MapInternal(0, 0, mWidth
, mHeight
, aStride
, GBM_BO_TRANSFER_READ
);
1071 void* DMABufSurfaceRGBA::Map(uint32_t aX
, uint32_t aY
, uint32_t aWidth
,
1072 uint32_t aHeight
, uint32_t* aStride
) {
1073 return MapInternal(aX
, aY
, aWidth
, aHeight
, aStride
,
1074 GBM_BO_TRANSFER_READ_WRITE
);
1077 void* DMABufSurfaceRGBA::Map(uint32_t* aStride
) {
1078 return MapInternal(0, 0, mWidth
, mHeight
, aStride
,
1079 GBM_BO_TRANSFER_READ_WRITE
);
1082 void DMABufSurface::Unmap(int aPlane
) {
1083 if (mMappedRegion
[aPlane
]) {
1084 LOGDMABUF(("DMABufSurface::Unmap() UID %d plane %d\n", mUID
, aPlane
));
1085 MutexAutoLock
lockFD(mSurfaceLock
);
1086 if (OpenFileDescriptorForPlane(lockFD
, aPlane
)) {
1087 SyncDmaBuf(mDmabufFds
[aPlane
]->GetHandle(), DMA_BUF_SYNC_END
);
1088 CloseFileDescriptorForPlane(lockFD
, aPlane
);
1090 GbmLib::Unmap(mGbmBufferObject
[aPlane
], mMappedRegionData
[aPlane
]);
1091 mMappedRegion
[aPlane
] = nullptr;
1092 mMappedRegionData
[aPlane
] = nullptr;
1093 mMappedRegionStride
[aPlane
] = 0;
1097 nsresult
DMABufSurface::BuildSurfaceDescriptorBuffer(
1098 SurfaceDescriptorBuffer
& aSdBuffer
, Image::BuildSdbFlags aFlags
,
1099 const std::function
<MemoryOrShmem(uint32_t)>& aAllocate
) {
1100 return NS_ERROR_NOT_IMPLEMENTED
;
1104 void DMABufSurfaceRGBA::DumpToFile(const char* pFile
) {
1107 if (!MapReadOnly(&stride
)) {
1110 cairo_surface_t
* surface
= nullptr;
1112 auto unmap
= MakeScopeExit([&] {
1114 cairo_surface_destroy(surface
);
1119 surface
= cairo_image_surface_create_for_data(
1120 (unsigned char*)mMappedRegion
[0], CAIRO_FORMAT_ARGB32
, mWidth
, mHeight
,
1122 if (cairo_surface_status(surface
) == CAIRO_STATUS_SUCCESS
) {
1123 cairo_surface_write_to_png(surface
, pFile
);
1129 // Copy from source surface by GL
1130 # include "GLBlitHelper.h"
1132 bool DMABufSurfaceRGBA::CopyFrom(class DMABufSurface
* aSourceSurface
,
1133 GLContext
* aGLContext
) {
1134 MOZ_ASSERT(aSourceSurface
->GetTexture());
1135 MOZ_ASSERT(GetTexture());
1137 gfx::IntSize
size(GetWidth(), GetHeight());
1138 aGLContext
->BlitHelper()->BlitTextureToTexture(aSourceSurface
->GetTexture(),
1139 GetTexture(), size
, size
);
1144 // TODO - Clear the surface by EGL
1145 void DMABufSurfaceRGBA::Clear() {
1146 uint32_t destStride
;
1147 void* destData
= Map(&destStride
);
1148 memset(destData
, 0, GetHeight() * destStride
);
1152 bool DMABufSurfaceRGBA::HasAlpha() {
1153 return mFOURCCFormat
== GBM_FORMAT_ARGB8888
;
1156 gfx::SurfaceFormat
DMABufSurfaceRGBA::GetFormat() {
1157 return HasAlpha() ? gfx::SurfaceFormat::B8G8R8A8
1158 : gfx::SurfaceFormat::B8G8R8X8
;
1161 // GL uses swapped R and B components so report accordingly.
1162 gfx::SurfaceFormat
DMABufSurfaceRGBA::GetFormatGL() {
1163 return HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8
1164 : gfx::SurfaceFormat::R8G8B8X8
;
1167 already_AddRefed
<DMABufSurfaceRGBA
> DMABufSurfaceRGBA::CreateDMABufSurface(
1168 int aWidth
, int aHeight
, int aDMABufSurfaceFlags
) {
1169 RefPtr
<DMABufSurfaceRGBA
> surf
= new DMABufSurfaceRGBA();
1170 if (!surf
->Create(aWidth
, aHeight
, aDMABufSurfaceFlags
)) {
1173 return surf
.forget();
1176 already_AddRefed
<DMABufSurfaceRGBA
> DMABufSurfaceRGBA::CreateDMABufSurface(
1177 int aWidth
, int aHeight
, RefPtr
<DRMFormat
> aFormat
,
1178 int aDMABufSurfaceFlags
) {
1179 RefPtr
<DMABufSurfaceRGBA
> surf
= new DMABufSurfaceRGBA();
1180 if (!surf
->Create(aWidth
, aHeight
, aFormat
, aDMABufSurfaceFlags
)) {
1183 return surf
.forget();
1186 already_AddRefed
<DMABufSurface
> DMABufSurfaceRGBA::CreateDMABufSurface(
1187 mozilla::gl::GLContext
* aGLContext
, const EGLImageKHR aEGLImage
, int aWidth
,
1189 RefPtr
<DMABufSurfaceRGBA
> surf
= new DMABufSurfaceRGBA();
1190 if (!surf
->Create(aGLContext
, aEGLImage
, aWidth
, aHeight
)) {
1193 return surf
.forget();
1196 already_AddRefed
<DMABufSurface
> DMABufSurfaceRGBA::CreateDMABufSurface(
1197 RefPtr
<mozilla::gfx::FileHandleWrapper
>&& aFd
,
1198 const mozilla::webgpu::ffi::WGPUDMABufInfo
& aDMABufInfo
, int aWidth
,
1200 RefPtr
<DMABufSurfaceRGBA
> surf
= new DMABufSurfaceRGBA();
1201 if (!surf
->Create(std::move(aFd
), aDMABufInfo
, aWidth
, aHeight
)) {
1204 return surf
.forget();
1207 already_AddRefed
<DMABufSurfaceYUV
> DMABufSurfaceYUV::CreateYUVSurface(
1208 const VADRMPRIMESurfaceDescriptor
& aDesc
, int aWidth
, int aHeight
) {
1209 RefPtr
<DMABufSurfaceYUV
> surf
= new DMABufSurfaceYUV();
1210 LOGDMABUF(("DMABufSurfaceYUV::CreateYUVSurface() UID %d from desc\n",
1212 if (!surf
->UpdateYUVData(aDesc
, aWidth
, aHeight
, /* aCopy */ false)) {
1215 return surf
.forget();
1218 already_AddRefed
<DMABufSurfaceYUV
> DMABufSurfaceYUV::CopyYUVSurface(
1219 const VADRMPRIMESurfaceDescriptor
& aDesc
, int aWidth
, int aHeight
) {
1220 RefPtr
<DMABufSurfaceYUV
> surf
= new DMABufSurfaceYUV();
1221 LOGDMABUF(("DMABufSurfaceYUV::CreateYUVSurfaceCopy() UID %d from desc\n",
1223 if (!surf
->UpdateYUVData(aDesc
, aWidth
, aHeight
, /* aCopy */ true)) {
1226 return surf
.forget();
1229 already_AddRefed
<DMABufSurfaceYUV
> DMABufSurfaceYUV::CreateYUVSurface(
1230 int aWidth
, int aHeight
, void** aPixelData
, int* aLineSizes
) {
1231 RefPtr
<DMABufSurfaceYUV
> surf
= new DMABufSurfaceYUV();
1232 LOGDMABUF(("DMABufSurfaceYUV::CreateYUVSurface() UID %d %d x %d\n",
1233 surf
->GetUID(), aWidth
, aHeight
));
1234 if (!surf
->Create(aWidth
, aHeight
, aPixelData
, aLineSizes
)) {
1237 return surf
.forget();
1240 DMABufSurfaceYUV::DMABufSurfaceYUV()
1241 : DMABufSurface(SURFACE_YUV
),
1247 for (int i
= 0; i
< DMABUF_BUFFER_PLANES
; i
++) {
1248 mEGLImage
[i
] = LOCAL_EGL_NO_IMAGE
;
1252 DMABufSurfaceYUV::~DMABufSurfaceYUV() { ReleaseSurface(); }
1254 bool DMABufSurfaceYUV::OpenFileDescriptorForPlane(
1255 const MutexAutoLock
& aProofOfLock
, int aPlane
) {
1256 // The fd is already opened, no need to reopen.
1257 // This can happen when we import dmabuf surface from VA-API decoder,
1258 // mGbmBufferObject is null and we don't close
1259 // file descriptors for surface as they are our only reference to it.
1260 if (mDmabufFds
[aPlane
]) {
1264 if (mGbmBufferObject
[aPlane
] == nullptr) {
1266 ("DMABufSurfaceYUV::OpenFileDescriptorForPlane: Missing "
1267 "mGbmBufferObject object!"));
1271 auto rawFd
= GbmLib::GetFd(mGbmBufferObject
[aPlane
]);
1273 CloseFileDescriptors(aProofOfLock
);
1276 mDmabufFds
[aPlane
] = new gfx::FileHandleWrapper(UniqueFileHandle(rawFd
));
1281 void DMABufSurfaceYUV::CloseFileDescriptorForPlane(
1282 const MutexAutoLock
& aProofOfLock
, int aPlane
, bool aForceClose
= false) {
1283 if ((aForceClose
|| mGbmBufferObject
[aPlane
]) && mDmabufFds
[aPlane
]) {
1284 mDmabufFds
[aPlane
] = nullptr;
1288 bool DMABufSurfaceYUV::ImportPRIMESurfaceDescriptor(
1289 const VADRMPRIMESurfaceDescriptor
& aDesc
, int aWidth
, int aHeight
) {
1291 ("DMABufSurfaceYUV::ImportPRIMESurfaceDescriptor() UID %d FOURCC %x",
1292 mUID
, aDesc
.fourcc
));
1294 MOZ_DIAGNOSTIC_ASSERT(!mDmabufFds
[0]);
1296 if (aDesc
.num_layers
> DMABUF_BUFFER_PLANES
||
1297 aDesc
.num_objects
> DMABUF_BUFFER_PLANES
) {
1298 LOGDMABUF((" Can't import, wrong layers/objects number (%d, %d)",
1299 aDesc
.num_layers
, aDesc
.num_objects
));
1302 mSurfaceType
= SURFACE_YUV
;
1303 mFOURCCFormat
= aDesc
.fourcc
;
1304 mBufferPlaneCount
= aDesc
.num_layers
;
1306 for (unsigned int i
= 0; i
< aDesc
.num_layers
; i
++) {
1307 // All supported formats have 4:2:0 chroma sub-sampling.
1308 unsigned int subsample
= i
== 0 ? 0 : 1;
1310 unsigned int object
= aDesc
.layers
[i
].object_index
[0];
1311 mBufferModifiers
[i
] = aDesc
.objects
[object
].drm_format_modifier
;
1312 mDrmFormats
[i
] = aDesc
.layers
[i
].drm_format
;
1313 mOffsets
[i
] = aDesc
.layers
[i
].offset
[0];
1314 mStrides
[i
] = aDesc
.layers
[i
].pitch
[0];
1315 mWidthAligned
[i
] = aDesc
.width
>> subsample
;
1316 mHeightAligned
[i
] = aDesc
.height
>> subsample
;
1317 mWidth
[i
] = aWidth
>> subsample
;
1318 mHeight
[i
] = aHeight
>> subsample
;
1319 LOGDMABUF((" plane %d size %d x %d format %x", i
, mWidth
[i
], mHeight
[i
],
1325 bool DMABufSurfaceYUV::MoveYUVDataImpl(const VADRMPRIMESurfaceDescriptor
& aDesc
,
1326 int aWidth
, int aHeight
) {
1327 if (!ImportPRIMESurfaceDescriptor(aDesc
, aWidth
, aHeight
)) {
1330 for (unsigned int i
= 0; i
< aDesc
.num_layers
; i
++) {
1331 unsigned int object
= aDesc
.layers
[i
].object_index
[0];
1332 // Keep VADRMPRIMESurfaceDescriptor untouched and dup() dmabuf
1333 // file descriptors.
1334 auto rawFd
= dup(aDesc
.objects
[object
].fd
);
1335 mDmabufFds
[i
] = new gfx::FileHandleWrapper(UniqueFileHandle(rawFd
));
1340 void DMABufSurfaceYUV::ReleaseVADRMPRIMESurfaceDescriptor(
1341 VADRMPRIMESurfaceDescriptor
& aDesc
) {
1342 for (unsigned int i
= 0; i
< aDesc
.num_layers
; i
++) {
1343 unsigned int object
= aDesc
.layers
[i
].object_index
[0];
1344 if (aDesc
.objects
[object
].fd
!= -1) {
1345 close(aDesc
.objects
[object
].fd
);
1346 aDesc
.objects
[object
].fd
= -1;
1351 bool DMABufSurfaceYUV::CreateYUVPlane(int aPlane
) {
1352 LOGDMABUF(("DMABufSurfaceYUV::CreateYUVPlane() UID %d size %d x %d", mUID
,
1353 mWidth
[aPlane
], mHeight
[aPlane
]));
1355 if (!GetDMABufDevice()->GetGbmDevice()) {
1356 LOGDMABUF((" Missing GbmDevice!"));
1360 MOZ_DIAGNOSTIC_ASSERT(mGbmBufferObject
[aPlane
] == nullptr);
1361 bool useModifiers
= (mBufferModifiers
[aPlane
] != DRM_FORMAT_MOD_INVALID
);
1363 LOGDMABUF((" Creating with modifiers"));
1364 mGbmBufferObject
[aPlane
] = GbmLib::CreateWithModifiers(
1365 GetDMABufDevice()->GetGbmDevice(), mWidth
[aPlane
], mHeight
[aPlane
],
1366 mDrmFormats
[aPlane
], mBufferModifiers
+ aPlane
, 1);
1368 if (!mGbmBufferObject
[aPlane
]) {
1369 LOGDMABUF((" Creating without modifiers"));
1370 mGbmBufferObject
[aPlane
] = GbmLib::Create(
1371 GetDMABufDevice()->GetGbmDevice(), mWidth
[aPlane
], mHeight
[aPlane
],
1372 mDrmFormats
[aPlane
], GBM_BO_USE_RENDERING
);
1373 mBufferModifiers
[aPlane
] = DRM_FORMAT_MOD_INVALID
;
1375 if (!mGbmBufferObject
[aPlane
]) {
1376 LOGDMABUF((" Failed to create GbmBufferObject: %s", strerror(errno
)));
1380 mStrides
[aPlane
] = GbmLib::GetStride(mGbmBufferObject
[aPlane
]);
1381 mOffsets
[aPlane
] = GbmLib::GetOffset(mGbmBufferObject
[aPlane
], 0);
1382 mWidthAligned
[aPlane
] = mWidth
[aPlane
];
1383 mHeightAligned
[aPlane
] = mHeight
[aPlane
];
1387 bool DMABufSurfaceYUV::CopyYUVDataImpl(const VADRMPRIMESurfaceDescriptor
& aDesc
,
1388 int aWidth
, int aHeight
) {
1389 RefPtr
<DMABufSurfaceYUV
> tmpSurf
= CreateYUVSurface(aDesc
, aWidth
, aHeight
);
1394 if (!ImportPRIMESurfaceDescriptor(aDesc
, aWidth
, aHeight
)) {
1398 StaticMutexAutoLock
lock(sSnapshotContextMutex
);
1399 RefPtr
<GLContext
> context
= ClaimSnapshotGLContext();
1400 auto releaseTextures
= MakeScopeExit([&] {
1401 tmpSurf
->ReleaseTextures();
1403 ReturnSnapshotGLContext(context
);
1406 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1407 if (!tmpSurf
->CreateTexture(context
, i
)) {
1410 if (!CreateYUVPlane(i
) || !CreateTexture(context
, i
)) {
1413 gfx::IntSize
size(GetWidth(i
), GetHeight(i
));
1414 context
->BlitHelper()->BlitTextureToTexture(
1415 tmpSurf
->GetTexture(i
), GetTexture(i
), size
, size
, LOCAL_GL_TEXTURE_2D
,
1416 LOCAL_GL_TEXTURE_2D
);
1421 bool DMABufSurfaceYUV::UpdateYUVData(const VADRMPRIMESurfaceDescriptor
& aDesc
,
1422 int aWidth
, int aHeight
, bool aCopy
) {
1423 LOGDMABUF(("DMABufSurfaceYUV::UpdateYUVData() UID %d copy %d", mUID
, aCopy
));
1424 return aCopy
? CopyYUVDataImpl(aDesc
, aWidth
, aHeight
)
1425 : MoveYUVDataImpl(aDesc
, aWidth
, aHeight
);
1428 bool DMABufSurfaceYUV::CreateLinearYUVPlane(int aPlane
, int aWidth
, int aHeight
,
1430 LOGDMABUF(("DMABufSurfaceYUV::CreateLinearYUVPlane() UID %d size %d x %d",
1431 mUID
, aWidth
, aHeight
));
1433 if (!GetDMABufDevice()->GetGbmDevice()) {
1434 LOGDMABUF((" Missing GbmDevice!"));
1438 mWidth
[aPlane
] = aWidth
;
1439 mHeight
[aPlane
] = aHeight
;
1440 mDrmFormats
[aPlane
] = aDrmFormat
;
1442 mGbmBufferObject
[aPlane
] =
1443 GbmLib::Create(GetDMABufDevice()->GetGbmDevice(), aWidth
, aHeight
,
1444 aDrmFormat
, GBM_BO_USE_LINEAR
);
1445 if (!mGbmBufferObject
[aPlane
]) {
1446 LOGDMABUF((" Failed to create GbmBufferObject: %s", strerror(errno
)));
1450 mStrides
[aPlane
] = GbmLib::GetStride(mGbmBufferObject
[aPlane
]);
1451 mDmabufFds
[aPlane
] = nullptr;
1456 void DMABufSurfaceYUV::UpdateYUVPlane(int aPlane
, void* aPixelData
,
1459 ("DMABufSurfaceYUV::UpdateYUVPlane() UID %d plane %d", mUID
, aPlane
));
1460 if (aLineSize
== mWidth
[aPlane
] &&
1461 (int)mMappedRegionStride
[aPlane
] == mWidth
[aPlane
]) {
1462 memcpy(mMappedRegion
[aPlane
], aPixelData
, aLineSize
* mHeight
[aPlane
]);
1464 char* src
= (char*)aPixelData
;
1465 char* dest
= (char*)mMappedRegion
[aPlane
];
1466 for (int i
= 0; i
< mHeight
[aPlane
]; i
++) {
1467 memcpy(dest
, src
, mWidth
[aPlane
]);
1469 dest
+= mMappedRegionStride
[aPlane
];
1474 bool DMABufSurfaceYUV::UpdateYUVData(void** aPixelData
, int* aLineSizes
) {
1475 LOGDMABUF(("DMABufSurfaceYUV::UpdateYUVData() UID %d", mUID
));
1477 if (mSurfaceType
!= SURFACE_YUV
|| mBufferPlaneCount
!= 3 ||
1478 mFOURCCFormat
!= VA_FOURCC_YV12
) {
1479 LOGDMABUF((" UpdateYUVData can upload YUV420 surface type only!"));
1483 auto unmapBuffers
= MakeScopeExit([&] {
1490 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1491 MapInternal(0, 0, mWidth
[i
], mHeight
[i
], nullptr, GBM_BO_TRANSFER_WRITE
, i
);
1492 if (!mMappedRegion
[i
]) {
1493 LOGDMABUF((" DMABufSurfaceYUV plane can't be mapped!"));
1496 if ((int)mMappedRegionStride
[i
] < mWidth
[i
]) {
1497 LOGDMABUF((" DMABufSurfaceYUV plane size stride does not match!"));
1503 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1504 UpdateYUVPlane(i
, aPixelData
[i
], aLineSizes
[i
]);
1510 bool DMABufSurfaceYUV::Create(int aWidth
, int aHeight
, void** aPixelData
,
1512 LOGDMABUF(("DMABufSurfaceYUV::Create() UID %d size %d x %d", mUID
, aWidth
,
1515 mSurfaceType
= SURFACE_YUV
;
1516 mFOURCCFormat
= VA_FOURCC_YV12
;
1517 mBufferPlaneCount
= 3;
1519 if (!CreateLinearYUVPlane(0, aWidth
, aHeight
, GBM_FORMAT_R8
)) {
1522 if (!CreateLinearYUVPlane(1, aWidth
>> 1, aHeight
>> 1, GBM_FORMAT_R8
)) {
1525 if (!CreateLinearYUVPlane(2, aWidth
>> 1, aHeight
>> 1, GBM_FORMAT_R8
)) {
1528 if (!aPixelData
|| !aLineSizes
) {
1531 return UpdateYUVData(aPixelData
, aLineSizes
);
1534 bool DMABufSurfaceYUV::Create(const SurfaceDescriptor
& aDesc
) {
1535 return ImportSurfaceDescriptor(aDesc
);
1538 bool DMABufSurfaceYUV::ImportSurfaceDescriptor(
1539 const SurfaceDescriptorDMABuf
& aDesc
) {
1540 mBufferPlaneCount
= aDesc
.fds().Length();
1541 mSurfaceType
= SURFACE_YUV
;
1542 mFOURCCFormat
= aDesc
.fourccFormat();
1543 mColorSpace
= aDesc
.yUVColorSpace();
1544 mColorRange
= aDesc
.colorRange();
1545 mColorPrimaries
= aDesc
.colorPrimaries();
1546 mTransferFunction
= aDesc
.transferFunction();
1549 LOGDMABUF(("DMABufSurfaceYUV::ImportSurfaceDescriptor() UID %d", mUID
));
1551 MOZ_RELEASE_ASSERT(mBufferPlaneCount
<= DMABUF_BUFFER_PLANES
);
1552 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1553 mDmabufFds
[i
] = aDesc
.fds()[i
];
1554 mWidth
[i
] = aDesc
.width()[i
];
1555 mHeight
[i
] = aDesc
.height()[i
];
1556 mWidthAligned
[i
] = aDesc
.widthAligned()[i
];
1557 mHeightAligned
[i
] = aDesc
.heightAligned()[i
];
1558 mDrmFormats
[i
] = aDesc
.format()[i
];
1559 mStrides
[i
] = aDesc
.strides()[i
];
1560 mOffsets
[i
] = aDesc
.offsets()[i
];
1561 mBufferModifiers
[i
] = aDesc
.modifier()[i
];
1562 LOGDMABUF((" plane %d fd %d size %d x %d format %x", i
,
1563 mDmabufFds
[i
]->GetHandle(), mWidth
[i
], mHeight
[i
],
1567 if (aDesc
.fence().Length() > 0) {
1568 mSyncFd
= aDesc
.fence()[0];
1571 if (aDesc
.refCount().Length() > 0) {
1572 GlobalRefCountImport(aDesc
.refCount()[0].ClonePlatformHandle().release());
1578 bool DMABufSurfaceYUV::Serialize(
1579 mozilla::layers::SurfaceDescriptor
& aOutDescriptor
) {
1580 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> width
;
1581 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> height
;
1582 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> widthBytes
;
1583 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> heightBytes
;
1584 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> format
;
1585 AutoTArray
<NotNull
<RefPtr
<gfx::FileHandleWrapper
>>, DMABUF_BUFFER_PLANES
> fds
;
1586 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> strides
;
1587 AutoTArray
<uint32_t, DMABUF_BUFFER_PLANES
> offsets
;
1588 AutoTArray
<uint64_t, DMABUF_BUFFER_PLANES
> modifiers
;
1589 AutoTArray
<NotNull
<RefPtr
<gfx::FileHandleWrapper
>>, 1> fenceFDs
;
1590 AutoTArray
<ipc::FileDescriptor
, 1> refCountFDs
;
1592 LOGDMABUF(("DMABufSurfaceYUV::Serialize() UID %d", mUID
));
1594 MutexAutoLock
lockFD(mSurfaceLock
);
1595 if (!OpenFileDescriptors(lockFD
)) {
1599 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1600 width
.AppendElement(mWidth
[i
]);
1601 height
.AppendElement(mHeight
[i
]);
1602 widthBytes
.AppendElement(mWidthAligned
[i
]);
1603 heightBytes
.AppendElement(mHeightAligned
[i
]);
1604 format
.AppendElement(mDrmFormats
[i
]);
1605 fds
.AppendElement(WrapNotNull(mDmabufFds
[i
]));
1606 strides
.AppendElement(mStrides
[i
]);
1607 offsets
.AppendElement(mOffsets
[i
]);
1608 modifiers
.AppendElement(mBufferModifiers
[i
]);
1611 CloseFileDescriptors(lockFD
);
1613 if (mSync
&& mSyncFd
) {
1614 fenceFDs
.AppendElement(WrapNotNull(mSyncFd
));
1617 if (mGlobalRefCountFd
) {
1618 refCountFDs
.AppendElement(ipc::FileDescriptor(GlobalRefCountExport()));
1621 aOutDescriptor
= SurfaceDescriptorDMABuf(
1622 mSurfaceType
, mFOURCCFormat
, modifiers
, 0, fds
, width
, height
, widthBytes
,
1623 heightBytes
, format
, strides
, offsets
, GetYUVColorSpace(), mColorRange
,
1624 mColorPrimaries
, mTransferFunction
, fenceFDs
, mUID
, refCountFDs
,
1625 /* semaphoreFd */ nullptr);
1629 bool DMABufSurfaceYUV::CreateEGLImage(GLContext
* aGLContext
, int aPlane
) {
1631 ("DMABufSurfaceYUV::CreateEGLImage() UID %d plane %d", mUID
, aPlane
));
1632 MOZ_ASSERT(mEGLImage
[aPlane
] == LOCAL_EGL_NO_IMAGE
,
1633 "EGLImage is already created!");
1634 MOZ_ASSERT(aGLContext
, "Missing GLContext!");
1636 const auto& gle
= gl::GLContextEGL::Cast(aGLContext
);
1637 const auto& egl
= gle
->mEgl
;
1639 MutexAutoLock
lockFD(mSurfaceLock
);
1640 if (!OpenFileDescriptorForPlane(lockFD
, aPlane
)) {
1641 LOGDMABUF((" failed to open dmabuf file descriptors"));
1645 nsTArray
<EGLint
> attribs
;
1646 attribs
.AppendElement(LOCAL_EGL_WIDTH
);
1647 attribs
.AppendElement(mWidthAligned
[aPlane
]);
1648 attribs
.AppendElement(LOCAL_EGL_HEIGHT
);
1649 attribs
.AppendElement(mHeightAligned
[aPlane
]);
1650 attribs
.AppendElement(LOCAL_EGL_LINUX_DRM_FOURCC_EXT
);
1651 attribs
.AppendElement(mDrmFormats
[aPlane
]);
1652 #define ADD_PLANE_ATTRIBS_NV12(plane_idx) \
1653 attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_FD_EXT); \
1654 attribs.AppendElement(mDmabufFds[aPlane]->GetHandle()); \
1655 attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_OFFSET_EXT); \
1656 attribs.AppendElement((int)mOffsets[aPlane]); \
1657 attribs.AppendElement(LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_PITCH_EXT); \
1658 attribs.AppendElement((int)mStrides[aPlane]); \
1659 if (mBufferModifiers[aPlane] != DRM_FORMAT_MOD_INVALID) { \
1660 attribs.AppendElement( \
1661 LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_MODIFIER_LO_EXT); \
1662 attribs.AppendElement(mBufferModifiers[aPlane] & 0xFFFFFFFF); \
1663 attribs.AppendElement( \
1664 LOCAL_EGL_DMA_BUF_PLANE##plane_idx##_MODIFIER_HI_EXT); \
1665 attribs.AppendElement(mBufferModifiers[aPlane] >> 32); \
1667 ADD_PLANE_ATTRIBS_NV12(0);
1668 #undef ADD_PLANE_ATTRIBS_NV12
1669 attribs
.AppendElement(LOCAL_EGL_NONE
);
1672 egl
->fCreateImage(LOCAL_EGL_NO_CONTEXT
, LOCAL_EGL_LINUX_DMA_BUF_EXT
,
1673 nullptr, attribs
.Elements());
1675 CloseFileDescriptorForPlane(lockFD
, aPlane
);
1677 if (mEGLImage
[aPlane
] == LOCAL_EGL_NO_IMAGE
) {
1678 LOGDMABUF((" EGLImageKHR creation failed"));
1682 LOGDMABUF((" Success."));
1686 void DMABufSurfaceYUV::ReleaseEGLImages(GLContext
* aGLContext
) {
1687 LOGDMABUF(("DMABufSurfaceYUV::ReleaseEGLImages() UID %d", mUID
));
1688 MOZ_ASSERT(aGLContext
, "Missing GLContext!");
1690 const auto& gle
= gl::GLContextEGL::Cast(aGLContext
);
1691 const auto& egl
= gle
->mEgl
;
1693 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1694 if (mEGLImage
[i
] != LOCAL_EGL_NO_IMAGE
) {
1695 egl
->fDestroyImage(mEGLImage
[i
]);
1696 mEGLImage
[i
] = LOCAL_EGL_NO_IMAGE
;
1701 bool DMABufSurfaceYUV::CreateTexture(GLContext
* aGLContext
, int aPlane
) {
1703 ("DMABufSurfaceYUV::CreateTexture() UID %d plane %d", mUID
, aPlane
));
1704 MOZ_ASSERT(!mTexture
[aPlane
], "Texture is already created!");
1705 MOZ_ASSERT(aGLContext
, "Missing GLContext!");
1707 if (!aGLContext
->MakeCurrent()) {
1708 LOGDMABUF((" Failed to make GL context current."));
1711 if (!CreateEGLImage(aGLContext
, aPlane
)) {
1714 aGLContext
->fGenTextures(1, &mTexture
[aPlane
]);
1715 const ScopedBindTexture
savedTex(aGLContext
, mTexture
[aPlane
]);
1716 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_S
,
1717 LOCAL_GL_CLAMP_TO_EDGE
);
1718 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_T
,
1719 LOCAL_GL_CLAMP_TO_EDGE
);
1720 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_MAG_FILTER
,
1722 aGLContext
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_MIN_FILTER
,
1724 aGLContext
->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D
, mEGLImage
[aPlane
]);
1729 void DMABufSurfaceYUV::ReleaseTextures() {
1730 LOGDMABUF(("DMABufSurfaceYUV::ReleaseTextures() UID %d", mUID
));
1734 bool textureActive
= false;
1735 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1736 if (mTexture
[i
] || mEGLImage
[i
]) {
1737 textureActive
= true;
1742 if (!textureActive
) {
1747 #ifdef NIGHTLY_BUILD
1748 MOZ_DIAGNOSTIC_ASSERT(mGL
, "Missing GL context!");
1751 "DMABufSurfaceYUV::ReleaseTextures(): Missing GL context! We're "
1752 "leaking textures!");
1757 if (!mGL
->MakeCurrent()) {
1759 "DMABufSurfaceYUV::ReleaseTextures(): MakeCurrent failed. We're "
1760 "leaking textures!");
1764 mGL
->fDeleteTextures(DMABUF_BUFFER_PLANES
, mTexture
);
1765 for (int i
= 0; i
< DMABUF_BUFFER_PLANES
; i
++) {
1768 ReleaseEGLImages(mGL
);
1772 bool DMABufSurfaceYUV::VerifyTextureCreation() {
1773 LOGDMABUF(("DMABufSurfaceYUV::VerifyTextureCreation() UID %d", mUID
));
1775 StaticMutexAutoLock
lock(sSnapshotContextMutex
);
1776 RefPtr
<GLContext
> context
= ClaimSnapshotGLContext();
1777 auto release
= MakeScopeExit([&] {
1778 ReleaseEGLImages(context
);
1779 ReturnSnapshotGLContext(context
);
1782 for (int i
= 0; i
< mBufferPlaneCount
; i
++) {
1783 if (!CreateEGLImage(context
, i
)) {
1784 LOGDMABUF((" failed to create EGL image!"));
1789 LOGDMABUF((" success"));
1793 gfx::SurfaceFormat
DMABufSurfaceYUV::GetFormat() {
1794 switch (mFOURCCFormat
) {
1795 case VA_FOURCC_P010
:
1796 // ReportVA_FOURCC_P010 as NV12 as Gecko threats P010 as a variant of P016
1797 // with zeroed bits, see gfx::SurfaceFormat for details.
1798 // NV12 / P010 uses the same plane composition but NV12 is 8-bit format
1799 // and P010 10-bit one.
1800 // It doesn't matter much as long as we create textures with correct
1802 case VA_FOURCC_NV12
:
1803 return gfx::SurfaceFormat::NV12
;
1804 case VA_FOURCC_YV12
:
1805 return gfx::SurfaceFormat::YUV420
;
1807 gfxCriticalNoteOnce
<< "DMABufSurfaceYUV::GetFormat() unknow format: "
1809 return gfx::SurfaceFormat::UNKNOWN
;
1813 // GL uses swapped R and B components so report accordingly.
1814 // YUV formats are not affected so report what we have directly.
1815 gfx::SurfaceFormat
DMABufSurfaceYUV::GetFormatGL() { return GetFormat(); }
1817 int DMABufSurfaceYUV::GetTextureCount() { return mBufferPlaneCount
; }
1819 void DMABufSurfaceYUV::ReleaseSurface() {
1820 LOGDMABUF(("DMABufSurfaceYUV::ReleaseSurface() UID %d", mUID
));
1825 nsresult
DMABufSurfaceYUV::BuildSurfaceDescriptorBuffer(
1826 SurfaceDescriptorBuffer
& aSdBuffer
, Image::BuildSdbFlags aFlags
,
1827 const std::function
<MemoryOrShmem(uint32_t)>& aAllocate
) {
1828 LOGDMABUF(("DMABufSurfaceYUV::BuildSurfaceDescriptorBuffer UID %d", mUID
));
1830 gfx::IntSize
size(GetWidth(), GetHeight());
1831 const auto format
= gfx::SurfaceFormat::B8G8R8A8
;
1833 uint8_t* buffer
= nullptr;
1835 nsresult rv
= Image::AllocateSurfaceDescriptorBufferRgb(
1836 size
, format
, buffer
, aSdBuffer
, stride
, aAllocate
);
1837 if (NS_WARN_IF(NS_FAILED(rv
))) {
1838 LOGDMABUF(("BuildSurfaceDescriptorBuffer allocate descriptor failed"));
1842 return ReadIntoBuffer(buffer
, stride
, size
, format
);
1846 wl_buffer
* DMABufSurfaceYUV::CreateWlBuffer() {
1847 nsWaylandDisplay
* waylandDisplay
= widget::WaylandDisplayGet();
1848 auto* dmabuf
= waylandDisplay
->GetDmabuf();
1851 << "DMABufSurfaceYUV::CreateWlBuffer(): Missing DMABuf support!";
1855 MutexAutoLock
lockFD(mSurfaceLock
);
1857 ("DMABufSurfaceYUV::CreateWlBuffer() UID %d format %s size [%d x %d]",
1858 mUID
, GetSurfaceTypeName(), GetWidth(), GetHeight()));
1860 if (!OpenFileDescriptors(lockFD
)) {
1861 LOGDMABUF((" failed to open dmabuf fd"));
1865 struct zwp_linux_buffer_params_v1
* params
=
1866 zwp_linux_dmabuf_v1_create_params(dmabuf
);
1867 for (int i
= 0; i
< GetTextureCount(); i
++) {
1868 LOGDMABUF((" layer [%d] modifier %" PRIx64
, i
, mBufferModifiers
[i
]));
1869 zwp_linux_buffer_params_v1_add(
1870 params
, mDmabufFds
[i
]->GetHandle(), i
, mOffsets
[i
], mStrides
[i
],
1871 mBufferModifiers
[i
] >> 32, mBufferModifiers
[i
] & 0xffffffff);
1875 (" zwp_linux_buffer_params_v1_create_immed() [%d x %d], fourcc [%x]",
1876 GetWidth(), GetHeight(), GetFOURCCFormat()));
1877 wl_buffer
* buffer
= zwp_linux_buffer_params_v1_create_immed(
1878 params
, GetWidth(), GetHeight(), GetFOURCCFormat(), 0);
1881 (" zwp_linux_buffer_params_v1_create_immed(): failed to create "
1884 LOGDMABUF((" created wl_buffer [%p]", buffer
));
1887 CloseFileDescriptors(lockFD
);
1893 void DMABufSurfaceYUV::ClearPlane(int aPlane
) {
1894 if (!MapInternal(0, 0, mWidth
[aPlane
], mHeight
[aPlane
], nullptr,
1895 GBM_BO_TRANSFER_WRITE
, aPlane
)) {
1898 if ((int)mMappedRegionStride
[aPlane
] < mWidth
[aPlane
]) {
1901 memset((char*)mMappedRegion
[aPlane
], 0,
1902 mMappedRegionStride
[aPlane
] * mHeight
[aPlane
]);
1906 # include "gfxUtils.h"
1908 void DMABufSurfaceYUV::DumpToFile(const char* aFile
) {
1909 RefPtr
<gfx::DataSourceSurface
> surf
= GetAsSourceSurface();
1910 gfxUtils::WriteAsPNG(surf
, aFile
);