From b2b36e851ec0724d1e6790ce5eb357e53402033e Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Tue, 17 Jan 2023 14:28:43 +0100 Subject: [PATCH] Added VA-API fixes mozbz#1809162, mozbz#1801576 --- D166324.diff | 75 +++++++ firefox.spec | 9 +- mozilla-1809162.patch | 504 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 587 insertions(+), 1 deletion(-) create mode 100644 D166324.diff create mode 100644 mozilla-1809162.patch diff --git a/D166324.diff b/D166324.diff new file mode 100644 index 0000000..00d234d --- /dev/null +++ b/D166324.diff @@ -0,0 +1,75 @@ +diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h +--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h ++++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h +@@ -175,11 +175,10 @@ + + PtsCorrectionContext mPtsContext; + + DurationMap mDurationMap; + const bool mLowLatency; +- AVDiscard mFrameDrop = AVDISCARD_DEFAULT; + const Maybe mTrackingId; + PerformanceRecorderMulti mPerformanceRecorder; + + // True if we're allocating shmem for ffmpeg decode buffer. + Maybe> mIsUsingShmemBufferForDecode; +diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +--- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp ++++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +@@ -850,17 +850,10 @@ + packet.dts = aSample->mTimecode.ToMicroseconds(); + packet.pts = aSample->mTime.ToMicroseconds(); + packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0; + packet.pos = aSample->mOffset; + +- mCodecContext->skip_frame = mFrameDrop; +-#if MOZ_LOGGING +- if (mFrameDrop == AVDISCARD_NONREF) { +- FFMPEG_LOG("Frame skip AVDISCARD_NONREF"); +- } +-#endif +- + mTrackingId.apply([&](const auto& aId) { + MediaInfoFlag flag = MediaInfoFlag::None; + flag |= (aSample->mKeyframe ? MediaInfoFlag::KeyFrame + : MediaInfoFlag::NonKeyFrame); + flag |= (IsHardwareAccelerated() ? MediaInfoFlag::HardwareDecoding +@@ -943,22 +936,10 @@ + return MediaResult( + NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("avcodec_receive_frame error: %s", errStr)); + } + +- if (mFrameDrop == AVDISCARD_NONREF) { +- FFMPEG_LOG("Requested pts %" PRId64 " decoded frame pts %" PRId64, +- packet.pts, GetFramePts(mFrame) + mFrame->pkt_duration); +- // Switch back to default frame skip policy if we hit correct +- // decode times. 5 ms treshold is taken from mpv project which +- // use similar approach after seek (feed_packet() at f_decoder_wrapper.c). +- if (packet.pts - 5000 <= GetFramePts(mFrame) + mFrame->pkt_duration) { +- FFMPEG_LOG("Set frame drop to AVDISCARD_DEFAULT."); +- mFrameDrop = AVDISCARD_DEFAULT; +- } +- } +- + UpdateDecodeTimes(decodeStart); + decodeStart = TimeStamp::Now(); + + MediaResult rv; + # ifdef MOZ_WAYLAND_USE_VAAPI +@@ -1366,14 +1347,10 @@ + FFMPEG_LOG("ProcessFlush()"); + MOZ_ASSERT(mTaskQueue->IsOnCurrentThread()); + mPtsContext.Reset(); + mDurationMap.Clear(); + mPerformanceRecorder.Record(std::numeric_limits::max()); +- // Discard non-ref frames on HW accelerated backend to avoid decode artifacts. +- if (IsHardwareAccelerated()) { +- mFrameDrop = AVDISCARD_NONREF; +- } + return FFmpegDataDecoder::ProcessFlush(); + } + + AVCodecID FFmpegVideoDecoder::GetCodecId( + const nsACString& aMimeType) { + diff --git a/firefox.spec b/firefox.spec index 416d326..7219707 100644 --- a/firefox.spec +++ b/firefox.spec @@ -173,7 +173,7 @@ ExcludeArch: i686 Summary: Mozilla Firefox Web browser Name: firefox Version: 109.0 -Release: 1%{?pre_tag}%{?dist} +Release: 2%{?pre_tag}%{?dist} URL: https://www.mozilla.org/firefox/ License: MPLv1.1 or GPLv2+ or LGPLv2+ Source0: https://archive.mozilla.org/pub/firefox/releases/%{version}%{?pre_version}/source/firefox-%{version}%{?pre_version}.source.tar.xz @@ -250,6 +250,8 @@ Patch407: mozilla-1667096.patch Patch408: mozilla-1663844.patch Patch415: mozilla-1670333.patch Patch416: D164651.diff +Patch417: D166324.diff +Patch418: mozilla-1809162.patch # PGO/LTO patches Patch600: pgo.patch @@ -525,6 +527,8 @@ This package contains results of tests executed during build. %patch408 -p1 -b .1663844 %patch415 -p1 -b .1670333 %patch416 -p1 -b .D164651 +%patch417 -p1 -b .D166324 +%patch418 -p1 -b .1809162 # PGO patches %if %{build_with_pgo} @@ -1078,6 +1082,9 @@ fi #--------------------------------------------------------------------- %changelog +* Tue Jan 17 2023 Martin Stransky - 109.0-2 +- Added VA-API fixes mozbz#1809162, mozbz#1801576 + * Mon Jan 16 2023 Martin Stransky - 109.0-1 - Update to 109.0 diff --git a/mozilla-1809162.patch b/mozilla-1809162.patch new file mode 100644 index 0000000..a6d2571 --- /dev/null +++ b/mozilla-1809162.patch @@ -0,0 +1,504 @@ +diff -up firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.cpp.1809162 firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.cpp +--- firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.cpp.1809162 2023-01-12 21:02:00.000000000 +0100 ++++ firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.cpp 2023-01-17 14:23:30.004040571 +0100 +@@ -9,6 +9,7 @@ + #include "FFmpegLog.h" + #include "mozilla/widget/DMABufLibWrapper.h" + #include "libavutil/pixfmt.h" ++#include "mozilla/gfx/gfxVars.h" + + #ifdef MOZ_LOGGING + # undef DMABUF_LOG +@@ -87,7 +88,10 @@ VideoFrameSurface::~VideoFram + } + + VideoFramePool::VideoFramePool() +- : mSurfaceLock("VideoFramePoolSurfaceLock") {} ++ : mSurfaceLock("VideoFramePoolSurfaceLock"), ++ mSurfaceCopy(!gfx::gfxVars::HwDecodedVideoZeroCopy()) { ++ DMABUF_LOG("VideoFramePool::VideoFramePool() surface copy %d", mSurfaceCopy); ++} + + VideoFramePool::~VideoFramePool() { + MutexAutoLock lock(mSurfaceLock); +@@ -129,32 +133,31 @@ VideoFramePool::GetVideoFrame + MutexAutoLock lock(mSurfaceLock); + RefPtr> videoSurface = + GetFreeVideoFrameSurface(); ++ RefPtr surface = ++ videoSurface ? videoSurface->GetDMABufSurface() : new DMABufSurfaceYUV(); + if (!videoSurface) { +- RefPtr surface = +- DMABufSurfaceYUV::CreateYUVSurface(aVaDesc, aWidth, aHeight); +- if (!surface) { +- return nullptr; +- } + DMABUF_LOG("Created new VA-API DMABufSurface UID %d", surface->GetUID()); +- RefPtr> surf = +- new VideoFrameSurface(surface); +- if (!mTextureCreationWorks) { +- mTextureCreationWorks = Some(surface->VerifyTextureCreation()); +- } +- if (!*mTextureCreationWorks) { +- DMABUF_LOG(" failed to create texture over DMABuf memory!"); +- return nullptr; +- } +- videoSurface = surf; +- mDMABufSurfaces.AppendElement(std::move(surf)); ++ videoSurface = new VideoFrameSurface(surface); ++ mDMABufSurfaces.AppendElement(videoSurface); + } else { +- RefPtr surface = videoSurface->GetDMABufSurface(); + DMABUF_LOG("Reusing VA-API DMABufSurface UID %d", surface->GetUID()); +- if (!surface->UpdateYUVData(aVaDesc, aWidth, aHeight)) { ++ } ++ ++ if (!surface->UpdateYUVData(aVaDesc, aWidth, aHeight, mSurfaceCopy)) { ++ return nullptr; ++ } ++ ++ if (MOZ_UNLIKELY(!mTextureCreationWorks)) { ++ mTextureCreationWorks = Some(surface->VerifyTextureCreation()); ++ if (!*mTextureCreationWorks) { ++ DMABUF_LOG(" failed to create texture over DMABuf memory!"); + return nullptr; + } + } +- videoSurface->LockVAAPIData(aAVCodecContext, aAVFrame, aLib); ++ ++ if (!mSurfaceCopy) { ++ videoSurface->LockVAAPIData(aAVCodecContext, aAVFrame, aLib); ++ } + videoSurface->MarkAsUsed(); + return videoSurface; + } +diff -up firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.h.1809162 firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.h +--- firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.h.1809162 2023-01-12 21:02:00.000000000 +0100 ++++ firefox-109.0/dom/media/platforms/ffmpeg/FFmpegVideoFramePool.h 2023-01-17 14:23:30.004040571 +0100 +@@ -129,6 +129,8 @@ class VideoFramePool { + // We may fail to create texture over DMABuf memory due to driver bugs so + // check that before we export first DMABuf video frame. + Maybe mTextureCreationWorks; ++ // Copy decoded dmabuf surfaces so we can return them to ffmpeg immediately. ++ const bool mSurfaceCopy; + }; + + } // namespace mozilla +diff -up firefox-109.0/gfx/thebes/gfxPlatformGtk.cpp.1809162 firefox-109.0/gfx/thebes/gfxPlatformGtk.cpp +--- firefox-109.0/gfx/thebes/gfxPlatformGtk.cpp.1809162 2023-01-12 21:02:01.000000000 +0100 ++++ firefox-109.0/gfx/thebes/gfxPlatformGtk.cpp 2023-01-17 14:23:30.004040571 +0100 +@@ -253,6 +253,34 @@ bool gfxPlatformGtk::InitVAAPIConfig(boo + feature.ForceDisable(FeatureStatus::Unavailable, "Requires EGL", + "FEATURE_FAILURE_REQUIRES_EGL"_ns); + } ++ ++ if (feature.IsEnabled()) { ++ FeatureState& featureZeroCopyDecode = ++ gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY); ++ featureZeroCopyDecode.EnableByDefault(); ++ ++ if (!StaticPrefs::media_ffmpeg_vaapi_zero_copy_enabled_AtStartup()) { ++ featureZeroCopyDecode.UserDisable("Disabled by pref", ++ "FEATURE_FAILURE_USER_DISABLED"_ns); ++ } else { ++ if (NS_FAILED(gfxInfo->GetFeatureStatus( ++ nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, failureId, ++ &status))) { ++ featureZeroCopyDecode.DisableByDefault( ++ FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken", ++ "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns); ++ } else if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) { ++ featureZeroCopyDecode.DisableByDefault( ++ FeatureStatus::Blocked, "Blocklisted by gfxInfo", failureId); ++ } ++ if (StaticPrefs::media_ffmpeg_vaapi_zero_copy_force_enabled_AtStartup()) { ++ featureZeroCopyDecode.UserForceEnable("Force enabled by pref"); ++ } ++ if (featureZeroCopyDecode.IsEnabled()) { ++ gfxVars::SetHwDecodedVideoZeroCopy(true); ++ } ++ } ++ } + #else + feature.DisableByDefault(FeatureStatus::Unavailable, + "Wayland support missing", +diff -up firefox-109.0/modules/libpref/init/StaticPrefList.yaml.1809162 firefox-109.0/modules/libpref/init/StaticPrefList.yaml +--- firefox-109.0/modules/libpref/init/StaticPrefList.yaml.1809162 2023-01-12 21:02:07.000000000 +0100 ++++ firefox-109.0/modules/libpref/init/StaticPrefList.yaml 2023-01-17 14:23:30.005040605 +0100 +@@ -9836,6 +9836,14 @@ + type: RelaxedAtomicBool + value: false + mirror: always ++- name: media.ffmpeg.vaapi.zero-copy.enabled ++ type: bool ++ value: true ++ mirror: once ++- name: media.ffmpeg.vaapi.zero-copy.force-enabled ++ type: bool ++ value: false ++ mirror: once + #endif # MOZ_WIDGET_GTK + #endif # MOZ_FFMPEG + +diff -up firefox-109.0/widget/gtk/DMABufLibWrapper.cpp.1809162 firefox-109.0/widget/gtk/DMABufLibWrapper.cpp +--- firefox-109.0/widget/gtk/DMABufLibWrapper.cpp.1809162 2023-01-12 21:02:18.000000000 +0100 ++++ firefox-109.0/widget/gtk/DMABufLibWrapper.cpp 2023-01-17 14:23:30.005040605 +0100 +@@ -12,12 +12,17 @@ + #include "mozilla/StaticPrefs_media.h" + #include "mozilla/gfx/gfxVars.h" + #include "WidgetUtilsGtk.h" ++#include "gfxConfig.h" ++#include "nsIGfxInfo.h" ++#include "mozilla/Components.h" + + #include + #include + #include + #include + ++using namespace mozilla::gfx; ++ + namespace mozilla { + namespace widget { + +@@ -224,24 +229,13 @@ nsDMABufDevice::~nsDMABufDevice() { + int nsDMABufDevice::GetDRMFd() { return mDRMFd; } + + bool nsDMABufDevice::Configure(nsACString& aFailureId) { +- LOGDMABUF(("nsDMABufDevice::Configure()")); ++ if (mInitialized) { ++ return true; ++ } + +- MOZ_ASSERT(!mInitialized); ++ LOGDMABUF(("nsDMABufDevice::Configure()")); + mInitialized = true; + +- bool isDMABufUsed = ( +-#ifdef NIGHTLY_BUILD +- StaticPrefs::widget_dmabuf_textures_enabled() || +-#endif +- StaticPrefs::widget_dmabuf_webgl_enabled()); +- +- if (!isDMABufUsed) { +- // Disabled by user, just quit. +- LOGDMABUF(("IsDMABufEnabled(): Disabled by preferences.")); +- aFailureId = "FEATURE_FAILURE_NO_PREFS_ENABLED"; +- return false; +- } +- + if (!nsGbmLib::IsAvailable()) { + LOGDMABUF(("nsGbmLib is not available!")); + aFailureId = "FEATURE_FAILURE_NO_LIBGBM"; +@@ -327,5 +321,13 @@ nsDMABufDevice* GetDMABufDevice() { + return &dmaBufDevice; + } + ++nsDMABufDevice* GetAndConfigureDMABufDevice() { ++ nsCString failureId; ++ if (GetDMABufDevice()->Configure(failureId)) { ++ return GetDMABufDevice(); ++ } ++ return nullptr; ++} ++ + } // namespace widget + } // namespace mozilla +diff -up firefox-109.0/widget/gtk/DMABufLibWrapper.h.1809162 firefox-109.0/widget/gtk/DMABufLibWrapper.h +--- firefox-109.0/widget/gtk/DMABufLibWrapper.h.1809162 2023-01-12 21:02:18.000000000 +0100 ++++ firefox-109.0/widget/gtk/DMABufLibWrapper.h 2023-01-17 14:23:30.005040605 +0100 +@@ -215,6 +215,7 @@ class nsDMABufDevice { + }; + + nsDMABufDevice* GetDMABufDevice(); ++nsDMABufDevice* GetAndConfigureDMABufDevice(); + + } // namespace widget + } // namespace mozilla +diff -up firefox-109.0/widget/gtk/DMABufSurface.cpp.1809162 firefox-109.0/widget/gtk/DMABufSurface.cpp +--- firefox-109.0/widget/gtk/DMABufSurface.cpp.1809162 2023-01-12 21:02:18.000000000 +0100 ++++ firefox-109.0/widget/gtk/DMABufSurface.cpp 2023-01-17 14:23:30.006040639 +0100 +@@ -67,13 +67,14 @@ RefPtr ClaimSnapshotGLContext + nsCString discardFailureId; + sSnapshotContext = GLContextProvider::CreateHeadless({}, &discardFailureId); + if (!sSnapshotContext) { +- LOGDMABUF(("GetAsSourceSurface: Failed to create snapshot GLContext.")); ++ LOGDMABUF( ++ ("ClaimSnapshotGLContext: Failed to create snapshot GLContext.")); + return nullptr; + } + sSnapshotContext->mOwningThreadId = Nothing(); // No singular owner. + } + if (!sSnapshotContext->MakeCurrent()) { +- LOGDMABUF(("GetAsSourceSurface: Failed to make GLContext current.")); ++ LOGDMABUF(("ClaimSnapshotGLContext: Failed to make GLContext current.")); + return nullptr; + } + return sSnapshotContext; +@@ -84,6 +85,7 @@ void ReturnSnapshotGLContext(RefPtrmUseTLSIsCurrent); + if (!aGLContext->IsCurrent()) { ++ LOGDMABUF(("ReturnSnapshotGLContext() failed, is not current!")); + return; + } + const auto& gle = gl::GLContextEGL::Cast(aGLContext); +@@ -911,7 +913,7 @@ already_AddRefed DMABu + RefPtr surf = new DMABufSurfaceYUV(); + LOGDMABUF(("DMABufSurfaceYUV::CreateYUVSurface() UID %d from desc\n", + surf->GetUID())); +- if (!surf->UpdateYUVData(aDesc, aWidth, aHeight)) { ++ if (!surf->UpdateYUVData(aDesc, aWidth, aHeight, false)) { + return nullptr; + } + return surf.forget(); +@@ -975,16 +977,16 @@ void DMABufSurfaceYUV::CloseFileDescript + } + } + +-bool DMABufSurfaceYUV::UpdateYUVData(const VADRMPRIMESurfaceDescriptor& aDesc, +- int aWidth, int aHeight) { ++bool DMABufSurfaceYUV::ImportPRIMESurfaceDescriptor( ++ const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, int aHeight) { ++ LOGDMABUF(("DMABufSurfaceYUV::ImportPRIMESurfaceDescriptor() UID %d", mUID)); ++ // Already exists? ++ MOZ_DIAGNOSTIC_ASSERT(mDmabufFds[0] < 0); ++ + if (aDesc.num_layers > DMABUF_BUFFER_PLANES || + aDesc.num_objects > DMABUF_BUFFER_PLANES) { +- return false; +- } +- +- LOGDMABUF(("DMABufSurfaceYUV::UpdateYUVData() UID %d", mUID)); +- if (mDmabufFds[0] >= 0) { +- LOGDMABUF((" Already created!")); ++ LOGDMABUF((" Can't import, wrong layers/objects number (%d, %d)", ++ aDesc.num_layers, aDesc.num_objects)); + return false; + } + if (aDesc.fourcc == VA_FOURCC_NV12) { +@@ -994,8 +996,7 @@ bool DMABufSurfaceYUV::UpdateYUVData(con + } else if (aDesc.fourcc == VA_FOURCC_YV12) { + mSurfaceType = SURFACE_YUV420; + } else { +- LOGDMABUF(("UpdateYUVData(): Can't import surface data of 0x%x format", +- aDesc.fourcc)); ++ LOGDMABUF((" Can't import surface data of 0x%x format", aDesc.fourcc)); + return false; + } + +@@ -1003,12 +1004,6 @@ bool DMABufSurfaceYUV::UpdateYUVData(con + + for (unsigned int i = 0; i < aDesc.num_layers; i++) { + unsigned int object = aDesc.layers[i].object_index[0]; +- // Intel exports VA-API surfaces in one object,planes have the same FD. +- // AMD exports surfaces in two objects with different FDs. +- int fd = aDesc.objects[object].fd; +- bool dupFD = (object != i); +- mDmabufFds[i] = dupFD ? dup(fd) : fd; +- + mBufferModifiers[i] = aDesc.objects[object].drm_format_modifier; + mDrmFormats[i] = aDesc.layers[i].drm_format; + mOffsets[i] = aDesc.layers[i].offset[0]; +@@ -1017,18 +1012,104 @@ bool DMABufSurfaceYUV::UpdateYUVData(con + mHeightAligned[i] = aDesc.height >> i; + mWidth[i] = aWidth >> i; + mHeight[i] = aHeight >> i; +- + LOGDMABUF((" plane %d size %d x %d format %x", i, mWidth[i], mHeight[i], + mDrmFormats[i])); + } ++ return true; ++} + ++bool DMABufSurfaceYUV::MoveYUVDataImpl(const VADRMPRIMESurfaceDescriptor& aDesc, ++ int aWidth, int aHeight) { ++ if (!ImportPRIMESurfaceDescriptor(aDesc, aWidth, aHeight)) { ++ return false; ++ } ++ for (unsigned int i = 0; i < aDesc.num_layers; i++) { ++ unsigned int object = aDesc.layers[i].object_index[0]; ++ // Intel exports VA-API surfaces in one object,planes have the same FD. ++ // AMD exports surfaces in two objects with different FDs. ++ int fd = aDesc.objects[object].fd; ++ bool dupFD = (object != i); ++ mDmabufFds[i] = dupFD ? dup(fd) : fd; ++ } + return true; + } + +-bool DMABufSurfaceYUV::CreateYUVPlane(int aPlane, int aWidth, int aHeight, +- int aDrmFormat) { ++bool DMABufSurfaceYUV::CreateYUVPlane(int aPlane) { + LOGDMABUF(("DMABufSurfaceYUV::CreateYUVPlane() UID %d size %d x %d", mUID, +- aWidth, aHeight)); ++ mWidth[aPlane], mHeight[aPlane])); ++ ++ if (!GetAndConfigureDMABufDevice()->GetGbmDevice()) { ++ LOGDMABUF((" Missing GbmDevice!")); ++ return false; ++ } ++ ++ bool useModifiers = (mBufferModifiers[aPlane] != DRM_FORMAT_MOD_INVALID); ++ if (useModifiers) { ++ mGbmBufferObject[aPlane] = nsGbmLib::CreateWithModifiers( ++ GetDMABufDevice()->GetGbmDevice(), mWidth[aPlane], mHeight[aPlane], ++ mDrmFormats[aPlane], mBufferModifiers + aPlane, 1); ++ } else { ++ mGbmBufferObject[aPlane] = nsGbmLib::Create( ++ GetDMABufDevice()->GetGbmDevice(), mWidth[aPlane], mHeight[aPlane], ++ mDrmFormats[aPlane], GBM_BO_USE_RENDERING); ++ } ++ if (!mGbmBufferObject[aPlane]) { ++ LOGDMABUF((" Failed to create GbmBufferObject: %s", strerror(errno))); ++ return false; ++ } ++ ++ mStrides[aPlane] = nsGbmLib::GetStride(mGbmBufferObject[aPlane]); ++ mOffsets[aPlane] = nsGbmLib::GetOffset(mGbmBufferObject[aPlane], 0); ++ mWidthAligned[aPlane] = mWidth[aPlane]; ++ mHeightAligned[aPlane] = mHeight[aPlane]; ++ return true; ++} ++ ++bool DMABufSurfaceYUV::CopyYUVDataImpl(const VADRMPRIMESurfaceDescriptor& aDesc, ++ int aWidth, int aHeight) { ++ RefPtr tmpSurf = CreateYUVSurface(aDesc, aWidth, aHeight); ++ if (!tmpSurf) { ++ return false; ++ } ++ ++ if (!ImportPRIMESurfaceDescriptor(aDesc, aWidth, aHeight)) { ++ return false; ++ } ++ ++ StaticMutexAutoLock lock(sSnapshotContextMutex); ++ RefPtr context = ClaimSnapshotGLContext(); ++ auto releaseTextures = MakeScopeExit([&] { ++ tmpSurf->ReleaseTextures(); ++ ReleaseTextures(); ++ ReturnSnapshotGLContext(context); ++ }); ++ ++ for (int i = 0; i < mBufferPlaneCount; i++) { ++ if (!tmpSurf->CreateTexture(context, i)) { ++ return false; ++ } ++ if (!CreateYUVPlane(i) || !CreateTexture(context, i)) { ++ return false; ++ } ++ gfx::IntSize size(GetWidth(i), GetHeight(i)); ++ context->BlitHelper()->BlitTextureToTexture( ++ tmpSurf->GetTexture(i), GetTexture(i), size, size, LOCAL_GL_TEXTURE_2D, ++ LOCAL_GL_TEXTURE_2D); ++ } ++ return true; ++} ++ ++bool DMABufSurfaceYUV::UpdateYUVData(const VADRMPRIMESurfaceDescriptor& aDesc, ++ int aWidth, int aHeight, bool aCopy) { ++ LOGDMABUF(("DMABufSurfaceYUV::UpdateYUVData() UID %d copy %d", mUID, aCopy)); ++ return aCopy ? CopyYUVDataImpl(aDesc, aWidth, aHeight) ++ : MoveYUVDataImpl(aDesc, aWidth, aHeight); ++} ++ ++bool DMABufSurfaceYUV::CreateLinearYUVPlane(int aPlane, int aWidth, int aHeight, ++ int aDrmFormat) { ++ LOGDMABUF(("DMABufSurfaceYUV::CreateLinearYUVPlane() UID %d size %d x %d", ++ mUID, aWidth, aHeight)); + + if (!GetDMABufDevice()->GetGbmDevice()) { + LOGDMABUF((" Missing GbmDevice!")); +@@ -1118,13 +1199,13 @@ bool DMABufSurfaceYUV::Create(int aWidth + mSurfaceType = SURFACE_YUV420; + mBufferPlaneCount = 3; + +- if (!CreateYUVPlane(0, aWidth, aHeight, GBM_FORMAT_R8)) { ++ if (!CreateLinearYUVPlane(0, aWidth, aHeight, GBM_FORMAT_R8)) { + return false; + } +- if (!CreateYUVPlane(1, aWidth >> 1, aHeight >> 1, GBM_FORMAT_R8)) { ++ if (!CreateLinearYUVPlane(1, aWidth >> 1, aHeight >> 1, GBM_FORMAT_R8)) { + return false; + } +- if (!CreateYUVPlane(2, aWidth >> 1, aHeight >> 1, GBM_FORMAT_R8)) { ++ if (!CreateLinearYUVPlane(2, aWidth >> 1, aHeight >> 1, GBM_FORMAT_R8)) { + return false; + } + if (!aPixelData || !aLineSizes) { +diff -up firefox-109.0/widget/gtk/DMABufSurface.h.1809162 firefox-109.0/widget/gtk/DMABufSurface.h +--- firefox-109.0/widget/gtk/DMABufSurface.h.1809162 2023-01-12 21:02:18.000000000 +0100 ++++ firefox-109.0/widget/gtk/DMABufSurface.h 2023-01-17 14:23:30.006040639 +0100 +@@ -323,7 +323,7 @@ class DMABufSurfaceYUV : public DMABufSu + + bool UpdateYUVData(void** aPixelData, int* aLineSizes); + bool UpdateYUVData(const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, +- int aHeight); ++ int aHeight, bool aCopy); + + bool VerifyTextureCreation(); + +@@ -332,9 +332,18 @@ class DMABufSurfaceYUV : public DMABufSu + + bool Create(const mozilla::layers::SurfaceDescriptor& aDesc); + bool Create(int aWidth, int aHeight, void** aPixelData, int* aLineSizes); +- bool CreateYUVPlane(int aPlane, int aWidth, int aHeight, int aDrmFormat); ++ bool CreateYUVPlane(int aPlane); ++ bool CreateLinearYUVPlane(int aPlane, int aWidth, int aHeight, ++ int aDrmFormat); + void UpdateYUVPlane(int aPlane, void* aPixelData, int aLineSize); + ++ bool MoveYUVDataImpl(const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, ++ int aHeight); ++ bool CopyYUVDataImpl(const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, ++ int aHeight); ++ ++ bool ImportPRIMESurfaceDescriptor(const VADRMPRIMESurfaceDescriptor& aDesc, ++ int aWidth, int aHeight); + bool ImportSurfaceDescriptor( + const mozilla::layers::SurfaceDescriptorDMABuf& aDesc); + +diff -up firefox-109.0/widget/gtk/GfxInfo.cpp.1809162 firefox-109.0/widget/gtk/GfxInfo.cpp +--- firefox-109.0/widget/gtk/GfxInfo.cpp.1809162 2023-01-17 14:23:30.006040639 +0100 ++++ firefox-109.0/widget/gtk/GfxInfo.cpp 2023-01-17 14:24:42.116475502 +0100 +@@ -887,6 +887,40 @@ const nsTArray& GfxInfo:: + V(0, 0, 0, 0), "FEATURE_HARDWARE_VIDEO_DECODING_NO_LINUX_AMD", ""); + + //////////////////////////////////// ++ // FEATURE_HW_DECODED_VIDEO_ZERO_COPY ++ APPEND_TO_DRIVER_BLOCKLIST_EXT( ++ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, ++ DesktopEnvironment::All, WindowProtocol::All, DriverVendor::MesaAll, ++ DeviceFamily::All, nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, ++ nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_LESS_THAN, ++ V(21, 0, 0, 0), "FEATURE_HW_DECODED_VIDEO_ZERO_COPY", "Mesa 21.0.0.0"); ++ ++ // Disable on all NVIDIA hardware ++ APPEND_TO_DRIVER_BLOCKLIST_EXT( ++ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, ++ DesktopEnvironment::All, WindowProtocol::All, DriverVendor::All, ++ DeviceFamily::NvidiaAll, nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, ++ nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED, ++ V(0, 0, 0, 0), "FEATURE_HW_DECODED_VIDEO_ZERO_COPY_NO_LINUX_NVIDIA", ++ ""); ++ ++ // Disable on all AMD devices (Bug 1802844) ++ APPEND_TO_DRIVER_BLOCKLIST_EXT( ++ OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All, ++ DesktopEnvironment::All, WindowProtocol::All, DriverVendor::All, ++ DeviceFamily::AtiAll, nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, ++ nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_COMPARISON_IGNORED, ++ V(0, 0, 0, 0), "FEATURE_HW_DECODED_VIDEO_ZERO_COPY_NO_LINUX_AMD", ""); ++ ++ // As FEATURE_HW_DECODED_VIDEO_ZERO_COPY is allow listed feature ++ // we need to explicitly enable it on all Intel hardware. ++ APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Linux, DeviceFamily::IntelAll, ++ nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, ++ nsIGfxInfo::FEATURE_ALLOW_ALWAYS, ++ DRIVER_COMPARISON_IGNORED, V(0, 0, 0, 0), ++ "FEATURE_ROLLOUT_ALL"); ++ ++ //////////////////////////////////// + // FEATURE_WEBRENDER_PARTIAL_PRESENT + APPEND_TO_DRIVER_BLOCKLIST_EXT( + OperatingSystem::Linux, ScreenSizeStatus::All, BatteryStatus::All,