From 724e6e4d97f608282e891742565b1036f3e970d5 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sun, 26 Jan 2025 22:22:53 +0100 Subject: graphics config --- client/src/render/mod.rs | 39 ++++++++++++++++----- client/src/render/scene/demand_map.rs | 18 ++++++++-- client/src/render/scene/mod.rs | 38 ++++++++++++++++---- client/src/render/scene/pipelines.rs | 9 +++-- client/src/render/scene/textures.rs | 4 +-- client/src/render/ui.rs | 66 ++++++++++++++++++++++++----------- 6 files changed, 133 insertions(+), 41 deletions(-) (limited to 'client/src/render') diff --git a/client/src/render/mod.rs b/client/src/render/mod.rs index db961f4..19f717a 100644 --- a/client/src/render/mod.rs +++ b/client/src/render/mod.rs @@ -57,13 +57,14 @@ pub struct Renderer<'a> { color_msaa: TextureView, config: GraphicsConfig, + pub config_update: Arc>, } #[derive(Debug, Clone)] pub struct GraphicsConfig { - max_anisotropy: u16, - max_mip_count: u32, - sample_count: u32, + pub max_anisotropy: u16, + pub max_mip_count: u32, + pub sample_count: u32, } impl<'a> Renderer<'a> { @@ -87,7 +88,8 @@ impl<'a> Renderer<'a> { let (device, queue) = adapter .request_device( &DeviceDescriptor { - required_features: Features::PUSH_CONSTANTS, + required_features: Features::PUSH_CONSTANTS + | Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, required_limits: Limits { max_push_constant_size: 128, max_vertex_buffers: 16, @@ -188,23 +190,42 @@ impl<'a> Renderer<'a> { queue, surface_configuration, ui_renderer, + color_msaa, + config_update: Arc::new(Mutex::new((false, config.clone()))), config, surface_needs_reconfigure: false, timing: Default::default(), timing_submit: Default::default(), - color_msaa, }) } + pub fn reconfigure(&mut self, config: GraphicsConfig) { + info!("graphics configuration changed"); + self.scene_prepare.reconfigure(&config); + self.ui_renderer.reconfigure(&config); + self.config = config; + self.recreate_framebuffers(); + } + pub fn check_reconfigure(&mut self) { + let m = self.config_update.clone(); + let mut lock = m.lock().unwrap(); + if lock.0 { + self.reconfigure(lock.1.clone()); + lock.0 = false; + } + } + pub fn resize(&mut self, width: u32, height: u32) { self.surface_configuration.width = width; self.surface_configuration.height = height; self.surface .configure(&self.device, &self.surface_configuration); - + self.recreate_framebuffers(); + } + pub fn recreate_framebuffers(&mut self) { let size = Extent3d { - height, - width, + width: self.surface_configuration.width, + height: self.surface_configuration.height, depth_or_array_layers: 1, }; self.depth = self @@ -242,6 +263,8 @@ impl<'a> Renderer<'a> { camera: &Camera, input_state: &mut InputState, ) -> Result<()> { + self.check_reconfigure(); + self.timing.begin("prepare"); if self.surface_needs_reconfigure { self.surface diff --git a/client/src/render/scene/demand_map.rs b/client/src/render/scene/demand_map.rs index 16fa181..c27eaac 100644 --- a/client/src/render/scene/demand_map.rs +++ b/client/src/render/scene/demand_map.rs @@ -25,7 +25,7 @@ pub struct DemandMap { inner: RwLock>, } struct DemandMapState { - values: HashMap, + values: HashMap, needed: HashSet, size_metric: usize, } @@ -46,18 +46,30 @@ impl DemandMap { 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); + if let Some((_, old_size)) = s.values.insert(key, (value, size)) { + s.size_metric -= old_size; + } 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) { + if let Some((k, _)) = s.values.get(&key) { Some(k.to_owned()) } else { s.needed.insert(key); None } } + pub fn regenerate_all(&self) { + let mut s = self.inner.write().unwrap(); + let keys = s.values.keys().cloned().collect::>(); + s.needed.extend(keys); + } + pub fn clear(&self) { + let mut s = self.inner.write().unwrap(); + s.values.clear(); + s.size_metric = 0; + } } impl Widget for &DemandMap { diff --git a/client/src/render/scene/mod.rs b/client/src/render/scene/mod.rs index ad7e0ce..16eecfc 100644 --- a/client/src/render/scene/mod.rs +++ b/client/src/render/scene/mod.rs @@ -21,16 +21,21 @@ pub mod pipelines; pub mod textures; pub mod vertex_buffers; -use super::{shaders::SceneShaders, GraphicsConfig}; +use super::{GraphicsConfig, shaders::SceneShaders}; use crate::{armature::RArmature, download::Downloader}; use anyhow::Result; use bytemuck::{Pod, Zeroable}; use demand_map::DemandMap; use egui::{Grid, Widget}; use glam::{UVec3, UVec4, Vec2, Vec3, Vec3A, uvec3, uvec4}; -use log::{debug, trace}; +use log::{debug, info, trace}; use pipelines::SceneBgLayouts; -use std::{hash::Hash, marker::PhantomData, sync::Arc, time::Instant}; +use std::{ + hash::Hash, + marker::PhantomData, + sync::{Arc, RwLock}, + time::Instant, +}; use textures::MipGenerationPipeline; use weareshared::{ Affine3A, @@ -49,7 +54,7 @@ pub struct ScenePreparer { layouts: SceneBgLayouts, shaders: SceneShaders, render_format: TextureFormat, - config: GraphicsConfig, + config: RwLock, downloader: Arc, textures: DemandMap, Arc)>, @@ -143,7 +148,7 @@ impl ScenePreparer { ) -> Self { Self { render_format, - config, + config: config.into(), layouts: SceneBgLayouts::load(&device), shaders: SceneShaders::load(&device), device, @@ -163,6 +168,22 @@ impl ScenePreparer { mip_generation_pipelines: DemandMap::new(), } } + pub fn reconfigure(&self, config: &GraphicsConfig) { + let mut cc = self.config.write().unwrap(); + if cc.max_anisotropy != config.max_anisotropy || cc.max_mip_count != config.max_mip_count { + info!("clear all scene textures"); + self.textures.clear(); + self.mesh_parts.clear(); + self.prefabs.clear(); + } + if cc.sample_count != config.sample_count { + info!("clear all scene pipelines"); + self.pipelines.clear(); + self.mesh_parts.clear(); + self.prefabs.clear(); + } + *cc = config.clone(); + } pub fn update(&self) -> Result { let mut num_done = 0; @@ -204,7 +225,12 @@ impl ScenePreparer { for spec in self.pipelines.needed() { self.pipelines.insert( spec.clone(), - Arc::new(spec.create(&self.device, &self.layouts, &self.shaders, &self.config)), + Arc::new(spec.create( + &self.device, + &self.layouts, + &self.shaders, + &self.config.read().unwrap().clone(), + )), 0, ); } diff --git a/client/src/render/scene/pipelines.rs b/client/src/render/scene/pipelines.rs index 53064c9..834d86d 100644 --- a/client/src/render/scene/pipelines.rs +++ b/client/src/render/scene/pipelines.rs @@ -16,6 +16,7 @@ */ use super::{GraphicsConfig, PipelineSpec}; use crate::render::shaders::SceneShaders; +use log::info; use wgpu::{ BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, @@ -95,8 +96,12 @@ impl PipelineSpec { shaders: &SceneShaders, config: &GraphicsConfig, ) -> RenderPipeline { + info!( + "creating scene pipeline (format={:?}, skin={}, culling={})", + self.format, self.backface_culling, self.skin + ); let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { - label: None, + label: Some("scene pipeline layout"), bind_group_layouts: &[&layouts.texture, &layouts.texture, &layouts.material], push_constant_ranges: &[PushConstantRange { // 4x4 model * view * project @@ -106,7 +111,7 @@ impl PipelineSpec { }], }); device.create_render_pipeline(&RenderPipelineDescriptor { - label: None, + label: Some("scene pipeline"), layout: Some(&pipeline_layout), fragment: Some(FragmentState { module: &shaders.fragment_pbr, diff --git a/client/src/render/scene/textures.rs b/client/src/render/scene/textures.rs index f85f21f..c385be2 100644 --- a/client/src/render/scene/textures.rs +++ b/client/src/render/scene/textures.rs @@ -94,7 +94,7 @@ impl ScenePreparer { TextureFormat::Rgba8UnormSrgb }, None, - &self.config, + &self.config.read().unwrap().clone(), ); self.placeholder_textures.insert(kind, tex_bg, 4); *num_done += 1; @@ -122,7 +122,7 @@ impl ScenePreparer { dims.1, format, Some(&mipgen), - &self.config, + &self.config.read().unwrap().clone(), ); self.textures.insert(spec, tex_bg, image.len()); debug!( diff --git a/client/src/render/ui.rs b/client/src/render/ui.rs index e27b9cb..4de2633 100644 --- a/client/src/render/ui.rs +++ b/client/src/render/ui.rs @@ -34,8 +34,8 @@ use wgpu::{ Buffer, BufferDescriptor, BufferUsages, ColorTargetState, ColorWrites, CommandEncoder, CompareFunction, DepthStencilState, Device, Extent3d, FilterMode, FragmentState, FrontFace, ImageCopyTexture, ImageDataLayout, IndexFormat, LoadOp, MultisampleState, Operations, Origin3d, - PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, - PrimitiveTopology, PushConstantRange, Queue, RenderPassColorAttachment, + PipelineCompilationOptions, PipelineLayout, PipelineLayoutDescriptor, PolygonMode, + PrimitiveState, PrimitiveTopology, PushConstantRange, Queue, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages, StoreOp, SurfaceConfiguration, Texture, TextureAspect, TextureDescriptor, TextureDimension, @@ -51,9 +51,11 @@ pub const UI_POSITION_OFFSET: f32 = 1000.; pub struct UiRenderer { device: Arc, queue: Arc, - _config: GraphicsConfig, + config: GraphicsConfig, ctx: Context, pipeline: RenderPipeline, + format: TextureFormat, + pipeline_layout: PipelineLayout, bind_group_layout: BindGroupLayout, textures: RwLock>, surfaces: RwLock>, @@ -82,9 +84,6 @@ impl UiRenderer { format: TextureFormat, config: GraphicsConfig, ) -> Self { - let frag_shader = device.create_shader_module(include_wgsl!("shaders/fragment_ui.wgsl")); - let vert_shader = device.create_shader_module(include_wgsl!("shaders/vertex_ui.wgsl")); - let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor { entries: &[ BindGroupLayoutEntry { @@ -114,8 +113,34 @@ impl UiRenderer { stages: ShaderStages::VERTEX, }], }); - let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor { - label: None, + let pipeline = + Self::create_pipeline(&device, &pipeline_layout, format, config.sample_count); + + Self { + ctx: Context::default(), + pipeline, + device, + queue, + pipeline_layout, + bind_group_layout, + config, + format, + last_pointer: Vec2::ZERO, + textures: HashMap::new().into(), + surfaces: HashMap::new().into(), + } + } + + fn create_pipeline( + device: &Device, + pipeline_layout: &PipelineLayout, + format: TextureFormat, + sample_count: u32, + ) -> RenderPipeline { + let frag_shader = device.create_shader_module(include_wgsl!("shaders/fragment_ui.wgsl")); + let vert_shader = device.create_shader_module(include_wgsl!("shaders/vertex_ui.wgsl")); + device.create_render_pipeline(&RenderPipelineDescriptor { + label: Some("ui pipeline"), layout: Some(&pipeline_layout), fragment: Some(FragmentState { module: &frag_shader, @@ -152,22 +177,23 @@ impl UiRenderer { bias: Default::default(), }), multisample: MultisampleState { - count: config.sample_count, + count: sample_count, ..Default::default() }, multiview: None, cache: None, - }); - Self { - ctx: Context::default(), - pipeline, - device, - queue, - bind_group_layout, - _config: config, - last_pointer: Vec2::ZERO, - textures: HashMap::new().into(), - surfaces: HashMap::new().into(), + }) + } + + pub fn reconfigure(&mut self, config: &GraphicsConfig) { + if self.config.sample_count != config.sample_count { + self.pipeline = Self::create_pipeline( + &self.device, + &self.pipeline_layout, + self.format, + config.sample_count, + ); + self.config.sample_count = config.sample_count; } } -- cgit v1.2.3-70-g09d2