From 736d6ee4ef7fba658a7ef45373487f90346f28a7 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 4 Jan 2021 00:46:59 +0900 Subject: [PATCH] common sw_engine: revise the masking implementation. We re-implement the masking feature with image composition method. This patch is working only for single shape but settle up coming extensions. --- src/examples/ClipPath.cpp | 5 +- src/examples/Masking.cpp | 47 +++++---- src/lib/gl_engine/tvgGlRenderer.cpp | 17 +++- src/lib/gl_engine/tvgGlRenderer.h | 15 +-- src/lib/sw_engine/tvgSwCommon.h | 14 ++- src/lib/sw_engine/tvgSwRaster.cpp | 114 +++++++++++++++++++--- src/lib/sw_engine/tvgSwRenderer.cpp | 146 +++++++++++++++------------- src/lib/sw_engine/tvgSwRenderer.h | 19 ++-- src/lib/tvgCanvasImpl.h | 2 +- src/lib/tvgPaint.h | 26 ++--- src/lib/tvgPictureImpl.h | 8 +- src/lib/tvgRender.h | 15 +-- src/lib/tvgSceneImpl.h | 17 ++-- src/lib/tvgShapeImpl.h | 6 +- 14 files changed, 292 insertions(+), 159 deletions(-) diff --git a/src/examples/ClipPath.cpp b/src/examples/ClipPath.cpp index d65c1e87..de57824b 100644 --- a/src/examples/ClipPath.cpp +++ b/src/examples/ClipPath.cpp @@ -100,10 +100,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) ////////////////////////////////////////////// auto picture = tvg::Picture::gen(); - char buf[PATH_MAX]; - sprintf(buf,"%s/cartman.svg", EXAMPLE_DIR); - - if (picture->load(buf) != tvg::Result::Success) return; + if (picture->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return; picture->scale(3); picture->translate(200, 400); diff --git a/src/examples/Masking.cpp b/src/examples/Masking.cpp index 4da3aa18..624ea6f3 100644 --- a/src/examples/Masking.cpp +++ b/src/examples/Masking.cpp @@ -11,16 +11,35 @@ void tvgDrawCmds(tvg::Canvas* canvas) { if (!canvas) return; - //Mask Target 2 -#if 0 - auto scene = tvg::Scene::gen(); - scene->opacity(127); - scene->scale(1.2); - scene->reserve(2); -#endif - //Star + //Solid Rectangle auto shape = tvg::Shape::gen(); + shape->appendRect(0, 0, 400, 400, 0, 0); + shape->fill(0, 0, 255, 255); + //Mask + auto mask = tvg::Shape::gen(); + mask->appendCircle(200, 200, 125, 125); + mask->fill(255, 0, 0, 255); + shape->composite(move(mask), tvg::CompositeMethod::AlphaMask); + canvas->push(move(shape)); + + //SVG + auto svg = tvg::Picture::gen(); + if (svg->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return; + svg->scale(3); + svg->translate(50, 400); + + //Mask2 + auto mask2 = tvg::Shape::gen(); + mask2->appendCircle(150, 500, 75, 75); + mask2->appendRect(150, 500, 200, 200, 30, 30); + mask2->fill(255, 255, 255, 255); + svg->composite(move(mask2), tvg::CompositeMethod::AlphaMask); + canvas->push(move(svg)); + + //Star + +#if 0 //Appends Paths shape->moveTo(199, 34); shape->lineTo(253, 143); @@ -33,20 +52,12 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->lineTo(26, 161); shape->lineTo(146, 143); shape->close(); - shape->fill(0, 0, 255, 255); -// shape->stroke(10); -// shape->stroke(255, 255, 255, 255); +#endif + //shape->opacity(127); // scene->push(move(shape)); - //Alpha Mask - auto mask = tvg::Shape::gen(); - mask->appendCircle(200, 200, 125, 125); - mask->fill(255, 255, 255, 255); - shape->composite(move(mask), tvg::CompositeMethod::AlphaMask); - canvas->push(move(shape)); - #if 0 scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask); if (canvas->push(move(scene)) != tvg::Result::Success) return; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 1e75e756..8df62dda 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -73,7 +73,7 @@ bool GlRenderer::sync() } -bool GlRenderer::renderRegion(TVG_UNUSED RenderData data, TVG_UNUSED uint32_t* x, TVG_UNUSED uint32_t* y, TVG_UNUSED uint32_t* w, TVG_UNUSED uint32_t* h) +bool GlRenderer::region(TVG_UNUSED RenderData data, TVG_UNUSED uint32_t* x, TVG_UNUSED uint32_t* y, TVG_UNUSED uint32_t* w, TVG_UNUSED uint32_t* h) { return true; } @@ -102,27 +102,34 @@ bool GlRenderer::postRender() } -Compositor* GlRenderer::addCompositor(TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h) +Compositor* GlRenderer::target(TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h) { //TODO: Prepare frameBuffer & Setup render target for composition return nullptr; } -bool GlRenderer::delCompositor(TVG_UNUSED Compositor* cmp) +bool GlRenderer::beginComposite(TVG_UNUSED Compositor* cmp, CompositeMethod method, uint32_t opacity) { //TODO: delete the given compositor and restore the context return false; } -bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED Compositor* cmp) +bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp) +{ + //TODO: delete the given compositor and restore the context + return false; +} + + +bool GlRenderer::renderImage(TVG_UNUSED void* data) { return false; } -bool GlRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp) +bool GlRenderer::renderShape(RenderData data) { auto sdata = static_cast(data); if (!sdata) return false; diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 19413997..7a982353 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -32,18 +32,21 @@ public: RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; - bool dispose(RenderData data) override; - Compositor* addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; - bool delCompositor(Compositor* cmp) override; bool preRender() override; - bool renderShape(RenderData data, Compositor* cmp) override; - bool renderImage(RenderData data, Compositor* cmp) override; + bool renderShape(RenderData data) override; + bool renderImage(RenderData data) override; bool postRender() override; - bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override; + bool dispose(RenderData data) override;; + bool region(RenderData 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; + Compositor* target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; + bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override; + bool endComposite(Compositor* cmp) override; + static GlRenderer* gen(); static int init(TVG_UNUSED uint32_t threads); static int term(); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index c0d22d4b..97dda994 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -226,9 +226,21 @@ struct SwBlender uint32_t (*alpha)(uint32_t rgba); }; +struct SwCompositor; + struct SwSurface : Surface { - SwBlender blender; + SwBlender blender; //mandatory + SwCompositor* compositor = nullptr; //compositor (optional) +}; + +struct SwCompositor : Compositor +{ + SwSurface* recoverSfc; //Recover surface when composition is started + SwCompositor* recoverCmp; //Recover compositor when composition is done + SwImage image; + SwBBox bbox; + bool valid; }; static inline SwCoord TO_SWCOORD(float val) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 791186ac..6e5141e7 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -92,7 +92,14 @@ static SwBBox _clipRegion(Surface* surface, SwBBox& in) } -static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) +static bool _translucent(SwSurface* surface, uint8_t a) +{ + if (a < 255) return true; + if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false; + return true; +} + +static bool _translucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -109,6 +116,46 @@ static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uin } +static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region, uint32_t color) +{ + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + +#ifdef THORVG_LOG_ENABLED + printf("SW_ENGINE: Rectangle Alpha Mask Composition\n"); +#endif + + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; //compositor buffer + auto tbuffer = static_cast(alloca(sizeof(uint32_t) * w)); //temp buffer for intermediate processing + + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface->stride]; + auto cmp = &cbuffer[y * surface->stride]; + auto tmp = tbuffer; + //Composition + for (uint32_t x = 0; x < w; ++x) { + *tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp)); + dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp)); + ++tmp; + ++cmp; + } + } + return true; +} + + +static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) +{ + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _translucentRectAlphaMask(surface, region, color); + } + } + return _translucentRect(surface, region, color); +} + + static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride); @@ -122,10 +169,8 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t } -static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color) +static bool _translucentRle(SwSurface* surface, SwRleData* rle, uint32_t color) { - if (!rle) return false; - auto span = rle->spans; uint32_t src; @@ -134,8 +179,8 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); else src = color; auto ialpha = 255 - surface->blender.alpha(src); - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + ALPHA_BLEND(dst[i], ialpha); + for (uint32_t x = 0; x < span->len; ++x) { + dst[x] = src + ALPHA_BLEND(dst[x], ialpha); } ++span; } @@ -143,6 +188,47 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c } +static bool _translucentRleAlphaMask(SwSurface* surface, SwRleData* rle, uint32_t color) +{ +#ifdef THORVG_LOG_ENABLED + printf("SW_ENGINE: Rle Alpha Mask Composition\n"); +#endif + auto span = rle->spans; + uint32_t src; + auto tbuffer = static_cast(alloca(sizeof(uint32_t) * surface->w)); //temp buffer for intermediate processing + auto cbuffer = surface->compositor->image.data; + + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto tmp = tbuffer; + if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); + else src = color; + for (uint32_t x = 0; x < span->len; ++x) { + *tmp = ALPHA_BLEND(src, surface->blender.alpha(*cmp)); + dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp)); + ++tmp; + ++cmp; + } + ++span; + } + return true; +} + + +static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color) +{ + if (!rle) return false; + + if (surface->compositor) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _translucentRleAlphaMask(surface, rle, color); + } + } + return _translucentRle(surface, rle, color); +} + + static bool _rasterTranslucentImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform) { auto span = rle->spans; @@ -456,17 +542,18 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, b = ALPHA_MULTIPLY(b, a); auto color = surface->blender.join(r, g, b, a); + auto translucent = _translucent(surface, a); //Fast Track if (shape->rect) { auto region = _clipRegion(surface, shape->bbox); - if (a == 255) return _rasterSolidRect(surface, region, color); - return _rasterTranslucentRect(surface, region, color); - } else{ - if (a == 255) return _rasterSolidRle(surface, shape->rle, color); + if (translucent) return _rasterTranslucentRect(surface, region, color); + return _rasterSolidRect(surface, region, color); + } + if (translucent) { return _rasterTranslucentRle(surface, shape->rle, color); } - return false; + return _rasterSolidRle(surface, shape->rle, color); } @@ -477,9 +564,10 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint b = ALPHA_MULTIPLY(b, a); auto color = surface->blender.join(r, g, b, a); + auto translucent = _translucent(surface, a); - if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color); - return _rasterTranslucentRle(surface, shape->strokeRle, color); + if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color); + return _rasterSolidRle(surface, shape->strokeRle, color); } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 5323947f..38dbaedc 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -30,15 +30,6 @@ static bool initEngine = false; static uint32_t rendererCnt = 0; -struct SwCompositor : Compositor -{ - SwSurface surface; - SwCompositor* recover; - SwImage image; - SwBBox bbox; - bool valid; -}; - struct SwTask : Task { @@ -51,10 +42,14 @@ struct SwTask : Task 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; + //Range over? + auto xx = bbox.min.x > 0 ? bbox.min.x : 0; + auto yy = bbox.min.y > 0 ? bbox.min.y : 0; + + if (x) *x = xx; + if (y) *y = yy; + if (w) *w = bbox.max.x - xx; + if (h) *h = bbox.max.y - yy; } virtual bool dispose() = 0; @@ -247,7 +242,6 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t if (!surface) { surface = new SwSurface; if (!surface) return false; - mainSurface = surface; } surface->buffer = buffer; @@ -272,7 +266,8 @@ bool SwRenderer::postRender() //Free Composite Caches for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) { - free((*comp)->image.data); + free((*comp)->compositor->image.data); + delete((*comp)->compositor); delete(*comp); } compositors.reset(); @@ -281,7 +276,7 @@ bool SwRenderer::postRender() } -bool SwRenderer::renderImage(RenderData data, TVG_UNUSED Compositor* cmp) +bool SwRenderer::renderImage(RenderData data) { auto task = static_cast(data); task->done(); @@ -292,7 +287,7 @@ bool SwRenderer::renderImage(RenderData data, TVG_UNUSED Compositor* cmp) } -bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp) +bool SwRenderer::renderShape(RenderData data) { auto task = static_cast(data); task->done(); @@ -300,18 +295,16 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp) if (task->opacity == 0) return true; uint32_t opacity; - Compositor* cmp2 = nullptr; + Compositor* cmp = nullptr; - //Do Composition + //Do Stroking Composition if (task->cmpStroking) { uint32_t x, y, w, h; task->bounds(&x, &y, &w, &h); opacity = 255; - //CompositeMethod::None is used for a default alpha blending - cmp2 = addCompositor(x, y, w, h); - cmp2->method = CompositeMethod::None; - cmp2->opacity = task->opacity; - //No Composition + cmp = target(x, y, w, h); + beginComposite(cmp, CompositeMethod::None, task->opacity); + //No Stroking Composition } else { opacity = task->opacity; } @@ -331,13 +324,12 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp) a = static_cast((opacity * (uint32_t) a) / 255); if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a); - //Composition (Shape + Stroke) stage - if (task->cmpStroking) delCompositor(cmp2); + if (task->cmpStroking) endComposite(cmp); return true; } -bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) +bool SwRenderer::region(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) { static_cast(data)->bounds(x, y, w, h); @@ -345,13 +337,31 @@ bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_ } -Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +bool SwRenderer::beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) { - SwCompositor* cmp = nullptr; + if (!cmp) return false; + auto p = static_cast(cmp); + + p->method = method; + p->opacity = opacity; + + //Current Context? + if (p->method != CompositeMethod::None) { + surface = p->recoverSfc; + surface->compositor = p; + } + + return true; +} + + +Compositor* SwRenderer::target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + SwSurface* cmp = nullptr; //Use cached data for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) { - if ((*p)->valid) { + if ((*p)->compositor->valid) { cmp = *p; break; } @@ -359,19 +369,21 @@ Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32 //New Composition if (!cmp) { - cmp = new SwCompositor; - if (!cmp) return nullptr; + cmp = new SwSurface; + if (!cmp) goto err; + + //Inherits attributes from main surface + *cmp = *surface; + + cmp->compositor = new SwCompositor; + if (!cmp->compositor) goto err; + //SwImage, Optimize Me: Surface size from MainSurface(WxH) to Parameter W x H - cmp->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h); - if (!cmp->image.data) { - delete(cmp); - return nullptr; - } + cmp->compositor->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h); + if (!cmp->compositor->image.data) goto err; compositors.push(cmp); } - cmp->valid = false; - //Boundary Check if (x + w > surface->w) w = (surface->w - x); if (y + h > surface->h) h = (surface->h - y); @@ -380,42 +392,44 @@ Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32 printf("SW_ENGINE: Using intermediate composition [Region: %d %d %d %d]\n", x, y, w, h); #endif - cmp->bbox.min.x = x; - cmp->bbox.min.y = y; - cmp->bbox.max.x = x + w; - cmp->bbox.max.y = y + h; - cmp->image.w = surface->w; - cmp->image.h = surface->h; - - //Inherits attributes from main surface - cmp->surface.blender = surface->blender; - cmp->surface.stride = surface->w; - cmp->surface.cs = surface->cs; + cmp->compositor->recoverSfc = surface; + cmp->compositor->recoverCmp = surface->compositor; + cmp->compositor->valid = false; + cmp->compositor->bbox.min.x = x; + cmp->compositor->bbox.min.y = y; + cmp->compositor->bbox.max.x = x + w; + cmp->compositor->bbox.max.y = y + h; + cmp->compositor->image.w = surface->w; + cmp->compositor->image.h = surface->h; //We know partial clear region - cmp->surface.buffer = cmp->image.data + (cmp->surface.stride * y + x); - cmp->surface.w = w; - cmp->surface.h = h; + cmp->buffer = cmp->compositor->image.data + (cmp->stride * y + x); + cmp->w = w; + cmp->h = h; - rasterClear(&cmp->surface); + rasterClear(cmp); //Recover context - cmp->surface.buffer = cmp->image.data; - cmp->surface.w = cmp->image.w; - cmp->surface.h = cmp->image.h; - - //Switch active compositor - cmp->recover = compositor; //Backup current compositor - compositor = cmp; + cmp->buffer = cmp->compositor->image.data; + cmp->w = cmp->compositor->image.w; + cmp->h = cmp->compositor->image.h; //Switch render target - surface = &cmp->surface; + surface = cmp; - return cmp; + return cmp->compositor; + +err: + if (cmp) { + if (cmp->compositor) delete(cmp->compositor); + delete(cmp); + } + + return nullptr; } -bool SwRenderer::delCompositor(Compositor* cmp) +bool SwRenderer::endComposite(Compositor* cmp) { if (!cmp) return false; @@ -423,8 +437,8 @@ bool SwRenderer::delCompositor(Compositor* cmp) p->valid = true; //Recover Context - compositor = p->recover; - surface = compositor ? &compositor->surface : mainSurface; + surface = p->recoverSfc; + surface->compositor = p->recoverCmp; //Default is alpha blending if (p->method == CompositeMethod::None) { diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 82b9259c..e681c840 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -36,28 +36,29 @@ class SwRenderer : public RenderMethod public: RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) override; - Compositor* addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; - bool delCompositor(Compositor* cmp) override; - bool dispose(RenderData data) override; bool preRender() override; + bool renderShape(RenderData data) override; + bool renderImage(RenderData data) override; bool postRender() override; - bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override; + bool dispose(RenderData data) override; + bool region(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override; + bool clear() override; - bool renderShape(RenderData data, Compositor* cmp) override; - bool renderImage(RenderData data, Compositor* cmp) override; bool sync() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); + Compositor* target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; + bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override; + bool endComposite(Compositor* cmp) override; + static SwRenderer* gen(); static bool init(uint32_t threads); static bool term(); private: SwSurface* surface = nullptr; //active surface - SwCompositor* compositor = nullptr; //active compositor - SwSurface* mainSurface = nullptr; //main (default) surface Array tasks; //async task list - Array compositors; //compositor cache list + Array compositors; //render targets cache list SwRenderer(){}; ~SwRenderer(); diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index ef63238d..1e870350 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -97,7 +97,7 @@ struct Canvas::Impl if (!renderer->preRender()) return Result::InsufficientCondition; for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { - if (!(*paint)->pImpl->render(*renderer)) return Result::InsufficientCondition; + if (!(*paint)->pImpl->render(*renderer, 255)) return Result::InsufficientCondition; } if (!renderer->postRender()) return Result::InsufficientCondition; diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index ceeb0c56..582ca3f7 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -35,7 +35,7 @@ namespace tvg virtual bool dispose(RenderMethod& renderer) = 0; virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has. - virtual bool render(RenderMethod& renderer) = 0; + virtual bool render(RenderMethod& renderer, uint32_t opacity) = 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; @@ -150,7 +150,7 @@ namespace tvg void *cmpData = nullptr; if (cmpTarget) { - cmpData = cmpTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag); + cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); } @@ -172,23 +172,25 @@ namespace tvg return edata; } - bool render(RenderMethod& renderer) + bool render(RenderMethod& renderer, uint32_t opacity) { Compositor* cmp = nullptr; - /* Note: only ClipPath is processed in update() step */ + /* Note: only ClipPath is processed in update() step. + Create a composition image. */ if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) { uint32_t x, y, w, h; if (!cmpTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false; - cmp = renderer.addCompositor(x, y, w, h); - cmp->method = CompositeMethod::None; - cmp->opacity = 255; - cmpTarget->pImpl->render(renderer); + cmp = renderer.target(x, y, w, h); + renderer.beginComposite(cmp, CompositeMethod::None, 255); + cmpTarget->pImpl->render(renderer, 255); } - auto ret = smethod->render(renderer); + if (cmp) renderer.beginComposite(cmp, CompositeMethod::AlphaMask, cmpTarget->pImpl->opacity); - renderer.delCompositor(cmp); + auto ret = smethod->render(renderer, ((opacity * this->opacity) / 255)); + + if (cmp) renderer.endComposite(cmp); return ret; } @@ -250,9 +252,9 @@ namespace tvg return inst->update(renderer, transform, opacity, clips, flag); } - bool render(RenderMethod& renderer) override + bool render(RenderMethod& renderer, uint32_t opacity) override { - return inst->render(renderer); + return inst->render(renderer, opacity); } Paint* duplicate() override diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index a9ff4484..f16bf027 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -122,10 +122,10 @@ struct Picture::Impl return rdata; } - bool render(RenderMethod &renderer) + bool render(RenderMethod &renderer, uint32_t opacity) { - if (pixels) return renderer.renderImage(rdata, nullptr); - else if (paint) return paint->pImpl->render(renderer); + if (pixels) return renderer.renderImage(rdata); + else if (paint) return paint->pImpl->render(renderer, opacity); return false; } @@ -155,7 +155,7 @@ struct Picture::Impl bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) { - if (rdata) return renderer.renderRegion(rdata, x, y, w, h); + if (rdata) return renderer.region(rdata, x, y, w, h); if (paint) return paint->pImpl->bounds(renderer, x, y, w, h); return false; } diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index befbf90b..7a900e49 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -67,16 +67,19 @@ struct RenderMethod virtual ~RenderMethod() {} virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) = 0; virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) = 0; - virtual Compositor* addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0; - virtual bool delCompositor(Compositor* cmp) = 0; - virtual bool dispose(RenderData data) = 0; virtual bool preRender() = 0; - virtual bool renderShape(RenderData data, Compositor* cmp) = 0; - virtual bool renderImage(RenderData data, Compositor* cmp) = 0; + virtual bool renderShape(RenderData data) = 0; + virtual bool renderImage(RenderData data) = 0; virtual bool postRender() = 0; - virtual bool renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0; + virtual bool dispose(RenderData data) = 0; + virtual bool region(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0; + virtual bool clear() = 0; virtual bool sync() = 0; + + virtual Compositor* target(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0; + virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0; + virtual bool endComposite(Compositor* cmp) = 0; }; } diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 047bb908..8ad12f99 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -31,7 +31,6 @@ struct Scene::Impl { Array paints; - uint32_t opacity; bool dispose(RenderMethod& renderer) { @@ -46,8 +45,6 @@ struct Scene::Impl void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flag) { - this->opacity = opacity; - /* Overriding opacity value. If this scene is half-translucent, It must do intermeidate composition with that opacity value. */ if (opacity > 0) opacity = 255; @@ -61,25 +58,23 @@ struct Scene::Impl return nullptr; } - bool render(RenderMethod& renderer) + bool render(RenderMethod& renderer, uint32_t opacity) { Compositor* cmp = nullptr; //Half translucent. This condition requires intermediate composition. - if (opacity < 255 && opacity > 0 && (paints.count > 1)) { + if ((opacity < 255 && opacity > 0) && (paints.count > 1)) { uint32_t x, y, w, h; if (!bounds(renderer, &x, &y, &w, &h)) return false; - //CompositeMethod::None is used for a default alpha blending - cmp = renderer.addCompositor(x, y, w, h); - cmp->method = CompositeMethod::None; - cmp->opacity = opacity; + cmp = renderer.target(x, y, w, h); + renderer.beginComposite(cmp, CompositeMethod::None, opacity); } for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { - if (!(*paint)->pImpl->render(renderer)) return false; + if (!(*paint)->pImpl->render(renderer, opacity)) return false; } - if (cmp) renderer.delCompositor(cmp); + if (cmp) renderer.endComposite(cmp); return true; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 2e697cac..de4112a2 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -218,9 +218,9 @@ struct Shape::Impl return renderer.dispose(rdata); } - bool render(RenderMethod& renderer) + bool render(RenderMethod& renderer, TVG_UNUSED uint32_t opacity) { - return renderer.renderShape(rdata, nullptr); + return renderer.renderShape(rdata); } void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) @@ -232,7 +232,7 @@ struct Shape::Impl bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) { - return renderer.renderRegion(rdata, x, y, w, h); + return renderer.region(rdata, x, y, w, h); } bool bounds(float* x, float* y, float* w, float* h)