Bug 1120294 - Use A8 format svg mask and refactor svg neon code. r=longsonr
authorEthan Lin <etlin@mozilla.com>
Mon, 12 Jan 2015 07:36:00 -0500
changeset 223592 da63d41b57e9de3d91d1660e36fc16a1ef2fa189
parent 223591 1c0b0e3074c356d94d8eb981b1fb930fc7cd2e75
child 223593 fba277ed63b8cb4b65d6978d2e02a64349bf169d
push id28098
push userkwierso@gmail.com
push dateWed, 14 Jan 2015 00:52:19 +0000
treeherdermozilla-central@e978b8bc5c45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs1120294
milestone38.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 1120294 - Use A8 format svg mask and refactor svg neon code. r=longsonr
layout/svg/nsSVGMaskFrame.cpp
layout/svg/nsSVGMaskFrameNEON.cpp
layout/svg/nsSVGMaskFrameNEON.h
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -55,116 +55,133 @@ 161, 163, 164, 166, 168, 170, 171, 173,
 175, 177, 179, 181, 183, 184, 186, 188,
 190, 192, 194, 196, 198, 200, 202, 204,
 206, 208, 210, 212, 214, 216, 218, 220,
 222, 224, 226, 229, 231, 233, 235, 237,
 239, 242, 244, 246, 248, 250, 253, 255
 };
 
 static void
-ComputesRGBLuminanceMask(uint8_t *aData,
-                         int32_t aStride,
+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(aData, aStride, aSize, aOpacity);
+    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 offset = aStride - 4 * aSize.width;
-  uint8_t *pixel = aData;
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t destOffset = aDestStride - aSize.width;
+  uint8_t *destPixel = aDestData;
 
   for (int32_t y = 0; y < aSize.height; y++) {
     for (int32_t x = 0; x < aSize.width; x++) {
-      uint8_t a = pixel[GFX_ARGB32_OFFSET_A];
+      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
 
-      uint8_t luminance;
       if (a) {
-        luminance = (redFactor * pixel[GFX_ARGB32_OFFSET_R] +
-                     greenFactor * pixel[GFX_ARGB32_OFFSET_G] +
-                     blueFactor * pixel[GFX_ARGB32_OFFSET_B]) >> 8;
+        *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] +
+                      greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
+                      blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
       } else {
-        luminance = 0;
+        *destPixel = 0;
       }
-      memset(pixel, luminance, 4);
-      pixel += 4;
+      sourcePixel += 4;
+      destPixel++;
     }
-    pixel += offset;
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
   }
 }
 
 static void
-ComputeLinearRGBLuminanceMask(uint8_t *aData,
-                              int32_t aStride,
+ComputeLinearRGBLuminanceMask(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
-  int32_t offset = aStride - 4 * aSize.width;
-  uint8_t *pixel = aData;
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t destOffset = aDestStride - aSize.width;
+  uint8_t *destPixel = aDestData;
 
   for (int32_t y = 0; y < aSize.height; y++) {
     for (int32_t x = 0; x < aSize.width; x++) {
-      uint8_t a = pixel[GFX_ARGB32_OFFSET_A];
+      uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
 
-      uint8_t luminance;
       // unpremultiply
       if (a) {
+        uint8_t tempPixel[4];
+        memcpy(tempPixel, sourcePixel, 4);
         if (a != 255) {
-          pixel[GFX_ARGB32_OFFSET_B] =
-            (255 * pixel[GFX_ARGB32_OFFSET_B]) / a;
-          pixel[GFX_ARGB32_OFFSET_G] =
-            (255 * pixel[GFX_ARGB32_OFFSET_G]) / a;
-          pixel[GFX_ARGB32_OFFSET_R] =
-            (255 * pixel[GFX_ARGB32_OFFSET_R]) / a;
+          tempPixel[GFX_ARGB32_OFFSET_B] =
+            (255 * tempPixel[GFX_ARGB32_OFFSET_B]) / a;
+          tempPixel[GFX_ARGB32_OFFSET_G] =
+            (255 * tempPixel[GFX_ARGB32_OFFSET_G]) / a;
+          tempPixel[GFX_ARGB32_OFFSET_R] =
+            (255 * tempPixel[GFX_ARGB32_OFFSET_R]) / a;
         }
 
         /* sRGB -> linearRGB -> intensity */
-        luminance =
+        *destPixel =
           static_cast<uint8_t>
-                     (((gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_R]] *
+                     (((gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_R]] *
                         redFactor +
-                        gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_G]] *
+                        gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_G]] *
                         greenFactor +
-                        gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_B]] *
+                        gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_B]] *
                         blueFactor) >> 8) * (a / 255.0f));
       } else {
-        luminance = 0;
+        *destPixel = 0;
       }
