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.
This commit is contained in:
Hermet Park 2020-12-25 19:47:01 +09:00 committed by GitHub
parent 9cb256f473
commit 4767f83b99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 251 additions and 237 deletions

View file

@ -279,6 +279,7 @@ public:
Result size(float w, float h) noexcept; Result size(float w, float h) noexcept;
Result size(float* w, float* h) const noexcept; Result size(float* w, float* h) const noexcept;
const uint32_t* data() const noexcept;
static std::unique_ptr<Picture> gen() noexcept; static std::unique_ptr<Picture> gen() noexcept;

View file

@ -12,11 +12,12 @@ void tvgDrawCmds(tvg::Canvas* canvas)
if (!canvas) return; if (!canvas) return;
//Mask Target 2 //Mask Target 2
#if 0
auto scene = tvg::Scene::gen(); auto scene = tvg::Scene::gen();
scene->opacity(127); scene->opacity(127);
scene->scale(1.2); scene->scale(1.2);
scene->reserve(2); scene->reserve(2);
#endif
//Star //Star
auto shape = tvg::Shape::gen(); auto shape = tvg::Shape::gen();
@ -33,17 +34,20 @@ void tvgDrawCmds(tvg::Canvas* canvas)
shape->lineTo(146, 143); shape->lineTo(146, 143);
shape->close(); shape->close();
shape->fill(0, 0, 255, 255); shape->fill(0, 0, 255, 255);
shape->stroke(10); // shape->stroke(10);
shape->stroke(255, 255, 255, 255); // shape->stroke(255, 255, 255, 255);
shape->opacity(127); //shape->opacity(127);
scene->push(move(shape)); // scene->push(move(shape));
//Alpha Mask //Alpha Mask
auto mask2 = tvg::Shape::gen(); auto mask = tvg::Shape::gen();
mask2->appendCircle(200, 200, 125, 125); mask->appendCircle(200, 200, 125, 125);
mask2->fill(255, 255, 255, 100); 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); scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
if (canvas->push(move(scene)) != tvg::Result::Success) return; 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); picture->composite(move(mask), tvg::CompositeMethod::AlphaMask);
if (canvas->push(move(picture)) != tvg::Result::Success) return; if (canvas->push(move(picture)) != tvg::Result::Success) return;
#endif
} }

View file

