Bug 1359527. Fixup DrawTarget::IntoLuminance mismerge. r=mchang
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Fri, 09 Jun 2017 10:57:44 -0400
changeset 411378 da58840d7f3d0e38299caf95a6299b670172a30b
parent 411377 4b6b2e9e5492d8e2606f4daa145f1f16ef6bbfb4
child 411379 7a7047b62b518b662751bff2cf9f2e35398636f9
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmchang
bugs1359527
milestone55.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 1359527. Fixup DrawTarget::IntoLuminance mismerge. r=mchang This adds back the NEON code and fixes up a couple of other pieces
gfx/2d/DrawTarget.cpp
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/LuminanceNEON.cpp
gfx/2d/LuminanceNEON.h
gfx/2d/moz.build
layout/svg/nsSVGMaskFrame.cpp
--- a/gfx/2d/DrawTarget.cpp
+++ b/gfx/2d/DrawTarget.cpp
@@ -6,16 +6,17 @@
 #include "2D.h"
 #include "Logging.h"
 #include "PathHelpers.h"
 
 #include "DrawTargetCapture.h"
 
 #ifdef BUILD_ARM_NEON
 #include "mozilla/arm.h"
+#include "LuminanceNEON.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
 /**
  * Byte offsets of channels in a native packed gfxColor or cairo image surface.
  */
