Bug 711043 - Make filters code more consistent in performance. r=roc

This commit is contained in:
Cameron McCormack 2012-03-20 22:20:21 +11:00
Родитель dc403d892f
Коммит 19b598c34c
1 изменённых файлов: 52 добавлений и 82 удалений

Просмотреть файл

@ -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;