This adds support for a static scene mode,
allowing a scene to be treated as a static image.
In this mode, partial rendering for the inner
drawable components is skipped. This is especially
useful for scenes designed to be fully updated as a whole,
such as those used in fully dynamic Lottie contents.
issue: https://github.com/thorvg/thorvg/issues/1747
Partial Rendering refers to a rendering technique where
only a portion of the scene or screen is updated, rather
than redrawing the entire output. It is commonly used as
a performance optimization strategy, focusing on redrawing
only the regions that have changed, often called dirty regions.
This introduces RenderDirtyRegion, which assists
in collecting a compact dirty region from render tasks.
Each backend can utilize this class to support efficient partial rendering.
This is implemented using a Line Sweep and Subdivision Merging O(NlogN).
The basic per-frame workflow is as follows:
1. RenderDirtyRegion::prepare() //Call this in Renderer::preRender().
2. RenderDirtyRegion::add() //Add all dirty paints for the frame before rendering.
3. RenderDirtyRegion::commit() //Generate the partial rendering region list before rendering.
4. RenderDirtyRegion::get() //Retrieve the current dirty region list and use it when drawing paints.
5. RenderDirtyRegion::clear() //Reset the state.
also removed the skip() from paint since engines need to capture the
drawable object in any case.
issue: https://github.com/thorvg/thorvg/issues/1747
Implemented support for clipping shapes and images using a render region
bounding box at render time. This allows partial drawing of content,
laying the groundwork for upcoming partial rendering functionality.
for fast access of the drawing region from the linear rle data,
we introduced the binary search for begin/end of rle instead of
additional y index buffer.
There is a reason for not using a y-index buffer:
the shapes in the RLE are not single, continuous shapes
but multiple shapes scattered across the space.
which means that we need a double-associated data structure
per shapes for y indexing, and this data preparation wouldn't be
cheaper enough than realtime binary search especially animated data.
This also helps for current clipping performance by utilizing
the introduced fast-clipping region access.
issue: https://github.com/thorvg/thorvg/issues/1747
- Ensured proper closure of star and polygon shapes.
The start and end points now match - in cases with
degenerate bezier curves, the second-to-last point
is also aligned.
Proper shape closure is necessary for modifiers like
offset (future pucker bloat). If the start and end
points aren’t equal (within the comparison function’s
precision), the shape will be closed with a straight
line - and during offsetting, that line will become
visible, even though it’s not intended.
- Use of the internal _zero() function for point equality check
in modifiers algs led to incorrect results when p2.x or p2.y
was zero (division by zero).
The intent was to treat nearly identical points as equal, but
this approach was flawed - at the modifier stage, it’s no longer
possible to tell if small gaps are intentional or just due to
limited numerical precision (as seen for example in the difference
between the start and end points of star/polygon shapes).
This approach should be introduced in d8ebd8b4f5.
Using FLOAT_EPSILON is not sufficient due to numerical precision,
since it's later inverted, and its very small value leads to
significant errors during inversion.
../src/loaders/jpg/tvgJpgd.cpp:670:10: note: ‘padding_flag’ was declared here
670 | bool padding_flag;
| ^~~~~~~~~~~~
../src/loaders/jpg/tvgJpgd.cpp:674:9: warning: ‘padding_flag’ may be used uninitialized [-Wmaybe-uninitialized]
674 | if (padding_flag) return 0xFF;
| ^~
If the radial gradient's focal point lies outside
the end circle, it's projected onto the edge.
A slight inward offset is applied to avoid numerical
issues.
Note:
Focal point support in the sw and wg engines is
consistent with the SVG 1.1 standard, whereas the gl
engine aligns with the SVG 2.0 standard.
After introducing staged buffer removed the need for forced flush of each texture data into gpu
General approach used for all data types
Can increase performance on discrete GPUs
Removed the paint parameter previously used to forcibly
update a single paint.
This behavior was unsafe in ThorVG, as a single paint
object may be connected to others through the scene graph.
Now, the canvas engine is responsible for properly updating
all damaged paints as needed, allowing the user to simply
call update() in any case.
API Modifications:
C++ API:
* Result Canvas::update(Paint* paint) -> Result Canvas::update()
CAPI:
- tvg_canvas_update_paint()
Issue: https://github.com/thorvg/thorvg/issues/3116
One point was skipped during the creation of the offset
corner. The error was not visible because the point lies
on the line, but it will become apparent if further
modifiers are applied to the object (not supported now).
previous logic doesn't work if the clipping shape
has any inner corners. replace the logic
with a intermediate composition approach for
stability.
- performance can be drop at texture clipping by ~11%
- size is reduced by -0.5kb
issue: https://github.com/thorvg/thorvg/issues/3520
The old approach often produced incorrect results,
especially when the fixed pixel had a noticeably
different color from the texture due to the AA
target blending position was fixed.
Although the previous method worked well as an analytical AA
solution with good speed and fair quality, it couldn't
overcome the above limitation.
The new approach still applies AA only to polygon edges
for efficiency. While the quality may be slightly reduced,
it offers greater stability.
- binary size: -1.1kb
- performance diff: ignoreable
issue: https://github.com/thorvg/thorvg/issues/1729
- Replaced `modff()` with a custom method,
boosting texture mapping performance by ~15%.
- Unified opacity/non-opacity logic for improved
binary size efficiency(-0.5kb).
- Implemented minor changes for better cache effectiveness.
The clear flag specified in Canvas::draw is ignored when set to false,
since GlRenderer::mClearBuffer is never explicitly reset to false.
This commit ensures that mClearBuffer is reset to its default (false)
after being used, so that the clear operation behaves correctly per frame.
- Issue: #1779