@ -54,6 +54,7 @@ class GlGeometry;
struct GlShape struct GlShape
{ {
const Shape* shape = nullptr;
float viewWd; float viewWd;
float viewHt; float viewHt;
RenderUpdateFlag updateFlag; RenderUpdateFlag updateFlag;

View file

@ -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; 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 //TODO: Prepare frameBuffer & Setup render target for composition
return nullptr; 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; 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 false;
return true;
} }
bool GlRenderer::render(const Shape& shape, void* data) bool GlRenderer::renderShape(RenderData data, TVG_UNUSED void* cmp)
{ {
GlShape* sdata = static_cast<GlShape*>(data); auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false; if (!sdata) return false;
uint8_t r, g, b, a; uint8_t r, g, b, a;
@ -139,17 +137,17 @@ bool GlRenderer::render(const Shape& shape, void* data)
{ {
if (flags & RenderUpdateFlag::Gradient) if (flags & RenderUpdateFlag::Gradient)
{ {
const Fill* gradient = shape.fill(); const Fill* gradient = sdata->shape->fill();
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient); drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
} }
else if (flags & RenderUpdateFlag::Color) 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); drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
} }
if (flags & RenderUpdateFlag::Stroke) 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); 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<GlShape*>(data); auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false; if (!sdata) return false;
delete sdata; 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<Composite>& 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<RenderData>& clips, TVG_UNUSED RenderUpdateFlag flags)
{ {
//TODO: //TODO:
return nullptr; return nullptr;
} }
void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) RenderData GlRenderer::prepare(const Shape& shape, RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{ {
//prepare shape data //prepare shape data
GlShape* sdata = static_cast<GlShape*>(data); GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) { if (!sdata) {
sdata = new GlShape; sdata = new GlShape;
if (!sdata) return nullptr; if (!sdata) return nullptr;
sdata->shape = &shape;
} }
sdata->viewWd = static_cast<float>(surface.w); sdata->viewWd = static_cast<float>(surface.w);

View file

@ -30,16 +30,16 @@ class GlRenderer : public RenderMethod
public: public:
Surface surface = {nullptr, 0, 0, 0}; Surface surface = {nullptr, 0, 0, 0};
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override; RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override; RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
bool dispose(void *data) override; bool dispose(RenderData data) override;
void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
bool endComposite(void* ctx, uint32_t opacity) override; bool delCompositor(void* cmp) override;
bool preRender() override; bool preRender() override;
bool render(const Shape& shape, void *data) override; bool renderShape(RenderData data, void* cmp) override;
bool render(const Picture& picture, void *data) override; bool renderImage(RenderData data, void* cmp) override;
bool postRender() 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 target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
bool sync() override; bool sync() override;
bool clear() override; bool clear() override;

View file

@ -33,9 +33,11 @@ static uint32_t rendererCnt = 0;
struct SwComposite struct SwComposite
{ {
SwSurface surface; SwSurface surface;
SwSurface* recover; SwComposite* recover;
SwImage image; SwImage image;
SwBBox bbox; SwBBox bbox;
CompositeMethod method;
uint32_t opacity;
bool valid; bool valid;
}; };
@ -45,7 +47,7 @@ struct SwTask : Task
Matrix* transform = nullptr; Matrix* transform = nullptr;
SwSurface* surface = nullptr; SwSurface* surface = nullptr;
RenderUpdateFlag flags = RenderUpdateFlag::None; RenderUpdateFlag flags = RenderUpdateFlag::None;
Array<Composite> compList; Array<RenderData> clips;
uint32_t opacity; uint32_t opacity;
SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region 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. shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition. */ Thus it turns off antialising in that condition. */
auto antiAlias = (strokeAlpha == 255 && strokeWidth > 2) ? false : true; 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; ++addStroking;
} }
} }
@ -131,22 +133,18 @@ struct SwShapeTask : SwTask
} }
} }
//Composition //Clip Path
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape; auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
if ((*comp).method == CompositeMethod::ClipPath) { //Clip shape rle
//Clip shape rle if (shape.rle) {
if (shape.rle) { if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox);
if (compShape->rect) rleClipRect(shape.rle, &compShape->bbox); else if (compShape->rle) rleClipPath(shape.rle, compShape->rle);
else if (compShape->rle) rleClipPath(shape.rle, compShape->rle); }
} //Clip stroke rle
//Clip stroke rle if (shape.strokeRle) {
if (shape.strokeRle) { if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox);
if (compShape->rect) rleClipRect(shape.strokeRle, &compShape->bbox); else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
else if (compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
}
} else if ((*comp).method == CompositeMethod::AlphaMask) {
rleAlphaMask(shape.rle, compShape->rle);
} }
} }
end: end:
@ -167,7 +165,6 @@ struct SwImageTask : SwTask
{ {
SwImage image; SwImage image;
const Picture* pdata = nullptr; const Picture* pdata = nullptr;
uint32_t* pixels = nullptr;
void run(unsigned tid) override void run(unsigned tid) override
{ {
@ -181,23 +178,19 @@ struct SwImageTask : SwTask
imageReset(&image); imageReset(&image);
if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end; if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
//Composition? //Clip Path?
if (compList.count > 0) { if (clips.count > 0) {
if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end; if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
if (image.rle) { if (image.rle) {
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
auto compShape = &static_cast<SwShapeTask*>((*comp).edata)->shape; auto compShape = &static_cast<SwShapeTask*>(*comp)->shape;
if ((*comp).method == CompositeMethod::ClipPath) { if (compShape->rect) rleClipRect(image.rle, &compShape->bbox);
if (compShape->rect) rleClipRect(image.rle, &compShape->bbox); else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
else if (compShape->rle) rleClipPath(image.rle, compShape->rle);
} else if ((*comp).method == CompositeMethod::AlphaMask) {
rleAlphaMask(image.rle, compShape->rle);
}
} }
} }
} }
} }
if (pixels) image.data = pixels; image.data = const_cast<uint32_t*>(pdata->data());
end: end:
imageDelOutline(&image, tid); imageDelOutline(&image, tid);
} }
@ -255,6 +248,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
if (!surface) { if (!surface) {
surface = new SwSurface; surface = new SwSurface;
if (!surface) return false; if (!surface) return false;
mainSurface = surface;
} }
surface->buffer = buffer; surface->buffer = buffer;
@ -278,17 +272,72 @@ bool SwRenderer::postRender()
tasks.clear(); tasks.clear();
//Free Composite Caches //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); free((*comp)->image.data);
delete(*comp); delete(*comp);
} }
composites.reset(); compositors.reset();
return true; 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<SwImageTask*>(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<SwShapeTask*>(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<uint8_t>((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<uint8_t>((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<SwTask*>(data)->bounds(x, y, w, h); static_cast<SwTask*>(data)->bounds(x, y, w, h);
@ -296,22 +345,12 @@ bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w,
} }
void* SwRenderer::addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity)
bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data)
{
auto task = static_cast<SwImageTask*>(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)
{ {
SwComposite* comp = nullptr; SwComposite* comp = nullptr;
//Use cached data //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) { if ((*p)->valid) {
comp = *p; comp = *p;
break; break;
@ -328,17 +367,19 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
delete(comp); delete(comp);
return nullptr; return nullptr;
} }
composites.push(comp); compositors.push(comp);
} }
comp->valid = false; comp->valid = false;
comp->method = method;
comp->opacity = opacity;
//Boundary Check //Boundary Check
if (x + w > surface->w) w = (surface->w - x); if (x + w > surface->w) w = (surface->w - x);
if (y + h > surface->h) h = (surface->h - y); if (y + h > surface->h) h = (surface->h - y);
#ifdef THORVG_LOG_ENABLED #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 #endif
comp->bbox.min.x = x; 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.w = comp->image.w;
comp->surface.h = comp->image.h; comp->surface.h = comp->image.h;
//Switch active compositor
comp->recover = compositor; //Backup current compositor
compositor = comp;
//Switch render target //Switch render target
comp->recover = surface;
surface = &comp->surface; surface = &comp->surface;
return comp; return comp;
} }
bool SwRenderer::endComposite(void* p, uint32_t opacity) bool SwRenderer::delCompositor(void* ctx)
{ {
if (!p) return false; if (!ctx) return false;
auto comp = static_cast<SwComposite*>(p);
//Recover render target
surface = comp->recover;
auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity);
auto comp = static_cast<SwComposite*>(ctx);
comp->valid = true; comp->valid = true;
return ret; //Recover Context
} compositor = comp->recover;
surface = compositor ? &compositor->surface : mainSurface;
//Default is alpha blending
bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data) if (comp->method == CompositeMethod::None) {
{ return rasterImage(surface, &comp->image, nullptr, comp->bbox, comp->opacity);
auto task = static_cast<SwShapeTask*>(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;
} }
//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<uint8_t>((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<uint8_t>((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; return true;
} }
bool SwRenderer::dispose(void *data) bool SwRenderer::dispose(RenderData data)
{ {
auto task = static_cast<SwTask*>(data); auto task = static_cast<SwTask*>(data);
if (!task) return true; 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<Composite>& compList, RenderUpdateFlag flags) void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& 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. //Guarantee composition targets get ready.
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { for (auto comp = clips.data; comp < (clips.data + clips.count); ++comp) {
static_cast<SwShapeTask*>((*comp).edata)->done(); static_cast<SwShapeTask*>(*comp)->done();
} }
task->compList = compList; task->clips = clips;
} }
if (transform) { if (transform) {
@ -471,50 +480,34 @@ void SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, u
tasks.push(task); tasks.push(task);
TaskScheduler::request(task); TaskScheduler::request(task);
return task;
} }
void* SwRenderer::prepare(const Picture& pdata, void* data, uint32_t *pixels, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) RenderData SwRenderer::prepare(const Picture& pdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{ {
//prepare task //prepare task
auto task = static_cast<SwImageTask*>(data); auto task = static_cast<SwImageTask*>(data);
if (!task) { if (!task) {
task = new SwImageTask; task = new SwImageTask;
if (!task) return nullptr; if (!task) return nullptr;
task->pdata = &pdata;
} }
return prepareCommon(task, transform, opacity, clips, flags);
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;
} }
void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{ {
//prepare task //prepare task
auto task = static_cast<SwShapeTask*>(data); auto task = static_cast<SwShapeTask*>(data);
if (!task) { if (!task) {
task = new SwShapeTask; task = new SwShapeTask;
if (!task) return nullptr; if (!task) return nullptr;
task->sdata = &sdata;
} }
return prepareCommon(task, transform, opacity, clips, flags);
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;
} }

View file

@ -26,8 +26,6 @@
struct SwSurface; struct SwSurface;
struct SwTask; struct SwTask;
struct SwShapeTask;
struct SwImage;
struct SwComposite; struct SwComposite;
namespace tvg namespace tvg
@ -36,17 +34,17 @@ namespace tvg
class SwRenderer : public RenderMethod class SwRenderer : public RenderMethod
{ {
public: public:
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override; RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) override; RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) override; void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) override;
bool endComposite(void* ctx, uint32_t opacity) override; bool delCompositor(void* cmp) override;
bool dispose(void *data) override; bool dispose(RenderData data) override;
bool preRender() override; bool preRender() override;
bool postRender() 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 clear() override;
bool render(const Shape& shape, void *data) override; bool renderShape(RenderData data, void* cmp) override;
bool render(const Picture& picture, void *data) override; bool renderImage(RenderData data, void* cmp) override;
bool sync() override; bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); 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(); static bool term();
private: private:
SwSurface* surface = nullptr; SwSurface* surface = nullptr; //active surface
Array<SwTask*> tasks; SwComposite* compositor = nullptr; //active compositor
Array<SwComposite*> composites; SwSurface* mainSurface = nullptr; //main (default) surface
Array<SwTask*> tasks; //async task list
Array<SwComposite*> compositors; //compositor cache list
SwRenderer(){}; SwRenderer(){};
~SwRenderer(); ~SwRenderer();
void prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags); RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags);
}; };
} }

View file

@ -76,15 +76,15 @@ struct Canvas::Impl
{ {
if (!renderer) return Result::InsufficientCondition; if (!renderer) return Result::InsufficientCondition;
Array<Composite> compList; Array<RenderData> clips;
//Update single paint node //Update single paint node
if (paint) { 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 //Update all retained paint nodes
} else { } else {
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { 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; return Result::Success;

View file

@ -34,7 +34,7 @@ namespace tvg
virtual ~StrategyMethod() {} virtual ~StrategyMethod() {}
virtual bool dispose(RenderMethod& renderer) = 0; virtual bool dispose(RenderMethod& renderer) = 0;
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has. virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
virtual bool render(RenderMethod& renderer) = 0; virtual bool render(RenderMethod& renderer) = 0;
virtual bool bounds(float* x, float* y, float* w, float* h) const = 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 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); return smethod->dispose(renderer);
} }
void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<Composite>& compList, uint32_t pFlag) void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, uint32_t pFlag)
{ {
if (flag & RenderUpdateFlag::Transform) { if (flag & RenderUpdateFlag::Transform) {
if (!rTransform) return nullptr; if (!rTransform) return nullptr;
@ -149,9 +149,9 @@ namespace tvg
void *compdata = nullptr; void *compdata = nullptr;
if (compTarget && (compMethod != CompositeMethod::None)) { if (compTarget) {
compdata = compTarget->pImpl->update(renderer, pTransform, opacity, compList, pFlag); compdata = compTarget->pImpl->update(renderer, pTransform, opacity, clips, pFlag);
if (compdata) compList.push({compdata, compMethod}); if (compMethod == CompositeMethod::ClipPath) clips.push(compdata);
} }
void *edata = nullptr; void *edata = nullptr;
@ -161,20 +161,34 @@ namespace tvg
if (rTransform && pTransform) { if (rTransform && pTransform) {
RenderTransform outTransform(pTransform, rTransform); RenderTransform outTransform(pTransform, rTransform);
edata = smethod->update(renderer, &outTransform, opacity, compList, newFlag); edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag);
} else { } else {
auto outTransform = pTransform ? pTransform : rTransform; 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; return edata;
} }
bool render(RenderMethod& renderer) 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() Paint* duplicate()
@ -198,6 +212,7 @@ namespace tvg
bool composite(Paint* target, CompositeMethod method) bool composite(Paint* target, CompositeMethod method)
{ {
if (!target && method != CompositeMethod::None) return false; if (!target && method != CompositeMethod::None) return false;
if (target && method == CompositeMethod::None) return false;
compTarget = target; compTarget = target;
compMethod = method; compMethod = method;
return true; return true;
@ -228,9 +243,9 @@ namespace tvg
return inst->dispose(renderer); return inst->dispose(renderer);
} }
void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag) override void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& 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 bool render(RenderMethod& renderer) override

View file

@ -89,3 +89,11 @@ Result Picture::size(float* w, float* h) const noexcept
return Result::Success; 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;
}

View file

@ -36,7 +36,7 @@ struct Picture::Impl
Paint* paint = nullptr; Paint* paint = nullptr;
uint32_t *pixels = nullptr; uint32_t *pixels = nullptr;
Picture *picture = nullptr; Picture *picture = nullptr;
void *edata = nullptr; //engine data void *rdata = nullptr; //engine data
float w = 0, h = 0; float w = 0, h = 0;
bool resizing = false; bool resizing = false;
@ -53,7 +53,7 @@ struct Picture::Impl
return true; return true;
} }
else if (pixels) { else if (pixels) {
return renderer.dispose(edata); return renderer.dispose(rdata);
} }
return false; return false;
} }
@ -103,28 +103,28 @@ struct Picture::Impl
} }
} }
if (!pixels) { if (!pixels) {
pixels = (uint32_t*)loader->pixels(); pixels = const_cast<uint32_t*>(loader->pixels());
if (pixels) return RenderUpdateFlag::Image; if (pixels) return RenderUpdateFlag::Image;
} }
} }
return RenderUpdateFlag::None; return RenderUpdateFlag::None;
} }
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{ {
uint32_t flag = reload(); auto flag = reload();
if (pixels) edata = renderer.prepare(*picture, edata, pixels, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag)); if (pixels) rdata = renderer.prepare(*picture, rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
else if (paint) { else if (paint) {
if (resizing) resize(); if (resizing) resize();
edata = paint->pImpl->update(renderer, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag)); rdata = paint->pImpl->update(renderer, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
} }
return edata; return rdata;
} }
bool render(RenderMethod &renderer) 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); else if (paint) return paint->pImpl->render(renderer);
return false; 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) 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 (rdata) return renderer.renderRegion(rdata, x, y, w, h);
if (paint) paint->pImpl->bounds(renderer, x, y, w, h); if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
return false; return false;
} }

View file

@ -37,10 +37,7 @@ struct Surface
uint32_t cs; uint32_t cs;
}; };
struct Composite { using RenderData = void*;
void* edata;
CompositeMethod method;
};
enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, All = 64}; 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); RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs);
}; };
class RenderMethod class RenderMethod
{ {
public: public:
virtual ~RenderMethod() {} virtual ~RenderMethod() {}
virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0; virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual void* prepare(const Picture& picture, void* data, uint32_t *buffer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flags) = 0; virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual void* beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0; virtual void* addCompositor(CompositeMethod method, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t opacity) = 0;
virtual bool endComposite(void* ctx, uint32_t opacity) = 0; virtual bool delCompositor(void* cmp) = 0;
virtual bool dispose(void *data) = 0; virtual bool dispose(RenderData data) = 0;
virtual bool preRender() = 0; virtual bool preRender() = 0;
virtual bool render(const Shape& shape, void *data) = 0; virtual bool renderShape(RenderData data, void* cmp) = 0;
virtual bool render(const Picture& picture, void *data) = 0; virtual bool renderImage(RenderData data, void* cmp) = 0;
virtual bool postRender() = 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 clear() = 0;
virtual bool sync() = 0; virtual bool sync() = 0;
}; };

View file

@ -44,41 +44,40 @@ struct Scene::Impl
return true; return true;
} }
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag flag) void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag)
{ {
this->opacity = opacity; this->opacity = opacity;
/* Overriding opacity value. If this scene is half-translucent, /* Overriding opacity value. If this scene is half-translucent,
It must do intermeidate composition with that opacity value. */ 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<uint32_t>(flag));
}
/* FXIME: it requires to return list of children engine data /* FXIME: it requires to return list of children engine data
This is necessary for scene composition */ This is necessary for scene composition */
void* edata = nullptr; return nullptr;
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
edata = (*paint)->pImpl->update(renderer, transform, opacity, compList, static_cast<uint32_t>(flag));
}
return edata;
} }
bool render(RenderMethod& renderer) bool render(RenderMethod& renderer)
{ {
void* ctx = nullptr; void* cmp = nullptr;
//Half translucent. This requires intermediate composition. //Half translucent. This condition requires intermediate composition.
if (opacity < 255 && opacity > 0) { if (opacity < 255 && opacity > 0 && (paints.count > 1)) {
uint32_t x, y, w, h; uint32_t x, y, w, h;
if (!bounds(renderer, &x, &y, &w, &h)) return false; 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) { for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
if (!(*paint)->pImpl->render(renderer)) return false; if (!(*paint)->pImpl->render(renderer)) return false;
} }
if (ctx) return renderer.endComposite(ctx, opacity); if (cmp) renderer.delCompositor(cmp);
return true; return true;
} }

