diff --git a/uppsrc/Core/Debug.cpp b/uppsrc/Core/Debug.cpp index 08a5126dc..8613056bd 100644 --- a/uppsrc/Core/Debug.cpp +++ b/uppsrc/Core/Debug.cpp @@ -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); diff --git a/uppsrc/Core/Profile.h b/uppsrc/Core/Profile.h index b9b5ba04e..25af5ed00 100644 --- a/uppsrc/Core/Profile.h +++ b/uppsrc/Core/Profile.h @@ -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); diff --git a/uppsrc/Painter/BufferPainter.h b/uppsrc/Painter/BufferPainter.h index c4bbb1502..4048dded3 100644 --- a/uppsrc/Painter/BufferPainter.h +++ b/uppsrc/Painter/BufferPainter.h @@ -177,11 +177,12 @@ private: PainterTarget *alt = NULL; double alt_tolerance = Null; ImageBuffer dummy; - ImageBuffer& ib; - int mode; + ImageBuffer *ip; + int mode = -1; Buffer subpixel; int render_cx; - int dopreclip; + int dopreclip = 0; + Sizef size = Sizef(0, 0); // = ib.GetSize() Attr attr; Array 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& 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" diff --git a/uppsrc/Painter/Context.cpp b/uppsrc/Painter/Context.cpp index 7c75cc5e0..d3b751bc7 100644 --- a/uppsrc/Painter/Context.cpp +++ b/uppsrc/Painter/Context.cpp @@ -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) diff --git a/uppsrc/Painter/LinearPath.h b/uppsrc/Painter/LinearPath.h index 09a0c7c58..766da052c 100644 --- a/uppsrc/Painter/LinearPath.h +++ b/uppsrc/Painter/LinearPath.h @@ -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 { diff --git a/uppsrc/Painter/Mask.cpp b/uppsrc/Painter/Mask.cpp index e754a90c3..51575d6ee 100644 --- a/uppsrc/Painter/Mask.cpp +++ b/uppsrc/Painter/Mask.cpp @@ -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 wb(mode == MODE_SUBPIXEL ? 6 * ib.GetWidth() : 2 * ib.GetWidth()); + Buffer 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& 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; } diff --git a/uppsrc/Painter/Rasterizer.cpp b/uppsrc/Painter/Rasterizer.cpp index 63002bbce..a85a8de4a 100644 --- a/uppsrc/Painter/Rasterizer.cpp +++ b/uppsrc/Painter/Rasterizer.cpp @@ -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) { diff --git a/uppsrc/Painter/Render.cpp b/uppsrc/Painter/Render.cpp index 8739956a2..14b97cb8f 100644 --- a/uppsrc/Painter/Render.cpp +++ b/uppsrc/Painter/Render.cpp @@ -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 BufferPainter::RenderPath(double width, Event= 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 BufferPainter::RenderPath(double width, EventGetHeight()); } 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 BufferPainter::RenderPath(double width, EventNext() : 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 BufferPainter::RenderPath(double width, EventGetHeight() - 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]; diff --git a/uppsrc/Painter/Todo.txt b/uppsrc/Painter/Todo.txt index bb9f84a29..6293d1510 100644 --- a/uppsrc/Painter/Todo.txt +++ b/uppsrc/Painter/Todo.txt @@ -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