sw_engine: fixed incorrect image blending operations

The anti-aliased outline color was incorrectly blended
at the multiply option.

The fix can be observed in the example:
'examples/lottie/resourcesguitar.json'

in order to do this, RenderMehthod::blend() method introduced
`bool direct` for figuring out the intermediate composition.
This commit is contained in:
Hermet Park 2024-08-20 16:43:32 +09:00 committed by Hermet Park
parent 078b1c8d86
commit 38697022f0
14 changed files with 25 additions and 18 deletions

View file

@ -913,11 +913,10 @@ const Surface* GlRenderer::mainSurface()
} }
bool GlRenderer::blend(TVG_UNUSED BlendMethod method) bool GlRenderer::blend(TVG_UNUSED BlendMethod method, TVG_UNUSED bool direct)
{ {
if (method != BlendMethod::Normal) { if (method != BlendMethod::Normal) return true;
return true;
}
//TODO: //TODO:
return false; return false;
} }

View file

@ -63,7 +63,7 @@ public:
RenderRegion region(RenderData data) override; RenderRegion region(RenderData data) override;
RenderRegion viewport() override; RenderRegion viewport() override;
bool viewport(const RenderRegion& vp) override; bool viewport(const RenderRegion& vp) override;
bool blend(BlendMethod method) override; bool blend(BlendMethod method, bool direct) override;
ColorSpace colorSpace() override; ColorSpace colorSpace() override;
const Surface* mainSurface() override; const Surface* mainSurface() override;

View file

