diff --git a/src/renderer/sw_engine/tvgSwCommon.h b/src/renderer/sw_engine/tvgSwCommon.h index 1a8fdc6b..7e532a85 100644 --- a/src/renderer/sw_engine/tvgSwCommon.h +++ b/src/renderer/sw_engine/tvgSwCommon.h @@ -23,6 +23,7 @@ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ +#include #include "tvgCommon.h" #include "tvgMath.h" #include "tvgRender.h" @@ -117,22 +118,47 @@ struct SwSpan uint16_t x, y; uint16_t len; uint8_t coverage; + + void fetch(const RenderRegion& bbox, int32_t& x, int32_t& len) const + { + x = std::max((int32_t)this->x, bbox.min.x); + len = std::min((int32_t)(this->x + this->len), bbox.max.x) - x; + } }; + struct SwRle { Array spans; - bool invalid() const + const SwSpan* fetch(const RenderRegion& bbox, const SwSpan** end) const { - return spans.empty(); + return fetch(bbox.min.y, bbox.max.y, end); } - bool valid() const + const SwSpan* fetch(int32_t min, uint32_t max, const SwSpan** end) const { - return !invalid(); + const SwSpan* begin; + + if (min <= spans.first().y) { + begin = spans.begin(); + } else { + auto comp = [](const SwSpan& span, int y) { return span.y < y; }; + begin = lower_bound(spans.begin(), spans.end(), min, comp); + } + if (end) { + if (max >= spans.last().y) { + *end = spans.end(); + } else { + auto comp = [](int y, const SwSpan& span) { return y < span.y; }; + *end = upper_bound(spans.begin(), spans.end(), max, comp); + } + } + return begin; } + bool invalid() const { return spans.empty(); } + bool valid() const { return !invalid(); } uint32_t size() const { return spans.count; } SwSpan* data() const { return spans.data; } }; @@ -566,11 +592,11 @@ SwOutline* mpoolReqDashOutline(SwMpool* mpool, unsigned idx); void mpoolRetDashOutline(SwMpool* mpool, unsigned idx); bool rasterCompositor(SwSurface* surface); -bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity); -bool rasterShape(SwSurface* surface, SwShape* shape, RenderColor& c); +bool rasterGradientShape(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, const Fill* fdata, uint8_t opacity); +bool rasterShape(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, RenderColor& c); bool rasterImage(SwSurface* surface, SwImage* image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity); -bool rasterStroke(SwSurface* surface, SwShape* shape, RenderColor& c); -bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity); +bool rasterStroke(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, RenderColor& c); +bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, const Fill* fdata, uint8_t opacity); bool rasterClear(SwSurface* surface, uint32_t x, uint32_t y, uint32_t w, uint32_t h, pixel_t val = 0); void rasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len); void rasterTranslucentPixel32(uint32_t* dst, uint32_t* src, uint32_t len, uint8_t opacity); diff --git a/src/renderer/sw_engine/tvgSwRaster.cpp b/src/renderer/sw_engine/tvgSwRaster.cpp index 16d8f45d..1a052a7c 100644 --- a/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/src/renderer/sw_engine/tvgSwRaster.cpp @@ -472,37 +472,44 @@ static bool _rasterRect(SwSurface* surface, const RenderRegion& bbox, const Rend /* Rle */ /************************************************************************/ -static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp, uint8_t a) +static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRle* rle, const RenderRegion& bbox, SwMask maskOp, uint8_t a) { auto cbuffer = surface->compositor->image.buf8; auto cstride = surface->compositor->image.stride; + const SwSpan* end; + int32_t x, len; uint8_t src; - ARRAY_FOREACH(span, rle->spans) { - auto cmp = &cbuffer[span->y * cstride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto cmp = &cbuffer[span->y * cstride + x]; if (span->coverage == 255) src = a; else src = MULTIPLY(a, span->coverage); auto ialpha = 255 - src; - for (auto x = 0; x < span->len; ++x, ++cmp) { + for (auto x = 0; x < len; ++x, ++cmp) { *cmp = maskOp(src, *cmp, ialpha); } } + return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox); } -static bool _rasterDirectMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp, uint8_t a) +static bool _rasterDirectMaskedRle(SwSurface* surface, SwRle* rle, const RenderRegion& bbox, SwMask maskOp, uint8_t a) { auto cbuffer = surface->compositor->image.buf8; auto cstride = surface->compositor->image.stride; + const SwSpan* end; + int32_t x, len; uint8_t src; - ARRAY_FOREACH(span, rle->spans) { - auto cmp = &cbuffer[span->y * cstride + span->x]; - auto dst = &surface->buf8[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto cmp = &cbuffer[span->y * cstride + x]; + auto dst = &surface->buf8[span->y * surface->stride + x]; if (span->coverage == 255) src = a; else src = MULTIPLY(a, span->coverage); - for (auto x = 0; x < span->len; ++x, ++cmp, ++dst) { + for (auto x = 0; x < len; ++x, ++cmp, ++dst) { auto tmp = maskOp(src, *cmp, 0); //not use alpha *dst = tmp + MULTIPLY(*dst, ~tmp); } @@ -511,7 +518,7 @@ static bool _rasterDirectMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp } -static bool _rasterMaskedRle(SwSurface* surface, SwRle* rle, const RenderColor& c) +static bool _rasterMaskedRle(SwSurface* surface, SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { TVGLOG("SW_ENGINE", "Masked(%d) Rle", (int)surface->compositor->method); @@ -519,30 +526,33 @@ static bool _rasterMaskedRle(SwSurface* surface, SwRle* rle, const RenderColor& if (surface->channelSize != sizeof(uint8_t)) return false; auto maskOp = _getMaskOp(surface->compositor->method); - if (_direct(surface->compositor->method)) return _rasterDirectMaskedRle(surface, rle, maskOp, c.a); - else return _rasterCompositeMaskedRle(surface, rle, maskOp, c.a); + if (_direct(surface->compositor->method)) return _rasterDirectMaskedRle(surface, rle, bbox, maskOp, c.a); + else return _rasterCompositeMaskedRle(surface, rle, bbox, maskOp, c.a); return false; } -static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor& c) +static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { TVGLOG("SW_ENGINE", "Matted(%d) Rle", (int)surface->compositor->method); auto cbuffer = surface->compositor->image.buf8; auto csize = surface->compositor->image.channelSize; auto alpha = surface->alpha(surface->compositor->method); + const SwSpan* end; + int32_t x, len; //32bit channels if (surface->channelSize == sizeof(uint32_t)) { uint32_t src; auto color = surface->join(c.r, c.g, c.b, c.a); - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf32[span->y * surface->stride + x]; + auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + x) * csize]; if (span->coverage == 255) src = color; else src = ALPHA_BLEND(color, span->coverage); - for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) { + for (auto x = 0; x < len; ++x, ++dst, cmp += csize) { auto tmp = ALPHA_BLEND(src, alpha(cmp)); *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } @@ -550,12 +560,13 @@ static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor& //8bit grayscale } else if (surface->channelSize == sizeof(uint8_t)) { uint8_t src; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf8[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf8[span->y * surface->stride + x]; + auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + x) * csize]; if (span->coverage == 255) src = c.a; else src = MULTIPLY(c.a, span->coverage); - for (uint32_t x = 0; x < span->len; ++x, ++dst, cmp += csize) { + for (auto x = 0; x < len; ++x, ++dst, cmp += csize) { *dst = INTERPOLATE8(src, *dst, alpha(cmp)); } } @@ -564,20 +575,23 @@ static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor& } -static bool _rasterBlendingRle(SwSurface* surface, const SwRle* rle, const RenderColor& c) +static bool _rasterBlendingRle(SwSurface* surface, const SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { if (surface->channelSize != sizeof(uint32_t)) return false; auto color = surface->join(c.r, c.g, c.b, c.a); + const SwSpan* end; + int32_t x, len; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf32[span->y * surface->stride + x]; if (span->coverage == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = surface->blender(color, *dst, 255); } } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { auto tmp = surface->blender(color, *dst, 255); *dst = INTERPOLATE(tmp, *dst, span->coverage); } @@ -587,44 +601,47 @@ static bool _rasterBlendingRle(SwSurface* surface, const SwRle* rle, const Rende } -static bool _rasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderColor& c) +static bool _rasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { #if defined(THORVG_AVX_VECTOR_SUPPORT) - return avxRasterTranslucentRle(surface, rle, c); + return avxRasterTranslucentRle(surface, rle, bbox, c); #elif defined(THORVG_NEON_VECTOR_SUPPORT) - return neonRasterTranslucentRle(surface, rle, c); + return neonRasterTranslucentRle(surface, rle, bbox, c); #else - return cRasterTranslucentRle(surface, rle, c); + return cRasterTranslucentRle(surface, rle, bbox, c); #endif } -static bool _rasterSolidRle(SwSurface* surface, const SwRle* rle, const RenderColor& c) +static bool _rasterSolidRle(SwSurface* surface, const SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { + const SwSpan* end; + int32_t x, len; + //32bit channels if (surface->channelSize == sizeof(uint32_t)) { auto color = surface->join(c.r, c.g, c.b, 255); - ARRAY_FOREACH(span, rle->spans) { - if (span->coverage == 255) { - rasterPixel32(surface->buf32 + span->y * surface->stride, color, span->x, span->len); - } else { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + if (span->coverage == 255) rasterPixel32(surface->buf32 + span->y * surface->stride, color, x, len); + else { + auto dst = &surface->buf32[span->y * surface->stride + x]; auto src = ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = src + ALPHA_BLEND(*dst, ialpha); } } } //8bit grayscale } else if (surface->channelSize == sizeof(uint8_t)) { - ARRAY_FOREACH(span, rle->spans) { - if (span->coverage == 255) { - rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + span->x, span->len); - } else { - auto dst = &surface->buf8[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + if (span->coverage == 255) rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + x, len); + else { + auto dst = &surface->buf8[span->y * surface->stride + x]; auto ialpha = 255 - span->coverage; - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = span->coverage + MULTIPLY(*dst, ialpha); } } @@ -634,18 +651,18 @@ static bool _rasterSolidRle(SwSurface* surface, const SwRle* rle, const RenderCo } -static bool _rasterRle(SwSurface* surface, SwRle* rle, const RenderColor& c) +static bool _rasterRle(SwSurface* surface, SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { if (!rle || rle->invalid()) return false; if (_compositing(surface)) { - if (_matting(surface)) return _rasterMattedRle(surface, rle, c); - else return _rasterMaskedRle(surface, rle, c); + if (_matting(surface)) return _rasterMattedRle(surface, rle, bbox, c); + else return _rasterMaskedRle(surface, rle, bbox, c); } else if (_blending(surface)) { - return _rasterBlendingRle(surface, rle, c); + return _rasterBlendingRle(surface, rle, bbox, c); } else { - if (c.a == 255) return _rasterSolidRle(surface, rle, c); - else return _rasterTranslucentRle(surface, rle, c); + if (c.a == 255) return _rasterSolidRle(surface, rle, bbox, c); + else return _rasterTranslucentRle(surface, rle, bbox, c); } return false; } @@ -781,26 +798,29 @@ static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matr /* RLE Direct Image */ /************************************************************************/ -static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity) +static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, uint8_t opacity) { TVGLOG("SW_ENGINE", "Direct Matted(%d) Rle Image", (int)surface->compositor->method); auto csize = surface->compositor->image.channelSize; auto cbuffer = surface->compositor->image.buf8; auto alpha = surface->alpha(surface->compositor->method); + const SwSpan* end; + int32_t x, len; - ARRAY_FOREACH(span, image->rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize]; - auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox); + for (auto span = image->rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf32[span->y * surface->stride + x]; + auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + x) * csize]; + auto img = image->buf32 + (span->y + image->oy) * image->stride + (x + image->ox); auto a = MULTIPLY(span->coverage, opacity); if (a == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) { + for (auto x = 0; x < len; ++x, ++dst, ++img, cmp += csize) { auto tmp = ALPHA_BLEND(*img, alpha(cmp)); *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img, cmp += csize) { + for (auto x = 0; x < len; ++x, ++dst, ++img, cmp += csize) { auto tmp = ALPHA_BLEND(*img, MULTIPLY(a, alpha(cmp))); *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } @@ -810,18 +830,22 @@ static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image } -static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity) +static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, uint8_t opacity) { - ARRAY_FOREACH(span, image->rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; - auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox); + const SwSpan* end; + int32_t x, len; + + for (auto span = image->rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf32[span->y * surface->stride + x]; + auto img = image->buf32 + (span->y + image->oy) * image->stride + (x + image->ox); auto alpha = MULTIPLY(span->coverage, opacity); if (alpha == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { + for (auto x = 0; x < len; ++x, ++dst, ++img) { *dst = surface->blender(*img, *dst, 255); } } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++img) { + for (auto x = 0; x < len; ++x, ++dst, ++img) { auto tmp = surface->blender(*img, *dst, 255); *dst = INTERPOLATE(tmp, *dst, MULTIPLY(alpha, A(*img))); } @@ -831,26 +855,30 @@ static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* ima } -static bool _rasterDirectRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity) +static bool _rasterDirectRleImage(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, uint8_t opacity) { - ARRAY_FOREACH(span, image->rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; - auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox); + const SwSpan* end; + int32_t x, len; + + for (auto span = image->rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf32[span->y * surface->stride + x]; + auto img = image->buf32 + (span->y + image->oy) * image->stride + (x + image->ox); auto alpha = MULTIPLY(span->coverage, opacity); - rasterTranslucentPixel32(dst, img, span->len, alpha); + rasterTranslucentPixel32(dst, img, len, alpha); } return true; } -static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity) +static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, uint8_t opacity) { TVGERR("SW_ENGINE", "Not Supported Direct Masked(%d) Rle Image", (int)surface->compositor->method); return false; } -static bool _directRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity) +static bool _directRleImage(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, uint8_t opacity) { if (surface->channelSize == sizeof(uint8_t)) { TVGERR("SW_ENGINE", "Not supported grayscale rle image!"); @@ -858,12 +886,12 @@ static bool _directRleImage(SwSurface* surface, const SwImage* image, uint8_t op } if (_compositing(surface)) { - if (_matting(surface)) return _rasterDirectMattedRleImage(surface, image, opacity); - else return _rasterDirectMaskedRleImage(surface, image, opacity); + if (_matting(surface)) return _rasterDirectMattedRleImage(surface, image, bbox, opacity); + else return _rasterDirectMaskedRleImage(surface, image, bbox, opacity); } else if (_blending(surface)) { - return _rasterDirectBlendingRleImage(surface, image, opacity); + return _rasterDirectBlendingRleImage(surface, image, bbox, opacity); } else { - return _rasterDirectRleImage(surface, image, opacity); + return _rasterDirectRleImage(surface, image, bbox, opacity); } return false; } @@ -1185,14 +1213,14 @@ static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix& trans { //RLE Image if (image->rle) { - if (image->direct) return _directRleImage(surface, image, opacity); + if (image->direct) return _directRleImage(surface, image, bbox, opacity); else if (image->scaled) return _scaledRleImage(surface, image, transform, bbox, opacity); - else return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity); + else return _rasterTexmapPolygon(surface, image, transform, bbox, opacity); //Whole Image } else { if (image->direct) return _directImage(surface, image, bbox, opacity); else if (image->scaled) return _scaledImage(surface, image, transform, bbox, opacity); - else return _rasterTexmapPolygon(surface, image, transform, &bbox, opacity); + else return _rasterTexmapPolygon(surface, image, transform, bbox, opacity); } } @@ -1666,36 +1694,35 @@ void rasterPremultiply(RenderSurface* surface) } -bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity) +bool rasterGradientShape(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, const Fill* fdata, uint8_t opacity) { if (!shape->fill) return false; if (auto color = fillFetchSolid(shape->fill, fdata)) { auto a = MULTIPLY(color->a, opacity); RenderColor c = {color->r, color->g, color->b, a}; - return a > 0 ? rasterShape(surface, shape, c) : true; + return a > 0 ? rasterShape(surface, shape, bbox, c) : true; } auto type = fdata->type(); if (shape->fastTrack) { - if (type == Type::LinearGradient) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill); - else if (type == Type::RadialGradient)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill); + if (type == Type::LinearGradient) return _rasterLinearGradientRect(surface, bbox, shape->fill); + else if (type == Type::RadialGradient)return _rasterRadialGradientRect(surface, bbox, shape->fill); } else if (shape->rle && shape->rle->valid()) { if (type == Type::LinearGradient) return _rasterLinearGradientRle(surface, shape->rle, shape->fill); else if (type == Type::RadialGradient) return _rasterRadialGradientRle(surface, shape->rle, shape->fill); - } - return false; + } return false; } -bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity) +bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, const Fill* fdata, uint8_t opacity) { if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle || shape->strokeRle->invalid()) return false; if (auto color = fillFetchSolid(shape->stroke->fill, fdata)) { RenderColor c = {color->r, color->g, color->b, color->a}; c.a = MULTIPLY(c.a, opacity); - return c.a > 0 ? rasterStroke(surface, shape, c) : true; + return c.a > 0 ? rasterStroke(surface, shape, bbox, c) : true; } auto type = fdata->type(); @@ -1705,19 +1732,19 @@ bool rasterGradientStroke(SwSurface* surface, SwShape* shape, const Fill* fdata, } -bool rasterShape(SwSurface* surface, SwShape* shape, RenderColor& c) +bool rasterShape(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, RenderColor& c) { if (c.a < 255) { c.r = MULTIPLY(c.r, c.a); c.g = MULTIPLY(c.g, c.a); c.b = MULTIPLY(c.b, c.a); } - if (shape->fastTrack) return _rasterRect(surface, shape->bbox, c); - else return _rasterRle(surface, shape->rle, c); + if (shape->fastTrack) return _rasterRect(surface, bbox, c); + else return _rasterRle(surface, shape->rle, bbox, c); } -bool rasterStroke(SwSurface* surface, SwShape* shape, RenderColor& c) +bool rasterStroke(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, RenderColor& c) { if (c.a < 255) { c.r = MULTIPLY(c.r, c.a); @@ -1725,7 +1752,7 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, RenderColor& c) c.b = MULTIPLY(c.b, c.a); } - return _rasterRle(surface, shape->strokeRle, c); + return _rasterRle(surface, shape->strokeRle, bbox, c); } @@ -1791,4 +1818,4 @@ void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32 } } } -} +} \ No newline at end of file diff --git a/src/renderer/sw_engine/tvgSwRasterAvx.h b/src/renderer/sw_engine/tvgSwRasterAvx.h index e2e8360d..3f53e877 100644 --- a/src/renderer/sw_engine/tvgSwRasterAvx.h +++ b/src/renderer/sw_engine/tvgSwRasterAvx.h @@ -158,47 +158,51 @@ static bool avxRasterTranslucentRect(SwSurface* surface, const RenderRegion& bbo } -static bool avxRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderColor& c) +static bool avxRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { + const SwSpan* end; + int32_t x, len; + //32bit channels if (surface->channelSize == sizeof(uint32_t)) { auto color = surface->join(c.r, c.g, c.b, c.a); uint32_t src; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; - + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + FETCH_BOUND(span, bbox); + span->fetch(bbox, x, len); if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); else src = color; + auto dst = &surface->buf32[span->y * surface->stride + x]; auto ialpha = IA(src); //1. fill the not aligned memory (for 128-bit registers a 16-bytes alignment is required) - auto notAligned = ((uintptr_t)dst & 0xf) / 4; + int32_t notAligned = ((uintptr_t)dst & 0xf) / 4; if (notAligned) { - notAligned = (N_32BITS_IN_128REG - notAligned > span->len ? span->len : N_32BITS_IN_128REG - notAligned); - for (uint32_t x = 0; x < notAligned; ++x, ++dst) { + notAligned = (N_32BITS_IN_128REG - notAligned > len ? len : N_32BITS_IN_128REG - notAligned); + for (auto x = 0; x < notAligned; ++x, ++dst) { *dst = src + ALPHA_BLEND(*dst, ialpha); } } //2. fill the aligned memory using avx - N_32BITS_IN_128REG pixels processed at once //In order to avoid unnecessary avx variables declarations a check is made whether there are any iterations at all - uint32_t iterations = (span->len - notAligned) / N_32BITS_IN_128REG; - uint32_t avxFilled = 0; + int32_t iterations = (len - notAligned) / N_32BITS_IN_128REG; + int32_t avxFilled = 0; if (iterations > 0) { auto avxSrc = _mm_set1_epi32(src); auto avxIalpha = _mm_set1_epi8(ialpha); avxFilled = iterations * N_32BITS_IN_128REG; auto avxDst = (__m128i*)dst; - for (uint32_t x = 0; x < iterations; ++x, ++avxDst) { + for (auto x = 0; x < iterations; ++x, ++avxDst) { *avxDst = _mm_add_epi32(avxSrc, ALPHA_BLEND(*avxDst, avxIalpha)); } } //3. fill the remaining pixels - int32_t leftovers = span->len - notAligned - avxFilled; + auto leftovers = len - notAligned - avxFilled; dst += avxFilled; while (leftovers--) { *dst = src + ALPHA_BLEND(*dst, ialpha); @@ -211,12 +215,14 @@ static bool avxRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const } else if (surface->channelSize == sizeof(uint8_t)) { TVGLOG("SW_ENGINE", "Require AVX Optimization, Channel Size = %d", surface->channelSize); uint8_t src; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf8[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + FETCH_BOUND(span, bbox); + span->fetch(bbox, x, len); + auto dst = &surface->buf8[span->y * surface->stride + x]; if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a); else src = c.a; auto ialpha = ~c.a; - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = src + MULTIPLY(*dst, ialpha); } } diff --git a/src/renderer/sw_engine/tvgSwRasterC.h b/src/renderer/sw_engine/tvgSwRasterC.h index 82b696be..8dcbf14c 100644 --- a/src/renderer/sw_engine/tvgSwRasterC.h +++ b/src/renderer/sw_engine/tvgSwRasterC.h @@ -92,30 +92,35 @@ static void inline cRasterPixels(PIXEL_T* dst, PIXEL_T val, uint32_t offset, int } -static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderColor& c) +static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { + const SwSpan* end; + int32_t x, len; + //32bit channels if (surface->channelSize == sizeof(uint32_t)) { auto color = surface->join(c.r, c.g, c.b, c.a); uint32_t src; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf32[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf32[span->y * surface->stride + x]; if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); else src = color; auto ialpha = IA(src); - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = src + ALPHA_BLEND(*dst, ialpha); } } //8bit grayscale } else if (surface->channelSize == sizeof(uint8_t)) { uint8_t src; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf8[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + span->fetch(bbox, x, len); + auto dst = &surface->buf8[span->y * surface->stride + x]; if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a); else src = c.a; auto ialpha = ~c.a; - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = src + MULTIPLY(*dst, ialpha); } } diff --git a/src/renderer/sw_engine/tvgSwRasterNeon.h b/src/renderer/sw_engine/tvgSwRasterNeon.h index d5c408c6..d8409b6d 100644 --- a/src/renderer/sw_engine/tvgSwRasterNeon.h +++ b/src/renderer/sw_engine/tvgSwRasterNeon.h @@ -89,20 +89,25 @@ static void neonRasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int3 } -static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderColor& c) +static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderRegion& bbox, const RenderColor& c) { + const SwSpan* end; + int32_t x, len; + //32bit channels if (surface->channelSize == sizeof(uint32_t)) { auto color = surface->join(c.r, c.g, c.b, c.a); uint32_t src; uint8x8_t *vDst = nullptr; - uint16_t align; + int32_t align; - ARRAY_FOREACH(span, rle->spans) { + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + FETCH_BOUND(span, bbox); + span->fetch(bbox, x, len); if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); else src = color; - auto dst = &surface->buf32[span->y * surface->stride + span->x]; + auto dst = &surface->buf32[span->y * surface->stride + x]; auto ialpha = IA(src); if ((((uintptr_t) dst) & 0x7) != 0) { @@ -118,11 +123,11 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const uint8x8_t vSrc = (uint8x8_t) vdup_n_u32(src); uint8x8_t vIalpha = vdup_n_u8((uint8_t) ialpha); - for (uint32_t x = 0; x < (span->len - align) / 2; ++x) + for (int32_t x = 0; x < (len - align) / 2; ++x) vDst[x] = vadd_u8(vSrc, ALPHA_BLEND(vDst[x], vIalpha)); - auto leftovers = (span->len - align) % 2; - if (leftovers > 0) dst[span->len - 1] = src + ALPHA_BLEND(dst[span->len - 1], ialpha); + auto leftovers = (len - align) % 2; + if (leftovers > 0) dst[len - 1] = src + ALPHA_BLEND(dst[len - 1], ialpha); ++span; } @@ -130,12 +135,14 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const } else if (surface->channelSize == sizeof(uint8_t)) { TVGLOG("SW_ENGINE", "Require Neon Optimization, Channel Size = %d", surface->channelSize); uint8_t src; - ARRAY_FOREACH(span, rle->spans) { - auto dst = &surface->buf8[span->y * surface->stride + span->x]; + for (auto span = rle->fetch(bbox, &end); span < end; ++span) { + FETCH_BOUND(span, bbox); + span->fetch(bbox, x, len); + auto dst = &surface->buf8[span->y * surface->stride + x]; if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a); else src = c.a; auto ialpha = ~c.a; - for (uint32_t x = 0; x < span->len; ++x, ++dst) { + for (auto x = 0; x < len; ++x, ++dst) { *dst = src + MULTIPLY(*dst, ialpha); } } diff --git a/src/renderer/sw_engine/tvgSwRasterTexmap.h b/src/renderer/sw_engine/tvgSwRasterTexmap.h index 62b0bea3..4cf46424 100644 --- a/src/renderer/sw_engine/tvgSwRasterTexmap.h +++ b/src/renderer/sw_engine/tvgSwRasterTexmap.h @@ -52,33 +52,25 @@ static float xa, xb, ua, va; //Y Range exception handling -static bool _arrange(const SwImage* image, const RenderRegion* bbox, int& yStart, int& yEnd) +static bool _arrange(const SwImage* image, const RenderRegion& bbox, int& yStart, int& yEnd) { - int32_t bboxTop, bboxBottom; - - if (bbox) { - bboxTop = bbox->min.y; - bboxBottom = bbox->max.y; - } else { - bboxTop = image->rle->spans.first().y; - bboxBottom = image->rle->spans.last().y; - } - - if (yStart < bboxTop) yStart = bboxTop; - if (yEnd > bboxBottom) yEnd = bboxBottom; + auto top = image->rle ? std::max((int)image->rle->spans.first().y, bbox.min.y) : (int)bbox.min.y; + auto bottom = image->rle? std::min((int)image->rle->spans.last().y, bbox.max.y) : (int)bbox.max.y; + if (yStart < top) yStart = top; + if (yEnd > bottom) yEnd = bottom; return yEnd > yStart; } -static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const RenderRegion* bbox, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag = 0) +static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag = 0) { TVGERR("SW_ENGINE", "TODO: _rasterMaskedPolygonImageSegment()"); return false; } -static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage* image, const RenderRegion* bbox, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity) +static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity) { float _dudx = dudx, _dvdx = dvdx; float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; @@ -89,26 +81,15 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage int32_t sh = static_cast(image->h); int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay; int32_t vv = 0, uu = 0; - int32_t minx = INT32_MAX, maxx = 0; + auto minx = bbox.min.x; + auto maxx = bbox.max.x; float dx, u, v, iptr; uint32_t* buf; - SwSpan* span = nullptr; //used only when rle based. if (!_arrange(image, bbox, yStart, yEnd)) return; - //Loop through all lines in the segment - uint32_t spanIdx = 0; - - if (bbox) { - minx = bbox->min.x; - maxx = bbox->max.x; - } else { - span = image->rle->data(); - while (span->y < yStart) { - ++span; - ++spanIdx; - } - } + const SwSpan* span = nullptr; //used only when rle based. + if (image->rle) span = image->rle->fetch(yStart, yEnd, nullptr); y = yStart; @@ -116,16 +97,17 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage x1 = (int32_t)_xa; x2 = (int32_t)_xb; - if (!bbox) { + if (span) { minx = INT32_MAX; maxx = 0; //one single row, could be consisted of multiple spans. - while (span->y == y && spanIdx < image->rle->size()) { + while (span->y == y && span < image->rle->spans.end()) { if (minx > span->x) minx = span->x; if (maxx < span->x + span->len) maxx = span->x + span->len; ++span; - ++spanIdx; } + if (minx < bbox.min.x) minx = bbox.min.x; + if (maxx > bbox.max.x) maxx = bbox.max.x; } if (x1 < minx) x1 = minx; if (x2 > maxx) x2 = maxx; @@ -195,8 +177,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage _ua += _dudya; _va += _dvdya; - if (!bbox && spanIdx >= image->rle->size()) break; - + if (span && span >= image->rle->spans.end()) break; ++y; } xa = _xa; @@ -206,7 +187,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage } -static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const RenderRegion* bbox, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, bool matting) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, bool matting) { float _dudx = dudx, _dvdx = dvdx; float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; @@ -217,10 +198,10 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, int32_t sh = static_cast(image->h); int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay; int32_t vv = 0, uu = 0; - int32_t minx = INT32_MAX, maxx = 0; + auto minx = bbox.min.x; + auto maxx = bbox.max.x; float dx, u, v, iptr; uint32_t* buf; - SwSpan* span = nullptr; //used only when rle based. //for matting(composition) auto csize = matting ? surface->compositor->image.channelSize: 0; @@ -229,19 +210,8 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, if (!_arrange(image, bbox, yStart, yEnd)) return; - //Loop through all lines in the segment - uint32_t spanIdx = 0; - - if (bbox) { - minx = bbox->min.x; - maxx = bbox->max.x; - } else { - span = image->rle->data(); - while (span->y < yStart) { - ++span; - ++spanIdx; - } - } + const SwSpan* span = nullptr; //used only when rle based. + if (image->rle) span = image->rle->fetch(yStart, yEnd, nullptr); y = yStart; @@ -249,16 +219,17 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, x1 = (int32_t)_xa; x2 = (int32_t)_xb; - if (!bbox) { + if (span) { minx = INT32_MAX; maxx = 0; //one single row, could be consisted of multiple spans. - while (span->y == y && spanIdx < image->rle->size()) { + while (span->y == y && span < image->rle->spans.end()) { if (minx > span->x) minx = span->x; if (maxx < span->x + span->len) maxx = span->x + span->len; ++span; - ++spanIdx; } + if (minx < bbox.min.x) minx = bbox.min.x; + if (maxx > bbox.max.x) maxx = bbox.max.x; } if (x1 < minx) x1 = minx; if (x2 > maxx) x2 = maxx; @@ -387,8 +358,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, _ua += _dudya; _va += _dvdya; - if (!bbox && spanIdx >= image->rle->size()) break; - + if (span && span >= image->rle->spans.end()) break; ++y; } xa = _xa; @@ -399,7 +369,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, /* This mapping algorithm is based on Mikael Kalms's. */ -static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const RenderRegion* bbox, Polygon& polygon, AASpans* aaSpans, uint8_t opacity) +static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const RenderRegion& bbox, Polygon& polygon, AASpans* aaSpans, uint8_t opacity) { 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}; @@ -460,7 +430,7 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const if (tvg::equal(y[0], y[1])) side = x[0] > x[1]; if (tvg::equal(y[1], y[2])) side = x[2] > x[1]; - auto bboxTop = bbox ? bbox->min.y : image->rle->data()->y; //Normal Image or Rle Image? + auto bboxTop = image->rle ? std::max(bbox.min.y, (int)image->rle->data()->y) : bbox.min.y; auto compositing = _compositing(surface); //Composition required auto blending = _blending(surface); //Blending required @@ -576,7 +546,7 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const } -static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const RenderRegion* bbox) +static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const RenderRegion& bbox) { auto yStart = static_cast(ymin); auto yEnd = static_cast(ymax); @@ -863,7 +833,7 @@ static bool _apply(SwSurface* surface, AASpans* aaSpans) | / | 3 -- 2 */ -static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix& transform, const RenderRegion* bbox, uint8_t opacity) +static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity) { if (surface->channelSize == sizeof(uint8_t)) { TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon!"); @@ -871,7 +841,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const } //Exceptions: No dedicated drawing area? - if ((!image->rle && !bbox) || (image->rle && image->rle->size() == 0)) return true; + if ((!image->rle && bbox.invalid()) || (image->rle && image->rle->size() == 0)) return true; /* Prepare vertices. shift XY coordinates to match the sub-pixeling technique. */ diff --git a/src/renderer/sw_engine/tvgSwRenderer.cpp b/src/renderer/sw_engine/tvgSwRenderer.cpp index c44f28cb..08ad4ee5 100644 --- a/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -204,9 +204,7 @@ struct SwImageTask : SwTask if ((flags & (RenderUpdateFlag::Image | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) && (opacity > 0)) { imageReset(&image); if (!image.data || image.w == 0 || image.h == 0) goto end; - - if (!imagePrepare(&image, transform, clipBox, bbox, mpool, tid)) goto end; - + if (!imagePrepare(&image, transform, clipBox, bbox, mpool, tid)) goto end; if (clips.count > 0) { if (!imageGenRle(&image, bbox, false)) goto end; if (image.rle) { @@ -222,6 +220,7 @@ struct SwImageTask : SwTask } goto end; err: + bbox.reset(); rleReset(image.rle); end: imageDelOutline(&image, mpool, tid); @@ -234,31 +233,6 @@ struct SwImageTask : SwTask }; -static void _renderFill(SwShapeTask* task, SwSurface* surface) -{ - if (auto fill = task->rshape->fill) { - rasterGradientShape(surface, &task->shape, fill, task->opacity); - } else { - RenderColor c; - task->rshape->fillColor(&c.r, &c.g, &c.b, &c.a); - c.a = MULTIPLY(task->opacity, c.a); - if (c.a > 0) rasterShape(surface, &task->shape, c); - } -} - -static void _renderStroke(SwShapeTask* task, SwSurface* surface) -{ - if (auto strokeFill = task->rshape->strokeFill()) { - rasterGradientStroke(surface, &task->shape, strokeFill, task->opacity); - } else { - RenderColor c; - if (task->rshape->strokeFill(&c.r, &c.g, &c.b, &c.a)) { - c.a = MULTIPLY(task->opacity, c.a); - if (c.a > 0) rasterStroke(surface, &task->shape, c); - } - } -} - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -299,10 +273,10 @@ bool SwRenderer::clear() bool SwRenderer::sync() { + //clear if the rendering was not triggered. ARRAY_FOREACH(p, tasks) { - if ((*p)->disposed) { - delete(*p); - } else { + if ((*p)->disposed) delete(*p); + else { (*p)->done(); (*p)->pushed = false; } @@ -400,6 +374,7 @@ bool SwRenderer::renderImage(RenderData data) if (task->opacity == 0) return true; + //full scene or partial rendering return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity); } @@ -413,13 +388,35 @@ bool SwRenderer::renderShape(RenderData data) if (task->opacity == 0) return true; - //Main raster stage + auto fill = [](SwShapeTask* task, SwSurface* surface, const RenderRegion& bbox) { + if (auto fill = task->rshape->fill) { + rasterGradientShape(surface, &task->shape, bbox, fill, task->opacity); + } else { + RenderColor c; + task->rshape->fillColor(&c.r, &c.g, &c.b, &c.a); + c.a = MULTIPLY(task->opacity, c.a); + if (c.a > 0) rasterShape(surface, &task->shape, bbox, c); + } + }; + + auto stroke = [](SwShapeTask* task, SwSurface* surface, const RenderRegion& bbox) { + if (auto strokeFill = task->rshape->strokeFill()) { + rasterGradientStroke(surface, &task->shape, bbox, strokeFill, task->opacity); + } else { + RenderColor c; + if (task->rshape->strokeFill(&c.r, &c.g, &c.b, &c.a)) { + c.a = MULTIPLY(task->opacity, c.a); + if (c.a > 0) rasterStroke(surface, &task->shape, bbox, c); + } + } + }; + if (task->rshape->strokeFirst()) { - _renderStroke(task, surface); - _renderFill(task, surface); + stroke(task, surface, task->bbox); + fill(task, surface, task->shape.bbox); } else { - _renderFill(task, surface); - _renderStroke(task, surface); + fill(task, surface, task->shape.bbox); + stroke(task, surface, task->bbox); } return true; diff --git a/src/renderer/sw_engine/tvgSwRle.cpp b/src/renderer/sw_engine/tvgSwRle.cpp index 58ebffa2..0b57be33 100644 --- a/src/renderer/sw_engine/tvgSwRle.cpp +++ b/src/renderer/sw_engine/tvgSwRle.cpp @@ -881,10 +881,10 @@ bool rleClip(SwRle *rle, const SwRle *clip) Array out; out.reserve(std::max(rle->spans.count, clip->spans.count)); - auto spans = rle->data(); - auto end = rle->spans.end(); - auto cspans = clip->data(); - auto cend = clip->spans.end(); + const SwSpan *end; + auto spans = rle->fetch(clip->spans.first().y, clip->spans.last().y, &end); + const SwSpan *cend; + auto cspans = clip->fetch(rle->spans.first().y, rle->spans.last().y, &cend); while(spans < end && cspans < cend) { //align y-coordinates. @@ -928,9 +928,10 @@ bool rleClip(SwRle *rle, const RenderRegion* clip) Array out; out.reserve(rle->spans.count); auto data = out.data; + const SwSpan* end; uint16_t x, len; - ARRAY_FOREACH(p, rle->spans) { + for (auto p = rle->fetch(*clip, &end); p < end; ++p) { if (p->y >= max.y) break; if (p->y < min.y || p->x >= max.x || (p->x + p->len) <= min.x) continue; if (p->x < min.x) {