Bug 711043 - Make filters code more consistent in performance. r=roc
☠☠ backed out by 09cc025b1f42 ☠ ☠
authorCameron McCormack <cam@mcc.id.au>
Tue, 20 Mar 2012 12:49:13 +1100
changeset 89787 47e84e1cc50f5dea0d0104d773b95633519637ac
parent 89786 14cb8f3effcbeb04e5c66a969c67a51040d7c488
child 89788 09cc025b1f42f9782bba90c80ed9063f856429d1
push id7319
push usercmccormack@mozilla.com
push dateTue, 20 Mar 2012 01:49:38 +0000
treeherdermozilla-inbound@47e84e1cc50f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs711043
milestone14.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 711043 - Make filters code more consistent in performance. r=roc
content/svg/content/src/nsSVGFilters.cpp
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -3795,71 +3795,43 @@ nsSVGFEMorphologyElement::Filter(nsSVGFi
   }
   if (rx == 0 && ry == 0) {
     return NS_OK;
   }
 
   PRUint8* sourceData = aSources[0]->mImage->Data();
   PRUint8* targetData = aTarget->mImage->Data();
   PRUint32 stride = aTarget->mImage->Stride();
-  PRUint32 xExt[4], yExt[4];  // X, Y indices of RGBA extrema
   PRUint8 extrema[4];         // RGBA magnitude of extrema
   PRUint16 op = mEnumAttributes[OPERATOR].GetAnimValue();
 
-  /* Scan the kernel for each pixel to determine max/min RGBA values.  Note that
-   * as we advance in the x direction, each kernel overlaps the previous kernel.
-   * Thus, we can avoid iterating over the entire kernel by comparing the
-   * leading edge of the new kernel against the extrema found in the previous
-   * kernel.   We must still scan the entire kernel if the previous extrema do
-   * not fall within the current kernel or if we are starting a new row.
-   */
+  // Scan the kernel for each pixel to determine max/min RGBA values.
   for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
     PRUint32 startY = NS_MAX(0, y - ry);
     // We need to read pixels not just in 'rect', which is limited to
     // the dirty part of our filter primitive subregion, but all pixels in
     // the given radii from the source surface, so use the surface size here.
     PRUint32 endY = NS_MIN(y + ry, instance->GetSurfaceHeight() - 1);
     for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
       PRUint32 startX = NS_MAX(0, x - rx);
       PRUint32 endX = NS_MIN(x + rx, instance->GetSurfaceWidth() - 1);
       PRUint32 targIndex = y * stride + 4 * x;
 
