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:
Hermet Park 2020-07-01 11:33:50 +09:00
parent 0d5adb2f03
commit 322174d778
4 changed files with 162 additions and 17 deletions

View file

@ -198,6 +198,8 @@ struct SwShape
SwRleData* rle;
SwRleData* strokeRle;
SwBBox bbox;
bool rect; //Fast Track: Othogonal rectangle?
};

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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();