mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Draw: RescaleFilter now parallelized
git-svn-id: svn://ultimatepp.org/upp/trunk@14472 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
f10a923a10
commit
be4b4e3334
7 changed files with 161 additions and 142 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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])&]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -42,7 +42,6 @@ file
|
|||
ImageOp.cpp,
|
||||
ImageChOp.cpp,
|
||||
ImageScale.cpp,
|
||||
BiCubic.cpp,
|
||||
RescaleFilter.cpp,
|
||||
MakeCache.cpp,
|
||||
DrawRasterData.cpp,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;%% ]]
|
||||
Loading…
Add table
Add a link
Reference in a new issue