diff --git a/src/examples/MaskingMethods.cpp b/src/examples/MaskingMethods.cpp index 86036cad..3a924e00 100644 --- a/src/examples/MaskingMethods.cpp +++ b/src/examples/MaskingMethods.cpp @@ -38,6 +38,12 @@ void tvgDrawCmds(tvg::Canvas* canvas) file.read(reinterpret_cast(data), sizeof (uint32_t) * 200 * 300); file.close(); + //background + auto bg = tvg::Shape::gen(); + bg->appendRect(0, 0, 625, HEIGHT); + bg->fill(50, 50, 50); + canvas->push(move(bg)); + { //Shape + Shape Mask Add auto shape = tvg::Shape::gen(); @@ -54,7 +60,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape + Shape Mask Subtract auto shape2 = tvg::Shape::gen(); shape2->appendCircle(375, 100, 50, 50); - shape2->fill(255, 255, 255); + shape2->fill(255, 255, 255, 127); auto mask2 = tvg::Shape::gen(); mask2->appendCircle(400, 100, 50, 50); @@ -67,7 +73,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape + Shape Mask Intersect auto shape3 = tvg::Shape::gen(); shape3->appendCircle(625, 100, 50, 50); - shape3->fill(255, 255, 255); + shape3->fill(255, 255, 255, 127); auto mask3 = tvg::Shape::gen(); mask3->appendCircle(650, 100, 50, 50); @@ -105,7 +111,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape + Image Mask Subtract auto shape2 = tvg::Shape::gen(); shape2->appendCircle(400, 250, 50, 50); - shape2->fill(255, 255, 255); + shape2->fill(255, 255, 255, 127); auto mask2 = tvg::Picture::gen(); if (mask2->load(data, 200, 300, true) != tvg::Result::Success) return; @@ -118,7 +124,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Shape + Image Mask Intersect auto shape3 = tvg::Shape::gen(); shape3->appendCircle(650, 250, 50, 50); - shape3->fill(255, 255, 255); + shape3->fill(255, 255, 255, 127); auto mask3 = tvg::Picture::gen(); if (mask3->load(data, 200, 300, true) != tvg::Result::Success) return; @@ -158,7 +164,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Rect + Rect Mask Subtract auto shape2 = tvg::Shape::gen(); shape2->appendRect(325, 500, 100, 100); - shape2->fill(255, 255, 255); + shape2->fill(255, 255, 255, 127); auto mask2 = tvg::Shape::gen(); mask2->appendRect(375, 450, 100, 100); @@ -170,7 +176,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) //Rect + Rect Mask Intersect auto shape3 = tvg::Shape::gen(); shape3->appendRect(575, 500, 100, 100); - shape3->fill(255, 255, 255); + shape3->fill(255, 255, 255, 127); auto mask3 = tvg::Shape::gen(); mask3->appendRect(625, 450, 100, 100); @@ -212,6 +218,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) image2->translate(400, 650); image2->scale(0.5f); image2->rotate(45); + image2->opacity(127); auto mask2 = tvg::Shape::gen(); mask2->appendCircle(375, 700, 50, 50); @@ -225,6 +232,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) image3->translate(650, 650); image3->scale(0.5f); image3->rotate(45); + image3->opacity(127); auto mask3 = tvg::Shape::gen(); mask3->appendCircle(625, 700, 50, 50); @@ -278,6 +286,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill2->linear(300, 850, 400, 950); fill2->colorStops(colorStops, 2); shape2->fill(std::move(fill2)); + shape2->opacity(127); auto mask2 = tvg::Shape::gen(); mask2->appendCircle(400, 900, 50, 50); @@ -296,6 +305,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) fill3->linear(550, 850, 650, 950); fill3->colorStops(colorStops, 2); shape3->fill(std::move(fill3)); + shape3->opacity(127); auto mask3 = tvg::Shape::gen(); mask3->appendCircle(650, 900, 50, 50); diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 58f40d22..ecf3f7e6 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -463,46 +463,6 @@ static inline uint32_t opBlendSoftLight(uint32_t s, uint32_t d, TVG_UNUSED uint8 return JOIN(255, c1, c2, c3); } -static inline uint32_t opMaskAdd(uint32_t s, uint32_t d, uint8_t a) -{ - return opBlendNormal(s, d, a); -} - -static inline uint32_t opMaskSubtract(uint32_t s, uint32_t d, uint8_t a) -{ - return ALPHA_BLEND(d, MULTIPLY(IA(s), a)); -} - -static inline uint32_t opMaskDifference(uint32_t s, uint32_t d, uint8_t a) -{ - auto t = ALPHA_BLEND(s, a); - return ALPHA_BLEND(t, IA(d)) + ALPHA_BLEND(d, IA(t)); -} - -static inline uint32_t opMaskIntersect(uint32_t s, uint32_t d, uint8_t a) -{ - return ALPHA_BLEND(d, MULTIPLY(IA(s), a)); -} - -static inline uint32_t opMaskPreAdd(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) -{ - return opBlendPreNormal(s, d, a); -} - -static inline uint32_t opMaskPreSubtract(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) -{ - return ALPHA_BLEND(d, IA(s)); -} - -static inline uint32_t opMaskPreDifference(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) -{ - return ALPHA_BLEND(s, IA(d)) + ALPHA_BLEND(d, IA(s)); -} - -static inline uint32_t opMaskPreIntersect(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) -{ - return ALPHA_BLEND(d, MULTIPLY(a, IA(s))); -} int64_t mathMultiply(int64_t a, int64_t b); int64_t mathDivide(int64_t a, int64_t b); @@ -554,9 +514,11 @@ void fillFree(SwFill* fill); //OPTIMIZE_ME: Skip the function pointer access void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver. void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a); //blending + BlendingMethod(op2) ver. +void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a); //direct masking ver. void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver. void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, uint8_t a); //blending ver. void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a); //blending + BlendingMethod(op2) ver. +void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a) ; //direct masking ver. void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity); //masking ver. SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 1c6eb4e4..77eca813 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -279,6 +279,27 @@ void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 } +void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a) +{ + auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; + auto ry = (x + 0.5f) * fill->radial.a21 + (y + 0.5f) * fill->radial.a22 + fill->radial.shiftY; + + // detSecondDerivative = d(detFirstDerivative)/dx = d( d(det)/dx )/dx + auto detSecondDerivative = fill->radial.detSecDeriv; + // detFirstDerivative = d(det)/dx + auto detFirstDerivative = 2.0f * (fill->radial.a11 * rx + fill->radial.a21 * ry) + 0.5f * detSecondDerivative; + auto det = rx * rx + ry * ry; + + for (uint32_t i = 0 ; i < len ; ++i, ++dst, ++cmp) { + auto tmp = op(_pixel(fill, sqrtf(det)), *cmp, a); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + det += detFirstDerivative; + detFirstDerivative += detSecondDerivative; + } +} + + + void fillRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a) { auto rx = (x + 0.5f) * fill->radial.a11 + (y + 0.5f) * fill->radial.a12 + fill->radial.shiftX; @@ -423,6 +444,51 @@ void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint3 } +void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a) +{ + //Rotation + float rx = x + 0.5f; + float ry = y + 0.5f; + float t = (fill->linear.dx * rx + fill->linear.dy * ry + fill->linear.offset) * (GRADIENT_STOP_SIZE - 1); + float inc = (fill->linear.dx) * (GRADIENT_STOP_SIZE - 1); + + if (mathZero(inc)) { + auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); + for (uint32_t i = 0; i < len; ++i, ++dst, ++cmp) { + auto tmp = op(color, *cmp, a); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + } + return; + } + + auto vMax = static_cast(INT32_MAX >> (FIXPT_BITS + 1)); + auto vMin = -vMax; + auto v = t + (inc * len); + + //we can use fixed point math + if (v < vMax && v > vMin) { + auto t2 = static_cast(t * FIXPT_SIZE); + auto inc2 = static_cast(inc * FIXPT_SIZE); + for (uint32_t j = 0; j < len; ++j, ++dst, ++cmp) { + auto tmp = op(_fixedPixel(fill, t2), *cmp, a); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + t2 += inc2; + } + //we have to fallback to float math + } else { + uint32_t counter = 0; + while (counter++ < len) { + auto tmp = op(_pixel(fill, t / GRADIENT_STOP_SIZE), *cmp, a); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + ++dst; + ++cmp; + t += inc; + } + } +} + + + void fillLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, SwBlender op, SwBlender op2, uint8_t a) { //Rotation diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index bd32bf0b..36ba09f3 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -44,6 +44,11 @@ struct FillLinear fillLinear(fill, dst, y, x, len, op, a); } + void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a) + { + fillLinear(fill, dst, y, x, len, cmp, op, a); + } + void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity) { fillLinear(fill, dst, y, x, len, cmp, alpha, csize, opacity); @@ -63,6 +68,11 @@ struct FillRadial fillRadial(fill, dst, y, x, len, op, a); } + void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint32_t* cmp, SwBlender op, uint8_t a) + { + fillRadial(fill, dst, y, x, len, cmp, op, a); + } + void operator()(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len, uint8_t* cmp, SwAlpha alpha, uint8_t csize, uint8_t opacity) { fillRadial(fill, dst, y, x, len, cmp, alpha, csize, opacity); @@ -162,9 +172,15 @@ static inline uint32_t _opMaskAdd(uint32_t s, uint32_t d, uint8_t a) } -static inline uint32_t _opMaskSubtract(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a) +static inline uint32_t _opMaskSubtract(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) { - return ALPHA_BLEND(d, a); + return ALPHA_BLEND(s, IA(d)); +} + + +static inline uint32_t _opMaskIntersect(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a) +{ + return ALPHA_BLEND(s, A(d)); } @@ -182,14 +198,28 @@ static inline uint32_t _opAMaskAdd(uint32_t s, uint32_t d, uint8_t a) static inline uint32_t _opAMaskSubtract(TVG_UNUSED uint32_t s, uint32_t d, uint8_t a) { - return ALPHA_BLEND(d, IA(ALPHA_BLEND(s, a))); + return ALPHA_BLEND(s, MULTIPLY(IA(d), a)); } static inline uint32_t _opAMaskDifference(uint32_t s, uint32_t d, uint8_t a) { - auto t = ALPHA_BLEND(s, a); - return ALPHA_BLEND(t, IA(d)) + ALPHA_BLEND(d, IA(t)); + auto t = ALPHA_BLEND(s, a); + return ALPHA_BLEND(t, IA(d)) + ALPHA_BLEND(d, IA(t)); +} + + +static inline uint32_t _opAMaskIntersect(uint32_t s, uint32_t d, uint8_t a) +{ + return ALPHA_BLEND(s, MULTIPLY(A(d), a)); +} + + +static inline bool _direct(CompositeMethod method) +{ + //subtract & Intersect allows the direct composition + if (method == CompositeMethod::SubtractMask || method == CompositeMethod::IntersectMask) return true; + return false; } @@ -199,6 +229,7 @@ static inline SwBlender _getMaskOp(CompositeMethod method) case CompositeMethod::AddMask: return _opMaskAdd; case CompositeMethod::SubtractMask: return _opMaskSubtract; case CompositeMethod::DifferenceMask: return _opMaskDifference; + case CompositeMethod::IntersectMask: return _opMaskIntersect; default: return nullptr; } } @@ -210,6 +241,7 @@ static inline SwBlender _getAMaskOp(CompositeMethod method) case CompositeMethod::AddMask: return _opAMaskAdd; case CompositeMethod::SubtractMask: return _opAMaskSubtract; case CompositeMethod::DifferenceMask: return _opAMaskDifference; + case CompositeMethod::IntersectMask: return _opAMaskIntersect; default: return nullptr; } } @@ -284,7 +316,7 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t /* Rect */ /************************************************************************/ -static void _rasterMaskedRectDup(SwSurface* surface, const SwBBox& region, SwBlender opMask, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static bool _rasterCompositeMaskedRect(SwSurface* surface, const SwBBox& region, SwBlender maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { auto w = static_cast(region.max.x - region.min.x); auto h = static_cast(region.max.y - region.min.y); @@ -296,45 +328,33 @@ static void _rasterMaskedRectDup(SwSurface* surface, const SwBBox& region, SwBle for (uint32_t y = 0; y < h; ++y) { auto cmp = cbuffer; for (uint32_t x = 0; x < w; ++x, ++cmp) { - *cmp = opMask(color, *cmp, ialpha); + *cmp = maskOp(color, *cmp, ialpha); } cbuffer += cstride; } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); } -static void _rasterMaskedRectInt(SwSurface* surface, const SwBBox& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static bool _rasterDirectMaskedRect(SwSurface* surface, const SwBBox& region, SwBlender maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { auto w = static_cast(region.max.x - region.min.x); auto h = static_cast(region.max.y - region.min.y); - auto cstride = surface->compositor->image.stride; + auto cbuffer = surface->compositor->image.buf32 + (region.min.y * surface->compositor->image.stride + region.min.x); //compositor buffer + auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); //destination buffer + auto color = surface->join(r, g, b, a); - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - auto cmp = surface->compositor->image.buf32 + (y * cstride + surface->compositor->bbox.min.x); - if (y == region.min.y) { - for (auto y2 = y; y2 < region.max.y; ++y2) { - auto tmp = cmp; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (x == region.min.x) { - for (uint32_t i = 0; i < w; ++i, ++tmp) { - *tmp = ALPHA_BLEND(*tmp, a); - } - x += w; - } else { - *tmp = 0; - ++tmp; - ++x; - } - } - cmp += cstride; - } - y += (h - 1); - } else { - rasterPixel32(cmp, 0x00000000, 0, w); - cmp += cstride; + for (uint32_t y = 0; y < h; ++y) { + auto cmp = cbuffer; + auto dst = dbuffer; + for (uint32_t x = 0; x < w; ++x, ++cmp, ++dst) { + auto tmp = maskOp(color, *cmp, 0); //not use alpha. + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } + cbuffer += surface->compositor->image.stride; + dbuffer += surface->stride; } + return true; } @@ -343,19 +363,13 @@ static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint8_t //32bit channels composition if (surface->channelSize != sizeof(uint32_t)) return false; - TVGLOG("SW_ENGINE", "Masked(%d) Rect [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.max.y, region.min.y); + TVGLOG("SW_ENGINE", "Masked(%d) Rect [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterMaskedRectInt(surface, region, r, g, b, a); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterMaskedRectDup(surface, region, opMask, r, g, b, a); - } else { - return false; - } + auto maskOp = _getMaskOp(surface->compositor->method); - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + if (_direct(surface->compositor->method)) return _rasterDirectMaskedRect(surface, region, maskOp, r, g, b, a); + else return _rasterCompositeMaskedRect(surface, region, maskOp, r, g, b, a); + return false; } @@ -471,7 +485,7 @@ static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint8_t r, uin /* Rle */ /************************************************************************/ -static void _rasterMaskedRleDup(SwSurface* surface, SwRleData* rle, SwBlender maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRleData* rle, SwBlender maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { auto span = rle->spans; auto cbuffer = surface->compositor->image.buf32; @@ -488,10 +502,11 @@ static void _rasterMaskedRleDup(SwSurface* surface, SwRleData* rle, SwBlender ma *cmp = maskOp(src, *cmp, ialpha); } } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); } -static void _rasterMaskedRleInt(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static bool _rasterDirectMaskedRle(SwSurface* surface, SwRleData* rle, SwBlender maskOp, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { auto span = rle->spans; auto cbuffer = surface->compositor->image.buf32; @@ -499,25 +514,17 @@ static void _rasterMaskedRleInt(SwSurface* surface, SwRleData* rle, uint8_t r, u auto color = surface->join(r, g, b, a); uint32_t src; - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - auto cmp = &cbuffer[y * cstride]; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) { - if (span->coverage == 255) src = color; - else src = ALPHA_BLEND(color, span->coverage); - auto alpha = A(src); - for (uint32_t i = 0; i < span->len; ++i) { - cmp[x + i] = ALPHA_BLEND(cmp[x + i], alpha); - } - x += span->len; - ++span; - } else { - cmp[x] = 0; - ++x; - } + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + auto cmp = &cbuffer[span->y * cstride + span->x]; + auto dst = &surface->buf32[span->y * surface->stride + span->x]; + if (span->coverage == 255) src = color; + else src = ALPHA_BLEND(color, span->coverage); + for (auto x = 0; x < span->len; ++x, ++cmp, ++dst) { + auto tmp = maskOp(src, *cmp, 0); //not use alpha + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } } + return true; } @@ -528,17 +535,11 @@ static bool _rasterMaskedRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint //32bit channels composition if (surface->channelSize != sizeof(uint32_t)) return false; - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterMaskedRleInt(surface, rle, r, g, b, a); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterMaskedRleDup(surface, rle, opMask, r, g, b, a); - } else { - return false; - } + auto maskOp = _getMaskOp(surface->compositor->method); - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + if (_direct(surface->compositor->method)) return _rasterDirectMaskedRle(surface, rle, maskOp, r, g, b, a); + else return _rasterCompositeMaskedRle(surface, rle, maskOp, r, g, b, a); + return false; } @@ -668,29 +669,11 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, } -/************************************************************************/ -/* RLE Transformed Image */ -/************************************************************************/ - -static bool _transformedRleImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint8_t opacity) -{ - auto ret = _rasterTexmapPolygon(surface, image, transform, nullptr, opacity); - - //Masking Composition - if (_compositing(surface) && _masking(surface)) { - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); - } - - return ret; - -} - - /************************************************************************/ /* RLE Scaled Image */ /************************************************************************/ -static void _rasterScaledMaskedRleImageDup(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) +static bool _rasterCompositeScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); @@ -718,47 +701,42 @@ static void _rasterScaledMaskedRleImageDup(SwSurface* surface, const SwImage* im } } } + return true; } -static void _rasterScaledMaskedRleImageInt(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity) +static bool _rasterDirectScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); auto sampleSize2 = sampleSize * sampleSize; auto span = image->rle->spans; - auto cbuffer = surface->compositor->image.buf32; - auto cstride = surface->compositor->image.stride; - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - auto cmp = &cbuffer[y * cstride]; - for (auto x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x) { - if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; - auto alpha = MULTIPLY(span->coverage, opacity); - if (alpha == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - auto sx = (x + i) * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(src)); - } - } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto sx = (x + i) * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(ALPHA_BLEND(src, alpha))); - } - } - x += span->len - 1; - ++span; - } else { - cmp[x] = 0; + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto sy = span->y * itransform->e22 + itransform->e23; + if ((uint32_t)sy >= image->h) continue; + auto cmp = &surface->compositor->image.buf32[span->y * surface->compositor->image.stride + span->x]; + auto dst = &surface->buf32[span->y * surface->stride + span->x]; + auto a = MULTIPLY(span->coverage, opacity); + if (a == 255) { + for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp, ++dst) { + auto sx = x * itransform->e11 + itransform->e13; + if ((uint32_t)sx >= image->w) continue; + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); + auto tmp = maskOp(src, *cmp, 0); //not use alpha + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + } + } else { + for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp, ++dst) { + auto sx = x * itransform->e11 + itransform->e13; + if ((uint32_t)sx >= image->w) continue; + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); + auto tmp = amaskOp(src, *cmp, a); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } } } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); } @@ -766,16 +744,12 @@ static bool _rasterScaledMaskedRleImage(SwSurface* surface, const SwImage* image { TVGLOG("SW_ENGINE", "Scaled Masked(%d) Rle Image", (int)surface->compositor->method); - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterScaledMaskedRleImageInt(surface, image, itransform, region, opacity); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterScaledMaskedRleImageDup(surface, image, itransform, region, opMask, _getAMaskOp(surface->compositor->method), opacity); - } else { - return false; - } - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + auto maskOp = _getMaskOp(surface->compositor->method); + auto amaskOp = _getAMaskOp(surface->compositor->method); + + if (_direct(surface->compositor->method)) return _rasterDirectScaledMaskedRleImage(surface, image, itransform, region, maskOp, amaskOp, opacity); + else return _rasterCompositeScaledMaskedRleImage(surface, image, itransform, region, maskOp, amaskOp, opacity); + return false; } @@ -917,7 +891,7 @@ static bool _scaledRleImage(SwSurface* surface, const SwImage* image, const Matr /* RLE Direct Image */ /************************************************************************/ -static void _rasterDirectMaskedRleImageDup(SwSurface* surface, const SwImage* image, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) +static bool _rasterCompositeDirectMaskedRleImage(SwSurface* surface, const SwImage* image, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto span = image->rle->spans; auto cbuffer = surface->compositor->image.buf32; @@ -937,40 +911,34 @@ static void _rasterDirectMaskedRleImageDup(SwSurface* surface, const SwImage* im } } } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); } -static void _rasterDirectMaskedRleImageInt(SwSurface* surface, const SwImage* image, uint8_t opacity) +static bool _rasterDirectDirectMaskedRleImage(SwSurface* surface, const SwImage* image, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto span = image->rle->spans; auto cbuffer = surface->compositor->image.buf32; auto ctride = surface->compositor->image.stride; - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - auto cmp = &cbuffer[y * ctride]; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) { - auto alpha = MULTIPLY(span->coverage, opacity); - auto src = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox); - if (alpha == 255) { - for (uint32_t i = 0; i < span->len; ++i, ++src) { - cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(*src)); - } - } else { - for (uint32_t i = 0; i < span->len; ++i, ++src) { - auto t = ALPHA_BLEND(*src, alpha); - cmp[x + i] = ALPHA_BLEND(cmp[x + i], A(t)); - } - } - x += span->len; - ++span; - } else { - cmp[x] = 0; - ++x; + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + auto src = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox); + auto cmp = &cbuffer[span->y * ctride + span->x]; + auto dst = &surface->buf32[span->y * surface->stride + span->x]; + auto alpha = MULTIPLY(span->coverage, opacity); + if (alpha == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++src, ++cmp, ++dst) { + auto tmp = maskOp(*src, *cmp, 0); //not use alpha + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + } + } else { + for (uint32_t x = 0; x < span->len; ++x, ++src, ++cmp, ++dst) { + auto tmp = amaskOp(*src, *cmp, alpha); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } } } + return true; } @@ -978,17 +946,12 @@ static bool _rasterDirectMaskedRleImage(SwSurface* surface, const SwImage* image { TVGLOG("SW_ENGINE", "Direct Masked(%d) Rle Image", (int)surface->compositor->method); - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterDirectMaskedRleImageInt(surface, image, opacity); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterDirectMaskedRleImageDup(surface, image, opMask, _getAMaskOp(surface->compositor->method), opacity); - } else { - return false; - } + auto maskOp = _getMaskOp(surface->compositor->method); + auto amaskOp = _getAMaskOp(surface->compositor->method); - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + if (_direct(surface->compositor->method)) _rasterDirectDirectMaskedRleImage(surface, image, maskOp, amaskOp, opacity); + else return _rasterCompositeDirectMaskedRleImage(surface, image, maskOp, amaskOp, opacity); + return false; } @@ -1088,35 +1051,11 @@ static bool _directRleImage(SwSurface* surface, const SwImage* image, uint8_t op } -/************************************************************************/ -/* Transformed Image */ -/************************************************************************/ - -static bool _transformedImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity) -{ - auto ret = _rasterTexmapPolygon(surface, image, transform, ®ion, opacity); - - //Masking Composition - if (_compositing(surface) && _masking(surface)) { - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); - } - - return ret; -} - - -static bool _transformedImageMesh(SwSurface* surface, const SwImage* image, const RenderMesh* mesh, const Matrix* transform, const SwBBox* region, uint8_t opacity) -{ - //TODO: Not completed for all cases. - return _rasterTexmapPolygonMesh(surface, image, mesh, transform, region, opacity); -} - - /************************************************************************/ /*Scaled Image */ /************************************************************************/ -static void _rasterScaledMaskedImageDup(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) +static bool _rasterCompositeScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); @@ -1145,61 +1084,45 @@ static void _rasterScaledMaskedImageDup(SwSurface* surface, const SwImage* image } cbuffer += cstride; } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); } -static void _rasterScaledMaskedImageInt(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity) + +static bool _rasterDirectScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); auto sampleSize2 = sampleSize * sampleSize; - auto h = static_cast(region.max.y - region.min.y); - auto w = static_cast(region.max.x - region.min.x); auto cstride = surface->compositor->image.stride; - auto cbuffer = surface->compositor->image.buf32 + (surface->compositor->bbox.min.y * cstride + surface->compositor->bbox.min.x); + auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x); + auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - if (y == region.min.y) { - auto cbuffer2 = cbuffer; - for (auto y2 = y; y2 < region.max.y; ++y2) { - auto sy = y2 * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; - auto tmp = cbuffer2; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (x == region.min.x) { - if (opacity == 255) { - for (uint32_t i = 0; i < w; ++i, ++tmp) { - auto sx = (x + i) * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *tmp = ALPHA_BLEND(*tmp, A(src)); - } - } else { - for (uint32_t i = 0; i < w; ++i, ++tmp) { - auto sx = (x + i) * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); - *tmp = ALPHA_BLEND(*tmp, A(src)); - } - } - x += w; - } else { - *tmp = 0; - ++tmp; - ++x; - } - } - cbuffer2 += cstride; + for (auto y = region.min.y; y < region.max.y; ++y) { + auto sy = y * itransform->e22 + itransform->e23; + if ((uint32_t)sy >= image->h) continue; + auto cmp = cbuffer; + auto dst = dbuffer; + if (opacity == 255) { + for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { + auto sx = x * itransform->e11 + itransform->e13; + if ((uint32_t)sx >= image->w) continue; + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); + auto tmp = maskOp(src, *cmp, 0); //not use alpha + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } - y += (h - 1); } else { - auto tmp = cbuffer; - for (auto x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x, ++tmp) { - *tmp = 0; + for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { + auto sx = x * itransform->e11 + itransform->e13; + if ((uint32_t)sx >= image->w) continue; + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); + auto tmp = amaskOp(src, *cmp, opacity); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } } cbuffer += cstride; + dbuffer += surface->stride; } + return true; } @@ -1207,17 +1130,12 @@ static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, c { TVGLOG("SW_ENGINE", "Scaled Masked(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterScaledMaskedImageInt(surface, image, itransform, region, opacity); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterScaledMaskedImageDup(surface, image, itransform, region, opMask, _getAMaskOp(surface->compositor->method), opacity); - } else { - return false; - } + auto maskOp = _getMaskOp(surface->compositor->method); + auto amaskOp = _getAMaskOp(surface->compositor->method); - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + if (_direct(surface->compositor->method)) return _rasterDirectScaledMaskedImage(surface, image, itransform, region, maskOp, amaskOp, opacity); + else return _rasterCompositeScaledMaskedImage(surface, image, itransform, region, maskOp, amaskOp, opacity); + return false; } @@ -1351,7 +1269,7 @@ static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* /* Direct Image */ /************************************************************************/ -static void _rasterDirectMaskedImageDup(SwSurface* surface, const SwImage* image, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) +static bool _rasterCompositeDirectMaskedImage(SwSurface* surface, const SwImage* image, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); @@ -1375,50 +1293,40 @@ static void _rasterDirectMaskedImageDup(SwSurface* surface, const SwImage* image cbuffer += cstride; sbuffer += image->stride; } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); } -static void _rasterDirectMaskedImageInt(SwSurface* surface, const SwImage* image, const SwBBox& region, uint8_t opacity) +static bool _rasterDirectDirectMaskedImage(SwSurface* surface, const SwImage* image, const SwBBox& region, SwBlender maskOp, SwBlender amaskOp, uint8_t opacity) { auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); auto cstride = surface->compositor->image.stride; - auto cbuffer = surface->compositor->image.buf32 + (surface->compositor->bbox.min.y * cstride + surface->compositor->bbox.min.x); - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - if (y == region.min.y) { - auto cbuffer2 = cbuffer; - for (auto y2 = y; y2 < region.max.y; ++y2) { - auto tmp = cbuffer2; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (x == region.min.x) { - auto src = &image->buf32[(y2 + image->oy) * image->stride + (x + image->ox)]; - if (opacity == 255) { - for (uint32_t i = 0; i < w; ++i, ++tmp, ++src) { - *tmp = ALPHA_BLEND(*tmp, A(*src)); - } - } else { - for (uint32_t i = 0; i < w; ++i, ++tmp, ++src) { - auto t = ALPHA_BLEND(*src, opacity); - *tmp = ALPHA_BLEND(*tmp, A(t)); - } - } - x += w; - } else { - *tmp = 0; - ++tmp; - ++x; - } - } - cbuffer2 += cstride; + auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x); //compositor buffer + auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); //destination buffer + auto sbuffer = image->buf32 + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox); + + for (uint32_t y = 0; y < h; ++y) { + auto cmp = cbuffer; + auto dst = dbuffer; + auto src = sbuffer; + if (opacity == 255) { + for (uint32_t x = 0; x < w; ++x, ++src, ++cmp, ++dst) { + auto tmp = maskOp(*src, *cmp, 0); //not use alpha + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } - y += (h - 1); } else { - rasterPixel32(cbuffer, 0x00000000, 0, surface->compositor->bbox.max.x - surface->compositor->bbox.min.x); + for (uint32_t x = 0; x < w; ++x, ++src, ++cmp, ++dst) { + auto tmp = amaskOp(*src, *cmp, opacity); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + } } cbuffer += cstride; + dbuffer += surface->stride; + sbuffer += image->stride; } + return true; } @@ -1426,16 +1334,12 @@ static bool _rasterDirectMaskedImage(SwSurface* surface, const SwImage* image, c { TVGLOG("SW_ENGINE", "Direct Masked(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterDirectMaskedImageInt(surface, image, region, opacity); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterDirectMaskedImageDup(surface, image, region, opMask, _getAMaskOp(surface->compositor->method), opacity); - } else { - return false; - } - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + auto maskOp = _getMaskOp(surface->compositor->method); + auto amaskOp = _getAMaskOp(surface->compositor->method); + + if (_direct(surface->compositor->method)) return _rasterDirectDirectMaskedImage(surface, image, region, maskOp, amaskOp, opacity); + else return _rasterCompositeDirectMaskedImage(surface, image, region, maskOp, amaskOp, opacity); + return false; } @@ -1549,12 +1453,12 @@ static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix* trans if (image->rle) { if (image->direct) return _directRleImage(surface, image, opacity); else if (image->scaled) return _scaledRleImage(surface, image, transform, region, opacity); - else return _transformedRleImage(surface, image, transform, opacity); + else return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity); //Whole Image } else { if (image->direct) return _directImage(surface, image, region, opacity); else if (image->scaled) return _scaledImage(surface, image, transform, region, opacity); - else return _transformedImage(surface, image, transform, region, opacity); + else return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity); } } @@ -1564,7 +1468,7 @@ static bool _rasterImage(SwSurface* surface, SwImage* image, const Matrix* trans /************************************************************************/ template -static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp) +static bool _rasterCompositeGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp) { auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); @@ -1575,41 +1479,25 @@ static void _rasterGradientMaskedRectDup(SwSurface* surface, const SwBBox& regio fillMethod()(fill, cbuffer, region.min.y + y, region.min.x, w, maskOp, 255); cbuffer += surface->stride; } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255); } template -static void _rasterGradientMaskedRectInt(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterDirectGradientMaskedRect(SwSurface* surface, const SwBBox& region, const SwFill* fill, SwBlender maskOp) { auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); auto cstride = surface->compositor->image.stride; + auto cbuffer = surface->compositor->image.buf32 + (region.min.y * cstride + region.min.x); + auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - auto cmp = surface->compositor->image.buf32 + (y * cstride + surface->compositor->bbox.min.x); - if (y == region.min.y) { - for (auto y2 = y; y2 < region.max.y; ++y2) { - auto tmp = cmp; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (x == region.min.x) { - fillMethod()(fill, tmp, y2, x, w, opMaskPreIntersect, 255); - x += w; - tmp += w; - } else { - *tmp = 0; - ++tmp; - ++x; - } - } - cmp += cstride; - } - y += (h - 1); - } else { - rasterPixel32(cmp, 0x00000000, 0, surface->compositor->bbox.max.x -surface->compositor->bbox.min.x); - cmp += cstride; - } + for (uint32_t y = 0; y < h; ++y) { + fillMethod()(fill, dbuffer, region.min.y + y, region.min.x, w, cbuffer, maskOp, 255); + cbuffer += cstride; + dbuffer += surface->stride; } + return true; } @@ -1618,16 +1506,13 @@ static bool _rasterGradientMaskedRect(SwSurface* surface, const SwBBox& region, { auto method = surface->compositor->method; - TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); + TVGLOG("SW_ENGINE", "Masked(%d) Gradient [Region: %lu %lu %lu %lu]", (int)method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y); - if (method == CompositeMethod::AddMask) _rasterGradientMaskedRectDup(surface, region, fill, opMaskPreAdd); - else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRectDup(surface, region, fill, opMaskPreSubtract); - else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRectDup(surface, region, fill, opMaskPreDifference); - else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRectInt(surface, region, fill); - else return false; + auto amaskOp = _getAMaskOp(method); - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255); + if (_direct(method)) return _rasterDirectGradientMaskedRect(surface, region, fill, amaskOp); + else return _rasterCompositeGradientMaskedRect(surface, region, fill, amaskOp); + return false; } @@ -1740,7 +1625,7 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, /************************************************************************/ template -static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp) +static bool _rasterCompositeGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp) { auto span = rle->spans; auto cstride = surface->compositor->image.stride; @@ -1750,48 +1635,39 @@ static void _rasterGradientMaskedRleDup(SwSurface* surface, const SwRleData* rle auto cmp = &cbuffer[span->y * cstride + span->x]; fillMethod()(fill, cmp, span->y, span->x, span->len, maskOp, span->coverage); } + return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255); } template -static void _rasterGradientMaskedRleInt(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill, SwBlender maskOp) { auto span = rle->spans; auto cstride = surface->compositor->image.stride; auto cbuffer = surface->compositor->image.buf32; + auto dbuffer = surface->buf32; - for (auto y = surface->compositor->bbox.min.y; y < surface->compositor->bbox.max.y; ++y) { - auto cmp = &cbuffer[y * cstride]; - auto x = surface->compositor->bbox.min.x; - while (x < surface->compositor->bbox.max.x) { - if (y == span->y && x == span->x && x + span->len <= surface->compositor->bbox.max.x) { - fillMethod()(fill, cmp, span->y, span->x, span->len, opMaskIntersect, span->coverage); - x += span->len; - ++span; - } else { - cmp[x] = 0; - ++x; - } - } + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + auto cmp = &cbuffer[span->y * cstride + span->x]; + auto dst = &dbuffer[span->y * surface->stride + span->x]; + fillMethod()(fill, dst, span->y, span->x, span->len, cmp, maskOp, span->coverage); } + return true; } template static bool _rasterGradientMaskedRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - TVGLOG("SW_ENGINE", "Masked(%d) Rle Linear Gradient", (int)surface->compositor->method); - auto method = surface->compositor->method; - if (method == CompositeMethod::AddMask) _rasterGradientMaskedRleDup(surface, rle, fill, opMaskAdd); - else if (method == CompositeMethod::SubtractMask) _rasterGradientMaskedRleDup(surface, rle, fill, opMaskSubtract); - else if (method == CompositeMethod::DifferenceMask) _rasterGradientMaskedRleDup(surface, rle, fill, opMaskDifference); - else if (method == CompositeMethod::IntersectMask) _rasterGradientMaskedRleInt(surface, rle, fill); - else return false; + TVGLOG("SW_ENGINE", "Masked(%d) Rle Linear Gradient", (int)method); - //Masking Composition - return _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox, 255); + auto amaskOp = _getAMaskOp(method); + + if (_direct(method)) return _rasterDirectGradientMaskedRle(surface, rle, fill, amaskOp); + else return _rasterCompositeGradientMaskedRle(surface, rle, fill, amaskOp); + return false; } @@ -2059,7 +1935,6 @@ bool rasterShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8 g = MULTIPLY(g, a); b = MULTIPLY(b, a); } - if (shape->fastTrack) return _rasterRect(surface, shape->bbox, r, g, b, a); else return _rasterRle(surface, shape->rle, r, g, b, a); } @@ -2091,7 +1966,7 @@ bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, con //TODO: case: _rasterRGBImageMesh() //TODO: case: _rasterGrayscaleImageMesh() //TODO: case: _rasterAlphaImageMesh() - if (mesh && mesh->triangleCnt > 0) return _transformedImageMesh(surface, image, mesh, transform, &bbox, opacity); + if (mesh && mesh->triangleCnt > 0) return _rasterTexmapPolygonMesh(surface, image, mesh, transform, &bbox, opacity); else return _rasterImage(surface, image, transform, bbox, opacity); } diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h index 4b30c52e..938a2a39 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmap.h +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -70,186 +70,11 @@ static bool _arrange(const SwImage* image, const SwBBox* region, int& yStart, in } -static void _rasterMaskedPolygonImageSegmentInt(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag) -{ - 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->buf32; - int32_t sw = static_cast(image->stride); - int32_t sh = image->h; - int32_t x1, x2, ar, ab, iru, irv, px, ay; - int32_t vv = 0, uu = 0; - int32_t minx = INT32_MAX, maxx = INT32_MIN; - float dx, u, v, iptr; - auto cbuffer = surface->compositor->image.buf32; - SwSpan* span = nullptr; //used only when rle based. - - if (!_arrange(image, region, yStart, yEnd)) return; - - //Clear out of the Polygon vertical ranges - auto size = surface->compositor->bbox.max.x - surface->compositor->bbox.min.x; - if (dirFlag == 1) { //left top case. - for(int y = surface->compositor->bbox.min.y; y < yStart; ++y) { - rasterPixel32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size); - } - } - if (dirFlag == 4) { //right bottom case. - for(int y = yEnd; y < surface->compositor->bbox.max.y; ++y) { - rasterPixel32(surface->compositor->image.buf32 + y * surface->compositor->image.stride, 0, surface->compositor->bbox.min.x, size); - } - } - - //Loop through all lines in the segment - uint32_t spanIdx = 0; - - if (region) { - minx = region->min.x; - maxx = region->max.x; - } else { - span = image->rle->spans; - while (span->y < yStart) { - ++span; - ++spanIdx; - } - } - - for (int32_t y = yStart; y < yEnd; ++y) { - auto cmp = &cbuffer[y * surface->compositor->image.stride]; - x1 = (int32_t)_xa; - x2 = (int32_t)_xb; - - if (!region) { - minx = INT32_MAX; - maxx = INT32_MIN; - //one single row, could be consisted of multiple spans. - while (span->y == y && spanIdx < image->rle->size) { - if (minx > span->x) minx = span->x; - if (maxx < span->x + span->len) maxx = span->x + span->len; - ++span; - ++spanIdx; - } - } - - if (x1 < minx) x1 = minx; - if (x2 > maxx) x2 = maxx; - - //Anti-Aliasing frames - //FIXME: this aa must be applied before masking op - ay = y - aaSpans->yStart; - if (aaSpans->lines[ay].x[0] > x1) aaSpans->lines[ay].x[0] = x1; - if (aaSpans->lines[ay].x[1] < x2) aaSpans->lines[ay].x[1] = x2; - - //Range allowed - if ((x2 - x1) >= 1 && (x1 < maxx) && (x2 > minx)) { - for (int32_t x = surface->compositor->bbox.min.x; x < surface->compositor->bbox.max.x; ++x) { - //Range allowed - if (x >= x1 && x < x2) { - //Perform subtexel pre-stepping on UV - dx = 1 - (_xa - x1); - u = _ua + dx * _dudx; - v = _va + dx * _dvdx; - if ((uint32_t)v >= image->h) { - cmp[x] = 0; - } else { - if (opacity == 255) { - uu = (int) u; - if (uu >= sw) continue; - vv = (int) v; - if (vv >= sh) continue; - - 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(px, px2, ar); - } - /* 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(px2, px3, ar); - } - px = INTERPOLATE(px, px2, ab); - } - cmp[x] = ALPHA_BLEND(cmp[x], A(px)); - - //Step UV horizontally - u += _dudx; - v += _dvdx; - } else { - uu = (int) u; - if (uu >= sw) continue; - vv = (int) v; - if (vv >= sh) continue; - - 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(px, px2, ar); - } - /* 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(px2, px3, ar); - } - px = INTERPOLATE(px, px2, ab); - } - cmp[x] = ALPHA_BLEND(cmp[x], MULTIPLY(A(px), opacity)); - - //Step UV horizontally - u += _dudx; - v += _dvdx; - } - } - } else { - //Clear out of polygon horizontal range - if (x < x1 && (dirFlag == 1 || dirFlag == 2)) cmp[x] = 0; - else if (x >= x2 && (dirFlag == 3 || dirFlag == 4)) cmp[x] = 0; - } - } - } - //Step along both edges - _xa += _dxdya; - _xb += _dxdyb; - _ua += _dudya; - _va += _dvdya; - } - xa = _xa; - xb = _xb; - ua = _ua; - va = _va; -} - - -static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImage* image, const SwBBox* region, SwBlender maskOp, SwBlender amaskOp, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity) +static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag = 0) { + auto maskOp = _getMaskOp(surface->compositor->method); + auto amaskOp = _getAMaskOp(surface->compositor->method); + auto direct = _direct(surface->compositor->method); float _dudx = dudx, _dvdx = dvdx; float _dxdya = dxdya, _dxdyb = dxdyb, _dudya = dudya, _dvdya = dvdya; float _xa = xa, _xb = xb, _ua = ua, _va = va; @@ -262,7 +87,7 @@ static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImag float dx, u, v, iptr; SwSpan* span = nullptr; //used only when rle based. - if (!_arrange(image, region, yStart, yEnd)) return; + if (!_arrange(image, region, yStart, yEnd)) return false; //Loop through all lines in the segment uint32_t spanIdx = 0; @@ -314,6 +139,7 @@ static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImag x = x1; auto cmp = &surface->compositor->image.buf32[y * surface->compositor->image.stride + x1]; + auto dst = &surface->buf32[y * surface->stride + x1]; if (opacity == 255) { //Draw horizontal line @@ -349,7 +175,13 @@ static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImag } px = INTERPOLATE(px, px2, ab); } - *cmp = maskOp(px, *cmp, IA(px)); + if (direct) { + auto tmp = maskOp(px, *cmp, 0); //not use alpha + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + ++dst; + } else { + *cmp = maskOp(px, *cmp, IA(px)); + } ++cmp; //Step UV horizontally @@ -392,7 +224,14 @@ static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImag } px = INTERPOLATE(px, px2, ab); } - *cmp = amaskOp(px, *cmp, opacity); + + if (direct) { + auto tmp = amaskOp(px, *cmp, opacity); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); + ++dst; + } else { + *cmp = amaskOp(px, *cmp, opacity); + } ++cmp; //Step UV horizontally @@ -418,17 +257,8 @@ static void _rasterMaskedPolygonImageSegmentDup(SwSurface* surface, const SwImag xb = _xb; ua = _ua; va = _va; -} - -static void _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, AASpans* aaSpans, uint8_t opacity, uint8_t dirFlag = 0) -{ - if (surface->compositor->method == CompositeMethod::IntersectMask) { - _rasterMaskedPolygonImageSegmentInt(surface, image, region, yStart, yEnd, aaSpans, opacity, dirFlag); - } else if (auto opMask = _getMaskOp(surface->compositor->method)) { - //Other Masking operations: Add, Subtract, Difference ... - _rasterMaskedPolygonImageSegmentDup(surface, image, region, opMask, _getAMaskOp(surface->compositor->method), yStart, yEnd, aaSpans, opacity); - } + return true; } @@ -1294,6 +1124,9 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const _rasterPolygonImage(surface, image, region, polygon, aaSpans, opacity); + if (_compositing(surface) && _masking(surface) && !_direct(surface->compositor->method)) { + _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + } return _apply(surface, aaSpans); } @@ -1342,15 +1175,15 @@ static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, c } // Get AA spans and step polygons again to draw - auto aaSpans = _AASpans(ys, ye, image, region); - if (aaSpans) { + if (auto aaSpans = _AASpans(ys, ye, image, region)) { for (uint32_t i = 0; i < mesh->triangleCnt; i++) { _rasterPolygonImage(surface, image, region, transformedTris[i], aaSpans, opacity); } - // Apply to surface (note: frees the AA spans) + if (_compositing(surface) && _masking(surface) && !_direct(surface->compositor->method)) { + _rasterDirectImage(surface, &surface->compositor->image, surface->compositor->bbox); + } _apply(surface, aaSpans); } free(transformedTris); - return true; } diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 959970cf..ed215795 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -641,8 +641,6 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) if (x + w > sw) w = (sw - x); if (y + h > sh) h = (sh - y); - TVGLOG("SW_ENGINE", "Using intermediate composition [Region: %d %d %d %d]", x, y, w, h); - cmp->compositor->recoverSfc = surface; cmp->compositor->recoverCmp = surface->compositor; cmp->compositor->valid = false; diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 8addb267..12b5ab63 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -83,6 +83,7 @@ using Size = Point; uint16_t THORVG_VERSION_NUMBER(); -#define P(A) ((A)->pImpl) //Access to pimpl. +#define P(A) ((A)->pImpl) //Access to pimpl. +#define PP(A) (((Paint*)(A))->pImpl) //Access to pimpl. #endif //_TVG_COMMON_H_ diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 5cfd2708..3a5eb7fc 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -166,7 +166,7 @@ bool Paint::Impl::render(RenderMethod& renderer) Create a composition image. */ if (compData && compData->method != CompositeMethod::ClipPath && !(compData->target->pImpl->ctxFlag & ContextFlag::FastTrack)) { auto region = smethod->bounds(renderer); - if (MASK_OPERATION(compData->method)) region.add(compData->target->pImpl->smethod->bounds(renderer)); + if (MASK_REGION_MERGING(compData->method)) region.add(compData->target->pImpl->smethod->bounds(renderer)); if (region.w == 0 || region.h == 0) return true; cmp = renderer.target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method)); if (renderer.beginComposite(cmp, CompositeMethod::None, 255)) { @@ -206,23 +206,20 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT auto method = compData->method; target->pImpl->ctxFlag &= ~ContextFlag::FastTrack; //reset - /* If transform has no rotation factors && ClipPath / AlphaMasking is a simple rectangle, - we can avoid regular ClipPath / AlphaMasking sequence but use viewport for performance */ + /* If the transformation has no rotational factors and the ClipPath/Alpha(InvAlpha)Masking involves a simple rectangle, + we can optimize by using the viewport instead of the regular ClipPath/AlphaMasking sequence for improved performance. */ auto tryFastTrack = false; if (target->identifier() == TVG_CLASS_ID_SHAPE) { if (method == CompositeMethod::ClipPath) tryFastTrack = true; - //OPTIMIZE HERE: Actually, this condition AlphaMask is useless. We can skip it? - else if (method == CompositeMethod::AlphaMask) { + else { auto shape = static_cast(target); uint8_t a; shape->fillColor(nullptr, nullptr, nullptr, &a); - if (a == 255 && shape->opacity() == 255 && !shape->fill()) tryFastTrack = true; - //OPTIMIZE HERE: Actually, this condition InvAlphaMask is useless. We can skip it? - } else if (method == CompositeMethod::InvAlphaMask) { - auto shape = static_cast(target); - uint8_t a; - shape->fillColor(nullptr, nullptr, nullptr, &a); - if ((a == 0 || shape->opacity() == 0) && !shape->fill()) tryFastTrack = true; + //no gradient fill & no compositions of the composition target. + if (!shape->fill() && !(PP(shape)->compData)) { + if (method == CompositeMethod::AlphaMask && a == 255 && PP(shape)->opacity == 255) tryFastTrack = true; + else if (method == CompositeMethod::InvAlphaMask && (a == 0 || PP(shape)->opacity == 0)) tryFastTrack = true; + } } if (tryFastTrack) { RenderRegion viewport2; diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 0a20e5a3..0e32e380 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -255,21 +255,22 @@ public: virtual bool endComposite(Compositor* cmp) = 0; }; -static inline bool MASK_OPERATION(CompositeMethod method) +static inline bool MASK_REGION_MERGING(CompositeMethod method) { switch(method) { case CompositeMethod::AlphaMask: case CompositeMethod::InvAlphaMask: case CompositeMethod::LumaMask: case CompositeMethod::InvLumaMask: - return false; - case CompositeMethod::AddMask: case CompositeMethod::SubtractMask: case CompositeMethod::IntersectMask: + return false; + //these might expand the rendering region + case CompositeMethod::AddMask: case CompositeMethod::DifferenceMask: return true; default: - TVGERR("RENDERER", "Unsupported Composite Size! = %d", (int)method); + TVGERR("RENDERER", "Unsupported Composite Method! = %d", (int)method); return false; } }