Implement toggleable gpu profiling that saves the timings from a recent frame with the screenshot key, rebase fixes

This commit is contained in:
Imbris 2021-02-27 04:21:23 -05:00 committed by Avi Weinstock
parent 5cdce0635d
commit d2e2580df4
15 changed files with 1134 additions and 790 deletions

544
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -110,3 +110,5 @@ nativeBuildInputs = ["pkg-config"]
# macos CI fix isn't merged yet # macos CI fix isn't merged yet
winit = { git = "https://gitlab.com/veloren/winit.git", branch = "macos-test-spiffed" } winit = { git = "https://gitlab.com/veloren/winit.git", branch = "macos-test-spiffed" }
vek = { git = "https://gitlab.com/veloren/vek.git", branch = "fix_intrinsics2" } vek = { git = "https://gitlab.com/veloren/vek.git", branch = "fix_intrinsics2" }
# patch wgpu so we can use wgpu-profiler crate
wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "1f1a7e5dd47a1610733bbc3989414acb62395359" }

View File

@ -46,6 +46,7 @@ i18n = {package = "veloren-i18n", path = "i18n"}
# Graphics # Graphics
winit = {version = "0.24.0", features = ["serde"]} winit = {version = "0.24.0", features = ["serde"]}
wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "1f1a7e5dd47a1610733bbc3989414acb62395359" } wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "1f1a7e5dd47a1610733bbc3989414acb62395359" }
wgpu-profiler = "0.2.1"
bytemuck = { version="1.4", features=["derive"] } bytemuck = { version="1.4", features=["derive"] }
shaderc = "0.6.2" shaderc = "0.6.2"
@ -95,8 +96,7 @@ rand = "0.8"
rodio = {version = "0.13", default-features = false, features = ["vorbis"]} rodio = {version = "0.13", default-features = false, features = ["vorbis"]}
ron = {version = "0.6", default-features = false} ron = {version = "0.6", default-features = false}
serde = {version = "1.0", features = [ "rc", "derive" ]} serde = {version = "1.0", features = [ "rc", "derive" ]}
# strum = "0.20" strum = "0.20"
strum = { version = "0.20.0", features = ["derive"] }
strum_macros = "0.20" strum_macros = "0.20"
treeculler = "0.2" treeculler = "0.2"
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }

View File

@ -82,6 +82,9 @@ widget_ids! {
refresh_rate, refresh_rate,
refresh_rate_label, refresh_rate_label,
// //
gpu_profiler_button,
gpu_profiler_label,
//
particles_button, particles_button,
particles_label, particles_label,
lossy_terrain_compression_button, lossy_terrain_compression_button,
@ -902,11 +905,37 @@ impl<'a> Widget for Video<'a> {
.set(state.ids.shadow_mode_map_resolution_value, ui); .set(state.ids.shadow_mode_map_resolution_value, ui);
} }
// GPU Profiler
Text::new(&self.localized_strings.get("hud.settings.gpu_profiler"))
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.down_from(state.ids.shadow_mode_list, 8.0)
.color(TEXT_COLOR)
.set(state.ids.gpu_profiler_label, ui);
let gpu_profiler_enabled = ToggleButton::new(
render_mode.profiler_enabled,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.right_from(state.ids.gpu_profiler_label, 10.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.gpu_profiler_button, ui);
if render_mode.profiler_enabled != gpu_profiler_enabled {
events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
profiler_enabled: gpu_profiler_enabled,
..render_mode.clone()
})));
}
// Particles // Particles
Text::new(&self.localized_strings.get("hud.settings.particles")) Text::new(&self.localized_strings.get("hud.settings.particles"))
.font_size(self.fonts.cyri.scale(14)) .font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id) .font_id(self.fonts.cyri.conrod_id)
.down_from(state.ids.shadow_mode_list, 8.0) .down_from(state.ids.gpu_profiler_label, 8.0)
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.particles_label, ui); .set(state.ids.particles_label, ui);

View File

@ -8,7 +8,8 @@
const_generics, const_generics,
drain_filter, drain_filter,
once_cell, once_cell,
trait_alias trait_alias,
or_patterns
)] )]
#![recursion_limit = "2048"] #![recursion_limit = "2048"]

View File

