Painter: BufferPainter::Create

git-svn-id: svn://ultimatepp.org/upp/trunk@12530 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2018-11-12 22:44:10 +00:00
parent fb091313e2
commit de38ea3ee1
9 changed files with 120 additions and 121 deletions

View file

@ -32,22 +32,11 @@ String GetTypeName(const char *s)
bool TimingInspector::active = true;
#if defined(PLATFORM_POSIX) || defined(PLATFORM_WINCE)
inline int tmGetTime() {
return GetTickCount();
}
#else
inline int tmGetTime() {
return timeGetTime();
}
#endif
static TimingInspector s_zero; // time of Start / End without actual body to measure
TimingInspector::TimingInspector(const char *_name) {
name = _name ? _name : "";
start_time = 0;
all_count = call_count = max_nesting = nesting_depth = min_time = max_time = total_time = 0;
all_count = call_count = max_nesting = min_time = max_time = total_time = 0;
static bool init;
if(!init) {
#if defined(PLATFORM_WIN32) && !defined(PLATFORM_WINCE)
@ -63,21 +52,15 @@ TimingInspector::~TimingInspector() {
StdLog() << Dump() << "\r\n";
}
void TimingInspector::Start() {
Mutex::Lock __(mutex);
if(!active) return;
if(!nesting_depth++)
start_time = tmGetTime();
if(nesting_depth > max_nesting)
max_nesting = nesting_depth;
}
void TimingInspector::End() {
void TimingInspector::Add(dword time, int nesting)
{
time = tmGetTime() - time;
Mutex::Lock __(mutex);
if(!active) return;
all_count++;
if(!--nesting_depth) {
dword time = tmGetTime() - start_time;
if(nesting > max_nesting)
max_nesting = nesting;
if(nesting == 0) {
total_time += time;
if(call_count++ == 0)
min_time = max_time = time;
@ -97,8 +80,10 @@ String TimingInspector::Dump() {
return s + "No active hit";
ONCELOCK {
int w = GetTickCount();
while(GetTickCount() - w < 200)
TimingInspector::Routine __(s_zero);
while(GetTickCount() - w < 200) { // measure profiling overhead
thread_local int nesting = 0;
TimingInspector::Routine __(s_zero, nesting);
}
}
double tm = max(0.0, double(total_time) / call_count / 1000 -
double(s_zero.total_time) / s_zero.call_count / 1000);

View file

@ -1,5 +1,15 @@
class String;
#if defined(PLATFORM_POSIX) || defined(PLATFORM_WINCE)
inline int tmGetTime() {
return GetTickCount();
}
#else
inline int tmGetTime() {
return timeGetTime();
}
#endif
class TimingInspector {
protected:
static bool active;
@ -9,27 +19,34 @@ protected:
dword total_time;
dword min_time;
dword max_time;
int nesting_depth;
int max_nesting;
int all_count;
dword start_time;
StaticMutex mutex;
public:
TimingInspector(const char *name = NULL); // Not String !!!
~TimingInspector();
void Start();
void End();
void Add(dword time, int nesting);
String Dump();
class Routine {
public:
Routine(TimingInspector& stat) : stat(stat) { stat.Start(); }
~Routine() { stat.End(); }
Routine(TimingInspector& stat, int& nesting)
: stat(stat), nesting(nesting) {
start_time = tmGetTime();
nesting++;
}
~Routine() {
nesting--;
stat.Add(start_time, nesting);
}
protected:
dword start_time;
int& nesting;
TimingInspector& stat;
};
@ -54,7 +71,8 @@ private:
#define RTIMING(x) \
static UPP::TimingInspector COMBINE(sTmStat, __LINE__)(x); \
UPP::TimingInspector::Routine COMBINE(sTmStatR, __LINE__)(COMBINE(sTmStat, __LINE__));
static thread_local int COMBINE(sTmStatNesting, __LINE__); \
UPP::TimingInspector::Routine COMBINE(sTmStatR, __LINE__)(COMBINE(sTmStat, __LINE__), COMBINE(sTmStatNesting, __LINE__))
#define RACTIVATE_TIMING() TimingInspector::Activate(true);
#define RDEACTIVATE_TIMING() TimingInspector::Activate(false);

View file

@ -177,11 +177,12 @@ private:
PainterTarget *alt = NULL;
double alt_tolerance = Null;
ImageBuffer dummy;
ImageBuffer& ib;
int mode;
ImageBuffer *ip;
int mode = -1;
Buffer<int16> subpixel;
int render_cx;
int dopreclip;
int dopreclip = 0;
Sizef size = Sizef(0, 0); // = ib.GetSize()
Attr attr;
Array<Attr> attrstack;
@ -196,7 +197,6 @@ private:
RGBA gradient1, gradient2;
int gradientn;
Sizef size; // = ib.GetSize()
Rectf preclip;
int preclip_mtx_serial = -1;
bool regular;
@ -306,28 +306,29 @@ private:
static void RenderPathSegments(LinearPathConsumer *g, const Vector<byte>& path, const SimpleAttr *attr, double tolerance);
void CoRasterize(int from, int to);
void FinishPathJob();
void FinishFillJob() { fill_job.Finish(); }
enum { FILL = -1, CLIP = -2, ONPATH = -3 };
public:
ImageBuffer& GetBuffer() { return ib; }
const ImageBuffer& GetBuffer() const { return ib; }
void Finish();
ImageBuffer& GetBuffer() { return *ip; }
const ImageBuffer& GetBuffer() const { return *ip; }
BufferPainter& Co(bool b = true) { Finish(); co = b; return *this; }
BufferPainter& PreClip(bool b = true) { dopreclip = b; preclip_mtx_serial = -1; return *this; }
BufferPainter& PreClipDashed() { dopreclip = 2; preclip_mtx_serial = -1; return *this; }
BufferPainter& ImageCache(bool b = true) { imagecache = b; return *this; }
BufferPainter& NoImageCache(bool b = true) { return ImageCache(false); }
BufferPainter(ImageBuffer& ib, int mode = MODE_ANTIALIASED);
BufferPainter(PainterTarget& t, double tolerance = Null);
~BufferPainter() { Finish(); }
void Create(ImageBuffer& ib, int mode = MODE_ANTIALIASED);
void Finish();
BufferPainter(ImageBuffer& ib, int mode = MODE_ANTIALIASED) { Create(ib, mode); }
BufferPainter(PainterTarget& t, double tolerance = Null);
BufferPainter() : BufferPainter(dummy, MODE_ANTIALIASED) {}
~BufferPainter() { Finish(); }
};
#include "Interpolator.hpp"

View file

@ -146,22 +146,28 @@ void BufferPainter::ClearStopsOp()
attr.color_stop.Clear();
}
BufferPainter::BufferPainter(ImageBuffer& ib, int mode)
: ib(ib),
mode(mode),
rasterizer(ib.GetWidth(), ib.GetHeight(), mode == MODE_SUBPIXEL)
void BufferPainter::Create(ImageBuffer& ib, int mode_)
{
paths.Alloc(BATCH_SIZE);
path_info = paths;
ClearPath();
render_cx = ib.GetWidth();
if(mode == MODE_SUBPIXEL) {
render_cx *= 3;
subpixel.Alloc(render_cx + 30);
ip = &ib;
if(mode_ != mode || (Size)size != ib.GetSize()) {
mode = mode_;
rasterizer.Create(ib.GetWidth(), ib.GetHeight(), mode == MODE_SUBPIXEL);
paths.Alloc(BATCH_SIZE);
path_info = paths;
ClearPath();
render_cx = ib.GetWidth();
if(mode == MODE_SUBPIXEL) {
render_cx *= 3;
subpixel.Alloc(render_cx + 30);
}
size = ib.GetSize();
}
auto& a = attr;
Attr& a = attr;
a.cap = LINECAP_BUTT;
a.join = LINEJOIN_MITER;
a.miter_limit = 4;
@ -175,10 +181,14 @@ BufferPainter::BufferPainter(ImageBuffer& ib, int mode)
gradientn = Null;
dopreclip = false;
jobcount = 0;
size = ib.GetSize();
jobcount = fillcount = 0;
cojob.Clear();
cofill.Clear();
attrstack.Clear();
clip.Clear();
mask.Clear();
onpathstack.Clear();
pathlenstack.Clear();
}
BufferPainter::BufferPainter(PainterTarget& t, double tolerance)

View file

@ -121,6 +121,7 @@ private:
void Init();
Cell *AddCells(int y, int n);
void AddCells2(CellArray& a, int n);
void RenderHLine(int ey, int x1, int y1, int x2, int y2);
void LineClip(double x1, double y1, double x2, double y2);
int CvX(double x);
@ -154,9 +155,9 @@ public:
void Create(int cx, int cy, bool subpixel);
Rasterizer(int cx, int cy, bool subpixel);
Rasterizer() { sz = Size(0, 0); }
~Rasterizer();
Rasterizer(int cx, int cy, bool subpixel) { Create(cx, cy, subpixel); }
Rasterizer() { sz = Size(0, 0); }
~Rasterizer() { Free(); }
};
class LinearInterpolator {

View file

@ -5,9 +5,9 @@ namespace Upp {
void BufferPainter::BeginMaskOp()
{
attr.mask = true;
Size sz = ib.GetSize();
mask.Add() = ib;
ib.Create(sz);
Size sz = ip->GetSize();
mask.Add() = *ip;
ip->Create(sz);
Clear(RGBAZero());
Begin();
}
@ -30,21 +30,21 @@ static inline byte *sSpan(byte *t, int c, int& len)
void BufferPainter::FinishMask()
{
Buffer<byte> wb(mode == MODE_SUBPIXEL ? 6 * ib.GetWidth() : 2 * ib.GetWidth());
Buffer<byte> wb(mode == MODE_SUBPIXEL ? 6 * ip->GetWidth() : 2 * ip->GetWidth());
bool creating = false;
if(!attr.hasclip) {
clip.Add().Alloc(ib.GetHeight());
clip.Add().Alloc(ip->GetHeight());
attr.hasclip = true;
attr.cliplevel = clip.GetCount();
creating = true;
}
Buffer<ClippingLine>& cl = clip.Top();
for(int y = 0; y < ib.GetHeight(); y++)
for(int y = 0; y < ip->GetHeight(); y++)
if(creating || !cl[y].IsEmpty()) {
int c0 = 0;
int c256 = 0;
const RGBA *s = ib[y];
const RGBA *e = ib[y] + ib.GetWidth();
const RGBA *s = (*ip)[y];
const RGBA *e = (*ip)[y] + ip->GetWidth();
byte *t = wb;
while(s < e) {
int val = s->a * (56 * s->r + 183 * s->g + 20 * s->b) >> 16;
@ -77,7 +77,7 @@ void BufferPainter::FinishMask()
cl[y].Clear();
cl[y].Set(~wb, int(t - ~wb));
}
ib = mask.Top();
*ip = mask.Top();
mask.Drop();
attr.mask = false;
}

View file

@ -27,24 +27,6 @@
namespace Upp {
Rasterizer::Rasterizer(int cx, int cy, bool subpixel)
{
Create(cx, cy, subpixel);
}
Rasterizer::~Rasterizer()
{
Free();
}
void Rasterizer::Free()
{
if(cell)
for(int i = 0; i <= sz.cy; i++)
if(cell[i].alloc != SVO_ALLOC)
MemoryFree(cell[i].ptr);
}
void Rasterizer::Create(int cx, int cy, bool subpixel)
{
Free();
@ -62,6 +44,14 @@ void Rasterizer::Create(int cx, int cy, bool subpixel)
Reset();
}
void Rasterizer::Free()
{
if(cell)
for(int i = 0; i <= sz.cy; i++)
if(cell[i].alloc != SVO_ALLOC)
MemoryFree(cell[i].ptr);
}
void Rasterizer::Init()
{
p0 = Pointf(0, 0);
@ -86,7 +76,8 @@ void Rasterizer::SetClip(const Rectf& rect)
cliprect = rect & Sizef(sz);
}
force_inline Rasterizer::Cell *Rasterizer::AddCells(int y, int n)
force_inline
Rasterizer::Cell *Rasterizer::AddCells(int y, int n)
{
CellArray& a = cell[y];
if(a.count + n <= SVO_ALLOC) {

View file

@ -10,7 +10,7 @@ void PainterTarget::Fill(double width, SpanSource *ss, const RGBA& color) {}
void BufferPainter::ClearOp(const RGBA& color)
{
UPP::Fill(~ib, color, ib.GetLength());
UPP::Fill(~*ip, color, ip->GetLength());
}
BufferPainter::PathJob::PathJob(Rasterizer& rasterizer, double width, const PathInfo *path_info,
@ -165,7 +165,7 @@ Buffer<ClippingLine> BufferPainter::RenderPath(double width, Event<One<SpanSourc
if(width >= FILL && !ss && !alt && mode == MODE_ANTIALIASED) {
for(int i = 0; i < path_info->path.GetCount(); i++) {
while(jobcount >= cojob.GetCount())
cojob.Add().rasterizer.Create(ib.GetWidth(), ib.GetHeight(), false);
cojob.Add().rasterizer.Create(ip->GetWidth(), ip->GetHeight(), false);
CoJob& job = cojob[jobcount++];
job.path_info = path_info;
job.subpath = i;
@ -209,19 +209,19 @@ Buffer<ClippingLine> BufferPainter::RenderPath(double width, Event<One<SpanSourc
if(doclip) {
rg = &clip_filler;
newclip.Alloc(ib.GetHeight());
newclip.Alloc(ip->GetHeight());
}
else
if(ss) {
ss(rss);
RGBA *lspan;
if(co) {
co_span.Alloc((subpixel ? 3 : 1) * ib.GetWidth() + 3);
co_span.Alloc((subpixel ? 3 : 1) * ip->GetWidth() + 3);
lspan = co_span;
}
else {
if(!span)
span.Alloc((subpixel ? 3 : 1) * ib.GetWidth() + 3);
span.Alloc((subpixel ? 3 : 1) * ip->GetWidth() + 3);
lspan = span;
}
if(subpixel) {
@ -263,8 +263,8 @@ Buffer<ClippingLine> BufferPainter::RenderPath(double width, Event<One<SpanSourc
int y = (co ? co->Next() : ii++) + rasterizer.MinY();
if(y > rasterizer.MaxY())
break;
solid_filler.t = subpixel_filler.t = span_filler.t = ib[y];
subpixel_filler.end = subpixel_filler.t + ib.GetWidth();
solid_filler.t = subpixel_filler.t = span_filler.t = (*ip)[y];
subpixel_filler.end = subpixel_filler.t + ip->GetWidth();
span_filler.y = subpixel_filler.y = y;
Rasterizer::Filler *rf = rg;
if(clip.GetCount()) {
@ -306,21 +306,14 @@ Buffer<ClippingLine> BufferPainter::RenderPath(double width, Event<One<SpanSourc
pathlen = j.onpathtarget.len;
}
return newclip;
}
void BufferPainter::CoRasterize(int from, int to)
{
// DLOG("CoRasterize " << from << " " << to);
}
void BufferPainter::FinishPathJob()
{
if(jobcount == 0)
return;
// RLOG("===== Finish");
// DDUMP(runningjobs);
// DDUMP(jobcount);
// RTIMING("Finish");
RTIMING("Finish");
CoWork co;
co * [&] {
@ -344,7 +337,7 @@ void BufferPainter::FinishPathJob()
Swap(cofill, cojob); // Swap to keep allocated rasters (instead of pick)
fill_job & [=] {
int miny = ib.GetHeight() - 1;
int miny = ip->GetHeight() - 1;
int maxy = 0;
for(int i = 0; i < fillcount; i++) {
CoJob& j = cofill[i];
@ -362,7 +355,7 @@ void BufferPainter::FinishPathJob()
if(j.rasterizer.NotEmpty(y)) {
solid_filler.c = j.c;
solid_filler.invert = j.attr.invert;
solid_filler.t = ib[y];
solid_filler.t = (*ip)[y];
if(clip.GetCount()) {
MaskFillerFilter mf;
const ClippingLine& s = clip.Top()[y];

View file

@ -1,8 +1,8 @@
Clip does not need to sync MT
Clear co
DashOp(const char *)
------
Cache of downscaled images
CO images
UseImageCache option
TIMING Reset M : 10.48 ms - 551.63 ns (11.00 ms / 18992 ), min: 0.00 ns, max: 5.00 ms, nesting: 16 - 26000
TIMING Add alloc : 18.62 ms - 372.48 ns (20.00 ms / 49995 ), min: 0.00 ns, max: 1.00 ms, nesting: 3 - 50688
TIMING Finish : 1.68 s - 17.53 ms ( 1.68 s / 96 ), min: 0.00 ns, max: 252.00 ms, nesting: 1 - 96
TIMING Add : 1.67 s - 13.70 us ( 1.67 s / 121801 ), min: 0.00 ns, max: 191.00 ms, nesting: 18 - 1155176
TIMING Render span : 0.00 ns - 0.00 ns ( 0.00 ns / 320 ), min: 0.00 ns, max: 0.00 ns, nesting: 1 - 320
TIMING Reset : 15.67 ms - 1.29 us (16.00 ms / 12150 ), min: 0.00 ns, max: 5.00 ms, nesting: 18 - 12778
TIMING Create : 95.92 ms - 35.03 us (96.00 ms / 2738 ), min: 0.00 ns, max: 1.00 ms, nesting: 1 - 2738
TIMING Free : 27.85 ms - 5.09 us (28.00 ms / 5476 ), min: 0.00 ns, max: 1.00 ms, nesting: 1 - 5476