@@ -71,16 +72,25 @@ 239, 242, 244, 246, 248, 250, 253, 255
 static void
 ComputesRGBLuminanceMask(const uint8_t *aSourceData,
                          int32_t aSourceStride,
                          uint8_t *aDestData,
                          int32_t aDestStride,
                          const IntSize &aSize,
                          float aOpacity)
 {
+#ifdef BUILD_ARM_NEON
+  if (mozilla::supports_neon()) {
+    ComputesRGBLuminanceMask_NEON(aSourceData, aSourceStride,
+                                  aDestData, aDestStride,
+                                  aSize, aOpacity);
+    return;
+  }
+#endif
+
   int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
   int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
   int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
   int32_t sourceOffset = aSourceStride - 4 * aSize.width;
   const uint8_t *sourcePixel = aSourceData;
   int32_t destOffset = aDestStride - aSize.width;
   uint8_t *destPixel = aDestData;
 
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -111,17 +111,16 @@ DrawTargetD2D1::EnsureLuminanceEffect()
   if (FAILED(hr)) {
     gfxWarning() << "Failed to create luminance effect. Code: " << hexa(hr);
   }
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetD2D1::IntoLuminanceSource(LuminanceType aLuminanceType, float aOpacity)
 {
-  //return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
   if (aLuminanceType != LuminanceType::LUMINANCE) {
     return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
   }
 
   // Create the luminance effect
   EnsureLuminanceEffect();
   mLuminanceEffect->SetInput(0, mBitmap);
 
new file mode 100644
--- /dev/null
+++ b/gfx/2d/LuminanceNEON.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <arm_neon.h>
+#include "LuminanceNEON.h"
+
+using namespace mozilla::gfx;
+
+/**
+ * Byte offsets of channels in a native packed gfxColor or cairo image surface.
+ */
+#ifdef IS_BIG_ENDIAN
+#define GFX_ARGB32_OFFSET_A 0
+#define GFX_ARGB32_OFFSET_R 1
+#define GFX_ARGB32_OFFSET_G 2
+#define GFX_ARGB32_OFFSET_B 3
+#else
+#define GFX_ARGB32_OFFSET_A 3
+#define GFX_ARGB32_OFFSET_R 2
+#define GFX_ARGB32_OFFSET_G 1
+#define GFX_ARGB32_OFFSET_B 0
+#endif
+
+
+void
+ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
+                              int32_t aSourceStride,
+                              uint8_t *aDestData,
+                              int32_t aDestStride,
+                              const IntSize &aSize,
+                              float aOpacity)
+{
+  int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
+  int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
+  int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  uint8_t *destPixel = aDestData;
+  int32_t destOffset = aDestStride - aSize.width;
+
+  sourcePixel = aSourceData;
+  int32_t remainderWidth = aSize.width % 8;
+  int32_t roundedWidth = aSize.width - remainderWidth;
+  uint16x8_t temp;
+  uint8x8_t gray;
+  uint8x8_t redVector = vdup_n_u8(redFactor);
+  uint8x8_t greenVector = vdup_n_u8(greenFactor);
+  uint8x8_t blueVector = vdup_n_u8(blueFactor);
+  uint8x8_t fullBitVector = vdup_n_u8(255);
+  uint8x8_t oneVector = vdup_n_u8(1);
+  for (int32_t y = 0; y < aSize.height; y++) {
+    // Calculate luminance by neon with 8 pixels per loop
+    for (int32_t x = 0; x < roundedWidth; x += 8) {
+      uint8x8x4_t argb  = vld4_u8(sourcePixel);
+      temp = vmull_u8(argb.val[GFX_ARGB32_OFFSET_R], redVector); // temp = red * redFactor
+      temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_G], greenVector); // temp += green * greenFactor
+      temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_B], blueVector); // temp += blue * blueFactor
+      gray = vshrn_n_u16(temp, 8); // gray = temp >> 8
+
+      // Check alpha value
+      uint8x8_t alphaVector = vtst_u8(argb.val[GFX_ARGB32_OFFSET_A], fullBitVector);
+      gray = vmul_u8(gray, vand_u8(alphaVector, oneVector));
+
+      // Put the result to the 8 pixels
+      vst1_u8(destPixel, gray);
+      sourcePixel += 8 * 4;
+      destPixel += 8;
+    }
+
+    // Calculate the rest pixels of the line by cpu
+    for (int32_t x = 0; x < remainderWidth; x++) {
+      if (sourcePixel[GFX_ARGB32_OFFSET_A] > 0) {
+        *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R]+
+                      greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
+                      blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
+      } else {
+        *destPixel = 0;
+      }
+      sourcePixel += 4;
+      destPixel++;
+    }
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/2d/LuminanceNEON.h
@@ -0,0 +1,19 @@
+/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* this source code form is subject to the terms of the mozilla public
+ * license, v. 2.0. if a copy of the mpl was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __LUMINANCENEON_H__
+#define __LUMINANCENEON_H__
+
+#include "mozilla/gfx/Point.h"
+
+void
+ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
+                              int32_t aSourceStride,
+                              uint8_t *aDestData,
+                              int32_t aDestStride,
+                              const mozilla::gfx::IntSize &aSize,
+                              float aOpacity);
+
+#endif /* __LUMINANCENEON_H__ */
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -215,19 +215,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     SOURCES += [
         'MacIOSurface.cpp',
         'QuartzSupport.mm',
     ]
 
 if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
     SOURCES += [
         'BlurNEON.cpp',
+        'LuminanceNEON.cpp',
         'SwizzleNEON.cpp',
     ]
     SOURCES['BlurNEON.cpp'].flags += CONFIG['NEON_FLAGS']
+    SOURCES['LuminanceNEON.cpp'].flags += CONFIG['NEON_FLAGS']
     SOURCES['SwizzleNEON.cpp'].flags += CONFIG['NEON_FLAGS']
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 for var in ('USE_CAIRO', 'MOZ2D_HAS_MOZ_CAIRO'):
     DEFINES[var] = True
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -119,23 +119,23 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(Ma
     gfxMatrix m = mMatrixForChildren;
     if (kid->GetContent()->IsSVGElement()) {
       m = static_cast<nsSVGElement*>(kid->GetContent())->
             PrependLocalTransformsTo(m, eUserSpaceToParent);
     }
     nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams);
   }
 
-  if (StyleSVG()->mColorInterpolation ==
-    NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
-    maskType = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
-  }
-
   RefPtr<SourceSurface> surface;
   if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
+    if (StyleSVG()->mColorInterpolation ==
+        NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
+      maskType = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
+    }
+
     RefPtr<SourceSurface> maskSnapshot =
       maskDT->IntoLuminanceSource(GetLuminanceType(maskType),
                                   aParams.opacity);
     if (!maskSnapshot) {
       return nullptr;
     }
     surface = maskSnapshot.forget();
   } else {