basis_universal/encoding/
mod.rs

1use basis_universal_sys as sys;
2
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::sync::Mutex;
5
6mod compressor_image;
7pub use compressor_image::*;
8
9mod compressor_params;
10pub use compressor_params::*;
11
12mod compressor;
13pub use compressor::*;
14
15/// A single uncompressed pixel value
16pub use basis_universal_sys::ColorU8;
17
18#[cfg(test)]
19mod encoding_tests;
20
21static ENCODER_INIT_CALLED: AtomicBool = AtomicBool::new(false);
22lazy_static::lazy_static! {
23    static ref ENCODER_INIT_LOCK: Mutex<()> = Mutex::default();
24}
25
26/// The underlying C++ library requires that encoder_init() has been called before a .basis file can
27/// be encoded. This function allows a user to do this early in the application explicitly. It is
28/// protected by a lock and AtomicBool flag so it is safe and cheap to call multiple times, and
29/// correctly handles multiple threads trying to initialize at the same time.
30pub fn encoder_init() {
31    unsafe {
32        // Early out if it has been initialized
33        if !ENCODER_INIT_CALLED.load(Ordering::Acquire) {
34            // Lock and check again to ensure that exactly one thread runs the init code and that
35            // all other threads wait for it to complete and don't re-run it.
36            let lock = ENCODER_INIT_LOCK.lock().unwrap();
37            if !ENCODER_INIT_CALLED.load(Ordering::Acquire) {
38                // Run the init code
39                sys::basisu_encoder_init();
40                ENCODER_INIT_CALLED.store(true, Ordering::Release);
41            }
42            std::mem::drop(lock);
43        }
44    }
45}