Draw: Minify SSE2 optimised, Core: Fixed to compile with FreeBSD

git-svn-id: svn://ultimatepp.org/upp/trunk@14596 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2020-06-15 11:57:51 +00:00
parent d09e6e9a27
commit dd33c6e655
7 changed files with 269 additions and 173 deletions

View file

@ -8,6 +8,9 @@
#endif
#endif
#ifdef PLATFORM_FREEBSD
#include <sys/vmmeter.h>
#endif
#ifdef PLATFORM_MACOS
#include <mach/mach.h>
#include <mach/vm_statistics.h>

View file

@ -42,6 +42,7 @@ file
ImageOp.h,
ImageOp.cpp,
ImageChOp.cpp,
Mify.cpp,
ImageScale.cpp,
RescaleFilter.cpp,
MakeCache.cpp,

View file

@ -859,38 +859,6 @@ Image FlipImage(const Image& m, int mode)
m);
}
Image Magnify(const Image& img, int nx, int ny)
{
if(nx == 1 && ny == 1)
return img;
if(nx == 0 || ny == 0)
return Image();
Size sz = img.GetSize();
bool xdown = nx < 0;
nx = abs(nx);
int ncx = xdown ? sz.cx / nx : sz.cx * nx;
ImageBuffer b(ncx, sz.cy * ny);
const RGBA *s = ~img;
const RGBA *e = s + img.GetLength();
RGBA *t = ~b;
while(s < e) {
RGBA *q = t;
const RGBA *le = s + sz.cx;
while(s < le) {
Fill(q, *s, nx);
q += nx;
s++;
}
for(int n = ny - 1; n--;) {
memcpy(q, t, ncx * sizeof(RGBA));
q += ncx;
}
t = q;
}
b.SetResolution(img.GetResolution());
return b;
}
static Pointf Cvp(double x, double y, double sina, double cosa)
{
return Pointf(x * cosa + y * sina, -x * sina + y * cosa);

View file

@ -158,8 +158,6 @@ struct ChPartMaker {
ChPartMaker(const Image& m);
};
Image Magnify(const Image& img, int nx, int ny);
// Image cache
struct ImageMaker {
@ -221,6 +219,10 @@ Image CachedRescalePaintOnly(const Image& m, Size sz, int filter = Null);
Image CachedSetColorKeepAlpha(const Image& img, Color color);
Image CachedSetColorKeepAlphaPaintOnly(const Image& img, Color color);
Image Magnify(const Image& img, int nx, int ny);
Image Minify(const Image& img, int nx, int ny, bool co = false);
Image MinifyCached(const Image& img, int nx, int ny, bool co);
Image Upscale2x(const Image& src);
Image Downscale2x(const Image& src);

236
uppsrc/Draw/Mify.cpp Normal file
View file

@ -0,0 +1,236 @@
#include "Draw.h"
namespace Upp {
#ifdef CPU_SSE2
Image Minify(const Image& img, int nx, int ny, bool co)
{
ASSERT(nx > 0 && ny > 0);
Size ssz = img.GetSize();
Size tsz = Size((ssz.cx + nx - 1) / nx, (ssz.cy + ny - 1) / ny);
ImageBuffer ib(tsz);
int scx0 = ssz.cx / nx * nx;
auto do_line = [&](int ty, __m128 *b, __m128 *div) {
memset(b, 0, tsz.cx * sizeof(__m128));
memset(div, 0, tsz.cx * sizeof(__m128));
__m128 v1 = _mm_set1_ps(1);
int yy = ny * ty;
for(int yi = 0; yi < ny; yi++) {
int y = yy + yi;
if(y < ssz.cy) {
const RGBA *s = img[yy + yi];
const RGBA *e = s + scx0;
const RGBA *e2 = s + ssz.cx;
__m128 *t = b;
__m128 *d = div;
while(s < e) {
__m128 px = _mm_setzero_ps();
__m128 dv = _mm_setzero_ps();
for(int n = nx; n--;) {
px = _mm_add_ps(px, LoadRGBAF(s++));
dv = _mm_add_ps(dv, v1);
}
*t++ = px;
*d++ = dv;
}
__m128 px = _mm_setzero_ps();
__m128 dv = _mm_setzero_ps();
while(s < e2) {
px = _mm_add_ps(px, LoadRGBAF(s++));
dv = _mm_add_ps(px, v1);
}
*t++ = px;
*d++ = dv;
}
}
__m128 *s = b;
__m128 *d = div;
RGBA *t = ~ib + ty * tsz.cx;
RGBA *e = t + tsz.cx;
while(t < e)
StoreRGBAF(t++, _mm_div_ps(*s++, *d++));
};
if(co) {
CoWork cw;
cw * [&] {
Buffer<__m128> div(tsz.cx);
Buffer<__m128> b(tsz.cx);
for(;;) {
int y = cw.Next();
if(y >= tsz.cy)
break;
do_line(y, b, div);
}
};
}
else {
Buffer<__m128> div(tsz.cx, _mm_setzero_ps());
Buffer<__m128> b(tsz.cx, _mm_setzero_ps());
for(int y = 0; y < tsz.cy; y++)
do_line(y, b, div);
}
return ib;
}
#else
struct RGBAV {
dword r, g, b, a;
void Set(dword v) { r = g = b = a = v; }
void Clear() { Set(0); }
void Put(dword weight, const RGBA& src) {
r += weight * src.r;
g += weight * src.g;
b += weight * src.b;
a += weight * src.a;
}
void Put(const RGBA& src) {
r += src.r;
g += src.g;
b += src.b;
a += src.a;
}
RGBA Get(int div) const {
RGBA c;
c.r = byte(r / div);
c.g = byte(g / div);
c.b = byte(b / div);
c.a = byte(a / div);
return c;
}
};
Image Minify(const Image& img, int nx, int ny, bool co)
{
ASSERT(nx > 0 && ny > 0);
Size ssz = img.GetSize();
Size tsz = Size((ssz.cx + nx - 1) / nx, (ssz.cy + ny - 1) / ny);
ImageBuffer ib(tsz);
int scx0 = ssz.cx / nx * nx;
auto do_line = [&](int ty, RGBAV *b, int *div) {
int yy = ny * ty;
for(int i = 0; i < tsz.cx; i++)
b[i].Clear();
memset(div, 0, tsz.cx * sizeof(int));
for(int yi = 0; yi < ny; yi++) {
int y = yy + yi;
if(y < ssz.cy) {
const RGBA *s = img[yy + yi];
const RGBA *e = s + scx0;
const RGBA *e2 = s + ssz.cx;
RGBAV *t = b;
int *dv = div;
while(s < e) {
for(int n = nx; n--;) {
t->Put(*s++);
(*dv)++;
}
t++;
dv++;
}
while(s < e2) {
t->Put(*s++);
(*dv)++;
}
}
}
const RGBAV *s = b;
const int *dv = div;
RGBA *it = ~ib + ty * tsz.cx;
for(int x = 0; x < tsz.cx; x++)
*it++ = (s++)->Get(*dv++);
};
if(co) {
CoWork cw;
cw * [&] {
Buffer<int> div(tsz.cx);
Buffer<RGBAV> b(tsz.cx);
for(;;) {
int y = cw.Next();
if(y >= tsz.cy)
break;
do_line(y, b, div);
}
};
}
else {
Buffer<int> div(tsz.cx);
Buffer<RGBAV> b(tsz.cx);
for(int y = 0; y < tsz.cy; y++)
do_line(y, b, div);
}
return ib;
}
#endif
struct MinifyImageMaker : public ImageMaker {
Image image;
int nx;
int ny;
bool co;
virtual String Key() const;
virtual Image Make() const;
};
String MinifyImageMaker::Key() const
{
String key;
RawCat(key, image.GetSerialId());
RawCat(key, nx);
RawCat(key, ny);
// we are not adding co as that is just a hint for actual image making
return key;
}
Image MinifyImageMaker::Make() const
{
return Minify(image, nx, ny, co);
}
Image MinifyCached(const Image& img, int nx, int ny, bool co)
{
MinifyImageMaker m;
m.image = img;
m.nx = nx;
m.ny = ny;
m.co = co;
return MakeImage(m);
}
Image Magnify(const Image& img, int nx, int ny)
{
if(nx == 1 && ny == 1)
return img;
if(nx == 0 || ny == 0)
return Image();
Size sz = img.GetSize();
bool xdown = nx < 0;
nx = abs(nx);
int ncx = xdown ? sz.cx / nx : sz.cx * nx;
ImageBuffer b(ncx, sz.cy * ny);
const RGBA *s = ~img;
const RGBA *e = s + img.GetLength();
RGBA *t = ~b;
while(s < e) {
RGBA *q = t;
const RGBA *le = s + sz.cx;
while(s < le) {
Fill(q, *s, nx);
q += nx;
s++;
}
for(int n = ny - 1; n--;) {
memcpy(q, t, ncx * sizeof(RGBA));
q += ncx;
}
t = q;
}
b.SetResolution(img.GetResolution());
return b;
}
};

View file

@ -110,6 +110,30 @@ with results being cached, that can only be used with Draw`::DrawImage(this
is optimization hint that can save some memory in certain situations).&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:Magnify`(const Upp`:`:Image`&`,int`,int`): [_^Upp`:`:Image^ Image]_[* Magnify
]([@(0.0.255) const]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 img],
[@(0.0.255) int]_[*@3 nx], [@(0.0.255) int]_[*@3 ny])&]
[s2;%% Multiplies the resolution of [%-*@3 img] by factors [%-*@3 nx]
and [%-*@3 ny] by simply repeating the pixels (each pixel becomes
[%-*@3 nx] x [%-*@3 ny] same color block).&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:Minify`(const Upp`:`:Image`&`,int`,int`,bool`): [_^Upp`:`:Image^ Image]_[* Mi
nify]([@(0.0.255) const]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 img],
[@(0.0.255) int]_[*@3 nx], [@(0.0.255) int]_[*@3 ny], [@(0.0.255) bool]_[*@3 co]_`=_[@(0.0.255) f
alse])&]
[s2;%% Reduces the resolution of [%-*@3 img] by factors [%-*@3 nx] and
[%-*@3 ny] by averaging pixel value (each [%-*@3 nx] x [%-*@3 ny] block
of pixels is averaged and produces single pixel in the resulting
image). If [%-*@3 co] is true, parallel processing is enabled.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:MinifyCached`(const Upp`:`:Image`&`,int`,int`,bool`): [_^Upp`:`:Image^ Imag
e]_[* MinifyCached]([@(0.0.255) const]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 img],
[@(0.0.255) int]_[*@3 nx], [@(0.0.255) int]_[*@3 ny], [@(0.0.255) bool]_[*@3 co])&]
[s2;%% [%-*@3 img] [%-*@3 nx] [%-*@3 ny] [%-*@3 co] .&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:Upscale2x`(const Upp`:`:Image`&`): [_^Upp`:`:Image^ Image]_[* Upscale2x]([@(0.0.255) c
onst]_[_^Upp`:`:Image^ Image][@(0.0.255) `&]_[*@3 src])&]
[s2;%% Doubles the resolution of image, using smart heuristics algorithm

View file

@ -2,146 +2,8 @@
namespace Upp {
struct RGBAV {
dword r, g, b, a;
void Set(dword v) { r = g = b = a = v; }
void Clear() { Set(0); }
void Put(dword weight, const RGBA& src) {
r += weight * src.r;
g += weight * src.g;
b += weight * src.b;
a += weight * src.a;
}
void Put(const RGBA& src) {
r += src.r;
g += src.g;
b += src.b;
a += src.a;
}
RGBA Get(int div) const {
RGBA c;
c.r = byte(r / div);
c.g = byte(g / div);
c.b = byte(b / div);
c.a = byte(a / div);
return c;
}
};
Image DownScale(const Image& img, int nx, int ny, bool co)
{
ASSERT(nx > 0 && ny > 0);
Size ssz = img.GetSize();
Size tsz = Size((ssz.cx + nx - 1) / nx, (ssz.cy + ny - 1) / ny);
ImageBuffer ib(tsz);
int scx0 = ssz.cx / nx * nx;
auto do_line = [&](int ty, RGBAV *b, int *div) {
int yy = ny * ty;
for(int i = 0; i < tsz.cx; i++)
b[i].Clear();
memset(div, 0, tsz.cx * sizeof(int));
for(int yi = 0; yi < ny; yi++) {
int y = yy + yi;
if(y < ssz.cy) {
const RGBA *s = img[yy + yi];
const RGBA *e = s + scx0;
const RGBA *e2 = s + ssz.cx;
RGBAV *t = b;
int *dv = div;
while(s < e) {
for(int n = nx; n--;) {
t->Put(*s++);
(*dv)++;
}
t++;
dv++;
}
while(s < e2) {
t->Put(*s++);
(*dv)++;
}
}
}
const RGBAV *s = b;
const int *dv = div;
RGBA *it = ~ib + ty * tsz.cx;
for(int x = 0; x < tsz.cx; x++)
*it++ = (s++)->Get(*dv++);
};
if(co) {
CoWork cw;
cw * [&] {
Buffer<int> div(tsz.cx);
Buffer<RGBAV> b(tsz.cx);
for(;;) {
int y = cw.Next();
if(y >= tsz.cy)
break;
do_line(y, b, div);
}
};
}
else {
Buffer<int> div(tsz.cx);
Buffer<RGBAV> b(tsz.cx);
for(int y = 0; y < tsz.cy; y++)
do_line(y, b, div);
}
return ib;
}
struct DownscaleImageMaker : public ImageMaker {
Image image;
int nx;
int ny;
bool co;
virtual String Key() const;
virtual Image Make() const;
};
String DownscaleImageMaker::Key() const
{
String key;
RawCat(key, image.GetSerialId());
RawCat(key, nx);
RawCat(key, ny);
// we are not adding co as that is just a hint for actual image making
return key;
}
Image DownscaleImageMaker::Make() const
{
return DownScale(image, nx, ny, co);
}
Image DownScaleCached(const Image& img, int nx, int ny, bool co)
{
DownscaleImageMaker m;
m.image = img;
m.nx = nx;
m.ny = ny;
m.co = co;
return MakeImage(m);
}
#ifdef CPU_X86
never_inline
String AsString(__m128 x)
{
float f[4];
memcpy(f, &x, 16);
return Sprintf("(%f, %f, %f, %f)", f[3], f[2], f[1], f[0]);
}
#if 1
#define DUMPS(x) RLOG(#x << " = " << AsString(x));
#else
#define DUMPS(x)
#endif
force_inline
int IntAndFraction(__m128 x, __m128& fraction)
{
@ -185,7 +47,7 @@ struct PainterImageSpanData {
xform = Inverse(m);
else {
if(!fast)
image = (imagecache ? DownScaleCached : DownScale)(image, nx, ny, co);
image = (imagecache ? MinifyCached : Minify)(image, nx, ny, co);
xform = Inverse(m) * Xform2D::Scale(1.0 / nx, 1.0 / ny);
}
cx = image.GetWidth();