mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-26 16:16:46 +00:00
sw_engine: optimize othogonal rectangle drawing.
if the rectangle is not transformed, we don't need to use rle method. we can directly raster pixels onto the bounding box. Change-Id: I4e8b57149c0bcd78124d09388bf5115093a43bee
This commit is contained in:
parent
0d5adb2f03
commit
322174d778
4 changed files with 162 additions and 17 deletions
|
@ -198,6 +198,8 @@ struct SwShape
|
||||||
SwRleData* rle;
|
SwRleData* rle;
|
||||||
SwRleData* strokeRle;
|
SwRleData* strokeRle;
|
||||||
SwBBox bbox;
|
SwBBox bbox;
|
||||||
|
|
||||||
|
bool rect; //Fast Track: Othogonal rectangle?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,17 +24,58 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
static SwBBox _clipRegion(Surface& surface, SwBBox& in)
|
||||||
|
{
|
||||||
|
auto bbox = in;
|
||||||
|
|
||||||
|
if (bbox.min.x < 0) bbox.min.x = 0;
|
||||||
|
if (bbox.min.y < 0) bbox.min.y = 0;
|
||||||
|
if (bbox.max.x > surface.w) bbox.max.x = surface.w;
|
||||||
|
if (bbox.max.y > surface.h) bbox.max.y = surface.h;
|
||||||
|
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint32_t color)
|
||||||
|
{
|
||||||
|
auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x;
|
||||||
|
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||||
|
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||||
|
auto ialpha = 255 - COLOR_ALPHA(color);
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
|
auto dst = &buffer[y * surface.stride];
|
||||||
|
for (uint32_t x = 0; x < w; ++x) {
|
||||||
|
dst[x] = color + COLOR_ALPHA_BLEND(dst[x], ialpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t color)
|
||||||
|
{
|
||||||
|
auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x;
|
||||||
|
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||||
|
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
|
auto dst = &buffer[y * surface.stride];
|
||||||
|
COLOR_SET(dst, color, w);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color)
|
static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t color)
|
||||||
{
|
{
|
||||||
if (!rle) return false;
|
if (!rle) return false;
|
||||||
|
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
auto stride = surface.stride;
|
|
||||||
uint32_t src;
|
uint32_t src;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||||
auto dst = &surface.buffer[span->y * stride + span->x];
|
auto dst = &surface.buffer[span->y * surface.stride + span->x];
|
||||||
if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage);
|
if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage);
|
||||||
else src = color;
|
else src = color;
|
||||||
auto ialpha = 255 - COLOR_ALPHA(src);
|
auto ialpha = 255 - COLOR_ALPHA(src);
|
||||||
|
@ -52,10 +93,9 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color)
|
||||||
if (!rle) return false;
|
if (!rle) return false;
|
||||||
|
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
auto stride = surface.stride;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||||
auto dst = &surface.buffer[span->y * stride + span->x];
|
auto dst = &surface.buffer[span->y * surface.stride + span->x];
|
||||||
if (span->coverage == 255) {
|
if (span->coverage == 255) {
|
||||||
COLOR_SET(dst, color, span->len);
|
COLOR_SET(dst, color, span->len);
|
||||||
} else {
|
} else {
|
||||||
|
@ -71,6 +111,70 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, const SwFill* fill)
|
||||||
|
{
|
||||||
|
if (!fill) return false;
|
||||||
|
|
||||||
|
auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x;
|
||||||
|
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||||
|
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||||
|
|
||||||
|
//Translucent Gradient
|
||||||
|
if (fill->translucent) {
|
||||||
|
|
||||||
|
auto tmpBuf = static_cast<uint32_t*>(alloca(surface.w * sizeof(uint32_t)));
|
||||||
|
if (!tmpBuf) return false;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
|
auto dst = &buffer[y * surface.stride];
|
||||||
|
fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w);
|
||||||
|
for (uint32_t x = 0; x < w; ++x) {
|
||||||
|
dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Opaque Gradient
|
||||||
|
} else {
|
||||||
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
|
auto dst = &buffer[y * surface.stride];
|
||||||
|
fillFetchLinear(fill, dst, region.min.y + y, region.min.x, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, const SwFill* fill)
|
||||||
|
{
|
||||||
|
if (!fill) return false;
|
||||||
|
|
||||||
|
auto buffer = surface.buffer + (region.min.y * surface.stride) + region.min.x;
|
||||||
|
auto h = static_cast<uint32_t>(region.max.y - region.min.y);
|
||||||
|
auto w = static_cast<uint32_t>(region.max.x - region.min.x);
|
||||||
|
|
||||||
|
//Translucent Gradient
|
||||||
|
if (fill->translucent) {
|
||||||
|
|
||||||
|
auto tmpBuf = static_cast<uint32_t*>(alloca(surface.w * sizeof(uint32_t)));
|
||||||
|
if (!tmpBuf) return false;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
|
auto dst = &buffer[y * surface.stride];
|
||||||
|
fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w);
|
||||||
|
for (uint32_t x = 0; x < w; ++x) {
|
||||||
|
dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Opaque Gradient
|
||||||
|
} else {
|
||||||
|
for (uint32_t y = 0; y < h; ++y) {
|
||||||
|
auto dst = &buffer[y * surface.stride];
|
||||||
|
fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill)
|
static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwFill* fill)
|
||||||
{
|
{
|
||||||
if (!rle || !fill) return false;
|
if (!rle || !fill) return false;
|
||||||
|
@ -79,12 +183,11 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF
|
||||||
if (!buf) return false;
|
if (!buf) return false;
|
||||||
|
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
auto stride = surface.stride;
|
|
||||||
|
|
||||||
//Translucent Gradient
|
//Translucent Gradient
|
||||||
if (fill->translucent) {
|
if (fill->translucent) {
|
||||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||||
auto dst = &surface.buffer[span->y * stride + span->x];
|
auto dst = &surface.buffer[span->y * surface.stride + span->x];
|
||||||
fillFetchLinear(fill, buf, span->y, span->x, span->len);
|
fillFetchLinear(fill, buf, span->y, span->x, span->len);
|
||||||
if (span->coverage == 255) {
|
if (span->coverage == 255) {
|
||||||
for (uint32_t i = 0; i < span->len; ++i) {
|
for (uint32_t i = 0; i < span->len; ++i) {
|
||||||
|
@ -101,7 +204,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF
|
||||||
//Opaque Gradient
|
//Opaque Gradient
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||||
auto dst = &surface.buffer[span->y * stride + span->x];
|
auto dst = &surface.buffer[span->y * surface.stride + span->x];
|
||||||
if (span->coverage == 255) {
|
if (span->coverage == 255) {
|
||||||
fillFetchLinear(fill, dst, span->y, span->x, span->len);
|
fillFetchLinear(fill, dst, span->y, span->x, span->len);
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,12 +229,11 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
|
||||||
if (!buf) return false;
|
if (!buf) return false;
|
||||||
|
|
||||||
auto span = rle->spans;
|
auto span = rle->spans;
|
||||||
auto stride = surface.stride;
|
|
||||||
|
|
||||||
//Translucent Gradient
|
//Translucent Gradient
|
||||||
if (fill->translucent) {
|
if (fill->translucent) {
|
||||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||||
auto dst = &surface.buffer[span->y * stride + span->x];
|
auto dst = &surface.buffer[span->y * surface.stride + span->x];
|
||||||
fillFetchRadial(fill, buf, span->y, span->x, span->len);
|
fillFetchRadial(fill, buf, span->y, span->x, span->len);
|
||||||
if (span->coverage == 255) {
|
if (span->coverage == 255) {
|
||||||
for (uint32_t i = 0; i < span->len; ++i) {
|
for (uint32_t i = 0; i < span->len; ++i) {
|
||||||
|
@ -148,7 +250,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
|
||||||
//Opaque Gradient
|
//Opaque Gradient
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t i = 0; i < rle->size; ++i) {
|
for (uint32_t i = 0; i < rle->size; ++i) {
|
||||||
auto dst = &surface.buffer[span->y * stride + span->x];
|
auto dst = &surface.buffer[span->y * surface.stride + span->x];
|
||||||
if (span->coverage == 255) {
|
if (span->coverage == 255) {
|
||||||
fillFetchRadial(fill, dst, span->y, span->x, span->len);
|
fillFetchRadial(fill, dst, span->y, span->x, span->len);
|
||||||
} else {
|
} else {
|
||||||
|
@ -171,15 +273,31 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
|
||||||
|
|
||||||
bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id)
|
bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id)
|
||||||
{
|
{
|
||||||
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill);
|
//Fast Track
|
||||||
return _rasterRadialGradientRle(surface, shape.rle, shape.fill);
|
if (shape.rect) {
|
||||||
|
auto region = _clipRegion(surface, shape.bbox);
|
||||||
|
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, region, shape.fill);
|
||||||
|
return _rasterRadialGradientRect(surface, region, shape.fill);
|
||||||
|
} else {
|
||||||
|
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill);
|
||||||
|
return _rasterRadialGradientRle(surface, shape.rle, shape.fill);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
bool rasterSolidShape(Surface& surface, SwShape& shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
||||||
{
|
{
|
||||||
if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a));
|
//Fast Track
|
||||||
return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a));
|
if (shape.rect) {
|
||||||
|
auto region = _clipRegion(surface, shape.bbox);
|
||||||
|
if (a == 255) return _rasterSolidRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a));
|
||||||
|
return _rasterTranslucentRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a));
|
||||||
|
} else{
|
||||||
|
if (a == 255) return _rasterSolidRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a));
|
||||||
|
return _rasterTranslucentRle(surface, shape.rle, COLOR_ARGB_JOIN(r, g, b, a));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,5 +322,4 @@ bool rasterClear(Surface& surface)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* _TVG_SW_RASTER_CPP_ */
|
#endif /* _TVG_SW_RASTER_CPP_ */
|
|
@ -241,7 +241,7 @@ static void _transformOutline(SwOutline* outline, const Matrix* transform)
|
||||||
auto dy = static_cast<float>(outline->pts[i].y >> 6);
|
auto dy = static_cast<float>(outline->pts[i].y >> 6);
|
||||||
auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31;
|
auto tx = dx * transform->e11 + dy * transform->e12 + transform->e31;
|
||||||
auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32;
|
auto ty = dx * transform->e21 + dy * transform->e22 + transform->e32;
|
||||||
auto pt = Point{tx, ty};
|
auto pt = Point{round(tx), round(ty)};
|
||||||
outline->pts[i] = TO_SWPOINT(&pt);
|
outline->pts[i] = TO_SWPOINT(&pt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,6 +437,28 @@ SwOutline* _genDashOutline(const Shape* sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool _fastTrack(const SwOutline* outline)
|
||||||
|
{
|
||||||
|
//Fast Track: Othogonal rectangle?
|
||||||
|
if (outline->ptsCnt != 5) return false;
|
||||||
|
|
||||||
|
auto pt1 = outline->pts + 0;
|
||||||
|
auto pt2 = outline->pts + 1;
|
||||||
|
auto pt3 = outline->pts + 2;
|
||||||
|
auto pt4 = outline->pts + 3;
|
||||||
|
|
||||||
|
auto min1 = pt1->y < pt3->y ? pt1 : pt3;
|
||||||
|
auto min2 = pt2->y < pt4->y ? pt2 : pt4;
|
||||||
|
if (min1->y != min2->y) return false;
|
||||||
|
|
||||||
|
SwCoord len1 = pow(pt1->x - pt3->x, 2) + pow(pt1->y - pt3->y, 2);
|
||||||
|
SwCoord len2 = pow(pt2->x - pt4->x, 2) + pow(pt2->y - pt4->y, 2);
|
||||||
|
if (len1 == len2) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
@ -451,6 +473,9 @@ bool shapeGenRle(SwShape& shape, const Shape* sdata, const SwSize& clip, const M
|
||||||
|
|
||||||
if (!_checkValid(shape.outline, shape.bbox, clip)) goto end;
|
if (!_checkValid(shape.outline, shape.bbox, clip)) goto end;
|
||||||
|
|
||||||
|
//Case: Fast Track Rectangle Drawing
|
||||||
|
if ((shape.rect = _fastTrack(shape.outline))) return true;
|
||||||
|
|
||||||
//Case: Stroke Line
|
//Case: Stroke Line
|
||||||
if (shape.outline->opened) return true;
|
if (shape.outline->opened) return true;
|
||||||
|
|
||||||
|
@ -474,6 +499,7 @@ void shapeReset(SwShape& shape)
|
||||||
shapeDelOutline(shape);
|
shapeDelOutline(shape);
|
||||||
rleFree(shape.rle);
|
rleFree(shape.rle);
|
||||||
shape.rle = nullptr;
|
shape.rle = nullptr;
|
||||||
|
shape.rect = false;
|
||||||
_initBBox(shape.bbox);
|
_initBBox(shape.bbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ bool tvgUpdateCmds(tvg::Canvas* canvas)
|
||||||
float w = 1 + rand() % (int)(WIDTH * 1.3 / 2);
|
float w = 1 + rand() % (int)(WIDTH * 1.3 / 2);
|
||||||
float h = 1 + rand() % (int)(HEIGHT * 1.3 / 2);
|
float h = 1 + rand() % (int)(HEIGHT * 1.3 / 2);
|
||||||
|
|
||||||
shape->appendRect(x, y, w, h, rand() % 400);
|
shape->appendRect(x, y, w, h, 0);
|
||||||
|
|
||||||
//LinearGradient
|
//LinearGradient
|
||||||
auto fill = tvg::LinearGradient::gen();
|
auto fill = tvg::LinearGradient::gen();
|
||||||
|
|
Loading…
Add table
Reference in a new issue