-      memset(pixel, luminance, 4);
-      pixel += 4;
+      sourcePixel += 4;
+      destPixel++;
     }
-    pixel += offset;
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
   }
 }
 
 static void
-ComputeAlphaMask(uint8_t *aData,
-                 int32_t aStride,
+ComputeAlphaMask(const uint8_t *aSourceData,
+                 int32_t aSourceStride,
+                 uint8_t *aDestData,
+                 int32_t aDestStride,
                  const IntSize &aSize,
                  float aOpacity)
 {
-  int32_t offset = aStride - 4 * aSize.width;
-  uint8_t *pixel = aData;
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t destOffset = aDestStride - aSize.width;
+  uint8_t *destPixel = aDestData;
 
   for (int32_t y = 0; y < aSize.height; y++) {
     for (int32_t x = 0; x < aSize.width; x++) {
-      uint8_t luminance = pixel[GFX_ARGB32_OFFSET_A] * aOpacity;
-      memset(pixel, luminance, 4);
-      pixel += 4;
+      *destPixel = sourcePixel[GFX_ARGB32_OFFSET_A] * aOpacity;
+      sourcePixel += 4;
+      destPixel++;
     }
-    pixel += offset;
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
   }
 }
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsIFrame*
 NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
@@ -255,40 +272,64 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(gf
   }
 
   RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
   if (!maskSnapshot) {
     return nullptr;
   }
   RefPtr<DataSourceSurface> maskSurface = maskSnapshot->GetDataSurface();
   DataSourceSurface::MappedSurface map;
-  if (!maskSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) {
+  if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
+    return nullptr;
+  }
+
+  // Create alpha channel mask for output
+  RefPtr<DrawTarget> destMaskDT =
+    Factory::CreateDrawTarget(BackendType::CAIRO, maskSurfaceSize,
+                              SurfaceFormat::A8);
+  if (!destMaskDT) {
+    return nullptr;
+  }
+  RefPtr<SourceSurface> destMaskSnapshot = destMaskDT->Snapshot();
+  if (!destMaskSnapshot) {
+    return nullptr;
+  }
+  RefPtr<DataSourceSurface> destMaskSurface = destMaskSnapshot->GetDataSurface();
+  DataSourceSurface::MappedSurface destMap;
+  if (!destMaskSurface->Map(DataSourceSurface::MapType::READ_WRITE, &destMap)) {
     return nullptr;
   }
 
   if (StyleSVGReset()->mMaskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
     if (StyleSVG()->mColorInterpolation ==
         NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
-      ComputeLinearRGBLuminanceMask(map.mData, map.mStride, maskSurfaceSize, aOpacity);
+      ComputeLinearRGBLuminanceMask(map.mData, map.mStride,
+                                    destMap.mData, destMap.mStride,
+                                    maskSurfaceSize, aOpacity);
     } else {
-      ComputesRGBLuminanceMask(map.mData, map.mStride, maskSurfaceSize, aOpacity);
+      ComputesRGBLuminanceMask(map.mData, map.mStride,
+                               destMap.mData, destMap.mStride,
+                               maskSurfaceSize, aOpacity);
     }
   } else {
-    ComputeAlphaMask(map.mData, map.mStride, maskSurfaceSize, aOpacity);
+      ComputeAlphaMask(map.mData, map.mStride,
+                       destMap.mData, destMap.mStride,
+                       maskSurfaceSize, aOpacity);
   }
 
   maskSurface->Unmap();
+  destMaskSurface->Unmap();
 
   // Moz2D transforms in the opposite direction to Thebes
   if (!maskSurfaceMatrix.Invert()) {
     return nullptr;
   }
 
   *aMaskTransform = ToMatrix(maskSurfaceMatrix);
-  return maskSurface;
+  return destMaskSurface;
 }
 
 nsresult
 nsSVGMaskFrame::AttributeChanged(int32_t  aNameSpaceID,
                                  nsIAtom* aAttribute,
                                  int32_t  aModType)
 {
   if (aNameSpaceID == kNameSpaceID_None &&
--- a/layout/svg/nsSVGMaskFrameNEON.cpp
+++ b/layout/svg/nsSVGMaskFrameNEON.cpp
@@ -3,69 +3,69 @@
  * 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 "nsSVGMaskFrameNEON.h"
 #include "nsSVGMaskFrame.h"
 #include <arm_neon.h>
 
 void
-ComputesRGBLuminanceMask_NEON(uint8_t *aData,
-                              int32_t aStride,
+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
-  uint8_t *pixel = aData;
-  int32_t offset = aStride - 4 * aSize.width;
+  const uint8_t *sourcePixel = aSourceData;
+  int32_t sourceOffset = aSourceStride - 4 * aSize.width;
+  uint8_t *destPixel = aDestData;
+  int32_t destOffset = aDestStride - aSize.width;
 
-  // Set the value to zero if the alpha is zero
-  for (int32_t y = 0; y < aSize.height; y++) {
-    for (int32_t x = 0; x < aSize.width; x++) {
-      if (!pixel[GFX_ARGB32_OFFSET_A]) {
-        memset(pixel, 0, 4);
-      }
-      pixel += 4;
-    }
-    pixel += offset;
-  }
-
-  pixel = aData;
+  sourcePixel = aSourceData;
   int32_t remainderWidth = aSize.width % 8;
   int32_t roundedWidth = aSize.width - remainderWidth;
   uint16x8_t temp;
   uint8x8_t gray;
-  uint8x8x4_t result;
-  uint8x8_t redVec = vdup_n_u8(redFactor);
-  uint8x8_t greenVec = vdup_n_u8(greenFactor);
-  uint8x8_t blueVec = vdup_n_u8(blueFactor);
+  uint8x8_t redVector = vdup_n_u8(redFactor);
+  uint8x8_t greenVector = vdup_n_u8(greenFactor);
+  uint8x8_t blueVector = vdup_n_u8(blueFactor);
+  uint8x8_t zeroVector = vdup_n_u8(0);
+  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 
+    // Calculate luminance by neon with 8 pixels per loop
     for (int32_t x = 0; x < roundedWidth; x += 8) {
-      uint8x8x4_t argb  = vld4_u8(pixel);
-      temp = vmull_u8(argb.val[GFX_ARGB32_OFFSET_R], redVec); // temp = red * redFactor
-      temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_G], greenVec); // temp += green * greenFactor
-      temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_B], blueVec); // temp += blue * blueFactor
+      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
 