@ -363,7 +363,7 @@ static inline uint32_t opBlendSrcOver(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNU
} }
//TODO: BlendMethod could remove the alpha parameter. //TODO: BlendMethod could remove the alpha parameter.
static inline uint32_t opBlendDifference(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) static inline uint32_t opBlendDifference(uint32_t s, uint32_t d, uint8_t a)
{ {
//if (s > d) => s - d //if (s > d) => s - d
//else => d - s //else => d - s
@ -400,8 +400,7 @@ static inline uint32_t opBlendScreen(uint32_t s, uint32_t d, TVG_UNUSED uint8_t
return JOIN(255, c1, c2, c3); return JOIN(255, c1, c2, c3);
} }
static inline uint32_t opBlendDirectMultiply(uint32_t s, uint32_t d, uint8_t a)
static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{ {
// s * d // s * d
auto c1 = MULTIPLY(C1(s), C1(d)); auto c1 = MULTIPLY(C1(s), C1(d));
@ -410,6 +409,10 @@ static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, TVG_UNUSED uint8_
return JOIN(255, c1, c2, c3); return JOIN(255, c1, c2, c3);
} }
static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, uint8_t a)
{
return opBlendDirectMultiply(s, d, a) + ALPHA_BLEND(d, IA(s));
}
static inline uint32_t opBlendOverlay(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) static inline uint32_t opBlendOverlay(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
{ {

View file

@ -1383,7 +1383,7 @@ static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image,
*dst = INTERPOLATE(tmp, *dst, A(*src)); *dst = INTERPOLATE(tmp, *dst, A(*src));
} }
} else { } else {
for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) { for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
auto tmp = ALPHA_BLEND(*src, opacity); auto tmp = ALPHA_BLEND(*src, opacity);
auto tmp2 = surface->blender(tmp, *dst, 255); auto tmp2 = surface->blender(tmp, *dst, 255);
*dst = INTERPOLATE(tmp2, *dst, A(tmp)); *dst = INTERPOLATE(tmp2, *dst, A(tmp));

View file

@ -100,7 +100,6 @@ struct SwShapeTask : SwTask
return (width * sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12)); return (width * sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12));
} }
bool clip(SwRle* target) override bool clip(SwRle* target) override
{ {
if (shape.fastTrack) rleClipRect(target, &bbox); if (shape.fastTrack) rleClipRect(target, &bbox);
@ -442,7 +441,7 @@ bool SwRenderer::renderShape(RenderData data)
} }
bool SwRenderer::blend(BlendMethod method) bool SwRenderer::blend(BlendMethod method, bool direct)
{ {
if (surface->blendMethod == method) return true; if (surface->blendMethod == method) return true;
surface->blendMethod = method; surface->blendMethod = method;
@ -455,7 +454,7 @@ bool SwRenderer::blend(BlendMethod method)
surface->blender = opBlendScreen; surface->blender = opBlendScreen;
break; break;
case BlendMethod::Multiply: case BlendMethod::Multiply:
surface->blender = opBlendMultiply; surface->blender = direct ? opBlendDirectMultiply : opBlendMultiply;
break; break;
case BlendMethod::Overlay: case BlendMethod::Overlay:
surface->blender = opBlendOverlay; surface->blender = opBlendOverlay;

View file

@ -46,7 +46,7 @@ public:
RenderRegion region(RenderData data) override; RenderRegion region(RenderData data) override;
RenderRegion viewport() override; RenderRegion viewport() override;
bool viewport(const RenderRegion& vp) override; bool viewport(const RenderRegion& vp) override;
bool blend(BlendMethod method) override; bool blend(BlendMethod method, bool direct) override;
ColorSpace colorSpace() override; ColorSpace colorSpace() override;
const Surface* mainSurface() override; const Surface* mainSurface() override;

View file

@ -225,8 +225,6 @@ bool Paint::Impl::render(RenderMethod* renderer)
if (cmp) renderer->beginComposite(cmp, compData->method, compData->target->pImpl->opacity); if (cmp) renderer->beginComposite(cmp, compData->method, compData->target->pImpl->opacity);
renderer->blend(blendMethod);
bool ret; bool ret;
PAINT_METHOD(ret, render(renderer)); PAINT_METHOD(ret, render(renderer));

View file

@ -73,6 +73,8 @@ bool Picture::Impl::needComposition(uint8_t opacity)
bool Picture::Impl::render(RenderMethod* renderer) bool Picture::Impl::render(RenderMethod* renderer)
{ {
bool ret = false; bool ret = false;
renderer->blend(picture->blend(), true);
if (surface) return renderer->renderImage(rd); if (surface) return renderer->renderImage(rd);
else if (paint) { else if (paint) {
Compositor* cmp = nullptr; Compositor* cmp = nullptr;

View file

@ -294,7 +294,7 @@ public:
virtual RenderRegion region(RenderData data) = 0; virtual RenderRegion region(RenderData data) = 0;
virtual RenderRegion viewport() = 0; virtual RenderRegion viewport() = 0;
virtual bool viewport(const RenderRegion& vp) = 0; virtual bool viewport(const RenderRegion& vp) = 0;
virtual bool blend(BlendMethod method) = 0; virtual bool blend(BlendMethod method, bool direct = false) = 0;
virtual ColorSpace colorSpace() = 0; virtual ColorSpace colorSpace() = 0;
virtual const Surface* mainSurface() = 0; virtual const Surface* mainSurface() = 0;

View file

@ -120,6 +120,8 @@ struct Scene::Impl
Compositor* cmp = nullptr; Compositor* cmp = nullptr;
auto ret = true; auto ret = true;
renderer->blend(scene->blend());
if (needComp) { if (needComp) {
cmp = renderer->target(bounds(renderer), renderer->colorSpace()); cmp = renderer->target(bounds(renderer), renderer->colorSpace());
renderer->beginComposite(cmp, CompositeMethod::None, opacity); renderer->beginComposite(cmp, CompositeMethod::None, opacity);

View file

@ -54,10 +54,13 @@ struct Shape::Impl
Compositor* cmp = nullptr; Compositor* cmp = nullptr;
bool ret; bool ret;
renderer->blend(shape->blend(), !needComp);
if (needComp) { if (needComp) {
cmp = renderer->target(bounds(renderer), renderer->colorSpace()); cmp = renderer->target(bounds(renderer), renderer->colorSpace());
renderer->beginComposite(cmp, CompositeMethod::None, opacity); renderer->beginComposite(cmp, CompositeMethod::None, opacity);
} }
ret = renderer->renderShape(rd); ret = renderer->renderShape(rd);
if (cmp) renderer->endComposite(cmp); if (cmp) renderer->endComposite(cmp);
return ret; return ret;

View file

@ -89,6 +89,7 @@ struct Text::Impl
bool render(RenderMethod* renderer) bool render(RenderMethod* renderer)
{ {
renderer->blend(paint->blend(), true);
return PP(shape)->render(renderer); return PP(shape)->render(renderer);
} }

View file

@ -218,7 +218,7 @@ bool WgRenderer::viewport(const RenderRegion& vp)
} }
bool WgRenderer::blend(BlendMethod method) bool WgRenderer::blend(BlendMethod method, TVG_UNUSED bool direct)
{ {
mBlendMethod = method; mBlendMethod = method;
return false; return false;

View file

@ -38,7 +38,7 @@ public:
RenderRegion region(RenderData data) override; RenderRegion region(RenderData data) override;
RenderRegion viewport() override; RenderRegion viewport() override;
bool viewport(const RenderRegion& vp) override; bool viewport(const RenderRegion& vp) override;
bool blend(BlendMethod method) override; bool blend(BlendMethod method, bool direct) override;
ColorSpace colorSpace() override; ColorSpace colorSpace() override;
const Surface* mainSurface() override; const Surface* mainSurface() override;