mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-25 23:59:12 +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* strokeRle;
|
||||
SwBBox bbox;
|
||||
|
||||
bool rect; //Fast Track: Othogonal rectangle?
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,17 +24,58 @@
|
|||
/* 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)
|
||||
{
|
||||
if (!rle) return false;
|
||||
|
||||
auto span = rle->spans;
|
||||
auto stride = surface.stride;
|
||||
uint32_t src;
|
||||
|
||||
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);
|
||||
else src = color;
|
||||
auto ialpha = 255 - COLOR_ALPHA(src);
|
||||
|
@ -52,10 +93,9 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color)
|
|||
if (!rle) return false;
|
||||
|
||||
auto span = rle->spans;
|
||||
auto stride = surface.stride;
|
||||
|
||||
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) {
|
||||
COLOR_SET(dst, color, span->len);
|
||||
} 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)
|
||||
{
|
||||
if (!rle || !fill) return false;
|
||||
|
@ -79,12 +183,11 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF
|
|||
if (!buf) return false;
|
||||
|
||||
auto span = rle->spans;
|
||||
auto stride = surface.stride;
|
||||
|
||||
//Translucent Gradient
|
||||
if (fill->translucent) {
|
||||
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);
|
||||
if (span->coverage == 255) {
|
||||
for (uint32_t i = 0; i < span->len; ++i) {
|
||||
|
@ -101,7 +204,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF
|
|||
//Opaque Gradient
|
||||
} else {
|
||||
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) {
|
||||
fillFetchLinear(fill, dst, span->y, span->x, span->len);
|
||||
} else {
|
||||
|
@ -126,12 +229,11 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
|
|||
if (!buf) return false;
|
||||
|
||||
auto span = rle->spans;
|
||||
auto stride = surface.stride;
|
||||
|
||||
//Translucent Gradient
|
||||
if (fill->translucent) {
|
||||
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);
|
||||
if (span->coverage == 255) {
|
||||
for (uint32_t i = 0; i < span->len; ++i) {
|
||||
|
@ -148,7 +250,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
|
|||
//Opaque Gradient
|
||||
} else {
|
||||
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) {
|
||||
fillFetchRadial(fill, dst, span->y, span->x, span->len);
|
||||
} else {
|
||||
|
@ -171,15 +273,31 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF
|
|||
|
||||
bool rasterGradientShape(Surface& surface, SwShape& shape, unsigned id)
|
||||
{
|
||||
if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape.rle, shape.fill);
|
||||
return _rasterRadialGradientRle(surface, shape.rle, shape.fill);
|
||||
//Fast Track
|
||||
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)
|
||||
{
|
||||
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));
|
||||
//Fast Track
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#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 tx = dx * transform->e11 + dy * transform->e12 + transform->e31;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
/************************************************************************/
|
||||
|
@ -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;
|
||||
|
||||
//Case: Fast Track Rectangle Drawing
|
||||
if ((shape.rect = _fastTrack(shape.outline))) return true;
|
||||
|
||||
//Case: Stroke Line
|
||||
if (shape.outline->opened) return true;
|
||||
|
||||
|
@ -474,6 +499,7 @@ void shapeReset(SwShape& shape)
|
|||
shapeDelOutline(shape);
|
||||
rleFree(shape.rle);
|
||||
shape.rle = nullptr;
|
||||
shape.rect = false;
|
||||
_initBBox(shape.bbox);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ bool tvgUpdateCmds(tvg::Canvas* canvas)
|
|||
float w = 1 + rand() % (int)(WIDTH * 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
|
||||
auto fill = tvg::LinearGradient::gen();
|
||||
|
|
Loading…
Add table
Reference in a new issue