-      // We need to scan the entire kernel
-      if (x == rect.x || xExt[0]  <= startX || xExt[1] <= startX ||
-          xExt[2] <= startX || xExt[3] <= startX) {
-        PRUint32 i;
-        for (i = 0; i < 4; i++) {
-          extrema[i] = sourceData[targIndex + i];
-        }
-        for (PRUint32 y1 = startY; y1 <= endY; y1++) {
-          for (PRUint32 x1 = startX; x1 <= endX; x1++) {
-            for (i = 0; i < 4; i++) {
-              PRUint8 pixel = sourceData[y1 * stride + 4 * x1 + i];
-              if ((extrema[i] >= pixel &&
-                   op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) ||
-                  (extrema[i] <= pixel &&
-                   op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) {
-                extrema[i] = pixel;
-                xExt[i] = x1;
-                yExt[i] = y1;
-              }
-            }
-          }
-        }
-      } else { // We only need to look at the newest column
-        for (PRUint32 y1 = startY; y1 <= endY; y1++) {
+      for (PRUint32 i = 0; i < 4; i++) {
+        extrema[i] = sourceData[targIndex + i];
+      }
+      for (PRUint32 y1 = startY; y1 <= endY; y1++) {
+        for (PRUint32 x1 = startX; x1 <= endX; x1++) {
           for (PRUint32 i = 0; i < 4; i++) {
-            PRUint8 pixel = sourceData[y1 * stride + 4 * endX + i];
-            if ((extrema[i] >= pixel &&
+            PRUint8 pixel = sourceData[y1 * stride + 4 * x1 + i];
+            if ((extrema[i] > pixel &&
                  op == nsSVGFEMorphologyElement::SVG_OPERATOR_ERODE) ||
-                (extrema[i] <= pixel &&
+                (extrema[i] < pixel &&
                  op == nsSVGFEMorphologyElement::SVG_OPERATOR_DILATE)) {
-                extrema[i] = pixel;
-                xExt[i] = endX;
-                yExt[i] = y1;
+              extrema[i] = pixel;
             }
           }
         }
       }
       targetData[targIndex  ] = extrema[0];
       targetData[targIndex+1] = extrema[1];
       targetData[targIndex+2] = extrema[2];
       targetData[targIndex+3] = extrema[3];
@@ -5114,24 +5086,21 @@ nsSVGFELightingElement::Filter(nsSVGFilt
 
       if (spotLight) {
         float S[3];
         S[0] = pointsAt[0] - lightPos[0];
         S[1] = pointsAt[1] - lightPos[1];
         S[2] = pointsAt[2] - lightPos[2];
         NORMALIZE(S);
         float dot = -DOT(L, S);
-        if (dot < cosConeAngle) {
-          color = NS_RGB(0, 0, 0);
-        } else {
-          float tmp = pow(dot, specularExponent);
-          color = NS_RGB(PRUint8(NS_GET_R(lightColor) * tmp),
-                         PRUint8(NS_GET_G(lightColor) * tmp),
-                         PRUint8(NS_GET_B(lightColor) * tmp));
-        }
+        if (dot < cosConeAngle) dot = 0;
+        float tmp = pow(dot, specularExponent);
+        color = NS_RGB(PRUint8(NS_GET_R(lightColor) * tmp),
+                       PRUint8(NS_GET_G(lightColor) * tmp),
+                       PRUint8(NS_GET_B(lightColor) * tmp));
       } else {
         color = lightColor;
       }
 
       LightPixel(N, L, color, targetData + index);
     }
   }
 
@@ -5288,29 +5257,24 @@ nsSVGFEDiffuseLightingElement::Attribute
 
 void
 nsSVGFEDiffuseLightingElement::LightPixel(const float *N, const float *L,
                                           nscolor color, PRUint8 *targetData)
 {
   float diffuseNL =
     mNumberAttributes[DIFFUSE_CONSTANT].GetAnimValue() * DOT(N, L);
 
-  if (diffuseNL > 0) {
-    targetData[GFX_ARGB32_OFFSET_B] =
-      NS_MIN(PRUint32(diffuseNL * NS_GET_B(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_G] =
-      NS_MIN(PRUint32(diffuseNL * NS_GET_G(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_R] =
-      NS_MIN(PRUint32(diffuseNL * NS_GET_R(color)), 255U);
-  } else {
-    targetData[GFX_ARGB32_OFFSET_B] = 0;
-    targetData[GFX_ARGB32_OFFSET_G] = 0;
-    targetData[GFX_ARGB32_OFFSET_R] = 0;
-  }
-
+  if (diffuseNL < 0) diffuseNL = 0;
+
+  targetData[GFX_ARGB32_OFFSET_B] =
+    NS_MIN(PRUint32(diffuseNL * NS_GET_B(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_G] =
+    NS_MIN(PRUint32(diffuseNL * NS_GET_G(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_R] =
+    NS_MIN(PRUint32(diffuseNL * NS_GET_R(color)), 255U);
   targetData[GFX_ARGB32_OFFSET_A] = 255;
 }
 
 //---------------------SpecularLighting------------------------
 
 typedef nsSVGFELightingElement nsSVGFESpecularLightingElementBase;
 
 class nsSVGFESpecularLightingElement : public nsSVGFESpecularLightingElementBase,
@@ -5455,37 +5419,34 @@ nsSVGFESpecularLightingElement::LightPix
   H[0] = L[0];
   H[1] = L[1];
   H[2] = L[2] + 1;
   NORMALIZE(H);
 
   float kS = mNumberAttributes[SPECULAR_CONSTANT].GetAnimValue();
   float dotNH = DOT(N, H);
 
-  if (dotNH > 0 && kS > 0) {
-    float specularNH =
-      kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue());
-
-    targetData[GFX_ARGB32_OFFSET_B] =
-      NS_MIN(PRUint32(specularNH * NS_GET_B(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_G] =
-      NS_MIN(PRUint32(specularNH * NS_GET_G(color)), 255U);
-    targetData[GFX_ARGB32_OFFSET_R] =
-      NS_MIN(PRUint32(specularNH * NS_GET_R(color)), 255U);
-
-    targetData[GFX_ARGB32_OFFSET_A] =
-      NS_MAX(targetData[GFX_ARGB32_OFFSET_B],
-             NS_MAX(targetData[GFX_ARGB32_OFFSET_G],
-                    targetData[GFX_ARGB32_OFFSET_R]));
-  } else {
-    targetData[GFX_ARGB32_OFFSET_B] = 0;
-    targetData[GFX_ARGB32_OFFSET_G] = 0;
-    targetData[GFX_ARGB32_OFFSET_R] = 0;
-    targetData[GFX_ARGB32_OFFSET_A] = 255;
-  }
+  bool invalid = dotNH <= 0 || kS <= 0;
+  kS *= invalid ? 0 : 1;
+  PRUint8 minAlpha = invalid ? 255 : 0;
+
+  float specularNH =
+    kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue());
+
+  targetData[GFX_ARGB32_OFFSET_B] =
+    NS_MIN(PRUint32(specularNH * NS_GET_B(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_G] =
+    NS_MIN(PRUint32(specularNH * NS_GET_G(color)), 255U);
+  targetData[GFX_ARGB32_OFFSET_R] =
+    NS_MIN(PRUint32(specularNH * NS_GET_R(color)), 255U);
+
+  targetData[GFX_ARGB32_OFFSET_A] =
+    NS_MAX(minAlpha, NS_MAX(targetData[GFX_ARGB32_OFFSET_B],
+                            NS_MAX(targetData[GFX_ARGB32_OFFSET_G],
+                                   targetData[GFX_ARGB32_OFFSET_R])));
 }
 
 //---------------------Image------------------------
 
 nsSVGElement::StringInfo nsSVGFEImageElement::sStringInfo[2] =
 {
   { &nsGkAtoms::result, kNameSpaceID_None, true },
   { &nsGkAtoms::href, kNameSpaceID_XLink, true }
@@ -5984,16 +5945,18 @@ nsSVGFEDisplacementMapElement::Filter(ns
   PRInt32 width = instance->GetSurfaceWidth();
   PRInt32 height = instance->GetSurfaceHeight();
 
   PRUint8* sourceData = aSources[0]->mImage->Data();
   PRUint8* displacementData = aSources[1]->mImage->Data();
   PRUint8* targetData = aTarget->mImage->Data();
   PRUint32 stride = aTarget->mImage->Stride();
 
+  static PRUint8 dummyData[1] = { 0 };
+
   static const PRUint16 channelMap[5] = {
                              0,
                              GFX_ARGB32_OFFSET_R,
                              GFX_ARGB32_OFFSET_G,
                              GFX_ARGB32_OFFSET_B,
                              GFX_ARGB32_OFFSET_A };
   PRUint16 xChannel = channelMap[mEnumAttributes[CHANNEL_X].GetAnimValue()];
   PRUint16 yChannel = channelMap[mEnumAttributes[CHANNEL_Y].GetAnimValue()];
@@ -6006,23 +5969,30 @@ nsSVGFEDisplacementMapElement::Filter(ns
       PRUint32 targIndex = y * stride + 4 * x;
       // At some point we might want to replace this with a bilinear sample.
       PRInt32 sourceX = x +
         NSToIntFloor(scaleOver255 * displacementData[targIndex + xChannel] +
                 scaleAdjustment);
       PRInt32 sourceY = y +
         NSToIntFloor(scaleOver255 * displacementData[targIndex + yChannel] +
                 scaleAdjustment);
-      if (sourceX < 0 || sourceX >= width ||
-          sourceY < 0 || sourceY >= height) {
-        *(PRUint32*)(targetData + targIndex) = 0;
+
+      bool outOfBounds = sourceX < 0 || sourceX >= width ||
+                         sourceY < 0 || sourceY >= height;
+      PRUint8* data;
+      PRInt32 multiplier;
+      if (outOfBounds) {
+        data = sourceData;
+        multiplier = 1;
       } else {
-        *(PRUint32*)(targetData + targIndex) =
-          *(PRUint32*)(sourceData + sourceY * stride + 4 * sourceX);
+        data = dummyData;
+        multiplier = 0;
       }
+      *(PRUint32*)(targetData + targIndex) =
+        *(PRUint32*)(data + multiplier * (sourceY * stride + 4 * sourceX));
     }
   }
   return NS_OK;
 }
 
 bool
 nsSVGFEDisplacementMapElement::AttributeAffectsRendering(PRInt32 aNameSpaceID,
                                                          nsIAtom* aAttribute) const