From 64d389781677716555589539b4a1acc5d834c4e9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 14 Dec 2020 12:29:37 +0900 Subject: [PATCH] common sw_engine: apply partial composition. Introduce RendererMethod::renderRegion() to return acutal drawing region info. That is used by scene composition to composite actual partial drawing region for better performance. @Issues: 173 --- src/lib/gl_engine/tvgGlRenderer.cpp | 6 ++++ src/lib/gl_engine/tvgGlRenderer.h | 1 + src/lib/sw_engine/tvgSwCommon.h | 13 ++++--- src/lib/sw_engine/tvgSwImage.cpp | 11 +++--- src/lib/sw_engine/tvgSwRaster.cpp | 8 ++--- src/lib/sw_engine/tvgSwRenderer.cpp | 53 +++++++++++++++++------------ src/lib/sw_engine/tvgSwRenderer.h | 1 + src/lib/sw_engine/tvgSwShape.cpp | 7 ++-- src/lib/tvgPaint.h | 11 ++++++ src/lib/tvgPictureImpl.h | 7 ++++ src/lib/tvgRender.h | 1 + src/lib/tvgSceneImpl.h | 42 +++++++++++++++++++---- src/lib/tvgShapeImpl.h | 5 +++ 13 files changed, 118 insertions(+), 48 deletions(-) diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index d94da508..1a4cbed1 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -73,6 +73,12 @@ bool GlRenderer::sync() } +bool GlRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) +{ + return true; +} + + bool GlRenderer::preRender() { if (mRenderTasks.size() == 0) diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 9dd96948..d7cb96cd 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -39,6 +39,7 @@ public: bool render(const Shape& shape, void *data) override; bool render(const Picture& picture, void *data) override; bool postRender() override; + bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool sync() override; bool clear() override; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 6f26e8c4..3b14f5e4 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -207,7 +207,7 @@ struct SwShape SwFill* fill = nullptr; SwRleData* rle = nullptr; SwRleData* strokeRle = nullptr; - SwBBox bbox; + SwBBox bbox; //keep it boundary without stroke region. Using for optimal filling. bool rect; //Fast Track: Othogonal rectangle? }; @@ -217,7 +217,6 @@ struct SwImage SwOutline* outline = nullptr; SwRleData* rle = nullptr; uint32_t* data = nullptr; - SwBBox bbox; uint32_t w, h; }; @@ -277,12 +276,12 @@ SwPoint mathTransform(const Point* to, const Matrix* transform); 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); +bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox); bool shapePrepared(SwShape* shape); bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, 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); +bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape* shape); bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable); @@ -294,9 +293,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); +bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox); bool imagePrepared(SwImage* image); -bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, bool antiAlias, bool hasComposite); +bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, SwBBox& bbox, bool antiAlias, bool hasComposite); void imageDelOutline(SwImage* image, uint32_t tid); void imageReset(SwImage* image); bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform); @@ -325,7 +324,7 @@ void mpoolRetStrokeOutline(unsigned idx); bool rasterCompositor(SwSurface* surface); bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id); bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); -bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, uint8_t opacity); +bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, SwBBox& bbox, uint8_t opacity); bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterClear(SwSurface* surface); diff --git a/src/lib/sw_engine/tvgSwImage.cpp b/src/lib/sw_engine/tvgSwImage.cpp index cefcc079..2968cb16 100644 --- a/src/lib/sw_engine/tvgSwImage.cpp +++ b/src/lib/sw_engine/tvgSwImage.cpp @@ -90,13 +90,13 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi /************************************************************************/ -bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform) +bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox) { if (!imageGenOutline(image, pdata, tid, transform)) return false; - if (!_updateBBox(image->outline, image->bbox, clip)) return false; + if (!_updateBBox(image->outline, bbox, clip)) return false; - if (!_checkValid(image->outline, image->bbox, clip)) return false; + if (!_checkValid(image->outline, bbox, clip)) return false; return true; } @@ -108,9 +108,9 @@ bool imagePrepared(SwImage* image) } -bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, bool antiAlias, bool hasComposite) +bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, SwBBox& bbox, bool antiAlias, bool hasComposite) { - if ((image->rle = rleRender(image->rle, image->outline, image->bbox, clip, antiAlias))) return true; + if ((image->rle = rleRender(image->rle, image->outline, bbox, clip, antiAlias))) return true; return false; } @@ -127,7 +127,6 @@ void imageReset(SwImage* image) { rleReset(image->rle); image->rle = nullptr; - _initBBox(image->bbox); } diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 577b577f..5518c49a 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -498,7 +498,7 @@ bool rasterClear(SwSurface* surface) } -bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, uint8_t opacity) +bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, SwBBox& bbox, uint8_t opacity) { Matrix invTransform; @@ -512,11 +512,11 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, ui else { // Fast track if (_identify(transform)) { - return _rasterImage(surface, image->data, image->w, image->h, image->bbox); + return _rasterImage(surface, image->data, image->w, image->h, bbox); } else { - if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, image->bbox, &invTransform); - return _rasterImage(surface, image->data, image->w, image->h, image->bbox, &invTransform); + if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform); + return _rasterImage(surface, image->data, image->w, image->h, bbox, &invTransform); } } } \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 580705f1..c2038916 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -35,6 +35,7 @@ struct SwComposite SwSurface surface; SwSurface* recover; SwImage image; + SwBBox bbox; bool valid; }; @@ -46,6 +47,15 @@ struct SwTask : Task RenderUpdateFlag flags = RenderUpdateFlag::None; Array compList; uint32_t opacity; + SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region + + void bounds(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) + { + if (x) *x = bbox.min.x; + if (y) *y = bbox.min.y; + if (w) *w = bbox.max.x - bbox.min.x; + if (h) *h = bbox.max.y - bbox.min.y; + } virtual bool dispose() = 0; }; @@ -86,7 +96,7 @@ struct SwShapeTask : SwTask bool renderShape = (alpha > 0 || sdata->fill()); if (renderShape || strokeAlpha) { shapeReset(&shape); - if (!shapePrepare(&shape, sdata, tid, clip, transform)) goto end; + if (!shapePrepare(&shape, sdata, tid, clip, transform, bbox)) goto end; if (renderShape) { /* We assume that if stroke width is bigger than 2, shape outline below stroke could be full covered by stroke drawing. @@ -114,7 +124,7 @@ struct SwShapeTask : SwTask if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (strokeAlpha > 0) { shapeResetStroke(&shape, sdata, transform); - if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip)) goto end; + if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip, bbox)) goto end; ++addStroking; } else { shapeDelStroke(&shape); @@ -167,11 +177,11 @@ struct SwImageTask : SwTask if (prepareImage) { imageReset(&image); - if (!imagePrepare(&image, pdata, tid, clip, transform)) goto end; + if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end; //Composition? if (compList.count > 0) { - if (!imageGenRle(&image, pdata, clip, false, true)) goto end; + if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end; if (image.rle) { for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { if ((*comp).method == CompositeMethod::ClipPath) { @@ -274,12 +284,21 @@ bool SwRenderer::postRender() } +bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) +{ + static_cast(data)->bounds(x, y, w, h); + + return true; +} + + + bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data) { auto task = static_cast(data); task->done(); - return rasterImage(surface, &task->image, task->transform, task->opacity); + return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity); } @@ -316,16 +335,10 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) if (x + w > surface->w) w = (surface->w - x); if (y + h > surface->h) h = (surface->h - y); - //FIXME: Should be removed if xywh is proper. - x = 0; - y = 0; - w = surface->w; - h = surface->h; - - comp->image.bbox.min.x = x; - comp->image.bbox.min.y = y; - comp->image.bbox.max.x = x + w; - comp->image.bbox.max.y = y + h; + comp->bbox.min.x = x; + comp->bbox.min.y = y; + comp->bbox.max.x = x + w; + comp->bbox.max.y = y + h; comp->image.w = surface->w; comp->image.h = surface->h; @@ -362,7 +375,7 @@ bool SwRenderer::endComposite(void* p, uint32_t opacity) //Recover render target surface = comp->recover; - auto ret = rasterImage(surface, &comp->image, nullptr, opacity); + auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity); comp->valid = true; @@ -382,12 +395,8 @@ bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data) //Do Composition if (task->compStroking) { - //Add stroke size to bounding box. - auto strokeWidth = static_cast(ceilf(task->sdata->strokeWidth() * 0.5f)); - auto x = task->shape.bbox.min.x - strokeWidth; - auto y = task->shape.bbox.min.y - strokeWidth; - auto w = task->shape.bbox.max.x + strokeWidth - x; - auto h = task->shape.bbox.max.y + strokeWidth - y; + uint32_t x, y, w, h; + task->bounds(&x, &y, &w, &h); ctx = beginComposite(x, y, w, h); opacity = 255; //No Composition diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 30bca7b8..e3e600d0 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -43,6 +43,7 @@ public: bool dispose(void *data) override; bool preRender() override; bool postRender() override; + bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override; bool clear() override; bool render(const Shape& shape, void *data) override; bool render(const Picture& picture, void *data) override; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index eaef58e1..c8edac0d 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -420,7 +420,7 @@ bool _fastTrack(const SwOutline* outline) /* External Class Implementation */ /************************************************************************/ -bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform) +bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox) { if (!shapeGenOutline(shape, sdata, tid, transform)) return false; @@ -428,6 +428,8 @@ bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize if (!_checkValid(shape->outline, shape->bbox, clip)) return false; + bbox = shape->bbox; + return true; } @@ -588,7 +590,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) +bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox) { SwOutline* shapeOutline = nullptr; SwOutline* strokeOutline = nullptr; @@ -619,7 +621,6 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M goto fail; } - SwBBox bbox; _updateBBox(strokeOutline, bbox); if (!_checkValid(strokeOutline, bbox, clip)) { diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 0d811a21..7c01a722 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -37,6 +37,7 @@ namespace tvg virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has. virtual bool render(RenderMethod& renderer) = 0; virtual bool bounds(float* x, float* y, float* w, float* h) const = 0; + virtual bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const = 0; virtual Paint* duplicate() = 0; }; @@ -125,6 +126,11 @@ namespace tvg return smethod->bounds(x, y, w, h); } + bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const + { + return smethod->bounds(renderer, x, y, w, h); + } + bool dispose(RenderMethod& renderer) { if (compTarget) compTarget->pImpl->dispose(renderer); @@ -212,6 +218,11 @@ namespace tvg return inst->bounds(x, y, w, h); } + bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const override + { + return inst->bounds(renderer, x, y, w, h); + } + bool dispose(RenderMethod& renderer) override { return inst->dispose(renderer); diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 0e52963f..c84b04b5 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -153,6 +153,13 @@ struct Picture::Impl return paint->pImpl->bounds(x, y, w, h); } + bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) + { + if (edata) return renderer.renderRegion(edata, x, y, w, h); + if (paint) paint->pImpl->bounds(renderer, x, y, w, h); + return false; + } + Result load(const string& path) { if (loader) loader->close(); diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 383f6784..6557ff03 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -74,6 +74,7 @@ public: virtual bool render(const Shape& shape, void *data) = 0; virtual bool render(const Picture& picture, void *data) = 0; virtual bool postRender() = 0; + virtual bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0; virtual bool clear() = 0; virtual bool sync() = 0; }; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 9a9f36c2..71b17f29 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -63,17 +63,15 @@ struct Scene::Impl return edata; } - bool render(RenderMethod &renderer) + bool render(RenderMethod& renderer) { void* ctx = nullptr; //Half translucent. This requires intermediate composition. if (opacity < 255 && opacity > 0) { - //FIXME: Get Render Boundary of Shapes. - //float x, y, w, h; - //if (!bounds(&x, &y, &w, &h)) return false; - //ctx = renderer.beginComposite(roundf(x), roundf(y), roundf(w), roundf(h)); - ctx = renderer.beginComposite(0, 0, 0, 0); + uint32_t x, y, w, h; + if (!bounds(renderer, &x, &y, &w, &h)) return false; + ctx = renderer.beginComposite(x, y, w, h); } for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { @@ -85,6 +83,38 @@ struct Scene::Impl return true; } + bool bounds(RenderMethod& renderer, uint32_t* px, uint32_t* py, uint32_t* pw, uint32_t* ph) + { + if (paints.count == 0) return false; + + uint32_t x1 = UINT32_MAX; + uint32_t y1 = UINT32_MAX; + uint32_t x2 = 0; + uint32_t y2 = 0; + + for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { + uint32_t x = UINT32_MAX; + uint32_t y = UINT32_MAX; + uint32_t w = 0; + uint32_t h = 0; + + if (!(*paint)->pImpl->bounds(renderer, &x, &y, &w, &h)) continue; + + //Merge regions + if (x < x1) x1 = x; + if (x2 < x + w) x2 = (x + w); + if (y < y1) y1 = y; + if (y2 < y + h) y2 = (y + h); + } + + if (px) *px = x1; + if (py) *py = y1; + if (pw) *pw = (x2 - x1); + if (ph) *ph = (y2 - y1); + + return true; + } + bool bounds(float* px, float* py, float* pw, float* ph) { if (paints.count == 0) return false; diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 7df14259..f5a2dfa8 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -230,6 +230,11 @@ struct Shape::Impl return this->edata; } + bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) + { + return renderer.renderRegion(edata, x, y, w, h); + } + bool bounds(float* x, float* y, float* w, float* h) { auto ret = path.bounds(x, y, w, h);