common sw_engine: apply partial composition.

Introduce RendererMethod::renderRegion() to return acutal drawing region info.

That is used by scene composition to composite actual partial drawing region

for better performance.

@Issues: 173
This commit is contained in:
Hermet Park 2020-12-14 12:29:37 +09:00 committed by GitHub
parent e3eff97fac
commit 64d3897816
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 118 additions and 48 deletions

View file

@ -73,6 +73,12 @@ bool GlRenderer::sync()
} }
bool GlRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
return true;
}
bool GlRenderer::preRender() bool GlRenderer::preRender()
{ {
if (mRenderTasks.size() == 0) if (mRenderTasks.size() == 0)

View file

@ -39,6 +39,7 @@ public:
bool render(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override;
bool render(const Picture& picture, void *data) override; bool render(const Picture& picture, void *data) override;
bool postRender() override; bool postRender() override;
bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
bool sync() override; bool sync() override;
bool clear() override; bool clear() override;

View file

@ -207,7 +207,7 @@ struct SwShape
SwFill* fill = nullptr; SwFill* fill = nullptr;
SwRleData* rle = nullptr; SwRleData* rle = nullptr;
SwRleData* strokeRle = nullptr; SwRleData* strokeRle = nullptr;
SwBBox bbox; SwBBox bbox; //keep it boundary without stroke region. Using for optimal filling.
bool rect; //Fast Track: Othogonal rectangle? bool rect; //Fast Track: Othogonal rectangle?
}; };
@ -217,7 +217,6 @@ struct SwImage
SwOutline* outline = nullptr; SwOutline* outline = nullptr;
SwRleData* rle = nullptr; SwRleData* rle = nullptr;
uint32_t* data = nullptr; uint32_t* data = nullptr;
SwBBox bbox;
uint32_t w, h; uint32_t w, h;
}; };
@ -277,12 +276,12 @@ SwPoint mathTransform(const Point* to, const Matrix* transform);
void shapeReset(SwShape* shape); void shapeReset(SwShape* shape);
bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform); bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform);
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform); bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox);
bool shapePrepared(SwShape* shape); bool shapePrepared(SwShape* shape);
bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias, bool hasComposite); bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias, bool hasComposite);
void shapeDelOutline(SwShape* shape, uint32_t tid); void shapeDelOutline(SwShape* shape, uint32_t tid);
void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform); void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip); bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox);
void shapeFree(SwShape* shape); void shapeFree(SwShape* shape);
void shapeDelStroke(SwShape* shape); void shapeDelStroke(SwShape* shape);
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable); bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable);
@ -294,9 +293,9 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid); SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid);
void strokeFree(SwStroke* stroke); void strokeFree(SwStroke* stroke);
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform); bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox);
bool imagePrepared(SwImage* image); bool imagePrepared(SwImage* image);
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, bool antiAlias, bool hasComposite); bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, SwBBox& bbox, bool antiAlias, bool hasComposite);
void imageDelOutline(SwImage* image, uint32_t tid); void imageDelOutline(SwImage* image, uint32_t tid);
void imageReset(SwImage* image); void imageReset(SwImage* image);
bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform); bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform);
@ -325,7 +324,7 @@ void mpoolRetStrokeOutline(unsigned idx);
bool rasterCompositor(SwSurface* surface); bool rasterCompositor(SwSurface* surface);
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id); bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, uint8_t opacity); bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, SwBBox& bbox, uint8_t opacity);
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a); bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
bool rasterClear(SwSurface* surface); bool rasterClear(SwSurface* surface);

View file

@ -90,13 +90,13 @@ static bool _checkValid(const SwOutline* outline, const SwBBox& bbox, const SwSi
/************************************************************************/ /************************************************************************/
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform) bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox)
{ {
if (!imageGenOutline(image, pdata, tid, transform)) return false; if (!imageGenOutline(image, pdata, tid, transform)) return false;
if (!_updateBBox(image->outline, image->bbox, clip)) return false; if (!_updateBBox(image->outline, bbox, clip)) return false;
if (!_checkValid(image->outline, image->bbox, clip)) return false; if (!_checkValid(image->outline, bbox, clip)) return false;
return true; return true;
} }
@ -108,9 +108,9 @@ bool imagePrepared(SwImage* image)
} }
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, bool antiAlias, bool hasComposite) bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwSize& clip, SwBBox& bbox, bool antiAlias, bool hasComposite)
{ {
if ((image->rle = rleRender(image->rle, image->outline, image->bbox, clip, antiAlias))) return true; if ((image->rle = rleRender(image->rle, image->outline, bbox, clip, antiAlias))) return true;
return false; return false;
} }
@ -127,7 +127,6 @@ void imageReset(SwImage* image)
{ {
rleReset(image->rle); rleReset(image->rle);
image->rle = nullptr; image->rle = nullptr;
_initBBox(image->bbox);
} }

View file

@ -498,7 +498,7 @@ bool rasterClear(SwSurface* surface)
} }
bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, uint8_t opacity) bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, SwBBox& bbox, uint8_t opacity)
{ {
Matrix invTransform; Matrix invTransform;
@ -512,11 +512,11 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, ui
else { else {
// Fast track // Fast track
if (_identify(transform)) { if (_identify(transform)) {
return _rasterImage(surface, image->data, image->w, image->h, image->bbox); return _rasterImage(surface, image->data, image->w, image->h, bbox);
} }
else { else {
if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, image->bbox, &invTransform); if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform);
return _rasterImage(surface, image->data, image->w, image->h, image->bbox, &invTransform); return _rasterImage(surface, image->data, image->w, image->h, bbox, &invTransform);
} }
} }
} }

View file

@ -35,6 +35,7 @@ struct SwComposite
SwSurface surface; SwSurface surface;
SwSurface* recover; SwSurface* recover;
SwImage image; SwImage image;
SwBBox bbox;
bool valid; bool valid;
}; };
@ -46,6 +47,15 @@ struct SwTask : Task
RenderUpdateFlag flags = RenderUpdateFlag::None; RenderUpdateFlag flags = RenderUpdateFlag::None;
Array<Composite> compList; Array<Composite> compList;
uint32_t opacity; uint32_t opacity;
SwBBox bbox = {{0, 0}, {0, 0}}; //Whole Rendering Region
void bounds(uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
if (x) *x = bbox.min.x;
if (y) *y = bbox.min.y;
if (w) *w = bbox.max.x - bbox.min.x;
if (h) *h = bbox.max.y - bbox.min.y;
}
virtual bool dispose() = 0; virtual bool dispose() = 0;
}; };
@ -86,7 +96,7 @@ struct SwShapeTask : SwTask
bool renderShape = (alpha > 0 || sdata->fill()); bool renderShape = (alpha > 0 || sdata->fill());
if (renderShape || strokeAlpha) { if (renderShape || strokeAlpha) {
shapeReset(&shape); shapeReset(&shape);
if (!shapePrepare(&shape, sdata, tid, clip, transform)) goto end; if (!shapePrepare(&shape, sdata, tid, clip, transform, bbox)) goto end;
if (renderShape) { if (renderShape) {
/* We assume that if stroke width is bigger than 2, /* We assume that if stroke width is bigger than 2,
shape outline below stroke could be full covered by stroke drawing. shape outline below stroke could be full covered by stroke drawing.
@ -114,7 +124,7 @@ struct SwShapeTask : SwTask
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
if (strokeAlpha > 0) { if (strokeAlpha > 0) {
shapeResetStroke(&shape, sdata, transform); shapeResetStroke(&shape, sdata, transform);
if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip)) goto end; if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip, bbox)) goto end;
++addStroking; ++addStroking;
} else { } else {
shapeDelStroke(&shape); shapeDelStroke(&shape);
@ -167,11 +177,11 @@ struct SwImageTask : SwTask
if (prepareImage) { if (prepareImage) {
imageReset(&image); imageReset(&image);
if (!imagePrepare(&image, pdata, tid, clip, transform)) goto end; if (!imagePrepare(&image, pdata, tid, clip, transform, bbox)) goto end;
//Composition? //Composition?
if (compList.count > 0) { if (compList.count > 0) {
if (!imageGenRle(&image, pdata, clip, false, true)) goto end; if (!imageGenRle(&image, pdata, clip, bbox, false, true)) goto end;
if (image.rle) { if (image.rle) {
for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) { for (auto comp = compList.data; comp < (compList.data + compList.count); ++comp) {
if ((*comp).method == CompositeMethod::ClipPath) { if ((*comp).method == CompositeMethod::ClipPath) {
@ -274,12 +284,21 @@ bool SwRenderer::postRender()
} }
bool SwRenderer::renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
static_cast<SwTask*>(data)->bounds(x, y, w, h);
return true;
}
bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data) bool SwRenderer::render(TVG_UNUSED const Picture& picture, void *data)
{ {
auto task = static_cast<SwImageTask*>(data); auto task = static_cast<SwImageTask*>(data);
task->done(); task->done();
return rasterImage(surface, &task->image, task->transform, task->opacity); return rasterImage(surface, &task->image, task->transform, task->bbox, task->opacity);
} }
@ -316,16 +335,10 @@ void* SwRenderer::beginComposite(uint32_t x, uint32_t y, uint32_t w, uint32_t h)
if (x + w > surface->w) w = (surface->w - x); if (x + w > surface->w) w = (surface->w - x);
if (y + h > surface->h) h = (surface->h - y); if (y + h > surface->h) h = (surface->h - y);
//FIXME: Should be removed if xywh is proper. comp->bbox.min.x = x;
x = 0; comp->bbox.min.y = y;
y = 0; comp->bbox.max.x = x + w;
w = surface->w; comp->bbox.max.y = y + h;
h = surface->h;
comp->image.bbox.min.x = x;
comp->image.bbox.min.y = y;
comp->image.bbox.max.x = x + w;
comp->image.bbox.max.y = y + h;
comp->image.w = surface->w; comp->image.w = surface->w;
comp->image.h = surface->h; comp->image.h = surface->h;
@ -362,7 +375,7 @@ bool SwRenderer::endComposite(void* p, uint32_t opacity)
//Recover render target //Recover render target
surface = comp->recover; surface = comp->recover;
auto ret = rasterImage(surface, &comp->image, nullptr, opacity); auto ret = rasterImage(surface, &comp->image, nullptr, comp->bbox, opacity);
comp->valid = true; comp->valid = true;
@ -382,12 +395,8 @@ bool SwRenderer::render(TVG_UNUSED const Shape& shape, void *data)
//Do Composition //Do Composition
if (task->compStroking) { if (task->compStroking) {
//Add stroke size to bounding box. uint32_t x, y, w, h;
auto strokeWidth = static_cast<SwCoord>(ceilf(task->sdata->strokeWidth() * 0.5f)); task->bounds(&x, &y, &w, &h);
auto x = task->shape.bbox.min.x - strokeWidth;
auto y = task->shape.bbox.min.y - strokeWidth;
auto w = task->shape.bbox.max.x + strokeWidth - x;
auto h = task->shape.bbox.max.y + strokeWidth - y;
ctx = beginComposite(x, y, w, h); ctx = beginComposite(x, y, w, h);
opacity = 255; opacity = 255;
//No Composition //No Composition

View file

@ -43,6 +43,7 @@ public:
bool dispose(void *data) override; bool dispose(void *data) override;
bool preRender() override; bool preRender() override;
bool postRender() override; bool postRender() override;
bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) override;
bool clear() override; bool clear() override;
bool render(const Shape& shape, void *data) override; bool render(const Shape& shape, void *data) override;
bool render(const Picture& picture, void *data) override; bool render(const Picture& picture, void *data) override;

View file

@ -420,7 +420,7 @@ bool _fastTrack(const SwOutline* outline)
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform) bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform, SwBBox& bbox)
{ {
if (!shapeGenOutline(shape, sdata, tid, transform)) return false; if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
@ -428,6 +428,8 @@ bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize
if (!_checkValid(shape->outline, shape->bbox, clip)) return false; if (!_checkValid(shape->outline, shape->bbox, clip)) return false;
bbox = shape->bbox;
return true; return true;
} }
@ -588,7 +590,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor
} }
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip) bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip, SwBBox& bbox)
{ {
SwOutline* shapeOutline = nullptr; SwOutline* shapeOutline = nullptr;
SwOutline* strokeOutline = nullptr; SwOutline* strokeOutline = nullptr;
@ -619,7 +621,6 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
goto fail; goto fail;
} }
SwBBox bbox;
_updateBBox(strokeOutline, bbox); _updateBBox(strokeOutline, bbox);
if (!_checkValid(strokeOutline, bbox, clip)) { if (!_checkValid(strokeOutline, bbox, clip)) {

View file

@ -37,6 +37,7 @@ namespace tvg
virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has. virtual void* update(RenderMethod& renderer, const RenderTransform* transform, uint32_t opacity, Array<Composite>& compList, RenderUpdateFlag pFlag) = 0; //Return engine data if it has.
virtual bool render(RenderMethod& renderer) = 0; virtual bool render(RenderMethod& renderer) = 0;
virtual bool bounds(float* x, float* y, float* w, float* h) const = 0; virtual bool bounds(float* x, float* y, float* w, float* h) const = 0;
virtual bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const = 0;
virtual Paint* duplicate() = 0; virtual Paint* duplicate() = 0;
}; };
@ -125,6 +126,11 @@ namespace tvg
return smethod->bounds(x, y, w, h); return smethod->bounds(x, y, w, h);
} }
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const
{
return smethod->bounds(renderer, x, y, w, h);
}
bool dispose(RenderMethod& renderer) bool dispose(RenderMethod& renderer)
{ {
if (compTarget) compTarget->pImpl->dispose(renderer); if (compTarget) compTarget->pImpl->dispose(renderer);
@ -212,6 +218,11 @@ namespace tvg
return inst->bounds(x, y, w, h); return inst->bounds(x, y, w, h);
} }
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) const override
{
return inst->bounds(renderer, x, y, w, h);
}
bool dispose(RenderMethod& renderer) override bool dispose(RenderMethod& renderer) override
{ {
return inst->dispose(renderer); return inst->dispose(renderer);

View file

@ -153,6 +153,13 @@ struct Picture::Impl
return paint->pImpl->bounds(x, y, w, h); return paint->pImpl->bounds(x, y, w, h);
} }
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
if (edata) return renderer.renderRegion(edata, x, y, w, h);
if (paint) paint->pImpl->bounds(renderer, x, y, w, h);
return false;
}
Result load(const string& path) Result load(const string& path)
{ {
if (loader) loader->close(); if (loader) loader->close();

View file

@ -74,6 +74,7 @@ public:
virtual bool render(const Shape& shape, void *data) = 0; virtual bool render(const Shape& shape, void *data) = 0;
virtual bool render(const Picture& picture, void *data) = 0; virtual bool render(const Picture& picture, void *data) = 0;
virtual bool postRender() = 0; virtual bool postRender() = 0;
virtual bool renderRegion(void* data, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h) = 0;
virtual bool clear() = 0; virtual bool clear() = 0;
virtual bool sync() = 0; virtual bool sync() = 0;
}; };

View file

@ -63,17 +63,15 @@ struct Scene::Impl
return edata; return edata;
} }
bool render(RenderMethod &renderer) bool render(RenderMethod& renderer)
{ {
void* ctx = nullptr; void* ctx = nullptr;
//Half translucent. This requires intermediate composition. //Half translucent. This requires intermediate composition.
if (opacity < 255 && opacity > 0) { if (opacity < 255 && opacity > 0) {
//FIXME: Get Render Boundary of Shapes. uint32_t x, y, w, h;
//float x, y, w, h; if (!bounds(renderer, &x, &y, &w, &h)) return false;
//if (!bounds(&x, &y, &w, &h)) return false; ctx = renderer.beginComposite(x, y, w, h);
//ctx = renderer.beginComposite(roundf(x), roundf(y), roundf(w), roundf(h));
ctx = renderer.beginComposite(0, 0, 0, 0);
} }
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) { for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
@ -85,6 +83,38 @@ struct Scene::Impl
return true; return true;
} }
bool bounds(RenderMethod& renderer, uint32_t* px, uint32_t* py, uint32_t* pw, uint32_t* ph)
{
if (paints.count == 0) return false;
uint32_t x1 = UINT32_MAX;
uint32_t y1 = UINT32_MAX;
uint32_t x2 = 0;
uint32_t y2 = 0;
for (auto paint = paints.data; paint < (paints.data + paints.count); ++paint) {
uint32_t x = UINT32_MAX;
uint32_t y = UINT32_MAX;
uint32_t w = 0;
uint32_t h = 0;
if (!(*paint)->pImpl->bounds(renderer, &x, &y, &w, &h)) continue;
//Merge regions
if (x < x1) x1 = x;
if (x2 < x + w) x2 = (x + w);
if (y < y1) y1 = y;
if (y2 < y + h) y2 = (y + h);
}
if (px) *px = x1;
if (py) *py = y1;
if (pw) *pw = (x2 - x1);
if (ph) *ph = (y2 - y1);
return true;
}
bool bounds(float* px, float* py, float* pw, float* ph) bool bounds(float* px, float* py, float* pw, float* ph)
{ {
if (paints.count == 0) return false; if (paints.count == 0) return false;

View file

@ -230,6 +230,11 @@ struct Shape::Impl
return this->edata; return this->edata;
} }
bool bounds(RenderMethod& renderer, uint32_t* x, uint32_t* y, uint32_t* w, uint32_t* h)
{
return renderer.renderRegion(edata, x, y, w, h);
}
bool bounds(float* x, float* y, float* w, float* h) bool bounds(float* x, float* y, float* w, float* h)
{ {
auto ret = path.bounds(x, y, w, h); auto ret = path.bounds(x, y, w, h);