mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
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:
parent
c5a7d76109
commit
36e5f68222
15 changed files with 104 additions and 86 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue