use bevy_app::{App, Plugin, First, Last};
use bevy_ecs::prelude::*;
use memkit::{MkAllocator, MkConfig};
#[cfg(feature = "gpu")]
use memkit_co::bevy::BevyGpuCoordinator;
#[cfg(feature = "gpu")]
use memkit_gpu::DummyBackend;
#[cfg(feature = "bevy_prelude")]
pub use bevy::prelude::*;
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub enum MkSystemSet {
FrameBegin,
FrameEnd,
}
#[derive(Resource)]
pub struct MkAllocatorRes {
allocator: MkAllocator,
frame_active: bool,
}
impl MkAllocatorRes {
pub fn new(config: MkConfig) -> Self {
Self {
allocator: MkAllocator::new(config),
frame_active: false,
}
}
pub fn allocator(&self) -> &MkAllocator {
&self.allocator
}
pub fn is_frame_active(&self) -> bool {
self.frame_active
}
pub fn frame_alloc<T>(&self) -> *mut T {
assert!(self.frame_active, "frame_alloc called outside active frame");
self.allocator.frame_alloc::<T>()
}
pub fn frame_slice<T>(&self, len: usize) -> Option<memkit::MkFrameSlice<'_, T>> {
assert!(self.frame_active, "frame_slice called outside active frame");
self.allocator.frame_slice::<T>(len)
}
pub fn frame_box<T>(&self, value: T) -> Option<memkit::MkFrameBox<'_, T>> {
assert!(self.frame_active, "frame_box called outside active frame");
self.allocator.frame_box(value)
}
}
impl std::ops::Deref for MkAllocatorRes {
type Target = MkAllocator;
fn deref(&self) -> &Self::Target {
&self.allocator
}
}
#[cfg(feature = "gpu")]
#[derive(Resource)]
pub struct MkGpuRes {
coordinator: BevyGpuCoordinator<DummyBackend>,
}
#[cfg(feature = "gpu")]
impl MkGpuRes {
pub fn new() -> Self {
Self {
coordinator: BevyGpuCoordinator::new(DummyBackend::new()),
}
}
pub fn coordinator(&self) -> &BevyGpuCoordinator<DummyBackend> {
&self.coordinator
}
}
#[cfg(feature = "gpu")]
impl Default for MkGpuRes {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "gpu")]
impl std::ops::Deref for MkGpuRes {
type Target = BevyGpuCoordinator<DummyBackend>;
fn deref(&self) -> &Self::Target {
&self.coordinator
}
}
pub struct MkPlugin {
config: MkConfig,
#[cfg(feature = "gpu")]
enable_gpu: bool,
}
impl Default for MkPlugin {
fn default() -> Self {
Self {
config: MkConfig::default(),
#[cfg(feature = "gpu")]
enable_gpu: true,
}
}
}
impl MkPlugin {
pub fn with_config(config: MkConfig) -> Self {
Self {
config,
#[cfg(feature = "gpu")]
enable_gpu: true,
}
}
pub fn with_arena_size(size: usize) -> Self {
Self::with_config(MkConfig {
frame_arena_size: size,
..Default::default()
})
}
#[cfg(feature = "gpu")]
pub fn without_gpu(mut self) -> Self {
self.enable_gpu = false;
self
}
}
impl Plugin for MkPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(MkAllocatorRes::new(self.config.clone()));
app.configure_sets(First, MkSystemSet::FrameBegin);
app.configure_sets(Last, MkSystemSet::FrameEnd);
app.add_systems(First, frame_begin_system.in_set(MkSystemSet::FrameBegin));
app.add_systems(Last, frame_end_system.in_set(MkSystemSet::FrameEnd));
#[cfg(feature = "gpu")]
if self.enable_gpu {
app.insert_resource(MkGpuRes::new());
app.add_systems(First, gpu_frame_begin_system.after(MkSystemSet::FrameBegin));
app.add_systems(Last, gpu_frame_end_system.before(MkSystemSet::FrameEnd));
}
}
}
fn frame_begin_system(mut alloc: ResMut<MkAllocatorRes>) {
alloc.allocator.begin_frame();
alloc.frame_active = true;
}
fn frame_end_system(mut alloc: ResMut<MkAllocatorRes>) {
alloc.frame_active = false;
alloc.allocator.end_frame();
}
#[cfg(feature = "gpu")]
fn gpu_frame_begin_system(gpu: Res<MkGpuRes>) {
gpu.coordinator.begin_frame();
}
#[cfg(feature = "gpu")]
fn gpu_frame_end_system(gpu: Res<MkGpuRes>) {
let _ = gpu.coordinator.end_frame();
}
pub mod prelude {
pub use super::{MkPlugin, MkAllocatorRes, MkSystemSet};
pub use memkit::{MkConfig, MkFrameBox, MkFrameSlice};
#[cfg(feature = "gpu")]
pub use super::MkGpuRes;
}
pub use MkAllocatorRes as MkAllocatorResource;