Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedded GLTF textures #54

Merged
merged 4 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ log = "0.4"
mint = "0.5"
naga = { version = "0.14", features = ["wgsl-in", "span", "validate"] }
profiling = "1"
slab = "0.4"
strum = { version = "0.25", features = ["derive"] }
web-sys = "0.3.60"

Expand Down Expand Up @@ -75,3 +76,7 @@ web-sys = { workspace = true, features = ["Window"] }

[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dev-dependencies]
renderdoc = "0.11"

# This is too slow in Debug
[profile.dev.package.texpresso]
opt-level = 3
24 changes: 18 additions & 6 deletions blade-asset/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ impl<T: Default> Arena<T> {
unsafe { first_ptr.add(handle.0.index as usize) }
}

pub fn dealloc(&self, handle: Handle<T>) -> T {
pub fn _dealloc(&self, handle: Handle<T>) -> T {
let mut freeman = self.freeman.lock().unwrap();
freeman.free_list.push(handle.0);
let ptr = self.get_mut_ptr(handle);
unsafe { mem::take(&mut *ptr) }
mem::take(unsafe { &mut *ptr })
}

pub fn for_each(&self, mut fun: impl FnMut(Handle<T>, &T)) {
fn for_internal(&self, mut fun: impl FnMut(Address, *mut T)) {
let mut freeman = self.freeman.lock().unwrap();
freeman.free_list.sort(); // enables fast search
for (chunk_index, chunk_start) in self.chunks[..freeman.chunk_bases.len()]
Expand All @@ -147,14 +147,26 @@ impl<T: Default> Arena<T> {
chunk,
};
if freeman.free_list.binary_search(&address).is_err() {
//Note: this is only safe if `get_mut_ptr` isn't called
//Note: accessing this is only safe if `get_mut_ptr` isn't called
// for example, during hot reloading.
let item = unsafe { &*first_ptr.add(index) };
fun(Handle(address, PhantomData), item);
fun(address, unsafe { first_ptr.add(index) });
}
}
}
}

pub fn for_each(&self, mut fun: impl FnMut(Handle<T>, &T)) {
self.for_internal(|address, ptr| fun(Handle(address, PhantomData), unsafe { &*ptr }))
}

pub fn dealloc_each(&self, mut fun: impl FnMut(Handle<T>, T)) {
self.for_internal(|address, ptr| {
fun(
Handle(address, PhantomData),
mem::take(unsafe { &mut *ptr }),
)
})
}
}

impl<T> Drop for FreeManager<T> {
Expand Down
1 change: 1 addition & 0 deletions blade-asset/src/flat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ macro_rules! impl_basic {
impl_basic!(bool);
impl_basic!(u32);
impl_basic!(u64);
impl_basic!(usize);
impl_basic!(f32);

/*
Expand Down
119 changes: 98 additions & 21 deletions blade-asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ impl<T> Default for Slot<T> {
}
}

#[derive(Default)]
struct Inner {
result: Vec<u8>,
dependencies: Vec<PathBuf>,
Expand Down Expand Up @@ -143,6 +144,21 @@ impl<B: Baker> Cooker<B> {
}
}

/// Create a new container with no data, no path, and no hasher.
pub fn new_embedded() -> Self {
Self {
inner: Mutex::new(Inner::default()),
base_path: Default::default(),
_phantom: PhantomData,
}
}

pub fn extract_embedded(&self) -> Vec<u8> {
let mut inner = self.inner.lock().unwrap();
assert!(inner.dependencies.is_empty());
mem::take(&mut inner.result)
}

/// Return the base path of the asset.
pub fn base_path(&self) -> &Path {
&self.base_path
Expand Down Expand Up @@ -197,12 +213,12 @@ pub trait Baker: Sized + Send + Sync + 'static {
extension: &str,
meta: Self::Meta,
cooker: Arc<Cooker<Self>>,
exe_context: choir::ExecutionContext,
exe_context: &choir::ExecutionContext,
);
/// Produce the output bsed on a cooked asset.
///
/// This method is also called within a task `exe_context`.
fn serve(&self, cooked: Self::Data<'_>, exe_context: choir::ExecutionContext) -> Self::Output;
fn serve(&self, cooked: Self::Data<'_>, exe_context: &choir::ExecutionContext) -> Self::Output;
/// Delete the output of an asset.
fn delete(&self, output: Self::Output);
}
Expand Down Expand Up @@ -318,8 +334,8 @@ impl<B: Baker> AssetManager<B> {
}
}

pub fn get_main_source_path(&self, handle: Handle<B::Output>) -> &Path {
self.slots[handle.inner].sources.first().unwrap()
pub fn get_main_source_path(&self, handle: Handle<B::Output>) -> Option<&PathBuf> {
self.slots[handle.inner].sources.first()
}

fn make_target_path(&self, base_path: &Path, file_name: &Path, meta: &B::Meta) -> PathBuf {
Expand All @@ -339,6 +355,7 @@ impl<B: Baker> AssetManager<B> {
&self,
slot: &'a mut Slot<B::Output>,
file_name: &Path,
content: Option<&[u8]>,
) -> Option<(u32, &'a choir::RunningTask)> {
use std::{hash::Hasher as _, io::Write as _};

Expand All @@ -355,6 +372,7 @@ impl<B: Baker> AssetManager<B> {

let target_path = self.make_target_path(&slot.base_path, file_name, meta);
let file_name = file_name.to_owned();
let content = content.map(Vec::from);
let mut hasher = DefaultHasher::new();
TypeId::of::<B::Data<'static>>().hash(&mut hasher);

Expand Down Expand Up @@ -403,7 +421,7 @@ impl<B: Baker> AssetManager<B> {
baker.delete(data);
}
let cooked = unsafe { <B::Data<'_> as Flat>::read(inner.result.as_ptr()) };
let target = baker.serve(cooked, exe_context);
let target = baker.serve(cooked, &exe_context);
unsafe {
*dr.data = Some(target);
*dr.version = version;
Expand All @@ -420,9 +438,12 @@ impl<B: Baker> AssetManager<B> {
.init(move |exe_context| {
// Read the source file through the same mechanism as the
// dependencies, so that its modified time makes it into the hash.
let source = cooker_arg.add_dependency(&file_name);
let extension = file_name.extension().unwrap().to_str().unwrap();
baker.cook(&source, extension, meta, cooker_arg, exe_context);
let source = match content {
Some(data) => data,
None => cooker_arg.add_dependency(&file_name),
};
baker.cook(&source, extension, meta, cooker_arg, &exe_context);
});

load_task.depend_on(&cook_task);
Expand All @@ -442,7 +463,7 @@ impl<B: Baker> AssetManager<B> {
let mut data = Vec::new();
file.read_to_end(&mut data).unwrap();
let cooked = unsafe { <B::Data<'_> as Flat>::read(data.as_ptr()) };
let target = baker.serve(cooked, exe_context);
let target = baker.serve(cooked, &exe_context);
let dr = data_ref;
unsafe {
*dr.data = Some(target);
Expand All @@ -462,20 +483,52 @@ impl<B: Baker> AssetManager<B> {
let (handle, slot_ptr) = self.slots.alloc_default();
let slot = unsafe { &mut *slot_ptr };
assert_eq!(slot.version, 0);
slot.base_path = source_path
.parent()
.unwrap_or_else(|| Path::new("."))
.to_owned();
slot.meta = Box::into_raw(Box::new(meta)) as *const _;
*slot = Slot {
base_path: source_path
.parent()
.unwrap_or_else(|| Path::new("."))
.to_owned(),
meta: Box::into_raw(Box::new(meta)) as *const _,
..Default::default()
};

let file_name = Path::new(source_path.file_name().unwrap());
let (version, _) = self.create_impl(slot, file_name).unwrap();
let (version, _) = self.create_impl(slot, file_name, None).unwrap();
Handle {
inner: handle,
version,
}
}

/// Load an asset given the data directly.
///
/// The `name` must be a pretend file name, with a proper extension.
///
/// Doesn't get cached by the manager, always goes through the cooking process.
pub fn load_data(
&self,
name: &Path,
data: &[u8],
meta: B::Meta,
) -> (Handle<B::Output>, &choir::RunningTask) {
let (handle, slot_ptr) = self.slots.alloc_default();
let slot = unsafe { &mut *slot_ptr };
assert_eq!(slot.version, 0);
*slot = Slot {
meta: Box::into_raw(Box::new(meta)) as *const _,
..Default::default()
};

let (version, _) = self.create_impl(slot, name, Some(data)).unwrap();

let task = self.slots[handle].load_task.as_ref().unwrap();
let out_handle = Handle {
inner: handle,
version,
};
(out_handle, task)
}

/// Load an asset given the relative path.
///
/// Metadata is an asset-specific piece of information that determines how the asset is processed.
Expand All @@ -501,12 +554,35 @@ impl<B: Baker> AssetManager<B> {
(handle, task)
}

/// Load an asset that has been pre-cooked already.
///
/// Expected to run inside a task.
pub fn load_cooked_inside_task(
&self,
cooked: B::Data<'_>,
exe_context: &choir::ExecutionContext,
) -> Handle<B::Output> {
let value = self.baker.serve(cooked, exe_context);
let (handle, slot_ptr) = self.slots.alloc_default();
let slot = unsafe { &mut *slot_ptr };
assert_eq!(slot.version, 0);
*slot = Slot {
version: 1,
data: Some(value),
..Slot::default()
};
Handle {
inner: handle,
version: slot.version,
}
}

/// Clear the asset manager by deleting all the stored assets.
///
/// Invalidates all handles produced from loading assets.
pub fn clear(&self) {
for (_key, handle) in self.paths.lock().unwrap().drain() {
let slot = self.slots.dealloc(handle.inner);
self.paths.lock().unwrap().clear();
self.slots.dealloc_each(|_handle, slot| {
if let Some(task) = slot.load_task {
task.join();
}
Expand All @@ -518,17 +594,18 @@ impl<B: Baker> AssetManager<B> {
let _ = Box::from_raw(slot.meta as *mut B::Meta);
}
}
}
})
}

/// Hot reload a changed asset.
pub fn hot_reload(&self, handle: &mut Handle<B::Output>) -> Option<&choir::RunningTask> {
let slot = unsafe { &mut *self.slots.get_mut_ptr(handle.inner) };
let file_name = slot.sources.first().unwrap().to_owned();
self.create_impl(slot, &file_name).map(|(version, task)| {
handle.version = version;
task
})
self.create_impl(slot, &file_name, None)
.map(|(version, task)| {
handle.version = version;
task
})
}

pub fn list_running_tasks(&self, list: &mut Vec<choir::RunningTask>) {
Expand Down
4 changes: 2 additions & 2 deletions blade-asset/tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ impl blade_asset::Baker for Baker {
_extension: &str,
meta: u32,
cooker: Arc<blade_asset::Cooker<Self>>,
_exe_context: choir::ExecutionContext,
_exe_context: &choir::ExecutionContext,
) {
assert!(self.allow_cooking.load(Ordering::SeqCst));
let _ = cooker.add_dependency("README.md".as_ref());
cooker.finish(meta);
}
fn serve(&self, cooked: u32, _exe_context: choir::ExecutionContext) -> usize {
fn serve(&self, cooked: u32, _exe_context: &choir::ExecutionContext) -> usize {
cooked as usize
}
fn delete(&self, _output: usize) {}
Expand Down
2 changes: 1 addition & 1 deletion blade-graphics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ ash-window = "0.12"
gpu-alloc = "0.6"
gpu-alloc-ash = "0.6"
naga = { workspace = true, features = ["spv-out"] }
slab = "0.4"
slab = { workspace = true }

[target.'cfg(any(gles, target_arch = "wasm32"))'.dependencies]
# Version contains `glGetProgramResource`
Expand Down
3 changes: 2 additions & 1 deletion blade-render/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/kvark/blade"

[features]
default = ["asset"]
asset = ["gltf" , "base64", "exr", "mikktspace", "texpresso", "zune-core", "zune-jpeg", "zune-png", "zune-imageprocs"]
asset = ["gltf" , "base64", "exr", "mikktspace", "slab", "texpresso", "zune-core", "zune-jpeg", "zune-png", "zune-imageprocs"]

[dependencies]
base64 = { workspace = true, optional = true }
Expand All @@ -28,6 +28,7 @@ log = { workspace = true }
mikktspace = { package = "bevy_mikktspace", version = "0.10", optional = true }
mint = { workspace = true }
profiling = { workspace = true }
slab = { workspace = true, optional = true }
strum = { workspace = true }
texpresso = { version = "2.0", optional = true }
#zune-core = { version = "0.2", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion blade-render/code/fill-gbuf.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
if (enable_debug && (debug.draw_flags & DebugDrawFlags_SPACE) != 0u) {
let normal_len = 0.15 * intersection.t;
let side = 0.05 * intersection.t;
debug_line(hit_position, hit_position + normal_len * normal_geo, 0xFFFFFFu);
debug_line(hit_position, hit_position + normal_len * qrot(geo_to_world_rot, normal_geo), 0xFFFFFFu);
debug_line(hit_position - side * tangent_geo, hit_position + side * tangent_geo, 0x808080u);
debug_line(hit_position - side * bitangent_geo, hit_position + side * bitangent_geo, 0x808080u);
}
Expand Down
Loading
Loading