mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Painter: BufferPainter::Create
git-svn-id: svn://ultimatepp.org/upp/trunk@12530 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
fb091313e2
commit
de38ea3ee1
9 changed files with 120 additions and 121 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue