From 322174d778d695be5153db574c6cb20fe251188b Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 1 Jul 2020 11:33:50 +0900 Subject: [PATCH] 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 --- src/lib/sw_engine/tvgSwCommon.h | 2 + src/lib/sw_engine/tvgSwRaster.cpp | 147 ++++++++++++++++++++++++++++++++++---- src/lib/sw_engine/tvgSwShape.cpp | 28 +++++++- test/testAsync.cpp | 2 +- 4 files changed, 162 insertions(+), 17 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 72fa700..88686b5 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -198,6 +198,8 @@ struct SwShape SwRleData* rle; SwRleData* strokeRle; SwBBox bbox; + + bool rect; //Fast Track: Othogonal rectangle? }; diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 05429f3..5a14822 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -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(region.max.y - region.min.y); + auto w = static_cast(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(region.max.y - region.min.y); + auto w = static_cast(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(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + //Translucent Gradient + if (fill->translucent) { + + auto tmpBuf = static_cast(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(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + //Translucent Gradient + if (fill->translucent) { + + auto tmpBuf = static_cast(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_ */ \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4c99fb1..1c0a09e 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -241,7 +241,7 @@ static void _transformOutline(SwOutline* outline, const Matrix* transform) auto dy = static_cast(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); } diff --git a/test/testAsync.cpp b/test/testAsync.cpp index 9ae7113..ca1d473 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -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(); -- 2.7.4