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) {
return true;
}
if (method != BlendMethod::Normal) return true;
//TODO:
return false;
}

View file

@ -63,7 +63,7 @@ public:
RenderRegion region(RenderData data) override;
RenderRegion viewport() override;
bool viewport(const RenderRegion& vp) override;
bool blend(BlendMethod method) override;
bool blend(BlendMethod method, bool direct) override;
ColorSpace colorSpace() 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.
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
//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);
}
static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
static inline uint32_t opBlendDirectMultiply(uint32_t s, uint32_t d, uint8_t a)
{
// s * 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);
}
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)
{

View file

@ -1383,7 +1383,7 @@ static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image,
*dst = INTERPOLATE(tmp, *dst, A(*src));
}
} 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 tmp2 = surface->blender(tmp, *dst, 255);
*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));
}
bool clip(SwRle* target) override
{
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;
surface->blendMethod = method;
@ -455,7 +454,7 @@ bool SwRenderer::blend(BlendMethod method)
surface->blender = opBlendScreen;
break;
case BlendMethod::Multiply:
surface->blender = opBlendMultiply;
surface->blender = direct ? opBlendDirectMultiply : opBlendMultiply;
break;
case BlendMethod::Overlay:
surface->blender = opBlendOverlay;

View file

@ -46,7 +46,7 @@ public:
RenderRegion region(RenderData data) override;
RenderRegion viewport() override;
bool viewport(const RenderRegion& vp) override;
bool blend(BlendMethod method) override;
bool blend(BlendMethod method, bool direct) override;
ColorSpace colorSpace() 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);
renderer->blend(blendMethod);
bool ret;
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 ret = false;
renderer->blend(picture->blend(), true);
if (surface) return renderer->renderImage(rd);
else if (paint) {
Compositor* cmp = nullptr;

View file

@ -294,7 +294,7 @@ public:
virtual RenderRegion region(RenderData data) = 0;
virtual RenderRegion viewport() = 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 const Surface* mainSurface() = 0;

View file

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

View file

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

View file

@ -89,6 +89,7 @@ struct Text::Impl
bool render(RenderMethod* renderer)
{
renderer->blend(paint->blend(), true);
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;
return false;

View file

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