mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
renderer/engines: support the canvas viewport function.
The viewport function defines the rectangular area of the canvas that will be used for drawing operations. It is used to clip the rendering output to the boundaries of the rectangle. Apps can use this function to set the drawing region within the canvas. When the ThorVG canvas is partially inside the screen area such as during scrolling it could help enhance rendering performance. New Experimental API: - Result Canvas::viewport(int32_t x, int32_t y, int32_t w, int32_t h) noexcept; Issue: https://github.com/thorvg/thorvg/issues/2274
This commit is contained in:
parent
70708211fe
commit
42409987e2
10 changed files with 102 additions and 48 deletions
31
inc/thorvg.h
31
inc/thorvg.h
|
@ -623,6 +623,30 @@ public:
|
|||
*/
|
||||
virtual Result draw() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Sets the drawing region in the canvas.
|
||||
*
|
||||
* This function defines the rectangular area of the canvas that will be used for drawing operations.
|
||||
* The specified viewport is used to clip the rendering output to the boundaries of the rectangle.
|
||||
*
|
||||
* @param[in] x The x-coordinate of the upper-left corner of the rectangle.
|
||||
* @param[in] y The y-coordinate of the upper-left corner of the rectangle.
|
||||
* @param[in] w The width of the rectangle.
|
||||
* @param[in] h The height of the rectangle.
|
||||
*
|
||||
* @retval Result::Success when succeed, Result::InsufficientCondition otherwise.
|
||||
*
|
||||
* @see SwCanvas::target()
|
||||
* @see GlCanvas::target()
|
||||
* @see WgCanvas::target()
|
||||
*
|
||||
* @warning It's not allowed to change the viewport during Canvas::push() - Canvas::sync() or Canvas::update() - Canvas::sync().
|
||||
*
|
||||
* @note The specified viewport region will be intersected with the target region.
|
||||
* @note Experimental API
|
||||
*/
|
||||
virtual Result viewport(int32_t x, int32_t y, int32_t w, int32_t h) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Guarantees that drawing task is finished.
|
||||
*
|
||||
|
@ -1611,7 +1635,9 @@ public:
|
|||
* @retval Result::InvalidArguments In case no valid pointer is provided or the width, or the height or the stride is zero.
|
||||
* @retval Result::NonSupport In case the software engine is not supported.
|
||||
*
|
||||
* @warning Do not access @p buffer during Canvas::draw() - Canvas::sync(). It should not be accessed while TVG is writing on it.
|
||||
* @warning Do not access @p buffer during Canvas::push() - Canvas::sync(). It should not be accessed while the engine is writing on it.
|
||||
*
|
||||
* @see Canvas::viewport()
|
||||
*/
|
||||
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept;
|
||||
|
||||
|
@ -1677,6 +1703,8 @@ public:
|
|||
* @warning This API is experimental and not officially supported. It may be modified or removed in future versions.
|
||||
* @warning Drawing on the main surface is currently not permitted. If the identifier (@p id) is set to @c 0, the operation will be aborted.
|
||||
*
|
||||
* @see Canvas::viewport()
|
||||
*
|
||||
* @note Currently, this only allows the GL_RGBA8 color space format.
|
||||
* @note Experimental API
|
||||
*/
|
||||
|
@ -1715,6 +1743,7 @@ public:
|
|||
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
|
||||
*
|
||||
* @note Experimental API
|
||||
* @see Canvas::viewport()
|
||||
*/
|
||||
Result target(void* window, uint32_t w, uint32_t h) noexcept;
|
||||
|
||||
|
|
|
@ -63,11 +63,6 @@ bool GlRenderer::target(int32_t id, uint32_t w, uint32_t h)
|
|||
surface.w = w;
|
||||
surface.h = h;
|
||||
|
||||
mViewport.x = 0;
|
||||
mViewport.y = 0;
|
||||
mViewport.w = surface.w;
|
||||
mViewport.h = surface.h;
|
||||
|
||||
mTargetViewport.x = 0;
|
||||
mTargetViewport.y = 0;
|
||||
mTargetViewport.w = surface.w;
|
||||
|
@ -459,7 +454,7 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const
|
|||
|
||||
RenderRegion GlRenderer::viewport()
|
||||
{
|
||||
return {0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)};
|
||||
return mViewport;
|
||||
}
|
||||
|
||||
|
||||
|
@ -503,7 +498,7 @@ GlRenderer* GlRenderer::gen()
|
|||
return new GlRenderer();
|
||||
}
|
||||
|
||||
GlRenderer::GlRenderer() :mViewport() ,mGpuBuffer(new GlStageBuffer), mPrograms(), mComposePool()
|
||||
GlRenderer::GlRenderer() :mGpuBuffer(new GlStageBuffer), mPrograms(), mComposePool()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -429,22 +429,12 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h,
|
|||
surface->channelSize = CHANNEL_SIZE(cs);
|
||||
surface->premultiplied = true;
|
||||
|
||||
vport.x = vport.y = 0;
|
||||
vport.w = surface->w;
|
||||
vport.h = surface->h;
|
||||
|
||||
return rasterCompositor(surface);
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::preRender()
|
||||
{
|
||||
if (surface) {
|
||||
vport.x = vport.y = 0;
|
||||
vport.w = surface->w;
|
||||
vport.h = surface->h;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,12 @@ Result Canvas::update(Paint* paint) noexcept
|
|||
}
|
||||
|
||||
|
||||
Result Canvas::viewport(int32_t x, int32_t y, int32_t w, int32_t h) noexcept
|
||||
{
|
||||
return pImpl->viewport(x, y, w, h);
|
||||
}
|
||||
|
||||
|
||||
Result Canvas::sync() noexcept
|
||||
{
|
||||
return pImpl->sync();
|
||||
|
|
|
@ -32,6 +32,7 @@ struct Canvas::Impl
|
|||
|
||||
list<Paint*> paints;
|
||||
RenderMethod* renderer;
|
||||
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
|
||||
Status status = Status::Synced;
|
||||
|
||||
bool refresh = false; //if all paints should be updated by force.
|
||||
|
@ -44,11 +45,11 @@ struct Canvas::Impl
|
|||
~Impl()
|
||||
{
|
||||
//make it sure any deffered jobs
|
||||
if (renderer) renderer->sync();
|
||||
renderer->sync();
|
||||
|
||||
clearPaints();
|
||||
|
||||
if (renderer && (renderer->unref() == 0)) delete(renderer);
|
||||
if (renderer->unref() == 0) delete(renderer);
|
||||
}
|
||||
|
||||
void clearPaints()
|
||||
|
@ -78,7 +79,7 @@ struct Canvas::Impl
|
|||
|
||||
//Clear render target
|
||||
if (buffer) {
|
||||
if (!renderer || !renderer->clear()) return Result::InsufficientCondition;
|
||||
if (!renderer->clear()) return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
if (paints) clearPaints();
|
||||
|
@ -137,6 +138,22 @@ struct Canvas::Impl
|
|||
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
Result viewport(int32_t x, int32_t y, int32_t w, int32_t h)
|
||||
{
|
||||
if (status != Status::Synced) return Result::InsufficientCondition;
|
||||
RenderRegion val = {x, y, w, h};
|
||||
//intersect if the target buffer is already set.
|
||||
auto surface = renderer->mainSurface();
|
||||
if (surface && surface->w > 0 && surface->h > 0) {
|
||||
val.intersect({0, 0, (int32_t)surface->w, (int32_t)surface->h});
|
||||
}
|
||||
if (vport == val) return Result::Success;
|
||||
renderer->viewport(val);
|
||||
vport = val;
|
||||
needRefresh();
|
||||
return Result::Success;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _TVG_CANVAS_H_ */
|
||||
|
|
|
@ -68,6 +68,8 @@ Result GlCanvas::target(int32_t id, uint32_t w, uint32_t h) noexcept
|
|||
if (!renderer) return Result::MemoryCorruption;
|
||||
|
||||
if (!renderer->target(id, w, h)) return Result::Unknown;
|
||||
Canvas::pImpl->vport.intersect({0, 0, (int32_t)w, (int32_t)h});
|
||||
renderer->viewport(Canvas::pImpl->vport);
|
||||
|
||||
//Paints must be updated again with this new target.
|
||||
Canvas::pImpl->needRefresh();
|
||||
|
|
|
@ -60,3 +60,35 @@ RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransfo
|
|||
else if (rhs) m = rhs->m;
|
||||
else mathIdentity(&m);
|
||||
}
|
||||
|
||||
|
||||
void RenderRegion::intersect(const RenderRegion& rhs)
|
||||
{
|
||||
auto x1 = x + w;
|
||||
auto y1 = y + h;
|
||||
auto x2 = rhs.x + rhs.w;
|
||||
auto y2 = rhs.y + rhs.h;
|
||||
|
||||
x = (x > rhs.x) ? x : rhs.x;
|
||||
y = (y > rhs.y) ? y : rhs.y;
|
||||
w = ((x1 < x2) ? x1 : x2) - x;
|
||||
h = ((y1 < y2) ? y1 : y2) - y;
|
||||
|
||||
if (w < 0) w = 0;
|
||||
if (h < 0) h = 0;
|
||||
}
|
||||
|
||||
|
||||
void RenderRegion::add(const RenderRegion& rhs)
|
||||
{
|
||||
if (rhs.x < x) {
|
||||
w += (x - rhs.x);
|
||||
x = rhs.x;
|
||||
}
|
||||
if (rhs.y < y) {
|
||||
h += (y - rhs.y);
|
||||
y = rhs.y;
|
||||
}
|
||||
if (rhs.x + rhs.w > x + w) w = (rhs.x + rhs.w) - x;
|
||||
if (rhs.y + rhs.h > y + h) h = (rhs.y + rhs.h) - y;
|
||||
}
|
|
@ -98,34 +98,13 @@ struct RenderRegion
|
|||
{
|
||||
int32_t x, y, w, h;
|
||||
|
||||
void intersect(const RenderRegion& rhs)
|
||||
void intersect(const RenderRegion& rhs);
|
||||
void add(const RenderRegion& rhs);
|
||||
|
||||
bool operator==(const RenderRegion& rhs)
|
||||
{
|
||||
auto x1 = x + w;
|
||||
auto y1 = y + h;
|
||||
auto x2 = rhs.x + rhs.w;
|
||||
auto y2 = rhs.y + rhs.h;
|
||||
|
||||
x = (x > rhs.x) ? x : rhs.x;
|
||||
y = (y > rhs.y) ? y : rhs.y;
|
||||
w = ((x1 < x2) ? x1 : x2) - x;
|
||||
h = ((y1 < y2) ? y1 : y2) - y;
|
||||
|
||||
if (w < 0) w = 0;
|
||||
if (h < 0) h = 0;
|
||||
}
|
||||
|
||||
void add(const RenderRegion& rhs)
|
||||
{
|
||||
if (rhs.x < x) {
|
||||
w += (x - rhs.x);
|
||||
x = rhs.x;
|
||||
}
|
||||
if (rhs.y < y) {
|
||||
h += (y - rhs.y);
|
||||
y = rhs.y;
|
||||
}
|
||||
if (rhs.x + rhs.w > x + w) w = (rhs.x + rhs.w) - x;
|
||||
if (rhs.y + rhs.h > y + h) h = (rhs.y + rhs.h) - y;
|
||||
if (x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
if (!renderer) return Result::MemoryCorruption;
|
||||
|
||||
if (!renderer->target(buffer, stride, w, h, static_cast<ColorSpace>(cs))) return Result::InvalidArguments;
|
||||
Canvas::pImpl->vport.intersect({0, 0, (int32_t)w, (int32_t)h});
|
||||
renderer->viewport(Canvas::pImpl->vport);
|
||||
|
||||
//Paints must be updated again with this new target.
|
||||
Canvas::pImpl->needRefresh();
|
||||
|
|
|
@ -63,6 +63,8 @@ Result WgCanvas::target(void* window, uint32_t w, uint32_t h) noexcept
|
|||
if (!renderer) return Result::MemoryCorruption;
|
||||
|
||||
if (!renderer->target(window, w, h)) return Result::Unknown;
|
||||
Canvas::pImpl->vport.intersect({0, 0, (int32_t)w, (int32_t)h});
|
||||
renderer->viewport(Canvas::pImpl->vport);
|
||||
|
||||
//Paints must be updated again with this new target.
|
||||
Canvas::pImpl->needRefresh();
|
||||
|
|
Loading…
Add table
Reference in a new issue