Skip to content

Commit 6530d7d

Browse files
committed
Abstract export functionality behind plugin
1 parent 022c564 commit 6530d7d

File tree

5 files changed

+87
-58
lines changed

5 files changed

+87
-58
lines changed

src/entry_point_export.rs

+34-21
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ use bevy::{
1717
};
1818
use serde::{Deserialize, Serialize};
1919

20+
#[cfg(feature = "hot-rebuild")]
21+
pub(crate) static EXPORT_HANDLES: once_cell::sync::Lazy<
22+
std::sync::RwLock<HashMap<PathBuf, ExportHandle>>,
23+
> = once_cell::sync::Lazy::new(default);
24+
25+
#[cfg(feature = "hot-rebuild")]
26+
pub(crate) static MATERIAL_EXPORTS: once_cell::sync::Lazy<
27+
std::sync::RwLock<HashMap<std::any::TypeId, PathBuf>>,
28+
> = once_cell::sync::Lazy::new(default);
29+
2030
/// Handles exporting known `RustGpuMaterial` permutations to a JSON file for static compilation.
2131
pub struct EntryPointExportPlugin;
2232

@@ -25,6 +35,10 @@ impl Plugin for EntryPointExportPlugin {
2535
app.world.init_non_send_resource::<EntryPointExport>();
2636

2737
app.add_system_to_stage(
38+
CoreStage::Update,
39+
EntryPointExport::create_export_containers_system,
40+
)
41+
.add_system_to_stage(
2842
CoreStage::Last,
2943
EntryPointExport::receive_entry_points_system,
3044
)
@@ -59,37 +73,36 @@ struct EntryPoints {
5973
/// Container for a set of entry points, with MPSC handles and change tracking
6074
#[derive(Debug)]
6175
struct EntryPointExportContainer {
62-
tx: ExportHandle,
6376
rx: EntryPointReceiver,
6477
entry_points: EntryPoints,
6578
changed: bool,
6679
}
6780

68-
impl Default for EntryPointExportContainer {
69-
fn default() -> Self {
70-
let (tx, rx) = std::sync::mpsc::sync_channel::<Export>(32);
71-
72-
EntryPointExportContainer {
73-
tx,
74-
rx,
75-
entry_points: default(),
76-
changed: default(),
77-
}
78-
}
79-
}
80-
8181
/// Non-send resource used to register export files and aggregate their entry points.
82-
#[derive(Debug, Default)]
83-
pub struct EntryPointExport {
82+
#[derive(Debug, Default, Deref, DerefMut)]
83+
struct EntryPointExport {
8484
exports: HashMap<PathBuf, EntryPointExportContainer>,
8585
}
8686

8787
impl EntryPointExport {
88-
/// Registers a path to which entrypoints will be exported,
89-
/// returning a corresponding [`ExportHandle`] that can be passed to a
90-
/// [`RustGpu`](crate::rust_gpu::RustGpu) material.
91-
pub fn export<T: Into<PathBuf>>(&mut self, path: T) -> ExportHandle {
92-
self.exports.entry(path.into()).or_default().tx.clone()
88+
/// System used to populate export containers for registered materials
89+
pub fn create_export_containers_system(mut exports: NonSendMut<Self>) {
90+
let material_exports = MATERIAL_EXPORTS.read().unwrap();
91+
for (_, path) in material_exports.iter() {
92+
if !exports.contains_key(path) {
93+
let (tx, rx) = std::sync::mpsc::sync_channel::<Export>(32);
94+
95+
EXPORT_HANDLES.write().unwrap().insert(path.clone(), tx);
96+
97+
let container = EntryPointExportContainer {
98+
rx,
99+
entry_points: default(),
100+
changed: default(),
101+
};
102+
103+
exports.insert(path.clone(), container);
104+
}
105+
}
93106
}
94107

95108
/// System used to receive and store entry points sent from materials.

src/load_rust_gpu_shader.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use std::path::PathBuf;
22

33
use bevy::prelude::{AssetServer, Handle, Shader};
44

5-
use crate::prelude::SHADER_META_MAP;
6-
75
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
86
pub struct RustGpuShader(pub(crate) Handle<Shader>);
97

@@ -30,7 +28,7 @@ impl LoadRustGpuShader for AssetServer {
3028

3129
#[cfg(feature = "hot-reload")]
3230
{
33-
let mut shader_meta_map = SHADER_META_MAP.write().unwrap();
31+
let mut shader_meta_map = crate::prelude::SHADER_META_MAP.write().unwrap();
3432
shader_meta_map.add(
3533
shader.clone_weak(),
3634
self.load::<crate::prelude::ModuleMeta, _>(meta_path),

src/rust_gpu.rs

+45-23
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
//! Wrapper for extending a `Material` with `rust-gpu` shader functionality.
22
3-
use std::{any::TypeId, marker::PhantomData, sync::RwLock};
3+
use std::{any::TypeId, marker::PhantomData, path::PathBuf, sync::RwLock};
44

55
use bevy::{
66
pbr::MaterialPipelineKey,
77
prelude::{
88
default, info, warn, CoreStage, Image, IntoSystemDescriptor, Material, MaterialPlugin,
9-
Plugin,
9+
Plugin, Handle, Shader, Deref, DerefMut, Resource,
1010
},
1111
reflect::TypeUuid,
1212
render::render_resource::{AsBindGroup, PreparedBindGroup, ShaderRef},
13-
utils::HashMap,
13+
utils::{HashMap, HashSet},
1414
};
1515
use once_cell::sync::Lazy;
1616

1717
use crate::{
1818
load_rust_gpu_shader::RustGpuShader,
19-
prelude::{EntryPoint, Export, ExportHandle, RustGpuMaterial, SHADER_META},
19+
prelude::{EntryPoint, RustGpuMaterial},
2020
systems::{reload_materials, shader_events},
2121
};
2222

@@ -68,6 +68,10 @@ where
6868
}
6969
}
7070

71+
/// A resource to track `rust-gpu` shaders that have been reloaded on a given frame
72+
#[derive(Debug, Default, Clone, Deref, DerefMut, Resource)]
73+
pub struct ChangedShaders(pub HashSet<Handle<Shader>>);
74+
7175
/// Type-level RustGpu material settings
7276
#[derive(Debug, Default, Copy, Clone)]
7377
pub struct RustGpuSettings {
@@ -86,8 +90,6 @@ where
8690
pub vertex_shader: Option<RustGpuShader>,
8791
pub fragment_shader: Option<RustGpuShader>,
8892
pub iteration: usize,
89-
#[cfg(feature = "hot-rebuild")]
90-
pub export_handle: Option<ExportHandle>,
9193
}
9294

9395
impl<M> Clone for RustGpuKey<M>
@@ -101,7 +103,6 @@ where
101103
vertex_shader: self.vertex_shader.clone(),
102104
fragment_shader: self.fragment_shader.clone(),
103105
iteration: self.iteration.clone(),
104-
export_handle: self.export_handle.clone(),
105106
}
106107
}
107108
}
@@ -154,10 +155,6 @@ pub struct RustGpu<M> {
154155

155156
/// Current reload iteration, used to drive hot-reloading.
156157
pub iteration: usize,
157-
158-
/// If `Some`, active entry points will be reported to this handle.
159-
#[cfg(feature = "hot-rebuild")]
160-
pub export_handle: Option<ExportHandle>,
161158
}
162159

163160
impl<M> PartialEq for RustGpu<M>
@@ -237,8 +234,6 @@ where
237234
vertex_shader: self.vertex_shader.clone(),
238235
fragment_shader: self.fragment_shader.clone(),
239236
iteration: self.iteration,
240-
#[cfg(feature = "hot-rebuild")]
241-
export_handle: self.export_handle.clone(),
242237
},
243238
})
244239
}
@@ -329,7 +324,7 @@ where
329324

