mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
renderer: ++stabilization
This introduces a managed condition to precisely control the canvas updates. This prevents a crash when the target is changed and drawn without any update calls. issue: https://github.com/thorvg/thorvg/issues/2484
This commit is contained in:
parent
23688dfb78
commit
d1067ad080
4 changed files with 21 additions and 21 deletions
|
@ -26,7 +26,7 @@
|
||||||
#include "tvgPaint.h"
|
#include "tvgPaint.h"
|
||||||
|
|
||||||
|
|
||||||
enum Status : uint8_t {Synced = 0, Updating, Drawing};
|
enum Status : uint8_t {Synced = 0, Updating, Drawing, Damanged};
|
||||||
|
|
||||||
struct Canvas::Impl
|
struct Canvas::Impl
|
||||||
{
|
{
|
||||||
|
@ -35,8 +35,6 @@ struct Canvas::Impl
|
||||||
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
|
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
|
||||||
Status status = Status::Synced;
|
Status status = Status::Synced;
|
||||||
|
|
||||||
bool refresh = false; //if all paints should be updated by force.
|
|
||||||
|
|
||||||
Impl(RenderMethod* pRenderer) : renderer(pRenderer)
|
Impl(RenderMethod* pRenderer) : renderer(pRenderer)
|
||||||
{
|
{
|
||||||
renderer->ref();
|
renderer->ref();
|
||||||
|
@ -87,18 +85,13 @@ struct Canvas::Impl
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void needRefresh()
|
|
||||||
{
|
|
||||||
refresh = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result update(Paint* paint, bool force)
|
Result update(Paint* paint, bool force)
|
||||||
{
|
{
|
||||||
if (paints.empty() || status == Status::Drawing) return Result::InsufficientCondition;
|
if (paints.empty() || status == Status::Drawing) return Result::InsufficientCondition;
|
||||||
|
|
||||||
Array<RenderData> clips;
|
Array<RenderData> clips;
|
||||||
auto flag = RenderUpdateFlag::None;
|
auto flag = RenderUpdateFlag::None;
|
||||||
if (refresh || force) flag = RenderUpdateFlag::All;
|
if (status == Status::Damanged || force) flag = RenderUpdateFlag::All;
|
||||||
|
|
||||||
if (paint) {
|
if (paint) {
|
||||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||||
|
@ -106,7 +99,6 @@ struct Canvas::Impl
|
||||||
for (auto paint : paints) {
|
for (auto paint : paints) {
|
||||||
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
paint->pImpl->update(renderer, nullptr, clips, 255, flag);
|
||||||
}
|
}
|
||||||
refresh = false;
|
|
||||||
}
|
}
|
||||||
status = Status::Updating;
|
status = Status::Updating;
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
|
@ -114,6 +106,7 @@ struct Canvas::Impl
|
||||||
|
|
||||||
Result draw()
|
Result draw()
|
||||||
{
|
{
|
||||||
|
if (status == Status::Damanged) update(nullptr, false);
|
||||||
if (status == Status::Drawing || paints.empty() || !renderer->preRender()) return Result::InsufficientCondition;
|
if (status == Status::Drawing || paints.empty() || !renderer->preRender()) return Result::InsufficientCondition;
|
||||||
|
|
||||||
bool rendered = false;
|
bool rendered = false;
|
||||||
|
@ -129,7 +122,7 @@ struct Canvas::Impl
|
||||||
|
|
||||||
Result sync()
|
Result sync()
|
||||||
{
|
{
|
||||||
if (status == Status::Synced) return Result::InsufficientCondition;
|
if (status == Status::Synced || status == Status::Damanged) return Result::InsufficientCondition;
|
||||||
|
|
||||||
if (renderer->sync()) {
|
if (renderer->sync()) {
|
||||||
status = Status::Synced;
|
status = Status::Synced;
|
||||||
|
@ -141,7 +134,8 @@ struct Canvas::Impl
|
||||||
|
|
||||||
Result viewport(int32_t x, int32_t y, int32_t w, int32_t h)
|
Result viewport(int32_t x, int32_t y, int32_t w, int32_t h)
|
||||||
{
|
{
|
||||||
if (status != Status::Synced) return Result::InsufficientCondition;
|
if (status != Status::Damanged && status != Status::Synced) return Result::InsufficientCondition;
|
||||||
|
|
||||||
RenderRegion val = {x, y, w, h};
|
RenderRegion val = {x, y, w, h};
|
||||||
//intersect if the target buffer is already set.
|
//intersect if the target buffer is already set.
|
||||||
auto surface = renderer->mainSurface();
|
auto surface = renderer->mainSurface();
|
||||||
|
@ -151,7 +145,7 @@ struct Canvas::Impl
|
||||||
if (vport == val) return Result::Success;
|
if (vport == val) return Result::Success;
|
||||||
renderer->viewport(val);
|
renderer->viewport(val);
|
||||||
vport = val;
|
vport = val;
|
||||||
needRefresh();
|
status = Status::Damanged;
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,9 @@ GlCanvas::~GlCanvas()
|
||||||
Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept
|
Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept
|
||||||
{
|
{
|
||||||
#ifdef THORVG_GL_RASTER_SUPPORT
|
#ifdef THORVG_GL_RASTER_SUPPORT
|
||||||
if (Canvas::pImpl->status != Status::Synced) return Result::InsufficientCondition;
|
if (Canvas::pImpl->status != Status::Damanged && Canvas::pImpl->status != Status::Synced) {
|
||||||
|
return Result::InsufficientCondition;
|
||||||
|
}
|
||||||
|
|
||||||
//We know renderer type, avoid dynamic_cast for performance.
|
//We know renderer type, avoid dynamic_cast for performance.
|
||||||
auto renderer = static_cast<GlRenderer*>(Canvas::pImpl->renderer);
|
auto renderer = static_cast<GlRenderer*>(Canvas::pImpl->renderer);
|
||||||
|
@ -73,7 +75,7 @@ Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept
|
||||||
renderer->viewport(Canvas::pImpl->vport);
|
renderer->viewport(Canvas::pImpl->vport);
|
||||||
|
|
||||||
//Paints must be updated again with this new target.
|
//Paints must be updated again with this new target.
|
||||||
Canvas::pImpl->needRefresh();
|
Canvas::pImpl->status = Status::Damanged;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -82,7 +82,9 @@ Result SwCanvas::mempool(MempoolPolicy policy) noexcept
|
||||||
Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept
|
Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept
|
||||||
{
|
{
|
||||||
#ifdef THORVG_SW_RASTER_SUPPORT
|
#ifdef THORVG_SW_RASTER_SUPPORT
|
||||||
if (Canvas::pImpl->status != Status::Synced) return Result::InsufficientCondition;
|
if (Canvas::pImpl->status != Status::Damanged && Canvas::pImpl->status != Status::Synced) {
|
||||||
|
return Result::InsufficientCondition;
|
||||||
|
}
|
||||||
|
|
||||||
//We know renderer type, avoid dynamic_cast for performance.
|
//We know renderer type, avoid dynamic_cast for performance.
|
||||||
auto renderer = static_cast<SwRenderer*>(Canvas::pImpl->renderer);
|
auto renderer = static_cast<SwRenderer*>(Canvas::pImpl->renderer);
|
||||||
|
@ -92,12 +94,12 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
||||||
Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h};
|
Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h};
|
||||||
renderer->viewport(Canvas::pImpl->vport);
|
renderer->viewport(Canvas::pImpl->vport);
|
||||||
|
|
||||||
//Paints must be updated again with this new target.
|
|
||||||
Canvas::pImpl->needRefresh();
|
|
||||||
|
|
||||||
//FIXME: The value must be associated with an individual canvas instance.
|
//FIXME: The value must be associated with an individual canvas instance.
|
||||||
ImageLoader::cs = static_cast<ColorSpace>(cs);
|
ImageLoader::cs = static_cast<ColorSpace>(cs);
|
||||||
|
|
||||||
|
//Paints must be updated again with this new target.
|
||||||
|
Canvas::pImpl->status = Status::Damanged;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
#endif
|
#endif
|
||||||
return Result::NonSupport;
|
return Result::NonSupport;
|
||||||
|
|
|
@ -57,7 +57,9 @@ WgCanvas::~WgCanvas()
|
||||||
Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h) noexcept
|
Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h) noexcept
|
||||||
{
|
{
|
||||||
#ifdef THORVG_WG_RASTER_SUPPORT
|
#ifdef THORVG_WG_RASTER_SUPPORT
|
||||||
if (Canvas::pImpl->status != Status::Synced) return Result::InsufficientCondition;
|
if (Canvas::pImpl->status != Status::Damanged && Canvas::pImpl->status != Status::Synced) {
|
||||||
|
return Result::InsufficientCondition;
|
||||||
|
}
|
||||||
|
|
||||||
if (!instance || !surface || (w == 0) || (h == 0)) return Result::InvalidArguments;
|
if (!instance || !surface || (w == 0) || (h == 0)) return Result::InvalidArguments;
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h) n
|
||||||
renderer->viewport(Canvas::pImpl->vport);
|
renderer->viewport(Canvas::pImpl->vport);
|
||||||
|
|
||||||
//Paints must be updated again with this new target.
|
//Paints must be updated again with this new target.
|
||||||
Canvas::pImpl->needRefresh();
|
Canvas::pImpl->status = Status::Damanged;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue