From 19b598c34cf3406c8362b1b2284562a9486ffff8 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Tue, 20 Mar 2012 22:20:21 +1100 Subject: [PATCH] Bug 711043 - Make filters code more consistent in performance. r=roc --- content/svg/content/src/nsSVGFilters.cpp | 134 +++++++++-------------- 1 file changed, 52 insertions(+), 82 deletions(-) diff --git a/content/svg/content/src/nsSVGFilters.cpp b/content/svg/content/src/nsSVGFilters.cpp index f97e8e4035c2..e15706512946 100644 --- a/content/svg/content/src/nsSVGFilters.cpp +++ b/content/svg/content/src/nsSVGFilters.cpp @@ -3800,17 +3800,10 @@ nsSVGFEMorphologyElement::Filter(nsSVGFilterInstance *instance, 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 @@ -3822,39 +3815,18 @@ nsSVGFEMorphologyElement::Filter(nsSVGFilterInstance *instance, 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; } } } @@ -5119,14 +5091,11 @@ nsSVGFELightingElement::Filter(nsSVGFilterInstance *instance, 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; } @@ -5293,19 +5262,14 @@ nsSVGFEDiffuseLightingElement::LightPixel(const float *N, const float *L, 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; } @@ -5460,27 +5424,24 @@ nsSVGFESpecularLightingElement::LightPixel(const float *N, const float *L, 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()); + bool invalid = dotNH <= 0 || kS <= 0; + kS *= invalid ? 0 : 1; + PRUint8 minAlpha = invalid ? 255 : 0; - 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); + float specularNH = + kS * pow(dotNH, mNumberAttributes[SPECULAR_EXPONENT].GetAnimValue()); - 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; - } + 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------------------------ @@ -5989,6 +5950,8 @@ nsSVGFEDisplacementMapElement::Filter(nsSVGFilterInstance *instance, PRUint8* targetData = aTarget->mImage->Data(); PRUint32 stride = aTarget->mImage->Stride(); + static PRUint8 dummyData[4] = { 0, 0, 0, 0 }; + static const PRUint16 channelMap[5] = { 0, GFX_ARGB32_OFFSET_R, @@ -6011,13 +5974,20 @@ nsSVGFEDisplacementMapElement::Filter(nsSVGFilterInstance *instance, 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 = dummyData; + multiplier = 0; } else { - *(PRUint32*)(targetData + targIndex) = - *(PRUint32*)(sourceData + sourceY * stride + 4 * sourceX); + data = sourceData; + multiplier = 1; } + *(PRUint32*)(targetData + targIndex) = + *(PRUint32*)(data + multiplier * (sourceY * stride + 4 * sourceX)); } } return NS_OK;