330325
#[cfg(feature = "hot-reload")]
331326
{
332-
let metas = SHADER_META.read().unwrap();
327+
let metas = crate::prelude::SHADER_META.read().unwrap();
333328
if let Some(vertex_meta) = metas.get(&vertex_shader.0) {
334329
info!("Vertex meta is valid");
335330
info!("Checking entry point {entry_point:}");
@@ -343,15 +338,25 @@ where
343338
}
344339

345340
#[cfg(feature = "hot-rebuild")]
346-
if let Some(sender) = &key.bind_group_data.export_handle {
341+
'hot_rebuild: {
342+
let exports = crate::prelude::MATERIAL_EXPORTS.read().unwrap();
343+
let Some(export) = exports.get(&std::any::TypeId::of::<Self>()) else {
344+
break 'hot_rebuild;
345+
};
346+
347+
let handles = crate::prelude::EXPORT_HANDLES.read().unwrap();
348+
let Some(handle) = handles.get(export) else {
349+
break 'hot_rebuild;
350+
};
351+
347352
info!("Entrypoint sender is valid");
348-
sender
349-
.send(Export {
353+
handle
354+
.send(crate::prelude::Export {
350355
shader: M::Vertex::NAME,
351356
permutation: M::Vertex::permutation(&shader_defs),
352357
})
353358
.unwrap();
354-
}
359+
};
355360

356361
if apply {
357362
info!("Applying vertex shader and entry point");
@@ -382,7 +387,7 @@ where
382387
#[cfg(feature = "hot-reload")]
383388
{
384389
info!("Fragment meta is present");
385-
let metas = SHADER_META.read().unwrap();
390+
let metas = crate::prelude::SHADER_META.read().unwrap();
386391
if let Some(fragment_meta) = metas.get(&fragment_shader.0) {
387392
info!("Fragment meta is valid");
388393
info!("Checking entry point {entry_point:}");
@@ -396,14 +401,25 @@ where
396401
}
397402

398403
#[cfg(feature = "hot-rebuild")]
399-
if let Some(sender) = &key.bind_group_data.export_handle {
400-
sender
401-
.send(Export {
404+
'hot_rebuild: {
405+
let exports = crate::prelude::MATERIAL_EXPORTS.read().unwrap();
406+
let Some(export) = exports.get(&std::any::TypeId::of::<Self>()) else {
407+
break 'hot_rebuild;
408+
};
409+
410+
let handles = crate::prelude::EXPORT_HANDLES.read().unwrap();
411+
let Some(handle) = handles.get(export) else {
412+
break 'hot_rebuild;
413+
};
414+
415+
info!("Entrypoint sender is valid");
416+
handle
417+
.send(crate::prelude::Export {
402418
shader: M::Fragment::NAME,
403419
permutation: M::Fragment::permutation(&shader_defs),
404420
})
405421
.unwrap();
406-
}
422+
};
407423

408424
if apply {
409425
info!("Applying fragment shader and entry point");
@@ -431,4 +447,10 @@ where
431447
let mut settings = MATERIAL_SETTINGS.write().unwrap();
432448
f(&mut settings.entry(TypeId::of::<Self>()).or_default());
433449
}
450+
451+
#[cfg(feature = "hot-rebuild")]
452+
pub fn export_to<P: Into<PathBuf>>(path: P) {
453+
let mut handles = crate::prelude::MATERIAL_EXPORTS.write().unwrap();
454+
handles.insert(std::any::TypeId::of::<Self>(), path.into());
455+
}
434456
}

src/shader_meta.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize};
1818

1919
use crate::{
2020
prelude::{reload_materials, RustGpuMaterial},
21-
systems::shader_events,
21+
systems::shader_events, ChangedShaders,
2222
};
2323

2424
pub(crate) static SHADER_META: Lazy<RwLock<ShaderMeta>> = Lazy::new(Default::default);
@@ -103,10 +103,6 @@ pub struct ModuleMeta {
103103
pub module: String,
104104
}
105105

106-
/// A resource to track `rust-gpu` shaders that have been reloaded on a given frame
107-
#[derive(Debug, Default, Clone, Deref, DerefMut, Resource)]
108-
pub struct ChangedShaders(pub HashSet<Handle<Shader>>);
109-
110106
/// Listens for asset events, updates backend data, and triggers material re-specialization
111107
pub fn module_meta_events<M>(
112108
mut module_meta_events: EventReader<AssetEvent<ModuleMeta>>,

src/systems.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use bevy::prelude::{info, AssetEvent, Assets, EventReader, Res, ResMut, Shader};
44

55
use crate::{
6-
prelude::{ChangedShaders, ModuleMeta, RustGpuMaterial, SHADER_META, SHADER_META_MAP},
6+
prelude::{ChangedShaders, RustGpuMaterial},
77
RustGpu,
88
};
99

@@ -25,7 +25,7 @@ pub fn shader_events<M>(
2525
} => {
2626
#[cfg(feature = "hot-reload")]
2727
// Remove meta in case the shader and meta load on different frames
28-
SHADER_META.write().unwrap().remove(shader_handle);
28+
crate::prelude::SHADER_META.write().unwrap().remove(shader_handle);
2929

3030
// Mark this shader for material reloading
3131
changed_shaders.insert(shader_handle.clone_weak());
@@ -71,13 +71,13 @@ pub fn reload_materials<M>(
7171
/// Listens for [`ModuleMeta`] asset events, updates backend data,
7272
/// and aggregates change events for application in [`reload_materials`].
7373
pub fn module_meta_events<M>(
74-
mut module_meta_events: EventReader<AssetEvent<ModuleMeta>>,
75-
assets: Res<Assets<ModuleMeta>>,
74+
mut module_meta_events: EventReader<AssetEvent<crate::prelude::ModuleMeta>>,
75+
assets: Res<Assets<crate::prelude::ModuleMeta>>,
7676
mut changed_shaders: ResMut<ChangedShaders>,
7777
) where
7878
M: RustGpuMaterial,
7979
{
80-
let shader_meta_map = SHADER_META_MAP.read().unwrap();
80+
let shader_meta_map = crate::prelude::SHADER_META_MAP.read().unwrap();
8181

8282
for event in module_meta_events.iter() {
8383
match event {
@@ -89,7 +89,7 @@ pub fn module_meta_events<M>(
8989
// Update module meta
9090
if let Some(asset) = assets.get(handle) {
9191
info!("Updating shader meta for {handle:?}");
92-
SHADER_META
92+
crate::prelude::SHADER_META
9393
.write()
9494
.unwrap()
9595
.insert(shader.clone_weak(), asset.clone());

0 commit comments

Comments
 (0)