mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 22:58:44 +00:00
common sw_engine: optimize single rectangle ClipPath.
If ClipPath is a singular rectangle, we don't need to apply this to all children nodes to adjust rle span regions. Rather than its regular sequence, we can adjust render region as merging viewport that is introduced internally, All in all, If a Paint has a single ClipPath that is Rectangle, it sets viewport with Rectangle area that viewport is applied to raster engine to cut off the rendering boundary. In the normal case it brings trivial effects. but when use SVGs which has a viewbox, it could increase the performance up to 10% (profiled with 200 svgs rendering at the same time) Note that, this won't be applied if the Paint has affine or rotation transform. @Issues: 294
This commit is contained in:
parent
4a8f45577a
commit
f1fe36d8f6
13 changed files with 187 additions and 84 deletions
|
@ -111,7 +111,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
|
|||
star3->translate(400, 0);
|
||||
|
||||
auto clipRect = tvg::Shape::gen();
|
||||
clipRect->appendRect(480, 110, 200, 200, 0, 0); //x, y, w, h, rx, ry
|
||||
clipRect->appendRect(500, 120, 200, 200, 0, 0); //x, y, w, h, rx, ry
|
||||
clipRect->fill(255, 255, 255, 255); // clip object must have alpha.
|
||||
clipRect->translate(20, 20);
|
||||
|
||||
|
|
|
@ -234,6 +234,19 @@ RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const Render
|
|||
}
|
||||
|
||||
|
||||
RenderRegion GlRenderer::viewport()
|
||||
{
|
||||
return {0, 0, UINT32_MAX, UINT32_MAX};
|
||||
}
|
||||
|
||||
|
||||
bool GlRenderer::viewport(TVG_UNUSED const RenderRegion& vp)
|
||||
{
|
||||
//TODO:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int GlRenderer::init(uint32_t threads)
|
||||
{
|
||||
if ((initEngineCnt++) > 0) return true;
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
bool postRender() override;
|
||||
bool dispose(RenderData data) override;;
|
||||
RenderRegion region(RenderData data) override;
|
||||
RenderRegion viewport() override;
|
||||
bool viewport(const RenderRegion& vp) override;
|
||||
|
||||
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
|
||||
bool sync() override;
|
||||
|
|
|
@ -296,16 +296,16 @@ SwFixed mathLength(const SwPoint& pt);
|
|||
bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);
|
||||
SwFixed mathMean(SwFixed angle1, SwFixed angle2);
|
||||
SwPoint mathTransform(const Point* to, const Matrix* transform);
|
||||
bool mathUpdateOutlineBBox(const SwOutline* outline, SwBBox& bbox, const SwSize& clip);
|
||||
bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion);
|
||||
|
||||
void shapeReset(SwShape* shape);
|
||||
bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform);
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox);
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
|
||||
bool shapePrepared(const SwShape* shape);
|
||||
bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias, bool hasComposite);
|
||||
void shapeDelOutline(SwShape* shape, uint32_t tid);
|
||||
void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox);
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
|
||||
void shapeFree(SwShape* shape);
|
||||
void shapeDelStroke(SwShape* shape);
|
||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
|
||||
|
@ -320,9 +320,9 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
|
|||
SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid);
|
||||
void strokeFree(SwStroke* stroke);
|
||||
|
||||
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox);
|
||||
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
|
||||
bool imagePrepared(const SwImage* image);
|
||||
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& bbox, bool antiAlias, bool hasComposite);
|
||||
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias);
|
||||
void imageDelOutline(SwImage* image, uint32_t tid);
|
||||
void imageReset(SwImage* image);
|
||||
bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform);
|
||||
|
@ -334,7 +334,7 @@ void fillFree(SwFill* fill);
|
|||
void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len);
|
||||
void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len);
|
||||
|
||||
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& bbox, bool antiAlias);
|
||||
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias);
|
||||
void rleFree(SwRleData* rle);
|
||||
void rleReset(SwRleData* rle);
|
||||
void rleClipPath(SwRleData *rle, const SwRleData *clip);
|
||||
|
|
|
@ -33,16 +33,10 @@
|
|||
/************************************************************************/
|
||||
|
||||
|
||||
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox)
|
||||
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion)
|
||||
{
|
||||
if (!imageGenOutline(image, pdata, tid, transform)) return false;
|
||||
if (!mathUpdateOutlineBBox(image->outline, bbox, clip)) return false;
|
||||
|
||||
//Guarantee boundary from mathUpdateOutlineBBox()
|
||||
bbox.min.x = max(bbox.min.x, TO_SWCOORD(0));
|
||||
bbox.min.y = max(bbox.min.y, TO_SWCOORD(0));
|
||||
|
||||
return true;
|
||||
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion);
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,9 +46,9 @@ bool imagePrepared(const SwImage* image)
|
|||
}
|
||||
|
||||
|
||||
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& bbox, bool antiAlias, TVG_UNUSED bool hasComposite)
|
||||
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias)
|
||||
{
|
||||
if ((image->rle = rleRender(image->rle, image->outline, bbox, antiAlias))) return true;
|
||||
if ((image->rle = rleRender(image->rle, image->outline, renderRegion, antiAlias))) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -429,14 +429,14 @@ SwPoint mathTransform(const Point* to, const Matrix* transform)
|
|||
}
|
||||
|
||||
|
||||
bool mathUpdateOutlineBBox(const SwOutline* outline, SwBBox& bbox, const SwSize& clip)
|
||||
bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion)
|
||||
{
|
||||
if (!outline) return false;
|
||||
|
||||
auto pt = outline->pts;
|
||||
|
||||
if (outline->ptsCnt == 0 || outline->cntrsCnt <= 0) {
|
||||
bbox.reset();
|
||||
renderRegion.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -453,20 +453,22 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, SwBBox& bbox, const SwSize&
|
|||
if (yMin > pt->y) yMin = pt->y;
|
||||
if (yMax < pt->y) yMax = pt->y;
|
||||
}
|
||||
bbox.min.x = xMin >> 6;
|
||||
bbox.max.x = (xMax + 63) >> 6;
|
||||
bbox.min.y = yMin >> 6;
|
||||
bbox.max.y = (yMax + 63) >> 6;
|
||||
renderRegion.min.x = xMin >> 6;
|
||||
renderRegion.max.x = (xMax + 63) >> 6;
|
||||
renderRegion.min.y = yMin >> 6;
|
||||
renderRegion.max.y = (yMax + 63) >> 6;
|
||||
|
||||
//Guarantee surface boundary
|
||||
bbox.max.x = min(bbox.max.x, clip.w);
|
||||
bbox.max.y = min(bbox.max.y, clip.h);
|
||||
renderRegion.max.x = min(renderRegion.max.x, clipRegion.max.x);
|
||||
renderRegion.max.y = min(renderRegion.max.y, clipRegion.max.y);
|
||||
renderRegion.min.x = max(renderRegion.min.x, clipRegion.min.x);
|
||||
renderRegion.min.y = max(renderRegion.min.y, clipRegion.min.y);
|
||||
|
||||
//Check valid region
|
||||
if (bbox.max.x - bbox.min.x < 1 && bbox.max.y - bbox.min.y < 1) return false;
|
||||
if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false;
|
||||
|
||||
//Check boundary
|
||||
if (bbox.min.x >= clip.w || bbox.min.y >= clip.h || bbox.max.x <= 0 || bbox.max.y <= 0) return false;
|
||||
if (renderRegion.min.x >= clipRegion.max.x || renderRegion.min.y >= clipRegion.max.y ||
|
||||
renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -86,19 +86,6 @@ static bool _identify(const Matrix* transform)
|
|||
}
|
||||
|
||||
|
||||
static SwBBox _clipRegion(const Surface* surface, const SwBBox& in)
|
||||
{
|
||||
auto bbox = in;
|
||||
|
||||
if (bbox.min.x < 0) bbox.min.x = 0;
|
||||
if (bbox.min.y < 0) bbox.min.y = 0;
|
||||
if (bbox.max.x > static_cast<SwCoord>(surface->w)) bbox.max.x = surface->w;
|
||||
if (bbox.max.y > static_cast<SwCoord>(surface->h)) bbox.max.y = surface->h;
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
|
||||
static bool _translucent(const SwSurface* surface, uint8_t a)
|
||||
{
|
||||
if (a < 255) return true;
|
||||
|
@ -799,9 +786,8 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
|
|||
{
|
||||
//Fast Track
|
||||
if (shape->rect) {
|
||||
auto region = _clipRegion(surface, shape->bbox);
|
||||
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, region, shape->fill);
|
||||
return _rasterRadialGradientRect(surface, region, shape->fill);
|
||||
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill);
|
||||
return _rasterRadialGradientRect(surface, shape->bbox, shape->fill);
|
||||
} else {
|
||||
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
|
||||
return _rasterRadialGradientRle(surface, shape->rle, shape->fill);
|
||||
|
@ -821,9 +807,8 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g,
|
|||
|
||||
//Fast Track
|
||||
if (shape->rect) {
|
||||
auto region = _clipRegion(surface, shape->bbox);
|
||||
if (translucent) return _rasterTranslucentRect(surface, region, color);
|
||||
return _rasterSolidRect(surface, region, color);
|
||||
if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color);
|
||||
return _rasterSolidRect(surface, shape->bbox, color);
|
||||
}
|
||||
if (translucent) {
|
||||
return _rasterTranslucentRle(surface, shape->rle, color);
|
||||
|
|
|
@ -47,7 +47,6 @@ struct SwTask : Task
|
|||
//Range over?
|
||||
region.x = bbox.min.x > 0 ? bbox.min.x : 0;
|
||||
region.y = bbox.min.y > 0 ? bbox.min.y : 0;
|
||||
|
||||
region.w = bbox.max.x - region.x;
|
||||
region.h = bbox.max.y - region.y;
|
||||
|
||||
|
@ -79,8 +78,7 @@ struct SwShapeTask : SwTask
|
|||
sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha);
|
||||
}
|
||||
bool validStroke = (strokeAlpha > 0) || sdata->strokeFill();
|
||||
|
||||
SwSize clip = {static_cast<SwCoord>(surface->w), static_cast<SwCoord>(surface->h)};
|
||||
auto clipRegion = bbox;
|
||||
|
||||
//invisible shape turned to visible by alpha.
|
||||
auto prepareShape = false;
|
||||
|
@ -94,7 +92,7 @@ struct SwShapeTask : SwTask
|
|||
bool renderShape = (alpha > 0 || sdata->fill());
|
||||
if (renderShape || validStroke) {
|
||||
shapeReset(&shape);
|
||||
if (!shapePrepare(&shape, sdata, tid, clip, transform, bbox)) goto err;
|
||||
if (!shapePrepare(&shape, sdata, tid, transform, clipRegion, bbox)) goto err;
|
||||
if (renderShape) {
|
||||
/* We assume that if stroke width is bigger than 2,
|
||||
shape outline below stroke could be full covered by stroke drawing.
|
||||
|
@ -123,7 +121,7 @@ struct SwShapeTask : SwTask
|
|||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||
if (validStroke) {
|
||||
shapeResetStroke(&shape, sdata, transform);
|
||||
if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip, bbox)) goto err;
|
||||
if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clipRegion, bbox)) goto err;
|
||||
++addStroking;
|
||||
|
||||
if (auto fill = sdata->strokeFill()) {
|
||||
|
@ -177,7 +175,7 @@ struct SwImageTask : SwTask
|
|||
|
||||
void run(unsigned tid) override
|
||||
{
|
||||
SwSize clip = {static_cast<SwCoord>(surface->w), static_cast<SwCoord>(surface->h)};
|
||||
auto clipRegion = bbox;
|
||||
|
||||
//Invisible shape turned to visible by alpha.
|
||||
auto prepareImage = false;
|
||||
|
@ -185,11 +183,11 @@ struct SwImageTask : SwTask
|
|||
|
||||
if (prepareImage) {
|
||||
imageReset(&image);
|
||||
if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
|
||||
if (!imagePrepare(&image, pdata, tid, transform, clipRegion, bbox)) goto end;
|
||||
|
||||
//Clip Path?
|
||||
if (clips.count > 0) {
|
||||
if (!imageGenRle(&image, pdata, bbox, false, true)) goto end;
|
||||
if (!imageGenRle(&image, pdata, bbox, false)) goto end;
|
||||
if (image.rle) {
|
||||
for (auto clip = clips.data; clip < (clips.data + clips.count); ++clip) {
|
||||
auto clipper = &static_cast<SwShapeTask*>(*clip)->shape;
|
||||
|
@ -241,6 +239,12 @@ bool SwRenderer::clear()
|
|||
for (auto task = tasks.data; task < (tasks.data + tasks.count); ++task) (*task)->done();
|
||||
tasks.clear();
|
||||
|
||||
if (surface) {
|
||||
vport.x = vport.y = 0;
|
||||
vport.w = surface->w;
|
||||
vport.h = surface->h;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -251,6 +255,20 @@ bool SwRenderer::sync()
|
|||
}
|
||||
|
||||
|
||||
RenderRegion SwRenderer::viewport()
|
||||
{
|
||||
return vport;
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::viewport(const RenderRegion& vp)
|
||||
{
|
||||
this->vport = vp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
|
||||
{
|
||||
if (!buffer || stride == 0 || w == 0 || h == 0) return false;
|
||||
|
@ -266,6 +284,10 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
surface->h = h;
|
||||
surface->cs = cs;
|
||||
|
||||
vport.x = vport.y = 0;
|
||||
vport.w = surface->w;
|
||||
vport.h = surface->h;
|
||||
|
||||
return rasterCompositor(surface);
|
||||
}
|
||||
|
||||
|
@ -348,6 +370,7 @@ bool SwRenderer::renderShape(RenderData data)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
RenderRegion SwRenderer::region(RenderData data)
|
||||
{
|
||||
return static_cast<SwTask*>(data)->bounds();
|
||||
|
@ -514,6 +537,10 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
|
|||
task->opacity = opacity;
|
||||
task->surface = surface;
|
||||
task->flags = flags;
|
||||
task->bbox.min.x = max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.x));
|
||||
task->bbox.min.y = max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.y));
|
||||
task->bbox.max.x = min(static_cast<SwCoord>(surface->w), static_cast<SwCoord>(vport.x + vport.w));
|
||||
task->bbox.max.y = min(static_cast<SwCoord>(surface->h), static_cast<SwCoord>(vport.y + vport.h));
|
||||
|
||||
tasks.push(task);
|
||||
TaskScheduler::request(task);
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
bool postRender() override;
|
||||
bool dispose(RenderData data) override;
|
||||
RenderRegion region(RenderData data) override;
|
||||
RenderRegion viewport() override;
|
||||
bool viewport(const RenderRegion& vp) override;
|
||||
|
||||
bool clear() override;
|
||||
bool sync() override;
|
||||
|
@ -59,6 +61,7 @@ private:
|
|||
SwSurface* surface = nullptr; //active surface
|
||||
Array<SwTask*> tasks; //async task list
|
||||
Array<SwSurface*> compositors; //render targets cache list
|
||||
RenderRegion vport; //viewport
|
||||
|
||||
SwRenderer(){};
|
||||
~SwRenderer();
|
||||
|
|
|
@ -159,7 +159,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
|
|||
y += rw.cellMin.y;
|
||||
|
||||
//Clip Y range
|
||||
if (y < 0 || y >= rw.cellMax.y) return;
|
||||
if (y < rw.cellMin.y || y >= rw.cellMax.y) return;
|
||||
|
||||
/* compute the coverage line's coverage, depending on the outline fill rule */
|
||||
/* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
|
||||
|
@ -198,14 +198,14 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
|
|||
//Clip x range
|
||||
SwCoord xOver = 0;
|
||||
if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
|
||||
if (x < 0) xOver += x;
|
||||
if (x < rw.cellMin.x) xOver -= (rw.cellMin.x - x);
|
||||
|
||||
//span->len += (acount + xOver) - 1;
|
||||
span->len += (acount + xOver);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count >= MAX_SPANS) {
|
||||
if (count >= MAX_SPANS) {
|
||||
_genSpan(rw.rle, rw.spans, count);
|
||||
rw.spansCnt = 0;
|
||||
rw.ySpan = 0;
|
||||
|
@ -217,9 +217,9 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
|
|||
//Clip x range
|
||||
SwCoord xOver = 0;
|
||||
if (x + acount >= rw.cellMax.x) xOver -= (x + acount - rw.cellMax.x);
|
||||
if (x < 0) {
|
||||
xOver += x;
|
||||
x = 0;
|
||||
if (x < rw.cellMin.x) {
|
||||
xOver -= (rw.cellMin.x - x);
|
||||
x = rw.cellMin.x;
|
||||
}
|
||||
|
||||
//Nothing to draw
|
||||
|
@ -317,11 +317,10 @@ static void _setCell(RleWorker& rw, SwPoint pos)
|
|||
|
||||
/* All cells that are on the left of the clipping region go to the
|
||||
min_ex - 1 horizontal position. */
|
||||
pos.x -= rw.cellMin.x;
|
||||
pos.y -= rw.cellMin.y;
|
||||
|
||||
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
|
||||
pos.x -= rw.cellMin.x;
|
||||
if (pos.x < 0) pos.x = -1;
|
||||
|
||||
//Are we moving to a different cell?
|
||||
if (pos != rw.cellPos) {
|
||||
|
@ -340,7 +339,6 @@ static void _startCell(RleWorker& rw, SwPoint pos)
|
|||
{
|
||||
if (pos.x > rw.cellMax.x) pos.x = rw.cellMax.x;
|
||||
if (pos.x < rw.cellMin.x) pos.x = rw.cellMin.x;
|
||||
//if (pos.x < rw.cellMin.x) pos.x = (rw.cellMin.x - 1);
|
||||
|
||||
rw.area = 0;
|
||||
rw.cover = 0;
|
||||
|
@ -373,10 +371,9 @@ static void _lineTo(RleWorker& rw, const SwPoint& to)
|
|||
auto e2 = TRUNC(to);
|
||||
|
||||
//vertical clipping
|
||||
if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) ||
|
||||
(e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) {
|
||||
rw.pos = to;
|
||||
return;
|
||||
if ((e1.y >= rw.cellMax.y && e2.y >= rw.cellMax.y) || (e1.y < rw.cellMin.y && e2.y < rw.cellMin.y)) {
|
||||
rw.pos = to;
|
||||
return;
|
||||
}
|
||||
|
||||
auto diff = to - rw.pos;
|
||||
|
@ -782,7 +779,7 @@ void _replaceClipSpan(SwRleData *rle, SwSpan* clippedSpans, uint32_t size)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& bbox, bool antiAlias)
|
||||
SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias)
|
||||
{
|
||||
constexpr auto RENDER_POOL_SIZE = 16384L;
|
||||
constexpr auto BAND_SIZE = 40;
|
||||
|
@ -801,8 +798,8 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& bbo
|
|||
rw.area = 0;
|
||||
rw.cover = 0;
|
||||
rw.invalid = true;
|
||||
rw.cellMin = bbox.min;
|
||||
rw.cellMax = bbox.max;
|
||||
rw.cellMin = renderRegion.min;
|
||||
rw.cellMax = renderRegion.max;
|
||||
rw.cellXCnt = rw.cellMax.x - rw.cellMin.x;
|
||||
rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
|
||||
rw.ySpan = 0;
|
||||
|
|
|
@ -367,12 +367,20 @@ bool _fastTrack(const SwOutline* outline)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox)
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion)
|
||||
{
|
||||
if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
|
||||
if (!mathUpdateOutlineBBox(shape->outline, shape->bbox, clip)) return false;
|
||||
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion)) return false;
|
||||
|
||||
bbox = shape->bbox;
|
||||
//Keep it for Rasterization Region
|
||||
shape->bbox = renderRegion;
|
||||
|
||||
//Check valid region
|
||||
if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false;
|
||||
|
||||
//Check boundary
|
||||
if (renderRegion.min.x >= clipRegion.max.x || renderRegion.min.y >= clipRegion.max.y ||
|
||||
renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -393,7 +401,7 @@ bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias,
|
|||
//Case A: Fast Track Rectangle Drawing
|
||||
if (!hasComposite && (shape->rect = _fastTrack(shape->outline))) return true;
|
||||
//Case B: Normale Shape RLE Drawing
|
||||
if ((shape->rle = rleRender(shape->rle, shape->outline, shape->bbox, antiAlias))) return true;
|
||||
if ((shape->rle = rleRender(shape->rle, shape->outline, shape->bbox,antiAlias))) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -535,7 +543,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor
|
|||
}
|
||||
|
||||
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox)
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion)
|
||||
{
|
||||
SwOutline* shapeOutline = nullptr;
|
||||
SwOutline* strokeOutline = nullptr;
|
||||
|
@ -566,12 +574,12 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (!mathUpdateOutlineBBox(strokeOutline, bbox, clip)) {
|
||||
if (!mathUpdateOutlineBBox(strokeOutline, clipRegion, renderRegion)) {
|
||||
ret = false;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
shape->strokeRle = rleRender(shape->strokeRle, strokeOutline, bbox, true);
|
||||
shape->strokeRle = rleRender(shape->strokeRle, strokeOutline, renderRegion, true);
|
||||
|
||||
fail:
|
||||
if (freeOutline) {
|
||||
|
|
|
@ -26,6 +26,58 @@
|
|||
#include <math.h>
|
||||
#include "tvgRender.h"
|
||||
|
||||
static inline bool FLT_SAME(float a, float b)
|
||||
{
|
||||
return (fabsf(a - b) < FLT_EPSILON);
|
||||
}
|
||||
|
||||
static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* transform, RenderRegion& viewport)
|
||||
{
|
||||
/* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
|
||||
auto shape = static_cast<Shape*>(cmpTarget);
|
||||
|
||||
//Rectangle Candidates?
|
||||
const Point* pts;
|
||||
if (shape->pathCoords(&pts) != 4) return false;
|
||||
|
||||
//No Rotation?
|
||||
if (transform) {
|
||||
if (transform->m.e12 != 0 || transform->m.e21 != 0 || transform->m.e11 != transform->m.e22) return false;
|
||||
}
|
||||
|
||||
//Othogonal Rectangle?
|
||||
auto pt1 = pts + 0;
|
||||
auto pt2 = pts + 1;
|
||||
auto pt3 = pts + 2;
|
||||
auto pt4 = pts + 3;
|
||||
|
||||
if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) ||
|
||||
(FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) {
|
||||
|
||||
auto x1 = pt1->x;
|
||||
auto y1 = pt1->y;
|
||||
auto x2 = pt3->x;
|
||||
auto y2 = pt3->y;
|
||||
|
||||
if (transform) {
|
||||
x1 = x1 * transform->m.e11 + transform->m.e13;
|
||||
y1 = y1 * transform->m.e22 + transform->m.e23;
|
||||
x2 = x2 * transform->m.e11 + transform->m.e13;
|
||||
y2 = y2 * transform->m.e22 + transform->m.e23;
|
||||
}
|
||||
|
||||
viewport.x = static_cast<uint32_t>(x1);
|
||||
viewport.y = static_cast<uint32_t>(y1);
|
||||
viewport.w = static_cast<uint32_t>(roundf(x2 - x1 + 0.5f));
|
||||
viewport.h = static_cast<uint32_t>(roundf(y2 - y1 + 0.5f));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
namespace tvg
|
||||
{
|
||||
enum class PaintType { Shape = 0, Scene, Picture };
|
||||
|
@ -150,13 +202,29 @@ namespace tvg
|
|||
}
|
||||
}
|
||||
|
||||
/* 1. Composition Pre Processing */
|
||||
void *cmpData = nullptr;
|
||||
RenderRegion viewport;
|
||||
bool cmpFastTrack = false;
|
||||
|
||||
if (cmpTarget) {
|
||||
cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag);
|
||||
if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
|
||||
/* If transform has no rotation factors && ClipPath is a simple rectangle,
|
||||
we can avoid regular ClipPath sequence but use viewport for performance */
|
||||
if (cmpMethod == CompositeMethod::ClipPath) {
|
||||
RenderRegion viewport2;
|
||||
if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, viewport2))) {
|
||||
viewport = renderer.viewport();
|
||||
renderer.viewport(viewport2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cmpFastTrack) {
|
||||
cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag);
|
||||
if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. Main Update */
|
||||
void *edata = nullptr;
|
||||
auto newFlag = static_cast<RenderUpdateFlag>(pFlag | flag);
|
||||
flag = RenderUpdateFlag::None;
|
||||
|
@ -170,7 +238,9 @@ namespace tvg
|
|||
edata = smethod->update(renderer, outTransform, opacity, clips, newFlag);
|
||||
}
|
||||
|
||||
if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop();
|
||||
/* 3. Composition Post Processing */
|
||||
if (cmpFastTrack) renderer.viewport(viewport);
|
||||
else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop();
|
||||
|
||||
return edata;
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ struct Surface
|
|||
{
|
||||
//TODO: Union for multiple types
|
||||
uint32_t* buffer;
|
||||
uint32_t stride;
|
||||
uint32_t w, h;
|
||||
uint32_t cs;
|
||||
uint32_t stride;
|
||||
uint32_t w, h;
|
||||
uint32_t cs;
|
||||
};
|
||||
|
||||
using RenderData = void*;
|
||||
|
@ -78,6 +78,8 @@ public:
|
|||
virtual bool postRender() = 0;
|
||||
virtual bool dispose(RenderData data) = 0;
|
||||
virtual RenderRegion region(RenderData data) = 0;
|
||||
virtual RenderRegion viewport() = 0;
|
||||
virtual bool viewport(const RenderRegion& vp) = 0;
|
||||
|
||||
virtual bool clear() = 0;
|
||||
virtual bool sync() = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue