From 3344eb2d678f9c5973c8e38083760254b54c20fc Mon Sep 17 00:00:00 2001 From: metamuffin Date: Thu, 23 Jan 2025 22:45:35 +0100 Subject: split scene_prepare to many files --- client/src/scene_prepare.rs | 1030 ------------------------------------------- 1 file changed, 1030 deletions(-) (limited to 'client/src/scene_prepare.rs') diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs index d4535a1..e69de29 100644 --- a/client/src/scene_prepare.rs +++ b/client/src/scene_prepare.rs @@ -1,1030 +0,0 @@ -/* - wearechat - generic multiplayer game with voip - Copyright (C) 2025 metamuffin - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, version 3 of the License only. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ -use crate::{ - armature::RArmature, - download::Downloader, - meshops::{generate_normals, generate_tangents, generate_texcoords}, - shaders::SceneShaders, -}; -use anyhow::Result; -use bytemuck::{Pod, Zeroable}; -use egui::{Grid, Widget}; -use glam::{UVec3, UVec4, Vec2, Vec3, Vec3A, uvec3, uvec4}; -use humansize::DECIMAL; -use image::ImageReader; -use log::{debug, trace}; -use std::{ - collections::{HashMap, HashSet}, - hash::Hash, - io::Cursor, - marker::PhantomData, - sync::{Arc, RwLock}, - time::Instant, -}; -use weareshared::{ - Affine3A, - packets::Resource, - resources::{Image, MeshPart, Prefab}, -}; -use wgpu::{ - AddressMode, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendState, - Buffer, BufferBindingType, BufferUsages, Color, ColorTargetState, ColorWrites, - CommandEncoderDescriptor, CompareFunction, DepthBiasState, DepthStencilState, Device, Extent3d, - Face, FilterMode, FragmentState, FrontFace, ImageDataLayout, LoadOp, MultisampleState, - Operations, PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, - PrimitiveTopology, PushConstantRange, Queue, RenderPassColorAttachment, RenderPassDescriptor, - RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages, - StencilState, StoreOp, Texture, TextureAspect, TextureDescriptor, TextureDimension, - TextureFormat, TextureSampleType, TextureUsages, TextureViewDescriptor, TextureViewDimension, - VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, include_wgsl, - util::{BufferInitDescriptor, DeviceExt}, -}; - -pub struct DemandMap { - inner: RwLock>, -} -struct DemandMapState { - values: HashMap, - needed: HashSet, - size_metric: usize, -} -impl DemandMap { - pub fn new() -> Self { - Self { - inner: DemandMapState { - needed: HashSet::new(), - values: HashMap::new(), - size_metric: 0, - } - .into(), - } - } - pub fn needed(&self) -> Vec { - self.inner.read().unwrap().needed.iter().cloned().collect() - } - pub fn insert(&self, key: K, value: V, size: usize) { - let mut s = self.inner.write().unwrap(); - s.needed.remove(&key); - s.values.insert(key, value); - s.size_metric += size; - } - pub fn try_get(&self, key: K) -> Option { - let mut s = self.inner.write().unwrap(); - if let Some(k) = s.values.get(&key) { - Some(k.to_owned()) - } else { - s.needed.insert(key); - None - } - } -} - -struct GraphicsConfig { - max_anisotropy: u16, - max_mip_count: u32, -} - -pub struct ScenePreparer { - device: Arc, - queue: Arc, - layouts: SceneBgLayouts, - shaders: SceneShaders, - render_format: TextureFormat, - config: GraphicsConfig, - - textures: DemandMap, Arc)>, - placeholder_textures: DemandMap, Arc)>, - index_buffers: DemandMap>, (Arc, u32)>, - vertex_buffers: DemandMap>, Arc>, - generated_tangent_buffers: DemandMap>, - generated_normal_buffers: DemandMap>, - generated_texcoord_buffers: DemandMap>, - mesh_parts: DemandMap, Arc>, - materials: DemandMap>, - pipelines: DemandMap>, - mip_generation_pipelines: DemandMap>, - pub prefabs: DemandMap, Arc>, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct PipelineSpec { - format: TextureFormat, - skin: bool, - backface_culling: bool, -} - -pub struct RPrefab(pub Vec<(Affine3A, Arc)>); -pub struct RMeshPart { - pub pipeline: Arc, - pub index_count: u32, - pub index: Arc, - pub va_position: Arc, - pub va_normal: Arc, - pub va_tangent: Arc, - pub va_texcoord: Arc, - pub tex_albedo: Arc, - pub tex_normal: Arc, - pub material: Arc, - pub double_sided: bool, - - pub va_joint_index: Option>, - pub va_joint_weight: Option>, - pub joint_uniform: Option>, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -struct TextureSpec { - data: Resource>, - linear: bool, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -struct TangentBufferSpec { - index: Resource>, - position: Resource>, - texcoord: Option>>, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -struct NormalBufferSpec { - index: Resource>, - position: Resource>, -} -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -struct TexcoordBufferSpec { - index: Resource>, - position: Resource>, -} - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -enum TextureIdentityKind { - Normal, - Multiply, -} - -#[derive(Debug, Clone, Copy, Pod, Zeroable, Hash, PartialEq, Eq)] -#[repr(C)] -struct Material { - roughness: u32, - metallic: u32, - _pad1: [u32; 2], - albedo_alpha: UVec4, - emission: UVec3, - _pad2: u32, -} - -impl ScenePreparer { - pub fn new(device: Arc, queue: Arc, render_format: TextureFormat) -> Self { - Self { - // TODO normal mipmap requires linear texture, also demand map? - render_format, - config: GraphicsConfig { - max_anisotropy: 16, - max_mip_count: 16, - }, - layouts: SceneBgLayouts::load(&device), - shaders: SceneShaders::load(&device), - device, - queue, - index_buffers: DemandMap::new(), - vertex_buffers: DemandMap::new(), - mesh_parts: DemandMap::new(), - prefabs: DemandMap::new(), - textures: DemandMap::new(), - placeholder_textures: DemandMap::new(), - generated_tangent_buffers: DemandMap::new(), - generated_normal_buffers: DemandMap::new(), - generated_texcoord_buffers: DemandMap::new(), - materials: DemandMap::new(), - pipelines: DemandMap::new(), - mip_generation_pipelines: DemandMap::new(), - } - } - pub fn update(&self, dls: &Downloader) -> Result { - let mut num_done = 0; - for pres in self.prefabs.needed() { - if let Some(prefab) = dls.try_get(pres.clone())? { - let mut rprefab = RPrefab(Vec::new()); - for (aff, partres) in &prefab.mesh { - if let Some(part) = self.mesh_parts.try_get(partres.clone()) { - rprefab.0.push((*aff, part.clone())); - } - } - if rprefab.0.len() == prefab.mesh.len() { - self.prefabs.insert(pres.clone(), Arc::new(rprefab), 0); - debug!("prefab created ({pres})"); - num_done += 1; - } - } - } - for pres in self.index_buffers.needed() { - let start = Instant::now(); - if let Some(buf) = dls.try_get(pres.clone())? { - let buffer = self.device.create_buffer_init(&BufferInitDescriptor { - label: Some("index"), - contents: bytemuck::cast_slice(buf.as_slice()), - usage: BufferUsages::INDEX | BufferUsages::COPY_DST, - }); - self.index_buffers.insert( - pres.clone(), - (Arc::new(buffer), (buf.len() * 3) as u32), - buf.len() * size_of::() * 3, - ); - debug!( - "index buffer created (len={}, took {:?}) {pres}", - buf.len() / size_of::(), - start.elapsed(), - ); - num_done += 1; - } - } - for pres in self.vertex_buffers.needed() { - let start = Instant::now(); - if let Some(buf) = dls.try_get(pres.clone())? { - let buffer = self.device.create_buffer_init(&BufferInitDescriptor { - contents: bytemuck::cast_slice(buf.as_slice()), - label: Some("vertex attribute"), - usage: BufferUsages::VERTEX | BufferUsages::COPY_DST, - }); - self.vertex_buffers.insert( - pres.clone(), - Arc::new(buffer), - buf.len() * size_of::(), - ); - debug!( - "vertex attribute buffer created (len={}, took {:?}) {pres}", - buf.len() / size_of::(), - start.elapsed() - ); - num_done += 1; - } - } - for format in self.mip_generation_pipelines.needed() { - self.mip_generation_pipelines.insert( - format, - Arc::new(MipGenerationPipeline::load(&self.device, format)), - 0, - ); - } - for spec in self.textures.needed() { - let start = Instant::now(); - let format = if spec.linear { - TextureFormat::Rgba8Unorm - } else { - TextureFormat::Rgba8UnormSrgb - }; - if let Some(mipgen) = self.mip_generation_pipelines.try_get(format) { - if let Some(buf) = dls.try_get(spec.data.clone())? { - let image = ImageReader::new(Cursor::new(buf.0)).with_guessed_format()?; - let image = image.decode()?; - let dims = (image.width(), image.height()); - let image = image.into_rgba8(); - let image = image.into_vec(); - let tex_bg = create_texture( - &self.device, - &self.queue, - &self.layouts.texture, - &image, - dims.0, - dims.1, - format, - Some(&mipgen), - &self.config, - ); - self.textures.insert(spec, tex_bg, image.len()); - debug!( - "texture created (res={}x{}, took {:?})", - dims.0, - dims.1, - start.elapsed() - ); - num_done += 1; - } - } - } - for kind in self.placeholder_textures.needed() { - let (linear, color) = match kind { - TextureIdentityKind::Normal => (true, [128, 128, 255, 255]), - TextureIdentityKind::Multiply => (false, [255, 255, 255, 255]), - }; - let tex_bg = create_texture( - &self.device, - &self.queue, - &self.layouts.texture, - &color, - 1, - 1, - if linear { - TextureFormat::Rgba8Unorm - } else { - TextureFormat::Rgba8UnormSrgb - }, - None, - &self.config, - ); - self.placeholder_textures.insert(kind, tex_bg, 4); - num_done += 1; - } - for spec in self.generated_tangent_buffers.needed() { - if let (Some(index), Some(position), texcoord) = ( - dls.try_get(spec.index.clone())?, - dls.try_get(spec.position.clone())?, - spec.texcoord.clone().map(|r| dls.try_get(r)).transpose()?, - ) { - let texcoord = match texcoord { - Some(Some(x)) => Some(x), - Some(None) => continue, // tangents provided but still loading - None => None, - }; - let texcoord = texcoord.unwrap_or_else(|| generate_texcoords(&index, &position)); - let tangents = generate_tangents(&index, &position, &texcoord); - let buffer = self.device.create_buffer_init(&BufferInitDescriptor { - label: Some("generated tangent"), - usage: BufferUsages::COPY_DST | BufferUsages::VERTEX, - contents: bytemuck::cast_slice(tangents.as_slice()), - }); - self.generated_tangent_buffers.insert( - spec, - Arc::new(buffer), - size_of::() * tangents.len() * 3, - ); - } - } - for spec in self.generated_normal_buffers.needed() { - if let (Some(index), Some(position)) = ( - dls.try_get(spec.index.clone())?, - dls.try_get(spec.position.clone())?, - ) { - let normals = generate_normals(&index, &position); - let buffer = self.device.create_buffer_init(&BufferInitDescriptor { - label: Some("generated normal"), - usage: BufferUsages::COPY_DST | BufferUsages::VERTEX, - contents: bytemuck::cast_slice(normals.as_slice()), - }); - self.generated_normal_buffers.insert( - spec, - Arc::new(buffer), - size_of::() * normals.len() * 3, - ); - } - } - for spec in self.generated_texcoord_buffers.needed() { - if let (Some(index), Some(position)) = ( - dls.try_get(spec.index.clone())?, - dls.try_get(spec.position.clone())?, - ) { - let texcoords = generate_texcoords(&index, &position); - let buffer = self.device.create_buffer_init(&BufferInitDescriptor { - label: Some("generated texcoord"), - usage: BufferUsages::COPY_DST | BufferUsages::VERTEX, - contents: bytemuck::cast_slice(texcoords.as_slice()), - }); - self.generated_texcoord_buffers.insert( - spec, - Arc::new(buffer), - size_of::() * texcoords.len() * 3, - ); - } - } - for spec in self.materials.needed() { - let buffer = self.device.create_buffer_init(&BufferInitDescriptor { - label: Some("material props"), - usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, - contents: bytemuck::cast_slice(&[spec]), - }); - let bind_group = self.device.create_bind_group(&BindGroupDescriptor { - label: Some("material"), - layout: &self.layouts.material, - entries: &[BindGroupEntry { - binding: 0, - resource: buffer.as_entire_binding(), - }], - }); - self.materials.insert(spec, Arc::new(bind_group), 0); - } - for spec in self.pipelines.needed() { - self.pipelines.insert( - spec.clone(), - Arc::new(spec.create(&self.device, &self.layouts, &self.shaders)), - 0, - ); - } - for pres in self.mesh_parts.needed() { - let start = Instant::now(); - if let Some(part) = dls.try_get(pres.clone())? { - if let (Some(indexres), Some(positionres)) = (part.index, part.va_position) { - let index = self.index_buffers.try_get(indexres.clone()); - let position = self - .vertex_buffers - .try_get(Resource(positionres.0, PhantomData)); - - let normal = if let Some(res) = part.va_normal.clone() { - self.vertex_buffers.try_get(Resource(res.0, PhantomData)) - } else { - self.generated_normal_buffers.try_get(NormalBufferSpec { - index: indexres.clone(), - position: Resource(positionres.0, PhantomData), - }) - }; - - let texcoord = if let Some(res) = part.va_texcoord.clone() { - self.vertex_buffers.try_get(Resource(res.0, PhantomData)) - } else { - self.generated_texcoord_buffers.try_get(TexcoordBufferSpec { - index: indexres.clone(), - position: Resource(positionres.0, PhantomData), - }) - }; - let tangent = if let Some(res) = part.va_tangent.clone() { - self.vertex_buffers.try_get(Resource(res.0, PhantomData)) - } else { - self.generated_tangent_buffers.try_get(TangentBufferSpec { - index: indexres, - position: Resource(positionres.0, PhantomData), - texcoord: part.va_texcoord, - }) - }; - - let joint_weight = if let Some(res) = part.va_joint_weight.clone() { - self.vertex_buffers - .try_get(Resource(res.0, PhantomData)) - .map(Some) - } else { - Some(None) - }; - let joint_index = if let Some(res) = part.va_joint_index.clone() { - self.vertex_buffers - .try_get(Resource(res.0, PhantomData)) - .map(Some) - } else { - Some(None) - }; - - let mut tex_albedo = None; - if let Some(albedores) = part.tex_albedo { - if let Some((_tex, bg)) = self.textures.try_get(TextureSpec { - data: albedores, - linear: false, - }) { - tex_albedo = Some(bg) - } - } else { - if let Some((_tex, bg)) = self - .placeholder_textures - .try_get(TextureIdentityKind::Multiply) - { - tex_albedo = Some(bg) - } - } - let mut tex_normal = None; - if let Some(normalres) = part.tex_normal { - if let Some((_tex, bg)) = self.textures.try_get(TextureSpec { - data: normalres, - linear: true, - }) { - tex_normal = Some(bg) - } - } else { - if let Some((_tex, bg)) = self - .placeholder_textures - .try_get(TextureIdentityKind::Normal) - { - tex_normal = Some(bg) - } - } - - let material = self.materials.try_get({ - let albedo = part.g_albedo.unwrap_or(Vec3A::ONE); - let emission = part.g_emission.unwrap_or(Vec3A::ONE); - Material { - roughness: part.g_roughness.unwrap_or(1.).to_bits(), - metallic: part.g_metallic.unwrap_or(0.).to_bits(), - _pad1: [0, 0], - albedo_alpha: uvec4( - albedo.x.to_bits(), - albedo.y.to_bits(), - albedo.z.to_bits(), - part.g_alpha.unwrap_or(1.).to_bits(), - ), - emission: uvec3( - emission.x.to_bits(), - emission.y.to_bits(), - emission.z.to_bits(), - ), - _pad2: 0, - } - }); - - let armature = if let Some(res) = part.armature.clone() { - Some(dls.try_get(res)?) - } else { - Some(None) - }; - - let pipeline = self.pipelines.try_get(PipelineSpec { - format: self.render_format, - skin: false, - backface_culling: part.g_double_sided.is_none(), - }); - - if let ( - Some(pipeline), - Some((index, index_count)), - Some(va_normal), - Some(va_tangent), - Some(va_texcoord), - Some(va_position), - Some(va_joint_index), - Some(va_joint_weight), - Some(armature), - Some(tex_normal), - Some(tex_albedo), - Some(material), - ) = ( - pipeline, - index, - normal, - tangent, - texcoord, - position, - joint_index, - joint_weight, - armature, - tex_normal, - tex_albedo, - material, - ) { - let double_sided = part.g_double_sided.is_some(); - - let joint_uniform = if let Some(a) = armature { - let ra = RArmature::new(&self.device, a); - Some(ra.joint_mat_uniform_buffer.clone()) - } else { - None - }; - - debug!("part created (took {:?}) {pres}", start.elapsed()); - self.mesh_parts.insert( - pres, - Arc::new(RMeshPart { - pipeline, - index_count, - index, - va_normal, - va_tangent, - va_position, - va_texcoord, - va_joint_index, - va_joint_weight, - tex_albedo, - tex_normal, - material, - double_sided, - joint_uniform, - }), - 0, - ); - num_done += 1; - } - } - } - } - self.print_missing(); - Ok(num_done) - } -} - -struct MipGenerationPipeline { - pipeline: RenderPipeline, -} -impl MipGenerationPipeline { - pub fn load(device: &Device, format: TextureFormat) -> Self { - let shader = device.create_shader_module(include_wgsl!("shaders/texture_copy.wgsl")); - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("mip generator"), - layout: None, - vertex: wgpu::VertexState { - module: &shader, - entry_point: Some("vs_main"), - compilation_options: Default::default(), - buffers: &[], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: Some("fs_main"), - compilation_options: Default::default(), - targets: &[Some(ColorTargetState { - format, - blend: None, - write_mask: ColorWrites::ALL, - })], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - multiview: None, - cache: None, - }); - Self { pipeline } - } -} - -fn create_texture( - device: &Device, - queue: &Queue, - bgl: &BindGroupLayout, - data: &[u8], - width: u32, - height: u32, - format: TextureFormat, - mipgen: Option<&MipGenerationPipeline>, - config: &GraphicsConfig, -) -> (Arc, Arc) { - let mip_level_count = (width.ilog2().max(4) - 3).min(config.max_mip_count); - - let extent = Extent3d { - depth_or_array_layers: 1, - width, - height, - }; - let texture = device.create_texture(&TextureDescriptor { - label: None, - size: extent, - mip_level_count, - sample_count: 1, - dimension: TextureDimension::D2, - format, - usage: TextureUsages::TEXTURE_BINDING - | TextureUsages::COPY_DST - | TextureUsages::RENDER_ATTACHMENT, - view_formats: &[], - }); - let textureview = texture.create_view(&TextureViewDescriptor::default()); - let sampler = device.create_sampler(&SamplerDescriptor { - address_mode_u: AddressMode::Repeat, - address_mode_v: AddressMode::Repeat, - mag_filter: FilterMode::Linear, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Linear, - anisotropy_clamp: config.max_anisotropy, - ..Default::default() - }); - let bind_group = device.create_bind_group(&BindGroupDescriptor { - label: None, - layout: &bgl, - entries: &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::TextureView(&textureview), - }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Sampler(&sampler), - }, - ], - }); - - let level_views = (0..mip_level_count) - .map(|mip| { - texture.create_view(&TextureViewDescriptor { - label: Some("mip generation level view"), - format: None, - dimension: None, - aspect: TextureAspect::All, - base_mip_level: mip, - mip_level_count: Some(1), - base_array_layer: 0, - array_layer_count: None, - }) - }) - .collect::>(); - - let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { label: None }); - - // TODO why does copy_buffer_to_texture have more restrictive alignment requirements?! - // let upload_buffer = device.create_buffer_init(&BufferInitDescriptor { - // label: Some("texture upload"), - // contents: data, - // usage: BufferUsages::COPY_DST | BufferUsages::COPY_SRC, - // }); - // encoder.copy_buffer_to_texture( - // ImageCopyBuffer { - // buffer: &upload_buffer, - // layout: ImageDataLayout { - // offset: 0, - // bytes_per_row: Some(width * 4), - // rows_per_image: None, - // }, - // }, - // texture.as_image_copy(), - // extent, - // ); - queue.write_texture( - texture.as_image_copy(), - data, - ImageDataLayout { - bytes_per_row: Some(width * 4), - rows_per_image: None, - offset: 0, - }, - extent, - ); - - for level in 1..mip_level_count { - let mip_pipeline = &mipgen.unwrap().pipeline; - let source_view = &level_views[level as usize - 1]; - let target_view = &level_views[level as usize]; - let mip_bind_group = device.create_bind_group(&BindGroupDescriptor { - layout: &mip_pipeline.get_bind_group_layout(0), - entries: &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::TextureView(source_view), - }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Sampler(&sampler), - }, - ], - label: None, - }); - let mut rpass = encoder.begin_render_pass(&RenderPassDescriptor { - label: None, - color_attachments: &[Some(RenderPassColorAttachment { - view: target_view, - resolve_target: None, - ops: Operations { - load: LoadOp::Clear(Color::WHITE), - store: StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - }); - - rpass.set_pipeline(&mip_pipeline); - rpass.set_bind_group(0, &mip_bind_group, &[]); - rpass.draw(0..3, 0..1); - } - - queue.submit(Some(encoder.finish())); - - (Arc::new(texture), Arc::new(bind_group)) -} - -pub struct SceneBgLayouts { - pub texture: BindGroupLayout, - pub material: BindGroupLayout, - pub joints: BindGroupLayout, -} -impl SceneBgLayouts { - pub fn load(device: &Device) -> Self { - Self { - texture: device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[ - BindGroupLayoutEntry { - binding: 0, - count: None, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Texture { - sample_type: TextureSampleType::Float { filterable: true }, - view_dimension: TextureViewDimension::D2, - multisampled: false, - }, - }, - BindGroupLayoutEntry { - binding: 1, - count: None, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Sampler(SamplerBindingType::Filtering), - }, - ], - label: None, - }), - material: device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - count: None, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - }], - label: None, - }), - joints: device.create_bind_group_layout(&BindGroupLayoutDescriptor { - entries: &[BindGroupLayoutEntry { - binding: 0, - count: None, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - }], - label: None, - }), - } - } -} - -impl PipelineSpec { - pub fn create( - &self, - device: &Device, - layouts: &SceneBgLayouts, - shaders: &SceneShaders, - ) -> RenderPipeline { - let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { - label: None, - bind_group_layouts: &[&layouts.texture, &layouts.texture, &layouts.material], - push_constant_ranges: &[PushConstantRange { - // 4x4 view projections - // 3x3(+1 pad) model basis - range: 0..((4 * 4 + 3 * 4) * size_of::() as u32), - stages: ShaderStages::VERTEX, - }], - }); - device.create_render_pipeline(&RenderPipelineDescriptor { - label: None, - layout: Some(&pipeline_layout), - fragment: Some(FragmentState { - module: &shaders.fragment_pbr, - entry_point: Some("main"), - targets: &[Some(ColorTargetState { - blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING), - format: self.format, - write_mask: ColorWrites::all(), - })], - compilation_options: PipelineCompilationOptions::default(), - }), - vertex: VertexState { - module: if self.skin { - &shaders.vertex_world_skin - } else { - &shaders.vertex_world - }, - entry_point: Some("main"), - buffers: &[ - // position - VertexBufferLayout { - step_mode: VertexStepMode::Vertex, - array_stride: 3 * size_of::() as u64, - attributes: &[VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 0, - }], - }, - // normal - VertexBufferLayout { - step_mode: VertexStepMode::Vertex, - array_stride: 3 * size_of::() as u64, - attributes: &[VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }], - }, - // tangent - VertexBufferLayout { - step_mode: VertexStepMode::Vertex, - array_stride: 3 * size_of::() as u64, - attributes: &[VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 2, - }], - }, - // texcoord - VertexBufferLayout { - step_mode: VertexStepMode::Vertex, - array_stride: 2 * size_of::() as u64, - attributes: &[VertexAttribute { - format: VertexFormat::Float32x2, - offset: 0, - shader_location: 3, - }], - }, - ], - compilation_options: PipelineCompilationOptions::default(), - }, - primitive: PrimitiveState { - topology: PrimitiveTopology::TriangleList, - front_face: FrontFace::Ccw, - cull_mode: if self.backface_culling { - Some(Face::Back) - } else { - None - }, - polygon_mode: PolygonMode::Fill, - ..Default::default() - }, - depth_stencil: Some(DepthStencilState { - depth_write_enabled: true, - depth_compare: CompareFunction::Less, - format: TextureFormat::Depth32Float, - bias: DepthBiasState::default(), - stencil: StencilState::default(), - }), - multisample: MultisampleState::default(), - multiview: None, - cache: None, - }) - } -} - -impl Widget for &DemandMap { - fn ui(self, ui: &mut egui::Ui) -> egui::Response { - let state = self.inner.read().unwrap(); - ui.label(state.needed.len().to_string()); - ui.label(state.values.len().to_string()); - ui.label(humansize::format_size(state.size_metric, DECIMAL)); - ui.end_row(); - ui.response() - } -} -impl ScenePreparer { - pub fn print_missing(&self) { - fn visit(name: &str, m: &DemandMap) - where - K: Clone, - K: Hash, - K: std::cmp::Eq, - V: Clone, - { - let nl = m.needed().len(); - if nl > 0 { - trace!("{name}: need {nl}") - } - } - visit("prefabs", &self.prefabs); - visit("mesh_parts", &self.mesh_parts); - visit("vertex_buffers", &self.vertex_buffers); - visit("index_buffers", &self.index_buffers); - visit("placeholder_textures", &self.placeholder_textures); - visit("generated_tangent_buffers", &self.generated_tangent_buffers); - visit("generated_normal_buffers", &self.generated_normal_buffers); - visit( - "generated_texcoord_buffers", - &self.generated_texcoord_buffers, - ); - visit("textures", &self.textures); - visit("materials", &self.materials); - visit("pipelines", &self.pipelines); - } -} - -impl Widget for &ScenePreparer { - fn ui(self, ui: &mut egui::Ui) -> egui::Response { - Grid::new("sp") - .num_columns(4) - .show(ui, |ui| { - ui.label("prefabs"); - self.prefabs.ui(ui); - ui.label("mesh_parts"); - self.mesh_parts.ui(ui); - ui.label("vertex_buffers"); - self.vertex_buffers.ui(ui); - ui.label("index_buffers"); - self.index_buffers.ui(ui); - ui.label("placeholder_textures"); - self.placeholder_textures.ui(ui); - ui.label("generated_tangent_buffers"); - self.generated_tangent_buffers.ui(ui); - ui.label("generated_normal_buffers"); - self.generated_normal_buffers.ui(ui); - ui.label("generated_texcoord_buffers"); - self.generated_texcoord_buffers.ui(ui); - ui.label("textures"); - self.textures.ui(ui); - ui.label("materials"); - self.materials.ui(ui); - ui.label("pipelines"); - self.pipelines.ui(ui); - }) - .response - } -} -- cgit v1.2.3-70-g09d2