From eea54f5feaf9c42b2b94af9dd1438fa0626e59c1 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 15 Jun 2023 12:38:03 +0900 Subject: [PATCH] sw_engine: code chores & fix gradient filling bugs. renaming internal methods for integrating with upcoming blending features. this also fixes minor wrong gradient filling blending equations. --- src/lib/sw_engine/tvgSwCommon.h | 55 +++++++++++++++++++++---------- src/lib/sw_engine/tvgSwFill.cpp | 20 +++++------ src/lib/sw_engine/tvgSwRaster.cpp | 38 ++++++++++----------- 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 2f2ef184..1e060346 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -239,6 +239,7 @@ struct SwImage bool scaled = false; //draw scaled image }; +typedef uint32_t(*SwBlender)(uint32_t s, uint32_t d, uint8_t sa); //src, dst, alpha typedef uint32_t(*SwJoin)(uint8_t r, uint8_t g, uint8_t b, uint8_t a); //color channel join typedef uint8_t(*SwAlpha)(uint8_t*); //blending alpha @@ -314,48 +315,66 @@ static inline uint8_t IALPHA(uint32_t c) return (~c >> 24); } +static inline uint32_t opBlendInterp(uint32_t s, uint32_t d, uint8_t a) +{ + return INTERPOLATE(s, d, a); +} -typedef uint32_t(*SwBlendOp)(uint32_t s, uint32_t d, uint8_t a); //src, dst, alpha - -static inline uint32_t opAlphaBlend(uint32_t s, uint32_t d, uint8_t a) +static inline uint32_t opBlendNormal(uint32_t s, uint32_t d, uint8_t a) { auto t = ALPHA_BLEND(s, a); return t + ALPHA_BLEND(d, IALPHA(t)); } -static inline uint32_t opBlend(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) +static inline uint32_t opBlendPreNormal(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) { return s + ALPHA_BLEND(d, IALPHA(s)); } -static inline uint32_t opDirect(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNUSED uint8_t a) +static inline uint32_t opBlendSrcOver(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNUSED uint8_t a) { return s; } -static inline uint32_t opAddMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) +static inline uint32_t opMaskAdd(uint32_t s, uint32_t d, uint8_t a) { - return opBlend(s, d, a); + return opBlendNormal(s, d, a); } -static inline uint32_t opSubMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) +static inline uint32_t opMaskSubtract(uint32_t s, uint32_t d, uint8_t a) +{ + return ALPHA_BLEND(d, MULTIPLY(IALPHA(s), a)); +} + +static inline uint32_t opMaskDifference(uint32_t s, uint32_t d, uint8_t a) +{ + auto t = ALPHA_BLEND(s, a); + return ALPHA_BLEND(t, IALPHA(d)) + ALPHA_BLEND(d, IALPHA(t)); +} + +static inline uint32_t opMaskIntersect(uint32_t s, uint32_t d, uint8_t a) +{ + return ALPHA_BLEND(d, MULTIPLY(IALPHA(s), a)); +} + +static inline uint32_t opMaskPreAdd(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) +{ + return opBlendPreNormal(s, d, a); +} + +static inline uint32_t opMaskPreSubtract(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) { return ALPHA_BLEND(d, IALPHA(s)); } -static inline uint32_t opIntMask(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a) -{ - return ALPHA_BLEND(d, a); -} - -static inline uint32_t opDifMask(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) +static inline uint32_t opMaskPreDifference(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) { return ALPHA_BLEND(s, IALPHA(d)) + ALPHA_BLEND(d, IALPHA(s)); } -static inline uint32_t opInterpolate(uint32_t s, uint32_t d, uint8_t a) +static inline uint32_t opMaskPreIntersect(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) { - return INTERPOLATE(s, d, a); + return ALPHA_BLEND(d, MULTIPLY(a, IALPHA(s))); } @@ -407,9 +426,9 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, void fillReset(SwFill* fill); void fillFree(SwFill* fill); //OPTIMIZE_ME: Skip the function pointer access -void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a); //blending ver. +void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver. void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver. -void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a); //blending ver. +void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver. void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver. SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 477bb280..b003b5b1 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -246,13 +246,13 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 if (opacity == 255) { for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { - *dst = opAlphaBlend(_pixel(fill, sqrtf(det)), *dst, alpha(cmp)); + *dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, alpha(cmp)); det += detFirstDerivative; detFirstDerivative += detSecondDerivative; } } else { for (uint32_t i = 0 ; i < len ; ++i, ++dst, cmp += csize) { - *dst = opAlphaBlend(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp))); + *dst = opBlendNormal(_pixel(fill, sqrtf(det)), *dst, MULTIPLY(opacity, alpha(cmp))); det += detFirstDerivative; detFirstDerivative += detSecondDerivative; } @@ -260,7 +260,7 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 } -void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a) +void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a) { auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; @@ -291,7 +291,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 if (mathZero(inc)) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); for (uint32_t i = 0; i < len; ++i, ++dst, cmp += csize) { - *dst = opAlphaBlend(color, *dst, alpha(cmp)); + *dst = opBlendNormal(color, *dst, alpha(cmp)); } return; } @@ -305,14 +305,14 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 auto t2 = static_cast(t * FIXPT_SIZE); auto inc2 = static_cast(inc * FIXPT_SIZE); for (uint32_t j = 0; j < len; ++j, ++dst, cmp += csize) { - *dst = opAlphaBlend(_fixedPixel(fill, t2), *dst, alpha(cmp)); + *dst = opBlendNormal(_fixedPixel(fill, t2), *dst, alpha(cmp)); t2 += inc2; } //we have to fallback to float math } else { uint32_t counter = 0; while (counter++ < len) { - *dst = opAlphaBlend(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, alpha(cmp)); + *dst = opBlendNormal(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, alpha(cmp)); ++dst; t += inc; cmp += csize; @@ -322,7 +322,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 if (mathZero(inc)) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); for (uint32_t i = 0; i < len; ++i, ++dst, cmp += csize) { - *dst = opAlphaBlend(color, *dst, MULTIPLY(alpha(cmp), opacity)); + *dst = opBlendNormal(color, *dst, MULTIPLY(alpha(cmp), opacity)); } return; } @@ -336,14 +336,14 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 auto t2 = static_cast(t * FIXPT_SIZE); auto inc2 = static_cast(inc * FIXPT_SIZE); for (uint32_t j = 0; j < len; ++j, ++dst, cmp += csize) { - *dst = opAlphaBlend(_fixedPixel(fill, t2), *dst, MULTIPLY(alpha(cmp), opacity)); + *dst = opBlendNormal(_fixedPixel(fill, t2), *dst, MULTIPLY(alpha(cmp), opacity)); t2 += inc2; } //we have to fallback to float math } else { uint32_t counter = 0; while (counter++ < len) { - *dst = opAlphaBlend(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, MULTIPLY(opacity, alpha(cmp))); + *dst = opBlendNormal(_pixel(fill, t / GRADIENT_STOP_SIZE), *dst, MULTIPLY(opacity, alpha(cmp))); ++dst; t += inc; cmp += csize; @@ -353,7 +353,7 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 } -void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a) +void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a) { //Rotation float rx = x + 0.5f; diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 1ac6d3fb..90a213b3 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -39,7 +39,7 @@ constexpr auto DOWN_SCALE_TOLERANCE = 0.5f; struct FillLinear { - void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a) + void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a) { fillLinear(fill, dst, y, x, len, op, a); } @@ -52,7 +52,7 @@ struct FillLinear struct FillRadial { - void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlendOp op, uint8_t a) + void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a) { fillRadial(fill, dst, y, x, len, op, a); } @@ -694,7 +694,7 @@ static bool _rasterScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* i if (method == CompositeMethod::AddMask) _rasterScaledMaskedRleRGBAImageDup(surface, image, itransform, region, opacity, halfScale); else if (method == CompositeMethod::SubtractMask) _rasterScaledMaskedRleRGBAImageDup(surface, image, itransform, region, opacity, halfScale); - else if (method == CompositeMethod::IntersectMask) _rasterScaledMaskedRleRGBAImageDup(surface, image, itransform, region, opacity, halfScale); + else if (method == CompositeMethod::DifferenceMask) _rasterScaledMaskedRleRGBAImageDup(surface, image, itransform, region, opacity, halfScale); else if (method == CompositeMethod::IntersectMask) _rasterScaledMaskedRleRGBAImageInt(surface, image, itransform, region, opacity, halfScale); else return false; @@ -1341,7 +1341,7 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t /************************************************************************/ template -static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlendOp maskOp) +static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp) { auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); @@ -1370,7 +1370,7 @@ static void _rasterGradientMaskedRectInt(SwSurface* surface, const SwBBox& regio auto x = surface->compositor->bbox.min.x; while (x < surface->compositor->bbox.max.x) { if (x == region.min.x) { - fillMethod()(fill, tmp, y2, x, w, opIntMask, 255); + fillMethod()(fill, tmp, y2, x, w, opMaskPreIntersect, 255); x += w; tmp += w; } else { @@ -1397,9 +1397,9 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); - if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup(surface, region, fill, opAddMask); - else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup(surface, region, fill, opSubMask); - else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup(surface, region, fill, opDifMask); + if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup(surface, region, fill, opMaskPreAdd); + else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup(surface, region, fill, opMaskPreSubtract); + else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup(surface, region, fill, opMaskPreDifference); else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRectInt(surface, region, fill); else return false; @@ -1437,7 +1437,7 @@ static bool _rasterTranslucentGradientRect(SwSurface* surface, const SwBBox& reg auto w = static_cast(region.max.x - region.min.x); for (uint32_t y = 0; y < h; ++y) { - fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlend, 255); + fillMethod()(fill, buffer, region.min.y + y, region.min.x, w, opBlendPreNormal, 255); buffer += surface->stride; } return true; @@ -1452,7 +1452,7 @@ static bool _rasterSolidGradientRect(SwSurface* surface, const SwBBox& region, c auto h = static_cast(region.max.y - region.min.y); for (uint32_t y = 0; y < h; ++y) { - fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opDirect, 0); + fillMethod()(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w, opBlendSrcOver, 255); } return true; } @@ -1494,7 +1494,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, /************************************************************************/ template -static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlendOp maskOp) +static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp) { auto span = rle->spans; auto cstride = surface->compositor->image.stride; @@ -1519,7 +1519,7 @@ static void _rasterGradientMaskedRleInt(SwSurface* surface, const SwRleData* rle uint32_t x = surface->compositor->bbox.min.x; while (x < surface->compositor->bbox.max.x) { if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) { - fillMethod()(fill, cmp, span->y, span->x, span->len, opIntMask, span->coverage); + fillMethod()(fill, cmp, span->y, span->x, span->len, opMaskIntersect, span->coverage); x += span->len; ++span; } else { @@ -1538,9 +1538,9 @@ static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, c auto method = surface->compositor->method; - if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup(surface, rle, fill, opAddMask); - else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup(surface, rle, fill, opSubMask); - else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup(surface, rle, fill, opDifMask); + if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup(surface, rle, fill, opMaskAdd); + else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup(surface, rle, fill, opMaskSubtract); + else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup(surface, rle, fill, opMaskDifference); else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRleInt(surface, rle, fill); else return false; @@ -1575,8 +1575,8 @@ static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRleData* r for (uint32_t i = 0; i < rle->size; ++i, ++span) { auto dst = &surface->buf32[span->y * surface->stride + span->x]; - if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlend, 255); - else fillMethod()(fill, dst, span->y, span->x, span->len, opAlphaBlend, span->coverage); + if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, 255); + else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendNormal, span->coverage); } return true; } @@ -1589,8 +1589,8 @@ static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, co for (uint32_t i = 0; i < rle->size; ++i, ++span) { auto dst = &surface->buf32[span->y * surface->stride + span->x]; - if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opDirect, 0); - else fillMethod()(fill, dst, span->y, span->x, span->len, opInterpolate, span->coverage); + if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendSrcOver, 255); + else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendInterp, span->coverage); } return true; }