mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement toggleable gpu profiling that saves the timings from a recent frame with the screenshot key, rebase fixes
This commit is contained in:
parent
5cdce0635d
commit
d2e2580df4
544
Cargo.lock
generated
544
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -110,3 +110,5 @@ nativeBuildInputs = ["pkg-config"]
|
||||
# macos CI fix isn't merged yet
|
||||
winit = { git = "https://gitlab.com/veloren/winit.git", branch = "macos-test-spiffed" }
|
||||
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" }
|
||||
|
@ -46,6 +46,7 @@ i18n = {package = "veloren-i18n", path = "i18n"}
|
||||
# Graphics
|
||||
winit = {version = "0.24.0", features = ["serde"]}
|
||||
wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "1f1a7e5dd47a1610733bbc3989414acb62395359" }
|
||||
wgpu-profiler = "0.2.1"
|
||||
bytemuck = { version="1.4", features=["derive"] }
|
||||
shaderc = "0.6.2"
|
||||
|
||||
@ -95,8 +96,7 @@ rand = "0.8"
|
||||
rodio = {version = "0.13", default-features = false, features = ["vorbis"]}
|
||||
ron = {version = "0.6", default-features = false}
|
||||
serde = {version = "1.0", features = [ "rc", "derive" ]}
|
||||
# strum = "0.20"
|
||||
strum = { version = "0.20.0", features = ["derive"] }
|
||||
strum = "0.20"
|
||||
strum_macros = "0.20"
|
||||
treeculler = "0.2"
|
||||
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
|
||||
|
@ -82,6 +82,9 @@ widget_ids! {
|
||||
refresh_rate,
|
||||
refresh_rate_label,
|
||||
//
|
||||
gpu_profiler_button,
|
||||
gpu_profiler_label,
|
||||
//
|
||||
particles_button,
|
||||
particles_label,
|
||||
lossy_terrain_compression_button,
|
||||
@ -902,11 +905,37 @@ impl<'a> Widget for Video<'a> {
|
||||
.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
|
||||
Text::new(&self.localized_strings.get("hud.settings.particles"))
|
||||
.font_size(self.fonts.cyri.scale(14))
|
||||
.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)
|
||||
.set(state.ids.particles_label, ui);
|
||||
|
||||
|
@ -8,7 +8,8 @@
|
||||
const_generics,
|
||||
drain_filter,
|
||||
once_cell,
|
||||
trait_alias
|
||||
trait_alias,
|
||||
or_patterns
|
||||
)]
|
||||
#![recursion_limit = "2048"]
|
||||
|
||||
|
@ -8,8 +8,8 @@ pub mod mesh;
|
||||
pub mod model;
|
||||
pub mod pipelines;
|
||||
pub mod renderer;
|
||||
mod scope;
|
||||
pub mod texture;
|
||||
mod time;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
@ -271,4 +271,5 @@ pub struct RenderMode {
|
||||
pub shadow: ShadowMode,
|
||||
pub upscale_mode: UpscaleMode,
|
||||
pub present_mode: PresentMode,
|
||||
pub profiler_enabled: bool,
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
mod binding;
|
||||
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::{
|
||||
consts::Consts,
|
||||
@ -18,141 +25,15 @@ use super::{
|
||||
use common::assets::{self, AssetExt, AssetHandle};
|
||||
use common_base::span;
|
||||
use core::convert::TryFrom;
|
||||
use hashbrown::HashMap;
|
||||
use tracing::{error, info, warn};
|
||||
use vek::*;
|
||||
|
||||
// TODO: yeet this somewhere else
|
||||
/// 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<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.
|
||||
struct Layouts {
|
||||
global: GlobalsLayouts,
|
||||
@ -167,72 +48,37 @@ struct Layouts {
|
||||
ui: ui::UiLayout,
|
||||
}
|
||||
|
||||
struct Locals {
|
||||
clouds: Consts<clouds::Locals>,
|
||||
clouds_bind: clouds::BindGroup,
|
||||
|
||||
postprocess: Consts<postprocess::Locals>,
|
||||
postprocess_bind: postprocess::BindGroup,
|
||||
/// A type that stores all the pipelines associated with this renderer.
|
||||
struct Pipelines {
|
||||
figure: figure::FigurePipeline,
|
||||
fluid: fluid::FluidPipeline,
|
||||
lod_terrain: lod_terrain::LodTerrainPipeline,
|
||||
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 {
|
||||
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);
|
||||
/// Render target views
|
||||
struct Views {
|
||||
// NOTE: unused for now
|
||||
win_depth: wgpu::TextureView,
|
||||
|
||||
Self {
|
||||
clouds: clouds_locals,
|
||||
clouds_bind,
|
||||
postprocess: postprocess_locals,
|
||||
postprocess_bind,
|
||||
}
|
||||
}
|
||||
tgt_color: wgpu::TextureView,
|
||||
tgt_depth: wgpu::TextureView,
|
||||
// TODO: rename
|
||||
tgt_color_pp: wgpu::TextureView,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
/// Shadow rendering textures, layouts, pipelines, and bind groups
|
||||
struct Shadow {
|
||||
map: ShadowMap,
|
||||
bind: ShadowTexturesBindGroup,
|
||||
}
|
||||
|
||||
/// A type that encapsulates rendering state. `Renderer` is central to Voxygen's
|
||||
@ -242,51 +88,28 @@ impl Locals {
|
||||
pub struct Renderer {
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
surface: wgpu::Surface,
|
||||
swap_chain: wgpu::SwapChain,
|
||||
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,
|
||||
depth_sampler: wgpu::Sampler,
|
||||
|
||||
shadow_map: ShadowMap,
|
||||
shadow_bind: ShadowTexturesBindGroup,
|
||||
|
||||
layouts: Layouts,
|
||||
|
||||
figure_pipeline: figure::FigurePipeline,
|
||||
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>,
|
||||
|
||||
pipelines: Pipelines,
|
||||
shadow: Shadow,
|
||||
// Note: we keep these here since their bind groups need to be updated if we resize the
|
||||
// color/depth textures
|
||||
locals: Locals,
|
||||
|
||||
views: Views,
|
||||
noise_tex: Texture,
|
||||
|
||||
mode: RenderMode,
|
||||
shaders: AssetHandle<Shaders>,
|
||||
|
||||
mode: RenderMode,
|
||||
resolution: Vec2<u32>,
|
||||
|
||||
tracer: super::time::GpuTracer<spans::Id>,
|
||||
profiler: wgpu_profiler::GpuProfiler,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
@ -334,7 +157,10 @@ impl Renderer {
|
||||
features: wgpu::Features::DEPTH_CLAMPING
|
||||
| wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER
|
||||
| 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,
|
||||
},
|
||||
None,
|
||||
@ -399,16 +225,7 @@ impl Renderer {
|
||||
};
|
||||
|
||||
let (
|
||||
skybox_pipeline,
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
lod_terrain_pipeline,
|
||||
clouds_pipeline,
|
||||
postprocess_pipeline,
|
||||
pipelines,
|
||||
//player_shadow_pipeline,
|
||||
point_shadow_pipeline,
|
||||
terrain_directed_shadow_pipeline,
|
||||
@ -422,8 +239,7 @@ impl Renderer {
|
||||
shadow_views.is_some(),
|
||||
)?;
|
||||
|
||||
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 views = Self::create_rt_views(&device, (dims.width, dims.height), &mode)?;
|
||||
|
||||
let shadow_map = if let (
|
||||
Some(point_pipeline),
|
||||
@ -467,6 +283,11 @@ impl Renderer {
|
||||
.bind_shadow_textures(&device, point, directed)
|
||||
};
|
||||
|
||||
let shadow = Shadow {
|
||||
map: shadow_map,
|
||||
bind: shadow_bind,
|
||||
};
|
||||
|
||||
let create_sampler = |filter| {
|
||||
device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
label: None,
|
||||
@ -502,78 +323,52 @@ impl Renderer {
|
||||
&layouts,
|
||||
clouds_locals,
|
||||
postprocess_locals,
|
||||
&tgt_color_view,
|
||||
&tgt_depth_view,
|
||||
&tgt_color_pp_view,
|
||||
&views.tgt_color,
|
||||
&views.tgt_depth,
|
||||
&views.tgt_color_pp,
|
||||
&sampler,
|
||||
&depth_sampler,
|
||||
);
|
||||
|
||||
let tracer =
|
||||
super::time::GpuTracer::new(&device, &queue, "voxygen_gpu_chrome_trace.json").unwrap();
|
||||
let mut profiler = wgpu_profiler::GpuProfiler::new(4, queue.get_timestamp_period());
|
||||
profiler.enable_timer = mode.profiler_enabled;
|
||||
profiler.enable_debug_marker = mode.profiler_enabled;
|
||||
|
||||
Ok(Self {
|
||||
device,
|
||||
queue,
|
||||
surface,
|
||||
swap_chain,
|
||||
sc_desc,
|
||||
surface,
|
||||
|
||||
win_depth_view,
|
||||
|
||||
tgt_color_view,
|
||||
tgt_depth_view,
|
||||
tgt_color_pp_view,
|
||||
layouts,
|
||||
pipelines,
|
||||
shadow,
|
||||
locals,
|
||||
views,
|
||||
|
||||
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,
|
||||
|
||||
mode,
|
||||
shaders,
|
||||
|
||||
mode,
|
||||
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.
|
||||
pub fn set_render_mode(&mut self, mode: RenderMode) -> Result<(), RenderError> {
|
||||
self.mode = mode;
|
||||
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
|
||||
self.on_resize(self.resolution)?;
|
||||
|
||||
@ -597,31 +392,26 @@ 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_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_view = tgt_depth_view;
|
||||
self.tgt_color_pp_view = tgt_color_pp_view;
|
||||
self.views = Self::create_rt_views(&mut self.device, (dims.x, dims.y), &self.mode)?;
|
||||
// Rebind views to clouds/postprocess bind groups
|
||||
self.locals.rebind(
|
||||
&self.device,
|
||||
&self.layouts,
|
||||
&self.tgt_color_view,
|
||||
&self.tgt_depth_view,
|
||||
&self.tgt_color_pp_view,
|
||||
&self.views.tgt_color,
|
||||
&self.views.tgt_depth,
|
||||
&self.views.tgt_color_pp,
|
||||
&self.sampler,
|
||||
&self.depth_sampler,
|
||||
);
|
||||
|
||||
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) {
|
||||
Ok((point_depth, directed_depth)) => {
|
||||
shadow_map.point_depth = point_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,
|
||||
&shadow_map.point_depth,
|
||||
&shadow_map.directed_depth,
|
||||
@ -637,19 +427,12 @@ impl Renderer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create render target views
|
||||
fn create_rt_views(
|
||||
device: &wgpu::Device,
|
||||
size: (u32, u32),
|
||||
mode: &RenderMode,
|
||||
) -> Result<
|
||||
(
|
||||
wgpu::TextureView,
|
||||
wgpu::TextureView,
|
||||
wgpu::TextureView,
|
||||
wgpu::TextureView,
|
||||
),
|
||||
RenderError,
|
||||
> {
|
||||
) -> Result<Views, RenderError> {
|
||||
let upscaled = Vec2::<u32>::from(size)
|
||||
.map(|e| (e as f32 * mode.upscale_mode.factor) as u32)
|
||||
.into_tuple();
|
||||
@ -743,12 +526,12 @@ impl Renderer {
|
||||
array_layer_count: None,
|
||||
});
|
||||
|
||||
Ok((
|
||||
tgt_color_view,
|
||||
tgt_depth_view,
|
||||
tgt_color_pp_view,
|
||||
win_depth_view,
|
||||
))
|
||||
Ok(Views {
|
||||
tgt_color: tgt_color_view,
|
||||
tgt_depth: tgt_depth_view,
|
||||
tgt_color_pp: tgt_color_pp_view,
|
||||
win_depth: win_depth_view,
|
||||
})
|
||||
}
|
||||
|
||||
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.
|
||||
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.directed_depth.get_dimensions().xy(),
|
||||
@ -993,7 +776,6 @@ impl Renderer {
|
||||
/// 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
|
||||
/// available.
|
||||
#[allow(unsafe_code)]
|
||||
fn enable_seamless_cube_maps() {
|
||||
todo!()
|
||||
// unsafe {
|
||||
@ -1072,34 +854,16 @@ impl Renderer {
|
||||
&self.shaders.read(),
|
||||
&self.mode,
|
||||
&self.sc_desc,
|
||||
self.shadow_map.is_enabled(),
|
||||
self.shadow.map.is_enabled(),
|
||||
) {
|
||||
Ok((
|
||||
skybox_pipeline,
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
lod_terrain_pipeline,
|
||||
clouds_pipeline,
|
||||
postprocess_pipeline,
|
||||
pipelines,
|
||||
//player_shadow_pipeline,
|
||||
point_shadow_pipeline,
|
||||
terrain_directed_shadow_pipeline,
|
||||
figure_directed_shadow_pipeline,
|
||||
)) => {
|
||||
self.skybox_pipeline = skybox_pipeline;
|
||||
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.pipelines = pipelines;
|
||||
//self.player_shadow_pipeline = player_shadow_pipeline;
|
||||
if let (
|
||||
Some(point_pipeline),
|
||||
@ -1110,7 +874,7 @@ impl Renderer {
|
||||
point_shadow_pipeline,
|
||||
terrain_directed_shadow_pipeline,
|
||||
figure_directed_shadow_pipeline,
|
||||
&mut self.shadow_map,
|
||||
&mut self.shadow.map,
|
||||
) {
|
||||
shadow_map.point_pipeline = point_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
|
||||
/// a image::DynamicImage.
|
||||
#[allow(clippy::map_clone)] // TODO: Pending review in #587
|
||||
pub fn create_screenshot(&mut self) -> Result<image::DynamicImage, RenderError> {
|
||||
todo!()
|
||||
//pub fn create_screenshot(&mut self) -> Result<image::DynamicImage,
|
||||
// RenderError> {
|
||||
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 download_buf = self
|
||||
@ -2042,7 +1831,6 @@ impl Renderer {
|
||||
}
|
||||
|
||||
/// Creates all the pipelines used to render.
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
fn create_pipelines(
|
||||
device: &wgpu::Device,
|
||||
layouts: &Layouts,
|
||||
@ -2052,16 +1840,7 @@ fn create_pipelines(
|
||||
has_shadow_views: bool,
|
||||
) -> Result<
|
||||
(
|
||||
skybox::SkyboxPipeline,
|
||||
figure::FigurePipeline,
|
||||
terrain::TerrainPipeline,
|
||||
fluid::FluidPipeline,
|
||||
sprite::SpritePipeline,
|
||||
particle::ParticlePipeline,
|
||||
ui::UiPipeline,
|
||||
lod_terrain::LodTerrainPipeline,
|
||||
clouds::CloudsPipeline,
|
||||
postprocess::PostProcessPipeline,
|
||||
Pipelines,
|
||||
//figure::FigurePipeline,
|
||||
Option<shadow::PointShadowPipeline>,
|
||||
Option<shadow::ShadowPipeline>,
|
||||
@ -2351,16 +2130,18 @@ fn create_pipelines(
|
||||
);
|
||||
|
||||
Ok((
|
||||
skybox_pipeline,
|
||||
figure_pipeline,
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
lod_terrain_pipeline,
|
||||
clouds_pipeline,
|
||||
postprocess_pipeline,
|
||||
Pipelines {
|
||||
skybox: skybox_pipeline,
|
||||
figure: figure_pipeline,
|
||||
terrain: terrain_pipeline,
|
||||
fluid: fluid_pipeline,
|
||||
sprite: sprite_pipeline,
|
||||
particle: particle_pipeline,
|
||||
ui: ui_pipeline,
|
||||
lod_terrain: lod_terrain_pipeline,
|
||||
clouds: clouds_pipeline,
|
||||
postprocess: postprocess_pipeline,
|
||||
},
|
||||
// player_shadow_pipeline,
|
||||
Some(point_shadow_pipeline),
|
||||
Some(terrain_directed_shadow_pipeline),
|
||||
|
@ -8,69 +8,89 @@ use super::{
|
||||
clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite,
|
||||
terrain, ui, ColLights, GlobalsBindGroup, Light, Shadow,
|
||||
},
|
||||
scope::{ManualOwningScope, OwningScope, Scope},
|
||||
},
|
||||
spans::{self, OwningSpan, Span},
|
||||
Renderer, ShadowMap, ShadowMapRenderer,
|
||||
};
|
||||
use core::{num::NonZeroU32, ops::Range};
|
||||
use std::sync::Arc;
|
||||
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> {
|
||||
encoder: Option<wgpu::CommandEncoder>,
|
||||
pub renderer: &'frame mut Renderer,
|
||||
tex: wgpu::SwapChainTexture,
|
||||
encoder: Option<ManualOwningScope<'frame, wgpu::CommandEncoder>>,
|
||||
borrow: RendererBorrow<'frame>,
|
||||
swap_tex: wgpu::SwapChainTexture,
|
||||
globals: &'frame GlobalsBindGroup,
|
||||
}
|
||||
|
||||
impl<'frame> Drawer<'frame> {
|
||||
pub fn new(
|
||||
mut encoder: wgpu::CommandEncoder,
|
||||
encoder: wgpu::CommandEncoder,
|
||||
renderer: &'frame mut Renderer,
|
||||
tex: wgpu::SwapChainTexture,
|
||||
swap_tex: wgpu::SwapChainTexture,
|
||||
globals: &'frame GlobalsBindGroup,
|
||||
) -> 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 {
|
||||
encoder: Some(encoder),
|
||||
renderer,
|
||||
tex,
|
||||
borrow,
|
||||
swap_tex,
|
||||
globals,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
|
||||
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map {
|
||||
let mut render_pass =
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("shadow pass"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &shadow_renderer.directed_depth.view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
/// Get the render mode.
|
||||
pub fn render_mode(&self) -> &super::super::RenderMode { self.borrow.mode }
|
||||
|
||||
pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
|
||||
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 =
|
||||
encoder.scoped_render_pass(device, "shadow_pass", &wgpu::RenderPassDescriptor {
|
||||
label: Some("shadow pass"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &shadow_renderer.directed_depth.view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
let mut render_pass = OwningSpan::start(
|
||||
&self.renderer.tracer,
|
||||
render_pass,
|
||||
spans::Id::DirectedShadows,
|
||||
);
|
||||
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
|
||||
|
||||
Some(ShadowPassDrawer {
|
||||
render_pass,
|
||||
renderer: &self.renderer,
|
||||
borrow: &self.borrow,
|
||||
shadow_renderer,
|
||||
})
|
||||
} else {
|
||||
@ -79,101 +99,86 @@ impl<'frame> Drawer<'frame> {
|
||||
}
|
||||
|
||||
pub fn first_pass(&mut self) -> FirstPassDrawer {
|
||||
let render_pass =
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("first pass"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.renderer.tgt_color_view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &self.renderer.tgt_depth_view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(0.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
let encoder = self.encoder.as_mut().unwrap();
|
||||
let device = self.borrow.device;
|
||||
let mut render_pass =
|
||||
OwningSpan::start(&self.renderer.tracer, render_pass, spans::Id::PassOne);
|
||||
encoder.scoped_render_pass(device, "first_pass", &wgpu::RenderPassDescriptor {
|
||||
label: Some("first pass"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.borrow.views.tgt_color,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &self.borrow.views.tgt_depth,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(0.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
});
|
||||
|
||||
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 {
|
||||
render_pass,
|
||||
renderer: &self.renderer,
|
||||
figures_called: false,
|
||||
borrow: &self.borrow,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn second_pass(&mut self) -> SecondPassDrawer {
|
||||
let render_pass =
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("second pass (clouds)"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.renderer.tgt_color_pp_view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
let encoder = self.encoder.as_mut().unwrap();
|
||||
let device = self.borrow.device;
|
||||
let mut render_pass =
|
||||
OwningSpan::start(&self.renderer.tracer, render_pass, spans::Id::PassTwo);
|
||||
encoder.scoped_render_pass(device, "second_pass", &wgpu::RenderPassDescriptor {
|
||||
label: Some("second pass (clouds)"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.borrow.views.tgt_color_pp,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
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 {
|
||||
render_pass,
|
||||
renderer: &self.renderer,
|
||||
borrow: &self.borrow,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn third_pass(&mut self) -> ThirdPassDrawer {
|
||||
let render_pass =
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("third pass (postprocess + ui)"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.tex.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
let encoder = self.encoder.as_mut().unwrap();
|
||||
let device = self.borrow.device;
|
||||
let mut render_pass =
|
||||
OwningSpan::start(&self.renderer.tracer, render_pass, spans::Id::PassThree);
|
||||
encoder.scoped_render_pass(device, "third_pass", &wgpu::RenderPassDescriptor {
|
||||
label: Some("third pass (postprocess + ui)"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &self.swap_tex.view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: true,
|
||||
},
|
||||
}],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
|
||||
|
||||
ThirdPassDrawer {
|
||||
render_pass,
|
||||
renderer: &self.renderer,
|
||||
borrow: &self.borrow,
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,10 +188,13 @@ impl<'frame> Drawer<'frame> {
|
||||
chunks: impl Clone
|
||||
+ Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
|
||||
) {
|
||||
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map {
|
||||
self.renderer
|
||||
.tracer
|
||||
.start_span(self.encoder.as_mut().unwrap(), &spans::Id::PointShadows);
|
||||
if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow.map {
|
||||
let device = self.borrow.device;
|
||||
let mut encoder = self
|
||||
.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.scope(device, "point shadows");
|
||||
const STRIDE: usize = std::mem::size_of::<shadow::PointLightMatrix>();
|
||||
let data = bytemuck::cast_slice(matrices);
|
||||
|
||||
@ -209,23 +217,20 @@ impl<'frame> Drawer<'frame> {
|
||||
|
||||
let label = format!("point shadow face-{} pass", face);
|
||||
let mut render_pass =
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some(&label),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
encoder.scoped_render_pass(device, &label, &wgpu::RenderPassDescriptor {
|
||||
label: Some(&label),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&shadow_renderer.point_pipeline.pipeline);
|
||||
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
|
||||
@ -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
|
||||
/// simply for clearing
|
||||
pub fn clear_shadows(&mut self) {
|
||||
if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map {
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
if let ShadowMap::Enabled(ref shadow_renderer) = self.borrow.shadow.map {
|
||||
let device = self.borrow.device;
|
||||
let encoder = self.encoder.as_mut().unwrap();
|
||||
encoder.scoped_render_pass(
|
||||
device,
|
||||
"clear_directed_shadow",
|
||||
&wgpu::RenderPassDescriptor {
|
||||
label: Some("clear directed shadow pass"),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
@ -275,7 +279,8 @@ impl<'frame> Drawer<'frame> {
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
for face in 0..6 {
|
||||
// TODO: view creation cost?
|
||||
@ -295,23 +300,20 @@ impl<'frame> Drawer<'frame> {
|
||||
});
|
||||
|
||||
let label = format!("clear point shadow face-{} pass", face);
|
||||
self.encoder
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some(&label),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
encoder.scoped_render_pass(device, &label, &wgpu::RenderPassDescriptor {
|
||||
label: Some(&label),
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(
|
||||
wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &view,
|
||||
depth_ops: Some(wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
},
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,47 +323,38 @@ impl<'frame> Drop for Drawer<'frame> {
|
||||
fn drop(&mut self) {
|
||||
// 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?
|
||||
self.renderer
|
||||
.tracer
|
||||
.end_span(self.encoder.as_mut().unwrap(), &spans::Id::Frame);
|
||||
self.renderer
|
||||
.tracer
|
||||
.resolve_timestamps(self.encoder.as_mut().unwrap());
|
||||
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)
|
||||
let (mut encoder, profiler) = self.encoder.take().unwrap().end_scope();
|
||||
profiler.resolve_queries(&mut encoder);
|
||||
self.borrow.queue.submit(std::iter::once(encoder.finish()));
|
||||
profiler
|
||||
.end_frame()
|
||||
.expect("Gpu profiler error! Maybe there was an unclosed scope?");
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow pass
|
||||
pub struct ShadowPassDrawer<'pass> {
|
||||
render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>,
|
||||
pub renderer: &'pass Renderer,
|
||||
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
|
||||
borrow: &'pass RendererBorrow<'pass>,
|
||||
shadow_renderer: &'pass ShadowMapRenderer,
|
||||
}
|
||||
|
||||
impl<'pass> ShadowPassDrawer<'pass> {
|
||||
pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::DirectedFigureShadows,
|
||||
);
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope(self.borrow.device, "direcred_figure_shadows");
|
||||
|
||||
render_pass.set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline);
|
||||
|
||||
FigureShadowDrawer { render_pass }
|
||||
}
|
||||
|
||||
pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::DirectedTerrainShadows,
|
||||
);
|
||||
let mut render_pass = self
|
||||
.render_pass
|
||||
.scope(self.borrow.device, "direcred_terrain_shadows");
|
||||
|
||||
render_pass.set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline);
|
||||
|
||||
TerrainShadowDrawer { render_pass }
|
||||
@ -369,7 +362,7 @@ impl<'pass> ShadowPassDrawer<'pass> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -385,7 +378,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -402,73 +395,50 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
|
||||
|
||||
// First pass
|
||||
pub struct FirstPassDrawer<'pass> {
|
||||
pub(super) render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>,
|
||||
pub renderer: &'pass Renderer,
|
||||
// TODO: hack
|
||||
figures_called: bool,
|
||||
pub(super) render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
|
||||
borrow: &'pass RendererBorrow<'pass>,
|
||||
}
|
||||
|
||||
impl<'pass> FirstPassDrawer<'pass> {
|
||||
pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model<skybox::Vertex>) {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::Skybox,
|
||||
);
|
||||
render_pass.set_pipeline(&self.renderer.skybox_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "skybox");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.skybox.pipeline);
|
||||
render_pass.set_vertex_buffer(0, model.buf().slice(..));
|
||||
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>) {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::Lod,
|
||||
);
|
||||
render_pass.set_pipeline(&self.renderer.lod_terrain_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "lod_terrain");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.lod_terrain.pipeline);
|
||||
render_pass.set_vertex_buffer(0, model.buf().slice(..));
|
||||
render_pass.draw(0..model.len() as u32, 0..1);
|
||||
}
|
||||
|
||||
pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
if !self.figures_called {
|
||||
spans::Id::Figures1
|
||||
} else {
|
||||
spans::Id::Figures2
|
||||
},
|
||||
);
|
||||
self.figures_called = true;
|
||||
render_pass.set_pipeline(&self.renderer.figure_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "figures");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.figure.pipeline);
|
||||
|
||||
FigureDrawer { render_pass }
|
||||
}
|
||||
|
||||
pub fn draw_terrain<'data: 'pass>(&mut self) -> TerrainDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::Terrain,
|
||||
);
|
||||
render_pass.set_pipeline(&self.renderer.terrain_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "terrain");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.terrain.pipeline);
|
||||
|
||||
TerrainDrawer {
|
||||
render_pass,
|
||||
|
||||
col_lights: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::Particles,
|
||||
);
|
||||
render_pass.set_pipeline(&self.renderer.particle_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "particles");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.particle.pipeline);
|
||||
|
||||
ParticleDrawer { render_pass }
|
||||
}
|
||||
@ -477,15 +447,10 @@ impl<'pass> FirstPassDrawer<'pass> {
|
||||
&mut self,
|
||||
col_lights: &'data ColLights<sprite::Locals>,
|
||||
) -> SpriteDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::Sprites,
|
||||
);
|
||||
self.render_pass
|
||||
.set_pipeline(&self.renderer.sprite_pipeline.pipeline);
|
||||
self.render_pass
|
||||
.set_bind_group(4, &col_lights.bind_group, &[]);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "sprites");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.sprite.pipeline);
|
||||
render_pass.set_bind_group(4, &col_lights.bind_group, &[]);
|
||||
|
||||
SpriteDrawer { render_pass }
|
||||
}
|
||||
@ -494,12 +459,9 @@ impl<'pass> FirstPassDrawer<'pass> {
|
||||
&mut self,
|
||||
waves: &'data fluid::BindGroup,
|
||||
) -> FluidDrawer<'_, 'pass> {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
spans::Id::Fluid,
|
||||
);
|
||||
render_pass.set_pipeline(&self.renderer.fluid_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "fluid");
|
||||
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.fluid.pipeline);
|
||||
render_pass.set_bind_group(2, &waves.bind_group, &[]);
|
||||
|
||||
FluidDrawer { render_pass }
|
||||
@ -507,7 +469,7 @@ impl<'pass> FirstPassDrawer<'pass> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -527,7 +489,7 @@ impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> {
|
||||
}
|
||||
|
||||
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>>>,
|
||||
}
|
||||
|
||||
@ -559,7 +521,7 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -580,7 +542,7 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -617,7 +579,7 @@ impl<'pass_ref, 'pass: 'pass_ref> ChunkSpriteDrawer<'pass_ref, 'pass> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -634,49 +596,44 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
|
||||
|
||||
// Second pass: clouds
|
||||
pub struct SecondPassDrawer<'pass> {
|
||||
render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>,
|
||||
renderer: &'pass Renderer,
|
||||
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
|
||||
borrow: &'pass RendererBorrow<'pass>,
|
||||
}
|
||||
|
||||
impl<'pass> SecondPassDrawer<'pass> {
|
||||
pub fn draw_clouds(&mut self) {
|
||||
self.render_pass
|
||||
.set_pipeline(&self.renderer.clouds_pipeline.pipeline);
|
||||
.set_pipeline(&self.borrow.pipelines.clouds.pipeline);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Third pass: postprocess + ui
|
||||
pub struct ThirdPassDrawer<'pass> {
|
||||
render_pass: OwningSpan<'pass, wgpu::RenderPass<'pass>>,
|
||||
renderer: &'pass Renderer,
|
||||
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
|
||||
borrow: &'pass RendererBorrow<'pass>,
|
||||
}
|
||||
|
||||
impl<'pass> ThirdPassDrawer<'pass> {
|
||||
pub fn draw_post_process(&mut self) {
|
||||
let mut render_pass = Span::start(
|
||||
&self.renderer.tracer,
|
||||
&mut *self.render_pass,
|
||||
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, &[]);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "postprocess");
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.postprocess.pipeline);
|
||||
render_pass.set_bind_group(1, &self.borrow.locals.postprocess_bind.bind_group, &[]);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
pub fn draw_ui(&mut self) -> UiDrawer<'_, 'pass> {
|
||||
let mut render_pass =
|
||||
Span::start(&self.renderer.tracer, &mut *self.render_pass, spans::Id::Ui);
|
||||
render_pass.set_pipeline(&self.renderer.ui_pipeline.pipeline);
|
||||
let mut render_pass = self.render_pass.scope(self.borrow.device, "ui");
|
||||
render_pass.set_pipeline(&self.borrow.pipelines.ui.pipeline);
|
||||
|
||||
UiDrawer { render_pass }
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
|
75
voxygen/src/render/renderer/locals.rs
Normal file
75
voxygen/src/render/renderer/locals.rs
Normal 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);
|
||||
}
|
||||
}
|
91
voxygen/src/render/renderer/shaders.rs
Normal file
91
voxygen/src/render/renderer/shaders.rs
Normal 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())
|
||||
}
|
||||
}
|
38
voxygen/src/render/renderer/shadow_map.rs
Normal file
38
voxygen/src/render/renderer/shadow_map.rs
Normal 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
165
voxygen/src/render/scope.rs
Normal 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 }
|
||||
}
|
@ -1048,9 +1048,7 @@ impl Scene {
|
||||
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
|
||||
|
||||
// would instead have this as an extension.
|
||||
if drawer.renderer.render_mode().shadow.is_map()
|
||||
&& (is_daylight || !self.light_data.is_empty())
|
||||
{
|
||||
if drawer.render_mode().shadow.is_map() && (is_daylight || !self.light_data.is_empty()) {
|
||||
if is_daylight {
|
||||
if let Some(mut shadow_pass) = drawer.shadow_pass() {
|
||||
// Render terrain directed shadows.
|
||||
|
@ -516,7 +516,7 @@ impl SpriteRenderContext {
|
||||
.into_iter()
|
||||
.map(
|
||||
|SpriteDataResponse {
|
||||
locals,
|
||||
locals: locals_buffer,
|
||||
model,
|
||||
offset,
|
||||
}| {
|
||||
|
@ -10,7 +10,6 @@ use gilrs::{EventType, Gilrs};
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use keyboard_keynames::key_layout::KeyLayout;
|
||||
use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{error, warn};
|
||||
use vek::*;
|
||||
@ -941,6 +940,9 @@ impl Window {
|
||||
let winit::dpi::PhysicalSize { width, height } = physical;
|
||||
self.events
|
||||
.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, .. } => {
|
||||
// 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 take_screenshot(&mut self, settings: &Settings) {
|
||||
match self.renderer.create_screenshot() {
|
||||
let _ = self.renderer.create_screenshot();
|
||||
// TODO
|
||||
/*match self.renderer.create_screenshot() {
|
||||
Ok(img) => {
|
||||
let mut path = settings.screenshots_path.clone();
|
||||
let sender = self.message_sender.clone();
|
||||
@ -1377,7 +1381,7 @@ impl Window {
|
||||
.unwrap();
|
||||
},
|
||||
Err(e) => error!(?e, "Couldn't create screenshot due to renderer error"),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
fn is_pressed(
|
||||
|
Loading…
Reference in New Issue
Block a user