mirror of https://github.com/adamdruppe/arsd.git
Refactor component foreach loop of bilinear scaler
This commit is contained in:
parent
2804f426c4
commit
c3beff155c
179
pixmappaint.d
179
pixmappaint.d
|
@ -3041,6 +3041,29 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
static if ((filter == ScalingFilter.bilinear) || (filter == ScalingFilter.fauxLinear)) {
|
static if ((filter == ScalingFilter.bilinear) || (filter == ScalingFilter.fauxLinear)) {
|
||||||
void scaleToLinearImpl(ScalingDirection directionX, ScalingDirection directionY)() {
|
void scaleToLinearImpl(ScalingDirection directionX, ScalingDirection directionY)() {
|
||||||
|
|
||||||
|
alias InterPixel = ulong[4];
|
||||||
|
|
||||||
|
static Pixel toPixel(const InterPixel ipx) @safe pure nothrow @nogc {
|
||||||
|
pragma(inline, true);
|
||||||
|
return Pixel(
|
||||||
|
clamp255(ipx[0]),
|
||||||
|
clamp255(ipx[1]),
|
||||||
|
clamp255(ipx[2]),
|
||||||
|
clamp255(ipx[3]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static InterPixel toInterPixel(const Pixel ipx) @safe pure nothrow @nogc {
|
||||||
|
pragma(inline, true);
|
||||||
|
InterPixel result = [
|
||||||
|
ipx.r,
|
||||||
|
ipx.g,
|
||||||
|
ipx.b,
|
||||||
|
ipx.a,
|
||||||
|
];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int[2] posSrcCenterToInterpolationTargets(
|
int[2] posSrcCenterToInterpolationTargets(
|
||||||
ScalingDirection direction,
|
ScalingDirection direction,
|
||||||
)(
|
)(
|
||||||
|
@ -3048,6 +3071,8 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
UDecimal ratioHalf,
|
UDecimal ratioHalf,
|
||||||
int sourceMax,
|
int sourceMax,
|
||||||
) {
|
) {
|
||||||
|
pragma(inline, true);
|
||||||
|
|
||||||
int[2] result;
|
int[2] result;
|
||||||
static if (direction == none) {
|
static if (direction == none) {
|
||||||
const value = posSrcCenter.castTo!int;
|
const value = posSrcCenter.castTo!int;
|
||||||
|
@ -3171,18 +3196,19 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======== Interpolate X ========
|
// ======== Interpolate X ========
|
||||||
auto sampleX(SamplingMode mode)(const size_t ib) {
|
auto sampleX(SamplingMode mode)() {
|
||||||
pragma(inline, true);
|
pragma(inline, true);
|
||||||
|
|
||||||
static if (mode == SamplingMode.multi) {
|
static if (mode == SamplingMode.multi) {
|
||||||
const nLines = 1 + posSrcY[idxB] - posSrcY[idxT];
|
const nLines = 1 + posSrcY[idxB] - posSrcY[idxT];
|
||||||
|
|
||||||
alias ForeachLineCallback = ulong delegate(const Point posLine) @safe pure nothrow @nogc;
|
alias ForeachLineCallback = InterPixel delegate(const Point posLine) @safe pure nothrow @nogc;
|
||||||
ulong foreachLine(scope ForeachLineCallback apply) {
|
InterPixel foreachLine(scope ForeachLineCallback apply) {
|
||||||
ulong linesSum = 0;
|
InterPixel linesSum = 0;
|
||||||
foreach (lineY; posSrcY[idxT] .. (1 + posSrcY[idxB])) {
|
foreach (lineY; posSrcY[idxT] .. (1 + posSrcY[idxB])) {
|
||||||
const posLine = Point(posSrcX[idxL], lineY);
|
const posLine = Point(posSrcX[idxL], lineY);
|
||||||
linesSum += apply(posLine);
|
const lineValues = apply(posLine);
|
||||||
|
linesSum[] += lineValues[];
|
||||||
}
|
}
|
||||||
return linesSum;
|
return linesSum;
|
||||||
}
|
}
|
||||||
|
@ -3191,25 +3217,26 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
// ========== None ==========
|
// ========== None ==========
|
||||||
static if (directionX == none) {
|
static if (directionX == none) {
|
||||||
static if (mode == SamplingMode.single) {
|
static if (mode == SamplingMode.single) {
|
||||||
return (() @trusted => pxNeighs[idxTL].components.ptr[ib])();
|
return pxNeighs[idxTL];
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (mode == SamplingMode.dual) {
|
static if (mode == SamplingMode.dual) {
|
||||||
return () @trusted {
|
return () @trusted {
|
||||||
ulong[2] result = [
|
InterPixel[2] result = [
|
||||||
pxNeighs[idxTL].components.ptr[ib],
|
toInterPixel(pxNeighs[idxTL]),
|
||||||
pxNeighs[idxBL].components.ptr[ib],
|
toInterPixel(pxNeighs[idxBL]),
|
||||||
];
|
];
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (mode == SamplingMode.multi) {
|
static if (mode == SamplingMode.multi) {
|
||||||
const ySum = foreachLine(delegate(const Point posLine) {
|
auto ySum = foreachLine(delegate(const Point posLine) {
|
||||||
const pxSrc = source.getPixel(posLine);
|
const pxSrc = source.getPixel(posLine);
|
||||||
return ulong((() @trusted => pxSrc.components.ptr[ib])());
|
return toInterPixel(pxSrc);
|
||||||
});
|
});
|
||||||
return (ySum / nLines);
|
ySum[] /= nLines;
|
||||||
|
return ySum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3223,13 +3250,16 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
||||||
}();
|
}();
|
||||||
|
|
||||||
ulong xSum = 0;
|
InterPixel xSum = [0, 0, 0, 0];
|
||||||
|
|
||||||
foreach (srcSample; srcSamples) {
|
foreach (srcSample; srcSamples) {
|
||||||
xSum += (() @trusted => srcSample.components.ptr[ib])();
|
foreach (immutable ib, c; srcSample.components) {
|
||||||
|
() @trusted { xSum.ptr[ib] += c; }();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (xSum / nSamples);
|
xSum[] /= nSamples;
|
||||||
|
return toPixel(xSum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (mode == SamplingMode.dual) {
|
static if (mode == SamplingMode.dual) {
|
||||||
|
@ -3252,15 +3282,19 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
ulong[2] xSums = [0, 0];
|
InterPixel[2] xSums = [[0, 0, 0, 0], [0, 0, 0, 0]];
|
||||||
|
|
||||||
foreach (idx, srcSamples; srcSamples2) {
|
foreach (idx, srcSamples; srcSamples2) {
|
||||||
foreach (srcSample; srcSamples) {
|
foreach (srcSample; srcSamples) {
|
||||||
() @trusted { xSums.ptr[idx] += srcSample.components.ptr[ib]; }();
|
foreach (immutable ib, c; srcSample.components)
|
||||||
|
() @trusted { xSums.ptr[idx].ptr[ib] += c; }();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xSums[] /= nSamples;
|
foreach (xSum; xSums) {
|
||||||
|
xSum[] /= nSamples;
|
||||||
|
}
|
||||||
|
|
||||||
return xSums;
|
return xSums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3273,17 +3307,20 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
return source.data.ptr[samplingOffset .. (samplingOffset + nSamples)];
|
||||||
}();
|
}();
|
||||||
|
|
||||||
ulong xSum = 0;
|
InterPixel xSum = 0;
|
||||||
|
|
||||||
foreach (srcSample; srcSamples) {
|
foreach (srcSample; srcSamples) {
|
||||||
xSum += (() @trusted => srcSample.components.ptr[ib])();
|
foreach (immutable ib, c; srcSample.components) {
|
||||||
|
() @trusted { xSum.ptr[ib] += c; }();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return xSum;
|
return xSum;
|
||||||
});
|
});
|
||||||
|
|
||||||
ySum /= nSamples;
|
ySum[] /= nSamples;
|
||||||
return (ySum / nLines);
|
ySum[] /= nLines;
|
||||||
|
return ySum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3292,26 +3329,26 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
|
|
||||||
if (posSrcX[0] == posSrcX[1]) {
|
if (posSrcX[0] == posSrcX[1]) {
|
||||||
static if (mode == SamplingMode.single) {
|
static if (mode == SamplingMode.single) {
|
||||||
return (() @trusted => pxNeighs[idxTL].components.ptr[ib])();
|
return pxNeighs[idxTL];
|
||||||
}
|
}
|
||||||
static if (mode == SamplingMode.dual) {
|
static if (mode == SamplingMode.dual) {
|
||||||
return () @trusted {
|
return () @trusted {
|
||||||
ulong[2] result = [
|
InterPixel[2] result = [
|
||||||
pxNeighs[idxTL].components.ptr[ib],
|
toInterPixel(pxNeighs[idxTL]),
|
||||||
pxNeighs[idxBL].components.ptr[ib],
|
toInterPixel(pxNeighs[idxBL]),
|
||||||
];
|
];
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
static if (mode == SamplingMode.multi) {
|
static if (mode == SamplingMode.multi) {
|
||||||
const ySum = foreachLine(delegate(const Point posLine) {
|
auto ySum = foreachLine(delegate(const Point posLine) {
|
||||||
ulong xSum = 0;
|
|
||||||
const samplingOffset = source.scanTo(posLine);
|
const samplingOffset = source.scanTo(posLine);
|
||||||
return (() @trusted
|
return toInterPixel(
|
||||||
=> source.data.ptr[samplingOffset].components.ptr[ib]
|
(() @trusted => source.data.ptr[samplingOffset])()
|
||||||
)();
|
);
|
||||||
});
|
});
|
||||||
return (ySum / nLines);
|
ySum[] /= nLines;
|
||||||
|
return ySum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3323,80 +3360,90 @@ private void scaleToImpl(ScalingFilter filter)(const Pixmap source, Pixmap targe
|
||||||
}();
|
}();
|
||||||
|
|
||||||
static if (mode == SamplingMode.single) {
|
static if (mode == SamplingMode.single) {
|
||||||
ulong xSum = 0;
|
InterPixel xSum = [0, 0, 0, 0];
|
||||||
|
|
||||||
() @trusted {
|
foreach (immutable ib, ref c; xSum) {
|
||||||
xSum += (pxNeighs[idxTL].components.ptr[ib] * weightsX[0]);
|
c += ((() @trusted => pxNeighs[idxTL].components.ptr[ib])() * weightsX[0]);
|
||||||
xSum += (pxNeighs[idxTR].components.ptr[ib] * weightsX[1]);
|
c += ((() @trusted => pxNeighs[idxTR].components.ptr[ib])() * weightsX[1]);
|
||||||
}();
|
}
|
||||||
|
|
||||||
xSum >>= 32;
|
foreach (ref c; xSum) {
|
||||||
return xSum;
|
c >>= 32;
|
||||||
|
}
|
||||||
|
return toPixel(xSum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (mode == SamplingMode.dual) {
|
static if (mode == SamplingMode.dual) {
|
||||||
ulong[2] xSums = [0, 0];
|
InterPixel[2] xSums = [[0, 0, 0, 0], [0, 0, 0, 0]];
|
||||||
|
|
||||||
() @trusted {
|
() @trusted {
|
||||||
xSums[0] += (pxNeighs[idxTL].components.ptr[ib] * weightsX[0]);
|
foreach (immutable ib, ref c; xSums[0]) {
|
||||||
xSums[0] += (pxNeighs[idxTR].components.ptr[ib] * weightsX[1]);
|
c += (pxNeighs[idxTL].components.ptr[ib] * weightsX[idxL]);
|
||||||
|
c += (pxNeighs[idxTR].components.ptr[ib] * weightsX[idxR]);
|
||||||
|
}
|
||||||
|
|
||||||
xSums[1] += (pxNeighs[idxBL].components.ptr[ib] * weightsX[0]);
|
foreach (immutable ib, ref c; xSums[1]) {
|
||||||
xSums[1] += (pxNeighs[idxBR].components.ptr[ib] * weightsX[1]);
|
c += (pxNeighs[idxBL].components.ptr[ib] * weightsX[idxL]);
|
||||||
|
c += (pxNeighs[idxBR].components.ptr[ib] * weightsX[idxR]);
|
||||||
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
foreach (ref sum; xSums) {
|
foreach (ref sum; xSums) {
|
||||||
sum >>= 32;
|
foreach (ref c; sum) {
|
||||||
|
c >>= 32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return xSums;
|
return xSums;
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (mode == SamplingMode.multi) {
|
static if (mode == SamplingMode.multi) {
|
||||||
const ySum = foreachLine(delegate(const Point posLine) {
|
auto ySum = foreachLine(delegate(const Point posLine) {
|
||||||
ulong xSum = 0;
|
InterPixel xSum = [0, 0, 0, 0];
|
||||||
|
|
||||||
const samplingOffset = source.scanTo(posLine);
|
const samplingOffset = source.scanTo(posLine);
|
||||||
ubyte[2] pxcLR = () @trusted {
|
Pixel[2] pxcLR = () @trusted {
|
||||||
ubyte[2] result = [
|
Pixel[2] result = [
|
||||||
source.data.ptr[samplingOffset].components.ptr[ib],
|
source.data.ptr[samplingOffset],
|
||||||
source.data.ptr[samplingOffset + 1].components.ptr[ib],
|
source.data.ptr[samplingOffset + 1],
|
||||||
];
|
];
|
||||||
return result;
|
return result;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
xSum += (pxcLR[idxL] * weightsX[idxL]);
|
foreach (immutable ib, ref c; xSum) {
|
||||||
xSum += (pxcLR[idxR] * weightsX[idxR]);
|
c += ((() @trusted => pxcLR[idxL].components.ptr[ib])() * weightsX[idxL]);
|
||||||
|
c += ((() @trusted => pxcLR[idxR].components.ptr[ib])() * weightsX[idxR]);
|
||||||
|
}
|
||||||
|
|
||||||
return (xSum >> 32);
|
foreach (ref c; xSum) {
|
||||||
|
c >>= 32;
|
||||||
|
}
|
||||||
|
return xSum;
|
||||||
});
|
});
|
||||||
|
|
||||||
return (ySum / nLines);
|
ySum[] /= nLines;
|
||||||
|
return ySum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======== Interpolate Y ========
|
// ======== Interpolate Y ========
|
||||||
static if (directionY == none) {
|
static if (directionY == none) {
|
||||||
foreach (immutable ib, ref c; pxInt.components) {
|
const Pixel tmp = sampleX!(SamplingMode.single)();
|
||||||
c = clamp255(sampleX!(SamplingMode.single)(ib));
|
pxInt = tmp;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
static if (directionY == down) {
|
static if (directionY == down) {
|
||||||
foreach (immutable ib, ref c; pxInt.components) {
|
const InterPixel tmp = sampleX!(SamplingMode.multi)();
|
||||||
c = clamp255(sampleX!(SamplingMode.multi)(ib));
|
pxInt = toPixel(tmp);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
static if (directionY == up) {
|
static if (directionY == up) {
|
||||||
|
const InterPixel[2] xSums = sampleX!(SamplingMode.dual)();
|
||||||
foreach (immutable ib, ref c; pxInt.components) {
|
foreach (immutable ib, ref c; pxInt.components) {
|
||||||
const xSums = sampleX!(SamplingMode.dual)(ib);
|
|
||||||
|
|
||||||
ulong ySum = 0;
|
ulong ySum = 0;
|
||||||
ySum += (xSums[idxT] * weightsY[idxT]);
|
ySum += ((() @trusted => xSums[idxT].ptr[ib])() * weightsY[idxT]);
|
||||||
ySum += (xSums[idxB] * weightsY[idxB]);
|
ySum += ((() @trusted => xSums[idxB].ptr[ib])() * weightsY[idxB]);
|
||||||
|
|
||||||
const xySum = (ySum >> 32);
|
const xySum = (ySum >> 32);
|
||||||
|
|
||||||
c = clamp255(xySum);
|
c = clamp255(xySum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue