common: improve the rendering pipeline

enhanced the rendering composition target to better support features such as
alpha blending, blending, masking, post effects, and more.
This allows rasterizers to prepare the composition context with more precise control.

Additionally, resolved a crash in the software engine's post-effect process
caused by a buffer size mismatch during XY buffer flipping.

issue: https://github.com/thorvg/thorvg/issues/3009
issue: https://github.com/thorvg/thorvg/issues/2984
This commit is contained in:
Hermet Park 2024-12-04 17:31:52 +09:00 committed by Mira Grudzinska
parent c5a7d76109
commit 36e5f68222
15 changed files with 104 additions and 86 deletions

View file

@ -1016,7 +1016,7 @@ bool GlRenderer::postRender()
} }
RenderCompositor* GlRenderer::target(const RenderRegion& region, TVG_UNUSED ColorSpace cs) RenderCompositor* GlRenderer::target(const RenderRegion& region, TVG_UNUSED ColorSpace cs, TVG_UNUSED CompositionFlag flags)
{ {
auto vp = region; auto vp = region;
if (currentPass()->isEmpty()) return nullptr; if (currentPass()->isEmpty()) return nullptr;

View file

@ -82,7 +82,7 @@ public:
bool sync() override; bool sync() override;
bool clear() override; bool clear() override;
RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override; RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) override;
bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override; bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override;
bool endComposite(RenderCompositor* cmp) override; bool endComposite(RenderCompositor* cmp) override;

View file

@ -546,15 +546,27 @@ const RenderSurface* SwRenderer::mainSurface()
} }
SwSurface* SwRenderer::request(int channelSize) SwSurface* SwRenderer::request(int channelSize, bool square)
{ {
SwSurface* cmp = nullptr; SwSurface* cmp = nullptr;
uint32_t w, h;
if (square) {
//Same Dimensional Size is demanded for the Post Processing Fast Flipping
w = h = std::max(surface->w, surface->h);
} else {
w = surface->w;
h = surface->h;
}
//Use cached data //Use cached data
for (auto p = compositors.begin(); p < compositors.end(); ++p) { for (auto p = compositors.begin(); p < compositors.end(); ++p) {
if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == channelSize) { auto cur = *p;
cmp = *p; if (cur->compositor->valid && cur->compositor->image.channelSize == channelSize) {
break; if (w == cur->w && h == cur->h) {
cmp = *p;
break;
}
} }
} }
@ -563,15 +575,13 @@ SwSurface* SwRenderer::request(int channelSize)
//Inherits attributes from main surface //Inherits attributes from main surface
cmp = new SwSurface(surface); cmp = new SwSurface(surface);
cmp->compositor = new SwCompositor; cmp->compositor = new SwCompositor;
cmp->compositor->image.data = (pixel_t*)malloc(channelSize * surface->stride * surface->h); cmp->compositor->image.data = (pixel_t*)malloc(channelSize * w * h);
cmp->compositor->image.w = surface->w; cmp->w = cmp->compositor->image.w = w;
cmp->compositor->image.h = surface->h; cmp->h = cmp->compositor->image.h = h;
cmp->compositor->image.stride = surface->stride; cmp->compositor->image.stride = w;
cmp->compositor->image.direct = true; cmp->compositor->image.direct = true;
cmp->compositor->valid = true; cmp->compositor->valid = true;
cmp->channelSize = cmp->compositor->image.channelSize = channelSize; cmp->channelSize = cmp->compositor->image.channelSize = channelSize;
cmp->w = cmp->compositor->image.w;
cmp->h = cmp->compositor->image.h;
compositors.push(cmp); compositors.push(cmp);
} }
@ -583,7 +593,7 @@ SwSurface* SwRenderer::request(int channelSize)
} }
RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags)
{ {
auto x = region.x; auto x = region.x;
auto y = region.y; auto y = region.y;
@ -595,7 +605,7 @@ RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
//Out of boundary //Out of boundary
if (x >= sw || y >= sh || x + w < 0 || y + h < 0) return nullptr; if (x >= sw || y >= sh || x + w < 0 || y + h < 0) return nullptr;
auto cmp = request(CHANNEL_SIZE(cs)); auto cmp = request(CHANNEL_SIZE(cs), (flags & CompositionFlag::PostProcessing));
//Boundary Check //Boundary Check
if (x < 0) x = 0; if (x < 0) x = 0;
@ -664,12 +674,12 @@ bool SwRenderer::effect(RenderCompositor* cmp, const RenderEffect* effect, uint8
switch (effect->type) { switch (effect->type) {
case SceneEffect::GaussianBlur: { case SceneEffect::GaussianBlur: {
return effectGaussianBlur(p, request(surface->channelSize), static_cast<const RenderEffectGaussianBlur*>(effect)); return effectGaussianBlur(p, request(surface->channelSize, true), static_cast<const RenderEffectGaussianBlur*>(effect));
} }
case SceneEffect::DropShadow: { case SceneEffect::DropShadow: {
auto cmp1 = request(surface->channelSize); auto cmp1 = request(surface->channelSize, true);
cmp1->compositor->valid = false; cmp1->compositor->valid = false;
auto cmp2 = request(surface->channelSize); auto cmp2 = request(surface->channelSize, true);
SwSurface* surfaces[] = {cmp1, cmp2}; SwSurface* surfaces[] = {cmp1, cmp2};
auto ret = effectDropShadow(p, surfaces, static_cast<const RenderEffectDropShadow*>(effect), opacity, direct); auto ret = effectDropShadow(p, surfaces, static_cast<const RenderEffectDropShadow*>(effect), opacity, direct);
cmp1->compositor->valid = true; cmp1->compositor->valid = true;

View file

@ -55,7 +55,7 @@ public:
bool target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, ColorSpace cs); bool target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, ColorSpace cs);
bool mempool(bool shared); bool mempool(bool shared);
RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override; RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) override;
bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override; bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override;
bool endComposite(RenderCompositor* cmp) override; bool endComposite(RenderCompositor* cmp) override;
void clearCompositors(); void clearCompositors();
@ -79,7 +79,7 @@ private:
SwRenderer(); SwRenderer();
~SwRenderer(); ~SwRenderer();
SwSurface* request(int channelSize); SwSurface* request(int channelSize, bool square);
RenderData prepareCommon(SwTask* task, const Matrix& transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags); RenderData prepareCommon(SwTask* task, const Matrix& transform, const Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flags);
}; };

View file

@ -216,7 +216,7 @@ bool Paint::Impl::render(RenderMethod* renderer)
if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer)); if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer));
if (region.w == 0 || region.h == 0) return true; if (region.w == 0 || region.h == 0) return true;
cmp = renderer->target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method)); cmp = renderer->target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method), CompositionFlag::Masking);
if (renderer->beginComposite(cmp, CompositeMethod::None, 255)) { if (renderer->beginComposite(cmp, CompositeMethod::None, 255)) {
compData->target->pImpl->render(renderer); compData->target->pImpl->render(renderer);
} }
@ -374,7 +374,7 @@ void Paint::Impl::reset()
blendMethod = BlendMethod::Normal; blendMethod = BlendMethod::Normal;
renderFlag = RenderUpdateFlag::None; renderFlag = RenderUpdateFlag::None;
ctxFlag = ContextFlag::Invalid; ctxFlag = ContextFlag::Default;
opacity = 255; opacity = 255;
paint->id = 0; paint->id = 0;
} }

View file

@ -28,7 +28,7 @@
namespace tvg namespace tvg
{ {
enum ContextFlag : uint8_t {Invalid = 0, FastTrack = 1}; enum ContextFlag : uint8_t {Default = 0, FastTrack = 1};
struct Iterator struct Iterator
{ {

View file

@ -56,18 +56,20 @@ RenderUpdateFlag Picture::Impl::load()
} }
bool Picture::Impl::needComposition(uint8_t opacity) void Picture::Impl::queryComposition(uint8_t opacity)
{ {
cFlag = CompositionFlag::Invalid;
//In this case, paint(scene) would try composition itself. //In this case, paint(scene) would try composition itself.
if (opacity < 255) return false; if (opacity < 255) return;
//Composition test //Composition test
const Paint* target; const Paint* target;
auto method = picture->composite(&target); auto method = picture->composite(&target);
if (!target || method == tvg::CompositeMethod::ClipPath) return false; if (!target || method == tvg::CompositeMethod::ClipPath) return;
if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false; if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return;
return true; cFlag = CompositionFlag::Opacity;
} }
@ -79,8 +81,8 @@ bool Picture::Impl::render(RenderMethod* renderer)
if (surface) return renderer->renderImage(rd); if (surface) return renderer->renderImage(rd);
else if (paint) { else if (paint) {
RenderCompositor* cmp = nullptr; RenderCompositor* cmp = nullptr;
if (needComp) { if (cFlag) {
cmp = renderer->target(bounds(renderer), renderer->colorSpace()); cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast<CompositionFlag>(cFlag));
renderer->beginComposite(cmp, CompositeMethod::None, 255); renderer->beginComposite(cmp, CompositeMethod::None, 255);
} }
ret = paint->pImpl->render(renderer); ret = paint->pImpl->render(renderer);

View file

@ -64,10 +64,10 @@ struct Picture::Impl
RenderData rd = nullptr; //engine data RenderData rd = nullptr; //engine data
float w = 0, h = 0; float w = 0, h = 0;
Picture* picture = nullptr; Picture* picture = nullptr;
uint8_t cFlag = CompositionFlag::Invalid;
bool resizing = false; bool resizing = false;
bool needComp = false; //need composition
bool needComposition(uint8_t opacity); void queryComposition(uint8_t opacity);
bool render(RenderMethod* renderer); bool render(RenderMethod* renderer);
bool size(float w, float h); bool size(float w, float h);
RenderRegion bounds(RenderMethod* renderer); RenderRegion bounds(RenderMethod* renderer);
@ -107,7 +107,7 @@ struct Picture::Impl
loader->resize(paint, w, h); loader->resize(paint, w, h);
resizing = false; resizing = false;
} }
needComp = needComposition(opacity) ? true : false; queryComposition(opacity);
rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false); rd = paint->pImpl->update(renderer, transform, clips, opacity, flag, false);
} }
return rd; return rd;

View file

@ -36,6 +36,7 @@ using RenderData = void*;
using pixel_t = uint32_t; using pixel_t = uint32_t;
enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255}; enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255};
enum CompositionFlag : uint8_t {Invalid = 0, Opacity = 1, Blending = 2, Masking = 4, PostProcessing = 8}; //Composition Purpose
//TODO: Move this in public header unifying with SwCanvas::Colorspace //TODO: Move this in public header unifying with SwCanvas::Colorspace
enum ColorSpace : uint8_t enum ColorSpace : uint8_t
@ -347,7 +348,7 @@ public:
virtual bool clear() = 0; virtual bool clear() = 0;
virtual bool sync() = 0; virtual bool sync() = 0;
virtual RenderCompositor* target(const RenderRegion& region, ColorSpace cs) = 0; virtual RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) = 0;
virtual bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) = 0; virtual bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) = 0;
virtual bool endComposite(RenderCompositor* cmp) = 0; virtual bool endComposite(RenderCompositor* cmp) = 0;

View file

@ -62,8 +62,8 @@ struct Scene::Impl
Scene* scene = nullptr; Scene* scene = nullptr;
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX}; RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
Array<RenderEffect*>* effects = nullptr; Array<RenderEffect*>* effects = nullptr;
uint8_t compFlag = CompositionFlag::Invalid;
uint8_t opacity; //for composition uint8_t opacity; //for composition
bool needComp = false; //composite or not
Impl(Scene* s) : scene(s) Impl(Scene* s) : scene(s)
{ {
@ -82,36 +82,36 @@ struct Scene::Impl
} }
} }
bool needComposition(uint8_t opacity) uint8_t needComposition(uint8_t opacity)
{ {
if (opacity == 0 || paints.empty()) return false; compFlag = CompositionFlag::Invalid;
//post effects requires composition if (opacity == 0 || paints.empty()) return 0;
if (effects) return true;
//Masking may require composition (even if opacity == 255) //post effects, masking, blending may require composition
if (effects) compFlag |= CompositionFlag::PostProcessing;
auto compMethod = scene->composite(nullptr); auto compMethod = scene->composite(nullptr);
if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) return true; if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) compFlag |= CompositionFlag::Masking;
if (PP(scene)->blendMethod != BlendMethod::Normal) compFlag |= CompositionFlag::Blending;
//Blending may require composition (even if opacity == 255)
if (PP(scene)->blendMethod != BlendMethod::Normal) return true;
//Half translucent requires intermediate composition. //Half translucent requires intermediate composition.
if (opacity == 255) return false; if (opacity == 255) return compFlag;
//If scene has several children or only scene, it may require composition. //If scene has several children or only scene, it may require composition.
//OPTIMIZE: the bitmap type of the picture would not need the composition. //OPTIMIZE: the bitmap type of the picture would not need the composition.
//OPTIMIZE: a single paint of a scene would not need the composition. //OPTIMIZE: a single paint of a scene would not need the composition.
if (paints.size() == 1 && paints.front()->type() == Type::Shape) return false; if (paints.size() == 1 && paints.front()->type() == Type::Shape) return compFlag;
return true; compFlag |= CompositionFlag::Opacity;
return 1;
} }
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, TVG_UNUSED bool clipper) RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag flag, TVG_UNUSED bool clipper)
{ {
this->vport = renderer->viewport(); this->vport = renderer->viewport();
if ((needComp = needComposition(opacity))) { if (needComposition(opacity)) {
/* Overriding opacity value. If this scene is half-translucent, /* Overriding opacity value. If this scene is half-translucent,
It must do intermediate composition with that opacity value. */ It must do intermediate composition with that opacity value. */
this->opacity = opacity; this->opacity = opacity;
@ -131,8 +131,8 @@ struct Scene::Impl
renderer->blend(PP(scene)->blendMethod); renderer->blend(PP(scene)->blendMethod);
if (needComp) { if (compFlag) {
cmp = renderer->target(bounds(renderer), renderer->colorSpace()); cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast<CompositionFlag>(compFlag));
renderer->beginComposite(cmp, CompositeMethod::None, opacity); renderer->beginComposite(cmp, CompositeMethod::None, opacity);
} }

View file

@ -66,7 +66,7 @@ Result Shape::reset() noexcept
pImpl->rs.path.cmds.clear(); pImpl->rs.path.cmds.clear();
pImpl->rs.path.pts.clear(); pImpl->rs.path.pts.clear();
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -93,7 +93,7 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point*
pImpl->grow(cmdCnt, ptsCnt); pImpl->grow(cmdCnt, ptsCnt);
pImpl->append(cmds, cmdCnt, pts, ptsCnt); pImpl->append(cmds, cmdCnt, pts, ptsCnt);
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -111,7 +111,7 @@ Result Shape::lineTo(float x, float y) noexcept
{ {
pImpl->lineTo(x, y); pImpl->lineTo(x, y);
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -121,7 +121,7 @@ Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float
{ {
pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y); pImpl->cubicTo(cx1, cy1, cx2, cy2, x, y);
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -131,7 +131,7 @@ Result Shape::close() noexcept
{ {
pImpl->close(); pImpl->close();
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -150,7 +150,7 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
pImpl->close(); pImpl->close();
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -212,7 +212,7 @@ TVG_DEPRECATED Result Shape::appendArc(float cx, float cy, float radius, float s
if (pie) pImpl->close(); if (pie) pImpl->close();
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -252,7 +252,7 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
pImpl->close(); pImpl->close();
} }
pImpl->flag |= RenderUpdateFlag::Path; pImpl->rFlag |= RenderUpdateFlag::Path;
return Result::Success; return Result::Success;
} }
@ -263,7 +263,7 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
if (pImpl->rs.fill) { if (pImpl->rs.fill) {
delete(pImpl->rs.fill); delete(pImpl->rs.fill);
pImpl->rs.fill = nullptr; pImpl->rs.fill = nullptr;
pImpl->flag |= RenderUpdateFlag::Gradient; pImpl->rFlag |= RenderUpdateFlag::Gradient;
} }
if (r == pImpl->rs.color[0] && g == pImpl->rs.color[1] && b == pImpl->rs.color[2] && a == pImpl->rs.color[3]) return Result::Success; if (r == pImpl->rs.color[0] && g == pImpl->rs.color[1] && b == pImpl->rs.color[2] && a == pImpl->rs.color[3]) return Result::Success;
@ -272,7 +272,7 @@ Result Shape::fill(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
pImpl->rs.color[1] = g; pImpl->rs.color[1] = g;
pImpl->rs.color[2] = b; pImpl->rs.color[2] = b;
pImpl->rs.color[3] = a; pImpl->rs.color[3] = a;
pImpl->flag |= RenderUpdateFlag::Color; pImpl->rFlag |= RenderUpdateFlag::Color;
return Result::Success; return Result::Success;
} }
@ -285,7 +285,7 @@ Result Shape::fill(unique_ptr<Fill> f) noexcept
if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill); if (pImpl->rs.fill && pImpl->rs.fill != p) delete(pImpl->rs.fill);
pImpl->rs.fill = p; pImpl->rs.fill = p;
pImpl->flag |= RenderUpdateFlag::Gradient; pImpl->rFlag |= RenderUpdateFlag::Gradient;
return Result::Success; return Result::Success;
} }

View file

@ -33,10 +33,9 @@ struct Shape::Impl
RenderShape rs; //shape data RenderShape rs; //shape data
RenderData rd = nullptr; //engine data RenderData rd = nullptr; //engine data
Shape* shape; Shape* shape;
uint8_t flag = RenderUpdateFlag::None; uint8_t rFlag = RenderUpdateFlag::None;
uint8_t cFlag = CompositionFlag::Invalid;
uint8_t opacity; //for composition uint8_t opacity; //for composition
bool needComp = false; //composite or not
Impl(Shape* s) : shape(s) Impl(Shape* s) : shape(s)
{ {
@ -57,8 +56,8 @@ struct Shape::Impl
renderer->blend(PP(shape)->blendMethod); renderer->blend(PP(shape)->blendMethod);
if (needComp) { if (cFlag) {
cmp = renderer->target(bounds(renderer), renderer->colorSpace()); cmp = renderer->target(bounds(renderer), renderer->colorSpace(), static_cast<CompositionFlag>(cFlag));
renderer->beginComposite(cmp, CompositeMethod::None, opacity); renderer->beginComposite(cmp, CompositeMethod::None, opacity);
} }
@ -69,6 +68,8 @@ struct Shape::Impl
bool needComposition(uint8_t opacity) bool needComposition(uint8_t opacity)
{ {
cFlag = CompositionFlag::Invalid;
if (opacity == 0) return false; if (opacity == 0) return false;
//Shape composition is only necessary when stroking & fill are valid. //Shape composition is only necessary when stroking & fill are valid.
@ -76,7 +77,10 @@ struct Shape::Impl
if (!rs.fill && rs.color[3] == 0) return false; if (!rs.fill && rs.color[3] == 0) return false;
//translucent fill & stroke //translucent fill & stroke
if (opacity < 255) return true; if (opacity < 255) {
cFlag = CompositionFlag::Opacity;
return true;
}
//Composition test //Composition test
const Paint* target; const Paint* target;
@ -97,22 +101,23 @@ struct Shape::Impl
} }
} }
cFlag = CompositionFlag::Masking;
return true; return true;
} }
RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper)
{ {
if (static_cast<RenderUpdateFlag>(pFlag | flag) == RenderUpdateFlag::None) return rd; if (static_cast<RenderUpdateFlag>(pFlag | rFlag) == RenderUpdateFlag::None) return rd;
if ((needComp = needComposition(opacity))) { if (needComposition(opacity)) {
/* Overriding opacity value. If this scene is half-translucent, /* Overriding opacity value. If this scene is half-translucent,
It must do intermediate composition with that opacity value. */ It must do intermediate composition with that opacity value. */
this->opacity = opacity; this->opacity = opacity;
opacity = 255; opacity = 255;
} }
rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | flag), clipper); rd = renderer->prepare(rs, rd, transform, clips, opacity, static_cast<RenderUpdateFlag>(pFlag | rFlag), clipper);
flag = RenderUpdateFlag::None; rFlag = RenderUpdateFlag::None;
return rd; return rd;
} }
@ -209,7 +214,7 @@ struct Shape::Impl
{ {
if (!rs.stroke) rs.stroke = new RenderStroke(); if (!rs.stroke) rs.stroke = new RenderStroke();
rs.stroke->width = width; rs.stroke->width = width;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
void strokeTrim(float begin, float end, bool simultaneous) void strokeTrim(float begin, float end, bool simultaneous)
@ -225,7 +230,7 @@ struct Shape::Impl
rs.stroke->trim.begin = begin; rs.stroke->trim.begin = begin;
rs.stroke->trim.end = end; rs.stroke->trim.end = end;
rs.stroke->trim.simultaneous = simultaneous; rs.stroke->trim.simultaneous = simultaneous;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
bool strokeTrim(float* begin, float* end) bool strokeTrim(float* begin, float* end)
@ -245,21 +250,21 @@ struct Shape::Impl
{ {
if (!rs.stroke) rs.stroke = new RenderStroke(); if (!rs.stroke) rs.stroke = new RenderStroke();
rs.stroke->cap = cap; rs.stroke->cap = cap;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
void strokeJoin(StrokeJoin join) void strokeJoin(StrokeJoin join)
{ {
if (!rs.stroke) rs.stroke = new RenderStroke(); if (!rs.stroke) rs.stroke = new RenderStroke();
rs.stroke->join = join; rs.stroke->join = join;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
void strokeMiterlimit(float miterlimit) void strokeMiterlimit(float miterlimit)
{ {
if (!rs.stroke) rs.stroke = new RenderStroke(); if (!rs.stroke) rs.stroke = new RenderStroke();
rs.stroke->miterlimit = miterlimit; rs.stroke->miterlimit = miterlimit;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
void strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) void strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
@ -268,7 +273,7 @@ struct Shape::Impl
if (rs.stroke->fill) { if (rs.stroke->fill) {
delete(rs.stroke->fill); delete(rs.stroke->fill);
rs.stroke->fill = nullptr; rs.stroke->fill = nullptr;
flag |= RenderUpdateFlag::GradientStroke; rFlag |= RenderUpdateFlag::GradientStroke;
} }
rs.stroke->color[0] = r; rs.stroke->color[0] = r;
@ -276,7 +281,7 @@ struct Shape::Impl
rs.stroke->color[2] = b; rs.stroke->color[2] = b;
rs.stroke->color[3] = a; rs.stroke->color[3] = a;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
Result strokeFill(unique_ptr<Fill> f) Result strokeFill(unique_ptr<Fill> f)
@ -289,8 +294,8 @@ struct Shape::Impl
rs.stroke->fill = p; rs.stroke->fill = p;
rs.stroke->color[3] = 0; rs.stroke->color[3] = 0;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
flag |= RenderUpdateFlag::GradientStroke; rFlag |= RenderUpdateFlag::GradientStroke;
return Result::Success; return Result::Success;
} }
@ -325,7 +330,7 @@ struct Shape::Impl
} }
rs.stroke->dashCnt = cnt; rs.stroke->dashCnt = cnt;
rs.stroke->dashOffset = offset; rs.stroke->dashOffset = offset;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
return Result::Success; return Result::Success;
} }
@ -340,12 +345,12 @@ struct Shape::Impl
{ {
if (!rs.stroke) rs.stroke = new RenderStroke(); if (!rs.stroke) rs.stroke = new RenderStroke();
rs.stroke->strokeFirst = strokeFirst; rs.stroke->strokeFirst = strokeFirst;
flag |= RenderUpdateFlag::Stroke; rFlag |= RenderUpdateFlag::Stroke;
} }
void update(RenderUpdateFlag flag) void update(RenderUpdateFlag flag)
{ {
this->flag |= flag; rFlag |= flag;
} }
Paint* duplicate(Paint* ret) Paint* duplicate(Paint* ret)
@ -358,7 +363,7 @@ struct Shape::Impl
delete(dup->rs.fill); delete(dup->rs.fill);
//Default Properties //Default Properties
dup->flag = RenderUpdateFlag::All; dup->rFlag = RenderUpdateFlag::All;
dup->rs.rule = rs.rule; dup->rs.rule = rs.rule;
//Color //Color

View file

@ -113,7 +113,7 @@ struct Text::Impl
//transform the gradient coordinates based on the final scaled font. //transform the gradient coordinates based on the final scaled font.
auto fill = P(shape)->rs.fill; auto fill = P(shape)->rs.fill;
if (fill && P(shape)->flag & RenderUpdateFlag::Gradient) { if (fill && P(shape)->rFlag & RenderUpdateFlag::Gradient) {
auto scale = 1.0f / loader->scale; auto scale = 1.0f / loader->scale;
if (fill->type() == Type::LinearGradient) { if (fill->type() == Type::LinearGradient) {
P(static_cast<LinearGradient*>(fill))->x1 *= scale; P(static_cast<LinearGradient*>(fill))->x1 *= scale;

View file

@ -347,7 +347,7 @@ bool WgRenderer::target(WGPUSurface surface, uint32_t w, uint32_t h) {
} }
RenderCompositor* WgRenderer::target(TVG_UNUSED const RenderRegion& region, TVG_UNUSED ColorSpace cs) RenderCompositor* WgRenderer::target(const RenderRegion& region, TVG_UNUSED ColorSpace cs, TVG_UNUSED CompositionFlag flags)
{ {
mCompositorStack.push(new WgCompose); mCompositorStack.push(new WgCompose);
mCompositorStack.last()->aabb = region; mCompositorStack.last()->aabb = region;

View file

@ -48,7 +48,7 @@ public:
bool target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device); bool target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device);
bool target(WGPUSurface surface, uint32_t w, uint32_t h); bool target(WGPUSurface surface, uint32_t w, uint32_t h);
RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override; RenderCompositor* target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags) override;
bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override; bool beginComposite(RenderCompositor* cmp, CompositeMethod method, uint8_t opacity) override;
bool endComposite(RenderCompositor* cmp) override; bool endComposite(RenderCompositor* cmp) override;