diff --git a/assets/voxygen/shaders/ui-frag.glsl b/assets/voxygen/shaders/ui-frag.glsl index 60a607bb22..d696663404 100644 --- a/assets/voxygen/shaders/ui-frag.glsl +++ b/assets/voxygen/shaders/ui-frag.glsl @@ -11,9 +11,9 @@ uniform u_locals { vec4 w_pos; }; -layout(set = 1, binding = 1) +layout(set = 2, binding = 0) uniform texture2D t_tex; -layout(set = 1, binding = 2) +layout(set = 2, binding = 1) uniform sampler s_tex; layout(location = 0) out vec4 tgt_color; diff --git a/assets/voxygen/shaders/ui-vert.glsl b/assets/voxygen/shaders/ui-vert.glsl index c8732c0e93..848486a912 100644 --- a/assets/voxygen/shaders/ui-vert.glsl +++ b/assets/voxygen/shaders/ui-vert.glsl @@ -13,9 +13,9 @@ uniform u_locals { vec4 w_pos; }; -layout(set = 1, binding = 1) +layout(set = 2, binding = 0) uniform texture2D t_tex; -layout(set = 1, binding = 2) +layout(set = 2, binding = 1) uniform sampler s_tex; layout(location = 0) out vec2 f_uv; @@ -33,10 +33,10 @@ void main() { f_uv = v_uv; // Fixed scale In-game element vec4 projected_pos = /*proj_mat * view_mat*/all_mat * vec4(w_pos.xyz - focus_off.xyz, 1.0); - gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos/* * projected_pos.w*/, -1.0, /*projected_pos.w*/1.0); + gl_Position = vec4(projected_pos.xy / projected_pos.w + v_pos/* * projected_pos.w*/, 0.0, /*projected_pos.w*/1.0); } else if (v_mode == uint(3)) { // HACK: North facing source rectangle. - gl_Position = vec4(v_pos, -1.0, 1.0); + gl_Position = vec4(v_pos, 0.0, 1.0); vec2 look_at_dir = normalize(vec2(-view_mat[0][2], -view_mat[1][2])); // TODO: Consider cleaning up matrix to something more efficient (e.g. a mat3). vec2 aspect_ratio = textureSize(sampler2D(t_tex, s_tex), 0).yx; @@ -53,11 +53,11 @@ void main() { mat2 look_at = mat2(look_at_dir.y, -look_at_dir.x, look_at_dir.x, look_at_dir.y); vec2 v_centered = (v_pos - v_center) / aspect_ratio; vec2 v_rotated = look_at * v_centered; - gl_Position = vec4(aspect_ratio * v_rotated + v_center, -1.0, 1.0); + gl_Position = vec4(aspect_ratio * v_rotated + v_center, 0.0, 1.0); } else { // Interface element f_uv = v_uv; - gl_Position = vec4(v_pos, -1.0, 1.0); + gl_Position = vec4(v_pos, 0.0, 1.0); } f_mode = v_mode; } diff --git a/voxygen/src/menu/char_selection/ui/mod.rs b/voxygen/src/menu/char_selection/ui/mod.rs index 502320c95d..0cf81b88ea 100644 --- a/voxygen/src/menu/char_selection/ui/mod.rs +++ b/voxygen/src/menu/char_selection/ui/mod.rs @@ -1584,7 +1584,8 @@ impl CharSelectionUi { } // TODO: do we need globals? - pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer); } + pub fn render(&self, renderer: &mut Renderer) { /* self.ui.render(renderer);*/ + } } #[derive(Default)] diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs index dac729c725..aa8bad8466 100644 --- a/voxygen/src/menu/main/mod.rs +++ b/voxygen/src/menu/main/mod.rs @@ -1,4 +1,5 @@ mod client_init; +mod scene; mod ui; use super::char_selection::CharSelectionState; @@ -20,6 +21,7 @@ use client::{ use client_init::{ClientConnArgs, ClientInit, Error as InitError, Msg as InitMsg}; use common::comp; use common_base::span; +use scene::Scene; use std::{fmt::Debug, sync::Arc}; use tokio::runtime; use tracing::error; @@ -29,6 +31,7 @@ pub struct MainMenuState { main_menu_ui: MainMenuUi, // Used for client creation. client_init: Option, + scene: Scene, } impl MainMenuState { @@ -37,6 +40,7 @@ impl MainMenuState { Self { main_menu_ui: MainMenuUi::new(global_state), client_init: None, + scene: Scene::new(global_state.window.renderer_mut()), } } } @@ -342,8 +346,18 @@ impl PlayState for MainMenuState { fn name(&self) -> &'static str { "Title" } fn render(&mut self, renderer: &mut Renderer, _: &Settings) { + // TODO: maybe the drawer should be passed in from above? + let mut drawer = match renderer + .start_recording_frame(self.scene.global_bind_group()) + .unwrap() + { + Some(d) => d, + // Couldn't get swap chain texture this fime + None => return, + }; + // Draw the UI to the screen. - self.main_menu_ui.render(renderer); + self.main_menu_ui.render(&mut drawer.third_pass().draw_ui()); } } diff --git a/voxygen/src/menu/main/scene.rs b/voxygen/src/menu/main/scene.rs new file mode 100644 index 0000000000..b592e13db5 --- /dev/null +++ b/voxygen/src/menu/main/scene.rs @@ -0,0 +1,28 @@ +use crate::render::{ + GlobalModel, Globals, GlobalsBindGroup, Light, LodData, Renderer, Shadow, ShadowLocals, +}; + +pub struct Scene { + // global_data: GlobalModel, + // lod_data: LodData, + bind_group: GlobalsBindGroup, +} + +impl Scene { + pub fn new(renderer: &mut Renderer) -> Self { + let global_data = GlobalModel { + globals: renderer.create_consts(&[Globals::default()]), + lights: renderer.create_consts(&[Light::default(); 32]), + shadows: renderer.create_consts(&[Shadow::default(); 32]), + shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]), + }; + + let lod_data = LodData::dummy(renderer); + + let bind_group = renderer.bind_globals(&global_data, &lod_data); + + Self { bind_group } + } + + pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.bind_group } +} diff --git a/voxygen/src/menu/main/ui/mod.rs b/voxygen/src/menu/main/ui/mod.rs index 063845266e..a853db39fa 100644 --- a/voxygen/src/menu/main/ui/mod.rs +++ b/voxygen/src/menu/main/ui/mod.rs @@ -6,7 +6,7 @@ mod servers; use crate::{ i18n::{LanguageMetadata, LocalizationHandle}, - render::Renderer, + render::UiDrawer, ui::{ self, fonts::IcedFonts as Fonts, @@ -477,7 +477,7 @@ pub struct MainMenuUi { controls: Controls, } -impl<'a> MainMenuUi { +impl MainMenuUi { pub fn new(global_state: &mut GlobalState) -> Self { // Load language let i18n = &global_state.i18n.read(); @@ -582,5 +582,5 @@ impl<'a> MainMenuUi { events } - pub fn render(&self, renderer: &mut Renderer) { self.ui.render(renderer); } + pub fn render<'a>(&'a self, drawer: &mut UiDrawer<'_, 'a>) { self.ui.render(drawer); } } diff --git a/voxygen/src/render/buffer.rs b/voxygen/src/render/buffer.rs index 42eb72bda9..68fb6057c4 100644 --- a/voxygen/src/render/buffer.rs +++ b/voxygen/src/render/buffer.rs @@ -2,7 +2,7 @@ use bytemuck::Pod; use wgpu::util::DeviceExt; pub struct Buffer { - pub buf: wgpu::Buffer, + pub(super) buf: wgpu::Buffer, // Size in number of elements // TODO: determine if this is a good name len: usize, diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 01a56ae520..000da2d167 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -37,11 +37,12 @@ pub use self::{ ui::{ create_quad as create_ui_quad, create_quad_vert_gradient as create_ui_quad_vert_gradient, create_tri as create_ui_tri, - Locals as UiLocals, Mode as UiMode, Vertex as UiVertex, + Locals as UiLocals, LocalsBindGroup as UiLocalsBindGroup, Mode as UiMode, + TextureBindGroup as UiTextureBindGroup, Vertex as UiVertex, }, - GlobalModel, Globals, GlobalsLayouts, Light, Shadow, + GlobalModel, Globals, GlobalsBindGroup, GlobalsLayouts, Light, Shadow, }, - renderer::{ColLightInfo, Renderer}, + renderer::{ColLightInfo, Drawer, Renderer, UiDrawer}, texture::Texture, }; pub use wgpu::{AddressMode, FilterMode}; diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs index 771ef9d50e..9d379c12d5 100644 --- a/voxygen/src/render/model.rs +++ b/voxygen/src/render/model.rs @@ -13,7 +13,7 @@ pub struct SubModel<'a, V: Vertex> { } impl<'a, V: Vertex> SubModel<'a, V> { - pub fn buf(&self) -> &wgpu::Buffer { self.buf } + pub(super) fn buf(&self) -> &wgpu::Buffer { self.buf } } /// Represents a mesh that has been sent to the GPU. @@ -38,7 +38,7 @@ impl Model { } } - pub fn buf(&self) -> &wgpu::Buffer { &self.vbuf.buf } + pub(super) fn buf(&self) -> &wgpu::Buffer { &self.vbuf.buf } pub fn len(&self) -> usize { self.vbuf.len() } } diff --git a/voxygen/src/render/pipelines/clouds.rs b/voxygen/src/render/pipelines/clouds.rs index 11fecc31dd..ec65f6eb5b 100644 --- a/voxygen/src/render/pipelines/clouds.rs +++ b/voxygen/src/render/pipelines/clouds.rs @@ -150,7 +150,6 @@ impl CloudsPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index 1f6ff869b1..d7a098165d 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -143,7 +143,6 @@ impl FigureLayout { }, count: None, }, - // TODO: does this change at the same frequency? // col lights wgpu::BindGroupLayoutEntry { binding: 2, @@ -192,7 +191,6 @@ impl FigurePipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/fluid.rs b/voxygen/src/render/pipelines/fluid.rs index 05106513d7..f81d0720e1 100644 --- a/voxygen/src/render/pipelines/fluid.rs +++ b/voxygen/src/render/pipelines/fluid.rs @@ -105,7 +105,6 @@ impl FluidPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/lod_terrain.rs b/voxygen/src/render/pipelines/lod_terrain.rs index a46f32f27c..d3abbb0f07 100644 --- a/voxygen/src/render/pipelines/lod_terrain.rs +++ b/voxygen/src/render/pipelines/lod_terrain.rs @@ -35,6 +35,25 @@ pub struct LodData { } impl LodData { + pub fn dummy(renderer: &mut Renderer) -> Self { + let map_size = Vec2::new(1, 1); + let map_border = [0.0, 0.0, 0.0, 0.0]; + let map_image = [0]; + let alt_image = [0]; + let horizon_image = [0x_00_01_00_01]; + //let map_border = [0.0, 0.0, 0.0, 0.0]; + + Self::new( + renderer, + map_size, + &map_image, + &alt_image, + &horizon_image, + 1, + //map_border.into(), + ) + } + pub fn new( renderer: &mut Renderer, map_size: Vec2, @@ -44,65 +63,54 @@ impl LodData { tgt_detail: u32, //border_color: gfx::texture::PackedColor, ) -> Self { - let mut texture_info = wgpu::TextureDescriptor { - label: None, - size: wgpu::Extent3d { - width: map_size.x, - height: map_size.y, - depth: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, - usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, - }; + let mut create_texture = |format, data| { + let texture_info = wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: map_size.x, + height: map_size.y, + depth: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, + }; - let sampler_info = wgpu::SamplerDescriptor { - label: None, - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Nearest, - border_color: Some(wgpu::SamplerBorderColor::TransparentBlack), - ..Default::default() - }; + let sampler_info = wgpu::SamplerDescriptor { + label: None, + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + border_color: Some(wgpu::SamplerBorderColor::TransparentBlack), + ..Default::default() + }; - let mut view_info = wgpu::TextureViewDescriptor { - label: None, - format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), - dimension: Some(wgpu::TextureViewDimension::D2), - aspect: wgpu::TextureAspect::All, - base_mip_level: 0, - level_count: None, - base_array_layer: 0, - array_layer_count: None, - }; + let view_info = wgpu::TextureViewDescriptor { + label: None, + format: Some(format), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }; - let map = renderer.create_texture_with_data_raw( - &texture_info, - &view_info, - &sampler_info, - bytemuck::cast_slice(lod_base), - ); - texture_info.format = wgpu::TextureFormat::Rg16Uint; - view_info.format = Some(wgpu::TextureFormat::Rg16Uint); - let alt = renderer.create_texture_with_data_raw( - &texture_info, - &view_info, - &sampler_info, - bytemuck::cast_slice(lod_base), - ); - texture_info.format = wgpu::TextureFormat::Rgba8Unorm; - view_info.format = Some(wgpu::TextureFormat::Rg16Uint); - let horizon = renderer.create_texture_with_data_raw( - &texture_info, - &view_info, - &sampler_info, - bytemuck::cast_slice(lod_base), - ); + renderer.create_texture_with_data_raw( + &texture_info, + &view_info, + &sampler_info, + bytemuck::cast_slice(data), + ) + }; + let map = create_texture(wgpu::TextureFormat::Rgba8UnormSrgb, lod_base); + let alt = create_texture(wgpu::TextureFormat::Rg16Uint, lod_alt); + let horizon = create_texture(wgpu::TextureFormat::Rgba8Unorm, lod_horizon); Self { map, @@ -173,7 +181,6 @@ impl LodTerrainPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index 3686b67a51..3e6c065ee0 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -10,7 +10,7 @@ pub mod sprite; pub mod terrain; pub mod ui; -use super::Consts; +use super::{Consts, Texture}; use crate::scene::camera::CameraMode; use bytemuck::{Pod, Zeroable}; use common::terrain::BlockKind; @@ -225,6 +225,10 @@ pub struct GlobalModel { pub shadow_mats: Consts, } +pub struct GlobalsBindGroup { + pub(super) bind_group: wgpu::BindGroup, +} + pub struct GlobalsLayouts { pub globals: wgpu::BindGroupLayout, } @@ -315,7 +319,7 @@ impl GlobalsLayouts { ty: wgpu::BindingType::Sampler { comparison: false }, count: None, }, - // light shadows + // light shadows (ie shadows from a light?) wgpu::BindGroupLayoutEntry { binding: 9, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, @@ -382,4 +386,96 @@ impl GlobalsLayouts { Self { globals } } + + pub fn bind( + &self, + device: &wgpu::Device, + global_model: &GlobalModel, + lod_data: &lod_terrain::LodData, + noise: &Texture, + point_shadow_map: &Texture, + directed_shadow_map: &Texture, + ) -> GlobalsBindGroup { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.globals, + entries: &[ + // Global uniform + wgpu::BindGroupEntry { + binding: 0, + resource: global_model.globals.buf().as_entire_binding(), + }, + // Noise tex + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&noise.view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(&noise.sampler), + }, + // Light uniform + wgpu::BindGroupEntry { + binding: 3, + resource: global_model.lights.buf().as_entire_binding(), + }, + // Shadow uniform + wgpu::BindGroupEntry { + binding: 4, + resource: global_model.shadows.buf().as_entire_binding(), + }, + // Alt texture + wgpu::BindGroupEntry { + binding: 5, + resource: wgpu::BindingResource::TextureView(&lod_data.alt.view), + }, + wgpu::BindGroupEntry { + binding: 6, + resource: wgpu::BindingResource::Sampler(&lod_data.alt.sampler), + }, + // Horizon texture + wgpu::BindGroupEntry { + binding: 7, + resource: wgpu::BindingResource::TextureView(&lod_data.horizon.view), + }, + wgpu::BindGroupEntry { + binding: 8, + resource: wgpu::BindingResource::Sampler(&lod_data.horizon.sampler), + }, + // light shadows + wgpu::BindGroupEntry { + binding: 9, + resource: global_model.shadow_mats.buf().as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 10, + resource: wgpu::BindingResource::TextureView(&point_shadow_map.view), + }, + wgpu::BindGroupEntry { + binding: 11, + resource: wgpu::BindingResource::Sampler(&point_shadow_map.sampler), + }, + // directed shadow maps + wgpu::BindGroupEntry { + binding: 12, + resource: wgpu::BindingResource::TextureView(&directed_shadow_map.view), + }, + wgpu::BindGroupEntry { + binding: 13, + resource: wgpu::BindingResource::Sampler(&directed_shadow_map.sampler), + }, + // lod map (t_map) + wgpu::BindGroupEntry { + binding: 14, + resource: wgpu::BindingResource::TextureView(&lod_data.map.view), + }, + wgpu::BindGroupEntry { + binding: 15, + resource: wgpu::BindingResource::Sampler(&lod_data.map.sampler), + }, + ], + }); + + GlobalsBindGroup { bind_group } + } } diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index 359be22b55..8c9192f4f9 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -189,7 +189,6 @@ impl ParticlePipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/postprocess.rs b/voxygen/src/render/pipelines/postprocess.rs index 1dd4f6a313..0ef5a02072 100644 --- a/voxygen/src/render/pipelines/postprocess.rs +++ b/voxygen/src/render/pipelines/postprocess.rs @@ -146,7 +146,6 @@ impl PostProcessPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/shadow.rs b/voxygen/src/render/pipelines/shadow.rs index 93e8a8ca5c..c073f42991 100644 --- a/voxygen/src/render/pipelines/shadow.rs +++ b/voxygen/src/render/pipelines/shadow.rs @@ -22,7 +22,6 @@ impl Locals { pub fn default() -> Self { Self::new(Mat4::identity(), Mat4::identity()) } - // TODO: unused? fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: None, @@ -131,7 +130,6 @@ impl ShadowFigurePipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, @@ -214,7 +212,6 @@ impl ShadowPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index b5a1d36021..c19b5493df 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -46,7 +46,6 @@ impl SkyboxPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/sprite.rs b/voxygen/src/render/pipelines/sprite.rs index 402feccf03..c9424bb6e9 100644 --- a/voxygen/src/render/pipelines/sprite.rs +++ b/voxygen/src/render/pipelines/sprite.rs @@ -176,7 +176,6 @@ impl SpriteLayout { label: None, entries: &[ // locals - // TODO: different freq wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, @@ -239,7 +238,6 @@ impl SpritePipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/terrain.rs b/voxygen/src/render/pipelines/terrain.rs index e8bb8b4dbb..79f5631030 100644 --- a/voxygen/src/render/pipelines/terrain.rs +++ b/voxygen/src/render/pipelines/terrain.rs @@ -170,7 +170,6 @@ impl TerrainLayout { count: None, }, // col lights - // TODO: same frequency? wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, @@ -218,7 +217,6 @@ impl TerrainPipeline { let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs index 9fe36a018c..6c87ab9adf 100644 --- a/voxygen/src/render/pipelines/ui.rs +++ b/voxygen/src/render/pipelines/ui.rs @@ -1,4 +1,4 @@ -use super::super::{AaMode, GlobalsLayouts, Quad, Tri}; +use super::super::{AaMode, Consts, GlobalsLayouts, Quad, Texture, Tri}; use bytemuck::{Pod, Zeroable}; use vek::*; @@ -80,11 +80,20 @@ impl Mode { } } -pub struct UILayout { - pub locals: wgpu::BindGroupLayout, +pub struct LocalsBindGroup { + pub(in super::super) bind_group: wgpu::BindGroup, } -impl UILayout { +pub struct TextureBindGroup { + pub(in super::super) bind_group: wgpu::BindGroup, +} + +pub struct UiLayout { + pub locals: wgpu::BindGroupLayout, + pub texture: wgpu::BindGroupLayout, +} + +impl UiLayout { pub fn new(device: &wgpu::Device) -> Self { Self { locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -100,9 +109,14 @@ impl UILayout { }, count: None, }, + ], + }), + texture: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[ // texture wgpu::BindGroupLayoutEntry { - binding: 1, + binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::SampledTexture { component_type: wgpu::TextureComponentType::Float, @@ -112,7 +126,7 @@ impl UILayout { count: None, }, wgpu::BindGroupLayoutEntry { - binding: 2, + binding: 1, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: false }, count: None, @@ -121,33 +135,64 @@ impl UILayout { }), } } + + pub fn bind_locals(&self, device: &wgpu::Device, locals: &Consts) -> LocalsBindGroup { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.locals, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: locals.buf().as_entire_binding(), + }], + }); + + LocalsBindGroup { bind_group } + } + + pub fn bind_texture(&self, device: &wgpu::Device, texture: &Texture) -> TextureBindGroup { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.texture, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&texture.sampler), + }, + ], + }); + + TextureBindGroup { bind_group } + } } -pub struct UIPipeline { +pub struct UiPipeline { pub pipeline: wgpu::RenderPipeline, } -impl UIPipeline { +impl UiPipeline { pub fn new( device: &wgpu::Device, vs_module: &wgpu::ShaderModule, fs_module: &wgpu::ShaderModule, sc_desc: &wgpu::SwapChainDescriptor, global_layout: &GlobalsLayouts, - layout: &UILayout, + layout: &UiLayout, aa_mode: AaMode, ) -> Self { let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("UI pipeline layout"), + label: Some("Ui pipeline layout"), push_constant_ranges: &[], - bind_group_layouts: &[&global_layout.globals, &layout.locals], + bind_group_layouts: &[&global_layout.globals, &layout.locals, &layout.texture], }); let samples = match aa_mode { AaMode::None | AaMode::Fxaa => 1, // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::SsaaX4 => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index c5cffa1e9b..64d723f49f 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -1,3 +1,8 @@ +mod bind_group; +mod drawer; + +pub use drawer::{Drawer, UiDrawer}; + use super::{ consts::Consts, instances::Instances, @@ -8,8 +13,8 @@ use super::{ ui, GlobalsLayouts, }, texture::Texture, - AaMode, AddressMode, CloudMode, FilterMode, FluidMode, LightingMode, RenderError, RenderMode, - ShadowMapMode, ShadowMode, Vertex, + AaMode, AddressMode, CloudMode, FilterMode, FluidMode, GlobalsBindGroup, LightingMode, + RenderError, RenderMode, ShadowMapMode, ShadowMode, Vertex, }; use common::assets::{self, AssetExt, AssetHandle}; use common_base::span; @@ -20,6 +25,7 @@ use vek::*; /// A type representing data that can be converted to an immutable texture map /// of ColLight data (used for texture atlases created during greedy meshing). +// TODO: revert to u16 pub type ColLightInfo = (Vec<[u8; 4]>, Vec2); /// Load from a GLSL file. @@ -116,9 +122,9 @@ impl Shaders { pub struct ShadowMapRenderer { // directed_encoder: gfx::Encoder, // point_encoder: gfx::Encoder, - directed_depth_stencil: Texture, + directed_depth: Texture, - point_depth_stencil: Texture, + point_depth: Texture, point_pipeline: shadow::ShadowPipeline, terrain_directed_pipeline: shadow::ShadowPipeline, @@ -128,6 +134,7 @@ pub struct ShadowMapRenderer { /// A type that stores all the layouts associated with this renderer. pub struct Layouts { + // TODO: pub(self)?? pub(self) global: GlobalsLayouts, pub(self) clouds: clouds::CloudsLayout, @@ -137,7 +144,7 @@ pub struct Layouts { pub(self) shadow: shadow::ShadowLayout, pub(self) sprite: sprite::SpriteLayout, pub(self) terrain: terrain::TerrainLayout, - pub(self) ui: ui::UILayout, + pub(self) ui: ui::UiLayout, } /// A type that encapsulates rendering state. `Renderer` is central to Voxygen's @@ -156,7 +163,7 @@ pub struct Renderer { win_depth_view: wgpu::TextureView, tgt_color_view: wgpu::TextureView, - tgt_depth_stencil_view: wgpu::TextureView, + tgt_depth_view: wgpu::TextureView, // TODO: rename tgt_color_pp_view: wgpu::TextureView, @@ -177,7 +184,7 @@ pub struct Renderer { skybox_pipeline: skybox::SkyboxPipeline, sprite_pipeline: sprite::SpritePipeline, terrain_pipeline: terrain::TerrainPipeline, - ui_pipeline: ui::UIPipeline, + ui_pipeline: ui::UiPipeline, shaders: AssetHandle, @@ -273,7 +280,7 @@ impl Renderer { let shadow = shadow::ShadowLayout::new(&device); let sprite = sprite::SpriteLayout::new(&device); let terrain = terrain::TerrainLayout::new(&device); - let ui = ui::UILayout::new(&device); + let ui = ui::UiLayout::new(&device); Layouts { global, @@ -313,7 +320,7 @@ impl Renderer { shadow_views.is_some(), )?; - let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) = + let (tgt_color_view, tgt_depth_view, tgt_color_pp_view, win_depth_view) = Self::create_rt_views(&device, (dims.width, dims.height), &mode)?; let shadow_map = if let ( @@ -327,16 +334,16 @@ impl Renderer { figure_directed_shadow_pipeline, shadow_views, ) { - let (point_depth_stencil, directed_depth_stencil) = shadow_views; + let (point_depth, directed_depth) = shadow_views; let layout = shadow::ShadowLayout::new(&device); Some(ShadowMapRenderer { - directed_depth_stencil, + directed_depth, // point_encoder: factory.create_command_buffer().into(), // directed_encoder: factory.create_command_buffer().into(), - point_depth_stencil, + point_depth, point_pipeline, terrain_directed_pipeline, @@ -378,7 +385,7 @@ impl Renderer { win_depth_view, tgt_color_view, - tgt_depth_stencil_view, + tgt_depth_view, tgt_color_pp_view, sampler, @@ -411,7 +418,7 @@ impl Renderer { /// before post-processing. #[allow(dead_code)] pub fn tgt_views(&self) -> (&wgpu::TextureView, &wgpu::TextureView) { - (&self.tgt_color_view, &self.tgt_depth_stencil_view) + (&self.tgt_color_view, &self.tgt_depth_view) } /// Get references to the internal render target views that get displayed @@ -446,19 +453,19 @@ impl Renderer { self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc); // Resize other render targets - let (tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view) = + let (tgt_color_view, tgt_depth_view, tgt_color_pp_view, win_depth_view) = Self::create_rt_views(&mut self.device, (dims.x, dims.y), &self.mode)?; self.win_depth_view = win_depth_view; self.tgt_color_view = tgt_color_view; - self.tgt_depth_stencil_view = tgt_depth_stencil_view; + self.tgt_depth_view = tgt_depth_view; self.tgt_color_pp_view = tgt_color_pp_view; if let (Some(shadow_map), ShadowMode::Map(mode)) = (self.shadow_map.as_mut(), self.mode.shadow) { match Self::create_shadow_views(&mut self.device, (dims.x, dims.y), &mode) { - Ok((point_depth_stencil, directed_depth_stencil)) => { - shadow_map.point_depth_stencil = point_depth_stencil; - shadow_map.directed_depth_stencil = directed_depth_stencil; + Ok((point_depth, directed_depth)) => { + shadow_map.point_depth = point_depth; + shadow_map.directed_depth = directed_depth; }, Err(err) => { warn!("Could not create shadow map views: {:?}", err); @@ -496,7 +503,7 @@ impl Renderer { }; let levels = 1; - let mut color_view = || { + let color_view = || { let tex = device.create_texture(&wgpu::TextureDescriptor { label: None, size: wgpu::Extent3d { @@ -527,7 +534,7 @@ impl Renderer { let tgt_color_view = color_view(); let tgt_color_pp_view = color_view(); - let tgt_depth_stencil_tex = device.create_texture(&wgpu::TextureDescriptor { + let tgt_depth_tex = device.create_texture(&wgpu::TextureDescriptor { label: None, size: wgpu::Extent3d { width, @@ -540,17 +547,16 @@ impl Renderer { format: wgpu::TextureFormat::Depth24Plus, usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::RENDER_ATTACHMENT, }); - let tgt_depth_stencil_view = - tgt_depth_stencil_tex.create_view(&wgpu::TextureViewDescriptor { - label: None, - format: Some(wgpu::TextureFormat::Depth24Plus), - dimension: Some(wgpu::TextureViewDimension::D2), - aspect: wgpu::TextureAspect::DepthOnly, - base_mip_level: 0, - level_count: None, - base_array_layer: 0, - array_layer_count: None, - }); + let tgt_depth_view = tgt_depth_tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Depth24Plus), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::DepthOnly, + base_mip_level: 0, + level_count: None, + base_array_layer: 0, + array_layer_count: None, + }); let win_depth_tex = device.create_texture(&wgpu::TextureDescriptor { label: None, @@ -565,7 +571,7 @@ impl Renderer { format: wgpu::TextureFormat::Depth24Plus, usage: wgpu::TextureUsage::RENDER_ATTACHMENT, }); - let win_depth_view = tgt_depth_stencil_tex.create_view(&wgpu::TextureViewDescriptor { + let win_depth_view = tgt_depth_tex.create_view(&wgpu::TextureViewDescriptor { label: None, format: Some(wgpu::TextureFormat::Depth24Plus), dimension: Some(wgpu::TextureViewDimension::D2), @@ -578,7 +584,7 @@ impl Renderer { Ok(( tgt_color_view, - tgt_depth_stencil_view, + tgt_depth_view, tgt_color_pp_view, win_depth_view, )) @@ -656,7 +662,7 @@ impl Renderer { }; //TODO: (0, levels - 1), ?? from master - let mut point_shadow_view = wgpu::TextureViewDescriptor { + let point_shadow_view = wgpu::TextureViewDescriptor { label: None, format: Some(wgpu::TextureFormat::Depth24Plus), dimension: Some(wgpu::TextureViewDimension::Cube), @@ -723,8 +729,8 @@ impl Renderer { pub fn get_shadow_resolution(&self) -> (Vec2, Vec2) { if let Some(shadow_map) = &self.shadow_map { ( - shadow_map.point_depth_stencil.get_dimensions().xy(), - shadow_map.directed_depth_stencil.get_dimensions().xy(), + shadow_map.point_depth.get_dimensions().xy(), + shadow_map.directed_depth.get_dimensions().xy(), ) } else { (Vec2::new(1, 1), Vec2::new(1, 1)) @@ -741,10 +747,10 @@ impl Renderer { // if let Some(shadow_map) = self.shadow_map.as_mut() { // // let point_encoder = &mut shadow_map.point_encoder; // let point_encoder = &mut self.encoder; - // point_encoder.clear_depth(&shadow_map.point_depth_stencil_view, 1.0); + // point_encoder.clear_depth(&shadow_map.point_depth_view, 1.0); // // let directed_encoder = &mut shadow_map.directed_encoder; // let directed_encoder = &mut self.encoder; - // directed_encoder.clear_depth(&shadow_map.directed_depth_stencil_view, + // directed_encoder.clear_depth(&shadow_map.directed_depth_view, // 1.0); } // } @@ -802,51 +808,20 @@ impl Renderer { // } // } - /// Perform all queued draw calls for this frame and clean up discarded - /// items. - pub fn flush(&mut self) -> Result<(), RenderError> { - span!(_guard, "flush", "Renderer::flush"); - let frame = match self.swap_chain.get_current_frame() { - Ok(frame) => frame.output, - // If lost recreate the swap chain - Err(err @ wgpu::SwapChainError::Lost) => { - warn!("{}. Recreating swap chain. A frame will be missed", err); - return self.on_resize(self.resolution); - }, - Err(err @ wgpu::SwapChainError::Timeout) => { - warn!("{}. This will probably be resolved on the next frame", err); - return Ok(()); - }, - Err(err @ wgpu::SwapChainError::Outdated) => { - warn!("{}. This will probably be resolved on the next frame", err); - return Ok(()); - }, - Err(err @ wgpu::SwapChainError::OutOfMemory) => return Err(err.into()), - }; - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("A render encoder"), - }); - { - let _render_pas = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.1, - g: 0.7, - b: 0.3, - a: 1.0, - }), - store: true, - }, - }], - depth_stencil_attachment: None, - }); - } - self.queue.submit(std::iter::once(encoder.finish())); + /// Start recording the frame + /// When the returned `Drawer` is dropped the recorded draw calls will be + /// submitted to the queue + /// If there is an intermittent issue with the swap chain then Ok(None) will + /// be returned + pub fn start_recording_frame<'a>( + &'a mut self, + globals: &'a GlobalsBindGroup, + ) -> Result>, RenderError> { + span!( + _guard, + "start_recording_frame", + "Renderer::start_recording_frame" + ); self.device.poll(wgpu::Maintain::Poll); @@ -855,7 +830,30 @@ impl Renderer { self.recreate_pipelines(); } - Ok(()) + let tex = match self.swap_chain.get_current_frame() { + Ok(frame) => frame.output, + // If lost recreate the swap chain + Err(err @ wgpu::SwapChainError::Lost) => { + warn!("{}. Recreating swap chain. A frame will be missed", err); + return self.on_resize(self.resolution).map(|()| None); + }, + Err(err @ wgpu::SwapChainError::Timeout) => { + warn!("{}. This will probably be resolved on the next frame", err); + return Ok(None); + }, + Err(err @ wgpu::SwapChainError::Outdated) => { + warn!("{}. This will probably be resolved on the next frame", err); + return Ok(None); + }, + Err(err @ wgpu::SwapChainError::OutOfMemory) => return Err(err.into()), + }; + let encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("A render encoder"), + }); + + Ok(Some(Drawer::new(encoder, self, tex, globals))) } /// Recreate the pipelines @@ -916,14 +914,10 @@ impl Renderer { } /// Create a new set of constants with the provided values. - pub fn create_consts( - &mut self, - vals: &[T], - // TODO: don't use result here - ) -> Result, RenderError> { + pub fn create_consts(&mut self, vals: &[T]) -> Consts { let mut consts = Consts::new(&self.device, vals.len()); consts.update(&self.device, &self.queue, vals, 0); - Ok(consts) + consts } /// Update a set of constants with the provided values. @@ -1134,8 +1128,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1193,8 +1187,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1253,8 +1247,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (0, 0) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (0, 0) */), }, // ); */ // } @@ -1312,8 +1306,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1371,8 +1365,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1414,7 +1408,7 @@ impl Renderer { // // Shadow stuff // light_shadows: locals.buf.clone(), - // tgt_depth_stencil: shadow_map.point_depth_stencil_view.clone(), + // tgt_depth: shadow_map.point_depth_view.clone(), // }, // ); // } @@ -1457,8 +1451,8 @@ impl Renderer { // // Shadow stuff // light_shadows: locals.buf.clone(), - // tgt_depth_stencil: - // shadow_map.directed_depth_stencil_view.clone(), }, + // tgt_depth: + // shadow_map.directed_depth_view.clone(), }, // ); // } @@ -1503,8 +1497,8 @@ impl Renderer { // // Shadow stuff // light_shadows: locals.buf.clone(), - // tgt_depth_stencil: - // shadow_map.directed_depth_stencil_view.clone(), }, + // tgt_depth: + // shadow_map.directed_depth_view.clone(), }, // ); // } @@ -1560,8 +1554,8 @@ impl Renderer { // noise: (self.noise_tex.srv.clone(), // self.noise_tex.sampler.clone()), waves: (waves.srv.clone(), // waves.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1625,8 +1619,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1657,8 +1651,8 @@ impl Renderer { // lod.map.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1711,8 +1705,8 @@ impl Renderer { // self.noise_tex.sampler.clone()), alt: (lod.alt.srv.clone(), // lod.alt.sampler.clone()), horizon: (lod.horizon.srv.clone(), // lod.horizon.sampler.clone()), tgt_color: - // self.tgt_color_view.clone(), tgt_depth_stencil: - // (self.tgt_depth_stencil_view.clone()/* , (1, 1) */), }, + // self.tgt_color_view.clone(), tgt_depth: + // (self.tgt_depth_view.clone()/* , (1, 1) */), }, // ); // } @@ -1836,7 +1830,7 @@ fn create_pipelines( fluid::FluidPipeline, sprite::SpritePipeline, particle::ParticlePipeline, - ui::UIPipeline, + ui::UiPipeline, lod_terrain::LodTerrainPipeline, clouds::CloudsPipeline, postprocess::PostProcessPipeline, @@ -2029,7 +2023,7 @@ fn create_pipelines( ); // Construct a pipeline for rendering UI elements - let ui_pipeline = ui::UIPipeline::new( + let ui_pipeline = ui::UiPipeline::new( device, &create_shader("ui-vert", ShaderKind::Vertex)?, &create_shader("ui-frag", ShaderKind::Fragment)?, @@ -2077,7 +2071,7 @@ fn create_pipelines( // let player_shadow_pipeline = create_pipeline( // factory, // figure::pipe::Init { - // tgt_depth_stencil: (gfx::preset::depth::PASS_TEST/*, + // tgt_depth: (gfx::preset::depth::PASS_TEST/*, // Stencil::new( // Comparison::Equal, // 0xff, diff --git a/voxygen/src/render/renderer/bind_group.rs b/voxygen/src/render/renderer/bind_group.rs new file mode 100644 index 0000000000..fd6af70f04 --- /dev/null +++ b/voxygen/src/render/renderer/bind_group.rs @@ -0,0 +1,38 @@ +use super::{ + super::{ + consts::Consts, + pipelines::{lod_terrain, ui, GlobalModel, GlobalsBindGroup}, + texture::Texture, + }, + Renderer, +}; + +impl Renderer { + pub fn bind_globals( + &self, + global_model: &GlobalModel, + lod_data: &lod_terrain::LodData, + ) -> GlobalsBindGroup { + let (point_shadow_map, directed_shadow_map) = match &self.shadow_map { + Some(shadow_map) => (&shadow_map.point_depth, &shadow_map.directed_depth), + None => (&self.noise_tex, &self.noise_tex), + }; + + self.layouts.global.bind( + &self.device, + global_model, + lod_data, + &self.noise_tex, + point_shadow_map, + directed_shadow_map, + ) + } + + pub fn ui_bind_locals(&self, locals: &Consts) -> ui::LocalsBindGroup { + self.layouts.ui.bind_locals(&self.device, locals) + } + + pub fn ui_bind_texture(&self, texture: &Texture) -> ui::TextureBindGroup { + self.layouts.ui.bind_texture(&self.device, texture) + } +} diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs new file mode 100644 index 0000000000..38a2b04605 --- /dev/null +++ b/voxygen/src/render/renderer/drawer.rs @@ -0,0 +1,360 @@ +use super::{ + super::{ + buffer::Buffer, + consts::Consts, + instances::Instances, + model::{DynamicModel, Model}, + pipelines::{ + figure, fluid, postprocess, sprite, terrain, ui, GlobalsBindGroup, Light, Shadow, + }, + }, + Renderer, +}; +use std::ops::Range; +use vek::Aabr; + +pub struct Drawer<'a> { + encoder: Option, + renderer: &'a mut Renderer, + tex: wgpu::SwapChainTexture, + globals: &'a GlobalsBindGroup, + //pub(super) postprocess_locals: wgpu::BindGroup, +} + +impl<'a> Drawer<'a> { + pub fn new( + encoder: wgpu::CommandEncoder, + renderer: &'a mut Renderer, + tex: wgpu::SwapChainTexture, + globals: &'a GlobalsBindGroup, + ) -> Self { + Self { + encoder: Some(encoder), + renderer, + tex, + globals, + } + } + + /*pub fn first_pass(&mut self) -> FirstPassDrawer { + let render_pass = + self.encoder + .as_mut() + .unwrap() + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &self.renderer.tgt_color_view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color::TRANSPARENT, + }], + depth_stencil_attachment: Some( + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &self.renderer.depth_stencil_texture.view, + depth_load_op: wgpu::LoadOp::Clear, + depth_store_op: wgpu::StoreOp::Store, + clear_depth: 1.0, + stencil_load_op: wgpu::LoadOp::Clear, + stencil_store_op: wgpu::StoreOp::Store, + clear_stencil: 0, + }, + ), + }); + + render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + + FirstPassDrawer { + render_pass, + renderer: &self.renderer, + } + } + + pub fn second_pass(&mut self) -> SecondPassDrawer { + let render_pass = + self.encoder + .as_mut() + .unwrap() + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &self.renderer.tgt_color_pp_view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color::TRANSPARENT, + }], + depth_stencil_attachment: None, + }); + + render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + + SecondPassDrawer { + render_pass, + renderer: &self.renderer, + } + }*/ + + pub fn third_pass(&mut self) -> ThirdPassDrawer { + let mut render_pass = + self.encoder + .as_mut() + .unwrap() + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &self.tex.view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 1.0, + g: 0.25, + b: 0.5, + a: 0.5, + }), + store: true, + }, + }], + // TODO: do we need this? + depth_stencil_attachment: Some( + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &self.renderer.win_depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }, + ), + }); + + render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + + ThirdPassDrawer { + render_pass, + renderer: &self.renderer, + //postprocess_locals: &self.postprocess_locals, + } + } +} + +impl<'a> Drop for Drawer<'a> { + fn drop(&mut self) { + self.renderer + .queue + .submit(std::iter::once(self.encoder.take().unwrap().finish())); + } +} + +/*pub struct FirstPassDrawer<'a> { + pub(super) render_pass: wgpu::RenderPass<'a>, + pub renderer: &'a Renderer, +} + +impl<'a> FirstPassDrawer<'a> { + pub fn draw_skybox<'b: 'a>( + &mut self, + model: &'b Model, + globals: &'b Consts, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.skybox_pipeline.pipeline); + self.render_pass.set_bind_group(0, &globals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); + self.render_pass.draw(verts, 0..1); + } + + pub fn draw_figure<'b: 'a>( + &mut self, + model: &'b Model, + locals: &'b Consts, + bones: &'b Consts, + globals: &'b Consts, + lights: &'b Consts, + shadows: &'b Consts, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.figure_pipeline.pipeline); + self.render_pass.set_bind_group(0, &globals.bind_group, &[]); + self.render_pass.set_bind_group(1, &lights.bind_group, &[]); + self.render_pass.set_bind_group(2, &shadows.bind_group, &[]); + self.render_pass.set_bind_group(3, &locals.bind_group, &[]); + self.render_pass.set_bind_group(4, &bones.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); + self.render_pass.draw(verts, 0..1); + } + + pub fn draw_terrain<'b: 'a>( + &mut self, + model: &'b Model, + locals: &'b Consts, + globals: &'b Consts, + lights: &'b Consts, + shadows: &'b Consts, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.terrain_pipeline.pipeline); + self.render_pass.set_bind_group(0, &globals.bind_group, &[]); + self.render_pass.set_bind_group(1, &lights.bind_group, &[]); + self.render_pass.set_bind_group(2, &shadows.bind_group, &[]); + self.render_pass.set_bind_group(3, &locals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); + self.render_pass.draw(verts, 0..1) + } + + pub fn draw_fluid<'b: 'a>( + &mut self, + model: &'b Model, + locals: &'b Consts, + waves: &'b Consts, + globals: &'b Consts, + lights: &'b Consts, + shadows: &'b Consts, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.fluid_pipeline.pipeline); + self.render_pass.set_bind_group(0, &globals.bind_group, &[]); + self.render_pass.set_bind_group(1, &lights.bind_group, &[]); + self.render_pass.set_bind_group(2, &shadows.bind_group, &[]); + self.render_pass.set_bind_group(3, &locals.bind_group, &[]); + self.render_pass.set_bind_group(4, &waves.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); + self.render_pass.draw(verts, 0..1); + } + + pub fn draw_sprite<'b: 'a>( + &mut self, + model: &'b Model, + instances: &'a Instances, + globals: &'b Consts, + lights: &'b Consts, + shadows: &'b Consts, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.sprite_pipeline.pipeline); + self.render_pass.set_bind_group(0, &globals.bind_group, &[]); + self.render_pass.set_bind_group(1, &lights.bind_group, &[]); + self.render_pass.set_bind_group(2, &shadows.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); + self.render_pass.set_vertex_buffer(1, &instances.ibuf, 0, 0); + self.render_pass.draw(verts, 0..instances.count() as u32); + } +} + +pub struct SecondPassDrawer<'a> { + pub(super) render_pass: wgpu::RenderPass<'a>, + pub renderer: &'a Renderer, +} + +impl<'a> SecondPassDrawer<'a> { + pub fn draw_post_process<'b: 'a>( + &mut self, + model: &'b Model, + globals: &'b Consts, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.postprocess_pipeline.pipeline); + self.render_pass.set_bind_group(0, &globals.bind_group, &[]); + self.render_pass + .set_bind_group(1, self.postprocess_locals, &[]); + self.render_pass.set_vertex_buffer(0, &model.vbuf, 0, 0); + self.render_pass.draw(verts, 0..1); + } +}*/ + +pub struct ThirdPassDrawer<'a> { + render_pass: wgpu::RenderPass<'a>, + renderer: &'a Renderer, + //postprocess_locals: &'a wgpu::BindGroup, +} + +impl<'a> ThirdPassDrawer<'a> { + pub fn draw_post_process<'b: 'a>( + &mut self, + model: &'b Model, + verts: Range, + ) { + self.render_pass + .set_pipeline(&self.renderer.postprocess_pipeline.pipeline); + //self.render_pass + // .set_bind_group(1, self.postprocess_locals, &[]); + self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); + self.render_pass.draw(verts, 0..1); + } + + pub fn draw_ui<'c>(&'c mut self) -> UiDrawer<'c, 'a> { + self.render_pass + .set_pipeline(&self.renderer.ui_pipeline.pipeline); + + UiDrawer { + render_pass: &mut self.render_pass, + } + } +} + +pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> { + /// Set vertex buffer, initial scissor, and locals + /// These can be changed later but this ensures that they don't have to be + /// set with every draw call + pub fn prepare<'data: 'pass>( + &mut self, + locals: &'data ui::LocalsBindGroup, + //texture: &'b ui::TextureBindGroup, + buf: &'data DynamicModel, + scissor: Aabr, + ) -> PreparedUiDrawer<'_, 'pass> { + // Note: not actually prepared yet + // we do this to avoid having to write extra code for the set functions + let mut prepared = PreparedUiDrawer { + render_pass: self.render_pass, + }; + // Prepare + prepared.set_locals(locals); + //prepared.set_texture(texture); + prepared.set_model(buf); + prepared.set_scissor(scissor); + + prepared + } +} + +impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> { + pub fn set_locals<'data: 'pass>(&mut self, locals: &'data ui::LocalsBindGroup) { + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + } + + //pub fn set_texture<'b: 'a>(&mut self, texture: &'b ui::TextureBindGroup) { + // self.render_pass.set_bind_group(1, &texture.bind_group, &[]); + //} + + pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel) { + self.render_pass.set_vertex_buffer(0, model.buf().slice(..)) + } + + pub fn set_scissor<'data: 'pass>(&mut self, scissor: Aabr) { + let Aabr { min, max } = scissor; + //self.render_pass.set_scissor_rect( + // min.x as u32, + // min.y as u32, + // (max.x - min.x) as u32, + // (max.y - min.y) as u32, + //); + } + + pub fn draw<'data: 'pass>(&mut self, texture: &'data ui::TextureBindGroup, verts: Range) { + self.render_pass.set_bind_group(2, &texture.bind_group, &[]); + self.render_pass.draw(verts, 0..1); + } +} diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index 32296b33c6..2429695e7e 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -179,7 +179,7 @@ impl Texture { data: &[u8], ) { // Note: we only accept 4 bytes per pixel - // (enforce this is API?) + // (enforce this in API?) debug_assert_eq!(data.len(), size[0] as usize * size[1] as usize * 4); // TODO: Only works for 2D images queue.write_texture( diff --git a/voxygen/src/run.rs b/voxygen/src/run.rs index 25c847381f..099bc94128 100644 --- a/voxygen/src/run.rs +++ b/voxygen/src/run.rs @@ -176,7 +176,7 @@ fn handle_main_events_cleared( last.render(renderer, &global_state.settings); // Finish the frame. // TODO: do this as part of dropping rendering thing - global_state.window.renderer_mut().flush().unwrap(); + //global_state.window.renderer_mut().flush().unwrap(); // // Display the frame on the window. // global_state // .window diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 6d5902a34a..6b81d8d281 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -8,13 +8,13 @@ use crate::{ ecs::comp::Interpolated, render::{ pipelines, ColLightInfo, Consts, FigureBoneData, FigureLocals, FigureModel, GlobalModel, - Mesh, RenderError, Renderer, SubModel, TerrainVertex, Texture, + LodData, Mesh, RenderError, Renderer, SubModel, TerrainVertex, Texture, }, scene::{ camera::{Camera, CameraMode, Dependents}, math, terrain::Terrain, - LodData, SceneData, + SceneData, }, }; use anim::{ @@ -5352,8 +5352,8 @@ impl FigureState { let bone_consts = figure_bone_data_from_anim(&buf); Self { meta: FigureStateMeta { - bone_consts: renderer.create_consts(bone_consts).unwrap(), - locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(), + bone_consts: renderer.create_consts(bone_consts), + locals: renderer.create_consts(&[FigureLocals::default()]), lantern_offset, state_time: 0.0, last_ori: Ori::default().into(), diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index ba355df112..c8f2b0e35f 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -17,8 +17,8 @@ use crate::{ audio::{ambient::AmbientMgr, music::MusicMgr, sfx::SfxMgr, AudioFrontend}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, CloudsLocals, CloudsVertex, Consts, - GlobalModel, Globals, Light, LodData, Model, PostProcessLocals, PostProcessVertex, - Renderer, Shadow, ShadowLocals, SkyboxVertex, + GlobalModel, Globals, Light, Model, PostProcessLocals, PostProcessVertex, Renderer, Shadow, + ShadowLocals, SkyboxVertex, }, settings::Settings, window::{AnalogGameInput, Event}, @@ -277,16 +277,11 @@ impl Scene { Self { data: GlobalModel { - globals: renderer.create_consts(&[Globals::default()]).unwrap(), - lights: renderer - .create_consts(&[Light::default(); MAX_LIGHT_COUNT]) - .unwrap(), - shadows: renderer - .create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]) - .unwrap(), + globals: renderer.create_consts(&[Globals::default()]), + lights: renderer.create_consts(&[Light::default(); MAX_LIGHT_COUNT]), + shadows: renderer.create_consts(&[Shadow::default(); MAX_SHADOW_COUNT]), shadow_mats: renderer - .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6]) - .unwrap(), + .create_consts(&[ShadowLocals::default(); MAX_LIGHT_COUNT * 6 + 6]), }, camera: Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson), camera_input_state: Vec2::zero(), @@ -297,13 +292,11 @@ impl Scene { }, clouds: Clouds { model: renderer.create_model(&create_clouds_mesh()).unwrap(), - locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(), + locals: renderer.create_consts(&[CloudsLocals::default()]), }, postprocess: PostProcess { model: renderer.create_model(&create_pp_mesh()).unwrap(), - locals: renderer - .create_consts(&[PostProcessLocals::default()]) - .unwrap(), + locals: renderer.create_consts(&[PostProcessLocals::default()]), }, terrain: Terrain::new(renderer, sprite_render_context), lod: Lod::new(renderer, client, settings), diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 7e30da8658..eae83c42d9 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -2,14 +2,13 @@ use crate::{ mesh::{greedy::GreedyMesh, segment::generate_mesh_base_vol_terrain}, render::{ create_clouds_mesh, create_pp_mesh, create_skybox_mesh, BoneMeshes, CloudsLocals, - CloudsVertex, Consts, FigureModel, GlobalModel, Globals, Light, Mesh, Model, + CloudsVertex, Consts, FigureModel, GlobalModel, Globals, Light, LodData, Mesh, Model, PostProcessLocals, PostProcessVertex, Renderer, Shadow, ShadowLocals, SkyboxVertex, TerrainVertex, }, scene::{ camera::{self, Camera, CameraMode}, figure::{load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState}, - LodData, }, window::{Event, PressState}, }; @@ -110,10 +109,6 @@ impl Scene { client.world_data().min_chunk_alt(), client.world_data().max_chunk_alt(), ); - let map_border = [0.0, 0.0, 0.0, 0.0]; - let map_image = [0]; - let alt_image = [0]; - let horizon_image = [0x_00_01_00_01]; let mut camera = Camera::new(resolution.x / resolution.y, CameraMode::ThirdPerson); camera.set_focus_pos(Vec3::unit_z() * 1.5); @@ -124,12 +119,10 @@ impl Scene { Self { data: GlobalModel { - globals: renderer.create_consts(&[Globals::default()]).unwrap(), - lights: renderer.create_consts(&[Light::default(); 32]).unwrap(), - shadows: renderer.create_consts(&[Shadow::default(); 32]).unwrap(), - shadow_mats: renderer - .create_consts(&[ShadowLocals::default(); 6]) - .unwrap(), + globals: renderer.create_consts(&[Globals::default()]), + lights: renderer.create_consts(&[Light::default(); 32]), + shadows: renderer.create_consts(&[Shadow::default(); 32]), + shadow_mats: renderer.create_consts(&[ShadowLocals::default(); 6]), }, skybox: Skybox { @@ -137,23 +130,13 @@ impl Scene { }, clouds: Clouds { model: renderer.create_model(&create_clouds_mesh()).unwrap(), - locals: renderer.create_consts(&[CloudsLocals::default()]).unwrap(), + locals: renderer.create_consts(&[CloudsLocals::default()]), }, postprocess: PostProcess { model: renderer.create_model(&create_pp_mesh()).unwrap(), - locals: renderer - .create_consts(&[PostProcessLocals::default()]) - .unwrap(), + locals: renderer.create_consts(&[PostProcessLocals::default()]), }, - lod: LodData::new( - renderer, - Vec2::new(1, 1), - &map_image, - &alt_image, - &horizon_image, - 1, - //map_border.into(), - ), + lod: LodData::dummy(renderer), map_bounds, figure_model_cache: FigureModelCache::new(), diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 02b367a119..075ff21c12 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -8,13 +8,13 @@ use crate::{ terrain::{generate_mesh, SUNLIGHT}, }, render::{ - pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, Mesh, Model, + pipelines, ColLightInfo, Consts, FluidVertex, GlobalModel, Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals, SpriteVertex, TerrainLocals, TerrainVertex, Texture, }, }; -use super::{math, LodData, SceneData}; +use super::{math, SceneData}; use common::{ assets::{self, AssetExt, DotVoxAsset}, figure::Segment, @@ -517,9 +517,7 @@ impl SpriteRenderContext { offset, }| { SpriteData { - locals: renderer - .create_consts(&locals) - .expect("Failed to upload sprite locals to the GPU!"), + locals: renderer.create_consts(&locals_buffer), model: renderer.create_model(&model).expect( "Failed to upload sprite model data to the GPU!", ), @@ -1161,24 +1159,22 @@ impl Terrain { light_map: mesh.light_map, glow_map: mesh.glow_map, sprite_instances, - locals: renderer - .create_consts(&[TerrainLocals { - model_offs: Vec3::from( - response.pos.map2(VolGrid2d::::chunk_size(), |e, sz| { - e as f32 * sz as f32 - }), - ) - .into_array(), - atlas_offs: Vec4::new( - atlas_offs.x as i32, - atlas_offs.y as i32, - 0, - 0, - ) - .into_array(), - load_time, - }]) - .expect("Failed to upload chunk locals to the GPU!"), + locals: renderer.create_consts(&[TerrainLocals { + model_offs: Vec3::from( + response.pos.map2(VolGrid2d::::chunk_size(), |e, sz| { + e as f32 * sz as f32 + }), + ) + .into_array(), + atlas_offs: Vec4::new( + atlas_offs.x as i32, + atlas_offs.y as i32, + 0, + 0, + ) + .into_array(), + load_time, + }]), visible: Visibility { in_range: false, in_frustum: false, diff --git a/voxygen/src/ui/graphic/mod.rs b/voxygen/src/ui/graphic/mod.rs index 461e7b8e87..ac0244d31d 100644 --- a/voxygen/src/ui/graphic/mod.rs +++ b/voxygen/src/ui/graphic/mod.rs @@ -3,7 +3,7 @@ mod renderer; pub use renderer::{SampleStrat, Transform}; -use crate::render::{Renderer, Texture}; +use crate::render::{Renderer, Texture, UiTextureBindGroup}; use common::figure::Segment; use guillotiere::{size2, SimpleAtlasAllocator}; use hashbrown::{hash_map::Entry, HashMap}; @@ -139,7 +139,7 @@ pub struct GraphicCache { // Atlases with the index of their texture in the textures vec atlases: Vec<(SimpleAtlasAllocator, usize)>, - textures: Vec, + textures: Vec<(Texture, UiTextureBindGroup)>, // Stores the location of graphics rendered at a particular resolution and cached on the cpu cache_map: HashMap, } @@ -184,7 +184,7 @@ impl GraphicCache { pub fn get_graphic(&self, id: Id) -> Option<&Graphic> { self.graphic_map.get(&id) } /// Used to acquire textures for rendering - pub fn get_tex(&self, id: TexId) -> &Texture { + pub fn get_tex(&self, id: TexId) -> &(Texture, UiTextureBindGroup) { self.textures.get(id.0).expect("Invalid TexId used") } @@ -284,7 +284,7 @@ impl GraphicCache { // color. assert!(border.is_none()); // Transfer to the gpu - upload_image(renderer, aabr, &textures[idx], &image); + upload_image(renderer, aabr, &textures[idx].0, &image); } return Some((transformed_aabr(aabr.map(|e| e as f64)), TexId(idx))); @@ -324,7 +324,7 @@ impl GraphicCache { valid: true, aabr, }); - upload_image(renderer, aabr, &textures[texture_idx], &image); + upload_image(renderer, aabr, &textures[texture_idx].0, &image); break; } } @@ -344,7 +344,7 @@ impl GraphicCache { let atlas_idx = atlases.len(); textures.push(texture); atlases.push((atlas, tex_idx)); - upload_image(renderer, aabr, &textures[tex_idx], &image); + upload_image(renderer, aabr, &textures[tex_idx].0, &image); CachedDetails::Atlas { atlas_idx, valid: true, @@ -354,7 +354,11 @@ impl GraphicCache { } } else { // Create a texture just for this - let texture = renderer.create_dynamic_texture(dims.map(|e| e as u32)); + let texture = { + let tex = renderer.create_dynamic_texture(dims.map(|e| e as u32)); + let bind = renderer.ui_bind_texture(&tex); + (tex, bind) + }; // NOTE: All mutations happen only after the texture creation succeeds! let index = textures.len(); textures.push(texture); @@ -365,7 +369,7 @@ impl GraphicCache { // Note texture should always match the cached dimensions max: dims, }, - &textures[index], + &textures[index].0, &image, ); CachedDetails::Texture { index, valid: true } @@ -419,11 +423,18 @@ fn atlas_size(renderer: &Renderer) -> Vec2 { }) } -fn create_atlas_texture(renderer: &mut Renderer) -> (SimpleAtlasAllocator, Texture) { +fn create_atlas_texture( + renderer: &mut Renderer, +) -> (SimpleAtlasAllocator, (Texture, UiTextureBindGroup)) { let size = atlas_size(renderer); // Note: here we assume the atlas size is under i32::MAX let atlas = SimpleAtlasAllocator::new(size2(size.x as i32, size.y as i32)); - let texture = renderer.create_dynamic_texture(size); + let texture = { + let tex = renderer.create_dynamic_texture(size); + let bind = renderer.ui_bind_texture(&tex); + (tex, bind) + }; + (atlas, texture) } @@ -449,8 +460,12 @@ fn upload_image(renderer: &mut Renderer, aabr: Aabr, tex: &Texture, image: ); } -fn create_image(renderer: &mut Renderer, image: RgbaImage, border_color: Rgba) -> Texture { - renderer +fn create_image( + renderer: &mut Renderer, + image: RgbaImage, + border_color: Rgba, +) -> (Texture, UiTextureBindGroup) { + let tex = renderer .create_texture( &DynamicImage::ImageRgba8(image), None, @@ -458,5 +473,8 @@ fn create_image(renderer: &mut Renderer, image: RgbaImage, border_color: Rgba, - glyph_cache_tex: Texture, + glyph_cache_tex: (Texture, UiTextureBindGroup), graphic_cache: GraphicCache, } @@ -66,16 +66,22 @@ impl Cache { .draw_cache_position_tolerance(POSITION_TOLERANCE) .build(); + let glyph_cache_tex = { + let tex = renderer.create_dynamic_texture(glyph_cache_dims); + let bind = renderer.ui_bind_texture(&tex); + (tex, bind) + }; + Ok(Self { glyph_brush: RefCell::new(glyph_brush), - glyph_cache_tex: renderer.create_dynamic_texture(glyph_cache_dims), + glyph_cache_tex, graphic_cache: GraphicCache::new(renderer), }) } - pub fn glyph_cache_tex(&self) -> &Texture { &self.glyph_cache_tex } + pub fn glyph_cache_tex(&self) -> &(Texture, UiTextureBindGroup) { &self.glyph_cache_tex } - pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &Texture) { + pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphBrush, &(Texture, UiTextureBindGroup)) { (self.glyph_brush.get_mut(), &self.glyph_cache_tex) } @@ -117,6 +123,7 @@ impl Cache { self.graphic_cache.replace_graphic(id, graphic) } + // TODO: combine resize functions // Resizes and clears the GraphicCache pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) { self.graphic_cache.clear_cache(renderer); @@ -134,7 +141,12 @@ impl Cache { .initial_cache_size((cache_dims.x, cache_dims.y)) .build(); - self.glyph_cache_tex = renderer.create_dynamic_texture(cache_dims); + self.glyph_cache_tex = { + let tex = renderer.create_dynamic_texture(cache_dims); + let bind = renderer.ui_bind_texture(&tex); + (tex, bind) + }; + Ok(()) } } diff --git a/voxygen/src/ui/ice/mod.rs b/voxygen/src/ui/ice/mod.rs index ea90a6048a..35adf48416 100644 --- a/voxygen/src/ui/ice/mod.rs +++ b/voxygen/src/ui/ice/mod.rs @@ -14,7 +14,11 @@ use super::{ graphic::{self, Graphic}, scale::{Scale, ScaleMode}, }; -use crate::{render::Renderer, window::Window, Error}; +use crate::{ + render::{Renderer, UiDrawer}, + window::Window, + Error, +}; use common_base::span; use iced::{mouse, Cache, Size, UserInterface}; use iced_winit::Clipboard; @@ -212,5 +216,5 @@ impl IcedUi { (messages, mouse_interaction) } - pub fn render(&self, renderer: &mut Renderer) { self.renderer.render(renderer, None); } + pub fn render<'a>(&'a self, drawer: &mut UiDrawer<'_, 'a>) { self.renderer.render(drawer); } } diff --git a/voxygen/src/ui/ice/renderer/mod.rs b/voxygen/src/ui/ice/renderer/mod.rs index b3b0447c9a..c41c8ad67f 100644 --- a/voxygen/src/ui/ice/renderer/mod.rs +++ b/voxygen/src/ui/ice/renderer/mod.rs @@ -15,8 +15,8 @@ use super::{ }; use crate::{ render::{ - create_ui_quad, create_ui_quad_vert_gradient, Consts, DynamicModel, Globals, Mesh, - Renderer, UiLocals, UiMode, UiVertex, + create_ui_quad, create_ui_quad_vert_gradient, Consts, DynamicModel, Mesh, Renderer, + UiDrawer, UiLocals, UiLocalsBindGroup, UiMode, UiVertex, }, Error, }; @@ -85,10 +85,10 @@ pub struct IcedRenderer { // Model for drawing the ui model: DynamicModel, // Consts to specify positions of ingame elements (e.g. Nametags) - ingame_locals: Vec>, + ingame_locals: Vec<(Consts, UiLocalsBindGroup)>, // Consts for default ui drawing position (ie the interface) - interface_locals: Consts, - default_globals: Consts, + interface_locals: (Consts, UiLocalsBindGroup), + //default_globals: Consts, // Used to delay cache resizing until after current frame is drawn //need_cache_resize: bool, @@ -125,12 +125,18 @@ impl IcedRenderer { let (half_res, align, p_scale) = Self::calculate_resolution_dependents(physical_resolution, scaled_resolution); + let interface_locals = { + let locals = renderer.create_consts(&[UiLocals::default()]); + let bind = renderer.ui_bind_locals(&locals); + (locals, bind) + }; + Ok(Self { cache: Cache::new(renderer, default_font)?, draw_commands: Vec::new(), model: renderer.create_dynamic_model(100), - interface_locals: renderer.create_consts(&[UiLocals::default()])?, - default_globals: renderer.create_consts(&[Globals::default()])?, + interface_locals, + //default_globals: renderer.create_consts(&[Globals::default()]), ingame_locals: Vec::new(), mesh: Mesh::new(), glyphs: Vec::new(), @@ -222,7 +228,7 @@ impl IcedRenderer { .push(DrawCommand::plain(self.start..self.mesh.vertices().len()));*/ // Fill in placeholder glyph quads - let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex(); + let (glyph_cache, (cache_tex, _)) = self.cache.glyph_cache_mut_and_tex(); let half_res = self.half_res; let brush_result = glyph_cache.process_queued( @@ -542,6 +548,7 @@ impl IcedRenderer { Some((aabr, tex_id)) => { let cache_dims = graphic_cache .get_tex(tex_id) + .0 .get_dimensions() .xy() .map(|e| e as f32); @@ -763,28 +770,32 @@ impl IcedRenderer { } } - pub fn render(&self, renderer: &mut Renderer, maybe_globals: Option<&Consts>) { + pub fn render<'pass_ref, 'pass: 'pass_ref, 'data: 'pass>( + &'data self, + drawer: &mut UiDrawer<'pass_ref, 'pass>, /* maybe_globals: Option<&Consts> */ + ) { span!(_guard, "render", "IcedRenderer::render"); - let mut scissor = self.window_scissor; - let globals = maybe_globals.unwrap_or(&self.default_globals); - let mut locals = &self.interface_locals; + let mut drawer = drawer.prepare(&self.interface_locals.1, &self.model, self.window_scissor); + //let mut scissor = self.window_scissor; + //let globals = maybe_globals.unwrap_or(&self.default_globals); + //let mut locals = &self.interface_locals.1; for draw_command in self.draw_commands.iter() { match draw_command { DrawCommand::Scissor(new_scissor) => { - scissor = *new_scissor; + drawer.set_scissor(*new_scissor); }, DrawCommand::WorldPos(index) => { - locals = index.map_or(&self.interface_locals, |i| &self.ingame_locals[i]); + drawer.set_locals( + index.map_or(&self.interface_locals.1, |i| &self.ingame_locals[i].1), + ); }, DrawCommand::Draw { kind, verts } => { + // TODO: don't make these assert!(!verts.is_empty()); let tex = match kind { DrawKind::Image(tex_id) => self.cache.graphic_cache().get_tex(*tex_id), DrawKind::Plain => self.cache.glyph_cache_tex(), }; - let model = self.model.submodel(verts.clone()); - // TODO - //renderer.render_ui_element(model, tex, scissor, globals, - // locals); + drawer.draw(&tex.1, verts.clone()); // Note: trivial clone }, } } diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index aece4088fe..c97e6f5661 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -163,8 +163,8 @@ impl Ui { draw_commands: Vec::new(), mesh: Mesh::new(), model: renderer.create_dynamic_model(100), - interface_locals: renderer.create_consts(&[UiLocals::default()])?, - default_globals: renderer.create_consts(&[Globals::default()])?, + interface_locals: renderer.create_consts(&[UiLocals::default()]), + default_globals: renderer.create_consts(&[Globals::default()]), ingame_locals: Vec::new(), window_resized: None, scale_factor_changed: None, @@ -812,6 +812,7 @@ impl Ui { Some((aabr, tex_id)) => { let cache_dims = graphic_cache .get_tex(tex_id) + .0 .get_dimensions() .xy() .map(|e| e as f32); @@ -953,7 +954,7 @@ impl Ui { ) } else { self.ingame_locals - .push(renderer.create_consts(&[world_pos.into()]).unwrap()); + .push(renderer.create_consts(&[world_pos.into()])); } self.draw_commands .push(DrawCommand::WorldPos(Some(ingame_local_index))); @@ -1019,11 +1020,12 @@ impl Ui { locals = index.map_or(&self.interface_locals, |i| &self.ingame_locals[i]); }, DrawCommand::Draw { kind, verts } => { - let tex = match kind { - DrawKind::Image(tex_id) => self.cache.graphic_cache().get_tex(*tex_id), - DrawKind::Plain => self.cache.glyph_cache_tex(), - }; - let model = self.model.submodel(verts.clone()); + //let tex = match kind { + // DrawKind::Image(tex_id) => + // self.cache.graphic_cache().get_tex(*tex_id), + // DrawKind::Plain => self.cache.glyph_cache_tex(), + //}; + //let model = self.model.submodel(verts.clone()); // TODO //renderer.render_ui_element(model, tex, scissor, globals, // locals);