sw_engine: replace RLE memory with common array

This commit has two purposes:

- refactoring to introduce y indexing method for the upcoming partial rendering.
- replaces the RLE-specific memory allocation with a shared array structure,
eliminating potential memory overflows during RLE clipping.
This commit is contained in:
Hermet Park 2025-05-28 18:22:28 +09:00 committed by Hermet Park
parent d0be8cd2bd
commit 995f756c26
8 changed files with 160 additions and 210 deletions

View file

@ -102,6 +102,17 @@ struct Array
count = rhs.count;
}
void move(Array& to)
{
to.reset();
to.data = data;
to.count = count;
to.reserved = reserved;
data = nullptr;
count = reserved = 0;
}
const T* begin() const
{
return data;
@ -137,6 +148,12 @@ struct Array
return data[count - 1];
}
T& next()
{
if (full()) grow(count + 1);
return data[count++];
}
T& first()
{
return data[0];
@ -164,6 +181,12 @@ struct Array
return count == 0;
}
bool full()
{
return count == reserved;
}
template<class COMPARE> void sort()
{
qsort<COMPARE>(data, 0, (int32_t)(count - 1));

View file

@ -121,9 +121,10 @@ struct SwSpan
struct SwRle
{
SwSpan *spans;
uint32_t alloc;
uint32_t size;
Array<SwSpan> spans;
uint32_t size() const { return spans.count; }
SwSpan* data() const { return spans.data; }
};
struct SwFill

View file

@ -474,12 +474,12 @@ static bool _rasterRect(SwSurface* surface, const RenderRegion& bbox, const Rend
static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp, uint8_t a)
{
auto span = rle->spans;
auto span = rle->data();
auto cbuffer = surface->compositor->image.buf8;
auto cstride = surface->compositor->image.stride;
uint8_t src;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto cmp = &cbuffer[span->y * cstride + span->x];
if (span->coverage == 255) src = a;
else src = MULTIPLY(a, span->coverage);
@ -494,12 +494,12 @@ static bool _rasterCompositeMaskedRle(SwSurface* surface, SwRle* rle, SwMask mas
static bool _rasterDirectMaskedRle(SwSurface* surface, SwRle* rle, SwMask maskOp, uint8_t a)
{
auto span = rle->spans;
auto span = rle->data();
auto cbuffer = surface->compositor->image.buf8;
auto cstride = surface->compositor->image.stride;
uint8_t src;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto cmp = &cbuffer[span->y * cstride + span->x];
auto dst = &surface->buf8[span->y * surface->stride + span->x];
if (span->coverage == 255) src = a;
@ -531,7 +531,7 @@ static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor&
{
TVGLOG("SW_ENGINE", "Matted(%d) Rle", (int)surface->compositor->method);
auto span = rle->spans;
auto span = rle->data();
auto cbuffer = surface->compositor->image.buf8;
auto csize = surface->compositor->image.channelSize;
auto alpha = surface->alpha(surface->compositor->method);
@ -540,7 +540,7 @@ static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor&
if (surface->channelSize == sizeof(uint32_t)) {
uint32_t src;
auto color = surface->join(c.r, c.g, c.b, c.a);
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
if (span->coverage == 255) src = color;
@ -553,7 +553,7 @@ static bool _rasterMattedRle(SwSurface* surface, SwRle* rle, const RenderColor&
//8bit grayscale
} else if (surface->channelSize == sizeof(uint8_t)) {
uint8_t src;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x];
auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
if (span->coverage == 255) src = c.a;
@ -571,10 +571,10 @@ static bool _rasterBlendingRle(SwSurface* surface, const SwRle* rle, const Rende
{
if (surface->channelSize != sizeof(uint32_t)) return false;
auto span = rle->spans;
auto span = rle->data();
auto color = surface->join(c.r, c.g, c.b, c.a);
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) {
for (uint32_t x = 0; x < span->len; ++x, ++dst) {
@ -605,12 +605,12 @@ static bool _rasterTranslucentRle(SwSurface* surface, const SwRle* rle, const Re
static bool _rasterSolidRle(SwSurface* surface, const SwRle* rle, const RenderColor& c)
{
auto span = rle->spans;
auto span = rle->data();
//32bit channels
if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, 255);
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
if (span->coverage == 255) {
rasterPixel32(surface->buf32 + span->y * surface->stride, color, span->x, span->len);
} else {
@ -624,7 +624,7 @@ static bool _rasterSolidRle(SwSurface* surface, const SwRle* rle, const RenderCo
}
//8bit grayscale
} else if (surface->channelSize == sizeof(uint8_t)) {
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
if (span->coverage == 255) {
rasterGrayscale8(surface->buf8, span->coverage, span->y * surface->stride + span->x, span->len);
} else {
@ -687,14 +687,14 @@ static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image
{
TVGLOG("SW_ENGINE", "Scaled Matted(%d) Rle Image", (int)surface->compositor->method);
auto span = image->rle->spans;
auto span = image->rle->data();
auto csize = surface->compositor->image.channelSize;
auto alpha = surface->alpha(surface->compositor->method);
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
auto sampleSize = _sampleSize(image->scale);
int32_t miny = 0, maxy = 0;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
for (uint32_t i = 0; i < image->rle->size(); ++i, ++span) {
SCALED_IMAGE_RANGE_Y(span->y)
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize];
@ -712,12 +712,12 @@ static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image
static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const RenderRegion& bbox, uint8_t opacity)
{
auto span = image->rle->spans;
auto span = image->rle->data();
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
auto sampleSize = _sampleSize(image->scale);
int32_t miny = 0, maxy = 0;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
for (uint32_t i = 0; i < image->rle->size(); ++i, ++span) {
SCALED_IMAGE_RANGE_Y(span->y)
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto alpha = MULTIPLY(span->coverage, opacity);
@ -743,12 +743,12 @@ static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* ima
static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const RenderRegion& bbox, uint8_t opacity)
{
auto span = image->rle->spans;
auto span = image->rle->data();
auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
auto sampleSize = _sampleSize(image->scale);
int32_t miny = 0, maxy = 0;
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
for (uint32_t i = 0; i < image->rle->size(); ++i, ++span) {
SCALED_IMAGE_RANGE_Y(span->y)
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto alpha = MULTIPLY(span->coverage, opacity);
@ -794,12 +794,12 @@ static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image
{
TVGLOG("SW_ENGINE", "Direct Matted(%d) Rle Image", (int)surface->compositor->method);
auto span = image->rle->spans;
auto span = image->rle->data();
auto csize = surface->compositor->image.channelSize;
auto cbuffer = surface->compositor->image.buf8;
auto alpha = surface->alpha(surface->compositor->method);
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
for (uint32_t i = 0; i < image->rle->size(); ++i, ++span) {
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);
@ -822,9 +822,9 @@ static bool _rasterDirectMattedRleImage(SwSurface* surface, const SwImage* image
static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
{
auto span = image->rle->spans;
auto span = image->rle->data();
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
for (uint32_t i = 0; i < image->rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
auto alpha = MULTIPLY(span->coverage, opacity);
@ -845,9 +845,9 @@ static bool _rasterDirectBlendingRleImage(SwSurface* surface, const SwImage* ima
static bool _rasterDirectRleImage(SwSurface* surface, const SwImage* image, uint8_t opacity)
{
auto span = image->rle->spans;
auto span = image->rle->data();
for (uint32_t i = 0; i < image->rle->size; ++i, ++span) {
for (uint32_t i = 0; i < image->rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto img = image->buf32 + (span->y + image->oy) * image->stride + (span->x + image->ox);
auto alpha = MULTIPLY(span->coverage, opacity);
@ -1378,11 +1378,11 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const RenderRegion& bb
template<typename fillMethod>
static bool _rasterCompositeGradientMaskedRle(SwSurface* surface, const SwRle* rle, const SwFill* fill, SwMask maskOp)
{
auto span = rle->spans;
auto span = rle->data();
auto cstride = surface->compositor->image.stride;
auto cbuffer = surface->compositor->image.buf8;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto cmp = &cbuffer[span->y * cstride + span->x];
fillMethod()(fill, cmp, span->y, span->x, span->len, maskOp, span->coverage);
}
@ -1393,12 +1393,12 @@ static bool _rasterCompositeGradientMaskedRle(SwSurface* surface, const SwRle* r
template<typename fillMethod>
static bool _rasterDirectGradientMaskedRle(SwSurface* surface, const SwRle* rle, const SwFill* fill, SwMask maskOp)
{
auto span = rle->spans;
auto span = rle->data();
auto cstride = surface->compositor->image.stride;
auto cbuffer = surface->compositor->image.buf8;
auto dbuffer = surface->buf8;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto cmp = &cbuffer[span->y * cstride + span->x];
auto dst = &dbuffer[span->y * surface->stride + span->x];
fillMethod()(fill, dst, span->y, span->x, span->len, cmp, maskOp, span->coverage);
@ -1427,12 +1427,12 @@ static bool _rasterGradientMattedRle(SwSurface* surface, const SwRle* rle, const
{
TVGLOG("SW_ENGINE", "Matted(%d) Rle Linear Gradient", (int)surface->compositor->method);
auto span = rle->spans;
auto span = rle->data();
auto csize = surface->compositor->image.channelSize;
auto cbuffer = surface->compositor->image.buf8;
auto alpha = surface->alpha(surface->compositor->method);
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
auto cmp = &cbuffer[(span->y * surface->compositor->image.stride + span->x) * csize];
fillMethod()(fill, dst, span->y, span->x, span->len, cmp, alpha, csize, span->coverage);
@ -1444,9 +1444,9 @@ static bool _rasterGradientMattedRle(SwSurface* surface, const SwRle* rle, const
template<typename fillMethod>
static bool _rasterBlendingGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
{
auto span = rle->spans;
auto span = rle->data();
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, surface->blender, span->coverage);
}
@ -1457,18 +1457,18 @@ static bool _rasterBlendingGradientRle(SwSurface* surface, const SwRle* rle, con
template<typename fillMethod>
static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
{
auto span = rle->spans;
auto span = rle->data();
//32 bits
if (surface->channelSize == sizeof(uint32_t)) {
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendPreNormal, 255);
else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendNormal, span->coverage);
}
//8 bits
} else if (surface->channelSize == sizeof(uint8_t)) {
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x];
fillMethod()(fill, dst, span->y, span->x, span->len, _opMaskAdd, span->coverage);
}
@ -1480,18 +1480,18 @@ static bool _rasterTranslucentGradientRle(SwSurface* surface, const SwRle* rle,
template<typename fillMethod>
static bool _rasterSolidGradientRle(SwSurface* surface, const SwRle* rle, const SwFill* fill)
{
auto span = rle->spans;
auto span = rle->data();
//32 bits
if (surface->channelSize == sizeof(uint32_t)) {
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, opBlendSrcOver, 255);
else fillMethod()(fill, dst, span->y, span->x, span->len, opBlendInterp, span->coverage);
}
//8 bits
} else if (surface->channelSize == sizeof(uint8_t)) {
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x];
if (span->coverage == 255) fillMethod()(fill, dst, span->y, span->x, span->len, _opMaskNone, 255);
else fillMethod()(fill, dst, span->y, span->x, span->len, _opMaskAdd, span->coverage);

View file

@ -160,14 +160,14 @@ static bool avxRasterTranslucentRect(SwSurface* surface, const RenderRegion& bbo
static bool avxRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderColor& c)
{
auto span = rle->spans;
auto span = rle->data();
//32bit channels
if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, c.a);
uint32_t src;
for (uint32_t i = 0; i < rle->size; ++i) {
for (uint32_t i = 0; i < rle->size(); ++i) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
@ -213,7 +213,7 @@ 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;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x];
if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a);
else src = c.a;

View file

@ -94,13 +94,13 @@ 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)
{
auto span = rle->spans;
auto span = rle->data();
//32bit channels
if (surface->channelSize == sizeof(uint32_t)) {
auto color = surface->join(c.r, c.g, c.b, c.a);
uint32_t src;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf32[span->y * surface->stride + span->x];
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
@ -112,7 +112,7 @@ static bool inline cRasterTranslucentRle(SwSurface* surface, const SwRle* rle, c
//8bit grayscale
} else if (surface->channelSize == sizeof(uint8_t)) {
uint8_t src;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x];
if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a);
else src = c.a;

View file

@ -91,7 +91,7 @@ static void neonRasterPixel32(uint32_t *dst, uint32_t val, uint32_t offset, int3
static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const RenderColor& c)
{
auto span = rle->spans;
auto span = rle->data();
//32bit channels
if (surface->channelSize == sizeof(uint32_t)) {
@ -100,7 +100,7 @@ static bool neonRasterTranslucentRle(SwSurface* surface, const SwRle* rle, const
uint8x8_t *vDst = nullptr;
uint16_t align;
for (uint32_t i = 0; i < rle->size; ++i) {
for (uint32_t i = 0; i < rle->size(); ++i) {
if (span->coverage < 255) src = ALPHA_BLEND(color, span->coverage);
else src = color;
@ -132,7 +132,7 @@ 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;
for (uint32_t i = 0; i < rle->size; ++i, ++span) {
for (uint32_t i = 0; i < rle->size(); ++i, ++span) {
auto dst = &surface->buf8[span->y * surface->stride + span->x];
if (span->coverage < 255) src = MULTIPLY(span->coverage, c.a);
else src = c.a;

View file

@ -60,8 +60,8 @@ static bool _arrange(const SwImage* image, const RenderRegion* bbox, int& yStart
bboxTop = bbox->min.y;
bboxBottom = bbox->max.y;
} else {
bboxTop = image->rle->spans->y;
bboxBottom = image->rle->spans[image->rle->size - 1].y;
bboxTop = image->rle->spans.first().y;
bboxBottom = image->rle->spans.last().y;
}
if (yStart < bboxTop) yStart = bboxTop;
@ -103,7 +103,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
minx = bbox->min.x;
maxx = bbox->max.x;
} else {
span = image->rle->spans;
span = image->rle->data();
while (span->y < yStart) {
++span;
++spanIdx;
@ -120,7 +120,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
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 && spanIdx < image->rle->size()) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
@ -195,7 +195,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
_ua += _dudya;
_va += _dvdya;
if (!bbox && spanIdx >= image->rle->size) break;
if (!bbox && spanIdx >= image->rle->size()) break;
++y;
}
@ -236,7 +236,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
minx = bbox->min.x;
maxx = bbox->max.x;
} else {
span = image->rle->spans;
span = image->rle->data();
while (span->y < yStart) {
++span;
++spanIdx;
@ -253,7 +253,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
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 && spanIdx < image->rle->size()) {
if (minx > span->x) minx = span->x;
if (maxx < span->x + span->len) maxx = span->x + span->len;
++span;
@ -387,7 +387,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
_ua += _dudya;
_va += _dvdya;
if (!bbox && spanIdx >= image->rle->size) break;
if (!bbox && spanIdx >= image->rle->size()) break;
++y;
}
@ -460,7 +460,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->spans->y; //Normal Image or Rle Image?
auto bboxTop = bbox ? bbox->min.y : image->rle->data()->y; //Normal Image or Rle Image?
auto compositing = _compositing(surface); //Composition required
auto blending = _blending(surface); //Blending required
@ -871,7 +871,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) || (image->rle && image->rle->size() == 0)) return true;
/* Prepare vertices.
shift XY coordinates to match the sub-pixeling technique. */

View file

@ -324,27 +324,18 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
if (!rw.antiAlias) coverage = 255;
//see whether we can add this span to the current list
if (rle->size > 0) {
auto span = rle->spans + rle->size - 1;
if ((span->coverage == coverage) && (span->y == y) && (span->x + span->len == x)) {
if (!rle->spans.empty()) {
auto& span = rle->spans.last();
if ((span.coverage == coverage) && (span.y == y) && (span.x + span.len == x)) {
//Clip x range
SwCoord xOver = 0;
if (x + aCount >= rw.cellMax.x) xOver -= (x + aCount - rw.cellMax.x);
if (x < rw.cellMin.x) xOver -= (rw.cellMin.x - x);
span->len += (aCount + xOver);
span.len += (aCount + xOver);
return;
}
}
//span pool is full, grow it.
if (rle->size >= rle->alloc) {
auto newSize = (rle->size > 0) ? (rle->size * 2) : 256;
if (rle->alloc < newSize) {
rle->alloc = newSize;
rle->spans = tvg::realloc<SwSpan*>(rle->spans, rle->alloc * sizeof(SwSpan));
}
}
//Clip x range
SwCoord xOver = 0;
if (x + aCount >= rw.cellMax.x) xOver -= (x + aCount - rw.cellMax.x);
@ -357,12 +348,7 @@ static void _horizLine(RleWorker& rw, SwCoord x, SwCoord y, SwCoord area, SwCoor
if (aCount + xOver <= 0) return;
//add a span to the current list
auto span = rle->spans + rle->size;
span->x = x;
span->y = y;
span->len = (aCount + xOver);
span->coverage = coverage;
rle->size++;
rle->spans.next() = {(uint16_t)x, (uint16_t)y, uint16_t(aCount + xOver), (uint8_t)coverage};
}
@ -737,109 +723,6 @@ static bool _genRle(RleWorker& rw)
}
static SwSpan* _intersectSpansRegion(const SwRle *clip, const SwRle *target, SwSpan *outSpans, uint32_t outSpansCnt)
{
auto out = outSpans;
auto spans = target->spans;
auto end = target->spans + target->size;
auto clipSpans = clip->spans;
auto clipEnd = clip->spans + clip->size;
while (spans < end && clipSpans < clipEnd) {
//align y-coordinates.
if (clipSpans->y > spans->y) {
++spans;
continue;
}
if (spans->y > clipSpans->y) {
++clipSpans;
continue;
}
//Try clipping with all clip spans which have a same y-coordinate.
auto temp = clipSpans;
while(temp < clipEnd && temp->y == clipSpans->y) {
if (outSpansCnt == 0) {
TVGERR("SW_ENGINE", "span buffer is over.");
break;
}
auto sx1 = spans->x;
auto sx2 = sx1 + spans->len;
auto cx1 = temp->x;
auto cx2 = cx1 + temp->len;
//The span must be left(x1) to right(x2) direction. Not intersected.
if (cx2 < sx1 || sx2 < cx1) {
++temp;
continue;
}
//clip span region.
auto x = sx1 > cx1 ? sx1 : cx1;
auto len = (sx2 < cx2 ? sx2 : cx2) - x;
if (len > 0) {
out->x = x;
out->y = temp->y;
out->len = len;
out->coverage = (uint8_t)(((spans->coverage * temp->coverage) + 0xff) >> 8);
++out;
--outSpansCnt;
}
++temp;
}
++spans;
}
return out;
}
static SwSpan* _intersectSpansRect(const RenderRegion *bbox, const SwRle *targetRle, SwSpan *outSpans, uint32_t outSpansCnt)
{
auto out = outSpans;
auto spans = targetRle->spans;
auto end = targetRle->spans + targetRle->size;
auto minx = static_cast<int16_t>(bbox->min.x);
auto miny = static_cast<int16_t>(bbox->min.y);
auto maxx = minx + static_cast<int16_t>(bbox->max.x - bbox->min.x) - 1;
auto maxy = miny + static_cast<int16_t>(bbox->max.y - bbox->min.y) - 1;
while (outSpansCnt > 0 && spans < end) {
if (spans->y > maxy) {
spans = end;
break;
}
if (spans->y < miny || spans->x > maxx || spans->x + spans->len <= minx) {
++spans;
continue;
}
if (spans->x < minx) {
out->len = (spans->len - (minx - spans->x)) < (maxx - minx + 1) ? (spans->len - (minx - spans->x)) : (maxx - minx + 1);
out->x = minx;
}
else {
out->x = spans->x;
out->len = spans->len < (maxx - spans->x + 1) ? spans->len : (maxx - spans->x + 1);
}
if (out->len > 0) {
out->y = spans->y;
out->coverage = spans->coverage;
++out;
--outSpansCnt;
}
++spans;
}
return out;
}
void _replaceClipSpan(SwRle *rle, SwSpan* clippedSpans, uint32_t size)
{
tvg::free(rle->spans);
rle->spans = clippedSpans;
rle->size = rle->alloc = size;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@ -876,6 +759,7 @@ SwRle* rleRender(SwRle* rle, const SwOutline* outline, const RenderRegion& bbox,
if (!rle) rw.rle = tvg::calloc<SwRle*>(1, sizeof(SwRle));
else rw.rle = rle;
rw.rle->spans.reserve(256);
//Generate RLE
Band bands[BAND_SIZE];
@ -963,20 +847,17 @@ error:
SwRle* rleRender(const RenderRegion* bbox)
{
auto width = static_cast<uint16_t>(bbox->w());
auto height = static_cast<uint16_t>(bbox->h());
auto rle = tvg::calloc<SwRle*>(sizeof(SwRle), 1);
rle->spans.reserve(bbox->h());
rle->spans.count = bbox->h();
auto rle = tvg::malloc<SwRle*>(sizeof(SwRle));
rle->spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * height);
rle->size = height;
rle->alloc = height;
//cheaper without push()
auto x = uint16_t(bbox->min.x);
auto y = uint16_t(bbox->min.y);
auto len = uint16_t(bbox->w());
auto span = rle->spans;
for (uint16_t i = 0; i < height; ++i, ++span) {
span->x = bbox->min.x;
span->y = bbox->min.y + i;
span->len = width;
span->coverage = 255;
ARRAY_FOREACH(p, rle->spans) {
*p = {x, y++, len, 255};
}
return rle;
@ -985,44 +866,89 @@ SwRle* rleRender(const RenderRegion* bbox)
void rleReset(SwRle* rle)
{
if (!rle) return;
rle->size = 0;
if (rle) rle->spans.clear();
}
void rleFree(SwRle* rle)
{
if (!rle) return;
if (rle->spans) tvg::free(rle->spans);
rle->spans.reset();
tvg::free(rle);
}
bool rleClip(SwRle *rle, const SwRle *clip)
{
if (rle->size == 0 || clip->size == 0) return false;
auto spanCnt = 2 * (rle->size > clip->size ? rle->size : clip->size); //factor 2 added for safety (no real cases observed where the factor exceeded 1.4)
auto spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * (spanCnt));
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);
if (rle->spans.empty() || clip->spans.empty()) return false;
_replaceClipSpan(rle, spans, spansEnd - spans);
Array<SwSpan> out;
out.reserve(std::max(rle->spans.count, clip->spans.count));
TVGLOG("SW_ENGINE", "Using Path Clipping!");
auto spans = rle->data();
auto end = rle->spans.end();
auto cspans = clip->data();
auto cend = clip->spans.end();
while(spans < end && cspans < cend) {
//align y-coordinates.
if (cspans->y > spans->y) {
++spans;
continue;
}
if (spans->y > cspans->y) {
++cspans;
continue;
}
//try clipping with all clip spans which have a same y-coordinate.
auto temp = cspans;
while(temp->y == cspans->y && temp < cend) {
//span must be left(x1) to right(x2) direction. Not intersected.
if ((spans->x + spans->len) < spans->x || (temp->x + temp->len) < temp->x) {
++temp;
continue;
}
//clip span region
auto x = std::max(spans->x, temp->x);
auto len = std::min((spans->x + spans->len), (temp->x + temp->len)) - x;
if (len > 0) out.next() = {uint16_t(x), temp->y, uint16_t(len), (uint8_t)(((spans->coverage * temp->coverage) + 0xff) >> 8)};
++temp;
}
++spans;
}
out.move(rle->spans);
return true;
}
bool rleClip(SwRle *rle, const RenderRegion* clip)
{
if (rle->size == 0) return false;
auto spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * (rle->size));
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size);
if (rle->spans.empty() || clip->invalid()) return false;
_replaceClipSpan(rle, spans, spansEnd - spans);
auto& min = clip->min;
auto& max = clip->max;
TVGLOG("SW_ENGINE", "Using Box Clipping!");
Array<SwSpan> out;
out.reserve(rle->spans.count);
auto data = out.data;
uint16_t x, len;
ARRAY_FOREACH(p, rle->spans) {
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) {
x = min.x;
len = std::min((p->len - (x - p->x)), (max.x - x));
} else {
x = p->x;
len = std::min(p->len, uint16_t(max.x - x));
}
if (len > 0) {
*data = {x, p->y, len, p->coverage};
++data;
++out.count;
}
}
out.move(rle->spans);
return true;
}
}