Addresses this issue: https://2dimensions.slack.com/archives/C07VD44ASE5/p1739456802968219
Rive's RenderPath steals the memory for the RawPath the runtime builds, which is usually fine apart from cases where we expect to use the RawPath after drawing with it. For example, with inner feather we want to be able to compute the bounds of the RawPath after it has been drawn. If during animation a user turns on inner feathering on a path which has not changed recently, which need to be able to compute its bounds, we can't if the RawPath is now gone.
This also can happen with trim paths and dash paths which are re-trimmed/dashed after having being rendered a few frames. Right now we force rebuild the whole path to re-trim it because we lose the RawPath.
This PR allows the ShapePaintPath to hold on to its RawPath by adding RenderPath::addRawPath. This is optimized memory usage but not having the runtime need to re-alloc the RawPath whenever it animates, but it means we're further from making RenderPaths immutable.
For the future: It'd be good to chat about a long term solution that can accommodate all goals of allocating less memory (prior to this change we were re-allocating RawPath memory every frame when animating), not rebuilding paths as often, and still allow for immutability.
Diffs=
9058a3fdad Add RenderPath::addRawPath (#9038)
Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
Made lite rtti now use compile time hashes that use the name of the class with rtti enabled as the hash string.
Every use of rtti now needs to be a macro. but other then that, usage of lite rtti is unchanged.
Diffs=
2be44a0f45 Deterministic lite rtti (#8349)
Co-authored-by: Jonathon Copeland <jcopela4@gmail.com>
This gives better support for smaller screens and side-by-side windows.
Also standardize the formatting check on GitHub on version 17.
Diffs=
e52e9fff29 Drop the ColumnLimit to 80 for clang-format (#8320)
Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
- Most of tools/* have been moved to the new packages/runtime/tests. (Excludes fuzz and a few things with proprietary information)
- The tools/test are now in packages/runtime/unit_tests/renderer.
- The runtime/tests are now also moved, to the following packages/runtime/unit_tests/runtime (moved the "dev/tests" to packages/runtime/unit_tests)
- Thus unit_tests comprises of runtime and renderer tests (in the future we can add more categories as folder, this avoids too many tests in one folder)
- The rendering tests and runtime tests are built together in one executable called unit_tests*. This is what is described in the rive-runtime README - it is the way our developers can test the rendering (GPU) and runtime (CPU) unit tests in one go.
- pr_runtime_tests now builds and runs all the unit_tests, previously it was only executing the runtime tests, but now it includes the renderer tests for the (same platforms still tested: windows, windows msvc, mac, linux)
- The pr_tools_tests still tests the same workloads on the same devices, limited still to the rendering tests
ISSUES:
- We cannot build all the "tools" tests (e.g. imagediff, rendering tests) with the runtime tests. The runtime tests enables TESTING. I'm also not sure if running the runtime tests on all the devices is actually is worth it - if the tests are platform+device agnostic then probably not worth it.
- Windows pr_runtime_tests switched to ws-actions/configure-aws-credentials@v1 from microsoft/setup-msbuild@v1.1, as would not build otherwise, seems related to old version of premake
TODO:
- Verify of the performance is reasonable for runner / checkins
Diffs=
f25ee97a0 Opensource (tools) tests as part of runtime (#8035)
Co-authored-by: rivessamr <suki@rive.app>
The following now builds and runs as per README in viewer:
./build_viewer.sh gl tess run
Diffs=
7d00d35d3 Fix viewer tess builds (#7935)
Co-authored-by: rivessamr <suki@rive.app>
This lets us trim a raw path directly which means all the trim path logic from the editor can now be pushed down to the C++ runtime, even for the case where the rendering is still happening via Skia/Impeller, all our path operations can be done in C++ (without using RenderPath/MetricsPath/RenderMetricsPath/OnlyMetricsPath/etc). Basically, I needed to do this now to not have as many edge cases in the editor for the difference between using our runtime to render with PLS vs Flutter.
It also quite greatly simplifies the code! More lines removed than added!
Some tests will fail as I think we're using the MetricsPath in some other parts of the code, but that can be refactored following the patterns used here...
It also means that most of our runtime now speaks RawPath which means we can optimize/reserve memory ahead of time in a lot of cases (not doing that yet).
Diffs=
8486c3445 Get rid of MetricsPath. (#7371)
Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
We need to be more robust if a user tries to use mismatched factories and renderers. This PR creates a simple "lite_rtti" utility and applies it to every Render object. The renderers now abort early instead of crashing if they are given a Render object for the wrong renderer.
Diffs=
c357e7aa7 Add a "lite_rtti" utility and use it with Render objects (#6311)
Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
Adds map() and unmap() functions to RenderBuffer, and changes Mesh::draw() to map and update the vertex buffer instead of making a new one.
Also refactors RenderBuffer to just be a blob of data as opposed to an array of elements of fixed size and type. Removes the type-specific factory methods for creating RenderBuffers in favor of a single one that just takes a buffer type and buffer size.
Diffs=
06a187288 Make RenderBuffer mappable (#5907)
Co-authored-by: Chris Dalton <99840794+csmartdalton@users.noreply.github.com>
In profiling Joel we saw that RawPath::reset was causing a lot of re-allocation. We realized the intention of reset in most of Rive code is to actually call rewind, so we renamed it and made other adjustments (like calling RawPath::rewind).
Diffs=
f4046e60b Rename reset to rewind. (#5004)
- Adds template classes to polyfill missing vector extensions.
- Removes other language features not supported by this compiler.
- Fixes or suppresses various new warnings.
- Adds a GitHub action to compile and run the runtime tests on MSVC.
Diffs=
2a53e702a Get Rive tests compiling and running on MSVC
1733f0c5a Add Mat2D::mapPoints, optimized in SIMD
I forgot to initialize m_isClosed on TessRenderPath. 🤦🏼 This was causing flickering as sometimes the path would think it was closed when it wasn't.
Diffs=
5a24e63d0 Initialize isClosed on TessRenderPath (#4431)
Adding support for bidirectional text using SheenBidi to break styled runs into directional runs. This also needs to introduce the "baseDirection" of a paragraph (and the concept of a paragraph) in order to properly flow the runs after shaping.
Diffs=
291a3a02b Bidi Text Support (#4282)
Implement Iter as an STL-style iterator that can be traversed very
efficiently using range-for:
for (auto [verb, pts] : rawPath) { ... }
Manually inject the implicit moveTos in RawPath (namely, the implicit
moveTo(0) at the beginning of a path, if the client didn't add one, and
a similar moveTo after close).
The implicit moveTos fix a bug in RawPath::bounds where we were not
accounting for the implicit moveTo(0), as well as a bug in
ContourMeasureIter::tryNext where we expected the first contour in a
path to begin with PathVerb::move.
With the implicit moveTos guaranteed to be in the raw path, the iterator
can be simplified to just peek back one point and give a contiguous array
beginning with p0 for each verb. In addition to generally simplifying
things, one more perk of having all the points contiguous is that it
also enables fast SIMD loads.
IterateRawPath bench result:
MacOS NEON: 8.71ms -> 5.02 (58%)
Windows SSE: 5.63ms -> 4.20 (75%)
BuildRawPath bench result:
MacOS NEON: 2.09ms -> 2.19 (105%)
Windows SSE: 2.18ms -> 2.27 (104%)
Diffs=
fdeff54d1 Simpify RawPath::Iter (#4157)
Deletes the version that takes spans of points and verbs. We are
planning to inject the implicit moveTos into RawPath, at which point we
won't be able to just copy in arrays of points and verbs anymore.
Also changes the "RawPath" version of the factory method to take a
non-const "RawPath&" ref. This enables zero-copy construction via
stealing the arrays out from under the RawPath's points and verbs.
Diffs=
1bd616612 Update Factory::makeRenderPath to only accept a RawPath (#4211)
Implements an example Atlas packer (ideally run offline/in a pre-runtime step using the runtime API). Imagine a game engine like Defold using this at edit time/from within engine tooling to pack all the images necessary for all the Rive files in one level into a single Atlas/set of Atlases to minimize state changes when drawing the whole scene.
Example implementation is mostly here: packages/runtime/viewer/src/sample_tools
The example does both atlas packing and runtime image resolving from the Atlas from the same set of utility classes and their corresponding objects in order to keep the example simple (no serialization of the atlas metadata or pixels). It also uses a very naive packing technique, but it illustrates these main features:
1. find all the image assets in a file
2. packing them sequentially into an atlas
3. ...while building up metadata of where they are in the atlas
4. strips the images from the file
5. shows how to then re-load the file (with no in-band images) and use the generated atlas
6. implements a FileAssetResolver to resolve the images in the Atlas and provide UV transforms
Steps 1-4 are what an engine would do at edit/export time. Steps 5-6 show what a runtime would do to then use the files generated in steps 1-4.
All of this is implemented in the viewer, minor changes were necessary to the runtime to transform UVs with a transform provided by the RenderImage and fix some bugs. See how the viewer wires this all up here: 86dbad80c6/packages/runtime/viewer/src/viewer_content/scene_content.cpp (L185-L233)
Diffs=
38b70a98d Cleanup
ac44c1ad7 Fix broken test.
40d2fa966 Fixing UV modification at load time.
736bcf133 Adding an example atlas packer.
e42e484eb Starting to add example atlas packer.
438f98716 Adding imgui menu bar
When using the earcut triangulatation we pass through the vertex buffer straight from raw path and just use an index buffer generating by the triangulation.
Diffs=
ba0406a89 Fix tess test.
oops - forgot to build the tess renderer on the prev PR (should update the bots to build viewer in a few configs)
Diffs=
a7615ab7c Update call site for RawPath constructor
Adds a ```File::stripAssets``` utility method that is optionally compiled in. This allows removing in-band asset bytes from the file. It only does this for the provided asset types. Right now we only put image assets in-band, but in the future we may have fonts, scripts, sounds, other .riv files, etc so allowing the utility to only strip specific concrete file types is nice to have.
The next step will be to use this utility to show how you'd create an atlas out of the in-band images, strip out the images, and save a smaller .riv that uses images from that generated atlas.
I envision adding more utility methods like this for tools that want to manipulate Rive content at build/pre-package time. These should be able to be compiled out as they are rarely necessary at mass-consumption runtime (I doubt anyone wants these in WASM unless they're building their game engine, not just the player, in JS).
Diffs=
698af558e Fix linux build.
cb742eb08 Adds a utility to strip out FileAssetContents for given FileAsset types.
We were triangulating single paths using a simple and fast triangulator, but most of our paths in Rive are container paths (shapes) with a single path inside of them. In that case we were always going through the slower triangulator (which does evenOdd/nonZero winding). This catches containers with a single path and lets them go through the fast path too.
Diffs=
ed84a5ca3 fast triangulate single “sub paths”
Implements immutable path creation constructor for SokolRenderPath.
Noticed that some files were no longer rendering with the tess renderer. We merged #4169 which now creates the artboard background via the immutable render path constructor. Tess wasn't implementing this so any file clipped against the artboard would end up drawing nothing into the clip stencil, so everything would get clipped.
Diffs=
4bc43ad92 Implements immutable path creation constructor for SokolRenderPath.
Compute gradient F in vertex shader as discussed on Slack with @csmartdalton
Diffs=
d4d6067a3 Fix radial gradient interpolation
14026d5dc Compute gradient F in vertex shader.
drawImage (without a Rive provided mesh) wasn't implemented in Tess. For now this just builds a tiny vertex buffer when it uploads the image.
I'll rework this when I add batching to this renderer (the vertex buffer will only be generated on demand and placed into the batched vertex buffer for the whole frame/artboard depending on where we'll create the batching boundary)
Diffs=
c9f97f7c1 DrawImage for Tess Renderer
Not sure why github sees a huge change on the catch.hpp file, locally it seems unchanged to me. That's the bulk of the linecount here, so maybe just ignore that file?
The actual important stuff:
- uses earcut and libtess2 for triangulation
- earcut benchmarks are insanely fast, but it fails on any complex path, doesn't do winding rules, etc. I have a pretty lame heuristic in there that tries to use it when we think we can get away with it
- libtess2 for anything multi-path (still need to pass winding rule down, however, that'll be in a follow up pr)
- re-added the stroker I built here: https://rive-app.github.io/stroke-exploration/
- stroker internally builds a tristrip, I convert that to triangles here so sokol can use the same pipeline for drawing the fills and strokes
- clipping with the stencil buffer by drawing clipping shapes additively and then testing on stencil buffer value == clipping shape count. makes it easy to propagate between draw calls and selectively remove clipping shapes when there are minor changes between draw calls (nice for Marty animation). Due to sokol's pipeline model, we have to build N pipelines for however many clipping shapes we want to support (I picked an arbitrary number) as we need to hardcode the stencil test value/ref.
- some obtuse blending
Demos:
https://2dimensions.slack.com/archives/CHMAP278R/p1660948586557719https://2dimensions.slack.com/archives/CHMAP278R/p1660952553086529
Diffs=
b0d342067 Shader expects good input.
5f642c48c Undo changes to catch.hpp.
937797ace Tweaks based on PR feedback.
576a54a79 fix test
bbd4e5a8b running formatter
959f22dcb More efficient pipeline changes.
b57f553e0 Strokes and clipping working.
56cb62b64 re-adding stroking
4d6253217 Only draw fills for now.
51f383844 Fix clipping.
d52476967 Working on clipping
2f5e858bd Adding solid color to shader
5bf705b1c Rendering
28492f8dc Adding abstraction for sokol render path.
917b0d5e4 Adding triangulation for simple case.
4f3f8af21 Match master
33e81ceb8 Starting to work on triangulation
* Always align function arguments at the opening paren if they have to
break (never just indented 4 spaces)
* Only break after a function's return type if there's no other way to
make it fit in 100 columns
* Allow one-liner case labels in a switch statement
* Delete packages/coop/.clang-format
* Reformat the world
Diffs=
7d242ebc8 clang-format tweaks
Adding a utility class for TessRenderPath to turn a RawPath into a segmented contour that it can then triangulate. More of the "move towards composition vs inheritance" work. Also removes old ContourRenderPath as this effectively replaces the logic it tried to implement via inheritance.
This mostly moves that old code around, in doing so it also adopts the new path iteration which leaves the "quad" case for the segmenter unhandled, which is ok for now as none of our render paths currently have quad commands.
Diffs=
98647c98c Change based on feedback
1db72a148 Adding SegmentedContour and removing old contour_render_path
Some good idea, perhaps for the future, but for now we don't take advantage of (nor does canvas2d support) ...
- local matrix on gradients or images
- tiling modes on gradients or images
- patterns (i.e. image->makeShader())
... so removing these (speculative) APIs from our porting layers.
If we decide to support some of these in the future, easy to add them back (but for now, we never used or tested them).
Diffs=
034d4f833 Simplify factory and renderer APIs
This is only used by the Tess renderer and is basically just stubbed out, but it touches a few of our other files so I figured it'd be good to PR early.
I'll add some comments inline below.
Diffs=
4055c3cd6 Rewind vs Reset
d16292784 Starting to add TessRenderPath.
6ed9e7352 Starting to add tess render path
In one of the last viewer PRs I added in a lua formatter config file.
It works off of [LuaFormatter](https://github.com/Koihik/LuaFormatter) (think clang-format for lua).
It helps our premake5.lua files look more consistent and auto formats them for us.
The only trick to "help it along" is to scope filter, project, etc sections with lua do end blocks. This is purely cosmetic but I find it keeps the scope of the filter really clear. Similar to adding commas in dart to help the formatter reflow indentation.
Open to suggestions, I already I applied this style to the premake5_viewer.lua config file, but I included an example of the newly formatted premake5_tess.lua file with this PR.
Diffs=
412ab8f4d Lua formatting
Adds ability to run tests when building rive_tess:
```
cd packages/runtime/tess/build/macosx
./build_tess.sh test
```
Also runs them in GitHub Actions.
Diffs=
265e9c7aa Run tests for rive_tess
This is the part that was split out from the other larger PR (#4020).
Diffs=
17c822472 Tabs to spaces and add comments to mat4
aa9448468 Adding rive_tess