@ -8,8 +8,8 @@ pub mod mesh;
pub mod model; pub mod model;
pub mod pipelines; pub mod pipelines;
pub mod renderer; pub mod renderer;
mod scope;
pub mod texture; pub mod texture;
mod time;
// Reexports // Reexports
pub use self::{ pub use self::{
@ -271,4 +271,5 @@ pub struct RenderMode {
pub shadow: ShadowMode, pub shadow: ShadowMode,
pub upscale_mode: UpscaleMode, pub upscale_mode: UpscaleMode,
pub present_mode: PresentMode, pub present_mode: PresentMode,
pub profiler_enabled: bool,
} }

View File

@ -1,6 +1,13 @@
mod binding; mod binding;
pub(super) mod drawer; pub(super) mod drawer;
mod spans; // Consts and bind groups for post-process and clouds
mod locals;
mod shaders;
mod shadow_map;
use locals::Locals;
use shaders::Shaders;
use shadow_map::{ShadowMap, ShadowMapRenderer};
use super::{ use super::{
consts::Consts, consts::Consts,
@ -18,141 +25,15 @@ use super::{
use common::assets::{self, AssetExt, AssetHandle}; use common::assets::{self, AssetExt, AssetHandle};
use common_base::span; use common_base::span;
use core::convert::TryFrom; use core::convert::TryFrom;
use hashbrown::HashMap;
use tracing::{error, info, warn}; use tracing::{error, info, warn};
use vek::*; use vek::*;
// TODO: yeet this somewhere else
/// A type representing data that can be converted to an immutable texture map /// A type representing data that can be converted to an immutable texture map
/// of ColLight data (used for texture atlases created during greedy meshing). /// of ColLight data (used for texture atlases created during greedy meshing).
// TODO: revert to u16 // TODO: revert to u16
pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u32>); pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u32>);
/// Load from a GLSL file.
pub struct Glsl(String);
impl From<String> for Glsl {
fn from(s: String) -> Glsl { Glsl(s) }
}
impl assets::Asset for Glsl {
type Loader = assets::LoadFrom<String, assets::StringLoader>;
const EXTENSION: &'static str = "glsl";
}
struct Shaders {
shaders: HashMap<String, AssetHandle<Glsl>>,
}
impl assets::Compound for Shaders {
// TODO: Taking the specifier argument as a base for shaders specifiers
// would allow to use several shaders groups easily
fn load<S: assets::source::Source>(
_: &assets::AssetCache<S>,
_: &str,
) -> Result<Shaders, assets::Error> {
let shaders = [
"include.constants",
"include.globals",
"include.sky",
"include.light",
"include.srgb",
"include.random",
"include.lod",
"include.shadows",
"antialias.none",
"antialias.fxaa",
"antialias.msaa-x4",
"antialias.msaa-x8",
"antialias.msaa-x16",
"include.cloud.none",
"include.cloud.regular",
"figure-vert",
"light-shadows-figure-vert",
"light-shadows-directed-vert",
"light-shadows-directed-frag",
"point-light-shadows-vert",
"skybox-vert",
"skybox-frag",
"figure-frag",
"terrain-vert",
"terrain-frag",
"fluid-vert",
"fluid-frag.cheap",
"fluid-frag.shiny",
"sprite-vert",
"sprite-frag",
"particle-vert",
"particle-frag",
"ui-vert",
"ui-frag",
"lod-terrain-vert",
"lod-terrain-frag",
"clouds-vert",
"clouds-frag",
"postprocess-vert",
"postprocess-frag",
"player-shadow-frag",
"light-shadows-geom",
"light-shadows-frag",
];
let shaders = shaders
.iter()
.map(|shader| {
let full_specifier = ["voxygen.shaders.", shader].concat();
let asset = AssetExt::load(&full_specifier)?;
Ok((String::from(*shader), asset))
})
.collect::<Result<HashMap<_, _>, assets::Error>>()?;
Ok(Self { shaders })
}
}
impl Shaders {
fn get(&self, shader: &str) -> Option<impl std::ops::Deref<Target = Glsl>> {
self.shaders.get(shader).map(|a| a.read())
}
}
/// A type that holds shadow map data. Since shadow mapping may not be
/// supported on all platforms, we try to keep it separate.
struct ShadowMapRenderer {
// directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
// point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
directed_depth: Texture,
point_depth: Texture,
point_pipeline: shadow::PointShadowPipeline,
terrain_directed_pipeline: shadow::ShadowPipeline,
figure_directed_pipeline: shadow::ShadowFigurePipeline,
layout: shadow::ShadowLayout,
}
enum ShadowMap {
Enabled(ShadowMapRenderer),
Disabled {
dummy_point: Texture, // Cube texture
dummy_directed: Texture,
},
}
impl ShadowMap {
fn textures(&self) -> (&Texture, &Texture) {
match self {
Self::Enabled(renderer) => (&renderer.point_depth, &renderer.directed_depth),
Self::Disabled {
dummy_point,
dummy_directed,
} => (dummy_point, dummy_directed),
}
}
fn is_enabled(&self) -> bool { matches!(self, Self::Enabled(_)) }
}
/// A type that stores all the layouts associated with this renderer. /// A type that stores all the layouts associated with this renderer.
struct Layouts { struct Layouts {
global: GlobalsLayouts, global: GlobalsLayouts,
@ -167,72 +48,37 @@ struct Layouts {
ui: ui::UiLayout, ui: ui::UiLayout,
} }
struct Locals { /// A type that stores all the pipelines associated with this renderer.
clouds: Consts<clouds::Locals>, struct Pipelines {
clouds_bind: clouds::BindGroup, figure: figure::FigurePipeline,
fluid: fluid::FluidPipeline,
postprocess: Consts<postprocess::Locals>, lod_terrain: lod_terrain::LodTerrainPipeline,
postprocess_bind: postprocess::BindGroup, particle: particle::ParticlePipeline,
clouds: clouds::CloudsPipeline,
postprocess: postprocess::PostProcessPipeline,
// Consider reenabling at some time
// player_shadow: figure::FigurePipeline,
skybox: skybox::SkyboxPipeline,
sprite: sprite::SpritePipeline,
terrain: terrain::TerrainPipeline,
ui: ui::UiPipeline,
} }
impl Locals { /// Render target views
fn new( struct Views {
device: &wgpu::Device, // NOTE: unused for now
layouts: &Layouts, win_depth: wgpu::TextureView,
clouds_locals: Consts<clouds::Locals>,
postprocess_locals: Consts<postprocess::Locals>,
tgt_color_view: &wgpu::TextureView,
tgt_depth_view: &wgpu::TextureView,
tgt_color_pp_view: &wgpu::TextureView,
sampler: &wgpu::Sampler,
depth_sampler: &wgpu::Sampler,
) -> Self {
let clouds_bind = layouts.clouds.bind(
device,
tgt_color_view,
tgt_depth_view,
sampler,
depth_sampler,
&clouds_locals,
);
let postprocess_bind =
layouts
.postprocess
.bind(device, tgt_color_pp_view, sampler, &postprocess_locals);
Self { tgt_color: wgpu::TextureView,
clouds: clouds_locals, tgt_depth: wgpu::TextureView,
clouds_bind, // TODO: rename
postprocess: postprocess_locals, tgt_color_pp: wgpu::TextureView,
postprocess_bind,
}
} }
fn rebind( /// Shadow rendering textures, layouts, pipelines, and bind groups
&mut self, struct Shadow {
device: &wgpu::Device, map: ShadowMap,
layouts: &Layouts, bind: ShadowTexturesBindGroup,
// Call when these are recreated and need to be rebound
// e.g. resizing
tgt_color_view: &wgpu::TextureView,
tgt_depth_view: &wgpu::TextureView,
tgt_color_pp_view: &wgpu::TextureView,
sampler: &wgpu::Sampler,
depth_sampler: &wgpu::Sampler,
) {
self.clouds_bind = layouts.clouds.bind(
device,
tgt_color_view,
tgt_depth_view,
sampler,
depth_sampler,
&self.clouds,
);
self.postprocess_bind =
layouts
.postprocess
.bind(device, tgt_color_pp_view, sampler, &self.postprocess);
}
} }
/// A type that encapsulates rendering state. `Renderer` is central to Voxygen's /// A type that encapsulates rendering state. `Renderer` is central to Voxygen's
@ -242,51 +88,28 @@ impl Locals {
pub struct Renderer { pub struct Renderer {
device: wgpu::Device, device: wgpu::Device,
queue: wgpu::Queue, queue: wgpu::Queue,
surface: wgpu::Surface,
swap_chain: wgpu::SwapChain, swap_chain: wgpu::SwapChain,
sc_desc: wgpu::SwapChainDescriptor, sc_desc: wgpu::SwapChainDescriptor,
surface: wgpu::Surface,
win_depth_view: wgpu::TextureView,
tgt_color_view: wgpu::TextureView,
tgt_depth_view: wgpu::TextureView,
// TODO: rename
tgt_color_pp_view: wgpu::TextureView,
sampler: wgpu::Sampler, sampler: wgpu::Sampler,
depth_sampler: wgpu::Sampler, depth_sampler: wgpu::Sampler,
shadow_map: ShadowMap,
shadow_bind: ShadowTexturesBindGroup,
layouts: Layouts, layouts: Layouts,
pipelines: Pipelines,
figure_pipeline: figure::FigurePipeline, shadow: Shadow,
fluid_pipeline: fluid::FluidPipeline,
lod_terrain_pipeline: lod_terrain::LodTerrainPipeline,
particle_pipeline: particle::ParticlePipeline,
clouds_pipeline: clouds::CloudsPipeline,
postprocess_pipeline: postprocess::PostProcessPipeline,
// Consider reenabling at some time
// player_shadow_pipeline: figure::FigurePipeline,
skybox_pipeline: skybox::SkyboxPipeline,
sprite_pipeline: sprite::SpritePipeline,
terrain_pipeline: terrain::TerrainPipeline,
ui_pipeline: ui::UiPipeline,
shaders: AssetHandle<Shaders>,
// Note: we keep these here since their bind groups need to be updated if we resize the // Note: we keep these here since their bind groups need to be updated if we resize the
// color/depth textures // color/depth textures
locals: Locals, locals: Locals,
views: Views,
noise_tex: Texture, noise_tex: Texture,
mode: RenderMode, shaders: AssetHandle<Shaders>,
mode: RenderMode,
resolution: Vec2<u32>, resolution: Vec2<u32>,
tracer: super::time::GpuTracer<spans::Id>, profiler: wgpu_profiler::GpuProfiler,
} }
impl Renderer { impl Renderer {
@ -334,7 +157,10 @@ impl Renderer {
features: wgpu::Features::DEPTH_CLAMPING features: wgpu::Features::DEPTH_CLAMPING
| wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER | wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER
| wgpu::Features::PUSH_CONSTANTS | wgpu::Features::PUSH_CONSTANTS
| super::time::required_features(), // TODO: make optional based on enabling profiling
// NOTE: requires recreating the device/queue is this setting changes
// alternatively it could be a compile time feature toggle
| super::scope::required_features(),
limits, limits,
}, },
None, None,
@ -399,16 +225,7 @@ impl Renderer {
}; };
let ( let (
skybox_pipeline, pipelines,
figure_pipeline,
terrain_pipeline,
fluid_pipeline,
sprite_pipeline,
particle_pipeline,
ui_pipeline,
lod_terrain_pipeline,
clouds_pipeline,
postprocess_pipeline,
//player_shadow_pipeline, //player_shadow_pipeline,
point_shadow_pipeline, point_shadow_pipeline,
terrain_directed_shadow_pipeline, terrain_directed_shadow_pipeline,
@ -422,8 +239,7 @@ impl Renderer {
shadow_views.is_some(), shadow_views.is_some(),
)?; )?;
let (tgt_color_view, tgt_depth_view, tgt_color_pp_view, win_depth_view) = let views = Self::create_rt_views(&device, (dims.width, dims.height), &mode)?;
Self::create_rt_views(&device, (dims.width, dims.height), &mode)?;
let shadow_map = if let ( let shadow_map = if let (
Some(point_pipeline), Some(point_pipeline),
@ -467,6 +283,11 @@ impl Renderer {
.bind_shadow_textures(&device, point, directed) .bind_shadow_textures(&device, point, directed)
}; };
let shadow = Shadow {
map: shadow_map,
bind: shadow_bind,
};
let create_sampler = |filter| { let create_sampler = |filter| {
device.create_sampler(&wgpu::SamplerDescriptor { device.create_sampler(&wgpu::SamplerDescriptor {
label: None, label: None,
@ -502,78 +323,52 @@ impl Renderer {
&layouts, &layouts,
clouds_locals, clouds_locals,
postprocess_locals, postprocess_locals,
&tgt_color_view, &views.tgt_color,
&tgt_depth_view, &views.tgt_depth,
&tgt_color_pp_view, &views.tgt_color_pp,
&sampler, &sampler,
&depth_sampler, &depth_sampler,
); );
let tracer = let mut profiler = wgpu_profiler::GpuProfiler::new(4, queue.get_timestamp_period());
super::time::GpuTracer::new(&device, &queue, "voxygen_gpu_chrome_trace.json").unwrap(); profiler.enable_timer = mode.profiler_enabled;
profiler.enable_debug_marker = mode.profiler_enabled;
Ok(Self { Ok(Self {
device, device,
queue, queue,
surface,
swap_chain, swap_chain,
sc_desc, sc_desc,
surface,
win_depth_view, layouts,
pipelines,
tgt_color_view, shadow,
tgt_depth_view, locals,
tgt_color_pp_view, views,
sampler, sampler,
depth_sampler, depth_sampler,
shadow_map,
shadow_bind,
layouts,
skybox_pipeline,
figure_pipeline,
terrain_pipeline,
fluid_pipeline,
sprite_pipeline,
particle_pipeline,
ui_pipeline,
lod_terrain_pipeline,
clouds_pipeline,
postprocess_pipeline,
shaders,
//player_shadow_pipeline,
locals,
noise_tex, noise_tex,
mode, shaders,
mode,
resolution: Vec2::new(dims.width, dims.height), resolution: Vec2::new(dims.width, dims.height),
tracer, profiler,
}) })
} }
/// Get references to the internal render target views that get rendered to
/// before post-processing.
#[allow(dead_code)]
pub fn tgt_views(&self) -> (&wgpu::TextureView, &wgpu::TextureView) {
(&self.tgt_color_view, &self.tgt_depth_view)
}
/// Get references to the internal render target views that get displayed
/// directly by the window.
#[allow(dead_code)]
pub fn win_views(&self) -> &wgpu::TextureView { &self.win_depth_view }
/// Change the render mode. /// Change the render mode.
pub fn set_render_mode(&mut self, mode: RenderMode) -> Result<(), RenderError> { pub fn set_render_mode(&mut self, mode: RenderMode) -> Result<(), RenderError> {
self.mode = mode; self.mode = mode;
self.sc_desc.present_mode = self.mode.present_mode.into(); self.sc_desc.present_mode = self.mode.present_mode.into();
// Enable/disable profiler
self.profiler.enable_timer = self.mode.profiler_enabled;
self.profiler.enable_debug_marker = self.mode.profiler_enabled;
// Recreate render target // Recreate render target
self.on_resize(self.resolution)?; self.on_resize(self.resolution)?;
@ -597,31 +392,26 @@ impl Renderer {
self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc); self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc);
// Resize other render targets // Resize other render targets
let (tgt_color_view, tgt_depth_view, tgt_color_pp_view, win_depth_view) = self.views = Self::create_rt_views(&mut self.device, (dims.x, dims.y), &self.mode)?;
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_view = tgt_depth_view;
self.tgt_color_pp_view = tgt_color_pp_view;
// Rebind views to clouds/postprocess bind groups // Rebind views to clouds/postprocess bind groups
self.locals.rebind( self.locals.rebind(
&self.device, &self.device,
&self.layouts, &self.layouts,
&self.tgt_color_view, &self.views.tgt_color,
&self.tgt_depth_view, &self.views.tgt_depth,
&self.tgt_color_pp_view, &self.views.tgt_color_pp,
&self.sampler, &self.sampler,
&self.depth_sampler, &self.depth_sampler,
); );
if let (ShadowMap::Enabled(shadow_map), ShadowMode::Map(mode)) = if let (ShadowMap::Enabled(shadow_map), ShadowMode::Map(mode)) =
(&mut self.shadow_map, self.mode.shadow) (&mut self.shadow.map, self.mode.shadow)
{ {
match Self::create_shadow_views(&mut self.device, (dims.x, dims.y), &mode) { match Self::create_shadow_views(&mut self.device, (dims.x, dims.y), &mode) {
Ok((point_depth, directed_depth)) => { Ok((point_depth, directed_depth)) => {
shadow_map.point_depth = point_depth; shadow_map.point_depth = point_depth;
shadow_map.directed_depth = directed_depth; shadow_map.directed_depth = directed_depth;
self.shadow_bind = self.layouts.global.bind_shadow_textures( self.shadow.bind = self.layouts.global.bind_shadow_textures(
&self.device, &self.device,
&shadow_map.point_depth, &shadow_map.point_depth,
&shadow_map.directed_depth, &shadow_map.directed_depth,
@ -637,19 +427,12 @@ impl Renderer {
Ok(()) Ok(())
} }
/// Create render target views
fn create_rt_views( fn create_rt_views(
device: &wgpu::Device, device: &wgpu::Device,
size: (u32, u32), size: (u32, u32),
mode: &RenderMode, mode: &RenderMode,
) -> Result< ) -> Result<Views, RenderError> {
(
wgpu::TextureView,
wgpu::TextureView,
wgpu::TextureView,
wgpu::TextureView,
),
RenderError,
> {
let upscaled = Vec2::<u32>::from(size) let upscaled = Vec2::<u32>::from(size)
.map(|e| (e as f32 * mode.upscale_mode.factor) as u32) .map(|e| (e as f32 * mode.upscale_mode.factor) as u32)
.into_tuple(); .into_tuple();
@ -743,12 +526,12 @@ impl Renderer {
array_layer_count: None, array_layer_count: None,
}); });
Ok(( Ok(Views {
tgt_color_view, tgt_color: tgt_color_view,
tgt_depth_view, tgt_depth: tgt_depth_view,
tgt_color_pp_view, tgt_color_pp: tgt_color_pp_view,
win_depth_view, win_depth: win_depth_view,
)) })
} }
fn create_dummy_shadow_tex(device: &wgpu::Device, queue: &wgpu::Queue) -> (Texture, Texture) { fn create_dummy_shadow_tex(device: &wgpu::Device, queue: &wgpu::Queue) -> (Texture, Texture) {
@ -959,7 +742,7 @@ impl Renderer {
/// Get the resolution of the shadow render target. /// Get the resolution of the shadow render target.
pub fn get_shadow_resolution(&self) -> (Vec2<u32>, Vec2<u32>) { pub fn get_shadow_resolution(&self) -> (Vec2<u32>, Vec2<u32>) {
if let ShadowMap::Enabled(shadow_map) = &self.shadow_map { if let ShadowMap::Enabled(shadow_map) = &self.shadow.map {
( (
shadow_map.point_depth.get_dimensions().xy(), shadow_map.point_depth.get_dimensions().xy(),
shadow_map.directed_depth.get_dimensions().xy(), shadow_map.directed_depth.get_dimensions().xy(),
@ -993,7 +776,6 @@ impl Renderer {
/// there may be some GPUs that don't quite support it correctly, the /// there may be some GPUs that don't quite support it correctly, the
/// impact is relatively small, so there is no reason not to enable it where /// impact is relatively small, so there is no reason not to enable it where
/// available. /// available.
#[allow(unsafe_code)]
fn enable_seamless_cube_maps() { fn enable_seamless_cube_maps() {
todo!() todo!()
// unsafe { // unsafe {
@ -1072,34 +854,16 @@ impl Renderer {
&self.shaders.read(), &self.shaders.read(),
&self.mode, &self.mode,
&self.sc_desc, &self.sc_desc,
self.shadow_map.is_enabled(), self.shadow.map.is_enabled(),
) { ) {
Ok(( Ok((
skybox_pipeline, pipelines,
figure_pipeline,
terrain_pipeline,
fluid_pipeline,
sprite_pipeline,
particle_pipeline,
ui_pipeline,
lod_terrain_pipeline,
clouds_pipeline,
postprocess_pipeline,
//player_shadow_pipeline, //player_shadow_pipeline,
point_shadow_pipeline, point_shadow_pipeline,
terrain_directed_shadow_pipeline, terrain_directed_shadow_pipeline,
figure_directed_shadow_pipeline, figure_directed_shadow_pipeline,
)) => { )) => {
self.skybox_pipeline = skybox_pipeline; self.pipelines = pipelines;
self.figure_pipeline = figure_pipeline;
self.terrain_pipeline = terrain_pipeline;
self.fluid_pipeline = fluid_pipeline;
self.sprite_pipeline = sprite_pipeline;
self.particle_pipeline = particle_pipeline;
self.ui_pipeline = ui_pipeline;
self.lod_terrain_pipeline = lod_terrain_pipeline;
self.clouds_pipeline = clouds_pipeline;
self.postprocess_pipeline = postprocess_pipeline;
//self.player_shadow_pipeline = player_shadow_pipeline; //self.player_shadow_pipeline = player_shadow_pipeline;
if let ( if let (
Some(point_pipeline), Some(point_pipeline),
@ -1110,7 +874,7 @@ impl Renderer {
point_shadow_pipeline, point_shadow_pipeline,
terrain_directed_shadow_pipeline, terrain_directed_shadow_pipeline,
figure_directed_shadow_pipeline, figure_directed_shadow_pipeline,
&mut self.shadow_map, &mut self.shadow.map,
) { ) {
shadow_map.point_pipeline = point_pipeline; shadow_map.point_pipeline = point_pipeline;
shadow_map.terrain_directed_pipeline = terrain_directed_pipeline; shadow_map.terrain_directed_pipeline = terrain_directed_pipeline;
@ -1275,9 +1039,34 @@ impl Renderer {
/// Creates a download buffer, downloads the win_color_view, and converts to /// Creates a download buffer, downloads the win_color_view, and converts to
/// a image::DynamicImage. /// a image::DynamicImage.
#[allow(clippy::map_clone)] // TODO: Pending review in #587 //pub fn create_screenshot(&mut self) -> Result<image::DynamicImage,
pub fn create_screenshot(&mut self) -> Result<image::DynamicImage, RenderError> { // RenderError> {
todo!() pub fn create_screenshot(&mut self) {
// TODO: check if enabled
// TODO: save alongside a screenshot
// Take profiler snapshot
let profiling_data = if let Some(data) = self.profiler.process_finished_frame() {
data
} else {
error!("Failed to retrieve profiling data");
return;
};
let file_name = format!(
"frame-trace_{}.json",
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0)
);
wgpu_profiler::chrometrace::write_chrometrace(
std::path::Path::new(&file_name),
&profiling_data,
);
println!("{}", file_name);
//todo!()
// let (width, height) = self.get_resolution().into_tuple(); // let (width, height) = self.get_resolution().into_tuple();
// let download_buf = self // let download_buf = self
@ -2042,7 +1831,6 @@ impl Renderer {
} }
/// Creates all the pipelines used to render. /// Creates all the pipelines used to render.
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
fn create_pipelines( fn create_pipelines(
device: &wgpu::Device, device: &wgpu::Device,
layouts: &Layouts, layouts: &Layouts,
@ -2052,16 +1840,7 @@ fn create_pipelines(
has_shadow_views: bool, has_shadow_views: bool,
) -> Result< ) -> Result<
( (
skybox::SkyboxPipeline, Pipelines,
figure::FigurePipeline,
terrain::TerrainPipeline,
fluid::FluidPipeline,
sprite::SpritePipeline,
particle::ParticlePipeline,
ui::UiPipeline,
lod_terrain::LodTerrainPipeline,
clouds::CloudsPipeline,
postprocess::PostProcessPipeline,
//figure::FigurePipeline, //figure::FigurePipeline,
Option<shadow::PointShadowPipeline>, Option<shadow::PointShadowPipeline>,
Option<shadow::ShadowPipeline>, Option<shadow::ShadowPipeline>,
@ -2351,16 +2130,18 @@ fn create_pipelines(
); );
Ok(( Ok((
skybox_pipeline, Pipelines {
figure_pipeline, skybox: skybox_pipeline,
terrain_pipeline, figure: figure_pipeline,
fluid_pipeline, terrain: terrain_pipeline,
sprite_pipeline, fluid: fluid_pipeline,
particle_pipeline, sprite: sprite_pipeline,
ui_pipeline, particle: particle_pipeline,
lod_terrain_pipeline, ui: ui_pipeline,
clouds_pipeline, lod_terrain: lod_terrain_pipeline,
postprocess_pipeline, clouds: clouds_pipeline,
postprocess: postprocess_pipeline,
},
// player_shadow_pipeline, // player_shadow_pipeline,
Some(point_shadow_pipeline), Some(point_shadow_pipeline),
Some(terrain_directed_shadow_pipeline), Some(terrain_directed_shadow_pipeline),

View File

@ -8,45 +8,70 @@ use super::{
clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite,
terrain, ui, ColLights, GlobalsBindGroup, Light, Shadow, terrain, ui, ColLights, GlobalsBindGroup, Light, Shadow,
}, },
scope::{ManualOwningScope, OwningScope, Scope},
}, },
spans::{self, OwningSpan, Span},
Renderer, ShadowMap, ShadowMapRenderer, Renderer, ShadowMap, ShadowMapRenderer,
}; };
use core::{num::NonZeroU32, ops::Range}; use core::{num::NonZeroU32, ops::Range};
use std::sync::Arc; use std::sync::Arc;
use vek::Aabr; use vek::Aabr;
// Borrow the fields we need from the renderer so that the GpuProfiler can be
// dijointly borrowed mutably
struct RendererBorrow<'frame> {
queue: &'frame wgpu::Queue,
device: &'frame wgpu::Device,
shadow: &'frame super::Shadow,
pipelines: &'frame super::Pipelines,
locals: &'frame super::locals::Locals,
views: &'frame super::Views,
mode: &'frame super::super::RenderMode,
}
pub struct Drawer<'frame> { pub struct Drawer<'frame> {
encoder: Option<wgpu::CommandEncoder>, encoder: Option<ManualOwningScope<'frame, wgpu::CommandEncoder>>,
pub renderer: &'frame mut Renderer, borrow: RendererBorrow<'frame>,
tex: wgpu::SwapChainTexture, swap_tex: wgpu::SwapChainTexture,
globals: &'frame GlobalsBindGroup, globals: &'frame GlobalsBindGroup,
} }
impl<'frame> Drawer<'frame> { impl<'frame> Drawer<'frame> {
pub fn new( pub fn new(
mut encoder: wgpu::CommandEncoder, encoder: wgpu::CommandEncoder,
renderer: &'frame mut Renderer, renderer: &'frame mut Renderer,
tex: wgpu::SwapChainTexture, swap_tex: wgpu::SwapChainTexture,
globals: &'frame GlobalsBindGroup, globals: &'frame GlobalsBindGroup,
) -> Self { ) -> Self {
renderer.tracer.start_span(&mut encoder, &spans::Id::Frame); let borrow = RendererBorrow {
queue: &renderer.queue,
device: &renderer.device,
shadow: &renderer.shadow,
pipelines: &renderer.pipelines,
locals: &renderer.locals,
views: &renderer.views,
mode: &renderer.mode,
};
let mut encoder =
ManualOwningScope::start(&mut renderer.profiler, encoder, borrow.device, "frame");
Self { Self {
encoder: Some(encoder), encoder: Some(encoder),
renderer, borrow,
tex, swap_tex,
globals, globals,
} }
} }
/// Get the render mode.
pub fn render_mode(&self) -> &super::super::RenderMode { self.borrow.mode }
pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> { pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map { if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow.map {
let encoder = self.encoder.as_mut().unwrap();
let device = self.borrow.device;
let mut render_pass = let mut render_pass =
self.encoder encoder.scoped_render_pass(device, "shadow_pass", &wgpu::RenderPassDescriptor {
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("shadow pass"), label: Some("shadow pass"),
color_attachments: &[], color_attachments: &[],
depth_stencil_attachment: Some( depth_stencil_attachment: Some(
@ -61,16 +86,11 @@ impl<'frame> Drawer<'frame> {
), ),
}); });
let mut render_pass = OwningSpan::start(
&self.renderer.tracer,
render_pass,
spans::Id::DirectedShadows,
);
render_pass.set_bind_group(0, &self.globals.bind_group, &[]); render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
Some(ShadowPassDrawer { Some(ShadowPassDrawer {
render_pass, render_pass,
renderer: &self.renderer, borrow: &self.borrow,
shadow_renderer, shadow_renderer,
}) })
} else { } else {
@ -79,54 +99,46 @@ impl<'frame> Drawer<'frame> {
} }
pub fn first_pass(&mut self) -> FirstPassDrawer { pub fn first_pass(&mut self) -> FirstPassDrawer {
let render_pass = let encoder = self.encoder.as_mut().unwrap();
self.encoder let device = self.borrow.device;
.as_mut() let mut render_pass =
.unwrap() encoder.scoped_render_pass(device, "first_pass", &wgpu::RenderPassDescriptor {
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("first pass"), label: Some("first pass"),
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &self.renderer.tgt_color_view, attachment: &self.borrow.views.tgt_color,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
store: true, store: true,
}, },
}], }],
depth_stencil_attachment: Some( depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
wgpu::RenderPassDepthStencilAttachmentDescriptor { attachment: &self.borrow.views.tgt_depth,
attachment: &self.renderer.tgt_depth_view,
depth_ops: Some(wgpu::Operations { depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(0.0), load: wgpu::LoadOp::Clear(0.0),
store: true, store: true,
}), }),
stencil_ops: None, stencil_ops: None,
}, }),
),
}); });
let mut render_pass =
OwningSpan::start(&self.renderer.tracer, render_pass, spans::Id::PassOne);
render_pass.set_bind_group(0, &self.globals.bind_group, &[]); render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
render_pass.set_bind_group(1, &self.renderer.shadow_bind.bind_group, &[]); render_pass.set_bind_group(1, &self.borrow.shadow.bind.bind_group, &[]);
FirstPassDrawer { FirstPassDrawer {
render_pass, render_pass,
renderer: &self.renderer, borrow: &self.borrow,
figures_called: false,
} }
} }
pub fn second_pass(&mut self) -> SecondPassDrawer { pub fn second_pass(&mut self) -> SecondPassDrawer {
let render_pass = let encoder = self.encoder.as_mut().unwrap();
self.encoder let device = self.borrow.device;
.as_mut() let mut render_pass =
.unwrap() encoder.scoped_render_pass(device, "second_pass", &wgpu::RenderPassDescriptor {
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("second pass (clouds)"), label: Some("second pass (clouds)"),
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &self.renderer.tgt_color_pp_view, attachment: &self.borrow.views.tgt_color_pp,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
@ -136,27 +148,23 @@ impl<'frame> Drawer<'frame> {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
let mut render_pass =
OwningSpan::start(&self.renderer.tracer, render_pass, spans::Id::PassTwo);
render_pass.set_bind_group(0, &self.globals.bind_group, &[]); render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
render_pass.set_bind_group(1, &self.renderer.shadow_bind.bind_group, &[]); render_pass.set_bind_group(1, &self.borrow.shadow.bind.bind_group, &[]);
SecondPassDrawer { SecondPassDrawer {
render_pass, render_pass,
renderer: &self.renderer, borrow: &self.borrow,
} }
} }
pub fn third_pass(&mut self) -> ThirdPassDrawer { pub fn third_pass(&mut self) -> ThirdPassDrawer {
let render_pass = let encoder = self.encoder.as_mut().unwrap();
self.encoder let device = self.borrow.device;
.as_mut() let mut render_pass =
.unwrap() encoder.scoped_render_pass(device, "third_pass", &wgpu::RenderPassDescriptor {
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("third pass (postprocess + ui)"), label: Some("third pass (postprocess + ui)"),
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &self.tex.view, attachment: &self.swap_tex.view,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
@ -166,14 +174,11 @@ impl<'frame> Drawer<'frame> {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}); });
let mut render_pass =
OwningSpan::start(&self.renderer.tracer, render_pass, spans::Id::PassThree);
render_pass.set_bind_group(0, &self.globals.bind_group, &[]); render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
ThirdPassDrawer { ThirdPassDrawer {
render_pass, render_pass,
renderer: &self.renderer, borrow: &self.borrow,
} }
} }
@ -183,10 +188,13 @@ impl<'frame> Drawer<'frame> {
chunks: impl Clone chunks: impl Clone
+ Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>, + Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
) { ) {
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map { if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow.map {
self.renderer let device = self.borrow.device;
.tracer let mut encoder = self
.start_span(self.encoder.as_mut().unwrap(), &spans::Id::PointShadows); .encoder
.as_mut()
.unwrap()
.scope(device, "point shadows");
const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>(); const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>();
let data = bytemuck::cast_slice(matrices); let data = bytemuck::cast_slice(matrices);
@ -209,10 +217,7 @@ impl<'frame> Drawer<'frame> {
let label = format!("point shadow face-{} pass", face); let label = format!("point shadow face-{} pass", face);
let mut render_pass = let mut render_pass =
self.encoder encoder.scoped_render_pass(device, &label, &wgpu::RenderPassDescriptor {
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some(&label), label: Some(&label),
color_attachments: &[], color_attachments: &[],
depth_stencil_attachment: Some( depth_stencil_attachment: Some(
@ -244,9 +249,6 @@ impl<'frame> Drawer<'frame> {
}); });
}); });
} }
self.renderer
.tracer
.end_span(self.encoder.as_mut().unwrap(), &spans::Id::PointShadows);
} }
} }
@ -258,11 +260,13 @@ impl<'frame> Drawer<'frame> {
/// requires an array of matrices that could be a pain to construct /// requires an array of matrices that could be a pain to construct
/// simply for clearing /// simply for clearing
pub fn clear_shadows(&mut self) { pub fn clear_shadows(&mut self) {
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map { if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow.map {
self.encoder let device = self.borrow.device;
.as_mut() let encoder = self.encoder.as_mut().unwrap();
.unwrap() encoder.scoped_render_pass(
.begin_render_pass(&wgpu::RenderPassDescriptor { device,
"clear_directed_shadow",
&wgpu::RenderPassDescriptor {
label: Some("clear directed shadow pass"), label: Some("clear directed shadow pass"),
color_attachments: &[], color_attachments: &[],
depth_stencil_attachment: Some( depth_stencil_attachment: Some(
@ -275,7 +279,8 @@ impl<'frame> Drawer<'frame> {
stencil_ops: None, stencil_ops: None,
}, },
), ),
}); },
);
for face in 0..6 { for face in 0..6 {
// TODO: view creation cost? // TODO: view creation cost?
@ -295,10 +300,7 @@ impl<'frame> Drawer<'frame> {
}); });
let label = format!("clear point shadow face-{} pass", face); let label = format!("clear point shadow face-{} pass", face);
self.encoder encoder.scoped_render_pass(device, &label, &wgpu::RenderPassDescriptor {
.as_mut()
.unwrap()
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some(&label), label: Some(&label),
color_attachments: &[], color_attachments: &[],
depth_stencil_attachment: Some( depth_stencil_attachment: Some(
@ -321,47 +323,38 @@ impl<'frame> Drop for Drawer<'frame> {
fn drop(&mut self) { fn drop(&mut self) {
// TODO: submitting things to the queue can let the gpu start on them sooner // TODO: submitting things to the queue can let the gpu start on them sooner
// maybe we should submit each render pass to the queue as they are produced? // maybe we should submit each render pass to the queue as they are produced?
self.renderer let (mut encoder, profiler) = self.encoder.take().unwrap().end_scope();
.tracer profiler.resolve_queries(&mut encoder);
.end_span(self.encoder.as_mut().unwrap(), &spans::Id::Frame); self.borrow.queue.submit(std::iter::once(encoder.finish()));
self.renderer profiler
.tracer .end_frame()
.resolve_timestamps(self.encoder.as_mut().unwrap()); .expect("Gpu profiler error! Maybe there was an unclosed scope?");
self.renderer
.queue
.submit(std::iter::once(self.encoder.take().unwrap().finish()));
// NOTE: this introduces blocking on GPU work
self.renderer
.tracer
.record_timestamps(&self.renderer.device)
} }
} }
// Shadow pass // Shadow pass
pub struct ShadowPassDrawer<'pass> { pub struct ShadowPassDrawer<'pass> {
render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>, render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
pub renderer: &'pass Renderer, borrow: &'pass RendererBorrow<'pass>,
shadow_renderer: &'pass ShadowMapRenderer, shadow_renderer: &'pass ShadowMapRenderer,
} }
impl<'pass> ShadowPassDrawer<'pass> { impl<'pass> ShadowPassDrawer<'pass> {
pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> { pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self
&self.renderer.tracer, .render_pass
&mut *self.render_pass, .scope(self.borrow.device, "direcred_figure_shadows");
spans::Id::DirectedFigureShadows,
);
render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline); render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
FigureShadowDrawer { render_pass } FigureShadowDrawer { render_pass }
} }
pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> { pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self
&self.renderer.tracer, .render_pass
&mut *self.render_pass, .scope(self.borrow.device, "direcred_terrain_shadows");
spans::Id::DirectedTerrainShadows,
);
render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline); render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
TerrainShadowDrawer { render_pass } TerrainShadowDrawer { render_pass }
@ -369,7 +362,7 @@ impl<'pass> ShadowPassDrawer<'pass> {
} }
pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> { impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
@ -385,7 +378,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
} }
pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> { impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
@ -402,73 +395,50 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
// First pass // First pass
pub struct FirstPassDrawer<'pass> { pub struct FirstPassDrawer<'pass> {
pub(super) render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>, pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
pub renderer: &'pass Renderer, borrow: &'pass RendererBorrow<'pass>,
// TODO: hack
figures_called: bool,
} }
impl<'pass> FirstPassDrawer<'pass> { impl<'pass> FirstPassDrawer<'pass> {
pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) { pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "skybox");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.skybox.pipeline);
spans::Id::Skybox,
);
render_pass.set_pipeline(&self.renderer.skybox_pipeline.pipeline);
render_pass.set_vertex_buffer(0, model.buf().slice(..)); render_pass.set_vertex_buffer(0, model.buf().slice(..));
render_pass.draw(0..model.len() as u32, 0..1); render_pass.draw(0..model.len() as u32, 0..1);
} }
pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) { pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "lod_terrain");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.lod_terrain.pipeline);
spans::Id::Lod,
);
render_pass.set_pipeline(&self.renderer.lod_terrain_pipeline.pipeline);
render_pass.set_vertex_buffer(0, model.buf().slice(..)); render_pass.set_vertex_buffer(0, model.buf().slice(..));
render_pass.draw(0..model.len() as u32, 0..1); render_pass.draw(0..model.len() as u32, 0..1);
} }
pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> { pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "figures");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.figure.pipeline);
if !self.figures_called {
spans::Id::Figures1
} else {
spans::Id::Figures2
},
);
self.figures_called = true;
render_pass.set_pipeline(&self.renderer.figure_pipeline.pipeline);
FigureDrawer { render_pass } FigureDrawer { render_pass }
} }
pub fn draw_terrain<'data: 'pass>(&mut self) -> TerrainDrawer<'_, 'pass> { pub fn draw_terrain<'data: 'pass>(&mut self) -> TerrainDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "terrain");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.terrain.pipeline);
spans::Id::Terrain,
);
render_pass.set_pipeline(&self.renderer.terrain_pipeline.pipeline);
TerrainDrawer { TerrainDrawer {
render_pass, render_pass,
col_lights: None, col_lights: None,
} }
} }
pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> { pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "particles");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.particle.pipeline);
spans::Id::Particles,
);
render_pass.set_pipeline(&self.renderer.particle_pipeline.pipeline);
ParticleDrawer { render_pass } ParticleDrawer { render_pass }
} }
@ -477,15 +447,10 @@ impl<'pass> FirstPassDrawer<'pass> {
&mut self, &mut self,
col_lights: &'data ColLights<sprite::Locals>, col_lights: &'data ColLights<sprite::Locals>,
) -> SpriteDrawer<'_, 'pass> { ) -> SpriteDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "sprites");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.sprite.pipeline);
spans::Id::Sprites, render_pass.set_bind_group(4, &col_lights.bind_group, &[]);
);
self.render_pass
.set_pipeline(&self.renderer.sprite_pipeline.pipeline);
self.render_pass
.set_bind_group(4, &col_lights.bind_group, &[]);
SpriteDrawer { render_pass } SpriteDrawer { render_pass }
} }
@ -494,12 +459,9 @@ impl<'pass> FirstPassDrawer<'pass> {
&mut self, &mut self,
waves: &'data fluid::BindGroup, waves: &'data fluid::BindGroup,
) -> FluidDrawer<'_, 'pass> { ) -> FluidDrawer<'_, 'pass> {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "fluid");
&self.renderer.tracer,
&mut *self.render_pass, render_pass.set_pipeline(&self.borrow.pipelines.fluid.pipeline);
spans::Id::Fluid,
);
render_pass.set_pipeline(&self.renderer.fluid_pipeline.pipeline);
render_pass.set_bind_group(2, &waves.bind_group, &[]); render_pass.set_bind_group(2, &waves.bind_group, &[]);
FluidDrawer { render_pass } FluidDrawer { render_pass }
@ -507,7 +469,7 @@ impl<'pass> FirstPassDrawer<'pass> {
} }
pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> { impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
@ -527,7 +489,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
} }
pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
col_lights: Option<&'pass_ref Arc<ColLights<terrain::Locals>>>, col_lights: Option<&'pass_ref Arc<ColLights<terrain::Locals>>>,
} }
@ -559,7 +521,7 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
} }
pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> { impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
@ -580,7 +542,7 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
} }
pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> { impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> {
@ -617,7 +579,7 @@ impl<'pass_ref, 'pass: 'pass_ref> ChunkSpriteDrawer<'pass_ref, 'pass> {
} }
pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct FluidDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> { impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
@ -634,49 +596,44 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
// Second pass: clouds // Second pass: clouds
pub struct SecondPassDrawer<'pass> { pub struct SecondPassDrawer<'pass> {
render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>, render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
renderer: &'pass Renderer, borrow: &'pass RendererBorrow<'pass>,
} }
impl<'pass> SecondPassDrawer<'pass> { impl<'pass> SecondPassDrawer<'pass> {
pub fn draw_clouds(&mut self) { pub fn draw_clouds(&mut self) {
self.render_pass self.render_pass
.set_pipeline(&self.renderer.clouds_pipeline.pipeline); .set_pipeline(&self.borrow.pipelines.clouds.pipeline);
self.render_pass self.render_pass
.set_bind_group(2, &self.renderer.locals.clouds_bind.bind_group, &[]); .set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]);
self.render_pass.draw(0..3, 0..1); self.render_pass.draw(0..3, 0..1);
} }
} }
// Third pass: postprocess + ui // Third pass: postprocess + ui
pub struct ThirdPassDrawer<'pass> { pub struct ThirdPassDrawer<'pass> {
render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>, render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
renderer: &'pass Renderer, borrow: &'pass RendererBorrow<'pass>,
} }
impl<'pass> ThirdPassDrawer<'pass> { impl<'pass> ThirdPassDrawer<'pass> {
pub fn draw_post_process(&mut self) { pub fn draw_post_process(&mut self) {
let mut render_pass = Span::start( let mut render_pass = self.render_pass.scope(self.borrow.device, "postprocess");
&self.renderer.tracer, render_pass.set_pipeline(&self.borrow.pipelines.postprocess.pipeline);
&mut *self.render_pass, render_pass.set_bind_group(1, &self.borrow.locals.postprocess_bind.bind_group, &[]);
spans::Id::Postprocess,
);
render_pass.set_pipeline(&self.renderer.postprocess_pipeline.pipeline);
render_pass.set_bind_group(1, &self.renderer.locals.postprocess_bind.bind_group, &[]);
render_pass.draw(0..3, 0..1); render_pass.draw(0..3, 0..1);
} }
pub fn draw_ui(&mut self) -> UiDrawer<'_, 'pass> { pub fn draw_ui(&mut self) -> UiDrawer<'_, 'pass> {
let mut render_pass = let mut render_pass = self.render_pass.scope(self.borrow.device, "ui");
Span::start(&self.renderer.tracer, &mut *self.render_pass, spans::Id::Ui); render_pass.set_pipeline(&self.borrow.pipelines.ui.pipeline);
render_pass.set_pipeline(&self.renderer.ui_pipeline.pipeline);
UiDrawer { render_pass } UiDrawer { render_pass }
} }
} }
pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct UiDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Span<'pass_ref, wgpu::RenderPass<'pass>>, render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
} }
pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> { pub struct PreparedUiDrawer<'pass_ref, 'pass: 'pass_ref> {

View File

@ -0,0 +1,75 @@
use super::{
super::{
consts::Consts,
pipelines::{clouds, postprocess},
},
Layouts,
};
pub struct Locals {
pub clouds: Consts<clouds::Locals>,
pub clouds_bind: clouds::BindGroup,
pub postprocess: Consts<postprocess::Locals>,
pub postprocess_bind: postprocess::BindGroup,
}
impl Locals {
pub(super) fn new(
device: &wgpu::Device,
layouts: &Layouts,
clouds_locals: Consts<clouds::Locals>,
postprocess_locals: Consts<postprocess::Locals>,
tgt_color_view: &wgpu::TextureView,
tgt_depth_view: &wgpu::TextureView,
tgt_color_pp_view: &wgpu::TextureView,
sampler: &wgpu::Sampler,
depth_sampler: &wgpu::Sampler,
) -> Self {
let clouds_bind = layouts.clouds.bind(
device,
tgt_color_view,
tgt_depth_view,
sampler,
depth_sampler,
&clouds_locals,
);
let postprocess_bind =
layouts
.postprocess
.bind(device, tgt_color_pp_view, sampler, &postprocess_locals);
Self {
clouds: clouds_locals,
clouds_bind,
postprocess: postprocess_locals,
postprocess_bind,
}
}
pub(super) fn rebind(
&mut self,
device: &wgpu::Device,
layouts: &Layouts,
// Call when these are recreated and need to be rebound
// e.g. resizing
tgt_color_view: &wgpu::TextureView,
tgt_depth_view: &wgpu::TextureView,
tgt_color_pp_view: &wgpu::TextureView,
sampler: &wgpu::Sampler,
depth_sampler: &wgpu::Sampler,
) {
self.clouds_bind = layouts.clouds.bind(
device,
tgt_color_view,
tgt_depth_view,
sampler,
depth_sampler,
&self.clouds,
);
self.postprocess_bind =
layouts
.postprocess
.bind(device, tgt_color_pp_view, sampler, &self.postprocess);
}
}

View File

@ -0,0 +1,91 @@
use common::assets::{self, AssetExt, AssetHandle};
use hashbrown::HashMap;
/// Load from a GLSL file.
pub struct Glsl(pub String);
impl From<String> for Glsl {
fn from(s: String) -> Glsl { Glsl(s) }
}
impl assets::Asset for Glsl {
type Loader = assets::LoadFrom<String, assets::StringLoader>;
const EXTENSION: &'static str = "glsl";
}
pub struct Shaders {
shaders: HashMap<String, AssetHandle<Glsl>>,
}
impl assets::Compound for Shaders {
// TODO: Taking the specifier argument as a base for shaders specifiers
// would allow to use several shaders groups easily
fn load<S: assets::source::Source>(
_: &assets::AssetCache<S>,
_: &str,
) -> Result<Shaders, assets::Error> {
let shaders = [
"include.constants",
"include.globals",
"include.sky",
"include.light",
"include.srgb",
"include.random",
"include.lod",
"include.shadows",
"antialias.none",
"antialias.fxaa",
"antialias.msaa-x4",
"antialias.msaa-x8",
"antialias.msaa-x16",
"include.cloud.none",
"include.cloud.regular",
"figure-vert",
"light-shadows-figure-vert",
"light-shadows-directed-vert",
"light-shadows-directed-frag",
"point-light-shadows-vert",
"skybox-vert",
"skybox-frag",
"figure-frag",
"terrain-vert",
"terrain-frag",
"fluid-vert",
"fluid-frag.cheap",
"fluid-frag.shiny",
"sprite-vert",
"sprite-frag",
"particle-vert",
"particle-frag",
"ui-vert",
"ui-frag",
"lod-terrain-vert",
"lod-terrain-frag",
"clouds-vert",
"clouds-frag",
"postprocess-vert",
"postprocess-frag",
"player-shadow-frag",
"light-shadows-geom",
"light-shadows-frag",
];
let shaders = shaders
.iter()
.map(|shader| {
let full_specifier = ["voxygen.shaders.", shader].concat();
let asset = AssetExt::load(&full_specifier)?;
Ok((String::from(*shader), asset))
})
.collect::<Result<HashMap<_, _>, assets::Error>>()?;
Ok(Self { shaders })
}
}
impl Shaders {
pub fn get(&self, shader: &str) -> Option<impl core::ops::Deref<Target = Glsl>> {
self.shaders.get(shader).map(|a| a.read())
}
}

View File

@ -0,0 +1,38 @@
use super::super::{pipelines::shadow, texture::Texture};
/// A type that holds shadow map data. Since shadow mapping may not be
/// supported on all platforms, we try to keep it separate.
pub struct ShadowMapRenderer {
// directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
// point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
pub directed_depth: Texture,
pub point_depth: Texture,
pub point_pipeline: shadow::PointShadowPipeline,
pub terrain_directed_pipeline: shadow::ShadowPipeline,
pub figure_directed_pipeline: shadow::ShadowFigurePipeline,
pub layout: shadow::ShadowLayout,
}
pub enum ShadowMap {
Enabled(ShadowMapRenderer),
Disabled {
dummy_point: Texture, // Cube texture
dummy_directed: Texture,
},
}
impl ShadowMap {
pub fn textures(&self) -> (&Texture, &Texture) {
match self {
Self::Enabled(renderer) => (&renderer.point_depth, &renderer.directed_depth),
Self::Disabled {
dummy_point,
dummy_directed,
} => (dummy_point, dummy_directed),
}
}
pub fn is_enabled(&self) -> bool { matches!(self, Self::Enabled(_)) }
}

165
voxygen/src/render/scope.rs Normal file
View File

@ -0,0 +1,165 @@
use wgpu_profiler::{GpuProfiler, ProfilerCommandRecorder};
pub fn required_features() -> wgpu::Features { wgpu::Features::TIMESTAMP_QUERY }
pub struct Scope<'a, W: ProfilerCommandRecorder> {
profiler: &'a mut GpuProfiler,
wgpu_thing: &'a mut W,
}
pub struct OwningScope<'a, W: ProfilerCommandRecorder> {
profiler: &'a mut GpuProfiler,
wgpu_thing: W,
}
// Separate type since we can't destructure types that impl Drop :/
pub struct ManualOwningScope<'a, W: ProfilerCommandRecorder> {
profiler: &'a mut GpuProfiler,
wgpu_thing: W,
}
impl<'a, W: ProfilerCommandRecorder> Scope<'a, W> {
pub fn start(
profiler: &'a mut GpuProfiler,
wgpu_thing: &'a mut W,
device: &wgpu::Device,
label: &str,
) -> Self {
profiler.begin_scope(label, wgpu_thing, device);
Self {
profiler,
wgpu_thing,
}
}
/// Starts a scope nested within this one
pub fn scope(&mut self, device: &wgpu::Device, label: &str) -> Scope<'_, W> {
Scope::start(self.profiler, self.wgpu_thing, device, label)
}
}
impl<'a, W: ProfilerCommandRecorder> OwningScope<'a, W> {
pub fn start(
profiler: &'a mut GpuProfiler,
mut wgpu_thing: W,
device: &wgpu::Device,
label: &str,
) -> Self {
profiler.begin_scope(label, &mut wgpu_thing, device);
Self {
profiler,
wgpu_thing,
}
}
/// Starts a scope nested within this one
pub fn scope(&mut self, device: &wgpu::Device, label: &str) -> Scope<'_, W> {
Scope::start(self.profiler, &mut self.wgpu_thing, device, label)
}
}
impl<'a, W: ProfilerCommandRecorder> ManualOwningScope<'a, W> {
pub fn start(
profiler: &'a mut GpuProfiler,
mut wgpu_thing: W,
device: &wgpu::Device,
label: &str,
) -> Self {
profiler.begin_scope(label, &mut wgpu_thing, device);
Self {
profiler,
wgpu_thing,
}
}
/// Starts a scope nested within this one
pub fn scope(&mut self, device: &wgpu::Device, label: &str) -> Scope<'_, W> {
Scope::start(self.profiler, &mut self.wgpu_thing, device, label)
}
/// Ends the scope allowing the extraction of owned the wgpu thing
/// and the mutable reference to the GpuProfiler
pub fn end_scope(mut self) -> (W, &'a mut GpuProfiler) {
self.profiler.end_scope(&mut self.wgpu_thing);
(self.wgpu_thing, self.profiler)
}
}
impl<'a> Scope<'a, wgpu::CommandEncoder> {
/// Start a render pass wrapped in an OwnedScope
pub fn scoped_render_pass<'b>(
&'b mut self,
device: &wgpu::Device,
label: &str,
pass_descriptor: &wgpu::RenderPassDescriptor<'b, '_>,
) -> OwningScope<'b, wgpu::RenderPass> {
let render_pass = self.wgpu_thing.begin_render_pass(pass_descriptor);
OwningScope::start(self.profiler, render_pass, device, label)
}
}
impl<'a> OwningScope<'a, wgpu::CommandEncoder> {
/// Start a render pass wrapped in an OwnedScope
pub fn scoped_render_pass<'b>(
&'b mut self,
device: &wgpu::Device,
label: &str,
pass_descriptor: &wgpu::RenderPassDescriptor<'b, '_>,
) -> OwningScope<'b, wgpu::RenderPass> {
let render_pass = self.wgpu_thing.begin_render_pass(pass_descriptor);
OwningScope::start(self.profiler, render_pass, device, label)
}
}
impl<'a> ManualOwningScope<'a, wgpu::CommandEncoder> {
/// Start a render pass wrapped in an OwnedScope
pub fn scoped_render_pass<'b>(
&'b mut self,
device: &wgpu::Device,
label: &str,
pass_descriptor: &wgpu::RenderPassDescriptor<'b, '_>,
) -> OwningScope<'b, wgpu::RenderPass> {
let render_pass = self.wgpu_thing.begin_render_pass(pass_descriptor);
OwningScope::start(self.profiler, render_pass, device, label)
}
}
// Scope
impl<'a, W: ProfilerCommandRecorder> std::ops::Deref for Scope<'a, W> {
type Target = W;
fn deref(&self) -> &Self::Target { self.wgpu_thing }
}
impl<'a, W: ProfilerCommandRecorder> std::ops::DerefMut for Scope<'a, W> {
fn deref_mut(&mut self) -> &mut Self::Target { self.wgpu_thing }
}
impl<'a, W: ProfilerCommandRecorder> Drop for Scope<'a, W> {
fn drop(&mut self) { self.profiler.end_scope(self.wgpu_thing); }
}
// OwningScope
impl<'a, W: ProfilerCommandRecorder> std::ops::Deref for OwningScope<'a, W> {
type Target = W;
fn deref(&self) -> &Self::Target { &self.wgpu_thing }
}
impl<'a, W: ProfilerCommandRecorder> std::ops::DerefMut for OwningScope<'a, W> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.wgpu_thing }
}
impl<'a, W: ProfilerCommandRecorder> Drop for OwningScope<'a, W> {
fn drop(&mut self) { self.profiler.end_scope(&mut self.wgpu_thing); }
}
// ManualOwningScope
impl<'a, W: ProfilerCommandRecorder> std::ops::Deref for ManualOwningScope<'a, W> {
type Target = W;
fn deref(&self) -> &Self::Target { &self.wgpu_thing }
}
impl<'a, W: ProfilerCommandRecorder> std::ops::DerefMut for ManualOwningScope<'a, W> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.wgpu_thing }
}

