зеркало из https://github.com/mozilla/pjs.git
Bug 399488. Faster gaussian blur. r=longsonr@gmail.com, sr=roc@ocallahan.org, a1.9=beltzner@mozilla.com
This commit is contained in:
Родитель
54606fd9fd
Коммит
9130ee5b59
|
@ -572,13 +572,15 @@ private:
|
||||||
nsresult GetDXY(PRUint32 *aDX, PRUint32 *aDY, const nsSVGFilterInstance& aInstance);
|
nsresult GetDXY(PRUint32 *aDX, PRUint32 *aDY, const nsSVGFilterInstance& aInstance);
|
||||||
void InflateRectForBlur(nsRect* aRect, const nsSVGFilterInstance& aInstance);
|
void InflateRectForBlur(nsRect* aRect, const nsSVGFilterInstance& aInstance);
|
||||||
|
|
||||||
|
PRUint8 *SetupPredivide(PRUint32 size) const;
|
||||||
|
|
||||||
void BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
void BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRInt32 aStride, const nsRect& aRegion,
|
PRInt32 aStride, const nsRect& aRegion,
|
||||||
PRUint32 leftLobe, PRUint32 rightLobe);
|
PRUint32 leftLobe, PRUint32 rightLobe, const PRUint8 *prediv);
|
||||||
|
|
||||||
void BoxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
void BoxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRInt32 aStride, const nsRect& aRegion,
|
PRInt32 aStride, const nsRect& aRegion,
|
||||||
PRUint32 topLobe, PRUint32 bottomLobe);
|
PRUint32 topLobe, PRUint32 bottomLobe, const PRUint8 *prediv);
|
||||||
|
|
||||||
void GaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
void GaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
nsSVGFilterResource *aFilterResource,
|
nsSVGFilterResource *aFilterResource,
|
||||||
|
@ -684,39 +686,41 @@ nsSVGFEGaussianBlurElement::ParseAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||||
void
|
void
|
||||||
nsSVGFEGaussianBlurElement::BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
nsSVGFEGaussianBlurElement::BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRInt32 aStride, const nsRect &aRegion,
|
PRInt32 aStride, const nsRect &aRegion,
|
||||||
PRUint32 leftLobe, PRUint32 rightLobe)
|
PRUint32 leftLobe, PRUint32 rightLobe,
|
||||||
|
const PRUint8 *prediv)
|
||||||
{
|
{
|
||||||
PRInt32 boxSize = leftLobe + rightLobe + 1;
|
PRInt32 boxSize = leftLobe + rightLobe + 1;
|
||||||
|
PRInt32 posStart = aRegion.x - leftLobe;
|
||||||
|
|
||||||
for (PRInt32 y = aRegion.y; y < aRegion.YMost(); y++) {
|
for (PRInt32 y = aRegion.y; y < aRegion.YMost(); y++) {
|
||||||
PRUint32 sums[4] = {0, 0, 0, 0};
|
PRUint32 sums[4] = {0, 0, 0, 0};
|
||||||
for (PRInt32 i=0; i < boxSize; i++) {
|
PRInt32 lineIndex = aStride * y;
|
||||||
PRInt32 pos = aRegion.x - leftLobe + i;
|
for (PRInt32 i = 0; i < boxSize; i++) {
|
||||||
|
PRInt32 pos = posStart + i;
|
||||||
pos = PR_MAX(pos, aRegion.x);
|
pos = PR_MAX(pos, aRegion.x);
|
||||||
pos = PR_MIN(pos, aRegion.XMost() - 1);
|
pos = PR_MIN(pos, aRegion.XMost() - 1);
|
||||||
sums[0] += aInput[aStride*y + 4*pos ];
|
PRInt32 index = lineIndex + (pos << 2);
|
||||||
sums[1] += aInput[aStride*y + 4*pos + 1];
|
sums[0] += aInput[index ];
|
||||||
sums[2] += aInput[aStride*y + 4*pos + 2];
|
sums[1] += aInput[index + 1];
|
||||||
sums[3] += aInput[aStride*y + 4*pos + 3];
|
sums[2] += aInput[index + 2];
|
||||||
|
sums[3] += aInput[index + 3];
|
||||||
}
|
}
|
||||||
for (PRInt32 x = aRegion.x; x < aRegion.XMost(); x++) {
|
for (PRInt32 x = aRegion.x; x < aRegion.XMost(); x++) {
|
||||||
|
PRInt32 index = lineIndex + (x << 2);
|
||||||
|
aOutput[index ] = prediv[sums[0]];
|
||||||
|
aOutput[index + 1] = prediv[sums[1]];
|
||||||
|
aOutput[index + 2] = prediv[sums[2]];
|
||||||
|
aOutput[index + 3] = prediv[sums[3]];
|
||||||
|
|
||||||
PRInt32 tmp = x - leftLobe;
|
PRInt32 tmp = x - leftLobe;
|
||||||
PRInt32 last = PR_MAX(tmp, aRegion.x);
|
PRInt32 last = PR_MAX(tmp, aRegion.x);
|
||||||
PRInt32 next = PR_MIN(tmp + boxSize, aRegion.XMost() - 1);
|
PRInt32 next = PR_MIN(tmp + boxSize, aRegion.XMost() - 1);
|
||||||
|
PRInt32 index2 = lineIndex + (next << 2);
|
||||||
aOutput[aStride*y + 4*x ] = sums[0]/boxSize;
|
PRInt32 index3 = lineIndex + (last << 2);
|
||||||
aOutput[aStride*y + 4*x + 1] = sums[1]/boxSize;
|
sums[0] += aInput[index2 ] - aInput[index3 ];
|
||||||
aOutput[aStride*y + 4*x + 2] = sums[2]/boxSize;
|
sums[1] += aInput[index2 + 1] - aInput[index3 + 1];
|
||||||
aOutput[aStride*y + 4*x + 3] = sums[3]/boxSize;
|
sums[2] += aInput[index2 + 2] - aInput[index3 + 2];
|
||||||
|
sums[3] += aInput[index2 + 3] - aInput[index3 + 3];
|
||||||
sums[0] += aInput[aStride*y + 4*next ] -
|
|
||||||
aInput[aStride*y + 4*last ];
|
|
||||||
sums[1] += aInput[aStride*y + 4*next + 1] -
|
|
||||||
aInput[aStride*y + 4*last + 1];
|
|
||||||
sums[2] += aInput[aStride*y + 4*next + 2] -
|
|
||||||
aInput[aStride*y + 4*last + 2];
|
|
||||||
sums[3] += aInput[aStride*y + 4*next + 3] -
|
|
||||||
aInput[aStride*y + 4*last + 3];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,43 +728,56 @@ nsSVGFEGaussianBlurElement::BoxBlurH(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
void
|
void
|
||||||
nsSVGFEGaussianBlurElement::BoxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
nsSVGFEGaussianBlurElement::BoxBlurV(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
PRInt32 aStride, const nsRect &aRegion,
|
PRInt32 aStride, const nsRect &aRegion,
|
||||||
PRUint32 topLobe, PRUint32 bottomLobe)
|
PRUint32 topLobe, PRUint32 bottomLobe,
|
||||||
|
const PRUint8 *prediv)
|
||||||
{
|
{
|
||||||
PRInt32 boxSize = topLobe + bottomLobe + 1;
|
PRInt32 boxSize = topLobe + bottomLobe + 1;
|
||||||
|
PRInt32 posStart = aRegion.y - topLobe;
|
||||||
|
|
||||||
for (PRInt32 x = aRegion.x; x < aRegion.XMost(); x++) {
|
for (PRInt32 x = aRegion.x; x < aRegion.XMost(); x++) {
|
||||||
PRUint32 sums[4] = {0, 0, 0, 0};
|
PRUint32 sums[4] = {0, 0, 0, 0};
|
||||||
for (PRInt32 i=0; i < boxSize; i++) {
|
PRInt32 fourX = x << 2;
|
||||||
PRInt32 pos = aRegion.y - topLobe + i;
|
for (PRInt32 i = 0; i < boxSize; i++) {
|
||||||
|
PRInt32 pos = posStart + i;
|
||||||
pos = PR_MAX(pos, aRegion.y);
|
pos = PR_MAX(pos, aRegion.y);
|
||||||
pos = PR_MIN(pos, aRegion.YMost() - 1);
|
pos = PR_MIN(pos, aRegion.YMost() - 1);
|
||||||
sums[0] += aInput[aStride*pos + 4*x ];
|
PRInt32 index = aStride * pos + fourX;
|
||||||
sums[1] += aInput[aStride*pos + 4*x + 1];
|
sums[0] += aInput[index ];
|
||||||
sums[2] += aInput[aStride*pos + 4*x + 2];
|
sums[1] += aInput[index + 1];
|
||||||
sums[3] += aInput[aStride*pos + 4*x + 3];
|
sums[2] += aInput[index + 2];
|
||||||
|
sums[3] += aInput[index + 3];
|
||||||
}
|
}
|
||||||
for (PRInt32 y = aRegion.y; y < aRegion.YMost(); y++) {
|
for (PRInt32 y = aRegion.y; y < aRegion.YMost(); y++) {
|
||||||
|
PRInt32 index = aStride * y + fourX;
|
||||||
|
aOutput[index ] = prediv[sums[0]];
|
||||||
|
aOutput[index + 1] = prediv[sums[1]];
|
||||||
|
aOutput[index + 2] = prediv[sums[2]];
|
||||||
|
aOutput[index + 3] = prediv[sums[3]];
|
||||||
|
|
||||||
PRInt32 tmp = y - topLobe;
|
PRInt32 tmp = y - topLobe;
|
||||||
PRInt32 last = PR_MAX(tmp, aRegion.y);
|
PRInt32 last = PR_MAX(tmp, aRegion.y);
|
||||||
PRInt32 next = PR_MIN(tmp + boxSize, aRegion.YMost() - 1);
|
PRInt32 next = PR_MIN(tmp + boxSize, aRegion.YMost() - 1);
|
||||||
|
PRInt32 index2 = aStride * next + fourX;
|
||||||
aOutput[aStride*y + 4*x ] = sums[0]/boxSize;
|
PRInt32 index3 = aStride * last + fourX;
|
||||||
aOutput[aStride*y + 4*x + 1] = sums[1]/boxSize;
|
sums[0] += aInput[index2 ] - aInput[index3 ];
|
||||||
aOutput[aStride*y + 4*x + 2] = sums[2]/boxSize;
|
sums[1] += aInput[index2 + 1] - aInput[index3 + 1];
|
||||||
aOutput[aStride*y + 4*x + 3] = sums[3]/boxSize;
|
sums[2] += aInput[index2 + 2] - aInput[index3 + 2];
|
||||||
|
sums[3] += aInput[index2 + 3] - aInput[index3 + 3];
|
||||||
sums[0] += aInput[aStride*next + 4*x ] -
|
|
||||||
aInput[aStride*last + 4*x ];
|
|
||||||
sums[1] += aInput[aStride*next + 4*x + 1] -
|
|
||||||
aInput[aStride*last + 4*x + 1];
|
|
||||||
sums[2] += aInput[aStride*next + 4*x + 2] -
|
|
||||||
aInput[aStride*last + 4*x + 2];
|
|
||||||
sums[3] += aInput[aStride*next + 4*x + 3] -
|
|
||||||
aInput[aStride*last + 4*x + 3];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRUint8 *
|
||||||
|
nsSVGFEGaussianBlurElement::SetupPredivide(PRUint32 size) const
|
||||||
|
{
|
||||||
|
PRUint8 *tmp = new PRUint8[size * 256];
|
||||||
|
if (tmp) {
|
||||||
|
for (PRUint32 i = 0; i < 256; i++)
|
||||||
|
memset(tmp + i * size, i, size);
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGFEGaussianBlurElement::GetDXY(PRUint32 *aDX, PRUint32 *aDY,
|
nsSVGFEGaussianBlurElement::GetDXY(PRUint32 *aDX, PRUint32 *aDY,
|
||||||
const nsSVGFilterInstance& aInstance)
|
const nsSVGFilterInstance& aInstance)
|
||||||
|
@ -791,8 +808,12 @@ nsSVGFEGaussianBlurElement::GaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
nsSVGFilterResource *aFilterResource,
|
nsSVGFilterResource *aFilterResource,
|
||||||
PRUint32 aDX, PRUint32 aDY)
|
PRUint32 aDX, PRUint32 aDY)
|
||||||
{
|
{
|
||||||
PRUint8 *tmp = static_cast<PRUint8*>
|
NS_ASSERTION(aDX > 0 && aDY > 0, "Invalid stdDeviation!");
|
||||||
(calloc(aFilterResource->GetDataSize(), 1));
|
|
||||||
|
nsAutoArrayPtr<PRUint8> tmp(new PRUint8[aFilterResource->GetDataSize()]);
|
||||||
|
if (!tmp)
|
||||||
|
return;
|
||||||
|
memset(tmp, 0, aFilterResource->GetDataSize());
|
||||||
nsRect rect = aFilterResource->GetSurfaceRect();
|
nsRect rect = aFilterResource->GetSurfaceRect();
|
||||||
#ifdef DEBUG_tor
|
#ifdef DEBUG_tor
|
||||||
fprintf(stderr, "FILTER GAUSS rect: %d,%d %dx%d\n",
|
fprintf(stderr, "FILTER GAUSS rect: %d,%d %dx%d\n",
|
||||||
|
@ -803,37 +824,53 @@ nsSVGFEGaussianBlurElement::GaussianBlur(PRUint8 *aInput, PRUint8 *aOutput,
|
||||||
|
|
||||||
if (aDX & 1) {
|
if (aDX & 1) {
|
||||||
// odd
|
// odd
|
||||||
BoxBlurH(aInput, tmp, stride, rect, aDX/2, aDX/2);
|
nsAutoArrayPtr<PRUint8> prediv(SetupPredivide(2 * (aDX / 2) + 1));
|
||||||
BoxBlurH(tmp, aOutput, stride, rect, aDX/2, aDX/2);
|
if (!prediv)
|
||||||
BoxBlurH(aOutput, tmp, stride, rect, aDX/2, aDX/2);
|
return;
|
||||||
|
|
||||||
|
BoxBlurH(aInput, tmp, stride, rect, aDX/2, aDX/2, prediv);
|
||||||
|
BoxBlurH(tmp, aOutput, stride, rect, aDX/2, aDX/2, prediv);
|
||||||
|
BoxBlurH(aOutput, tmp, stride, rect, aDX/2, aDX/2, prediv);
|
||||||
} else {
|
} else {
|
||||||
// even
|
// even
|
||||||
if (aDX == 0) {
|
if (aDX == 0) {
|
||||||
aFilterResource->CopyImageSubregion(tmp, aInput);
|
aFilterResource->CopyImageSubregion(tmp, aInput);
|
||||||
} else {
|
} else {
|
||||||
BoxBlurH(aInput, tmp, stride, rect, aDX/2, aDX/2 - 1);
|
nsAutoArrayPtr<PRUint8> prediv(SetupPredivide(2 * (aDX / 2) + 1));
|
||||||
BoxBlurH(tmp, aOutput, stride, rect, aDX/2 - 1, aDX/2);
|
nsAutoArrayPtr<PRUint8> prediv2(SetupPredivide(2 * (aDX / 2)));
|
||||||
BoxBlurH(aOutput, tmp, stride, rect, aDX/2, aDX/2);
|
if (!prediv || !prediv2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BoxBlurH(aInput, tmp, stride, rect, aDX/2, aDX/2 - 1, prediv2);
|
||||||
|
BoxBlurH(tmp, aOutput, stride, rect, aDX/2 - 1, aDX/2, prediv2);
|
||||||
|
BoxBlurH(aOutput, tmp, stride, rect, aDX/2, aDX/2, prediv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aDY & 1) {
|
if (aDY & 1) {
|
||||||
// odd
|
// odd
|
||||||
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2);
|
nsAutoArrayPtr<PRUint8> prediv(SetupPredivide(2 * (aDY / 2) + 1));
|
||||||
BoxBlurV(aOutput, tmp, stride, rect, aDY/2, aDY/2);
|
if (!prediv)
|
||||||
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2);
|
return;
|
||||||
|
|
||||||
|
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2, prediv);
|
||||||
|
BoxBlurV(aOutput, tmp, stride, rect, aDY/2, aDY/2, prediv);
|
||||||
|
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2, prediv);
|
||||||
} else {
|
} else {
|
||||||
// even
|
// even
|
||||||
if (aDY == 0) {
|
if (aDY == 0) {
|
||||||
aFilterResource->CopyImageSubregion(aOutput, tmp);
|
aFilterResource->CopyImageSubregion(aOutput, tmp);
|
||||||
} else {
|
} else {
|
||||||
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2 - 1);
|
nsAutoArrayPtr<PRUint8> prediv(SetupPredivide(2 * (aDY / 2) + 1));
|
||||||
BoxBlurV(aOutput, tmp, stride, rect, aDY/2 - 1, aDY/2);
|
nsAutoArrayPtr<PRUint8> prediv2(SetupPredivide(2 * (aDY / 2)));
|
||||||
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2);
|
if (!prediv || !prediv2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2 - 1, prediv2);
|
||||||
|
BoxBlurV(aOutput, tmp, stride, rect, aDY/2 - 1, aDY/2, prediv2);
|
||||||
|
BoxBlurV(tmp, aOutput, stride, rect, aDY/2, aDY/2, prediv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -4307,7 +4344,7 @@ nsSVGFEConvolveMatrixElement::Filter(nsSVGFilterInstance *instance)
|
||||||
if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
|
if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
|
||||||
orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
|
orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
nsAutoPtr<float> kernel(new float[orderX * orderY]);
|
nsAutoArrayPtr<float> kernel(new float[orderX * orderY]);
|
||||||
if (!kernel)
|
if (!kernel)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
for (PRUint32 i = 0; i < num; i++) {
|
for (PRUint32 i = 0; i < num; i++) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче