sw_engine: enable render region clipping during rendering

Implemented support for clipping shapes and images using a render region
bounding box at render time. This allows partial drawing of content,
laying the groundwork for upcoming partial rendering functionality.

for fast access of the drawing region from the linear rle data,
we introduced the binary search for begin/end of rle instead of
additional y index buffer.

There is a reason for not using a y-index buffer:
the shapes in the RLE are not single, continuous shapes
but multiple shapes scattered across the space.

which means that we need a double-associated data structure
per shapes for y indexing, and this data preparation wouldn't be
cheaper enough than realtime binary search especially animated data.

This also helps for current clipping performance by utilizing
the introduced fast-clipping region access.

issue: https://github.com/thorvg/thorvg/issues/1747
This commit is contained in:
Hermet Park 2025-06-11 22:49:17 +09:00
parent 830db9ecb7
commit b22ceaae7c
7 changed files with 244 additions and 171 deletions

View file

@ -23,6 +23,7 @@
#ifndef _TVG_SW_COMMON_H_ #ifndef _TVG_SW_COMMON_H_
#define _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_
#include <algorithm>
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgMath.h" #include "tvgMath.h"
#include "tvgRender.h" #include "tvgRender.h"
@ -117,22 +118,47 @@ struct SwSpan
uint16_t x, y; uint16_t x, y;
uint16_t len; uint16_t len;
uint8_t coverage; 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 struct SwRle
{ {
Array<SwSpan> spans; Array<SwSpan> 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 - 1, 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; } uint32_t size() const { return spans.count; }
SwSpan* data() const { return spans.data; } SwSpan* data() const { return spans.data; }
}; };
@ -566,15 +592,15 @@ SwOutline* mpoolReqDashOutline(SwMpool* mpool, unsigned idx);
void mpoolRetDashOutline(SwMpool* mpool, unsigned idx); void mpoolRetDashOutline(SwMpool* mpool, unsigned idx);
bool rasterCompositor(SwSurface* surface); bool rasterCompositor(SwSurface* surface);
bool rasterGradientShape(SwSurface* surface, SwShape* shape, const Fill* fdata, uint8_t opacity); bool rasterShape(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, RenderColor& c);
bool rasterShape(SwSurface* surface, SwShape* shape, RenderColor& c);
bool rasterTexmapPolygon(SwSurface* surface, const SwImage& image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity); bool rasterTexmapPolygon(SwSurface* surface, const SwImage& image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity);
bool rasterScaledImage(SwSurface* surface, const SwImage& image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity); bool rasterScaledImage(SwSurface* surface, const SwImage& image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity);
bool rasterDirectImage(SwSurface* surface, const SwImage& image, const RenderRegion& bbox, uint8_t opacity); bool rasterDirectImage(SwSurface* surface, const SwImage& image, const RenderRegion& bbox, uint8_t opacity);
bool rasterScaledRleImage(SwSurface* surface, const SwImage& image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity); bool rasterScaledRleImage(SwSurface* surface, const SwImage& image, const Matrix& transform, const RenderRegion& bbox, uint8_t opacity);
bool rasterDirectRleImage(SwSurface* surface, const SwImage& image, uint8_t opacity); bool rasterDirectRleImage(SwSurface* surface, const SwImage& image, const RenderRegion& bbox, uint8_t opacity);
bool rasterStroke(SwSurface* surface, SwShape* shape, RenderColor& c); bool rasterStroke(SwSurface* surface, SwShape* shape, const RenderRegion& bbox, RenderColor& c);
bool rasterGradientStroke(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);
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); 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 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); void rasterTranslucentPixel32(uint32_t* dst, uint32_t* src, uint32_t len, uint8_t opacity);

View file

