Draw: RescaleFilter now parallelized

git-svn-id: svn://ultimatepp.org/upp/trunk@14472 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2020-05-14 12:31:53 +00:00
parent f10a923a10
commit be4b4e3334
7 changed files with 161 additions and 142 deletions

View file

@ -122,6 +122,15 @@ void CoDo_ST(Function<void ()>&& fn)
fn();
}
inline
void CoDo(bool co, Function<void ()>&& fn)
{
if(co)
CoDo(pick(fn));
else
CoDo_ST(pick(fn));
}
template <typename Fn>
void CoFor(int n, Fn iterator)
{
@ -132,6 +141,22 @@ void CoFor(int n, Fn iterator)
});
}
template <typename Fn>
void CoFor_ST(int n, Fn iterator)
{
for(int i = 0; i < n; i++)
iterator(i);
}
template <typename Fn>
void CoFor(bool co, int n, Fn iterator)
{
if(co)
CoFor(n, iterator);
else
CoFor_ST(n, iterator);
}
template <class T>
class CoWorkerResources {
int workercount;

View file

@ -209,10 +209,29 @@ unction]<[@(0.0.255) void]_()>`&`&_[*@3 fn])&]
by adding `"`_ST`" text.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:CoDo`(bool`,Upp`:`:Function`<void`(`)`>`&`&`): [@(0.0.255) void]_[* CoDo]([@(0.0.255) b
ool]_[*@3 co], [_^Upp`:`:Function^ Function]<[@(0.0.255) void]_()>`&`&_[*@3 fn])&]
[s2;%% If [%-*@3 co] is true, calls CoDo([%-*@3 fn]), otherwise CoDo`_ST([%-*@3 fn]).
This allows to parametrize algorithms with respect to parallelization.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:CoFor`(int`,Fn`): [@(0.0.255) template]_<[@(0.0.255) typename]_[*@4 Fn]>_[@(0.0.255) v
oid]_[* CoFor]([@(0.0.255) int]_[*@3 n], [*@4 Fn]_[*@3 iterator])&]
[s2;%% Based on CoDo, runs in parallel [%-*@3 iterator] for values
0..[%-*@3 n] passing the value as argument.&]
[s3; &]
[s4; &]
[s5;:Upp`:`:CoFor`_ST`(int`,Fn`): [@(0.0.255) template]_<[@(0.0.255) typename]_[*@4 Fn]>_[@(0.0.255) v
oid]_[* CoFor`_ST]([@(0.0.255) int]_[*@3 n], [*@4 Fn]_[*@3 iterator])&]
[s2;%% Single threaded variant of CoFor, for diagnostics purposes.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:CoFor`(bool`,int`,Fn`): [@(0.0.255) template]_<[@(0.0.255) typename]_[*@4 Fn]>_
[@(0.0.255) void]_[* CoFor]([@(0.0.255) bool]_[*@3 co], [@(0.0.255) int]_[*@3 n],
[*@4 Fn]_[*@3 iterator])&]
[s2;%% Calls CoFor([%-*@3 n], [%-*@3 iterator]) if [%-*@3 co] is true,
CoFor`_ST([%-*@3 n], [%-*@3 iterator]) otherwise. This allows to
parametrize algorithms with respect to parallelization.&]
[s0; &]
[ {{10000@(113.42.0) [s0;%% [*@7;4 CoWorkerResources]]}}&]
[s3; &]
@ -235,7 +254,7 @@ better solved by using CoDo function.&]
[s5;:Upp`:`:CoWorkerResources`:`:CoWorkerResources`(`): [* CoWorkerResources]()&]
[s2;%% Creates a required number of instances so that each sub`-job
of CoWork has its unique instance.&]
[s3; &]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:CoWorkerResources`:`:CoWorkerResources`(Upp`:`:Event`<T`&`>`): [* CoWorkerR
esources]([_^Upp`:`:Event^ Event]<[*@4 T][@(0.0.255) `&]>_[*@3 initializer])&]

View file

@ -1,73 +0,0 @@
#include "Draw.h"
namespace Upp {
double BicubicKernel(double x)
{
double r = 0;
double xp2 = x + 2;
double xp1 = x + 1;
double xm1 = x - 1;
if(xp2 > 0)
r += xp2 * xp2 * xp2;
if(xp1 > 0)
r -= 4 * xp1 * xp1 * xp1;
if(x > 0)
r += 6 * x * x * x;
if(xm1 > 0)
r -= 4 * xm1 * xm1 * xm1;
return 0.16666666666666666 * r;
}
Image RescaleBicubic(const Image& img, Size sz, const Rect& sr, Gate<int, int> progress)
{
ASSERT(sr.top >= 0 && sr.left >= 0 && sr.right <= img.GetWidth() && sr.bottom <= img.GetHeight());
Size isz = sr.GetSize();
ImageBuffer ib(sz);
RGBA *t = ~ib;
double inv_cx = 1.0 / sz.cx;
for(int y = 0; y < sz.cy; y++) {
if(progress(y, sz.cy))
return ib;
int sy = y * isz.cy / sz.cy;
double dy = y * isz.cy / (double)sz.cy - sy;
for(int x = 0; x < sz.cx; x++) {
int sx = x * isz.cx / sz.cx;
double dx = x * isz.cx * inv_cx - sx;
double red = 0;
double green = 0;
double blue = 0;
double alpha = 0;
for(int yy = -1; yy <= 2; yy++) {
double ky = BicubicKernel(yy - dy);
const RGBA *l = img[minmax(sy + yy + sr.top, sr.top, sr.bottom - 1)];
for(int xx = -1; xx <= 2; xx++) {
const RGBA& s = l[minmax(sx + xx + sr.left, sr.left, sr.right - 1)];
double weight = ky * BicubicKernel(xx - dx);
red += weight * s.r;
green += weight * s.g;
blue += weight * s.b;
alpha += weight * s.a;
}
}
t->r = (int)fround(red);
t->g = (int)fround(green);
t->b = (int)fround(blue);
t->a = (int)fround(alpha);
t++;
}
}
return ib;
}
Image RescaleBicubic(const Image& img, int cx, int cy, Gate<int, int> progress)
{
return RescaleBicubic(img, Size(cx, cy), img.GetSize(), progress);
}
Image RescaleBicubic(const Image& img, Size sz, Gate<int, int> progress)
{
return RescaleBicubic(img, sz, img.GetSize(), progress);
}
}

View file

@ -42,7 +42,6 @@ file
ImageOp.cpp,
ImageChOp.cpp,
ImageScale.cpp,
BiCubic.cpp,
RescaleFilter.cpp,
MakeCache.cpp,
DrawRasterData.cpp,

View file

@ -52,6 +52,8 @@ Image Contrast(const Image& img, int amount = 256);
Image HorzFadeOut(int cx, int cy, Color color);
Image HorzFadeOut(Size sz, Color color);
void DrawRasterData(Draw& w, int x, int y, int cx, int cy, const String& data);
class RescaleImage {
Raster *src;
Size tsz;
@ -85,10 +87,10 @@ class RescaleImage {
public:
void Create(Size sz, Raster& src, const Rect& src_rc);
void Get(RGBA *line);
Image CoRescale(Size sz, const Image& img, const Rect& src_rc);
};
void DrawRasterData(Draw& w, int x, int y, int cx, int cy, const String& data);
bool Rescale(RasterEncoder& tgt, Size sz, Raster& src, const Rect& src_rc,
Gate<int, int> progress = Null);
Image Rescale(const Image& src, Size sz, const Rect& src_rc, Gate<int, int> progress = Null);
@ -179,11 +181,14 @@ void SetMakeImageCacheMax(int m);
Image MakeImagePaintOnly(const ImageMaker& m);
Image RescaleFilter(const Image& img, Size sz, const Rect& sr,
double (*kernel_fn)(double x), int kernel_width, Gate<int, int> progress);
double (*kernel_fn)(double x), int kernel_width, Gate<int, int> progress,
bool co);
Image RescaleFilter(const Image& img, Size sz,
double (*kernel_fn)(double x), int kernel_width, Gate<int, int> progress);
double (*kernel_fn)(double x), int kernel_width, Gate<int, int> progress,
bool co);
Image RescaleFilter(const Image& img, int cx, int cy,
double (*kernel_fn)(double x), int kernel_width, Gate<int, int> progress);
double (*kernel_fn)(double x), int kernel_width, Gate<int, int> progress,
bool co);
enum {
FILTER_NEAREST = 0,
@ -198,10 +203,14 @@ enum {
FILTER_LANCZOS5 = 9,
};
Image RescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<int, int> progress = Null);
Image RescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<int, int> progress = Null, bool co = false);
Image RescaleFilter(const Image& img, Size sz, int filter, Gate<int, int> progress = Null);
Image RescaleFilter(const Image& img, int cx, int cy, int filter, Gate<int, int> progress = Null);
Image CoRescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<int, int> progress = Null);
Image CoRescaleFilter(const Image& img, Size sz, int filter, Gate<int, int> progress = Null);
Image CoRescaleFilter(const Image& img, int cx, int cy, int filter, Gate<int, int> progress = Null);
Image CachedRescale(const Image& m, Size sz, const Rect& src, int filter = Null);
Image CachedRescale(const Image& m, Size sz, int filter = Null);
Image CachedRescalePaintOnly(const Image& m, Size sz, const Rect& src, int filter = Null);

View file

@ -39,7 +39,7 @@ static int sGeta(int a, int src, int tgt, int& shift)
Image RescaleFilter(const Image& img, Size sz, const Rect& sr,
double (*kfn)(double x), int a,
Gate<int, int> progress)
Gate<int, int> progress, bool co)
{
ASSERT(Rect(img.GetSize()).Contains(sr));
Size isz = sr.GetSize();
@ -72,78 +72,81 @@ Image RescaleFilter(const Image& img, Size sz, const Rect& sr,
}
ImageBuffer ib(sz);
RGBA *t = ~ib;
for(int y = 0; y < sz.cy; y++) {
if(progress(y, sz.cy))
break;
int dy = ((y * isz.cy) << shift) / sz.cy - cr.cy;
int sy = dy >> shift;
dy -= sy << shift;
if(dy < 0)
dy = 0;
xd = ~px;
std::atomic<int> yy(0);
CoDo(co, [&] {
Buffer<int> py(2 * ay * 2);
int *yd = py;
for(int yy = -ay + 1; yy <= ay; yy++) {
*yd++ = sGetk(kernel, ((yy << shift) - dy) * a / ay, a, shift);
*yd++ = minmax(sy + yy, 0, isz.cy - 1) + sr.top;
}
for(int x = 0; x < sz.cx; x++) {
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
int w = 0;
yd = py;
int hasalpha = 0;
for(int yy = 2 * ay; yy-- > 0;) {
int ky = *yd++;
const RGBA *l = img[*yd++];
for(int xx = 2 * ax; xx-- > 0;) {
const RGBA& s = l[*xd++];
int weight = ky * *xd++;
red += weight * s.r;
green += weight * s.g;
blue += weight * s.b;
alpha += weight * s.a;
hasalpha |= s.a - 255;
w += weight;
}
for(int y = yy++; y < sz.cy; y = yy++) {
if(progress(y, sz.cy))
break;
int dy = ((y * isz.cy) << shift) / sz.cy - cr.cy;
int sy = dy >> shift;
dy -= sy << shift;
if(dy < 0)
dy = 0;
int *xd = px;
int *yd = py;
for(int yy = -ay + 1; yy <= ay; yy++) {
*yd++ = sGetk(kernel, ((yy << shift) - dy) * a / ay, a, shift);
*yd++ = minmax(sy + yy, 0, isz.cy - 1) + sr.top;
}
if(w)
if(hasalpha) {
t->a = alpha = Saturate255(alpha / w);
t->r = clamp(red / w, 0, alpha);
t->g = clamp(green / w, 0, alpha);
t->b = clamp(blue / w, 0, alpha);
RGBA *t = ib[y];
for(int x = 0; x < sz.cx; x++) {
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
int w = 0;
yd = py;
int hasalpha = 0;
for(int yy = 2 * ay; yy-- > 0;) {
int ky = *yd++;
const RGBA *l = img[*yd++];
for(int xx = 2 * ax; xx-- > 0;) {
const RGBA& s = l[*xd++];
int weight = ky * *xd++;
red += weight * s.r;
green += weight * s.g;
blue += weight * s.b;
alpha += weight * s.a;
hasalpha |= s.a - 255;
w += weight;
}
}
else {
t->a = 255;
t->r = Saturate255(red / w);
t->g = Saturate255(green / w);
t->b = Saturate255(blue / w);
}
else
t->a = t->r = t->g = t->b = 0;
t++;
if(w)
if(hasalpha) {
t->a = alpha = Saturate255(alpha / w);
t->r = clamp(red / w, 0, alpha);
t->g = clamp(green / w, 0, alpha);
t->b = clamp(blue / w, 0, alpha);
}
else {
t->a = 255;
t->r = Saturate255(red / w);
t->g = Saturate255(green / w);
t->b = Saturate255(blue / w);
}
else
t->a = t->r = t->g = t->b = 0;
t++;
}
}
}
});
ib.SetResolution(img.GetResolution());
return ib;
}
Image RescaleFilter(const Image& img, Size sz,
double (*kfn)(double x), int a,
Gate<int, int> progress)
Gate<int, int> progress, bool co)
{
return RescaleFilter(img, sz, img.GetSize(), kfn, a, progress);
return RescaleFilter(img, sz, img.GetSize(), kfn, a, progress, co);
}
Image RescaleFilter(const Image& img, int cx, int cy,
double (*kfn)(double x), int a,
Gate<int, int> progress)
Gate<int, int> progress, bool co)
{
return RescaleFilter(img, Size(cx, cy), img.GetSize(), kfn, a, progress);
return RescaleFilter(img, Size(cx, cy), img.GetSize(), kfn, a, progress, co);
}
static double sNearest(double x)
@ -224,7 +227,7 @@ static double sCostello(double x)
0;
}
Image RescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<int, int> progress)
Image RescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<int, int> progress, bool co)
{
if(IsNull(filter))
return Rescale(img, sz, sr);
@ -241,7 +244,7 @@ Image RescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<
{ sLanczos5, 5 },
};
ASSERT(filter >= FILTER_NEAREST && filter <= FILTER_LANCZOS5);
return RescaleFilter(img, sz, sr, tab[filter].a, tab[filter].b, progress);
return RescaleFilter(img, sz, sr, tab[filter].a, tab[filter].b, progress, co);
}
Image RescaleFilter(const Image& img, Size sz, int filter, Gate<int, int> progress)
@ -254,4 +257,37 @@ Image RescaleFilter(const Image& img, int cx, int cy, int filter, Gate<int, int>
return RescaleFilter(img, Size(cx, cy), filter, progress);
}
Image CoRescaleFilter(const Image& img, Size sz, const Rect& sr, int filter, Gate<int, int> progress)
{
return RescaleFilter(img, sz, sr, filter, progress, true);
}
Image CoRescaleFilter(const Image& img, Size sz, int filter, Gate<int, int> progress)
{
return CoRescaleFilter(img, sz, img.GetSize(), filter, progress);
}
Image CoRescaleFilter(const Image& img, int cx, int cy, int filter, Gate<int, int> progress)
{
return CoRescaleFilter(img, Size(cx, cy), filter, progress);
}
// Obsolete functions
Image RescaleBicubic(const Image& img, Size sz, const Rect& sr, Gate<int, int> progress)
{
return RescaleFilter(img, sz, sr, FILTER_BICUBIC_MITCHELL, progress);
}
Image RescaleBicubic(const Image& img, int cx, int cy, Gate<int, int> progress)
{
return RescaleBicubic(img, Size(cx, cy), img.GetSize(), progress);
}
Image RescaleBicubic(const Image& img, Size sz, Gate<int, int> progress)
{
return RescaleBicubic(img, sz, img.GetSize(), progress);
}
}

View file

@ -1,5 +1,4 @@
topic "ImageMaker - image cache system";
[2 $$0,0#00000000000000000000000000000000:Default]
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
[l288;2 $$2,2#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
@ -9,6 +8,7 @@ topic "ImageMaker - image cache system";
[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param]
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
[b42;2 $$9,9#13035079074754324216151401829390:normal]
[2 $$0,0#00000000000000000000000000000000:Default]
[{_}
[ {{10000@(113.42.0) [s0;%% [*@7;4 ImageMaker `- image cache system]]}}&]
[s1;@(0.0.255)3 &]
@ -138,4 +138,8 @@ onst]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 src])&]
[s2;%% Doubles the resolution of image, using smart heuristics algorithm
designed for upscaling synthetic images (like icons).&]
[s3;%% &]
[s0;%% ]]
[s4; &]
[s5;:Upp`:`:Downscale2x`(const Upp`:`:Image`&`): [_^Upp`:`:Image^ Image]_[* Downscale2x](
[@(0.0.255) const]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 src])&]
[s2;%% Halves the resolution of image.&]
[s3;%% ]]