Bug 1735893 - Add pref to use NV12 when uploading software-decoded video to an IOSurface. r=bradwerth
authorMarkus Stange <mstange.moz@gmail.com>
Thu, 14 Oct 2021 20:17:02 +0000
changeset 595982 5b05c21bd9199c4e2cab2fac67b582123e644043
parent 595981 5bc725606c819815fe8e56465023fc24ecc28ffb
child 595983 bdfd88ac24907afcc06de7b0fd170d5a81ce8458
push id151530
push usermwoodrow@mozilla.com
push dateThu, 14 Oct 2021 20:19:24 +0000
treeherderautoland@5b05c21bd919 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbradwerth
bugs1735893
milestone95.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1735893 - Add pref to use NV12 when uploading software-decoded video to an IOSurface. r=bradwerth Differential Revision: https://phabricator.services.mozilla.com/D128512
gfx/layers/MacIOSurfaceImage.cpp
modules/libpref/init/StaticPrefList.yaml
--- a/gfx/layers/MacIOSurfaceImage.cpp
+++ b/gfx/layers/MacIOSurfaceImage.cpp
@@ -59,57 +59,87 @@ bool MacIOSurfaceImage::SetData(ImageCon
   RefPtr<MacIOSurfaceRecycleAllocator> allocator =
       aContainer->GetMacIOSurfaceRecycleAllocator();
 
   RefPtr<MacIOSurface> surf = allocator->Allocate(
       aData.mYSize, aData.mCbCrSize, aData.mYUVColorSpace, aData.mColorRange);
 
   surf->Lock(false);
 
-  // If the CbCrSize's height is half of the YSize's height, then we'll
-  // need to duplicate the CbCr data on every second row.
-  size_t heightScale = aData.mYSize.height / aData.mCbCrSize.height;
+  if (surf->GetFormat() == SurfaceFormat::YUV422) {
+    // If the CbCrSize's height is half of the YSize's height, then we'll
+    // need to duplicate the CbCr data on every second row.
+    size_t heightScale = aData.mYSize.height / aData.mCbCrSize.height;
 
-  MOZ_ASSERT(surf->GetFormat() == SurfaceFormat::YUV422);
+    // The underlying IOSurface has format
+    // kCVPixelFormatType_422YpCbCr8FullRange or
+    // kCVPixelFormatType_422YpCbCr8_yuvs, which uses a 4:2:2 Y`0 Cb Y`1 Cr
+    // layout. See CVPixelBuffer.h for the full list of format descriptions.
+    MOZ_ASSERT(aData.mYSize.height > 0);
+    uint8_t* dst = (uint8_t*)surf->GetBaseAddressOfPlane(0);
+    size_t stride = surf->GetBytesPerRow(0);
+    for (size_t i = 0; i < (size_t)aData.mYSize.height; i++) {
+      // Compute the row addresses. If the input was 4:2:0, then
+      // we divide i by 2, so that each source row of CbCr maps to
+      // two dest rows.
+      uint8_t* rowYSrc = aData.mYChannel + aData.mYStride * i;
+      uint8_t* rowCbSrc =
+          aData.mCbChannel + aData.mCbCrStride * (i / heightScale);
+      uint8_t* rowCrSrc =
+          aData.mCrChannel + aData.mCbCrStride * (i / heightScale);
+      uint8_t* rowDst = dst + stride * i;
+
+      // Iterate across the CbCr width (which we have guaranteed to be half of
+      // the surface width), and write two 16bit pixels each time.
+      for (size_t j = 0; j < (size_t)aData.mCbCrSize.width; j++) {
+        *rowDst = *rowYSrc;
+        rowDst++;
+        rowYSrc++;
+
+        *rowDst = *rowCbSrc;
+        rowDst++;
+        rowCbSrc++;
 
-  // The underlying IOSurface has format kCVPixelFormatType_422YpCbCr8FullRange
-  // or kCVPixelFormatType_422YpCbCr8_yuvs, which uses a 4:2:2 Y`0 Cb Y`1 Cr
-  // layout. See CVPixelBuffer.h for the full list of format descriptions.
-  MOZ_ASSERT(aData.mYSize.height > 0);
-  uint8_t* dst = (uint8_t*)surf->GetBaseAddressOfPlane(0);
-  size_t stride = surf->GetBytesPerRow(0);
-  for (size_t i = 0; i < (size_t)aData.mYSize.height; i++) {
-    // Compute the row addresses. If the input was 4:2:0, then
-    // we divide i by 2, so that each source row of CbCr maps to
-    // two dest rows.
-    uint8_t* rowYSrc = aData.mYChannel + aData.mYStride * i;
-    uint8_t* rowCbSrc =
-        aData.mCbChannel + aData.mCbCrStride * (i / heightScale);
-    uint8_t* rowCrSrc =
-        aData.mCrChannel + aData.mCbCrStride * (i / heightScale);
-    uint8_t* rowDst = dst + stride * i;
+        *rowDst = *rowYSrc;
+        rowDst++;
+        rowYSrc++;
+
+        *rowDst = *rowCrSrc;
+        rowDst++;
+        rowCrSrc++;
+      }
+    }
+  } else if (surf->GetFormat() == SurfaceFormat::NV12) {
+    MOZ_ASSERT(aData.mYSize.height > 0);
+    uint8_t* dst = (uint8_t*)surf->GetBaseAddressOfPlane(0);
+    size_t stride = surf->GetBytesPerRow(0);
+    for (size_t i = 0; i < (size_t)aData.mYSize.height; i++) {
+      uint8_t* rowSrc = aData.mYChannel + aData.mYStride * i;
+      uint8_t* rowDst = dst + stride * i;
+      memcpy(rowDst, rowSrc, aData.mYSize.width);
+    }
 
-    // Iterate across the CbCr width (which we have guaranteed to be half of
-    // the surface width), and write two 16bit pixels each time.
-    for (size_t j = 0; j < (size_t)aData.mCbCrSize.width; j++) {
-      *rowDst = *rowYSrc;
-      rowDst++;
-      rowYSrc++;
+    // Copy and interleave the Cb and Cr channels.
+    MOZ_ASSERT(aData.mCbCrSize.height > 0);
+    dst = (uint8_t*)surf->GetBaseAddressOfPlane(1);
+    stride = surf->GetBytesPerRow(1);
+    for (size_t i = 0; i < (size_t)aData.mCbCrSize.height; i++) {
+      uint8_t* rowCbSrc = aData.mCbChannel + aData.mCbCrStride * i;
+      uint8_t* rowCrSrc = aData.mCrChannel + aData.mCbCrStride * i;
+      uint8_t* rowDst = dst + stride * i;
 
-      *rowDst = *rowCbSrc;
-      rowDst++;
-      rowCbSrc++;
+      for (size_t j = 0; j < (size_t)aData.mCbCrSize.width; j++) {
+        *rowDst = *rowCbSrc;
+        rowDst++;
+        rowCbSrc++;
 
-      *rowDst = *rowYSrc;
-      rowDst++;
-      rowYSrc++;
-
-      *rowDst = *rowCrSrc;
-      rowDst++;
-      rowCrSrc++;
+        *rowDst = *rowCrSrc;
+        rowDst++;
+        rowCrSrc++;
+      }
     }
   }
 
   surf->Unlock(false);
   mSurface = surf;
   mPictureRect = aData.GetPictureRect();
   return true;
 }
@@ -132,18 +162,23 @@ already_AddRefed<MacIOSurface> MacIOSurf
     if (!result && !::IOSurfaceIsInUse(surf.get())) {
       result = new MacIOSurface(surf, false, aYUVColorSpace);
     }
 
     mSurfaces.AppendElement(surf);
   }
 
   if (!result) {
-    result =
-        MacIOSurface::CreateYUV422Surface(aYSize, aYUVColorSpace, aColorRange);
+    if (StaticPrefs::layers_iosurfaceimage_use_nv12_AtStartup()) {
+      result = MacIOSurface::CreateNV12Surface(aYSize, aCbCrSize,
+                                               aYUVColorSpace, aColorRange);
+    } else {
+      result = MacIOSurface::CreateYUV422Surface(aYSize, aYUVColorSpace,
+                                                 aColorRange);
+    }
 
     if (mSurfaces.Length() <
         StaticPrefs::layers_iosurfaceimage_recycle_limit()) {
       mSurfaces.AppendElement(result->GetIOSurfaceRef());
     }
   }
 
   return result.forget();
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -6527,16 +6527,21 @@
   value: true
   mirror: once
 
 - name: layers.iosurfaceimage.recycle-limit
   type: RelaxedAtomicUint32
   value: 15
   mirror: always
 
+- name: layers.iosurfaceimage.use-nv12
+  type: bool
+  value: false
+  mirror: once
+
 #---------------------------------------------------------------------------
 # Prefs starting with "layout."
 #---------------------------------------------------------------------------
 
 # Debug-only pref to force enable the AccessibleCaret. If you want to
 # control AccessibleCaret by mouse, you'll need to set
 # "layout.accessiblecaret.hide_carets_for_mouse_input" to false.
 - name: layout.accessiblecaret.enabled