1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
// Copyright (c) 2024 Lily Lyons
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use fmod_sys::*;
use std::ffi::{c_char, c_int, c_uint, c_void};
#[derive(PartialEq, Eq, Debug)]
pub enum MemoryType {
Pool(&'static mut [u8]),
Callback {
alloc: unsafe extern "C" fn(
size: c_uint,
type_: FMOD_MEMORY_TYPE,
sourcestr: *const c_char,
) -> *mut c_void,
realloc: FMOD_MEMORY_REALLOC_CALLBACK,
free: unsafe extern "C" fn(
ptr: *mut c_void,
type_: FMOD_MEMORY_TYPE,
sourcestr: *const c_char,
),
},
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MemoryFlags: FMOD_MEMORY_TYPE {
const NORMAL = FMOD_MEMORY_NORMAL;
const STREAM_FILE = FMOD_MEMORY_STREAM_FILE;
const STREAM_DECODE = FMOD_MEMORY_STREAM_DECODE;
const SAMPLEDATA = FMOD_MEMORY_SAMPLEDATA;
const DSP_BUFFER = FMOD_MEMORY_DSP_BUFFER;
const PLUGIN = FMOD_MEMORY_PLUGIN;
const PERSISTENT = FMOD_MEMORY_PERSISTENT;
const ALL = FMOD_MEMORY_ALL;
}
}
impl From<FMOD_MEMORY_TYPE> for MemoryFlags {
fn from(value: FMOD_MEMORY_TYPE) -> Self {
MemoryFlags::from_bits_truncate(value)
}
}
impl From<MemoryFlags> for FMOD_MEMORY_TYPE {
fn from(value: MemoryFlags) -> Self {
value.bits()
}
}
/// Specifies a method for FMOD to allocate and free memory, either through user supplied callbacks or through a user supplied memory buffer with a fixed size.
///
/// # Safety
///
/// This function must be called before any FMOD System object is created.
///
/// If [`MemoryType::Callback::alloc`] and [`MemoryType::Callback::free`] are provided without [`MemoryType::Callback::realloc`]
/// the reallocation is implemented via an allocation of the new size, copy from old address to new, then a free of the old address.
///
/// Callback implementations must be thread safe.
///
/// If you specify a fixed size pool that is too small, FMOD will return [`FMOD_RESULT::FMOD_ERR_MEMORY`] when the limit of the fixed size pool is exceeded.
/// At this point, it's possible that FMOD may become unstable. To maintain stability, do not allow FMOD to run out of memory.
/// To find out the required fixed size call [`memory_initialize`] with an overly large pool size (or no pool) and find out the maximum RAM usage at any one time with [`memory_get_stats`].
/// The size of the pool is limited to [`c_int::MAX`].
pub unsafe fn memory_initialize(memory_type: MemoryType, flags: MemoryFlags) -> Result<()> {
match memory_type {
MemoryType::Pool(pool) => unsafe {
FMOD_Memory_Initialize(
pool.as_mut_ptr().cast(),
pool.len() as c_int,
None,
None,
None,
flags.into(),
)
.to_result()
},
MemoryType::Callback {
alloc,
realloc,
free,
} => unsafe {
FMOD_Memory_Initialize(
std::ptr::null_mut(),
0,
Some(alloc),
realloc,
Some(free),
flags.into(),
)
.to_result()
},
}
}
/// Returns information on the memory usage of FMOD.
///
/// This information is byte accurate and counts all allocs and frees internally.
/// This is useful for determining a fixed memory size to make FMOD work within for fixed memory machines such as consoles.
///
/// Note that if using [`memory_initialize`], the memory usage will be slightly higher than without it, as FMOD has to have a small amount of memory overhead to manage the available memory.
pub fn memory_get_stats(blocking: bool) -> Result<(c_int, c_int)> {
let mut current = 0;
let mut max = 0;
unsafe {
FMOD_Memory_GetStats(&mut current, &mut max, blocking.into()).to_result()?;
}
Ok((current, max))
}