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.
This commit is contained in:
Hermet Park 2021-01-04 00:46:59 +09:00 committed by GitHub
parent 333ff3a12b
commit 736d6ee4ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 292 additions and 159 deletions

View file

@ -100,10 +100,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
////////////////////////////////////////////// //////////////////////////////////////////////
auto picture = tvg::Picture::gen(); auto picture = tvg::Picture::gen();
char buf[PATH_MAX]; if (picture->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return;
sprintf(buf,"%s/cartman.svg", EXAMPLE_DIR);
if (picture->load(buf) != tvg::Result::Success) return;
picture->scale(3); picture->scale(3);
picture->translate(200, 400); picture->translate(200, 400);

View file

@ -11,16 +11,35 @@ void tvgDrawCmds(tvg::Canvas* canvas)
{ {
if (!canvas) return; if (!canvas) return;
//Mask Target 2 //Solid Rectangle
#if 0
auto scene = tvg::Scene::gen();
scene->opacity(127);
scene->scale(1.2);
scene->reserve(2);
#endif
//Star
auto shape = tvg::Shape::gen(); 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 //Appends Paths
shape->moveTo(199, 34); shape->moveTo(199, 34);
shape->lineTo(253, 143); shape->lineTo(253, 143);
@ -33,20 +52,12 @@ void tvgDrawCmds(tvg::Canvas* canvas)
shape->lineTo(26, 161); shape->lineTo(26, 161);
shape->lineTo(146, 143); shape->lineTo(146, 143);
shape->close(); shape->close();
shape->fill(0, 0, 255, 255); #endif
// shape->stroke(10);
// shape->stroke(255, 255, 255, 255);
//shape->opacity(127); //shape->opacity(127);
// scene->push(move(shape)); // 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 #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;

View file

@ -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; 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 //TODO: Prepare frameBuffer & Setup render target for composition
return nullptr; 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 //TODO: delete the given compositor and restore the context
return false; 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; return false;
} }
bool GlRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp) bool GlRenderer::renderShape(RenderData data)
{ {
auto sdata = static_cast<GlShape*>(data); auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false; if (!sdata) return false;

View file

@ -32,18 +32,21 @@ public:
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override; RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override; RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& 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 preRender() override;
bool renderShape(RenderData data, Compositor* cmp) override; bool renderShape(RenderData data) override;
bool renderImage(RenderData data, Compositor* cmp) override; bool renderImage(RenderData data) override;
bool postRender() 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 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;
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 GlRenderer* gen();
static int init(TVG_UNUSED uint32_t threads); static int init(TVG_UNUSED uint32_t threads);
static int term(); static int term();

View file

@ -226,9 +226,21 @@ struct SwBlender
uint32_t (*alpha)(uint32_t rgba); uint32_t (*alpha)(uint32_t rgba);
}; };
struct SwCompositor;
struct SwSurface : Surface 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) static inline SwCoord TO_SWCOORD(float val)

View file

@ -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 buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
auto h = static_cast<uint32_t>(region.max.y - region.min.y); auto h = static_cast<uint32_t>(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<uint32_t>(region.max.y - region.min.y);
auto w = static_cast<uint32_t>(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<uint32_t*>(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) static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color)
{ {
auto buffer = surface->buffer + (region.min.y * surface->stride); 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; auto span = rle->spans;
uint32_t src; 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); if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color; else src = color;
auto ialpha = 255 - surface->blender.alpha(src); auto ialpha = 255 - surface->blender.alpha(src);
for (uint32_t i = 0; i < span->len; ++i) { for (uint32_t x = 0; x < span->len; ++x) {
dst[i] = src + ALPHA_BLEND(dst[i], ialpha); dst[x] = src + ALPHA_BLEND(dst[x], ialpha);
} }
++span; ++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<uint32_t*>(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) 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; 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); b = ALPHA_MULTIPLY(b, a);
auto color = surface->blender.join(r, g, b, a); auto color = surface->blender.join(r, g, b, a);
auto translucent = _translucent(surface, a);
//Fast Track //Fast Track
if (shape->rect) { if (shape->rect) {
auto region = _clipRegion(surface, shape->bbox); auto region = _clipRegion(surface, shape->bbox);
if (a == 255) return _rasterSolidRect(surface, region, color); if (translucent) return _rasterTranslucentRect(surface, region, color);
return _rasterTranslucentRect(surface, region, color); return _rasterSolidRect(surface, region, color);
} else{ }
if (a == 255) return _rasterSolidRle(surface, shape->rle, color); if (translucent) {
return _rasterTranslucentRle(surface, shape->rle, color); 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); b = ALPHA_MULTIPLY(b, a);
auto color = surface->blender.join(r, g, 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); if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color);
return _rasterTranslucentRle(surface, shape->strokeRle, color); return _rasterSolidRle(surface, shape->strokeRle, color);
} }

