Skip to content

Commit

Permalink
fix: replaced atomic operations with Mutex for engine initialization …
Browse files Browse the repository at this point in the history
…in TvgRenderer
  • Loading branch information
theashraf committed Nov 28, 2024
1 parent 52829ff commit cd2f0f8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 8 deletions.
1 change: 1 addition & 0 deletions dotlottie-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ zip = { version = "2.2.0", default-features = false, features = ["deflate"] }
base64 = "0.22.1"
json = "0.12.4"
jzon = "0.12.5"
spin = "0.9"

[build-dependencies]
bindgen = "0.70.1"
Expand Down
61 changes: 53 additions & 8 deletions dotlottie-rs/src/lottie_renderer/thorvg.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use std::{ffi::CString, ptr, result::Result, sync::atomic::AtomicUsize};
#[cfg(not(target_arch = "wasm32"))]
use std::sync::Mutex;

#[cfg(target_arch = "wasm32")]
use spin::Mutex;

use std::{ffi::CString, ptr, result::Result};
use thiserror::Error;

use super::{Animation, ColorSpace, Drawable, Renderer, Shape};
Expand Down Expand Up @@ -73,7 +79,7 @@ impl From<TvgEngine> for tvg::Tvg_Engine {
}
}

static RENDERERS_COUNT: AtomicUsize = AtomicUsize::new(0);
static RENDERERS_COUNT: spin::Mutex<usize> = spin::Mutex::new(0);

pub struct TvgRenderer {
raw_canvas: *mut tvg::Tvg_Canvas,
Expand All @@ -84,12 +90,14 @@ impl TvgRenderer {
pub fn new(engine_method: TvgEngine, threads: u32) -> Self {
let engine = engine_method.into();

if RENDERERS_COUNT.load(std::sync::atomic::Ordering::SeqCst) == 0 {
let mut count = RENDERERS_COUNT.lock();

if *count == 0 {
unsafe { tvg::tvg_engine_init(engine, threads).into_result() }
.expect("Failed to initialize ThorVG engine");
}

RENDERERS_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
*count += 1;

TvgRenderer {
raw_canvas: unsafe { tvg::tvg_swcanvas_create() },
Expand Down Expand Up @@ -158,13 +166,21 @@ impl Renderer for TvgRenderer {

impl Drop for TvgRenderer {
fn drop(&mut self) {
let mut count = RENDERERS_COUNT.lock();

unsafe {
tvg::tvg_canvas_destroy(self.raw_canvas);
}

if RENDERERS_COUNT.fetch_sub(1, std::sync::atomic::Ordering::SeqCst) == 1 {
tvg::tvg_engine_term(self.engine_method);
}
};
if *count <= 0 {
unreachable!();
}

*count -= 1;

if *count == 0 {
unsafe { tvg::tvg_engine_term(self.engine_method) };
}
}
}

Expand Down Expand Up @@ -391,3 +407,32 @@ impl Shape for TvgShape {
unsafe { tvg::tvg_shape_reset(self.raw_shape).into_result() }
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, Barrier};
use std::thread;

#[test]
fn test_tvg_renderer_no_deadlock() {
const THREAD_COUNT: usize = 10;
let barrier = Arc::new(Barrier::new(THREAD_COUNT));
let mut handles = vec![];

for _ in 0..THREAD_COUNT {
let barrier_clone = Arc::clone(&barrier);
let handle = thread::spawn(move || {
barrier_clone.wait();

let renderer = TvgRenderer::new(TvgEngine::TvgEngineSw, 0);
drop(renderer);
});
handles.push(handle);
}

for handle in handles {
handle.join().expect("Thread panicked");
}
}
}

0 comments on commit cd2f0f8

Please sign in to comment.