From 4f7ef8f30ec08fe82629d7b05fedbbc18e9a7c35 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Nov 2021 20:25:47 +0900 Subject: [PATCH 01/16] sw_engine raster: code refactoring +neat and clean code --- src/lib/sw_engine/tvgSwRaster.cpp | 460 +++++++++++++++++------------------- src/lib/sw_engine/tvgSwRasterAvx.h | 6 +- src/lib/sw_engine/tvgSwRasterC.h | 24 +- src/lib/sw_engine/tvgSwRasterNeon.h | 6 +- 4 files changed, 234 insertions(+), 262 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index dafc649..dcd82d7 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -62,14 +62,6 @@ static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) } -static bool _translucent(const SwSurface* surface, uint8_t a) -{ - if (a < 255) return true; - if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false; - return true; -} - - static inline bool _compositing(const SwSurface* surface) { if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false; @@ -130,48 +122,27 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t w, uint32_t h, u /* Rect */ /************************************************************************/ -static bool _rasterTranslucentMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint32_t (*blendMethod)(uint32_t)) { + TVGLOG("SW_ENGINE", "Masked Rect"); + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; - auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); - - TVGLOG("SW_ENGINE", "Translucent Masked Rect"); + auto h = static_cast(region.max.y - region.min.y); auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface->stride]; auto cmp = &cbuffer[y * surface->stride]; - for (uint32_t x = 0; x < w; ++x) { + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp) { auto tmp = ALPHA_BLEND(color, blendMethod(*cmp)); - dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.ialpha(tmp)); - ++cmp; + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); } } return true; } -static bool _rasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTranslucentMaskedRect(surface, region, color, surface->blender.ialpha); - } - } - -#if defined(THORVG_AVX_VECTOR_SUPPORT) - return avxRasterTranslucentRect(surface, region, color); -#elif defined(THORVG_NEON_VECTOR_SUPPORT) - return neonRasterTranslucentRect(surface, region, color); -#else - return cRasterTranslucentRect(surface, region, color); -#endif -} - static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t color) { @@ -186,79 +157,104 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t } +static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color, uint8_t opacity) +{ + if (_compositing(surface)) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterMaskedRect(surface, region, color, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterMaskedRect(surface, region, color, surface->blender.ialpha); + } + } else { + if (opacity == 255) { + return _rasterSolidRect(surface, region, color); + } else { +#if defined(THORVG_AVX_VECTOR_SUPPORT) + return avxRasterTranslucentRect(surface, region, color); +#elif defined(THORVG_NEON_VECTOR_SUPPORT) + return neonRasterTranslucentRect(surface, region, color); +#else + return cRasterTranslucentRect(surface, region, color); +#endif + } + } + return false; +} + + /************************************************************************/ /* Rle */ /************************************************************************/ -static bool _rasterTranslucentMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint32_t (*blendMethod)(uint32_t)) { - TVGLOG("SW_ENGINE", "Translucent Masked Rle"); + TVGLOG("SW_ENGINE", "Masked Rle"); auto span = rle->spans; uint32_t src; auto cbuffer = surface->compositor->image.data; - for (uint32_t i = 0; i < rle->size; ++i) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); - else src = color; - for (uint32_t x = 0; x < span->len; ++x) { + if (span->coverage == 255) src = color; + else src = ALPHA_BLEND(color, span->coverage); + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - dst[x] = tmp + ALPHA_BLEND(dst[x], surface->blender.ialpha(tmp)); - ++cmp; + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); } - ++span; } return true; } -static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t color) -{ - if (!rle) return false; - - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTranslucentMaskedRle(surface, rle, color, surface->blender.ialpha); - } - } - -#if defined(THORVG_AVX_VECTOR_SUPPORT) - return avxRasterTranslucentRle(surface, rle, color); -#elif defined(THORVG_NEON_VECTOR_SUPPORT) - return neonRasterTranslucentRle(surface, rle, color); -#else - return cRasterTranslucentRle(surface, rle, color); -#endif -} - static bool _rasterSolidRle(SwSurface* surface, const SwRleData* rle, uint32_t color) { - if (!rle) return false; - auto span = rle->spans; - for (uint32_t i = 0; i < rle->size; ++i) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { if (span->coverage == 255) { rasterRGBA32(surface->buffer + span->y * surface->stride, color, span->x, span->len); } else { auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto src = ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + ALPHA_BLEND(dst[i], ialpha); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + *dst = src + ALPHA_BLEND(*dst, ialpha); } } - ++span; } return true; } +static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8_t opacity) +{ + if (!rle) return false; + + if (_compositing(surface)) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterMaskedRle(surface, rle, color, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterMaskedRle(surface, rle, color, surface->blender.ialpha); + } + } else { + if (opacity == 255) { + return _rasterSolidRle(surface, rle, color); + } else { +#if defined(THORVG_AVX_VECTOR_SUPPORT) + return avxRasterTranslucentRle(surface, rle, color); +#elif defined(THORVG_NEON_VECTOR_SUPPORT) + return neonRasterTranslucentRle(surface, rle, color); +#else + return cRasterTranslucentRle(surface, rle, color); +#endif + } + } + return false; +} + + /************************************************************************/ /* RLE Transformed RGBA Image */ /************************************************************************/ @@ -1896,7 +1892,7 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t /* Rect Linear Gradient */ /************************************************************************/ -static bool _rasterTranslucentLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterLinearGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { if (fill->linear.len < FLT_EPSILON) return false; @@ -1924,7 +1920,7 @@ static bool _rasterTranslucentLinearGradientMaskedRect(SwSurface* surface, const } -static bool __rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (fill->linear.len < FLT_EPSILON) return false; @@ -1935,39 +1931,25 @@ static bool __rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBB auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); if (!sbuffer) return false; - auto dst = buffer; for (uint32_t y = 0; y < h; ++y) { + auto dst = buffer; fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x])); + for (uint32_t x = 0; x < w; ++x, ++dst) { + *dst = sbuffer[x] + ALPHA_BLEND(*dst, surface->blender.ialpha(sbuffer[x])); } - dst += surface->stride; + buffer += surface->stride; } return true; } -static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha); - } - if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTranslucentLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha); - } - } - return __rasterTranslucentLinearGradientRect(surface, region, fill); -} - - static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (fill->linear.len < FLT_EPSILON) return false; auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; - auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); + auto h = static_cast(region.max.y - region.min.y); for (uint32_t y = 0; y < h; ++y) { fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w); @@ -1976,12 +1958,27 @@ static bool _rasterSolidLinearGradientRect(SwSurface* surface, const SwBBox& reg } +static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +{ + if (_compositing(surface)) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.ialpha); + } + } else { + if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill); + else _rasterSolidLinearGradientRect(surface, region, fill); + } + return false; +} + + /************************************************************************/ /* Rle Linear Gradient */ /************************************************************************/ - -static bool _rasterTranslucentLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterLinearGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { if (fill->linear.len < FLT_EPSILON) return false; @@ -2013,7 +2010,7 @@ static bool _rasterTranslucentLinearGradientMaskedRle(SwSurface* surface, const } -static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (fill->linear.len < FLT_EPSILON) return false; @@ -2025,13 +2022,13 @@ static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRle auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchLinear(fill, buffer, span->y, span->x, span->len); if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i])); + for (uint32_t i = 0; i < span->len; ++i, ++dst) { + *dst = buffer[i] + ALPHA_BLEND(*dst, surface->blender.ialpha(buffer[i])); } } else { - for (uint32_t i = 0; i < span->len; ++i) { + for (uint32_t i = 0; i < span->len; ++i, ++dst) { auto tmp = ALPHA_BLEND(buffer[i], span->coverage); - dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp)); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); } } } @@ -2039,21 +2036,6 @@ static bool __rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRle } -static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) -{ - if (!rle) return false; - - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTranslucentLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha); - } - } - return __rasterTranslucentLinearGradientRle(surface, rle, fill); -} - - static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (fill->linear.len < FLT_EPSILON) return false; @@ -2079,11 +2061,29 @@ static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* r } +static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (!rle) return false; + + if (_compositing(surface)) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.ialpha); + } + } else { + if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill); + else return _rasterSolidLinearGradientRle(surface, rle, fill); + } + return false; +} + + /************************************************************************/ /* Rect Radial Gradient */ /************************************************************************/ -static bool _rasterTranslucentRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterRadialGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { if (fill->radial.a < FLT_EPSILON) return false; @@ -2111,7 +2111,7 @@ static bool _rasterTranslucentRadialGradientMaskedRect(SwSurface* surface, const } -static bool __rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -2122,31 +2122,18 @@ static bool __rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBB auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); if (!sbuffer) return false; - auto dst = buffer; for (uint32_t y = 0; y < h; ++y) { + auto dst = buffer; fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], surface->blender.ialpha(sbuffer[x])); + for (uint32_t x = 0; x < w; ++x, ++dst) { + *dst = sbuffer[x] + ALPHA_BLEND(*dst, surface->blender.ialpha(sbuffer[x])); } - dst += surface->stride; + buffer += surface->stride; } return true; } -static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) -{ - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTranslucentRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha); - } - } - return __rasterTranslucentRadialGradientRect(surface, region, fill); -} - - static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -2163,12 +2150,27 @@ static bool _rasterSolidRadialGradientRect(SwSurface* surface, const SwBBox& reg } +static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +{ + if (_compositing(surface)) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.ialpha); + } + } else { + if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill); + else return _rasterSolidRadialGradientRect(surface, region, fill); + } + return false; +} + + /************************************************************************/ /* RLE Radial Gradient */ /************************************************************************/ - -static bool _rasterTranslucentRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, uint32_t (*blendMethod)(uint32_t)) { if (fill->radial.a < FLT_EPSILON) return false; @@ -2200,7 +2202,7 @@ static bool _rasterTranslucentRadialGradientMaskedRle(SwSurface* surface, const } -static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -2212,13 +2214,13 @@ static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRle auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchRadial(fill, buffer, span->y, span->x, span->len); if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buffer[i] + ALPHA_BLEND(dst[i], surface->blender.ialpha(buffer[i])); + for (uint32_t i = 0; i < span->len; ++i, ++dst) { + *dst = buffer[i] + ALPHA_BLEND(*dst, surface->blender.ialpha(buffer[i])); } } else { - for (uint32_t i = 0; i < span->len; ++i) { + for (uint32_t i = 0; i < span->len; ++i, ++dst) { auto tmp = ALPHA_BLEND(buffer[i], span->coverage); - dst[i] = tmp + ALPHA_BLEND(dst[i], surface->blender.ialpha(tmp)); + *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); } } } @@ -2226,21 +2228,6 @@ static bool __rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRle } -static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) -{ - if (!rle) return false; - - if (surface->compositor) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTranslucentRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha); - } - } - return __rasterTranslucentRadialGradientRle(surface, rle, fill); -} - - static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (fill->radial.a < FLT_EPSILON) return false; @@ -2258,7 +2245,7 @@ static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* r fillFetchRadial(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); + *dst = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(*dst, ialpha); } } } @@ -2266,6 +2253,24 @@ static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* r } +static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (!rle) return false; + + if (_compositing(surface)) { + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.ialpha); + } + } else { + if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill); + else return _rasterSolidRadialGradientRle(surface, rle, fill); + } + return false; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -2299,92 +2304,6 @@ bool rasterCompositor(SwSurface* surface) } -bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) -{ - if (!shape->fill) return false; - - auto translucent = shape->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None); - - //Fast Track - if (shape->fastTrack) { - if (id == TVG_CLASS_ID_LINEAR) { - if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill); - return _rasterSolidLinearGradientRect(surface, shape->bbox, shape->fill); - } else { - if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill); - return _rasterSolidRadialGradientRect(surface, shape->bbox, shape->fill); - } - } else { - if (!shape->rle) return false; - if (id == TVG_CLASS_ID_LINEAR) { - if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill); - return _rasterSolidLinearGradientRle(surface, shape->rle, shape->fill); - } else { - if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill); - return _rasterSolidRadialGradientRle(surface, shape->rle, shape->fill); - } - } - return false; -} - - -bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - if (a < 255) { - r = _multiplyAlpha(r, a); - g = _multiplyAlpha(g, a); - b = _multiplyAlpha(b, a); - } - - auto color = surface->blender.join(r, g, b, a); - auto translucent = _translucent(surface, a); - - //Fast Track - if (shape->fastTrack) { - if (translucent) return _rasterTranslucentRect(surface, shape->bbox, color); - return _rasterSolidRect(surface, shape->bbox, color); - } - if (translucent) { - return _rasterTranslucentRle(surface, shape->rle, color); - } - return _rasterSolidRle(surface, shape->rle, color); -} - - -bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) -{ - if (a < 255) { - r = _multiplyAlpha(r, a); - g = _multiplyAlpha(g, a); - b = _multiplyAlpha(b, a); - } - - auto color = surface->blender.join(r, g, b, a); - auto translucent = _translucent(surface, a); - - if (translucent) return _rasterTranslucentRle(surface, shape->strokeRle, color); - return _rasterSolidRle(surface, shape->strokeRle, color); -} - - -bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) -{ - if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false; - - auto translucent = shape->stroke->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None); - - if (id == TVG_CLASS_ID_LINEAR) { - if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); - return _rasterSolidLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); - } else { - if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); - return _rasterSolidRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); - } - - return false; -} - - bool rasterClear(SwSurface* surface) { if (!surface || !surface->buffer || surface->stride <= 0 || surface->w <= 0 || surface->h <= 0) return false; @@ -2425,6 +2344,61 @@ void rasterUnpremultiply(SwSurface* surface) } +bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) +{ + if (!shape->fill) return false; + + if (shape->fastTrack) { + if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill); + else if (id == TVG_CLASS_ID_RADIAL)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill); + } else { + if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill); + else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->rle, shape->fill); + } + return false; +} + + +bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) +{ + if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false; + + if (id == TVG_CLASS_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + else if (id == TVG_CLASS_ID_RADIAL) return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + + return false; +} + + +bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + if (a < 255) { + r = _multiplyAlpha(r, a); + g = _multiplyAlpha(g, a); + b = _multiplyAlpha(b, a); + } + + auto color = surface->blender.join(r, g, b, a); + + if (shape->fastTrack) return _rasterRect(surface, shape->bbox, color, a); + else return _rasterRle(surface, shape->rle, color, a); +} + + +bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + if (a < 255) { + r = _multiplyAlpha(r, a); + g = _multiplyAlpha(g, a); + b = _multiplyAlpha(b, a); + } + + auto color = surface->blender.join(r, g, b, a); + + return _rasterRle(surface, shape->strokeRle, color, a); +} + + bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity) { //Verify Boundary diff --git a/src/lib/sw_engine/tvgSwRasterAvx.h b/src/lib/sw_engine/tvgSwRasterAvx.h index c14a213..df494dd 100644 --- a/src/lib/sw_engine/tvgSwRasterAvx.h +++ b/src/lib/sw_engine/tvgSwRasterAvx.h @@ -62,7 +62,7 @@ static inline __m128i ALPHA_BLEND(__m128i c, __m128i a) } -static inline void avxRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +static void avxRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { //1. calculate how many iterations we need to cover the length uint32_t iterations = len / N_32BITS_IN_256REG; @@ -82,7 +82,7 @@ static inline void avxRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, } -static inline bool avxRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) +static bool avxRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -125,7 +125,7 @@ static inline bool avxRasterTranslucentRect(SwSurface* surface, const SwBBox& re } -static inline bool avxRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) +static bool avxRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) { auto span = rle->spans; uint32_t src; diff --git a/src/lib/sw_engine/tvgSwRasterC.h b/src/lib/sw_engine/tvgSwRasterC.h index b634edf..9b46361 100644 --- a/src/lib/sw_engine/tvgSwRasterC.h +++ b/src/lib/sw_engine/tvgSwRasterC.h @@ -21,45 +21,43 @@ */ -static inline void cRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +static void cRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { dst += offset; while (len--) *dst++ = val; } -static inline bool cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) +static bool cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) { auto span = rle->spans; uint32_t src; - for (uint32_t i = 0; i < rle->size; ++i) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { auto dst = &surface->buffer[span->y * surface->stride + span->x]; if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); else src = color; - auto ialpha = 255 - surface->blender.alpha(src); - - for (uint32_t x = 0; x < span->len; ++x) - dst[x] = src + ALPHA_BLEND(dst[x], ialpha); - - ++span; + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); + } } return true; } -static inline bool cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) + +static bool cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); - auto ialpha = 255 - surface->blender.alpha(color); + auto ialpha = surface->blender.ialpha(color); for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface->stride]; - for (uint32_t x = 0; x < w; ++x) { - dst[x] = color + ALPHA_BLEND(dst[x], ialpha); + for (uint32_t x = 0; x < w; ++x, ++dst) { + *dst = color + ALPHA_BLEND(*dst, ialpha); } } return true; diff --git a/src/lib/sw_engine/tvgSwRasterNeon.h b/src/lib/sw_engine/tvgSwRasterNeon.h index efc69e9..6cb9cf7 100644 --- a/src/lib/sw_engine/tvgSwRasterNeon.h +++ b/src/lib/sw_engine/tvgSwRasterNeon.h @@ -31,7 +31,7 @@ static inline uint8x8_t ALPHA_BLEND(uint8x8_t c, uint8x8_t a) } -static inline void neonRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +static void neonRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { uint32_t iterations = len / 4; uint32_t neonFilled = iterations * 4; @@ -49,7 +49,7 @@ static inline void neonRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset } -static inline bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) +static bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) { auto span = rle->spans; uint32_t src; @@ -88,7 +88,7 @@ static inline bool neonRasterTranslucentRle(SwSurface* surface, const SwRleData* } -static inline bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) +static bool neonRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); -- 2.7.4 From 1dd31c691c89f6f3b38b0c1a3d2a2490a023bd99 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 24 Nov 2021 20:51:05 +0900 Subject: [PATCH 02/16] sw_engine raster: fix a mistake by the previous hot refactoring. --- src/lib/sw_engine/tvgSwRaster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index dcd82d7..5de990f 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -590,7 +590,7 @@ static bool _rasterDownScaledRleRGBAImage(SwSurface* surface, const SwImage* ima auto ey1 = span->y * itransform->e12 + itransform->e13; auto ey2 = span->y * itransform->e22 + itransform->e23; auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t x = span->x; x < span->len; ++x, ++dst) { + for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) { auto rX = static_cast(roundf(x * itransform->e11 + ey1)); auto rY = static_cast(roundf(x * itransform->e21 + ey2)); if (rX >= w || rY >= h) continue; @@ -616,7 +616,7 @@ static bool _rasterUpScaledRleRGBAImage(SwSurface* surface, const SwImage* image auto ey1 = span->y * itransform->e12 + itransform->e13; auto ey2 = span->y * itransform->e22 + itransform->e23; auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t x = span->x; x < span->len; ++x, ++dst) { + for (uint32_t x = span->x; x < ((uint32_t)span->x) + span->len; ++x, ++dst) { auto fX = x * itransform->e11 + ey1; auto fY = x * itransform->e21 + ey2; auto rX = static_cast(roundf(fX)); -- 2.7.4 From 4bf816ceb75f57897c430b498aeb9bb33d4919b1 Mon Sep 17 00:00:00 2001 From: jykeon Date: Thu, 25 Nov 2021 10:13:51 +0900 Subject: [PATCH 03/16] bump up version 0.6.2 Change-Id: I3f732e458c85133e3b5d17bd2ca19b5f5cf17254 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index fd48ceb..f44daf4 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.6.1 +Version: 0.6.2 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 3ce367a2784e9703f914bc579279bb88648dcd1a Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Nov 2021 11:47:26 +0900 Subject: [PATCH 04/16] sw_engine raster: fix compiler warnings. popped up unused-functions when simd enabled. --- src/lib/sw_engine/tvgSwRasterC.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRasterC.h b/src/lib/sw_engine/tvgSwRasterC.h index 9b46361..15f2d6d 100644 --- a/src/lib/sw_engine/tvgSwRasterC.h +++ b/src/lib/sw_engine/tvgSwRasterC.h @@ -21,14 +21,14 @@ */ -static void cRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +static void inline cRasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { dst += offset; while (len--) *dst++ = val; } -static bool cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) +static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint32_t color) { auto span = rle->spans; uint32_t src; @@ -47,7 +47,7 @@ static bool cRasterTranslucentRle(SwSurface* surface, const SwRleData* rle, uint } -static bool cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) +static bool inline cRasterTranslucentRect(SwSurface* surface, const SwBBox& region, uint32_t color) { auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); -- 2.7.4 From 0c2cf2212fe4f62c73d7f0f7ac9964ce331cf034 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Nov 2021 14:48:16 +0900 Subject: [PATCH 05/16] sw_engine raster: fix a regression bug. mistaken by 8ef31f6cd031b1369ec52e18cc0c97b6efaca6ab --- src/lib/sw_engine/tvgSwRaster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 5de990f..e75f260 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -2244,7 +2244,7 @@ static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* r } else { fillFetchRadial(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; - for (uint32_t i = 0; i < span->len; ++i) { + for (uint32_t i = 0; i < span->len; ++i, ++dst) { *dst = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(*dst, ialpha); } } -- 2.7.4 From 384db0d29eec5922cdae491a30c0a45e0f3b1d73 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Nov 2021 15:04:56 +0900 Subject: [PATCH 06/16] sw_engien renderer: ++safety +exceptional handling for the drawing region. --- src/lib/sw_engine/tvgSwRenderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 61c9156..70c7768 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -53,6 +53,8 @@ struct SwTask : Task region.y = bbox.min.y > 0 ? bbox.min.y : 0; region.w = bbox.max.x - region.x; region.h = bbox.max.y - region.y; + if (region.w < 0) region.w = 0; + if (region.h < 0) region.h = 0; return region; } -- 2.7.4 From c0823d62c90ecdda511e69cf5fd8f976be123b52 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 18 Nov 2021 11:03:29 +0900 Subject: [PATCH 07/16] sw_engine texmap: introduced texture mapping polygon drawing. Introduced the texture-mapping algorithm for the image-scaler. With this approach, we can support any arbitrary forms of the transformed shapes while appling the scale factors - x/y separately. Also this is more efficient when the transformed image is far from the rectangular form because our current normal image rasterizer based on the given drawing region whereas our new approach is span-based. Thus, we applied this mechanism only for the transformed images. --- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwRaster.cpp | 425 ++-------------------------------- src/lib/sw_engine/tvgSwRasterTexmap.h | 382 ++++++++++++++++++++++++++++++ 3 files changed, 400 insertions(+), 408 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwRasterTexmap.h diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index 0b1a6a7..f390d03 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -3,6 +3,7 @@ source_file = [ 'tvgSwRasterC.h', 'tvgSwRasterAvx.h', 'tvgSwRasterNeon.h', + 'tvgSwRasterTexmap.h', 'tvgSwFill.cpp', 'tvgSwImage.cpp', 'tvgSwMath.cpp', diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index e75f260..57adb7c 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -22,9 +22,6 @@ #include "tvgMath.h" #include "tvgRender.h" #include "tvgSwCommon.h" -#include "tvgSwRasterC.h" -#include "tvgSwRasterAvx.h" -#include "tvgSwRasterNeon.h" /************************************************************************/ /* Internal Class Implementation */ @@ -62,6 +59,18 @@ static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) } +static inline uint32_t _interpolate(uint32_t a, uint32_t c0, uint32_t c1) +{ + return (((((((c0 >> 8) & 0xff00ff) - ((c1 >> 8) & 0xff00ff)) * a) + (c1 & 0xff00ff00)) & 0xff00ff00) + ((((((c0 & 0xff00ff) - (c1 & 0xff00ff)) * a) >> 8) + (c1 & 0xff00ff)) & 0xff00ff)); +} + + +#include "tvgSwRasterTexmap.h" +#include "tvgSwRasterC.h" +#include "tvgSwRasterAvx.h" +#include "tvgSwRasterNeon.h" + + static inline bool _compositing(const SwSurface* surface) { if (!surface->compositor || surface->compositor->method == CompositeMethod::None) return false; @@ -76,7 +85,6 @@ static inline uint32_t _halfScale(float scale) return halfScale; } - //Bilinear Interpolation static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, float sx, float sy) { @@ -1054,414 +1062,16 @@ static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32 /* Transformed RGBA Image */ /************************************************************************/ -static bool _rasterTransformedMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Transformed Masked Image"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->compositor->image.stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp))); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->compositor->image.stride; - } - return true; -} - - -static bool _rasterTransformedMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Transformed Masked Image"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->compositor->image.stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], blendMethod(*cmp)); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->compositor->image.stride; - } - return true; -} - - -static bool _rasterTransformedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - - auto src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - } - return true; -} - - -static bool _rasterDownScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Down Scaled Masked Image"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->compositor->image.stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) { - src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp))); - } else { - src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), _multiplyAlpha(opacity, blendMethod(*cmp))); - } - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->compositor->image.stride; - } - return true; -} - - -static bool _rasterDownScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Down Scaled Masked Image"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->compositor->image.stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) { - src = ALPHA_BLEND(img[rX + (rY * image->stride)], blendMethod(*cmp)); - } else { - src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), blendMethod(*cmp)); - } - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->compositor->image.stride; - } - return true; -} - - -static bool _rasterDownScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rX + (rY * w)], opacity); - else src = ALPHA_BLEND(_interpDownScaler(img, w, h, rX, rY, halfScale), opacity); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - } - return true; -} - - -static bool _rasterUpScaledMaskedTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Up Scaled Masked Image"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->compositor->image.stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto fX = x * itransform->e11 + ey1; - auto fY = x * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], _multiplyAlpha(opacity, blendMethod(*cmp))); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), _multiplyAlpha(opacity, blendMethod(*cmp))); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->compositor->image.stride; - } - return true; -} - - -static bool _rasterUpScaledMaskedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Up Scaled Masked Image"); - - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - auto cbuffer = &surface->compositor->image.data[region.min.y * surface->compositor->image.stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto cmp = cbuffer; - float ey1 = y * itransform->e12 + itransform->e13; - float ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto fX = x * itransform->e11 + ey1; - auto fY = x * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], blendMethod(*cmp)); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), blendMethod(*cmp)); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - cbuffer += surface->compositor->image.stride; - } - return true; -} - - -static bool _rasterUpScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto dbuffer = &surface->buffer[region.min.y * surface->stride + region.min.x]; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = dbuffer; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto fX = x * itransform->e11 + ey1; - auto fY = x * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rX + (rY * image->stride)], opacity); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), opacity); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - dbuffer += surface->stride; - } - return true; -} - - -static bool _rasterTransformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = &surface->buffer[y * surface->stride + region.min.x]; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = img[rX + (rY * image->stride)]; - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - return true; -} - - -static bool _rasterDownScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = &surface->buffer[y * surface->stride + region.min.x]; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rX + (rY * w)]; - else src = _interpDownScaler(img, w, h, rX, rY, halfScale); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - return true; -} - - -static bool _rasterUpScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region) -{ - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (auto y = region.min.y; y < region.max.y; ++y) { - auto dst = &surface->buffer[y * surface->stride + region.min.x]; - auto ey1 = y * itransform->e12 + itransform->e13; - auto ey2 = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto fX = x * itransform->e11 + ey1; - auto fY = x * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = img[rX + (rY * w)]; - else src = _interpUpScaler(img, w, h, fX, fY); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - return true; -} - - static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity) { - Matrix itransform; - if (transform && !mathInverse(transform, &itransform)) return false; - - auto halfScale = _halfScale(image->scale); - if (_compositing(surface)) { - if (opacity == 255) { - //Transformd - if (mathEqual(image->scale, 1.0f)) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTransformedMaskedRGBAImage(surface, image, &itransform, region, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTransformedMaskedRGBAImage(surface, image, &itransform, region, surface->blender.ialpha); - } - //Transformed + DownScaled - } else if (image->scale < DOWN_SCALE_TOLERANCE) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterDownScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterDownScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.ialpha); - } - //Transformed + UpScaled - } else { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterUpScaledMaskedRGBAImage(surface, image, &itransform, region, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterUpScaledMaskedRGBAImage(surface, image, &itransform, region, surface->blender.ialpha); - } - } - } else { - //Transformd - if (mathEqual(image->scale, 1.0f)) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTransformedMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTransformedMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.ialpha); - } - //Transformed + DownScaled - } else if (image->scale < DOWN_SCALE_TOLERANCE) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterDownScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterDownScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.ialpha); - } - //Transformed + UpScaled - } else { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterUpScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterUpScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, surface->blender.ialpha); - } - } + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterTexmapPolygon(surface, image, transform, region, opacity, surface->blender.alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTexmapPolygon(surface, image, transform, region, opacity, surface->blender.ialpha); } } else { - if (opacity == 255) { - if (mathEqual(image->scale, 1.0f)) return _rasterTransformedRGBAImage(surface, image, &itransform, region); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledRGBAImage(surface, image, &itransform, region, halfScale); - else return _rasterUpScaledRGBAImage(surface, image, &itransform, region); - } else { - if (mathEqual(image->scale, 1.0f)) return _rasterTransformedTranslucentRGBAImage(surface, image, &itransform, region, opacity); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale); - else return _rasterUpScaledTranslucentRGBAImage(surface, image, &itransform, region, opacity); - } + return _rasterTexmapPolygon(surface, image, transform, region, opacity, nullptr); } return false; } @@ -1882,7 +1492,6 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t } else { if (image->direct) return _directRGBAImage(surface, image, region, opacity); else if (image->scaled) return _scaledRGBAImage(surface, image, transform, region, opacity); - //OPTIMIZE_ME: Replace with the TexMap Rasterizer else return _transformedRGBAImage(surface, image, transform, region, opacity); } } diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h new file mode 100644 index 0000000..3ba1e51 --- /dev/null +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +struct Vertex +{ + Point pt; + Point uv; +}; + +struct Polygon +{ + Vertex vertex[3]; +}; + +static inline void _swap(float& a, float& b, float& tmp) +{ + tmp = a; + a = b; + b = tmp; +} + +//Careful! Shared resource, No support threading +static float dudx, dvdx; +static float dxdya, dxdyb, dudya, dvdya; +static float xa, xb, ua, va; + +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) +{ +#define RASTER_COMMON() \ + uu = (int) u; \ + vv = (int) v; \ + /* FIXME: sometimes u and v are < 0 - don'tc crash */ \ + if (uu < 0) uu = 0;\ + if (vv < 0) vv = 0; \ + \ + /* Range exception handling */ \ + /* OPTIMIZE ME, handle in advance? */ \ + if (uu >= sw) uu = sw - 1; \ + if (vv >= sh) vv = sh - 1; \ + \ + ar = (int)(255 * (1 - modff(u, &iptr))); \ + ab = (int)(255 * (1 - modff(v, &iptr))); \ + iru = uu + 1; \ + irv = vv + 1; \ + px = *(sbuf + (vv * sw) + uu); \ + \ + /* horizontal interpolate */ \ + if (iru < sw) { \ + /* right pixel */ \ + int px2 = *(sbuf + (vv * sw) + iru); \ + px = _interpolate(ar, px, px2); \ + } \ + /* vertical interpolate */ \ + if (irv < sh) { \ + /* bottom pixel */ \ + int px2 = *(sbuf + (irv * sw) + uu); \ + \ + /* horizontal interpolate */ \ + if (iru < sw) { \ + /* bottom right pixel */ \ + int px3 = *(sbuf + (irv * sw) + iru);\ + px2 = _interpolate(ar, px2, px3); \ + } \ + px = _interpolate(ab, px, px2); \ + } + + float _dudx = dudx, _dvdx = dvdx; + float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; + float _xa = xa, _xb = xb, _ua = ua, _va = va; + auto sbuf = image->data; + auto dbuf = surface->buffer; + int sw = static_cast(image->stride); + int sh = image->h; + int dw = surface->stride; + int x1, x2, x, y, ar, ab, iru, irv, px; + int vv = 0; + int uu = 0; + float dx, u, v, iptr; + uint32_t* buf; + + //Range exception handling + if (ystart >= region.max.y) return; + if (ystart < region.min.y) ystart = region.min.y; + if (yend > region.max.y) yend = region.max.y; + + //Loop through all lines in the segment + y = ystart; + + while (y < yend) { + x1 = _xa; + x2 = _xb; + + //Range exception handling + if (x1 < region.min.x) x1 = region.min.x; + if (x2 > region.max.x) x2 = region.max.x; + + if ((x2 - x1) < 1) goto next; + if ((x1 >= region.max.x) || (x2 <= region.min.x)) goto next; + + //Perform subtexel pre-stepping on UV + dx = 1 - (_xa - x1); + u = _ua + dx * _dudx; + v = _va + dx * _dvdx; + + buf = dbuf + ((y * dw) + x1); + + x = x1; + + if (blendMethod) { + TVGLOG("SW_ENGINE", "Transformed Masked Image"); + auto cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1]; + if (opacity == 255) { + //Draw horizontal line + while (x++ < x2) { + RASTER_COMMON(); + auto src = ALPHA_BLEND(px, blendMethod(*cmp)); + *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); + ++cmp; + ++buf; + //Step UV horizontally + u += _dudx; + v += _dvdx; + } + } else { + //Draw horizontal line + while (x++ < x2) { + RASTER_COMMON(); + auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp))); + *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); + ++buf; + ++cmp; + //Step UV horizontally + u += _dudx; + v += _dvdx; + } + } + } else { + if (opacity == 255) { + //Draw horizontal line + while (x++ < x2) { + RASTER_COMMON(); + *buf = px + ALPHA_BLEND(*buf, surface->blender.ialpha(px)); + ++buf; + //Step UV horizontally + u += _dudx; + v += _dvdx; + } + } else { + //Draw horizontal line + while (x++ < x2) { + RASTER_COMMON(); + auto src = ALPHA_BLEND(px, opacity); + *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); + ++buf; + //Step UV horizontally + u += _dudx; + v += _dvdx; + } + } + } +next: + //Step along both edges + _xa += _dxdya; + _xb += _dxdyb; + _ua += _dudya; + _va += _dvdya; + + y++; + } + xa = _xa; + xb = _xb; + ua = _ua; + va = _va; +} + + +/* This mapping algorithm is based on Mikael Kalms's. */ +static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, Polygon& polygon, uint32_t (*blendMethod)(uint32_t)) +{ + float x[3] = {polygon.vertex[0].pt.x, polygon.vertex[1].pt.x, polygon.vertex[2].pt.x}; + float y[3] = {polygon.vertex[0].pt.y, polygon.vertex[1].pt.y, polygon.vertex[2].pt.y}; + float u[3] = {polygon.vertex[0].uv.x, polygon.vertex[1].uv.x, polygon.vertex[2].uv.x}; + float v[3] = {polygon.vertex[0].uv.y, polygon.vertex[1].uv.y, polygon.vertex[2].uv.y}; + + float off_y; + float dxdy[3] = {0.0f, 0.0f, 0.0f}; + float tmp; + + auto upper = false; + + //Sort the vertices in ascending Y order + if (y[0] > y[1]) { + _swap(x[0], x[1], tmp); + _swap(y[0], y[1], tmp); + _swap(u[0], u[1], tmp); + _swap(v[0], v[1], tmp); + } + if (y[0] > y[2]) { + _swap(x[0], x[2], tmp); + _swap(y[0], y[2], tmp); + _swap(u[0], u[2], tmp); + _swap(v[0], v[2], tmp); + } + if (y[1] > y[2]) { + _swap(x[1], x[2], tmp); + _swap(y[1], y[2], tmp); + _swap(u[1], u[2], tmp); + _swap(v[1], v[2], tmp); + } + + //Y indexes + int yi[3] = {(int)y[0], (int)y[1], (int)y[2]}; + + //Skip drawing if it's too thin to cover any pixels at all. + if ((yi[0] == yi[1] && yi[0] == yi[2]) || ((int) x[0] == (int) x[1] && (int) x[0] == (int) x[2])) return; + + //Calculate horizontal and vertical increments for UV axes (these calcs are certainly not optimal, although they're stable (handles any dy being 0) + auto denom = ((x[2] - x[0]) * (y[1] - y[0]) - (x[1] - x[0]) * (y[2] - y[0])); + + //Skip poly if it's an infinitely thin line + if (mathZero(denom)) return; + + denom = 1 / denom; //Reciprocal for speeding up + dudx = ((u[2] - u[0]) * (y[1] - y[0]) - (u[1] - u[0]) * (y[2] - y[0])) * denom; + dvdx = ((v[2] - v[0]) * (y[1] - y[0]) - (v[1] - v[0]) * (y[2] - y[0])) * denom; + auto dudy = ((u[1] - u[0]) * (x[2] - x[0]) - (u[2] - u[0]) * (x[1] - x[0])) * denom; + auto dvdy = ((v[1] - v[0]) * (x[2] - x[0]) - (v[2] - v[0]) * (x[1] - x[0])) * denom; + + //Calculate X-slopes along the edges + if (y[1] > y[0]) dxdy[0] = (x[1] - x[0]) / (y[1] - y[0]); + if (y[2] > y[0]) dxdy[1] = (x[2] - x[0]) / (y[2] - y[0]); + if (y[2] > y[1]) dxdy[2] = (x[2] - x[1]) / (y[2] - y[1]); + + //Determine which side of the polygon the longer edge is on + auto side = (dxdy[1] > dxdy[0]) ? true : false; + + if (mathEqual(y[0], y[1])) side = x[0] > x[1]; + if (mathEqual(y[1], y[2])) side = x[2] > x[1]; + + //Longer edge is on the left side + if (!side) { + //Calculate slopes along left edge + dxdya = dxdy[1]; + dudya = dxdya * dudx + dudy; + dvdya = dxdya * dvdx + dvdy; + + //Perform subpixel pre-stepping along left edge + auto dy = 1.0f - (y[0] - yi[0]); + xa = x[0] + dy * dxdya; + ua = u[0] + dy * dudya; + va = v[0] + dy * dvdya; + + //Draw upper segment if possibly visible + if (yi[0] < yi[1]) { + off_y = y[0] < region.min.y ? (region.min.y - y[0]) : 0; + xa += (off_y * dxdya); + ua += (off_y * dudya); + va += (off_y * dvdya); + + // Set right edge X-slope and perform subpixel pre-stepping + dxdyb = dxdy[0]; + xb = x[0] + dy * dxdyb + (off_y * dxdyb); + _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod); + upper = true; + } + //Draw lower segment if possibly visible + if (yi[1] < yi[2]) { + off_y = y[1] < region.min.y ? (region.min.y - y[1]) : 0; + if (!upper) { + xa += (off_y * dxdya); + ua += (off_y * dudya); + va += (off_y * dvdya); + } + // Set right edge X-slope and perform subpixel pre-stepping + dxdyb = dxdy[2]; + xb = x[1] + (1 - (y[1] - yi[1])) * dxdyb + (off_y * dxdyb); + _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod); + } + //Longer edge is on the right side + } else { + //Set right edge X-slope and perform subpixel pre-stepping + dxdyb = dxdy[1]; + auto dy = 1.0f - (y[0] - yi[0]); + xb = x[0] + dy * dxdyb; + + //Draw upper segment if possibly visible + if (yi[0] < yi[1]) { + off_y = y[0] < region.min.y ? (region.min.y - y[0]) : 0; + xb += (off_y *dxdyb); + + // Set slopes along left edge and perform subpixel pre-stepping + dxdya = dxdy[0]; + dudya = dxdya * dudx + dudy; + dvdya = dxdya * dvdx + dvdy; + + xa = x[0] + dy * dxdya + (off_y * dxdya); + ua = u[0] + dy * dudya + (off_y * dudya); + va = v[0] + dy * dvdya + (off_y * dvdya); + + _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod); + + upper = true; + } + //Draw lower segment if possibly visible + if (yi[1] < yi[2]) { + off_y = y[1] < region.min.y ? (region.min.y - y[1]) : 0; + if (!upper) xb += (off_y *dxdyb); + + // Set slopes along left edge and perform subpixel pre-stepping + dxdya = dxdy[2]; + dudya = dxdya * dudx + dudy; + dvdya = dxdya * dvdx + dvdy; + dy = 1 - (y[1] - yi[1]); + xa = x[1] + dy * dxdya + (off_y * dxdya); + ua = u[1] + dy * dudya + (off_y * dudya); + va = v[1] + dy * dvdya + (off_y * dvdya); + + _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod); + } + } +} + + +/* + 2 triangles constructs 1 mesh. + below figure illustrates vert[4] index info. + If you need better quality, please divide a mesh by more number of triangles. + + 0 -- 1 + | / | + | / | + 3 -- 2 +*/ +static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) +{ + /* Prepare vertices. + shift XY coordinates to match the sub-pixeling technique. */ + Vertex vertices[4]; + vertices[0] = {{0.0f, 0.0f}, 0.0f, 0.0f}; + vertices[1] = {{float(image->w), 0.0f}, float(image->w), 0.0f}; + vertices[2] = {{float(image->w), float(image->h)}, float(image->w), float(image->h)}; + vertices[3] = {{0.0f, float(image->h)}, 0.0f, float(image->h)}; + + for (int i = 0; i < 4; i++) mathMultiply(&vertices[i].pt, transform); + + Polygon polygon; + + //Draw the first polygon + polygon.vertex[0] = vertices[0]; + polygon.vertex[1] = vertices[1]; + polygon.vertex[2] = vertices[3]; + + _rasterPolygonImage(surface, image, region, opacity, polygon, blendMethod); + + //Draw the second polygon + polygon.vertex[0] = vertices[1]; + polygon.vertex[1] = vertices[2]; + polygon.vertex[2] = vertices[3]; + + _rasterPolygonImage(surface, image, region, opacity, polygon, blendMethod); + + return true; +} \ No newline at end of file -- 2.7.4 From 8288b50fba0ec065781841c7fb48e17cf1aac35b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Nov 2021 18:31:00 +0900 Subject: [PATCH 08/16] sw_engine texmap: code refactoring. Unrolled the blending stages by applying macro magics. I know this is a bit bad for code readibility but good for the performance and the optimal LOC. --- src/lib/sw_engine/tvgSwRasterTexmap.h | 219 +++++++++++++++++++--------------- 1 file changed, 123 insertions(+), 96 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h index 3ba1e51..3f9b777 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmap.h +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -43,46 +43,9 @@ static float dudx, dvdx; static float dxdya, dxdyb, dudya, dvdya; static float xa, xb, ua, va; -static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ -#define RASTER_COMMON() \ - uu = (int) u; \ - vv = (int) v; \ - /* FIXME: sometimes u and v are < 0 - don'tc crash */ \ - if (uu < 0) uu = 0;\ - if (vv < 0) vv = 0; \ - \ - /* Range exception handling */ \ - /* OPTIMIZE ME, handle in advance? */ \ - if (uu >= sw) uu = sw - 1; \ - if (vv >= sh) vv = sh - 1; \ - \ - ar = (int)(255 * (1 - modff(u, &iptr))); \ - ab = (int)(255 * (1 - modff(v, &iptr))); \ - iru = uu + 1; \ - irv = vv + 1; \ - px = *(sbuf + (vv * sw) + uu); \ - \ - /* horizontal interpolate */ \ - if (iru < sw) { \ - /* right pixel */ \ - int px2 = *(sbuf + (vv * sw) + iru); \ - px = _interpolate(ar, px, px2); \ - } \ - /* vertical interpolate */ \ - if (irv < sh) { \ - /* bottom pixel */ \ - int px2 = *(sbuf + (irv * sw) + uu); \ - \ - /* horizontal interpolate */ \ - if (iru < sw) { \ - /* bottom right pixel */ \ - int px3 = *(sbuf + (irv * sw) + iru);\ - px2 = _interpolate(ar, px2, px3); \ - } \ - px = _interpolate(ab, px, px2); \ - } +static inline void _rasterRGBA(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, TVG_UNUSED uint32_t opacity, TVG_UNUSED uint32_t (*blendMethod)(uint32_t)) +{ float _dudx = dudx, _dvdx = dvdx; float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; float _xa = xa, _xb = xb, _ua = ua, _va = va; @@ -125,57 +88,64 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, x = x1; - if (blendMethod) { - TVGLOG("SW_ENGINE", "Transformed Masked Image"); - auto cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1]; - if (opacity == 255) { - //Draw horizontal line - while (x++ < x2) { - RASTER_COMMON(); - auto src = ALPHA_BLEND(px, blendMethod(*cmp)); - *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); - ++cmp; - ++buf; - //Step UV horizontally - u += _dudx; - v += _dvdx; - } - } else { - //Draw horizontal line - while (x++ < x2) { - RASTER_COMMON(); - auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp))); - *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); - ++buf; - ++cmp; - //Step UV horizontally - u += _dudx; - v += _dvdx; - } +#ifdef TEXMAP_MAKSING + auto cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1]; +#endif + //Draw horizontal line + while (x++ < x2) { + uu = (int) u; + vv = (int) v; + /* FIXME: sometimes u and v are < 0 - don'tc crash */ + if (uu < 0) uu = 0; + if (vv < 0) vv = 0; + + /* Range exception handling */ + /* OPTIMIZE ME, handle in advance? */ + if (uu >= sw) uu = sw - 1; + if (vv >= sh) vv = sh - 1; + + ar = (int)(255 * (1 - modff(u, &iptr))); + ab = (int)(255 * (1 - modff(v, &iptr))); + iru = uu + 1; + irv = vv + 1; + px = *(sbuf + (vv * sw) + uu); + + /* horizontal interpolate */ + if (iru < sw) { + /* right pixel */ + int px2 = *(sbuf + (vv * sw) + iru); + px = _interpolate(ar, px, px2); } - } else { - if (opacity == 255) { - //Draw horizontal line - while (x++ < x2) { - RASTER_COMMON(); - *buf = px + ALPHA_BLEND(*buf, surface->blender.ialpha(px)); - ++buf; - //Step UV horizontally - u += _dudx; - v += _dvdx; - } - } else { - //Draw horizontal line - while (x++ < x2) { - RASTER_COMMON(); - auto src = ALPHA_BLEND(px, opacity); - *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); - ++buf; - //Step UV horizontally - u += _dudx; - v += _dvdx; + /* vertical interpolate */ + if (irv < sh) { + /* bottom pixel */ + int px2 = *(sbuf + (irv * sw) + uu); + + /* horizontal interpolate */ + if (iru < sw) { + /* bottom right pixel */ + int px3 = *(sbuf + (irv * sw) + iru); + px2 = _interpolate(ar, px2, px3); } + px = _interpolate(ab, px, px2); } +#if defined(TEXMAP_MAKSING) && defined(TEXTMAP_TRANSLUCENT) + auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp))); +#elif defined(TEXMAP_MAKSING) + auto src = ALPHA_BLEND(px, blendMethod(*cmp)); +#elif defined(TEXTMAP_TRANSLUCENT) + auto src = ALPHA_BLEND(px, opacity); +#else + auto src = px; +#endif + *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); + ++buf; +#ifdef TEXMAP_MAKSING + ++cmp; +#endif + //Step UV horizontally + u += _dudx; + v += _dvdx; } next: //Step along both edges @@ -185,11 +155,42 @@ next: _va += _dvdya; y++; - } - xa = _xa; - xb = _xb; - ua = _ua; - va = _va; + } + xa = _xa; + xb = _xb; + ua = _ua; + va = _va; +} + +static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) +{ +#define TEXTMAP_TRANSLUCENT +#define TEXMAP_MAKSING + _rasterRGBA(surface, image, region, ystart, yend, opacity, blendMethod); +#undef TEXMAP_MASKING +#undef TEXTMAP_TRANSLUCENT +} + + +static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t (*blendMethod)(uint32_t)) +{ +#define TEXMAP_MAKSING + _rasterRGBA(surface, image, region, ystart, yend, 255, nullptr); +#undef TEXMAP_MASKING +} + + +static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity) +{ +#define TEXTMAP_TRANSLUCENT + _rasterRGBA(surface, image, region, ystart, yend, opacity, nullptr); +#undef TEXTMAP_TRANSLUCENT +} + + +static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend) +{ + _rasterRGBA(surface, image, region, ystart, yend, 255, nullptr); } @@ -279,7 +280,15 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const // Set right edge X-slope and perform subpixel pre-stepping dxdyb = dxdy[0]; xb = x[0] + dy * dxdyb + (off_y * dxdyb); - _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod); + + if (blendMethod) { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], blendMethod); + else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod); + } else { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1]); + else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity); + } + upper = true; } //Draw lower segment if possibly visible @@ -293,7 +302,13 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const // Set right edge X-slope and perform subpixel pre-stepping dxdyb = dxdy[2]; xb = x[1] + (1 - (y[1] - yi[1])) * dxdyb + (off_y * dxdyb); - _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod); + if (blendMethod) { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], blendMethod); + else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod); + } else { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2]); + else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity); + } } //Longer edge is on the right side } else { @@ -316,7 +331,13 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const ua = u[0] + dy * dudya + (off_y * dudya); va = v[0] + dy * dvdya + (off_y * dvdya); - _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod); + if (blendMethod) { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], blendMethod); + else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity, blendMethod); + } else { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1]); + else _rasterPolygonImageSegment(surface, image, region, yi[0], yi[1], opacity); + } upper = true; } @@ -334,7 +355,13 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const ua = u[1] + dy * dudya + (off_y * dudya); va = v[1] + dy * dvdya + (off_y * dvdya); - _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod); + if (blendMethod) { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], blendMethod); + else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity, blendMethod); + } else { + if (opacity == 255) _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2]); + else _rasterPolygonImageSegment(surface, image, region, yi[1], yi[2], opacity); + } } } } -- 2.7.4 From 532e580f89726c1519590ea03d0c1e6ca0f79085 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 25 Nov 2021 17:25:25 +0900 Subject: [PATCH 09/16] sw_engine: code refactoring unified the two color interpolate methods. Change-Id: I7ff67af280fa78b11d3b083aec790ac043387b1a --- src/lib/sw_engine/tvgSwCommon.h | 6 ++---- src/lib/sw_engine/tvgSwFill.cpp | 2 +- src/lib/sw_engine/tvgSwRaster.cpp | 15 +++------------ src/lib/sw_engine/tvgSwRasterTexmap.h | 6 +++--- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index ce69e37..87577f9 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -274,11 +274,9 @@ static inline uint32_t ALPHA_BLEND(uint32_t c, uint32_t a) ((((c & 0x00ff00ff) * a + 0x00ff00ff) >> 8) & 0x00ff00ff)); } -static inline uint32_t COLOR_INTERPOLATE(uint32_t c1, uint32_t a1, uint32_t c2, uint32_t a2) +static inline uint32_t INTERPOLATE(uint32_t a, uint32_t c0, uint32_t c1) { - auto t = (((c1 & 0xff00ff) * a1 + (c2 & 0xff00ff) * a2) >> 8) & 0xff00ff; - c1 = (((c1 >> 8) & 0xff00ff) * a1 + ((c2 >> 8) & 0xff00ff) * a2) & 0xff00ff00; - return (c1 |= t); + return (((((((c0 >> 8) & 0xff00ff) - ((c1 >> 8) & 0xff00ff)) * a) + (c1 & 0xff00ff00)) & 0xff00ff00) + ((((((c0 & 0xff00ff) - (c1 & 0xff00ff)) * a) >> 8) + (c1 & 0xff00ff)) & 0xff00ff)); } static inline SwCoord HALF_STROKE(float width) diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 8afc2c0..0bf051c 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -79,7 +79,7 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* auto dist = static_cast(255 * t); auto dist2 = 255 - dist; - auto color = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); + auto color = INTERPOLATE(dist2, rgba, rgba2); fill->ctable[i] = ALPHA_BLEND((color | 0xff000000), (color >> 24)); ++i; diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 57adb7c..e531872 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -59,12 +59,6 @@ static inline uint32_t _argbJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) } -static inline uint32_t _interpolate(uint32_t a, uint32_t c0, uint32_t c1) -{ - return (((((((c0 >> 8) & 0xff00ff) - ((c1 >> 8) & 0xff00ff)) * a) + (c1 & 0xff00ff00)) & 0xff00ff00) + ((((((c0 & 0xff00ff) - (c1 & 0xff00ff)) * a) >> 8) + (c1 & 0xff00ff)) & 0xff00ff)); -} - - #include "tvgSwRasterTexmap.h" #include "tvgSwRasterC.h" #include "tvgSwRasterAvx.h" @@ -99,7 +93,7 @@ static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, flo auto c3 = img[(rx + 1) + ((ry + 1) * w)]; auto c4 = img[rx + ((ry + 1) * w)]; - return COLOR_INTERPOLATE(COLOR_INTERPOLATE(c1, 255 - dx, c2, dx), 255 - dy, COLOR_INTERPOLATE(c4, 255 - dx, c3, dx), dy); + return INTERPOLATE(dy, INTERPOLATE(dx, c3, c4), INTERPOLATE(dx, c2, c1)); } @@ -1659,10 +1653,9 @@ static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* r fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len); } else { fillFetchLinear(fill, buf, span->y, span->x, span->len); - auto ialpha = 255 - span->coverage; auto dst = &surface->buffer[span->y * surface->stride + span->x]; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); + dst[i] = INTERPOLATE(span->coverage, buf[i], dst[i]); } } } @@ -1799,10 +1792,8 @@ static bool _rasterRadialGradientMaskedRle(SwSurface* surface, const SwRleData* *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); } } else { - auto ialpha = 255 - span->coverage; for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, blendMethod(*cmp)); - tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); + auto tmp = INTERPOLATE(span->coverage, ALPHA_BLEND(*src, blendMethod(*cmp)), *dst); *dst = tmp + ALPHA_BLEND(*dst, surface->blender.ialpha(tmp)); } } diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h index 3f9b777..c4ee7ce 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmap.h +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -114,7 +114,7 @@ static inline void _rasterRGBA(SwSurface* surface, const SwImage* image, const S if (iru < sw) { /* right pixel */ int px2 = *(sbuf + (vv * sw) + iru); - px = _interpolate(ar, px, px2); + px = INTERPOLATE(ar, px, px2); } /* vertical interpolate */ if (irv < sh) { @@ -125,9 +125,9 @@ static inline void _rasterRGBA(SwSurface* surface, const SwImage* image, const S if (iru < sw) { /* bottom right pixel */ int px3 = *(sbuf + (irv * sw) + iru); - px2 = _interpolate(ar, px2, px3); + px2 = INTERPOLATE(ar, px2, px3); } - px = _interpolate(ab, px, px2); + px = INTERPOLATE(ab, px, px2); } #if defined(TEXMAP_MAKSING) && defined(TEXTMAP_TRANSLUCENT) auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp))); -- 2.7.4 From 23cf215a6eca9049e0806a04e6d94ee27169f723 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 26 Nov 2021 17:14:44 +0900 Subject: [PATCH 11/16] sw_engine raster: fix the texmap regression bug. Wrong inline function with C-preprocessing doesn't work at all... Correct them with including the separate files instead. --- src/lib/sw_engine/meson.build | 1 + src/lib/sw_engine/tvgSwRasterTexmap.h | 146 +++----------------------- src/lib/sw_engine/tvgSwRasterTexmapInternal.h | 140 ++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 132 deletions(-) create mode 100644 src/lib/sw_engine/tvgSwRasterTexmapInternal.h diff --git a/src/lib/sw_engine/meson.build b/src/lib/sw_engine/meson.build index f390d03..8d41bee 100644 --- a/src/lib/sw_engine/meson.build +++ b/src/lib/sw_engine/meson.build @@ -4,6 +4,7 @@ source_file = [ 'tvgSwRasterAvx.h', 'tvgSwRasterNeon.h', 'tvgSwRasterTexmap.h', + 'tvgSwRasterTexmapInternal.h', 'tvgSwFill.cpp', 'tvgSwImage.cpp', 'tvgSwMath.cpp', diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h index c4ee7ce..ca4e303 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmap.h +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -44,153 +44,35 @@ static float dxdya, dxdyb, dudya, dvdya; static float xa, xb, ua, va; -static inline void _rasterRGBA(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, TVG_UNUSED uint32_t opacity, TVG_UNUSED uint32_t (*blendMethod)(uint32_t)) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) { - float _dudx = dudx, _dvdx = dvdx; - float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; - float _xa = xa, _xb = xb, _ua = ua, _va = va; - auto sbuf = image->data; - auto dbuf = surface->buffer; - int sw = static_cast(image->stride); - int sh = image->h; - int dw = surface->stride; - int x1, x2, x, y, ar, ab, iru, irv, px; - int vv = 0; - int uu = 0; - float dx, u, v, iptr; - uint32_t* buf; - - //Range exception handling - if (ystart >= region.max.y) return; - if (ystart < region.min.y) ystart = region.min.y; - if (yend > region.max.y) yend = region.max.y; - - //Loop through all lines in the segment - y = ystart; - - while (y < yend) { - x1 = _xa; - x2 = _xb; - - //Range exception handling - if (x1 < region.min.x) x1 = region.min.x; - if (x2 > region.max.x) x2 = region.max.x; - - if ((x2 - x1) < 1) goto next; - if ((x1 >= region.max.x) || (x2 <= region.min.x)) goto next; - - //Perform subtexel pre-stepping on UV - dx = 1 - (_xa - x1); - u = _ua + dx * _dudx; - v = _va + dx * _dvdx; - - buf = dbuf + ((y * dw) + x1); - - x = x1; - -#ifdef TEXMAP_MAKSING - auto cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1]; -#endif - //Draw horizontal line - while (x++ < x2) { - uu = (int) u; - vv = (int) v; - /* FIXME: sometimes u and v are < 0 - don'tc crash */ - if (uu < 0) uu = 0; - if (vv < 0) vv = 0; - - /* Range exception handling */ - /* OPTIMIZE ME, handle in advance? */ - if (uu >= sw) uu = sw - 1; - if (vv >= sh) vv = sh - 1; - - ar = (int)(255 * (1 - modff(u, &iptr))); - ab = (int)(255 * (1 - modff(v, &iptr))); - iru = uu + 1; - irv = vv + 1; - px = *(sbuf + (vv * sw) + uu); - - /* horizontal interpolate */ - if (iru < sw) { - /* right pixel */ - int px2 = *(sbuf + (vv * sw) + iru); - px = INTERPOLATE(ar, px, px2); - } - /* vertical interpolate */ - if (irv < sh) { - /* bottom pixel */ - int px2 = *(sbuf + (irv * sw) + uu); - - /* horizontal interpolate */ - if (iru < sw) { - /* bottom right pixel */ - int px3 = *(sbuf + (irv * sw) + iru); - px2 = INTERPOLATE(ar, px2, px3); - } - px = INTERPOLATE(ab, px, px2); - } -#if defined(TEXMAP_MAKSING) && defined(TEXTMAP_TRANSLUCENT) - auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp))); -#elif defined(TEXMAP_MAKSING) - auto src = ALPHA_BLEND(px, blendMethod(*cmp)); -#elif defined(TEXTMAP_TRANSLUCENT) - auto src = ALPHA_BLEND(px, opacity); -#else - auto src = px; -#endif - *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); - ++buf; -#ifdef TEXMAP_MAKSING - ++cmp; -#endif - //Step UV horizontally - u += _dudx; - v += _dvdx; - } -next: - //Step along both edges - _xa += _dxdya; - _xb += _dxdyb; - _ua += _dudya; - _va += _dvdya; - - y++; - } - xa = _xa; - xb = _xb; - ua = _ua; - va = _va; -} - -static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ -#define TEXTMAP_TRANSLUCENT -#define TEXMAP_MAKSING - _rasterRGBA(surface, image, region, ystart, yend, opacity, blendMethod); +#define TEXMAP_TRANSLUCENT +#define TEXMAP_MASKING + #include "tvgSwRasterTexmapInternal.h" #undef TEXMAP_MASKING -#undef TEXTMAP_TRANSLUCENT +#undef TEXMAP_TRANSLUCENT } -static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t (*blendMethod)(uint32_t)) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t (*blendMethod)(uint32_t)) { -#define TEXMAP_MAKSING - _rasterRGBA(surface, image, region, ystart, yend, 255, nullptr); +#define TEXMAP_MASKING + #include "tvgSwRasterTexmapInternal.h" #undef TEXMAP_MASKING } -static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity) { -#define TEXTMAP_TRANSLUCENT - _rasterRGBA(surface, image, region, ystart, yend, opacity, nullptr); -#undef TEXTMAP_TRANSLUCENT +#define TEXMAP_TRANSLUCENT + #include "tvgSwRasterTexmapInternal.h" +#undef TEXMAP_TRANSLUCENT } -static inline void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend) { - _rasterRGBA(surface, image, region, ystart, yend, 255, nullptr); + #include "tvgSwRasterTexmapInternal.h" } diff --git a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h new file mode 100644 index 0000000..d7084bc --- /dev/null +++ b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +{ + float _dudx = dudx, _dvdx = dvdx; + float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; + float _xa = xa, _xb = xb, _ua = ua, _va = va; + auto sbuf = image->data; + auto dbuf = surface->buffer; + int sw = static_cast(image->stride); + int sh = image->h; + int dw = surface->stride; + int x1, x2, x, y, ar, ab, iru, irv, px; + int vv = 0; + int uu = 0; + float dx, u, v, iptr; + uint32_t* buf; +#ifdef TEXMAP_MASKING + uint32_t* cmp; +#endif + + //Range exception handling + if (ystart >= region.max.y) return; + if (ystart < region.min.y) ystart = region.min.y; + if (yend > region.max.y) yend = region.max.y; + + //Loop through all lines in the segment + y = ystart; + + while (y < yend) { + x1 = _xa; + x2 = _xb; + + //Range exception handling + if (x1 < region.min.x) x1 = region.min.x; + if (x2 > region.max.x) x2 = region.max.x; + + if ((x2 - x1) < 1) goto next; + if ((x1 >= region.max.x) || (x2 <= region.min.x)) goto next; + + //Perform subtexel pre-stepping on UV + dx = 1 - (_xa - x1); + u = _ua + dx * _dudx; + v = _va + dx * _dvdx; + + buf = dbuf + ((y * dw) + x1); + + x = x1; + +#ifdef TEXMAP_MASKING + cmp = &surface->compositor->image.data[y * surface->compositor->image.stride + x1]; +#endif + //Draw horizontal line + while (x++ < x2) { + uu = (int) u; + vv = (int) v; + /* FIXME: sometimes u and v are < 0 - don'tc crash */ + if (uu < 0) uu = 0; + if (vv < 0) vv = 0; + + /* Range exception handling */ + /* OPTIMIZE ME, handle in advance? */ + if (uu >= sw) uu = sw - 1; + if (vv >= sh) vv = sh - 1; + + ar = (int)(255 * (1 - modff(u, &iptr))); + ab = (int)(255 * (1 - modff(v, &iptr))); + iru = uu + 1; + irv = vv + 1; + px = *(sbuf + (vv * sw) + uu); + + /* horizontal interpolate */ + if (iru < sw) { + /* right pixel */ + int px2 = *(sbuf + (vv * sw) + iru); + px = INTERPOLATE(ar, px, px2); + } + /* vertical interpolate */ + if (irv < sh) { + /* bottom pixel */ + int px2 = *(sbuf + (irv * sw) + uu); + + /* horizontal interpolate */ + if (iru < sw) { + /* bottom right pixel */ + int px3 = *(sbuf + (irv * sw) + iru); + px2 = INTERPOLATE(ar, px2, px3); + } + px = INTERPOLATE(ab, px, px2); + } +#if defined(TEXMAP_MASKING) && defined(TEXMAP_TRANSLUCENT) + auto src = ALPHA_BLEND(px, _multiplyAlpha(opacity, blendMethod(*cmp))); +#elif defined(TEXMAP_MASKING) + auto src = ALPHA_BLEND(px, blendMethod(*cmp)); +#elif defined(TEXMAP_TRANSLUCENT) + auto src = ALPHA_BLEND(px, opacity); +#else + auto src = px; +#endif + *buf = src + ALPHA_BLEND(*buf, surface->blender.ialpha(src)); + ++buf; +#ifdef TEXMAP_MASKING + ++cmp; +#endif + //Step UV horizontally + u += _dudx; + v += _dvdx; + } +next: + //Step along both edges + _xa += _dxdya; + _xb += _dxdyb; + _ua += _dudya; + _va += _dvdya; + + y++; + } + xa = _xa; + xb = _xb; + ua = _ua; + va = _va; +} \ No newline at end of file -- 2.7.4 From 307ef60c7961481d111d152dadc060198ad00c43 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 24 Nov 2021 21:57:40 +0100 Subject: [PATCH 12/16] svg_loader: struct used to pass 1 args instead of 4 of them The Box struct is introduced to replace the four functions args: vx, vy, vw, vh, so all of them can be passed at once. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 116 ++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 6737053..c37bcb0 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -56,13 +56,20 @@ #include "tvgSvgPath.h" #include "tvgSvgUtil.h" -static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh, const string& svgPath); -static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath, bool mask); - /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +struct Box +{ + float x, y, w, h; +}; + + +static bool _appendShape(SvgNode* node, Shape* shape, const Box& vBox, const string& svgPath); +static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask); + + static inline bool _isGroupType(SvgNodeType type) { if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::Use || type == SvgNodeType::ClipPath) return true; @@ -82,7 +89,7 @@ static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf) } -static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh, int opacity) +static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity) { Fill::ColorStop* stops; int stopCount = 0; @@ -93,12 +100,12 @@ static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* if (isTransform) finalTransform = *g->transform; if (g->userSpace) { - g->linear->x1 = g->linear->x1 * rw; - g->linear->y1 = g->linear->y1 * rh; - g->linear->x2 = g->linear->x2 * rw; - g->linear->y2 = g->linear->y2 * rh; + g->linear->x1 = g->linear->x1 * vBox.w; + g->linear->y1 = g->linear->y1 * vBox.h; + g->linear->x2 = g->linear->x2 * vBox.w; + g->linear->y2 = g->linear->y2 * vBox.h; } else { - Matrix m = {rw, 0, rx, 0, rh, ry, 0, 0, 1}; + Matrix m = {vBox.w, 0, vBox.x, 0, vBox.h, vBox.y, 0, 0, 1}; if (isTransform) _transformMultiply(&m, &finalTransform); else { finalTransform = m; @@ -137,7 +144,7 @@ static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* } -static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh, int opacity) +static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity) { Fill::ColorStop *stops; int stopCount = 0; @@ -150,13 +157,13 @@ static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* if (g->userSpace) { //The radius scalling is done according to the Units section: //https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html - g->radial->cx = g->radial->cx * rw; - g->radial->cy = g->radial->cy * rh; - g->radial->r = g->radial->r * sqrtf(powf(rw, 2.0f) + powf(rh, 2.0f)) / sqrtf(2.0f); - g->radial->fx = g->radial->fx * rw; - g->radial->fy = g->radial->fy * rh; + g->radial->cx = g->radial->cx * vBox.w; + g->radial->cy = g->radial->cy * vBox.h; + g->radial->r = g->radial->r * sqrtf(powf(vBox.w, 2.0f) + powf(vBox.h, 2.0f)) / sqrtf(2.0f); + g->radial->fx = g->radial->fx * vBox.w; + g->radial->fy = g->radial->fy * vBox.h; } else { - Matrix m = {rw, 0, rx, 0, rh, ry, 0, 0, 1}; + Matrix m = {vBox.w, 0, vBox.x, 0, vBox.h, vBox.y, 0, 0, 1}; if (isTransform) _transformMultiply(&m, &finalTransform); else { finalTransform = m; @@ -199,16 +206,16 @@ static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* } -static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh, const string& svgPath) +static bool _appendChildShape(SvgNode* node, Shape* shape, const Box& vBox, const string& svgPath) { auto valid = false; - if (_appendShape(node, shape, vx, vy, vw, vh, svgPath)) valid = true; + if (_appendShape(node, shape, vBox, svgPath)) valid = true; if (node->child.count > 0) { auto child = node->child.data; for (uint32_t i = 0; i < node->child.count; ++i, ++child) { - if (_appendChildShape(*child, shape, vx, vy, vw, vh, svgPath)) valid = true; + if (_appendChildShape(*child, shape, vBox, svgPath)) valid = true; } } @@ -216,7 +223,7 @@ static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, f } -static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath) +static void _applyComposition(Paint* paint, const SvgNode* node, const Box& vBox, const string& svgPath) { /* ClipPath */ /* Do not drop in Circular Dependency for ClipPath. @@ -236,7 +243,7 @@ static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float auto valid = false; //Composite only when valid shapes are existed for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { - if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh, svgPath)) valid = true; + if (_appendChildShape(*child, comp.get(), vBox, svgPath)) valid = true; } if (valid) paint->composite(move(comp), CompositeMethod::ClipPath); @@ -255,7 +262,7 @@ static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float if (compNode && compNode->child.count > 0) { node->style->mask.applying = true; - auto comp = _sceneBuildHelper(compNode, vx, vy, vw, vh, svgPath, true); + auto comp = _sceneBuildHelper(compNode, vBox, svgPath, true); if (comp) { if (node->transform) comp->transform(*node->transform); paint->composite(move(comp), CompositeMethod::AlphaMask); @@ -267,7 +274,7 @@ static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float } -static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh, const string& svgPath) +static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const string& svgPath) { SvgStyleProperty* style = node->style; @@ -278,23 +285,24 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v if (style->fill.paint.none) { //Do nothing } else if (style->fill.paint.gradient) { + Box bBox = vBox; if (!style->fill.paint.gradient->userSpace) { - vg->bounds(&vx, &vy, &vw, &vh, false); + vg->bounds(&bBox.x, &bBox.y, &bBox.w, &bBox.h, false); //According to: https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits (the last paragraph) //a stroke width should be ignored for bounding box calculations if (auto strokeW = vg->strokeWidth()) { - vx += 0.5f * strokeW; - vy += 0.5f * strokeW; - vw -= strokeW; - vh -= strokeW; + bBox.x += 0.5f * strokeW; + bBox.y += 0.5f * strokeW; + bBox.w -= strokeW; + bBox.h -= strokeW; } } if (style->fill.paint.gradient->type == SvgGradientType::Linear) { - auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, vx, vy, vw, vh, style->fill.opacity); + auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity); vg->fill(move(linear)); } else if (style->fill.paint.gradient->type == SvgGradientType::Radial) { - auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg, vx, vy, vw, vh, style->fill.opacity); + auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity); vg->fill(move(radial)); } } else if (style->fill.paint.url) { @@ -327,23 +335,24 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v if (style->stroke.paint.none) { //Do nothing } else if (style->stroke.paint.gradient) { + Box bBox = vBox; if (!style->stroke.paint.gradient->userSpace) { //According to: https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits (the last paragraph) //a stroke width should be ignored for bounding box calculations - vg->bounds(&vx, &vy, &vw, &vh, false); + vg->bounds(&bBox.x, &bBox.y, &bBox.w, &bBox.h, false); if (auto strokeW = vg->strokeWidth()) { - vx += 0.5f * strokeW; - vy += 0.5f * strokeW; - vw -= strokeW; - vh -= strokeW; + bBox.x += 0.5f * strokeW; + bBox.y += 0.5f * strokeW; + bBox.w -= strokeW; + bBox.h -= strokeW; } } if (style->stroke.paint.gradient->type == SvgGradientType::Linear) { - auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, vg, vx, vy, vw, vh, style->stroke.opacity); + auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity); vg->stroke(move(linear)); } else if (style->stroke.paint.gradient->type == SvgGradientType::Radial) { - auto radial = _applyRadialGradientProperty(style->stroke.paint.gradient, vg, vx, vy, vw, vh, style->stroke.opacity); + auto radial = _applyRadialGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity); vg->stroke(move(radial)); } } else if (style->stroke.paint.url) { @@ -356,19 +365,19 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v vg->stroke(style->stroke.paint.color.r, style->stroke.paint.color.g, style->stroke.paint.color.b, style->stroke.opacity); } - _applyComposition(vg, node, vx, vy, vw, vh, svgPath); + _applyComposition(vg, node, vBox, svgPath); } -static unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath) +static unique_ptr _shapeBuildHelper(SvgNode* node, const Box& vBox, const string& svgPath) { auto shape = Shape::gen(); - if (_appendShape(node, shape.get(), vx, vy, vw, vh, svgPath)) return shape; + if (_appendShape(node, shape.get(), vBox, svgPath)) return shape; else return nullptr; } -static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh, const string& svgPath) +static bool _appendShape(SvgNode* node, Shape* shape, const Box& vBox, const string& svgPath) { Array cmds; Array pts; @@ -421,7 +430,7 @@ static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float } } - _applyProperty(node, shape, vx, vy, vw, vh, svgPath); + _applyProperty(node, shape, vBox, svgPath); return true; } @@ -496,7 +505,7 @@ static bool _isValidImageMimeTypeAndEncoding(const char** href, const char** mim } -static unique_ptr _imageBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath) +static unique_ptr _imageBuildHelper(SvgNode* node, const Box& vBox, const string& svgPath) { if (!node->node.image.href) return nullptr; auto picture = Picture::gen(); @@ -539,14 +548,14 @@ static unique_ptr _imageBuildHelper(SvgNode* node, float vx, float vy, picture->transform(m); } - _applyComposition(picture.get(), node, vx, vy, vw, vh, svgPath); + _applyComposition(picture.get(), node, vBox, svgPath); return picture; } -static unique_ptr _useBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath) +static unique_ptr _useBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath) { - auto scene = _sceneBuildHelper(node, vx, vy, vw, vh, svgPath, false); + auto scene = _sceneBuildHelper(node, vBox, svgPath, false); if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) { scene->translate(node->node.use.x, node->node.use.y); } @@ -557,7 +566,7 @@ static unique_ptr _useBuildHelper(const SvgNode* node, float vx, float vy } -static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh, const string& svgPath, bool mask) +static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, const string& svgPath, bool mask) { if (_isGroupType(node->type) || mask) { auto scene = Scene::gen(); @@ -568,18 +577,18 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float for (uint32_t i = 0; i < node->child.count; ++i, ++child) { if (_isGroupType((*child)->type)) { if ((*child)->type == SvgNodeType::Use) - scene->push(_useBuildHelper(*child, vx, vy, vw, vh, svgPath)); + scene->push(_useBuildHelper(*child, vBox, svgPath)); else - scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, svgPath, false)); + scene->push(_sceneBuildHelper(*child, vBox, svgPath, false)); } else if ((*child)->type == SvgNodeType::Image) { - auto image = _imageBuildHelper(*child, vx, vy, vw, vh, svgPath); + auto image = _imageBuildHelper(*child, vBox, svgPath); if (image) scene->push(move(image)); } else if ((*child)->type != SvgNodeType::Mask) { - auto shape = _shapeBuildHelper(*child, vx, vy, vw, vh, svgPath); + auto shape = _shapeBuildHelper(*child, vBox, svgPath); if (shape) scene->push(move(shape)); } } - _applyComposition(scene.get(), node, vx, vy, vw, vh, svgPath); + _applyComposition(scene.get(), node, vBox, svgPath); scene->opacity(node->style->opacity); } return scene; @@ -596,7 +605,8 @@ unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, flo { if (!node || (node->type != SvgNodeType::Doc)) return nullptr; - auto docNode = _sceneBuildHelper(node, vx, vy, vw, vh, svgPath, false); + Box vBox = {vx, vy, vw, vh}; + auto docNode = _sceneBuildHelper(node, vBox, svgPath, false); if (!mathEqual(w, vw) || !mathEqual(h, vh)) { auto sx = w / vw; -- 2.7.4 From 186039d862c7badcd8b29e93e3e3109b97a90fc7 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 24 Nov 2021 23:07:35 +0100 Subject: [PATCH 13/16] svg_loader: a function to establish shapes boundries without a stroke introduced To handle the objectBoundingBox units, the shape's boundaries have to be known. According to the SVG standard, a stroke shouldn't be taken into account. Since the bounds() api uses the shape's stroke information, a new function is introduced, that compensates this and returns boundaries without any strokes. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 42 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index c37bcb0..8701fe3 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -77,6 +77,24 @@ static inline bool _isGroupType(SvgNodeType type) } +//According to: https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits (the last paragraph) +//a stroke width should be ignored for bounding box calculations +static Box _boundingBox(const Shape* shape) +{ + float x, y, w, h; + shape->bounds(&x, &y, &w, &h, false); + + if (auto strokeW = shape->strokeWidth()) { + x += 0.5f * strokeW; + y += 0.5f * strokeW; + w -= strokeW; + h -= strokeW; + } + + return {x, y, w, h}; +} + + static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf) { gradTransf->e13 = gradTransf->e13 * mBBox->e11 + mBBox->e13; @@ -286,17 +304,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const stri //Do nothing } else if (style->fill.paint.gradient) { Box bBox = vBox; - if (!style->fill.paint.gradient->userSpace) { - vg->bounds(&bBox.x, &bBox.y, &bBox.w, &bBox.h, false); - //According to: https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits (the last paragraph) - //a stroke width should be ignored for bounding box calculations - if (auto strokeW = vg->strokeWidth()) { - bBox.x += 0.5f * strokeW; - bBox.y += 0.5f * strokeW; - bBox.w -= strokeW; - bBox.h -= strokeW; - } - } + if (!style->fill.paint.gradient->userSpace) bBox = _boundingBox(vg); if (style->fill.paint.gradient->type == SvgGradientType::Linear) { auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity); @@ -336,17 +344,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, const Box& vBox, const stri //Do nothing } else if (style->stroke.paint.gradient) { Box bBox = vBox; - if (!style->stroke.paint.gradient->userSpace) { - //According to: https://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBoxUnits (the last paragraph) - //a stroke width should be ignored for bounding box calculations - vg->bounds(&bBox.x, &bBox.y, &bBox.w, &bBox.h, false); - if (auto strokeW = vg->strokeWidth()) { - bBox.x += 0.5f * strokeW; - bBox.y += 0.5f * strokeW; - bBox.w -= strokeW; - bBox.h -= strokeW; - } - } + if (!style->stroke.paint.gradient->userSpace) bBox = _boundingBox(vg); if (style->stroke.paint.gradient->type == SvgGradientType::Linear) { auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity); -- 2.7.4 From ea55ea8a5fafb075b41a750867c42bf15eb4a420 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 26 Nov 2021 20:05:48 +0900 Subject: [PATCH 14/16] sw_engine texmap: remove unnecessary conditions. remove exceptional handling for the performance. --- src/lib/sw_engine/tvgSwRasterTexmapInternal.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h index d7084bc..c30186b 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h +++ b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h @@ -72,14 +72,6 @@ while (x++ < x2) { uu = (int) u; vv = (int) v; - /* FIXME: sometimes u and v are < 0 - don'tc crash */ - if (uu < 0) uu = 0; - if (vv < 0) vv = 0; - - /* Range exception handling */ - /* OPTIMIZE ME, handle in advance? */ - if (uu >= sw) uu = sw - 1; - if (vv >= sh) vv = sh - 1; ar = (int)(255 * (1 - modff(u, &iptr))); ab = (int)(255 * (1 - modff(v, &iptr))); -- 2.7.4 From d86ce695a96b71d5e5194d01eb4cd6a40a2996ce Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 29 Nov 2021 11:38:29 +0900 Subject: [PATCH 15/16] sw_engine raster: fix the regression bug of the image simple scaling rendering. Gave up the optimization this logic. It brings too many digressed code, not good for maintenance... Change-Id: I6adafcba58e58b0f6d389159a92b7dfd2ea68444 --- src/lib/sw_engine/tvgSwRaster.cpp | 192 +++++++++----------------------------- 1 file changed, 46 insertions(+), 146 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index e531872..6067a07 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -84,14 +84,18 @@ static uint32_t _interpUpScaler(const uint32_t *img, uint32_t w, uint32_t h, flo { auto rx = static_cast(sx); auto ry = static_cast(sy); + auto rx2 = rx + 1; + if (rx2 >= w) rx2 = w - 1; + auto ry2 = ry + 1; + if (ry2 >= h) ry2 = h - 1; auto dx = static_cast((sx - rx) * 255.0f); auto dy = static_cast((sy - ry) * 255.0f); - auto c1 = img[rx + (ry * w)]; - auto c2 = img[(rx + 1) + (ry * w)]; - auto c3 = img[(rx + 1) + ((ry + 1) * w)]; - auto c4 = img[rx + ((ry + 1) * w)]; + auto c1 = img[rx + ry * w]; + auto c2 = img[rx2 + ry * w]; + auto c3 = img[rx2 + ry2 * w]; + auto c4 = img[rx + ry2 * w]; return INTERPOLATE(dy, INTERPOLATE(dx, c3, c4), INTERPOLATE(dx, c2, c1)); } @@ -1080,43 +1084,16 @@ static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const Sw { TVGLOG("SW_ENGINE", "Scaled Masked Image"); - //Top, Bottom Lines - SwCoord ys[2] = {region.min.y, region.max.y - 1}; - - for (auto i = 0; i < 2; ++i) { - auto y = ys[i]; - auto dst = surface->buffer + (y * surface->stride + region.min.x); - auto cmp = surface->compositor->image.data + (y * surface->compositor->image.stride + region.min.x); - auto img = image->data + static_cast(y * itransform->e22 + itransform->e23) * image->stride; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp)); - auto src = ALPHA_BLEND(img[static_cast(x * itransform->e11 + itransform->e13)], alpha); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Left, Right Lines - SwCoord xs[2] = {region.min.x, region.max.x - 1}; + auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x); - for (auto i = 0; i < 2; ++i) { - auto x = xs[i]; - auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x); - auto cmp = surface->compositor->image.data + ((region.min.y + 1) * surface->compositor->image.stride + x); - auto img = image->data + static_cast(x * itransform->e11 + itransform->e13); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride, cmp += surface->stride) { - auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp)); - auto src = ALPHA_BLEND(img[static_cast(y * itransform->e22 + itransform->e23) * image->stride], alpha); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Center (Down-Scaled) + // Down-Scaled if (image->scale < DOWN_SCALE_TOLERANCE) { - auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1)); - auto cbuffer = surface->compositor->image.data + ((region.min.y + 1) * surface->compositor->image.stride + (region.min.x + 1)); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y) { + for (auto y = region.min.y; y < region.max.y; ++y) { auto dst = dbuffer; auto cmp = cbuffer; auto sy = static_cast(y * itransform->e22 + itransform->e23); - for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst, ++cmp) { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp)); auto sx = static_cast(x * itransform->e11 + itransform->e13); auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), alpha); @@ -1125,17 +1102,15 @@ static bool _rasterScaledMaskedTranslucentRGBAImage(SwSurface* surface, const Sw dbuffer += surface->stride; cbuffer += surface->compositor->image.stride; } - //Center (Up-Scaled) + // Up-Scaled } else { - auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); - auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x); - for (auto y = region.min.y; y < region.max.y - 1; ++y) { + for (auto y = region.min.y; y < region.max.y; ++y) { auto dst = dbuffer; auto cmp = cbuffer; - auto sy = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst, ++cmp) { + auto sy = fabsf(y * itransform->e22 + itransform->e23); + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { auto alpha = _multiplyAlpha(opacity, blendMethod(*cmp)); - auto sx = x * itransform->e11 + itransform->e13; + auto sx = fabsf(x * itransform->e11 + itransform->e13); auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), alpha); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } @@ -1151,41 +1126,16 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag { TVGLOG("SW_ENGINE", "Scaled Masked Image"); - //Top, Bottom Lines - SwCoord ys[2] = {region.min.y, region.max.y - 1}; - - for (auto i = 0; i < 2; ++i) { - auto y = ys[i]; - auto dst = surface->buffer + (y * surface->stride + region.min.x); - auto cmp = surface->compositor->image.data + (y * surface->compositor->image.stride + region.min.x); - auto img = image->data + static_cast(y * itransform->e22 + itransform->e23) * image->stride; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { - auto src = ALPHA_BLEND(img[static_cast(x * itransform->e11 + itransform->e13)], blendMethod(*cmp)); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Left, Right Lines - SwCoord xs[2] = {region.min.x, region.max.x - 1}; + auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x); - for (auto i = 0; i < 2; ++i) { - auto x = xs[i]; - auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x); - auto cmp = surface->compositor->image.data + ((region.min.y + 1) * surface->compositor->image.stride + x); - auto img = image->data + static_cast(x * itransform->e11 + itransform->e13); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride, cmp += surface->stride) { - auto src = ALPHA_BLEND(img[static_cast(y * itransform->e22 + itransform->e23) * image->stride], blendMethod(*cmp)); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Center (Down-Scaled) + // Down-Scaled if (image->scale < DOWN_SCALE_TOLERANCE) { - auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1)); - auto cbuffer = surface->compositor->image.data + ((region.min.y + 1) * surface->compositor->image.stride + (region.min.x + 1)); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y) { + for (auto y = region.min.y; y < region.max.y; ++y) { auto dst = dbuffer; auto cmp = cbuffer; auto sy = static_cast(y * itransform->e22 + itransform->e23); - for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst, ++cmp) { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { auto sx = static_cast(x * itransform->e11 + itransform->e13); auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), blendMethod(*cmp)); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); @@ -1193,16 +1143,14 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag dbuffer += surface->stride; cbuffer += surface->compositor->image.stride; } - //Center (Up-Scaled) + // Up-Scaled } else { - auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); - auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride + region.min.x); - for (auto y = region.min.y; y < region.max.y - 1; ++y) { + for (auto y = region.min.y; y < region.max.y; ++y) { auto dst = dbuffer; auto cmp = cbuffer; - auto sy = y * itransform->e22 + itransform->e23; - for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; + auto sy = fabsf(y * itransform->e22 + itransform->e23); + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) { + auto sx = fabsf(x * itransform->e11 + itransform->e13); auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), blendMethod(*cmp)); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } @@ -1216,50 +1164,26 @@ static bool _rasterScaledMaskedRGBAImage(SwSurface* surface, const SwImage* imag static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t opacity, uint32_t halfScale) { - //Top, Bottom Lines - SwCoord ys[2] = {region.min.y, region.max.y - 1}; + auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); - for (auto i = 0; i < 2; ++i) { - auto y = ys[i]; - auto dst = surface->buffer + (y * surface->stride + region.min.x); - auto img = image->data + static_cast(y * itransform->e22 + itransform->e23) * image->stride; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto src = ALPHA_BLEND(img[static_cast(x * itransform->e11 + itransform->e13)], opacity); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Left, Right Lines - SwCoord xs[2] = {region.min.x, region.max.x - 1}; - - for (auto i = 0; i < 2; ++i) { - auto x = xs[i]; - auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x); - auto img = image->data + static_cast(x * itransform->e11 + itransform->e13); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) { - auto src = ALPHA_BLEND(img[static_cast(y * itransform->e22 + itransform->e23) * image->stride], opacity); - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Center (Down-Scaled) + // Down-Scaled if (image->scale < DOWN_SCALE_TOLERANCE) { - auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1)); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) { + for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { auto sy = static_cast(y * itransform->e22 + itransform->e23); auto dst = dbuffer; - for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { auto sx = static_cast(x * itransform->e11 + itransform->e13); auto src = ALPHA_BLEND(_interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale), opacity); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } } - //Center (Up-Scaled) + // Up-Scaled } else { - auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); - for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) { - auto sy = y * itransform->e22 + itransform->e23; + for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { + auto sy = fabsf(y * itransform->e22 + itransform->e23); auto dst = dbuffer; - for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + auto sx = fabsf(x * itransform->e11 + itransform->e13); auto src = ALPHA_BLEND(_interpUpScaler(image->data, image->w, image->h, sx, sy), opacity); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } @@ -1271,50 +1195,26 @@ static bool _rasterScaledTranslucentRGBAImage(SwSurface* surface, const SwImage* static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint32_t halfScale) { - //Top, Bottom Lines - SwCoord ys[2] = {region.min.y, region.max.y - 1}; + auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); - for (auto i = 0; i < 2; ++i) { - auto y = ys[i]; - auto dst = surface->buffer + (y * surface->stride + region.min.x); - auto img = image->data + static_cast((y * itransform->e22 + itransform->e23)) * image->stride; - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto src = img[static_cast(x * itransform->e11 + itransform->e13)]; - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Left, Right Lines - SwCoord xs[2] = {region.min.x, region.max.x - 1}; - - for (auto i = 0; i < 2; ++i) { - auto x = xs[i]; - auto dst = surface->buffer + ((region.min.y + 1) * surface->stride + x); - auto img = image->data + static_cast(x * itransform->e11 + itransform->e13); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dst += surface->stride) { - auto src = img[static_cast(y * itransform->e22 + itransform->e23) * image->stride]; - *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); - } - } - //Center (Down-Scaled) + // Down-Scaled if (image->scale < DOWN_SCALE_TOLERANCE) { - auto dbuffer = surface->buffer + ((region.min.y + 1) * surface->stride + (region.min.x + 1)); - for (auto y = region.min.y + 1; y < region.max.y - 1; ++y, dbuffer += surface->stride) { + for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { auto sy = static_cast(y * itransform->e22 + itransform->e23); auto dst = dbuffer; - for (auto x = region.min.x + 1; x < region.max.x - 1; ++x, ++dst) { + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { auto sx = static_cast(x * itransform->e11 + itransform->e13); auto src = _interpDownScaler(image->data, image->w, image->h, sx, sy, halfScale); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } } - //Center (Up-Scaled) + // Up-Scaled } else { - auto dbuffer = surface->buffer + (region.min.y * surface->stride + region.min.x); - for (auto y = region.min.y; y < region.max.y - 1; ++y, dbuffer += surface->stride) { - auto sy = y * itransform->e22 + itransform->e23; + for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { + auto sy = fabsf(y * itransform->e22 + itransform->e23); auto dst = dbuffer; - for (auto x = region.min.x; x < region.max.x - 1; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + auto sx = fabsf(x * itransform->e11 + itransform->e13); auto src = _interpUpScaler(image->data, image->w, image->h, sx, sy); *dst = src + ALPHA_BLEND(*dst, surface->blender.ialpha(src)); } -- 2.7.4 From cf49c765b1a583dd268278fd67145749f0952648 Mon Sep 17 00:00:00 2001 From: jykeon Date: Tue, 30 Nov 2021 13:40:01 +0900 Subject: [PATCH 16/16] bump up version 0.6.3 Change-Id: I7ee8ad468f02ac8b69ce3baf0d7918a5b9e6879a Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index f44daf4..7adaa29 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.6.2 +Version: 0.6.3 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4