mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
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:
parent
d09e6e9a27
commit
dd33c6e655
7 changed files with 269 additions and 173 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ file
|
|||
ImageOp.h,
|
||||
ImageOp.cpp,
|
||||
ImageChOp.cpp,
|
||||
Mify.cpp,
|
||||
ImageScale.cpp,
|
||||
RescaleFilter.cpp,
|
||||
MakeCache.cpp,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
236
uppsrc/Draw/Mify.cpp
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue