use awsm_renderer_core::{
bind_groups::{
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutResource, BindGroupResource,
BufferBindingLayout, BufferBindingType,
},
buffers::BufferBinding,
};
use crate::error::Result;
use crate::{
bind_group_layout::{
BindGroupLayoutCacheKey, BindGroupLayoutCacheKeyEntry, BindGroupLayoutKey,
},
bind_groups::{AwsmBindGroupError, BindGroupRecreateContext},
meshes::meta::geometry_meta::GEOMETRY_MESH_META_BYTE_ALIGNMENT,
render_passes::RenderPassInitContext,
};
pub struct GeometryBindGroups {
pub camera: GeometryBindGroupCamera,
pub transforms: GeometryBindGroupTransforms,
pub meta: GeometryBindGroupMeta,
pub animation: GeometryBindGroupAnimation,
}
impl GeometryBindGroups {
pub async fn new(ctx: &mut RenderPassInitContext<'_>) -> Result<Self> {
let camera = GeometryBindGroupCamera::new(ctx).await?;
let transforms = GeometryBindGroupTransforms::new(ctx).await?;
let meta = GeometryBindGroupMeta::new(ctx).await?;
let animation = GeometryBindGroupAnimation::new(ctx).await?;
Ok(Self {
camera,
transforms,
meta,
animation,
})
}
}
pub struct GeometryBindGroupCamera {
pub bind_group_layout_key: BindGroupLayoutKey,
_bind_group: Option<web_sys::GpuBindGroup>,
}
impl GeometryBindGroupCamera {
pub async fn new(ctx: &mut RenderPassInitContext<'_>) -> Result<Self> {
let bind_group_layout_cache_key = BindGroupLayoutCacheKey {
entries: vec![
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new().with_binding_type(BufferBindingType::Uniform),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new().with_binding_type(BufferBindingType::Uniform),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
],
};
let bind_group_layout_key = ctx
.bind_group_layouts
.get_key(ctx.gpu, bind_group_layout_cache_key)?;
Ok(Self {
bind_group_layout_key,
_bind_group: None,
})
}
pub fn recreate(&mut self, ctx: &BindGroupRecreateContext<'_>) -> Result<()> {
let descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(self.bind_group_layout_key)?,
Some("Geometry Camera"),
vec![
BindGroupEntry::new(
0,
BindGroupResource::Buffer(BufferBinding::new(&ctx.camera.gpu_buffer)),
),
BindGroupEntry::new(
1,
BindGroupResource::Buffer(BufferBinding::new(&ctx.frame_globals.gpu_buffer)),
),
],
);
let bind_group = ctx.gpu.create_bind_group(&descriptor.into());
self._bind_group = Some(bind_group);
Ok(())
}
pub fn get_bind_group(
&self,
) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self._bind_group
.as_ref()
.ok_or_else(|| AwsmBindGroupError::NotFound("Geometry camera".to_string()))
}
}
#[derive(Default)]
pub struct GeometryBindGroupTransforms {
pub bind_group_layout_key: BindGroupLayoutKey,
_bind_group: Option<web_sys::GpuBindGroup>,
}
impl GeometryBindGroupTransforms {
pub async fn new(ctx: &mut RenderPassInitContext<'_>) -> Result<Self> {
let bind_group_layout_cache_key = BindGroupLayoutCacheKey {
entries: vec![
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::ReadOnlyStorage),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
],
};
let bind_group_layout_key = ctx
.bind_group_layouts
.get_key(ctx.gpu, bind_group_layout_cache_key)?;
Ok(Self {
bind_group_layout_key,
_bind_group: None,
})
}
pub fn recreate(&mut self, ctx: &BindGroupRecreateContext<'_>) -> Result<()> {
let descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(self.bind_group_layout_key)?,
Some("Geometry Transforms"),
vec![BindGroupEntry::new(
0,
BindGroupResource::Buffer(BufferBinding::new(&ctx.transforms.gpu_buffer)),
)],
);
let bind_group = ctx.gpu.create_bind_group(&descriptor.into());
self._bind_group = Some(bind_group);
Ok(())
}
pub fn get_bind_group(
&self,
) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self._bind_group
.as_ref()
.ok_or_else(|| AwsmBindGroupError::NotFound("Geometry transform".to_string()))
}
}
#[derive(Default)]
pub struct GeometryBindGroupMeta {
pub storage_layout_key: BindGroupLayoutKey,
pub uniform_layout_key: BindGroupLayoutKey,
_storage_bind_group: Option<web_sys::GpuBindGroup>,
_uniform_bind_group: Option<web_sys::GpuBindGroup>,
}
impl GeometryBindGroupMeta {
pub async fn new(ctx: &mut RenderPassInitContext<'_>) -> Result<Self> {
let storage_layout_cache_key = BindGroupLayoutCacheKey {
entries: vec![BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::ReadOnlyStorage),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
}],
};
let uniform_layout_cache_key = BindGroupLayoutCacheKey {
entries: vec![BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::Uniform)
.with_dynamic_offset(true),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
}],
};
let storage_layout_key = ctx
.bind_group_layouts
.get_key(ctx.gpu, storage_layout_cache_key)?;
let uniform_layout_key = ctx
.bind_group_layouts
.get_key(ctx.gpu, uniform_layout_cache_key)?;
Ok(Self {
storage_layout_key,
uniform_layout_key,
_storage_bind_group: None,
_uniform_bind_group: None,
})
}
pub fn recreate(&mut self, ctx: &BindGroupRecreateContext<'_>) -> Result<()> {
let storage_descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(self.storage_layout_key)?,
Some("Geometry meta (storage array)"),
vec![BindGroupEntry::new(
0,
BindGroupResource::Buffer(BufferBinding::new(
ctx.meshes.meta.geometry_gpu_buffer(),
)),
)],
);
self._storage_bind_group = Some(ctx.gpu.create_bind_group(&storage_descriptor.into()));
let uniform_descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(self.uniform_layout_key)?,
Some("Geometry meta (uniform + dyn offset)"),
vec![BindGroupEntry::new(
0,
BindGroupResource::Buffer(
BufferBinding::new(ctx.meshes.meta.geometry_gpu_buffer())
.with_size(GEOMETRY_MESH_META_BYTE_ALIGNMENT),
),
)],
);
self._uniform_bind_group = Some(ctx.gpu.create_bind_group(&uniform_descriptor.into()));
Ok(())
}
pub fn get_storage_bind_group(
&self,
) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self._storage_bind_group
.as_ref()
.ok_or_else(|| AwsmBindGroupError::NotFound("Geometry meta (storage)".to_string()))
}
pub fn get_uniform_bind_group(
&self,
) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self._uniform_bind_group
.as_ref()
.ok_or_else(|| AwsmBindGroupError::NotFound("Geometry meta (uniform)".to_string()))
}
}
#[derive(Default)]
pub struct GeometryBindGroupAnimation {
pub bind_group_layout_key: BindGroupLayoutKey,
_bind_group: Option<web_sys::GpuBindGroup>,
}
impl GeometryBindGroupAnimation {
pub async fn new(ctx: &mut RenderPassInitContext<'_>) -> Result<Self> {
let bind_group_layout_cache_key = BindGroupLayoutCacheKey {
entries: vec![
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::ReadOnlyStorage),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::ReadOnlyStorage),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::ReadOnlyStorage),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
BindGroupLayoutCacheKeyEntry {
resource: BindGroupLayoutResource::Buffer(
BufferBindingLayout::new()
.with_binding_type(BufferBindingType::ReadOnlyStorage),
),
visibility_vertex: true,
visibility_fragment: true,
visibility_compute: false,
},
],
};
let bind_group_layout_key = ctx
.bind_group_layouts
.get_key(ctx.gpu, bind_group_layout_cache_key)?;
Ok(Self {
bind_group_layout_key,
_bind_group: None,
})
}
pub fn recreate(&mut self, ctx: &BindGroupRecreateContext<'_>) -> Result<()> {
let descriptor = BindGroupDescriptor::new(
ctx.bind_group_layouts.get(self.bind_group_layout_key)?,
Some("Geometry animation"),
vec![
BindGroupEntry::new(
0,
BindGroupResource::Buffer(BufferBinding::new(
&ctx.meshes.morphs.geometry.gpu_buffer_weights,
)),
),
BindGroupEntry::new(
1,
BindGroupResource::Buffer(BufferBinding::new(
&ctx.meshes.morphs.geometry.gpu_buffer_values,
)),
),
BindGroupEntry::new(
2,
BindGroupResource::Buffer(BufferBinding::new(
&ctx.meshes.skins.matrices_gpu_buffer,
)),
),
BindGroupEntry::new(
3,
BindGroupResource::Buffer(BufferBinding::new(
&ctx.meshes.skins.joint_index_weights_gpu_buffer,
)),
),
],
);
let bind_group = ctx.gpu.create_bind_group(&descriptor.into());
self._bind_group = Some(bind_group);
Ok(())
}
pub fn get_bind_group(
&self,
) -> std::result::Result<&web_sys::GpuBindGroup, AwsmBindGroupError> {
self._bind_group
.as_ref()
.ok_or_else(|| AwsmBindGroupError::NotFound("Geometry skin".to_string()))
}
}