github rive-app/rive-android 11.16.1

3 hours ago

Features

Blend modes on masked layers

Masked layers now composite with their blend mode over the content beneath them. For example, a shape masked to an image can now recolor or light that image. Previously, every blend mode except Additive looked like Normal on a masked layer. Existing files render this way without re-exporting. On Android, layer masks currently apply only when GPU Canvas is enabled, and not when Vulkan renders with MSAA. (Change)

Fixes

  • Vulkan shader warmup crash: With precompileShaders enabled, Vulkan warmup could create pipelines for render pass configurations that Rive never uses. Some Adreno drivers, including the one on the Pixel 4a, crashed in vkCreateGraphicsPipelines shortly after launch. Warmup now creates only pipelines that match the render passes Rive builds. This affected 11.15.0 and 11.16.0, and was reported in #480. (Fix)
  • Legacy view model instance leak: In the Legacy API, view model instances never released their native object. Once nothing referenced an instance, it stayed in memory until the process exited, together with any image or artboard bound to it. This affected created, child, list item, auto-bound, and transferred instances since 10.4.5. Releasing an instance's last reference now frees it. Related ownership changes are described under Behavior changes. (Fix)
  • Legacy list item removal: In the Legacy API, ViewModelListProperty.remove threw a RiveException and left the item in the list when the item came from the list itself, such as list.remove(list[0]). Such items are now removed. (Fix)
  • Hug layouts with stale sizes: A layout that hugs its content could reuse a measurement taken under different constraints. For example, text could stay wrapped onto two lines after it had room for one. A nested grid also failed to lay out a child that was hidden and shown again. These layouts now measure again. The stale measurement was introduced in 11.16.0. (Fix)
  • List row crashes: After a list was unbound from its view model list property, a later size change to its rows could use freed memory and crash. Scrolling a virtualized list after a row's item stopped mapping to an artboard could also use freed memory. Both cases are now safe. (Fix)
  • Leftover state in reused list rows: When a list reused a removed item's row for a new item, the row could keep state from the old item. A row reused during a transition kept applying the old item's transition values, and a row with a scroll constraint opened at the old item's scroll position. In virtualized lists, nested inputs reset to 0 or false instead of their authored values. Rows chosen by a map rule could also take another artboard's override sizes. Reused rows now start like new rows. (Fix)
  • Nested artboards shown by a Solo: A nested artboard that fills its host laid out at zero size when its Solo option was inactive at load and the Solo showed it later. It now lays out at its host's size. (Fix)
  • Early exit transition reversals: When a transition with early exit was interrupted, the first frame of the reversal jumped toward the outgoing state. The same happened when reversing out of a 1D blend state with reset, and with elastic curves. Reversals now continue from the blended pose. (Fix)
  • Right-to-left layouts switched to absolute positioning: When a state machine or data binding switched a right-to-left layout to absolute positioning, the layout jumped to its mirrored horizontal position. It now stays in place. (Fix)
  • Slivers from shapes scaled to zero: With the Rive renderer, shapes and images scaled to zero along one axis could leave thin visible lines when combined with a rotation or skew. The renderer now skips these draws. (Fix)
  • Scripted sounds after a faded stop: A sound that a script stopped with a fade stayed silent when the script played or resumed it again. It now plays. (Fix)
  • Script animation advance result: In scripts, Animation.advance(0) returned false for looping and ping-pong animations that could keep playing. It now returns true while the animation can keep playing. (Fix)
  • GPU Canvas mip views on OpenGL: Scripts that sampled a texture view covering only some mip levels read from the whole mip chain on OpenGL. OpenGL now samples only the view's levels, as Vulkan does. (Fix)
  • GPU Canvas render passes cut off on OpenGL: A GPU Canvas render pass could inherit a scissor rectangle left by Rive's own drawing, which cut off a script's draws and clears. Each pass now starts without a scissor. (Fix)
  • Legacy Canvas renderer at 0% Additive: With the Legacy Android Canvas renderer, shapes, images, and text that use Additive at 0% strength drew at full additive strength. They now draw as Normal. Partial strengths still require the Rive renderer. (Fix)

Behavior changes

Legacy view model instance ownership

With the leak fix above, Legacy view model instances follow their Kotlin references strictly.

  • A child instance from getInstanceProperty is disposed when setInstanceProperty replaces it. Later calls on the old wrapper throw unless it was retained with acquire().
  • ViewModelListProperty.elementAt throws ViewModelException for a list item without an instance, instead of returning a wrapper around a null pointer.
  • The private native release function is renamed. Integrations that called the old cppDerefInstance through reflection to work around the leak now fail instead of freeing a live instance. They can remove the workaround.

The current API is not affected.

Performance

Faster first frame

This release shortens the time from mounting Rive content to its first frame. Vulkan now keeps compiled pipelines across launches, so later launches skip most shader compilation. Rive stores them in the app's code cache directory, which Android clears when the app or the system updates. This requires initializing Rive with a Context, as Rive.init(context) and the default RiveInitializer do.

Images now decode straight to premultiplied sRGB RGBA without a second pass over the pixels. CommandQueue delivers an awaited reply as soon as the worker posts it, instead of a frame or two later. The Rive composable draws its first frame as soon as its resources are ready, without waiting for the next vsync. (Change)

List rows

Lists now reuse a removed item's row for a new item even when the row hosts nested artboards or nested lists, instead of destroying it and building a new one. Rows with artboard paints, stateful nested artboards, scripts, or scroll constraints are still rebuilt. Rows that host nested artboards can also go idle and skip per-frame work until something changes, including rows with a listener that writes back to a view model. A new row in a list with focus content now builds its focus tree once instead of twice. (Change, Change, Change)

In a release-build C++ benchmark on an M2 Max Mac, switching the content of a chat-style list spent 16% less time advancing, from 58.4 ms to 48.8 ms across the switch frames. This illustrates one improvement, and gains depend on the content.

Fewer allocations for artboard instances

Creating artboard instances, such as new list rows, now allocates less. Instances share component names and data bind paths with their source artboard, keep bound values inline, and size their internal lists once. Text glyph paths and runs are also sized once, and shaping reuses one buffer per thread. (Change, Change, Change)

In a release-build C++ benchmark on an M2 Max Mac, each row added to a test list went from 708 to 483 allocations. Gains depend on the content.

Less text shaping

Text is shaped less often. A text with a fixed size no longer shapes itself to measure. A size change breaks the existing shape into lines again instead of reshaping, and a change that leaves the styled text the same reuses the existing shape. Text styles that ask for the same font with the same variable axes or features now share one font and its glyph outline cache. (Change, Change)

Fewer layout allocations

Layout passes no longer allocate on the heap, and grid layouts reuse min-content measurements. Building and syncing layouts also allocates less. Adding many rows to a list no longer syncs the root layout once per row or scans every row on each layout change. (Change, Change)

State machine layers

When states in two or more layers of a state machine key the same property, the state machine now sets that property once per frame. Previously, each layer set it in turn. Content that held a property at different values in different layers ran layout every frame and never settled. It now settles, so Rive can stop advancing it until something changes. (Change)

Rendering

Feathered fills now keep their softened path while their geometry and feather are unchanged, instead of rebuilding it every frame. Rive also skips fully transparent paints and draws under a transform that collapses to zero area. When the Rive renderer uses MSAA, it combines more stroke draws into a single draw call. (Change, Change, Change)


Full comparison

Don't miss a new rive-android release

NewReleases is sending notifications on new releases.