View file

@ -199,7 +199,7 @@ struct Shape::Impl
ShapeStroke *stroke = nullptr; ShapeStroke *stroke = nullptr;
uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a uint8_t color[4] = {0, 0, 0, 0}; //r, g, b, a
FillRule rule = FillRule::Winding; FillRule rule = FillRule::Winding;
void *edata = nullptr; //engine data RenderData rdata = nullptr; //engine data
Shape *shape = nullptr; Shape *shape = nullptr;
uint32_t flag = RenderUpdateFlag::None; uint32_t flag = RenderUpdateFlag::None;
@ -215,24 +215,24 @@ struct Shape::Impl
bool dispose(RenderMethod& renderer) bool dispose(RenderMethod& renderer)
{ {
return renderer.dispose(edata); return renderer.dispose(rdata);
} }
bool render(RenderMethod& renderer) 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<Composite>& compList, RenderUpdateFlag pFlag) void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{ {
this->edata = renderer.prepare(*shape, this->edata, transform, opacity, compList, static_cast<RenderUpdateFlag>(pFlag | flag)); this->rdata = renderer.prepare(*shape, this->rdata, transform, opacity, clips, static_cast<RenderUpdateFlag>(pFlag | flag));
flag = RenderUpdateFlag::None; 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) 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) bool bounds(float* x, float* y, float* w, float* h)