@ -472,18 +472,21 @@ static bool _rasterRect(SwSurface* surface, const RenderRegion& bbox, const Rend
/* Rle */ /* 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 cbuffer = surface->compositor->image.buf8;
auto cstride = surface->compositor->image.stride; auto cstride = surface->compositor->image.stride;
const SwSpan* end;
int32_t x, len;
uint8_t src; uint8_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto cmp = &cbuffer[span->y * cstride + span->x]; span->fetch(bbox, x, len);
auto cmp = &cbuffer[span->y * cstride + x];
if (span->coverage == 255) src = a; if (span->coverage == 255) src = a;
else src = MULTIPLY(a, span->coverage); else src = MULTIPLY(a, span->coverage);
auto ialpha = 255 - src; 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); *cmp = maskOp(src, *cmp, ialpha);
} }
} }
@ -491,18 +494,21 @@ static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRle* rle, SwMask mas
} }
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 cbuffer = surface->compositor->image.buf8;
auto cstride = surface->compositor->image.stride; auto cstride = surface->compositor->image.stride;
const SwSpan* end;
int32_t x, len;
uint8_t src; uint8_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto cmp = &cbuffer[span->y * cstride + span->x]; span->fetch(bbox, x, len);
auto dst = &surface->buf8[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * cstride + x];
auto dst = &surface->buf8[span->y * surface->stride + x];
if (span->coverage == 255) src = a; if (span->coverage == 255) src = a;
else src = MULTIPLY(a, span->coverage); 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 auto tmp = maskOp(src, *cmp, 0); //not use alpha
*dst = tmp + MULTIPLY(*dst, ~tmp); *dst = tmp + MULTIPLY(*dst, ~tmp);
} }
@ -511,7 +517,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); TVGLOG("SW_ENGINE", "Masked(%d) Rle", (int)surface->compositor->method);
@ -519,30 +525,33 @@ static bool _rasterMaskedRle(SwSurface* surface, SwRle* rle, const RenderColor&
if (surface->channelSize != sizeof(uint8_t)) return false; if (surface->channelSize != sizeof(uint8_t)) return false;
auto maskOp = _getMaskOp(surface->compositor->method); auto maskOp = _getMaskOp(surface->compositor->method);
if (_direct(surface->compositor->method)) return _rasterDirectMaskedRle(surface, rle, maskOp, c.a); if (_direct(surface->compositor->method)) return _rasterDirectMaskedRle(surface, rle, bbox, maskOp, c.a);
else return _rasterCompositeMaskedRle(surface, rle, maskOp, c.a); else return _rasterCompositeMaskedRle(surface, rle, bbox, maskOp, c.a);
return false; 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); TVGLOG("SW_ENGINE", "Matted(%d) Rle", (int)surface->compositor->method);
auto cbuffer = surface->compositor->image.buf8; auto cbuffer = surface->compositor->image.buf8;
auto csize = surface->compositor->image.channelSize; auto csize = surface->compositor->image.channelSize;
auto alpha = surface->alpha(surface->compositor->method); auto alpha = surface->alpha(surface->compositor->method);
const SwSpan* end;
int32_t x, len;
//32bit channels //32bit channels
if (surface->channelSize == sizeof(uint32_t)) { if (surface->channelSize == sizeof(uint32_t)) {
uint32_t src; uint32_t src;
auto color = surface->join(c.r, c.g, c.b, c.a); auto color = surface->join(c.r, c.g, c.b, c.a);
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x]; span->fetch(bbox, x, len);
auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize]; 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; if (span->coverage == 255) src = color;
else src = ALPHA_BLEND(color, span->coverage); 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)); auto tmp = ALPHA_BLEND(src, alpha(cmp));
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
} }
@ -550,12 +559,13 @@ static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor&
//8bit grayscale //8bit grayscale
} else if (surface->channelSize == sizeof(uint8_t)) { } else if (surface->channelSize == sizeof(uint8_t)) {
uint8_t src; uint8_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x]; span->fetch(bbox, x, len);
auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize]; 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; if (span->coverage == 255) src = c.a;
else src = MULTIPLY(c.a, span->coverage); 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)); *dst = INTERPOLATE8(src, *dst, alpha(cmp));
} }
} }
@ -564,20 +574,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; if (surface->channelSize != sizeof(uint32_t)) return false;
auto color = surface->join(c.r, c.g, c.b, c.a); auto color = surface->join(c.r, c.g, c.b, c.a);
const SwSpan* end;
int32_t x, len;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x]; span->fetch(bbox, x, len);
auto dst = &surface->buf32[span->y * surface->stride + x];
if (span->coverage == 255) { 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); *dst = surface->blender(color, *dst, 255);
} }
} else { } 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); auto tmp = surface->blender(color, *dst, 255);
*dst = INTERPOLATE(tmp, *dst, span->coverage); *dst = INTERPOLATE(tmp, *dst, span->coverage);
} }
@ -587,44 +600,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) #if defined(THORVG_AVX_VECTOR_SUPPORT)
return avxRasterTranslucentRle(surface, rle, c); return avxRasterTranslucentRle(surface, rle, bbox, c);
#elif defined(THORVG_NEON_VECTOR_SUPPORT) #elif defined(THORVG_NEON_VECTOR_SUPPORT)
return neonRasterTranslucentRle(surface, rle, c); return neonRasterTranslucentRle(surface, rle, bbox, c);
#else #else
return cRasterTranslucentRle(surface, rle, c); return cRasterTranslucentRle(surface, rle, bbox, c);
#endif #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 //32bit channels
if (surface->channelSize == sizeof(uint32_t)) { if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, 255); auto color = surface->join(c.r, c.g, c.b, 255);
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
if (span->coverage == 255) { span->fetch(bbox, x, len);
rasterPixel32(surface->buf32 + span->y * surface->stride, color, span->x, span->len); if (span->coverage == 255) rasterPixel32(surface->buf32 + span->y * surface->stride, color, x, len);
} else { else {
auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto dst = &surface->buf32[span->y * surface->stride + x];
auto src = ALPHA_BLEND(color, span->coverage); auto src = ALPHA_BLEND(color, span->coverage);
auto ialpha = 255 - 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); *dst = src + ALPHA_BLEND(*dst, ialpha);
} }
} }
} }
//8bit grayscale //8bit grayscale
} else if (surface->channelSize == sizeof(uint8_t)) { } else if (surface->channelSize == sizeof(uint8_t)) {
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
if (span->coverage == 255) { span->fetch(bbox, x, len);
rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + span->x, span->len); if (span->coverage == 255) rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + x, len);
} else { else {
auto dst = &surface->buf8[span->y * surface->stride + span->x]; auto dst = &surface->buf8[span->y * surface->stride + x];
auto ialpha = 255 - 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 = span->coverage + MULTIPLY(*dst, ialpha); *dst = span->coverage + MULTIPLY(*dst, ialpha);
} }
} }
@ -634,18 +650,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 (!rle || rle->invalid()) return false;
if (_compositing(surface)) { if (_compositing(surface)) {
if (_matting(surface)) return _rasterMattedRle(surface, rle, c); if (_matting(surface)) return _rasterMattedRle(surface, rle, bbox, c);
else return _rasterMaskedRle(surface, rle, c); else return _rasterMaskedRle(surface, rle, bbox, c);
} else if (_blending(surface)) { } else if (_blending(surface)) {
return _rasterBlendingRle(surface, rle, c); return _rasterBlendingRle(surface, rle, bbox, c);
} else { } else {
if (c.a == 255) return _rasterSolidRle(surface, rle, c); if (c.a == 255) return _rasterSolidRle(surface, rle, bbox, c);
else return _rasterTranslucentRle(surface, rle, c); else return _rasterTranslucentRle(surface, rle, bbox, c);
} }
return false; return false;
} }
@ -758,26 +774,29 @@ static bool _rasterScaledRleImage(SwSurface* surface, const SwImage& image, cons
/* RLE Direct Image */ /* 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); TVGLOG("SW_ENGINE", "Direct Matted(%d) Rle Image", (int)surface->compositor->method);
auto csize = surface->compositor->image.channelSize; auto csize = surface->compositor->image.channelSize;
auto cbuffer = surface->compositor->image.buf8; auto cbuffer = surface->compositor->image.buf8;
auto alpha = surface->alpha(surface->compositor->method); auto alpha = surface->alpha(surface->compositor->method);
const SwSpan* end;
int32_t x, len;
ARRAY_FOREACH(span, image.rle->spans) { for (auto span = image.rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x]; span->fetch(bbox, x, len);
auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize]; auto dst = &surface->buf32[span->y * surface->stride + x];
auto img = image.buf32 + (span->y + image.oy) * image.stride + (span->x + image.ox); 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); auto a = MULTIPLY(span->coverage, opacity);
if (a == 255) { 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)); auto tmp = ALPHA_BLEND(*img, alpha(cmp));
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
} }
} else { } 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))); auto tmp = ALPHA_BLEND(*img, MULTIPLY(a, alpha(cmp)));
*dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); *dst = tmp + ALPHA_BLEND(*dst, IA(tmp));
} }
@ -787,18 +806,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) { const SwSpan* end;
auto dst = &surface->buf32[span->y * surface->stride + span->x]; int32_t x, len;
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 img = image.buf32 + (span->y + image.oy) * image.stride + (x + image.ox);
auto alpha = MULTIPLY(span->coverage, opacity); auto alpha = MULTIPLY(span->coverage, opacity);
if (alpha == 255) { 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); *dst = surface->blender(*img, *dst, 255);
} }
} else { } 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); auto tmp = surface->blender(*img, *dst, 255);
*dst = INTERPOLATE(tmp, *dst, MULTIPLY(alpha, A(*img))); *dst = INTERPOLATE(tmp, *dst, MULTIPLY(alpha, A(*img)));
} }
@ -808,19 +831,23 @@ 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) { const SwSpan* end;
auto dst = &surface->buf32[span->y * surface->stride + span->x]; int32_t x, len;
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 img = image.buf32 + (span->y + image.oy) * image.stride + (x + image.ox);
auto alpha = MULTIPLY(span->coverage, opacity); auto alpha = MULTIPLY(span->coverage, opacity);
rasterTranslucentPixel32(dst, img, span->len, alpha); rasterTranslucentPixel32(dst, img, len, alpha);
} }
return true; 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); TVGERR("SW_ENGINE", "Not Supported Direct Masked(%d) Rle Image", (int)surface->compositor->method);
return false; return false;
@ -1629,7 +1656,7 @@ bool rasterScaledRleImage(SwSurface* surface, const SwImage& image, const Matrix
} }
bool rasterDirectRleImage(SwSurface* surface, const SwImage& image, uint8_t opacity) bool rasterDirectRleImage(SwSurface* surface, const SwImage& image, const RenderRegion& bbox, uint8_t opacity)
{ {
if (surface->channelSize == sizeof(uint8_t)) { if (surface->channelSize == sizeof(uint8_t)) {
TVGERR("SW_ENGINE", "Not supported grayscale rle image!"); TVGERR("SW_ENGINE", "Not supported grayscale rle image!");
@ -1637,47 +1664,46 @@ bool rasterDirectRleImage(SwSurface* surface, const SwImage& image, uint8_t opac
} }
if (_compositing(surface)) { if (_compositing(surface)) {
if (_matting(surface)) return _rasterDirectMattedRleImage(surface, image, opacity); if (_matting(surface)) return _rasterDirectMattedRleImage(surface, image, bbox, opacity);
else return _rasterDirectMaskedRleImage(surface, image, opacity); else return _rasterDirectMaskedRleImage(surface, image, bbox, opacity);
} else if (_blending(surface)) { } else if (_blending(surface)) {
return _rasterDirectBlendingRleImage(surface, image, opacity); return _rasterDirectBlendingRleImage(surface, image, bbox, opacity);
} else { } else {
return _rasterDirectRleImage(surface, image, opacity); return _rasterDirectRleImage(surface, image, bbox, opacity);
} }
return false; return false;
} }
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 (!shape->fill) return false;
if (auto color = fillFetchSolid(shape->fill, fdata)) { if (auto color = fillFetchSolid(shape->fill, fdata)) {
auto a = MULTIPLY(color->a, opacity); auto a = MULTIPLY(color->a, opacity);
RenderColor c = {color->r, color->g, color->b, a}; 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(); auto type = fdata->type();
if (shape->fastTrack) { if (shape->fastTrack) {
if (type == Type::LinearGradient) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill); if (type == Type::LinearGradient) return _rasterLinearGradientRect(surface, bbox, shape->fill);
else if (type == Type::RadialGradient)return _rasterRadialGradientRect(surface, shape->bbox, shape->fill); else if (type == Type::RadialGradient)return _rasterRadialGradientRect(surface, bbox, shape->fill);
} else if (shape->rle && shape->rle->valid()) { } else if (shape->rle && shape->rle->valid()) {
if (type == Type::LinearGradient) return _rasterLinearGradientRle(surface, shape->rle, shape->fill); if (type == Type::LinearGradient) return _rasterLinearGradientRle(surface, shape->rle, shape->fill);
else if (type == Type::RadialGradient) return _rasterRadialGradientRle(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 (!shape->stroke || !shape->stroke->fill || !shape->strokeRle || shape->strokeRle->invalid()) return false;
if (auto color = fillFetchSolid(shape->stroke->fill, fdata)) { if (auto color = fillFetchSolid(shape->stroke->fill, fdata)) {
RenderColor c = {color->r, color->g, color->b, color->a}; RenderColor c = {color->r, color->g, color->b, color->a};
c.a = MULTIPLY(c.a, opacity); 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(); auto type = fdata->type();
@ -1687,19 +1713,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) { if (c.a < 255) {
c.r = MULTIPLY(c.r, c.a); c.r = MULTIPLY(c.r, c.a);
c.g = MULTIPLY(c.g, c.a); c.g = MULTIPLY(c.g, c.a);
c.b = MULTIPLY(c.b, c.a); c.b = MULTIPLY(c.b, c.a);
} }
if (shape->fastTrack) return _rasterRect(surface, shape->bbox, c); if (shape->fastTrack) return _rasterRect(surface, bbox, c);
else return _rasterRle(surface, shape->rle, 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) { if (c.a < 255) {
c.r = MULTIPLY(c.r, c.a); c.r = MULTIPLY(c.r, c.a);
@ -1707,7 +1733,7 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, RenderColor& c)
c.b = MULTIPLY(c.b, c.a); c.b = MULTIPLY(c.b, c.a);
} }
return _rasterRle(surface, shape->strokeRle, c); return _rasterRle(surface, shape->strokeRle, bbox, c);
} }
@ -1764,4 +1790,4 @@ void rasterXYFlip(uint32_t* src, uint32_t* dst, int32_t stride, int32_t w, int32
} }
} }
} }
} }

View file

@ -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 //32bit channels
if (surface->channelSize == sizeof(uint32_t)) { if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, c.a); auto color = surface->join(c.r, c.g, c.b, c.a);
uint32_t src; uint32_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x]; FETCH_BOUND(span, bbox);
span->fetch(bbox, x, len);
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color; else src = color;
auto dst = &surface->buf32[span->y * surface->stride + x];
auto ialpha = IA(src); auto ialpha = IA(src);
//1. fill the not aligned memory (for 128-bit registers a 16-bytes alignment is required) //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) { if (notAligned) {
notAligned = (N_32BITS_IN_128REG - notAligned > span->len ? span->len : N_32BITS_IN_128REG - notAligned); notAligned = (N_32BITS_IN_128REG - notAligned > len ? len : N_32BITS_IN_128REG - notAligned);
for (uint32_t x = 0; x < notAligned; ++x, ++dst) { for (auto x = 0; x < notAligned; ++x, ++dst) {
*dst = src + ALPHA_BLEND(*dst, ialpha); *dst = src + ALPHA_BLEND(*dst, ialpha);
} }
} }
//2. fill the aligned memory using avx - N_32BITS_IN_128REG pixels processed at once //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 //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; int32_t iterations = (len - notAligned) / N_32BITS_IN_128REG;
uint32_t avxFilled = 0; int32_t avxFilled = 0;
if (iterations > 0) { if (iterations > 0) {
auto avxSrc = _mm_set1_epi32(src); auto avxSrc = _mm_set1_epi32(src);
auto avxIalpha = _mm_set1_epi8(ialpha); auto avxIalpha = _mm_set1_epi8(ialpha);
avxFilled = iterations * N_32BITS_IN_128REG; avxFilled = iterations * N_32BITS_IN_128REG;
auto avxDst = (__m128i*)dst; 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)); *avxDst = _mm_add_epi32(avxSrc, ALPHA_BLEND(*avxDst, avxIalpha));
} }
} }
//3. fill the remaining pixels //3. fill the remaining pixels
int32_t leftovers = span->len - notAligned - avxFilled; auto leftovers = len - notAligned - avxFilled;
dst += avxFilled; dst += avxFilled;
while (leftovers--) { while (leftovers--) {
*dst = src + ALPHA_BLEND(*dst, ialpha); *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)) { } else if (surface->channelSize == sizeof(uint8_t)) {
TVGLOG("SW_ENGINE", "Require AVX Optimization, Channel Size = %d", surface->channelSize); TVGLOG("SW_ENGINE", "Require AVX Optimization, Channel Size = %d", surface->channelSize);
uint8_t src; uint8_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x]; 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); if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a);
else src = c.a; else src = c.a;
auto ialpha = ~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); *dst = src + MULTIPLY(*dst, ialpha);
} }
} }

View file

@ -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 //32bit channels
if (surface->channelSize == sizeof(uint32_t)) { if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, c.a); auto color = surface->join(c.r, c.g, c.b, c.a);
uint32_t src; uint32_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x]; span->fetch(bbox, x, len);
auto dst = &surface->buf32[span->y * surface->stride + x];
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage); if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color; else src = color;
auto ialpha = IA(src); 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); *dst = src + ALPHA_BLEND(*dst, ialpha);
} }
} }
//8bit grayscale //8bit grayscale
} else if (surface->channelSize == sizeof(uint8_t)) { } else if (surface->channelSize == sizeof(uint8_t)) {
uint8_t src; uint8_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x]; span->fetch(bbox, x, len);
auto dst = &surface->buf8[span->y * surface->stride + x];
if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a); if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a);
else src = c.a; else src = c.a;
auto ialpha = ~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); *dst = src + MULTIPLY(*dst, ialpha);
} }
} }

View file

@ -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 //32bit channels
if (surface->channelSize == sizeof(uint32_t)) { if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, c.a); auto color = surface->join(c.r, c.g, c.b, c.a);
uint32_t src; uint32_t src;
uint8x8_t *vDst = nullptr; 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); if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color; 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); auto ialpha = IA(src);
if ((((uintptr_t) dst) & 0x7) != 0) { 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 vSrc = (uint8x8_t) vdup_n_u32(src);
uint8x8_t vIalpha = vdup_n_u8((uint8_t) ialpha); 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)); vDst[x] = vadd_u8(vSrc, ALPHA_BLEND(vDst[x], vIalpha));
auto leftovers = (span->len - align) % 2; auto leftovers = (len - align) % 2;
if (leftovers > 0) dst[span->len - 1] = src + ALPHA_BLEND(dst[span->len - 1], ialpha); if (leftovers > 0) dst[len - 1] = src + ALPHA_BLEND(dst[len - 1], ialpha);
++span; ++span;
} }
@ -130,12 +135,14 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const
} else if (surface->channelSize == sizeof(uint8_t)) { } else if (surface->channelSize == sizeof(uint8_t)) {
TVGLOG("SW_ENGINE", "Require Neon Optimization, Channel Size = %d", surface->channelSize); TVGLOG("SW_ENGINE", "Require Neon Optimization, Channel Size = %d", surface->channelSize);
uint8_t src; uint8_t src;
ARRAY_FOREACH(span, rle->spans) { for (auto span = rle->fetch(bbox, &end); span < end; ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x]; 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); if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a);
else src = c.a; else src = c.a;
auto ialpha = ~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); *dst = src + MULTIPLY(*dst, ialpha);
} }
} }

View file

@ -204,9 +204,7 @@ struct SwImageTask : SwTask
if ((flags & (RenderUpdateFlag::Image | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) && (opacity > 0)) { if ((flags & (RenderUpdateFlag::Image | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) && (opacity > 0)) {
imageReset(&image); imageReset(&image);
if (!image.data || image.w == 0 || image.h == 0) goto end; 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 (clips.count > 0) {
if (!imageGenRle(&image, bbox, false)) goto end; if (!imageGenRle(&image, bbox, false)) goto end;
if (image.rle) { if (image.rle) {
@ -222,6 +220,7 @@ struct SwImageTask : SwTask
} }
goto end; goto end;
err: err:
bbox.reset();
rleReset(image.rle); rleReset(image.rle);
end: end:
imageDelOutline(&image, mpool, tid); 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 */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
@ -299,10 +273,10 @@ bool SwRenderer::clear()
bool SwRenderer::sync() bool SwRenderer::sync()
{ {
//clear if the rendering was not triggered.
ARRAY_FOREACH(p, tasks) { ARRAY_FOREACH(p, tasks) {
if ((*p)->disposed) { if ((*p)->disposed) delete(*p);
delete(*p); else {
} else {
(*p)->done(); (*p)->done();
(*p)->pushed = false; (*p)->pushed = false;
} }
@ -402,7 +376,7 @@ bool SwRenderer::renderImage(RenderData data)
//RLE Image //RLE Image
if (image.rle) { if (image.rle) {
if (image.direct) return rasterDirectRleImage(surface, image, task->opacity); if (image.direct) return rasterDirectRleImage(surface, image, bbox, task->opacity);
else if (image.scaled) return rasterScaledRleImage(surface, image, task->transform, bbox, task->opacity); else if (image.scaled) return rasterScaledRleImage(surface, image, task->transform, bbox, task->opacity);
else { else {
//create a intermediate buffer for rle clipping //create a intermediate buffer for rle clipping
@ -412,7 +386,7 @@ bool SwRenderer::renderImage(RenderData data)
cmp->compositor->image.rle = image.rle; cmp->compositor->image.rle = image.rle;
rasterClear(cmp, bbox.x(), bbox.y(), bbox.w(), bbox.h(), 0); rasterClear(cmp, bbox.x(), bbox.y(), bbox.w(), bbox.h(), 0);
rasterTexmapPolygon(cmp, image, task->transform, bbox, 255); rasterTexmapPolygon(cmp, image, task->transform, bbox, 255);
return rasterDirectRleImage(surface, cmp->compositor->image, task->opacity); return rasterDirectRleImage(surface, cmp->compositor->image, bbox, task->opacity);
} }
//Whole Image //Whole Image
} else { } else {
@ -432,13 +406,35 @@ bool SwRenderer::renderShape(RenderData data)
if (task->opacity == 0) return true; 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()) { if (task->rshape->strokeFirst()) {
_renderStroke(task, surface); stroke(task, surface, task->bbox);
_renderFill(task, surface); fill(task, surface, task->shape.bbox);
} else { } else {
_renderFill(task, surface); fill(task, surface, task->shape.bbox);
_renderStroke(task, surface); stroke(task, surface, task->bbox);
} }
return true; return true;

View file

@ -881,12 +881,18 @@ bool rleClip(SwRle *rle, const SwRle *clip)
Array<SwSpan> out; Array<SwSpan> out;
out.reserve(std::max(rle->spans.count, clip->spans.count)); out.reserve(std::max(rle->spans.count, clip->spans.count));
auto spans = rle->data(); const SwSpan *end;
auto end = rle->spans.end(); auto spans = rle->fetch(clip->spans.first().y, clip->spans.last().y, &end);
auto cspans = clip->data();
auto cend = clip->spans.end();
while(spans < end && cspans < cend) { if (spans >= end) {
rle->spans.clear();
return false;
}
const SwSpan *cend;
auto cspans = clip->fetch(spans->y, (end - 1)->y, &cend);
while (spans < end && cspans < cend) {
//align y-coordinates. //align y-coordinates.
if (cspans->y > spans->y) { if (cspans->y > spans->y) {
++spans; ++spans;
@ -928,9 +934,10 @@ bool rleClip(SwRle *rle, const RenderRegion* clip)
Array<SwSpan> out; Array<SwSpan> out;
out.reserve(rle->spans.count); out.reserve(rle->spans.count);
auto data = out.data; auto data = out.data;
const SwSpan* end;
uint16_t x, len; 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 >= max.y) break;
if (p->y < min.y || p->x >= max.x || (p->x + p->len) <= min.x) continue; if (p->y < min.y || p->x >= max.x || (p->x + p->len) <= min.x) continue;
if (p->x < min.x) { if (p->x < min.x) {