From 4767f83b99293238619307463d5db0efe7d34c0a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 25 Dec 2020 19:47:01 +0900 Subject: [PATCH] common composite: code refactoring Splited out ClipPath routine from other pixel compositions' since yet it's unlikely compatible... Also revise internal engine interfaces to be simpler. This is a step forward to enhance masking feature. --- inc/thorvg.h | 1 + src/examples/Masking.cpp | 24 +-- src/lib/gl_engine/tvgGlCommon.h | 1 + src/lib/gl_engine/tvgGlRenderer.cpp | 33 ++-- src/lib/gl_engine/tvgGlRenderer.h | 16 +- src/lib/sw_engine/tvgSwRenderer.cpp | 249 ++++++++++++++-------------- src/lib/sw_engine/tvgSwRenderer.h | 28 ++-- src/lib/tvgCanvasImpl.h | 6 +- src/lib/tvgPaint.h | 37 +++-- src/lib/tvgPicture.cpp | 8 + src/lib/tvgPictureImpl.h | 22 +-- src/lib/tvgRender.h | 22 +-- src/lib/tvgSceneImpl.h | 27 ++- src/lib/tvgShapeImpl.h | 14 +- 14 files changed, 251 insertions(+), 237 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 01f19042..e525dc73 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -279,6 +279,7 @@ public: Result size(float w, float h) noexcept; Result size(float* w, float* h) const noexcept; + const uint32_t* data() const noexcept; static std::unique_ptr gen() noexcept; diff --git a/src/examples/Masking.cpp b/src/examples/Masking.cpp index 08eb1eee..4da3aa18 100644 --- a/src/examples/Masking.cpp +++ b/src/examples/Masking.cpp @@ -12,11 +12,12 @@ 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 auto shape = tvg::Shape::gen(); @@ -33,17 +34,20 @@ void tvgDrawCmds(tvg::Canvas* canvas) shape->lineTo(146, 143); shape->close(); shape->fill(0, 0, 255, 255); - shape->stroke(10); - shape->stroke(255, 255, 255, 255); - shape->opacity(127); +// shape->stroke(10); +// shape->stroke(255, 255, 255, 255); + //shape->opacity(127); - scene->push(move(shape)); +// scene->push(move(shape)); //Alpha Mask - auto mask2 = tvg::Shape::gen(); - mask2->appendCircle(200, 200, 125, 125); - mask2->fill(255, 255, 255, 100); + 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; @@ -66,9 +70,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) picture->composite(move(mask), tvg::CompositeMethod::AlphaMask); if (canvas->push(move(picture)) != tvg::Result::Success) return; - - - +#endif } diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h index 7c5ba2e6..31dd1028 100644 --- a/src/lib/gl_engine/tvgGlCommon.h +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -54,6 +54,7 @@ class GlGeometry; struct GlShape { + const Shape* shape = nullptr; float viewWd; float viewHt; RenderUpdateFlag updateFlag; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index 1a4cbed1..bae6e4f6 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(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) +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) { return true; } @@ -102,31 +102,29 @@ bool GlRenderer::postRender() } -void* GlRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +void* GlRenderer::addCompositor(TVG_UNUSED CompositeMethod method, TVG_UNUSED uint32_t x, TVG_UNUSED uint32_t y, TVG_UNUSED uint32_t w, TVG_UNUSED uint32_t h, TVG_UNUSED uint32_t opacity) { //TODO: Prepare frameBuffer & Setup render target for composition return nullptr; } -bool GlRenderer::endComposite(void* ctx, uint32_t opacity) +bool GlRenderer::delCompositor(TVG_UNUSED void* cmp) { - //TODO: Composite Framebuffer to main surface + //TODO: delete the given compositor and restore the context return false; } -bool GlRenderer::render(const Picture& picture, void *data) +bool GlRenderer::renderImage(TVG_UNUSED void* data, TVG_UNUSED void* cmp) { - //TODO Draw Bitmap Image - - return true; + return false; } -bool GlRenderer::render(const Shape& shape, void* data) +bool GlRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp) { - GlShape* sdata = static_cast(data); + auto sdata = static_cast(data); if (!sdata) return false; uint8_t r, g, b, a; @@ -139,17 +137,17 @@ bool GlRenderer::render(const Shape& shape, void* data) { if (flags & RenderUpdateFlag::Gradient) { - const Fill* gradient = shape.fill(); + const Fill* gradient = sdata->shape->fill(); drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient); } else if (flags & RenderUpdateFlag::Color) { - shape.fillColor(&r, &g, &b, &a); + sdata->shape->fillColor(&r, &g, &b, &a); drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color); } if (flags & RenderUpdateFlag::Stroke) { - shape.strokeColor(&r, &g, &b, &a); + sdata->shape->strokeColor(&r, &g, &b, &a); drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke); } } @@ -158,9 +156,9 @@ bool GlRenderer::render(const Shape& shape, void* data) } -bool GlRenderer::dispose(void *data) +bool GlRenderer::dispose(RenderData data) { - GlShape* sdata = static_cast(data); + auto sdata = static_cast(data); if (!sdata) return false; delete sdata; @@ -168,20 +166,21 @@ bool GlRenderer::dispose(void *data) } -void* GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED void* data, TVG_UNUSED uint32_t *buffer, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array& compList, TVG_UNUSED RenderUpdateFlag flags) +RenderData GlRenderer::prepare(TVG_UNUSED const Picture& picture, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array& clips, TVG_UNUSED RenderUpdateFlag flags) { //TODO: return nullptr; } -void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array& compList, RenderUpdateFlag flags) +RenderData GlRenderer::prepare(const Shape& shape, RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array& clips, RenderUpdateFlag flags) { //prepare shape data GlShape* sdata = static_cast(data); if (!sdata) { sdata = new GlShape; if (!sdata) return nullptr; + sdata->shape = &shape; } sdata->viewWd = static_cast(surface.w); diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index d7cb96cd..d1da960c 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -30,16 +30,16 @@ class GlRenderer : public RenderMethod public: Surface surface = {nullptr, 0, 0, 0}; - void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) override; - void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) override; - bool dispose(void *data) override; - void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; - bool endComposite(void* ctx, uint32_t opacity) override; + 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; + void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override; + bool delCompositor(void* cmp) override; bool preRender() override; - bool render(const Shape& shape, void *data) override; - bool render(const Picture& picture, void *data) override; + bool renderShape(RenderData data, void* cmp) override; + bool renderImage(RenderData data, void* cmp) override; bool postRender() override; - bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override; + bool renderRegion(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; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index de76176c..cbb51dcf 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -33,9 +33,11 @@ static uint32_t rendererCnt = 0; struct SwComposite { SwSurface surface; - SwSurface* recover; + SwComposite* recover; SwImage image; SwBBox bbox; + CompositeMethod method; + uint32_t opacity; bool valid; }; @@ -45,7 +47,7 @@ struct SwTask : Task Matrix* transform = nullptr; SwSurface* surface = nullptr; RenderUpdateFlag flags = RenderUpdateFlag::None; - Array compList; + Array clips; uint32_t opacity; SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region @@ -102,7 +104,7 @@ struct SwShapeTask : SwTask shape outline below stroke could be full covered by stroke drawing. Thus it turns off antialising in that condition. */ auto antiAlias = (strokeAlpha == 255 && strokeWidth > 2) ? false : true; - if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.count > 0 ? true : false)) goto end; + if (!shapeGenRle(&shape, sdata, clip, antiAlias, clips.count > 0 ? true : false)) goto end; ++addStroking; } } @@ -131,22 +133,18 @@ struct SwShapeTask : SwTask } } - //Composition - for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { - auto compShape = &static_cast((*comp).edata)->shape; - if ((*comp).method == CompositeMethod::ClipPath) { - //Clip shape rle - if (shape.rle) { - if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox); - else if (compShape->rle) rleClipPath(shape.rle, compShape->rle); - } - //Clip stroke rle - if (shape.strokeRle) { - if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox); - else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle); - } - } else if ((*comp).method == CompositeMethod::AlphaMask) { - rleAlphaMask(shape.rle, compShape->rle); + //Clip Path + for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) { + auto compShape = &static_cast(*comp)->shape; + //Clip shape rle + if (shape.rle) { + if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox); + else if (compShape->rle) rleClipPath(shape.rle, compShape->rle); + } + //Clip stroke rle + if (shape.strokeRle) { + if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox); + else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle); } } end: @@ -167,7 +165,6 @@ struct SwImageTask : SwTask { SwImage image; const Picture* pdata = nullptr; - uint32_t* pixels = nullptr; void run(unsigned tid) override { @@ -181,23 +178,19 @@ struct SwImageTask : SwTask imageReset(&image); if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end; - //Composition? - if (compList.count > 0) { + //Clip Path? + if (clips.count > 0) { if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end; if (image.rle) { - for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { - auto compShape = &static_cast((*comp).edata)->shape; - if ((*comp).method == CompositeMethod::ClipPath) { - if (compShape->rect) rleClipRect(image.rle, &compShape->bbox); - else if (compShape->rle) rleClipPath(image.rle, compShape->rle); - } else if ((*comp).method == CompositeMethod::AlphaMask) { - rleAlphaMask(image.rle, compShape->rle); - } + for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) { + auto compShape = &static_cast(*comp)->shape; + if (compShape->rect) rleClipRect(image.rle, &compShape->bbox); + else if (compShape->rle) rleClipPath(image.rle, compShape->rle); } } } } - if (pixels) image.data = pixels; + image.data = const_cast(pdata->data()); end: imageDelOutline(&image, tid); } @@ -255,6 +248,7 @@ 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; @@ -278,17 +272,72 @@ bool SwRenderer::postRender() tasks.clear(); //Free Composite Caches - for (auto comp = composites.data; comp < (composites.data + composites.count); ++comp) { + for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) { free((*comp)->image.data); delete(*comp); } - composites.reset(); + compositors.reset(); return true; } -bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) +bool SwRenderer::renderImage(RenderData data, TVG_UNUSED void* cmp) +{ + auto task = static_cast(data); + task->done(); + + if (task->opacity == 0) return true; + + return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity); +} + + +bool SwRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp) +{ + auto task = static_cast(data); + task->done(); + + if (task->opacity == 0) return true; + + uint32_t opacity; + void *cmp2 = nullptr; + + //Do Composition + if (task->compStroking) { + 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(CompositeMethod::None, x, y, w, h, opacity); + //No Composition + } else { + opacity = task->opacity; + } + + //Main raster stage + uint8_t r, g, b, a; + + if (auto fill = task->sdata->fill()) { + //FIXME: pass opacity to apply gradient fill? + rasterGradientShape(surface, &task->shape, fill->id()); + } else{ + task->sdata->fillColor(&r, &g, &b, &a); + a = static_cast((opacity * (uint32_t) a) / 255); + if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a); + } + + task->sdata->strokeColor(&r, &g, &b, &a); + 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->compStroking) delCompositor(cmp2); + + return true; +} + +bool SwRenderer::renderRegion(RenderData data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) { static_cast(data)->bounds(x, y, w, h); @@ -296,22 +345,12 @@ bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, } - -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->bbox, task->opacity); -} - - -void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) +void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) { SwComposite* comp = nullptr; //Use cached data - for (auto p = composites.data; p < (composites.data + composites.count); ++p) { + for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) { if ((*p)->valid) { comp = *p; break; @@ -328,17 +367,19 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) delete(comp); return nullptr; } - composites.push(comp); + compositors.push(comp); } comp->valid = false; + comp->method = method; + comp->opacity = opacity; //Boundary Check if (x + w > surface->w) w = (surface->w - x); if (y + h > surface->h) h = (surface->h - y); #ifdef THORVG_LOG_ENABLED - printf("SW_ENGINE: Using intermediate opacity composition [Region: %d %d %d %d]\n", x, y, w, h); + printf("SW_ENGINE: Using intermediate composition [Method: %d][Region: %d %d %d %d]\n", (int)method, x, y, w, h); #endif comp->bbox.min.x = x; @@ -365,75 +406,38 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) comp->surface.w = comp->image.w; comp->surface.h = comp->image.h; + //Switch active compositor + comp->recover = compositor; //Backup current compositor + compositor = comp; + //Switch render target - comp->recover = surface; surface = &comp->surface; return comp; } -bool SwRenderer::endComposite(void* p, uint32_t opacity) +bool SwRenderer::delCompositor(void* ctx) { - if (!p) return false; - auto comp = static_cast(p); - - //Recover render target - surface = comp->recover; - - auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity); + if (!ctx) return false; + auto comp = static_cast(ctx); comp->valid = true; - return ret; -} + //Recover Context + compositor = comp->recover; + surface = compositor ? &compositor->surface : mainSurface; - -bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data) -{ - auto task = static_cast(data); - task->done(); - - if (task->opacity == 0) return true; - - uint32_t opacity; - void *ctx = nullptr; - - //Do Composition - if (task->compStroking) { - uint32_t x, y, w, h; - task->bounds(&x, &y, &w, &h); - ctx = beginComposite(x, y, w, h); - opacity = 255; - //No Composition - } else { - opacity = task->opacity; + //Default is alpha blending + if (comp->method == CompositeMethod::None) { + return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity); } - //Main raster stage - uint8_t r, g, b, a; - - if (auto fill = task->sdata->fill()) { - //FIXME: pass opacity to apply gradient fill? - rasterGradientShape(surface, &task->shape, fill->id()); - } else{ - task->sdata->fillColor(&r, &g, &b, &a); - a = static_cast((opacity * (uint32_t) a) / 255); - if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a); - } - - task->sdata->strokeColor(&r, &g, &b, &a); - 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->compStroking) endComposite(ctx, task->opacity); - return true; } -bool SwRenderer::dispose(void *data) +bool SwRenderer::dispose(RenderData data) { auto task = static_cast(data); if (!task) return true; @@ -447,14 +451,19 @@ bool SwRenderer::dispose(void *data) } -void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) +void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) { - if (compList.count > 0) { + if (flags == RenderUpdateFlag::None) return task; + + //Finish previous task if it has duplicated request. + task->done(); + + if (clips.count > 0) { //Guarantee composition targets get ready. - for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { - static_cast((*comp).edata)->done(); + for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) { + static_cast(*comp)->done(); } - task->compList = compList; + task->clips = clips; } if (transform) { @@ -471,50 +480,34 @@ void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, u tasks.push(task); TaskScheduler::request(task); + + return task; } -void* SwRenderer::prepare(const Picture& pdata, void* data, uint32_t *pixels, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) +RenderData SwRenderer::prepare(const Picture& pdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) { //prepare task auto task = static_cast(data); if (!task) { task = new SwImageTask; if (!task) return nullptr; + task->pdata = &pdata; } - - if (flags == RenderUpdateFlag::None) return task; - - //Finish previous task if it has duplicated request. - task->done(); - - task->pdata = &pdata; - task->pixels = pixels; - - prepareCommon(task, transform, opacity, compList, flags); - - return task; + return prepareCommon(task, transform, opacity, clips, flags); } -void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) +RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags) { //prepare task auto task = static_cast(data); if (!task) { task = new SwShapeTask; if (!task) return nullptr; + task->sdata = &sdata; } - - if (flags == RenderUpdateFlag::None) return task; - - //Finish previous task if it has duplicated request. - task->done(); - task->sdata = &sdata; - - prepareCommon(task, transform, opacity, compList, flags); - - return task; + return prepareCommon(task, transform, opacity, clips, flags); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index e3e600d0..5c252ee7 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -26,8 +26,6 @@ struct SwSurface; struct SwTask; -struct SwShapeTask; -struct SwImage; struct SwComposite; namespace tvg @@ -36,17 +34,17 @@ namespace tvg class SwRenderer : public RenderMethod { public: - void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) override; - void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) override; - void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; - bool endComposite(void* ctx, uint32_t opacity) override; - bool dispose(void *data) override; + 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; + void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override; + bool delCompositor(void* cmp) override; + bool dispose(RenderData 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 renderRegion(RenderData 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; + bool renderShape(RenderData data, void* cmp) override; + bool renderImage(RenderData data, void* cmp) override; bool sync() override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); @@ -55,14 +53,16 @@ public: static bool term(); private: - SwSurface* surface = nullptr; - Array tasks; - Array composites; + SwSurface* surface = nullptr; //active surface + SwComposite* compositor = nullptr; //active compositor + SwSurface* mainSurface = nullptr; //main (default) surface + Array tasks; //async task list + Array compositors; //compositor cache list SwRenderer(){}; ~SwRenderer(); - void prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags); + RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flags); }; } diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index 03527c86..ef63238d 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -76,15 +76,15 @@ struct Canvas::Impl { if (!renderer) return Result::InsufficientCondition; - Array compList; + Array clips; //Update single paint node if (paint) { - paint->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None); + paint->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None); //Update all retained paint nodes } else { for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { - (*paint)->pImpl->update(*renderer, nullptr, 255, compList, RenderUpdateFlag::None); + (*paint)->pImpl->update(*renderer, nullptr, 255, clips, RenderUpdateFlag::None); } } return Result::Success; diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 4d2a7213..91adb68a 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -34,7 +34,7 @@ namespace tvg virtual ~StrategyMethod() {} virtual bool dispose(RenderMethod& renderer) = 0; - virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has. + 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 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; @@ -137,7 +137,7 @@ namespace tvg return smethod->dispose(renderer); } - void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& compList, uint32_t pFlag) + void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag) { if (flag & RenderUpdateFlag::Transform) { if (!rTransform) return nullptr; @@ -149,9 +149,9 @@ namespace tvg void *compdata = nullptr; - if (compTarget && (compMethod != CompositeMethod::None)) { - compdata = compTarget->pImpl->update(renderer, pTransform, opacity, compList, pFlag); - if (compdata) compList.push({compdata, compMethod}); + if (compTarget) { + compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag); + if (compMethod == CompositeMethod::ClipPath) clips.push(compdata); } void *edata = nullptr; @@ -161,20 +161,34 @@ namespace tvg if (rTransform && pTransform) { RenderTransform outTransform(pTransform, rTransform); - edata = smethod->update(renderer, &outTransform, opacity, compList, newFlag); + edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag); } else { auto outTransform = pTransform ? pTransform : rTransform; - edata = smethod->update(renderer, outTransform, opacity, compList, newFlag); + edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); } - if (compdata) compList.pop(); + if (compdata) clips.pop(); return edata; } bool render(RenderMethod& renderer) { - return smethod->render(renderer); + void* cmp = nullptr; + + /* Note: only ClipPath is processed in update() step */ + if (compTarget && compMethod != CompositeMethod::ClipPath) { + uint32_t x, y, w, h; + if (!compTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false; + cmp = renderer.addCompositor(compMethod, x, y, w, h, 255); + compTarget->pImpl->render(renderer); + } + + auto ret = smethod->render(renderer); + + renderer.delCompositor(cmp); + + return ret; } Paint* duplicate() @@ -198,6 +212,7 @@ namespace tvg bool composite(Paint* target, CompositeMethod method) { if (!target && method != CompositeMethod::None) return false; + if (target && method == CompositeMethod::None) return false; compTarget = target; compMethod = method; return true; @@ -228,9 +243,9 @@ namespace tvg return inst->dispose(renderer); } - void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flag) override + void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag flag) override { - return inst->update(renderer, transform, opacity, compList, flag); + return inst->update(renderer, transform, opacity, clips, flag); } bool render(RenderMethod& renderer) override diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index eed0e0e0..f66fb6eb 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -89,3 +89,11 @@ Result Picture::size(float* w, float* h) const noexcept return Result::Success; } + +const uint32_t* Picture::data() const noexcept +{ + //Try it, If not loaded yet. + if (pImpl->loader) return pImpl->loader->pixels(); + + return pImpl->pixels; +} \ No newline at end of file diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index c84b04b5..a9ff4484 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -36,7 +36,7 @@ struct Picture::Impl Paint* paint = nullptr; uint32_t *pixels = nullptr; Picture *picture = nullptr; - void *edata = nullptr; //engine data + void *rdata = nullptr; //engine data float w = 0, h = 0; bool resizing = false; @@ -53,7 +53,7 @@ struct Picture::Impl return true; } else if (pixels) { - return renderer.dispose(edata); + return renderer.dispose(rdata); } return false; } @@ -103,28 +103,28 @@ struct Picture::Impl } } if (!pixels) { - pixels = (uint32_t*)loader->pixels(); + pixels = const_cast(loader->pixels()); if (pixels) return RenderUpdateFlag::Image; } } return RenderUpdateFlag::None; } - void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag pFlag) + void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) { - uint32_t flag = reload(); + auto flag = reload(); - if (pixels) edata = renderer.prepare(*picture, edata, pixels, transform, opacity, compList, static_cast(pFlag | flag)); + if (pixels) rdata = renderer.prepare(*picture, rdata, transform, opacity, clips, static_cast(pFlag | flag)); else if (paint) { if (resizing) resize(); - edata = paint->pImpl->update(renderer, transform, opacity, compList, static_cast(pFlag | flag)); + rdata = paint->pImpl->update(renderer, transform, opacity, clips, static_cast(pFlag | flag)); } - return edata; + return rdata; } bool render(RenderMethod &renderer) { - if (pixels) return renderer.render(*picture, edata); + if (pixels) return renderer.renderImage(rdata, nullptr); else if (paint) return paint->pImpl->render(renderer); return false; } @@ -155,8 +155,8 @@ struct Picture::Impl 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); + if (rdata) return renderer.renderRegion(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 6557ff03..681d4500 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -37,10 +37,7 @@ struct Surface uint32_t cs; }; -struct Composite { - void* edata; - CompositeMethod method; -}; +using RenderData = void*; enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64}; @@ -60,21 +57,20 @@ struct RenderTransform RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; - class RenderMethod { public: virtual ~RenderMethod() {} - virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) = 0; - virtual void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flags) = 0; - virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0; - virtual bool endComposite(void* ctx, uint32_t opacity) = 0; - virtual bool dispose(void *data) = 0; + 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 void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) = 0; + virtual bool delCompositor(void* cmp) = 0; + virtual bool dispose(RenderData data) = 0; virtual bool preRender() = 0; - virtual bool render(const Shape& shape, void *data) = 0; - virtual bool render(const Picture& picture, void *data) = 0; + virtual bool renderShape(RenderData data, void* cmp) = 0; + virtual bool renderImage(RenderData data, void* cmp) = 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 renderRegion(RenderData 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 71b17f29..fc293641 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -44,41 +44,40 @@ struct Scene::Impl return true; } - void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag flag) + 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 < 255 && opacity > 0) opacity = 255; + if (opacity > 0) opacity = 255; + + for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { + (*paint)->pImpl->update(renderer, transform, opacity, clips, static_cast(flag)); + } /* FXIME: it requires to return list of children engine data This is necessary for scene composition */ - void* edata = nullptr; - - for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { - edata = (*paint)->pImpl->update(renderer, transform, opacity, compList, static_cast(flag)); - } - - return edata; + return nullptr; } bool render(RenderMethod& renderer) { - void* ctx = nullptr; + void* cmp = nullptr; - //Half translucent. This requires intermediate composition. - if (opacity < 255 && opacity > 0) { + //Half translucent. This condition requires intermediate composition. + if (opacity < 255 && opacity > 0 && (paints.count > 1)) { uint32_t x, y, w, h; if (!bounds(renderer, &x, &y, &w, &h)) return false; - ctx = renderer.beginComposite(x, y, w, h); + //CompositeMethod::None is used for a default alpha blending + cmp = renderer.addCompositor(CompositeMethod::None, x, y, w, h, opacity); } for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { if (!(*paint)->pImpl->render(renderer)) return false; } - if (ctx) return renderer.endComposite(ctx, opacity); + if (cmp) renderer.delCompositor(cmp); return true; } diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 82b56ed2..2e697cac 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -199,7 +199,7 @@ struct Shape::Impl ShapeStroke *stroke = nullptr; uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a FillRule rule = FillRule::Winding; - void *edata = nullptr; //engine data + RenderData rdata = nullptr; //engine data Shape *shape = nullptr; uint32_t flag = RenderUpdateFlag::None; @@ -215,24 +215,24 @@ struct Shape::Impl bool dispose(RenderMethod& renderer) { - return renderer.dispose(edata); + return renderer.dispose(rdata); } bool render(RenderMethod& renderer) { - return renderer.render(*shape, edata); + return renderer.renderShape(rdata, nullptr); } - void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& compList, RenderUpdateFlag pFlag) + void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array& clips, RenderUpdateFlag pFlag) { - this->edata = renderer.prepare(*shape, this->edata, transform, opacity, compList, static_cast(pFlag | flag)); + this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast(pFlag | flag)); flag = RenderUpdateFlag::None; - return this->edata; + return this->rdata; } bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) { - return renderer.renderRegion(edata, x, y, w, h); + return renderer.renderRegion(rdata, x, y, w, h); } bool bounds(float* x, float* y, float* w, float* h)