View File

@ -1048,9 +1048,7 @@ impl Scene {
let camera_data = (&self.camera, scene_data.figure_lod_render_distance); let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
// would instead have this as an extension. // would instead have this as an extension.
if drawer.renderer.render_mode().shadow.is_map() if drawer.render_mode().shadow.is_map() && (is_daylight || !self.light_data.is_empty()) {
&& (is_daylight || !self.light_data.is_empty())
{
if is_daylight { if is_daylight {
if let Some(mut shadow_pass) = drawer.shadow_pass() { if let Some(mut shadow_pass) = drawer.shadow_pass() {
// Render terrain directed shadows. // Render terrain directed shadows.

View File

@ -516,7 +516,7 @@ impl SpriteRenderContext {
.into_iter() .into_iter()
.map( .map(
|SpriteDataResponse { |SpriteDataResponse {
locals, locals: locals_buffer,
model, model,
offset, offset,
}| { }| {

View File

@ -10,7 +10,6 @@ use gilrs::{EventType, Gilrs};
use hashbrown::HashMap; use hashbrown::HashMap;
use itertools::Itertools; use itertools::Itertools;
use keyboard_keynames::key_layout::KeyLayout; use keyboard_keynames::key_layout::KeyLayout;
use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::{error, warn}; use tracing::{error, warn};
use vek::*; use vek::*;
@ -941,6 +940,9 @@ impl Window {
let winit::dpi::PhysicalSize { width, height } = physical; let winit::dpi::PhysicalSize { width, height } = physical;
self.events self.events
.push(Event::Resize(Vec2::new(width as u32, height as u32))); .push(Event::Resize(Vec2::new(width as u32, height as u32)));
// TODO: can get invalid scissor rect
// panic with this + resize several times
// std::thread::sleep_ms(500);
}, },
WindowEvent::ScaleFactorChanged { scale_factor, .. } => { WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
// TODO: is window resized event emitted? or do we need to handle that here? // TODO: is window resized event emitted? or do we need to handle that here?
@ -1342,7 +1344,9 @@ impl Window {
pub fn send_event(&mut self, event: Event) { self.events.push(event) } pub fn send_event(&mut self, event: Event) { self.events.push(event) }
pub fn take_screenshot(&mut self, settings: &Settings) { pub fn take_screenshot(&mut self, settings: &Settings) {
match self.renderer.create_screenshot() { let _ = self.renderer.create_screenshot();
// TODO
/*match self.renderer.create_screenshot() {
Ok(img) => { Ok(img) => {
let mut path = settings.screenshots_path.clone(); let mut path = settings.screenshots_path.clone();
let sender = self.message_sender.clone(); let sender = self.message_sender.clone();
@ -1377,7 +1381,7 @@ impl Window {
.unwrap(); .unwrap();
}, },
Err(e) => error!(?e, "Couldn't create screenshot due to renderer error"), Err(e) => error!(?e, "Couldn't create screenshot due to renderer error"),
} }*/
} }
fn is_pressed( fn is_pressed(