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