-      // Put the result to the 8 pixels in argb format
-      result.val[0] = gray;
-      result.val[1] = gray;
-      result.val[2] = gray;
-      result.val[3] = gray;
-      vst4_u8(pixel, result);
-      pixel += 8 * 4;
+      // Check alpha value
+      uint8x8_t alphaVector = vcgt_u8(argb.val[GFX_ARGB32_OFFSET_A], zeroVector);
+      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++) {
-      pixel[0] = (redFactor * pixel[GFX_ARGB32_OFFSET_R] +
-                  greenFactor * pixel[GFX_ARGB32_OFFSET_G] +
-                  blueFactor * pixel[GFX_ARGB32_OFFSET_B]) >> 8;
-      memset(pixel + 1, pixel[0], 3);
-      pixel += 4;
+      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++;
     }
-    pixel += offset;
+    sourcePixel += sourceOffset;
+    destPixel += destOffset;
   }
 }
 
--- a/layout/svg/nsSVGMaskFrameNEON.h
+++ b/layout/svg/nsSVGMaskFrameNEON.h
@@ -6,14 +6,16 @@
 #ifndef __NS_SVGMASKFRAMENEON_H__
 #define __NS_SVGMASKFRAMENEON_H__
 
 #include "mozilla/gfx/2D.h"
 
 using namespace mozilla::gfx;
 
 void
-ComputesRGBLuminanceMask_NEON(uint8_t *aData,
-                              int32_t aStride,
+ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
+                              int32_t aSourceStride,
+                              uint8_t *aDestData,
+                              int32_t aDestStride,
                               const IntSize &aSize,
                               float aOpacity);
 
 #endif /* __NS_SVGMASKFRAMENEON_H__ */