View file

@ -30,15 +30,6 @@
static bool initEngine = false; static bool initEngine = false;
static uint32_t rendererCnt = 0; static uint32_t rendererCnt = 0;
struct SwCompositor : Compositor
{
SwSurface surface;
SwCompositor* recover;
SwImage image;
SwBBox bbox;
bool valid;
};
struct SwTask : Task struct SwTask : Task
{ {
@ -51,10 +42,14 @@ struct SwTask : Task
void bounds(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) void bounds(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{ {
if (x) *x = bbox.min.x; //Range over?
if (y) *y = bbox.min.y; auto xx = bbox.min.x > 0 ? bbox.min.x : 0;
if (w) *w = bbox.max.x - bbox.min.x; auto yy = bbox.min.y > 0 ? bbox.min.y : 0;
if (h) *h = bbox.max.y - bbox.min.y;
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; virtual bool dispose() = 0;
@ -247,7 +242,6 @@ 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;
@ -272,7 +266,8 @@ bool SwRenderer::postRender()
//Free Composite Caches //Free Composite Caches
for (auto comp = compositors.data; comp < (compositors.data + compositors.count); ++comp) { 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); delete(*comp);
} }
compositors.reset(); 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<SwImageTask*>(data); auto task = static_cast<SwImageTask*>(data);
task->done(); 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<SwShapeTask*>(data); auto task = static_cast<SwShapeTask*>(data);
task->done(); task->done();
@ -300,18 +295,16 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
if (task->opacity == 0) return true; if (task->opacity == 0) return true;
uint32_t opacity; uint32_t opacity;
Compositor* cmp2 = nullptr; Compositor* cmp = nullptr;
//Do Composition //Do Stroking Composition
if (task->cmpStroking) { if (task->cmpStroking) {
uint32_t x, y, w, h; uint32_t x, y, w, h;
task->bounds(&x, &y, &w, &h); task->bounds(&x, &y, &w, &h);
opacity = 255; opacity = 255;
//CompositeMethod::None is used for a default alpha blending cmp = target(x, y, w, h);
cmp2 = addCompositor(x, y, w, h); beginComposite(cmp, CompositeMethod::None, task->opacity);
cmp2->method = CompositeMethod::None; //No Stroking Composition
cmp2->opacity = task->opacity;
//No Composition
} else { } else {
opacity = task->opacity; opacity = task->opacity;
} }
@ -331,13 +324,12 @@ bool SwRenderer::renderShape(RenderData data, TVG_UNUSED Compositor* cmp)
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255); a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a); if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
//Composition (Shape + Stroke) stage if (task->cmpStroking) endComposite(cmp);
if (task->cmpStroking) delCompositor(cmp2);
return true; 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<SwTask*>(data)->bounds(x, y, w, h); static_cast<SwTask*>(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<SwCompositor*>(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 //Use cached data
for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) { for (auto p = compositors.data; p < (compositors.data + compositors.count); ++p) {
if ((*p)->valid) { if ((*p)->compositor->valid) {
cmp = *p; cmp = *p;
break; break;
} }
@ -359,19 +369,21 @@ Compositor* SwRenderer::addCompositor(uint32_t x, uint32_t y, uint32_t w, uint32
//New Composition //New Composition
if (!cmp) { if (!cmp) {
cmp = new SwCompositor; cmp = new SwSurface;
if (!cmp) return nullptr; 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 //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); cmp->compositor->image.data = (uint32_t*) malloc(sizeof(uint32_t) * surface->w * surface->h);
if (!cmp->image.data) { if (!cmp->compositor->image.data) goto err;
delete(cmp);
return nullptr;
}
compositors.push(cmp); compositors.push(cmp);
} }
cmp->valid = false;
//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);
@ -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); printf("SW_ENGINE: Using intermediate composition [Region: %d %d %d %d]\n", x, y, w, h);
#endif #endif
cmp->bbox.min.x = x; cmp->compositor->recoverSfc = surface;
cmp->bbox.min.y = y; cmp->compositor->recoverCmp = surface->compositor;
cmp->bbox.max.x = x + w; cmp->compositor->valid = false;
cmp->bbox.max.y = y + h; cmp->compositor->bbox.min.x = x;
cmp->image.w = surface->w; cmp->compositor->bbox.min.y = y;
cmp->image.h = surface->h; cmp->compositor->bbox.max.x = x + w;
cmp->compositor->bbox.max.y = y + h;
//Inherits attributes from main surface cmp->compositor->image.w = surface->w;
cmp->surface.blender = surface->blender; cmp->compositor->image.h = surface->h;
cmp->surface.stride = surface->w;
cmp->surface.cs = surface->cs;
//We know partial clear region //We know partial clear region
cmp->surface.buffer = cmp->image.data + (cmp->surface.stride * y + x); cmp->buffer = cmp->compositor->image.data + (cmp->stride * y + x);
cmp->surface.w = w; cmp->w = w;
cmp->surface.h = h; cmp->h = h;
rasterClear(&cmp->surface); rasterClear(cmp);
//Recover context //Recover context
cmp->surface.buffer = cmp->image.data; cmp->buffer = cmp->compositor->image.data;
cmp->surface.w = cmp->image.w; cmp->w = cmp->compositor->image.w;
cmp->surface.h = cmp->image.h; cmp->h = cmp->compositor->image.h;
//Switch active compositor
cmp->recover = compositor; //Backup current compositor
compositor = cmp;
//Switch render target //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; if (!cmp) return false;
@ -423,8 +437,8 @@ bool SwRenderer::delCompositor(Compositor* cmp)
p->valid = true; p->valid = true;
//Recover Context //Recover Context
compositor = p->recover; surface = p->recoverSfc;
surface = compositor ? &compositor->surface : mainSurface; surface->compositor = p->recoverCmp;
//Default is alpha blending //Default is alpha blending
if (p->method == CompositeMethod::None) { if (p->method == CompositeMethod::None) {

View file

@ -36,28 +36,29 @@ class SwRenderer : public RenderMethod
public: public:
RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override; RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override;
RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) override; RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& 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 preRender() override;
bool renderShape(RenderData data) override;
bool renderImage(RenderData data) override;
bool postRender() 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 clear() override;
bool renderShape(RenderData data, Compositor* cmp) override;
bool renderImage(RenderData data, Compositor* 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);
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 SwRenderer* gen();
static bool init(uint32_t threads); static bool init(uint32_t threads);
static bool term(); static bool term();
private: private:
SwSurface* surface = nullptr; //active surface SwSurface* surface = nullptr; //active surface
SwCompositor* compositor = nullptr; //active compositor
SwSurface* mainSurface = nullptr; //main (default) surface
Array<SwTask*> tasks; //async task list Array<SwTask*> tasks; //async task list
Array<SwCompositor*> compositors; //compositor cache list Array<SwSurface*> compositors; //render targets cache list
SwRenderer(){}; SwRenderer(){};
~SwRenderer(); ~SwRenderer();

View file

@ -97,7 +97,7 @@ struct Canvas::Impl
if (!renderer->preRender()) return Result::InsufficientCondition; if (!renderer->preRender()) return Result::InsufficientCondition;
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 Result::InsufficientCondition; if (!(*paint)->pImpl->render(*renderer, 255)) return Result::InsufficientCondition;
} }
if (!renderer->postRender()) return Result::InsufficientCondition; if (!renderer->postRender()) return Result::InsufficientCondition;

View file

@ -35,7 +35,7 @@ namespace tvg
virtual bool dispose(RenderMethod& renderer) = 0; virtual bool dispose(RenderMethod& renderer) = 0;
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, 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, uint32_t opacity) = 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;
virtual Paint* duplicate() = 0; virtual Paint* duplicate() = 0;
@ -150,7 +150,7 @@ namespace tvg
void *cmpData = nullptr; void *cmpData = nullptr;
if (cmpTarget) { 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); if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData);
} }
@ -172,23 +172,25 @@ namespace tvg
return edata; return edata;
} }
bool render(RenderMethod& renderer) bool render(RenderMethod& renderer, uint32_t opacity)
{ {
Compositor* cmp = nullptr; 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) { if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) {
uint32_t x, y, w, h; uint32_t x, y, w, h;
if (!cmpTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false; if (!cmpTarget->pImpl->bounds(renderer, &x, &y, &w, &h)) return false;
cmp = renderer.addCompositor(x, y, w, h); cmp = renderer.target(x, y, w, h);
cmp->method = CompositeMethod::None; renderer.beginComposite(cmp, CompositeMethod::None, 255);
cmp->opacity = 255; cmpTarget->pImpl->render(renderer, 255);
cmpTarget->pImpl->render(renderer);
} }
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; return ret;
} }
@ -250,9 +252,9 @@ namespace tvg
return inst->update(renderer, transform, opacity, clips, flag); 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 Paint* duplicate() override

View file

@ -122,10 +122,10 @@ struct Picture::Impl
return rdata; return rdata;
} }
bool render(RenderMethod &renderer) bool render(RenderMethod &renderer, uint32_t opacity)
{ {
if (pixels) return renderer.renderImage(rdata, nullptr); if (pixels) return renderer.renderImage(rdata);
else if (paint) return paint->pImpl->render(renderer); else if (paint) return paint->pImpl->render(renderer, opacity);
return false; 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) 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); if (paint) return paint->pImpl->bounds(renderer, x, y, w, h);
return false; return false;
} }

View file

@ -67,16 +67,19 @@ struct RenderMethod
virtual ~RenderMethod() {} virtual ~RenderMethod() {}
virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0; virtual RenderData prepare(const Shape& shape, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0;
virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags) = 0; virtual RenderData prepare(const Picture& picture, RenderData data, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& 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 preRender() = 0;
virtual bool renderShape(RenderData data, Compositor* cmp) = 0; virtual bool renderShape(RenderData data) = 0;
virtual bool renderImage(RenderData data, Compositor* cmp) = 0; virtual bool renderImage(RenderData data) = 0;
virtual bool postRender() = 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 clear() = 0;
virtual bool sync() = 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;
}; };
} }

View file

@ -31,7 +31,6 @@
struct Scene::Impl struct Scene::Impl
{ {
Array<Paint*> paints; Array<Paint*> paints;
uint32_t opacity;
bool dispose(RenderMethod& renderer) bool dispose(RenderMethod& renderer)
{ {
@ -46,8 +45,6 @@ struct Scene::Impl
void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag) void* update(RenderMethod &renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flag)
{ {
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 > 0) opacity = 255; if (opacity > 0) opacity = 255;
@ -61,25 +58,23 @@ struct Scene::Impl
return nullptr; return nullptr;
} }
bool render(RenderMethod& renderer) bool render(RenderMethod& renderer, uint32_t opacity)
{ {
Compositor* cmp = nullptr; Compositor* cmp = nullptr;
//Half translucent. This condition requires intermediate composition. //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; uint32_t x, y, w, h;
if (!bounds(renderer, &x, &y, &w, &h)) return false; if (!bounds(renderer, &x, &y, &w, &h)) return false;
//CompositeMethod::None is used for a default alpha blending cmp = renderer.target(x, y, w, h);
cmp = renderer.addCompositor(x, y, w, h); renderer.beginComposite(cmp, CompositeMethod::None, opacity);
cmp->method = CompositeMethod::None;
cmp->opacity = 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, opacity)) return false;
} }
if (cmp) renderer.delCompositor(cmp); if (cmp) renderer.endComposite(cmp);
return true; return true;
} }

View file

@ -218,9 +218,9 @@ struct Shape::Impl
return renderer.dispose(rdata); 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<RenderData>& clips, RenderUpdateFlag pFlag) void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<RenderData>& 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) 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) bool bounds(float* x, float* y, float* w, float* h)