diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index a600cb9d..256c4bbe 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -203,11 +203,11 @@ struct SwFill struct SwShape { - SwOutline* outline; - SwStroke* stroke; - SwFill* fill; - SwRleData* rle; - SwRleData* strokeRle; + SwOutline* outline = nullptr; + SwStroke* stroke = nullptr; + SwFill* fill = nullptr; + SwRleData* rle = nullptr; + SwRleData* strokeRle = nullptr; SwBBox bbox; bool rect; //Fast Track: Othogonal rectangle? diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 28ddf639..0d77d386 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -27,6 +27,63 @@ /************************************************************************/ static RenderInitializer renderInit; +struct SwTask : Task +{ + SwShape shape; + const Shape* sdata = nullptr; + Matrix* transform = nullptr; + SwSurface* surface = nullptr; + RenderUpdateFlag flags = RenderUpdateFlag::None; + + void run() override + { + //Valid Stroking? + uint8_t strokeAlpha = 0; + auto strokeWidth = sdata->strokeWidth(); + if (strokeWidth > FLT_EPSILON) { + sdata->strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); + } + + SwSize clip = {static_cast(surface->w), static_cast(surface->h)}; + + //Shape + if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { + shapeReset(&shape); + uint8_t alpha = 0; + sdata->fill(nullptr, nullptr, nullptr, &alpha); + bool renderShape = (alpha > 0 || sdata->fill()); + if (renderShape || strokeAlpha) { + if (!shapePrepare(&shape, sdata, clip, transform)) return; + if (renderShape) { + auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true; + if (!shapeGenRle(&shape, sdata, clip, antiAlias)) return; + } + } + } + //Fill + if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { + auto fill = sdata->fill(); + if (fill) { + auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; + if (ctable) shapeResetFill(&shape); + if (!shapeGenFillColors(&shape, fill, transform, surface, ctable)) return; + } else { + shapeDelFill(&shape); + } + } + //Stroke + if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + if (strokeAlpha > 0) { + shapeResetStroke(&shape, sdata, transform); + if (!shapeGenStrokeRle(&shape, sdata, transform, clip)) return; + } else { + shapeDelStroke(&shape); + } + } + shapeDelOutline(&shape); + } +}; + /************************************************************************/ /* External Class Implementation */ @@ -34,10 +91,30 @@ static RenderInitializer renderInit; SwRenderer::~SwRenderer() { + flush(); if (surface) delete(surface); } +bool SwRenderer::clear() +{ + if (this->valid() || tasks.size() > 0) return false; + + return flush(); +} + + +bool SwRenderer::flush() +{ + this->get(); //complete rendering + + for (auto task : tasks) task->get(); + tasks.clear(); + + 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; @@ -59,98 +136,76 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t bool SwRenderer::preRender() { - return rasterClear(surface); -} + //before we start rendering, we should finish all preparing tasks + for (auto task : tasks) task->get(); - -bool SwRenderer::render(const Shape& sdata, TVG_UNUSED void *data) -{ - auto shape = static_cast(data); - if (!shape) return false; - - uint8_t r, g, b, a; - - if (auto fill = sdata.fill()) { - rasterGradientShape(surface, shape, fill->id()); - } else{ - sdata.fill(&r, &g, &b, &a); - if (a > 0) rasterSolidShape(surface, shape, r, g, b, a); - } - sdata.strokeColor(&r, &g, &b, &a); - if (a > 0) rasterStroke(surface, shape, r, g, b, a); + TaskScheduler::request(this); return true; } +void SwRenderer::run() +{ + rasterClear(surface); + + for (auto task : tasks) { + uint8_t r, g, b, a; + if (auto fill = task->sdata->fill()) { + rasterGradientShape(surface, &task->shape, fill->id()); + } else{ + task->sdata->fill(&r, &g, &b, &a); + if (a > 0) rasterSolidShape(surface, &task->shape, r, g, b, a); + } + task->sdata->strokeColor(&r, &g, &b, &a); + if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a); + } + tasks.clear(); +}; + + bool SwRenderer::dispose(TVG_UNUSED const Shape& sdata, void *data) { - auto shape = static_cast(data); - if (!shape) return false; - shapeFree(shape); + auto task = static_cast(data); + if (!task) return true; + + task->get(); + shapeFree(&task->shape); + if (task->transform) free(task->transform); + delete(task); + return true; } void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, RenderUpdateFlag flags) { - //prepare shape data - auto shape = static_cast(data); - if (!shape) { - shape = static_cast(calloc(1, sizeof(SwShape))); - if (!shape) return nullptr; + //prepare task + auto task = static_cast(data); + if (!task) { + task = new SwTask; + if (!task) return nullptr; } - if (flags == RenderUpdateFlag::None) return shape; + if (flags == RenderUpdateFlag::None || task->valid()) return task; - SwSize clip = {static_cast(surface->w), static_cast(surface->h)}; + task->sdata = &sdata; - //Valid Stroking? - uint8_t strokeAlpha = 0; - auto strokeWidth = sdata.strokeWidth(); - if (strokeWidth > FLT_EPSILON) { - sdata.strokeColor(nullptr, nullptr, nullptr, &strokeAlpha); + if (transform) { + if (!task->transform) task->transform = static_cast(malloc(sizeof(Matrix))); + *task->transform = transform->m; + } else { + if (task->transform) free(task->transform); + task->transform = nullptr; } - const Matrix* matrix = (transform ? &transform->m : nullptr); + task->surface = surface; + task->flags = flags; - //Shape - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform)) { - shapeReset(shape); - uint8_t alpha = 0; - sdata.fill(nullptr, nullptr, nullptr, &alpha); - bool renderShape = (alpha > 0 || sdata.fill()); - if (renderShape || strokeAlpha) { - if (!shapePrepare(shape, &sdata, clip, matrix)) return shape; - if (renderShape) { - auto antiAlias = (strokeAlpha > 0 && strokeWidth >= 2) ? false : true; - if (!shapeGenRle(shape, &sdata, clip, antiAlias)) return shape; - } - } - } - //Fill - if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) { - auto fill = sdata.fill(); - if (fill) { - auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; - if (ctable) shapeResetFill(shape); - if (!shapeGenFillColors(shape, fill, matrix, surface, ctable)) return shape; - } else { - shapeDelFill(shape); - } - } - //Stroke - if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { - if (strokeAlpha > 0) { - shapeResetStroke(shape, &sdata, matrix); - if (!shapeGenStrokeRle(shape, &sdata, matrix, clip)) return shape; - } else { - shapeDelStroke(shape); - } - } - shapeDelOutline(shape); + tasks.push_back(task); + TaskScheduler::request(task); - return shape; + return task; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 2185f344..67d2f159 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -23,20 +23,23 @@ #define _TVG_SW_RENDERER_H_ struct SwSurface; +struct SwTask; namespace tvg { -class SwRenderer : public RenderMethod +class SwRenderer : public RenderMethod, public Task { public: void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override; bool dispose(const Shape& shape, void *data) override; bool preRender() override; - bool render(const Shape& shape, void *data) override; bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); + bool clear() override; + bool flush() override; uint32_t ref() override; uint32_t unref() override; + void run() override; static SwRenderer* inst(); static int init(); @@ -44,6 +47,7 @@ public: private: SwSurface* surface = nullptr; + vector tasks; SwRenderer(){}; ~SwRenderer(); diff --git a/src/lib/tvgTaskScheduler.h b/src/lib/tvgTaskScheduler.h index 1b1cc128..31d1ee1a 100644 --- a/src/lib/tvgTaskScheduler.h +++ b/src/lib/tvgTaskScheduler.h @@ -43,6 +43,11 @@ public: } } + bool valid() + { + return receiver.valid(); + } + protected: virtual void run() = 0;