mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Make bloom optional with a config option that is not exposed in the UI (to give artists time to refine bloom before exposing the option)
This commit is contained in:
parent
bfdee903dd
commit
6cabd74871
@ -5,7 +5,7 @@ uniform texture2D t_src_color;
|
||||
layout(set = 0, binding = 1)
|
||||
uniform sampler s_src_color;
|
||||
layout(set = 0, binding = 2)
|
||||
// TODO: refactor in rust
|
||||
|
||||
uniform u_locals {
|
||||
vec2 halfpixel;
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ uniform texture2D t_src_color;
|
||||
layout(set = 0, binding = 1)
|
||||
uniform sampler s_src_color;
|
||||
layout(set = 0, binding = 2)
|
||||
// TODO: refactor in rust
|
||||
|
||||
uniform u_locals {
|
||||
vec2 halfpixel;
|
||||
};
|
||||
|
@ -198,7 +198,7 @@ void main() {
|
||||
// For now, just make glowing material light be the same colour as the surface
|
||||
// TODO: Add a way to control this better outside the shaders
|
||||
if ((material & (1u << 0u)) > 0u) {
|
||||
emitted_light += 10 * surf_color;
|
||||
emitted_light += 20 * surf_color;
|
||||
}
|
||||
|
||||
float glow_mag = length(model_glow.xyz);
|
||||
|
@ -24,6 +24,9 @@
|
||||
#define SHADOW_MODE_CHEAP 1
|
||||
#define SHADOW_MODE_MAP 2
|
||||
|
||||
#define BLOOM_DISABLED 0
|
||||
#define BLOOM_ENABLED 1
|
||||
|
||||
/* Unlike the other flags (for now anyway), these are bitmask values */
|
||||
#define LIGHTING_TYPE_REFLECTION 0x01
|
||||
#define LIGHTING_TYPE_TRANSMISSION 0x02
|
||||
|
@ -25,19 +25,21 @@
|
||||
layout(set = 1, binding = 0)
|
||||
uniform texture2D t_src_color;
|
||||
layout(set = 1, binding = 1)
|
||||
uniform texture2D t_src_bloom;
|
||||
layout(set = 1, binding = 2)
|
||||
uniform sampler s_src_color;
|
||||
|
||||
|
||||
layout(location = 0) in vec2 uv;
|
||||
|
||||
layout (std140, set = 1, binding = 3)
|
||||
layout (std140, set = 1, binding = 2)
|
||||
uniform u_locals {
|
||||
mat4 proj_mat_inv;
|
||||
mat4 view_mat_inv;
|
||||
};
|
||||
|
||||
#if (BLOOM == BLOOM_ENABLED)
|
||||
layout(set = 1, binding = 3)
|
||||
uniform texture2D t_src_bloom;
|
||||
#endif
|
||||
|
||||
layout(location = 0) out vec4 tgt_color;
|
||||
|
||||
vec3 rgb2hsv(vec3 c) {
|
||||
@ -185,10 +187,12 @@ void main() {
|
||||
vec4 aa_color = aa_apply(t_src_color, s_src_color, uv * screen_res.xy, screen_res.xy);
|
||||
|
||||
// Bloom
|
||||
#if (BLOOM == BLOOM_ENABLED)
|
||||
// divide by 4.0 to account for adding blurred layers together
|
||||
vec4 bloom = textureLod(sampler2D(t_src_bloom, s_src_color), uv, 0) / 4.0;
|
||||
float bloom_factor = 0.10;
|
||||
aa_color = aa_color * (1.0 - bloom_factor) + bloom * bloom_factor;
|
||||
aa_color = mix(aa_color, bloom, bloom_factor);
|
||||
#endif
|
||||
|
||||
// Tonemapping
|
||||
float exposure_offset = 1.0;
|
||||
|
@ -257,11 +257,8 @@ impl PlayState for CharSelectionState {
|
||||
if let Some(mut second_pass) = drawer.second_pass() {
|
||||
second_pass.draw_clouds();
|
||||
}
|
||||
// Bloom
|
||||
// TODO: make optional
|
||||
{
|
||||
drawer.run_bloom_passes()
|
||||
}
|
||||
// Bloom (does nothing if bloom is disabled)
|
||||
drawer.run_bloom_passes();
|
||||
// PostProcess and UI
|
||||
let mut third_pass = drawer.third_pass();
|
||||
third_pass.draw_postprocess();
|
||||
|
@ -274,7 +274,49 @@ pub struct RenderMode {
|
||||
pub fluid: FluidMode,
|
||||
pub lighting: LightingMode,
|
||||
pub shadow: ShadowMode,
|
||||
pub bloom: bool,
|
||||
|
||||
pub upscale_mode: UpscaleMode,
|
||||
pub present_mode: PresentMode,
|
||||
pub profiler_enabled: bool,
|
||||
}
|
||||
|
||||
impl RenderMode {
|
||||
fn split(self) -> (PipelineModes, OtherModes) {
|
||||
(
|
||||
PipelineModes {
|
||||
aa: self.aa,
|
||||
cloud: self.cloud,
|
||||
fluid: self.fluid,
|
||||
lighting: self.lighting,
|
||||
shadow: self.shadow,
|
||||
bloom: self.bloom,
|
||||
},
|
||||
OtherModes {
|
||||
upscale_mode: self.upscale_mode,
|
||||
present_mode: self.present_mode,
|
||||
profiler_enabled: self.profiler_enabled,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Render modes that require pipeline recreation (e.g. shader recompilation)
|
||||
/// when changed
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub struct PipelineModes {
|
||||
aa: AaMode,
|
||||
cloud: CloudMode,
|
||||
fluid: FluidMode,
|
||||
lighting: LightingMode,
|
||||
pub shadow: ShadowMode,
|
||||
bloom: bool,
|
||||
}
|
||||
|
||||
/// Other render modes that don't effect pipelines
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
struct OtherModes {
|
||||
upscale_mode: UpscaleMode,
|
||||
present_mode: PresentMode,
|
||||
profiler_enabled: bool,
|
||||
}
|
||||
|
@ -18,11 +18,15 @@ pub struct BindGroup {
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||
pub struct HalfPixel([f32; 2]);
|
||||
pub struct Locals {
|
||||
halfpixel: [f32; 2],
|
||||
}
|
||||
|
||||
impl HalfPixel {
|
||||
impl Locals {
|
||||
pub fn new(source_texture_resolution: Vec2<f32>) -> Self {
|
||||
Self(source_texture_resolution.map(|e| 0.5 / e).into_array())
|
||||
Self {
|
||||
halfpixel: source_texture_resolution.map(|e| 0.5 / e).into_array(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +81,7 @@ impl BloomLayout {
|
||||
device: &wgpu::Device,
|
||||
src_color: &wgpu::TextureView,
|
||||
sampler: &wgpu::Sampler,
|
||||
half_pixel: Consts<HalfPixel>,
|
||||
half_pixel: Consts<Locals>,
|
||||
) -> BindGroup {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::super::{Consts, GlobalsLayouts};
|
||||
use super::super::{Consts, GlobalsLayouts, PipelineModes};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use vek::*;
|
||||
|
||||
@ -31,55 +31,61 @@ pub struct PostProcessLayout {
|
||||
}
|
||||
|
||||
impl PostProcessLayout {
|
||||
pub fn new(device: &wgpu::Device) -> Self {
|
||||
pub fn new(device: &wgpu::Device, pipeline_modes: &PipelineModes) -> Self {
|
||||
let mut bind_entries = vec![
|
||||
// src color
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
filtering: true,
|
||||
comparison: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// Locals
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 2,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
];
|
||||
|
||||
if pipeline_modes.bloom {
|
||||
bind_entries.push(
|
||||
// src bloom
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 3,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Self {
|
||||
layout: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: None,
|
||||
entries: &[
|
||||
// src color
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// TODO: make optional
|
||||
// src bloom
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 2,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler {
|
||||
filtering: true,
|
||||
comparison: false,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
// Locals
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 3,
|
||||
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
entries: &bind_entries,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -88,35 +94,42 @@ impl PostProcessLayout {
|
||||
&self,
|
||||
device: &wgpu::Device,
|
||||
src_color: &wgpu::TextureView,
|
||||
src_bloom: &wgpu::TextureView,
|
||||
src_bloom: Option<&wgpu::TextureView>,
|
||||
sampler: &wgpu::Sampler,
|
||||
locals: &Consts<Locals>,
|
||||
) -> BindGroup {
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &self.layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(src_color),
|
||||
},
|
||||
let mut entries = vec![
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(src_color),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(sampler),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: locals.buf().as_entire_binding(),
|
||||
},
|
||||
];
|
||||
// Optional bloom source
|
||||
if let Some(src_bloom) = src_bloom {
|
||||
entries.push(
|
||||
// TODO: might be cheaper to premix bloom at lower resolution if we are doing
|
||||
// extensive upscaling
|
||||
// TODO: if there is no upscaling we can do the last bloom upsampling in post
|
||||
// process to save a pass and the need for the final full size bloom render target
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
binding: 3,
|
||||
resource: wgpu::BindingResource::TextureView(src_bloom),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: wgpu::BindingResource::Sampler(sampler),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 3,
|
||||
resource: locals.buf().as_entire_binding(),
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &self.layout,
|
||||
entries: &entries,
|
||||
});
|
||||
|
||||
BindGroup { bind_group }
|
||||
|
@ -25,7 +25,8 @@ use super::{
|
||||
GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup,
|
||||
},
|
||||
texture::Texture,
|
||||
AaMode, AddressMode, FilterMode, RenderError, RenderMode, ShadowMapMode, ShadowMode, Vertex,
|
||||
AaMode, AddressMode, FilterMode, OtherModes, PipelineModes, RenderError, RenderMode,
|
||||
ShadowMapMode, ShadowMode, Vertex,
|
||||
};
|
||||
use common::assets::{self, AssetExt, AssetHandle};
|
||||
use common_base::span;
|
||||
@ -45,8 +46,9 @@ pub type ColLightInfo = (Vec<[u8; 4]>, Vec2<u16>);
|
||||
const QUAD_INDEX_BUFFER_U16_START_VERT_LEN: u16 = 3000;
|
||||
const QUAD_INDEX_BUFFER_U32_START_VERT_LEN: u32 = 3000;
|
||||
|
||||
/// A type that stores all the layouts associated with this renderer.
|
||||
struct Layouts {
|
||||
/// A type that stores all the layouts associated with this renderer that never
|
||||
/// change when the RenderMode is modified.
|
||||
struct ImmutableLayouts {
|
||||
global: GlobalsLayouts,
|
||||
|
||||
debug: debug::DebugLayout,
|
||||
@ -56,11 +58,23 @@ struct Layouts {
|
||||
terrain: terrain::TerrainLayout,
|
||||
clouds: clouds::CloudsLayout,
|
||||
bloom: bloom::BloomLayout,
|
||||
postprocess: postprocess::PostProcessLayout,
|
||||
ui: ui::UiLayout,
|
||||
blit: blit::BlitLayout,
|
||||
}
|
||||
|
||||
/// A type that stores all the layouts associated with this renderer.
|
||||
struct Layouts {
|
||||
immutable: Arc<ImmutableLayouts>,
|
||||
|
||||
postprocess: Arc<postprocess::PostProcessLayout>,
|
||||
}
|
||||
|
||||
impl core::ops::Deref for Layouts {
|
||||
type Target = ImmutableLayouts;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.immutable }
|
||||
}
|
||||
|
||||
/// Render target views
|
||||
struct Views {
|
||||
// NOTE: unused for now, maybe... we will want it for something
|
||||
@ -69,7 +83,7 @@ struct Views {
|
||||
tgt_color: wgpu::TextureView,
|
||||
tgt_depth: wgpu::TextureView,
|
||||
|
||||
bloom_tgts: [wgpu::TextureView; bloom::NUM_SIZES],
|
||||
bloom_tgts: Option<[wgpu::TextureView; bloom::NUM_SIZES]>,
|
||||
// TODO: rename
|
||||
tgt_color_pp: wgpu::TextureView,
|
||||
}
|
||||
@ -84,6 +98,7 @@ struct Shadow {
|
||||
/// 1. Only interface pipelines created
|
||||
/// 2. All of the pipelines have been created
|
||||
#[allow(clippy::large_enum_variant)] // They are both pretty large
|
||||
#[allow(clippy::type_complexity)]
|
||||
enum State {
|
||||
// NOTE: this is used as a transient placeholder for moving things out of State temporarily
|
||||
Nothing,
|
||||
@ -96,7 +111,19 @@ enum State {
|
||||
Complete {
|
||||
pipelines: Pipelines,
|
||||
shadow: Shadow,
|
||||
recreating: Option<PipelineCreation<Result<(Pipelines, ShadowPipelines), RenderError>>>,
|
||||
recreating: Option<
|
||||
PipelineCreation<
|
||||
Result<
|
||||
(
|
||||
Pipelines,
|
||||
ShadowPipelines,
|
||||
PipelineModes,
|
||||
Arc<postprocess::PostProcessLayout>,
|
||||
),
|
||||
RenderError,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -115,11 +142,11 @@ pub struct Renderer {
|
||||
depth_sampler: wgpu::Sampler,
|
||||
|
||||
state: State,
|
||||
// true if there is a pending need to recreate the pipelines (e.g. RenderMode change or shader
|
||||
// Some if there is a pending need to recreate the pipelines (e.g. RenderMode change or shader
|
||||
// hotloading)
|
||||
recreation_pending: bool,
|
||||
recreation_pending: Option<PipelineModes>,
|
||||
|
||||
layouts: Arc<Layouts>,
|
||||
layouts: Layouts,
|
||||
// Note: we keep these here since their bind groups need to be updated if we resize the
|
||||
// color/depth textures
|
||||
locals: Locals,
|
||||
@ -131,7 +158,8 @@ pub struct Renderer {
|
||||
|
||||
shaders: AssetHandle<Shaders>,
|
||||
|
||||
mode: RenderMode,
|
||||
pipeline_modes: PipelineModes,
|
||||
other_modes: OtherModes,
|
||||
resolution: Vec2<u32>,
|
||||
|
||||
// If this is Some then a screenshot will be taken and passed to the handler here
|
||||
@ -155,7 +183,8 @@ pub struct Renderer {
|
||||
impl Renderer {
|
||||
/// Create a new `Renderer` from a variety of backend-specific components
|
||||
/// and the window targets.
|
||||
pub fn new(window: &winit::window::Window, mut mode: RenderMode) -> Result<Self, RenderError> {
|
||||
pub fn new(window: &winit::window::Window, mode: RenderMode) -> Result<Self, RenderError> {
|
||||
let (pipeline_modes, mut other_modes) = mode.split();
|
||||
// Enable seamless cubemaps globally, where available--they are essentially a
|
||||
// strict improvement on regular cube maps.
|
||||
//
|
||||
@ -288,7 +317,7 @@ impl Renderer {
|
||||
format,
|
||||
width: dims.width,
|
||||
height: dims.height,
|
||||
present_mode: mode.present_mode.into(),
|
||||
present_mode: other_modes.present_mode.into(),
|
||||
};
|
||||
|
||||
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||
@ -296,7 +325,7 @@ impl Renderer {
|
||||
let shadow_views = ShadowMap::create_shadow_views(
|
||||
&device,
|
||||
(dims.width, dims.height),
|
||||
&ShadowMapMode::try_from(mode.shadow).unwrap_or_default(),
|
||||
&ShadowMapMode::try_from(pipeline_modes.shadow).unwrap_or_default(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("Could not create shadow map views: {:?}", err);
|
||||
@ -315,11 +344,14 @@ impl Renderer {
|
||||
let terrain = terrain::TerrainLayout::new(&device);
|
||||
let clouds = clouds::CloudsLayout::new(&device);
|
||||
let bloom = bloom::BloomLayout::new(&device);
|
||||
let postprocess = postprocess::PostProcessLayout::new(&device);
|
||||
let postprocess = Arc::new(postprocess::PostProcessLayout::new(
|
||||
&device,
|
||||
&pipeline_modes,
|
||||
));
|
||||
let ui = ui::UiLayout::new(&device);
|
||||
let blit = blit::BlitLayout::new(&device);
|
||||
|
||||
Layouts {
|
||||
let immutable = Arc::new(ImmutableLayouts {
|
||||
global,
|
||||
|
||||
debug,
|
||||
@ -329,22 +361,27 @@ impl Renderer {
|
||||
terrain,
|
||||
clouds,
|
||||
bloom,
|
||||
postprocess,
|
||||
ui,
|
||||
blit,
|
||||
});
|
||||
|
||||
Layouts {
|
||||
immutable,
|
||||
postprocess,
|
||||
}
|
||||
};
|
||||
|
||||
// Arcify the device and layouts
|
||||
// Arcify the device
|
||||
let device = Arc::new(device);
|
||||
let layouts = Arc::new(layouts);
|
||||
|
||||
let (interface_pipelines, creating) = pipeline_creation::initial_create_pipelines(
|
||||
// TODO: combine Arcs?
|
||||
Arc::clone(&device),
|
||||
Arc::clone(&layouts),
|
||||
Layouts {
|
||||
immutable: Arc::clone(&layouts.immutable),
|
||||
postprocess: Arc::clone(&layouts.postprocess),
|
||||
},
|
||||
shaders.read().clone(),
|
||||
mode.clone(),
|
||||
pipeline_modes.clone(),
|
||||
sc_desc.clone(), // Note: cheap clone
|
||||
shadow_views.is_some(),
|
||||
)?;
|
||||
@ -355,8 +392,12 @@ impl Renderer {
|
||||
creating,
|
||||
};
|
||||
|
||||
let (views, bloom_sizes) =
|
||||
Self::create_rt_views(&device, (dims.width, dims.height), &mode)?;
|
||||
let (views, bloom_sizes) = Self::create_rt_views(
|
||||
&device,
|
||||
(dims.width, dims.height),
|
||||
&pipeline_modes,
|
||||
&other_modes,
|
||||
);
|
||||
|
||||
let create_sampler = |filter| {
|
||||
device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
@ -385,8 +426,6 @@ impl Renderer {
|
||||
|
||||
let clouds_locals =
|
||||
Self::create_consts_inner(&device, &queue, &[clouds::Locals::default()]);
|
||||
let bloom_locals = bloom_sizes
|
||||
.map(|size| Self::create_consts_inner(&device, &queue, &[bloom::HalfPixel::new(size)]));
|
||||
let postprocess_locals =
|
||||
Self::create_consts_inner(&device, &queue, &[postprocess::Locals::default()]);
|
||||
|
||||
@ -394,18 +433,16 @@ impl Renderer {
|
||||
&device,
|
||||
&layouts,
|
||||
clouds_locals,
|
||||
bloom_locals,
|
||||
postprocess_locals,
|
||||
&views.tgt_color,
|
||||
&views.tgt_depth,
|
||||
[
|
||||
&views.tgt_color_pp,
|
||||
&views.bloom_tgts[1],
|
||||
&views.bloom_tgts[2],
|
||||
&views.bloom_tgts[3],
|
||||
&views.bloom_tgts[4],
|
||||
],
|
||||
&views.bloom_tgts[0],
|
||||
views.bloom_tgts.as_ref().map(|tgts| locals::BloomParams {
|
||||
locals: bloom_sizes.map(|size| {
|
||||
Self::create_consts_inner(&device, &queue, &[bloom::Locals::new(size)])
|
||||
}),
|
||||
src_views: [&views.tgt_color_pp, &tgts[1], &tgts[2], &tgts[3], &tgts[4]],
|
||||
final_tgt_view: &tgts[0],
|
||||
}),
|
||||
&views.tgt_color_pp,
|
||||
&sampler,
|
||||
&depth_sampler,
|
||||
@ -416,9 +453,9 @@ impl Renderer {
|
||||
let quad_index_buffer_u32 =
|
||||
create_quad_index_buffer_u32(&device, QUAD_INDEX_BUFFER_U32_START_VERT_LEN as usize);
|
||||
let mut profiler = wgpu_profiler::GpuProfiler::new(4, queue.get_timestamp_period());
|
||||
mode.profiler_enabled &= profiler_features_enabled;
|
||||
profiler.enable_timer = mode.profiler_enabled;
|
||||
profiler.enable_debug_marker = mode.profiler_enabled;
|
||||
other_modes.profiler_enabled &= profiler_features_enabled;
|
||||
profiler.enable_timer = other_modes.profiler_enabled;
|
||||
profiler.enable_debug_marker = other_modes.profiler_enabled;
|
||||
|
||||
#[cfg(feature = "egui-ui")]
|
||||
let egui_renderpass =
|
||||
@ -432,7 +469,7 @@ impl Renderer {
|
||||
sc_desc,
|
||||
|
||||
state,
|
||||
recreation_pending: false,
|
||||
recreation_pending: None,
|
||||
|
||||
layouts,
|
||||
locals,
|
||||
@ -447,7 +484,8 @@ impl Renderer {
|
||||
|
||||
shaders,
|
||||
|
||||
mode,
|
||||
pipeline_modes,
|
||||
other_modes,
|
||||
resolution: Vec2::new(dims.width, dims.height),
|
||||
|
||||
take_screenshot: None,
|
||||
@ -492,37 +530,47 @@ impl Renderer {
|
||||
|
||||
/// Change the render mode.
|
||||
pub fn set_render_mode(&mut self, mode: RenderMode) -> Result<(), RenderError> {
|
||||
// TODO: are there actually any issues with the current mode not matching the
|
||||
// pipelines (since we could previously have inconsistencies from
|
||||
// pipelines failing to build due to shader editing)?
|
||||
// TODO: FIXME: defer mode changing until pipelines are rebuilt to prevent
|
||||
// incompatibilities as pipelines are now rebuilt in a deferred mannder in the
|
||||
// background TODO: consider separating changes that don't require
|
||||
// rebuilding pipelines
|
||||
self.mode = mode;
|
||||
self.sc_desc.present_mode = self.mode.present_mode.into();
|
||||
let (pipeline_modes, other_modes) = mode.split();
|
||||
|
||||
// Only enable profiling if the wgpu features are enabled
|
||||
self.mode.profiler_enabled &= self.profiler_features_enabled;
|
||||
// Enable/disable profiler
|
||||
if !self.mode.profiler_enabled {
|
||||
// Clear the times if disabled
|
||||
core::mem::take(&mut self.profile_times);
|
||||
if self.other_modes != other_modes {
|
||||
self.other_modes = other_modes;
|
||||
|
||||
// Update present mode in swap chain descriptor
|
||||
self.sc_desc.present_mode = self.other_modes.present_mode.into();
|
||||
|
||||
// Only enable profiling if the wgpu features are enabled
|
||||
self.other_modes.profiler_enabled &= self.profiler_features_enabled;
|
||||
// Enable/disable profiler
|
||||
if !self.other_modes.profiler_enabled {
|
||||
// Clear the times if disabled
|
||||
core::mem::take(&mut self.profile_times);
|
||||
}
|
||||
self.profiler.enable_timer = self.other_modes.profiler_enabled;
|
||||
self.profiler.enable_debug_marker = self.other_modes.profiler_enabled;
|
||||
|
||||
// Recreate render target
|
||||
self.on_resize(self.resolution);
|
||||
}
|
||||
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)?;
|
||||
|
||||
// Recreate pipelines with the new AA mode
|
||||
self.recreate_pipelines();
|
||||
// We can't cancel the pending recreation even if the new settings are equal
|
||||
// to the current ones becuase the recreation could be triggered by something
|
||||
// else like shader hotloading
|
||||
if dbg!(self.pipeline_modes != pipeline_modes)
|
||||
|| dbg!(
|
||||
self.recreation_pending
|
||||
.as_ref()
|
||||
.map_or(false, |modes| modes != &pipeline_modes)
|
||||
)
|
||||
{
|
||||
// Recreate pipelines with new modes
|
||||
self.recreate_pipelines(pipeline_modes);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the render mode.
|
||||
pub fn render_mode(&self) -> &RenderMode { &self.mode }
|
||||
/// Get the pipelines mode.
|
||||
pub fn pipeline_modes(&self) -> &PipelineModes { &self.pipeline_modes }
|
||||
|
||||
/// Get the current profiling times
|
||||
/// Nested timings immediately follow their parent
|
||||
@ -552,7 +600,7 @@ impl Renderer {
|
||||
}
|
||||
|
||||
/// Resize internal render targets to match window render target dimensions.
|
||||
pub fn on_resize(&mut self, dims: Vec2<u32>) -> Result<(), RenderError> {
|
||||
pub fn on_resize(&mut self, dims: Vec2<u32>) {
|
||||
// Avoid panics when creating texture with w,h of 0,0.
|
||||
if dims.x != 0 && dims.y != 0 {
|
||||
self.is_minimized = false;
|
||||
@ -563,26 +611,36 @@ impl Renderer {
|
||||
self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc);
|
||||
|
||||
// Resize other render targets
|
||||
let (views, bloom_sizes) =
|
||||
Self::create_rt_views(&self.device, (dims.x, dims.y), &self.mode)?;
|
||||
let (views, bloom_sizes) = Self::create_rt_views(
|
||||
&self.device,
|
||||
(dims.x, dims.y),
|
||||
&self.pipeline_modes,
|
||||
&self.other_modes,
|
||||
);
|
||||
self.views = views;
|
||||
let bloom_locals =
|
||||
bloom_sizes.map(|size| self.create_consts(&[bloom::HalfPixel::new(size)]));
|
||||
// Rebind views to clouds/postprocess bind groups
|
||||
|
||||
// appease borrow check
|
||||
let device = &self.device;
|
||||
let queue = &self.queue;
|
||||
let views = &self.views;
|
||||
let bloom_params = self
|
||||
.views
|
||||
.bloom_tgts
|
||||
.as_ref()
|
||||
.map(|tgts| locals::BloomParams {
|
||||
locals: bloom_sizes.map(|size| {
|
||||
Self::create_consts_inner(device, queue, &[bloom::Locals::new(size)])
|
||||
}),
|
||||
src_views: [&views.tgt_color_pp, &tgts[1], &tgts[2], &tgts[3], &tgts[4]],
|
||||
final_tgt_view: &tgts[0],
|
||||
});
|
||||
|
||||
self.locals.rebind(
|
||||
&self.device,
|
||||
&self.layouts,
|
||||
bloom_locals,
|
||||
&self.views.tgt_color,
|
||||
&self.views.tgt_depth,
|
||||
[
|
||||
&self.views.tgt_color_pp,
|
||||
&self.views.bloom_tgts[1],
|
||||
&self.views.bloom_tgts[2],
|
||||
&self.views.bloom_tgts[3],
|
||||
&self.views.bloom_tgts[4],
|
||||
],
|
||||
&self.views.bloom_tgts[0],
|
||||
bloom_params,
|
||||
&self.views.tgt_color_pp,
|
||||
&self.sampler,
|
||||
&self.depth_sampler,
|
||||
@ -606,7 +664,7 @@ impl Renderer {
|
||||
};
|
||||
|
||||
if let (Some((point_depth, directed_depth)), ShadowMode::Map(mode)) =
|
||||
(shadow_views, self.mode.shadow)
|
||||
(shadow_views, self.pipeline_modes.shadow)
|
||||
{
|
||||
match ShadowMap::create_shadow_views(&self.device, (dims.x, dims.y), &mode) {
|
||||
Ok((new_point_depth, new_directed_depth)) => {
|
||||
@ -638,8 +696,6 @@ impl Renderer {
|
||||
} else {
|
||||
self.is_minimized = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn maintain(&self) {
|
||||
@ -654,12 +710,13 @@ impl Renderer {
|
||||
fn create_rt_views(
|
||||
device: &wgpu::Device,
|
||||
size: (u32, u32),
|
||||
mode: &RenderMode,
|
||||
) -> Result<(Views, [Vec2<f32>; bloom::NUM_SIZES]), RenderError> {
|
||||
pipeline_modes: &PipelineModes,
|
||||
other_modes: &OtherModes,
|
||||
) -> (Views, [Vec2<f32>; bloom::NUM_SIZES]) {
|
||||
let upscaled = Vec2::<u32>::from(size)
|
||||
.map(|e| (e as f32 * mode.upscale_mode.factor) as u32)
|
||||
.map(|e| (e as f32 * other_modes.upscale_mode.factor) as u32)
|
||||
.into_tuple();
|
||||
let (width, height, sample_count) = match mode.aa {
|
||||
let (width, height, sample_count) = match pipeline_modes.aa {
|
||||
AaMode::None | AaMode::Fxaa => (upscaled.0, upscaled.1, 1),
|
||||
AaMode::MsaaX4 => (upscaled.0, upscaled.1, 4),
|
||||
AaMode::MsaaX8 => (upscaled.0, upscaled.1, 8),
|
||||
@ -707,7 +764,9 @@ impl Renderer {
|
||||
size
|
||||
});
|
||||
|
||||
let bloom_tgt_views = bloom_sizes.map(|size| color_view(size.x, size.y));
|
||||
let bloom_tgt_views = pipeline_modes
|
||||
.bloom
|
||||
.then(|| bloom_sizes.map(|size| color_view(size.x, size.y)));
|
||||
|
||||
let tgt_depth_tex = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
@ -758,7 +817,7 @@ impl Renderer {
|
||||
array_layer_count: None,
|
||||
});
|
||||
|
||||
Ok((
|
||||
(
|
||||
Views {
|
||||
tgt_color: tgt_color_view,
|
||||
tgt_depth: tgt_depth_view,
|
||||
@ -767,7 +826,7 @@ impl Renderer {
|
||||
_win_depth: win_depth_view,
|
||||
},
|
||||
bloom_sizes.map(|s| s.map(|e| e as f32)),
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the resolution of the render target.
|
||||
@ -841,7 +900,7 @@ impl Renderer {
|
||||
}
|
||||
|
||||
// Try to get the latest profiling results
|
||||
if self.mode.profiler_enabled {
|
||||
if self.other_modes.profiler_enabled {
|
||||
// Note: this lags a few frames behind
|
||||
if let Some(profile_times) = self.profiler.process_finished_frame() {
|
||||
self.profile_times = profile_times;
|
||||
@ -851,6 +910,10 @@ impl Renderer {
|
||||
// Handle polling background pipeline creation/recreation
|
||||
// Temporarily set to nothing and then replace in the statement below
|
||||
let state = core::mem::replace(&mut self.state, State::Nothing);
|
||||
// Indicator for if pipeline recreation finished and we need to recreate bind
|
||||
// groups / render targets (handling defered so that State will be valid
|
||||
// when calling Self::on_resize)
|
||||
let mut trigger_on_resize = false;
|
||||
// If still creating initial pipelines, check if complete
|
||||
self.state = if let State::Interface {
|
||||
pipelines: interface,
|
||||
@ -906,7 +969,7 @@ impl Renderer {
|
||||
} = state
|
||||
{
|
||||
match recreating.try_complete() {
|
||||
Ok(Ok((pipelines, shadow_pipelines))) => {
|
||||
Ok(Ok((pipelines, shadow_pipelines, new_pipeline_modes, postprocess_layout))) => {
|
||||
if let (
|
||||
Some(point_pipeline),
|
||||
Some(terrain_directed_pipeline),
|
||||
@ -922,6 +985,14 @@ impl Renderer {
|
||||
shadow_map.terrain_directed_pipeline = terrain_directed_pipeline;
|
||||
shadow_map.figure_directed_pipeline = figure_directed_pipeline;
|
||||
}
|
||||
|
||||
self.pipeline_modes = new_pipeline_modes;
|
||||
self.layouts.postprocess = postprocess_layout;
|
||||
// TODO: we have the potential to skip recreating bindings / render targets on
|
||||
// pipeline recreation trigged by shader reloading (would need to ensure new
|
||||
// postprocess_layout is not created...)
|
||||
trigger_on_resize = true;
|
||||
|
||||
State::Complete {
|
||||
pipelines,
|
||||
shadow,
|
||||
@ -947,17 +1018,26 @@ impl Renderer {
|
||||
state
|
||||
};
|
||||
|
||||
// Call on_resize to recreate render targets and their bind groups if the
|
||||
// pipelines were recreated with a new postprocess layout and or changes in the
|
||||
// render modes
|
||||
if trigger_on_resize {
|
||||
self.on_resize(self.resolution);
|
||||
}
|
||||
|
||||
// If the shaders files were changed attempt to recreate the shaders
|
||||
if self.shaders.reloaded() {
|
||||
self.recreate_pipelines();
|
||||
self.recreate_pipelines(self.pipeline_modes.clone());
|
||||
}
|
||||
|
||||
// Or if we have a recreation pending
|
||||
if self.recreation_pending
|
||||
&& matches!(&self.state, State::Complete { recreating, .. } if recreating.is_none())
|
||||
{
|
||||
self.recreation_pending = false;
|
||||
self.recreate_pipelines();
|
||||
if matches!(&self.state, State::Complete {
|
||||
recreating: None,
|
||||
..
|
||||
}) {
|
||||
if let Some(new_pipeline_modes) = self.recreation_pending.take() {
|
||||
self.recreate_pipelines(new_pipeline_modes);
|
||||
}
|
||||
}
|
||||
|
||||
let tex = match self.swap_chain.get_current_frame() {
|
||||
@ -965,7 +1045,8 @@ impl Renderer {
|
||||
// If lost recreate the swap chain
|
||||
Err(err @ wgpu::SwapChainError::Lost) => {
|
||||
warn!("{}. Recreating swap chain. A frame will be missed", err);
|
||||
return self.on_resize(self.resolution).map(|()| None);
|
||||
self.on_resize(self.resolution);
|
||||
return Ok(None);
|
||||
},
|
||||
Err(wgpu::SwapChainError::Timeout) => {
|
||||
// This will probably be resolved on the next frame
|
||||
@ -990,21 +1071,24 @@ impl Renderer {
|
||||
}
|
||||
|
||||
/// Recreate the pipelines
|
||||
fn recreate_pipelines(&mut self) {
|
||||
fn recreate_pipelines(&mut self, pipeline_modes: PipelineModes) {
|
||||
match &mut self.state {
|
||||
State::Complete { recreating, .. } if recreating.is_some() => {
|
||||
// Defer recreation so that we are not building multiple sets of pipelines in
|
||||
// the background at once
|
||||
self.recreation_pending = true;
|
||||
self.recreation_pending = Some(pipeline_modes);
|
||||
},
|
||||
State::Complete {
|
||||
recreating, shadow, ..
|
||||
} => {
|
||||
*recreating = Some(pipeline_creation::recreate_pipelines(
|
||||
Arc::clone(&self.device),
|
||||
Arc::clone(&self.layouts),
|
||||
Arc::clone(&self.layouts.immutable),
|
||||
self.shaders.read().clone(),
|
||||
self.mode.clone(),
|
||||
self.pipeline_modes.clone(),
|
||||
// NOTE: if present_mode starts to be used to configure pipelines then it needs
|
||||
// to become a part of the pipeline modes (note here since the present mode is
|
||||
// accessible through the swap chain descriptor)
|
||||
self.sc_desc.clone(), // Note: cheap clone
|
||||
shadow.map.is_enabled(),
|
||||
));
|
||||
@ -1012,7 +1096,7 @@ impl Renderer {
|
||||
State::Interface { .. } => {
|
||||
// Defer recreation so that we are not building multiple sets of pipelines in
|
||||
// the background at once
|
||||
self.recreation_pending = true;
|
||||
self.recreation_pending = Some(pipeline_modes);
|
||||
},
|
||||
State::Nothing => {},
|
||||
}
|
||||
@ -1229,7 +1313,7 @@ impl Renderer {
|
||||
// Queue screenshot
|
||||
self.take_screenshot = Some(Box::new(screenshot_handler));
|
||||
// Take profiler snapshot
|
||||
if self.mode.profiler_enabled {
|
||||
if self.other_modes.profiler_enabled {
|
||||
let file_name = format!(
|
||||
"frame-trace_{}.json",
|
||||
std::time::SystemTime::now()
|
||||
|
@ -61,7 +61,7 @@ struct RendererBorrow<'frame> {
|
||||
pipelines: Pipelines<'frame>,
|
||||
locals: &'frame super::locals::Locals,
|
||||
views: &'frame super::Views,
|
||||
mode: &'frame super::super::RenderMode,
|
||||
pipeline_modes: &'frame super::super::PipelineModes,
|
||||
quad_index_buffer_u16: &'frame Buffer<u16>,
|
||||
quad_index_buffer_u32: &'frame Buffer<u32>,
|
||||
#[cfg(feature = "egui-ui")]
|
||||
@ -112,7 +112,7 @@ impl<'frame> Drawer<'frame> {
|
||||
pipelines,
|
||||
locals: &renderer.locals,
|
||||
views: &renderer.views,
|
||||
mode: &renderer.mode,
|
||||
pipeline_modes: &renderer.pipeline_modes,
|
||||
quad_index_buffer_u16: &renderer.quad_index_buffer_u16,
|
||||
quad_index_buffer_u32: &renderer.quad_index_buffer_u32,
|
||||
#[cfg(feature = "egui-ui")]
|
||||
@ -131,13 +131,13 @@ impl<'frame> Drawer<'frame> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the render mode.
|
||||
pub fn render_mode(&self) -> &super::super::RenderMode { self.borrow.mode }
|
||||
/// Get the pipeline modes.
|
||||
pub fn pipeline_modes(&self) -> &super::super::PipelineModes { self.borrow.pipeline_modes }
|
||||
|
||||
/// Returns None if the shadow renderer is not enabled at some level or the
|
||||
/// pipelines are not available yet
|
||||
pub fn shadow_pass(&mut self) -> Option<ShadowPassDrawer> {
|
||||
if !self.borrow.mode.shadow.is_map() {
|
||||
if !self.borrow.pipeline_modes.shadow.is_map() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -243,15 +243,24 @@ impl<'frame> Drawer<'frame> {
|
||||
|
||||
/// To be ran between the second pass and the third pass
|
||||
/// does nothing if the ingame pipelines are not yet ready
|
||||
/// does nothing if bloom is disabled
|
||||
pub fn run_bloom_passes(&mut self) {
|
||||
let pipelines = match self.borrow.pipelines.all() {
|
||||
Some(p) => p,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let locals = &self.borrow.locals;
|
||||
let views = &self.borrow.views;
|
||||
|
||||
let bloom_pipelines = match self.borrow.pipelines.all() {
|
||||
Some(super::Pipelines { bloom: Some(p), .. }) => p,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// TODO: consider consolidating optional bloom bind groups and optional pipeline
|
||||
// into a single structure?
|
||||
let (bloom_tgts, bloom_binds) =
|
||||
match views.bloom_tgts.as_ref().zip(locals.bloom_binds.as_ref()) {
|
||||
Some((t, b)) => (t, b),
|
||||
None => return,
|
||||
};
|
||||
|
||||
let device = self.borrow.device;
|
||||
let mut encoder = self.encoder.as_mut().unwrap().scope("bloom", device);
|
||||
|
||||
@ -275,18 +284,18 @@ impl<'frame> Drawer<'frame> {
|
||||
|
||||
// Downsample filter passes
|
||||
(0..bloom::NUM_SIZES - 1).for_each(|index| {
|
||||
let bind = &locals.bloom_binds[index].bind_group;
|
||||
let view = &views.bloom_tgts[index + 1];
|
||||
let bind = &bloom_binds[index].bind_group;
|
||||
let view = &bloom_tgts[index + 1];
|
||||
// Do filtering out of non-bright things during the first downsample
|
||||
let (label, pipeline) = if index == 0 {
|
||||
(
|
||||
format!("downsample filtered {}", index + 1),
|
||||
&pipelines.bloom.downsample_filtered,
|
||||
&bloom_pipelines.downsample_filtered,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
format!("downsample {}", index + 1),
|
||||
&pipelines.bloom.downsample,
|
||||
&bloom_pipelines.downsample,
|
||||
)
|
||||
};
|
||||
run_bloom_pass(
|
||||
@ -300,14 +309,14 @@ impl<'frame> Drawer<'frame> {
|
||||
|
||||
// Upsample filter passes
|
||||
(0..bloom::NUM_SIZES - 1).for_each(|index| {
|
||||
let bind = &locals.bloom_binds[bloom::NUM_SIZES - 1 - index].bind_group;
|
||||
let view = &views.bloom_tgts[bloom::NUM_SIZES - 2 - index];
|
||||
let bind = &bloom_binds[bloom::NUM_SIZES - 1 - index].bind_group;
|
||||
let view = &bloom_tgts[bloom::NUM_SIZES - 2 - index];
|
||||
let label = format!("upsample {}", index + 1);
|
||||
run_bloom_pass(
|
||||
bind,
|
||||
view,
|
||||
label,
|
||||
&pipelines.bloom.upsample,
|
||||
&bloom_pipelines.upsample,
|
||||
if index + 2 == bloom::NUM_SIZES {
|
||||
// Clear for the final image since that is just stuff from the pervious frame.
|
||||
wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT)
|
||||
@ -400,7 +409,7 @@ impl<'frame> Drawer<'frame> {
|
||||
chunks: impl Clone
|
||||
+ Iterator<Item = (&'data Model<terrain::Vertex>, &'data terrain::BoundLocals)>,
|
||||
) {
|
||||
if !self.borrow.mode.shadow.is_map() {
|
||||
if !self.borrow.pipeline_modes.shadow.is_map() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,17 @@ use super::{
|
||||
Layouts,
|
||||
};
|
||||
|
||||
pub struct BloomParams<'a> {
|
||||
pub locals: [Consts<bloom::Locals>; bloom::NUM_SIZES],
|
||||
pub src_views: [&'a wgpu::TextureView; bloom::NUM_SIZES],
|
||||
pub final_tgt_view: &'a wgpu::TextureView,
|
||||
}
|
||||
|
||||
pub struct Locals {
|
||||
pub clouds: Consts<clouds::Locals>,
|
||||
pub clouds_bind: clouds::BindGroup,
|
||||
|
||||
pub bloom_binds: [bloom::BindGroup; bloom::NUM_SIZES],
|
||||
pub bloom_binds: Option<[bloom::BindGroup; bloom::NUM_SIZES]>,
|
||||
|
||||
pub postprocess: Consts<postprocess::Locals>,
|
||||
pub postprocess_bind: postprocess::BindGroup,
|
||||
@ -21,12 +27,10 @@ impl Locals {
|
||||
device: &wgpu::Device,
|
||||
layouts: &Layouts,
|
||||
clouds_locals: Consts<clouds::Locals>,
|
||||
bloom_locals: [Consts<bloom::HalfPixel>; bloom::NUM_SIZES],
|
||||
postprocess_locals: Consts<postprocess::Locals>,
|
||||
tgt_color_view: &wgpu::TextureView,
|
||||
tgt_depth_view: &wgpu::TextureView,
|
||||
bloom_src_views: [&wgpu::TextureView; bloom::NUM_SIZES],
|
||||
bloom_final_tgt_view: &wgpu::TextureView,
|
||||
bloom: Option<BloomParams>,
|
||||
tgt_color_pp_view: &wgpu::TextureView,
|
||||
sampler: &wgpu::Sampler,
|
||||
depth_sampler: &wgpu::Sampler,
|
||||
@ -39,18 +43,22 @@ impl Locals {
|
||||
depth_sampler,
|
||||
&clouds_locals,
|
||||
);
|
||||
let bloom_binds = bloom_src_views
|
||||
.zip(bloom_locals)
|
||||
.map(|(view, locals)| layouts.bloom.bind(device, view, sampler, locals));
|
||||
|
||||
let postprocess_bind = layouts.postprocess.bind(
|
||||
device,
|
||||
tgt_color_pp_view,
|
||||
bloom_final_tgt_view,
|
||||
bloom.as_ref().map(|b| b.final_tgt_view),
|
||||
sampler,
|
||||
&postprocess_locals,
|
||||
);
|
||||
|
||||
let bloom_binds = bloom.map(|bloom| {
|
||||
bloom
|
||||
.src_views
|
||||
.zip(bloom.locals) // zip arrays
|
||||
.map(|(view, locals)| layouts.bloom.bind(device, view, sampler, locals))
|
||||
});
|
||||
|
||||
Self {
|
||||
clouds: clouds_locals,
|
||||
clouds_bind,
|
||||
@ -66,11 +74,9 @@ impl Locals {
|
||||
layouts: &Layouts,
|
||||
// Call when these are recreated and need to be rebound
|
||||
// e.g. resizing
|
||||
bloom_locals: [Consts<bloom::HalfPixel>; bloom::NUM_SIZES],
|
||||
tgt_color_view: &wgpu::TextureView,
|
||||
tgt_depth_view: &wgpu::TextureView,
|
||||
bloom_src_views: [&wgpu::TextureView; bloom::NUM_SIZES],
|
||||
bloom_final_tgt_view: &wgpu::TextureView,
|
||||
bloom: Option<BloomParams>,
|
||||
tgt_color_pp_view: &wgpu::TextureView,
|
||||
sampler: &wgpu::Sampler,
|
||||
depth_sampler: &wgpu::Sampler,
|
||||
@ -83,15 +89,18 @@ impl Locals {
|
||||
depth_sampler,
|
||||
&self.clouds,
|
||||
);
|
||||
self.bloom_binds = bloom_src_views
|
||||
.zip(bloom_locals)
|
||||
.map(|(view, locals)| layouts.bloom.bind(device, view, sampler, locals));
|
||||
self.postprocess_bind = layouts.postprocess.bind(
|
||||
device,
|
||||
tgt_color_pp_view,
|
||||
bloom_final_tgt_view,
|
||||
bloom.as_ref().map(|b| b.final_tgt_view),
|
||||
sampler,
|
||||
&self.postprocess,
|
||||
);
|
||||
self.bloom_binds = bloom.map(|bloom| {
|
||||
bloom
|
||||
.src_views
|
||||
.zip(bloom.locals) // zip arrays
|
||||
.map(|(view, locals)| layouts.bloom.bind(device, view, sampler, locals))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ use super::{
|
||||
blit, bloom, clouds, debug, figure, fluid, lod_terrain, particle, postprocess, shadow,
|
||||
skybox, sprite, terrain, ui,
|
||||
},
|
||||
AaMode, CloudMode, FluidMode, LightingMode, RenderError, RenderMode, ShadowMode,
|
||||
AaMode, CloudMode, FluidMode, LightingMode, PipelineModes, RenderError, ShadowMode,
|
||||
},
|
||||
shaders::Shaders,
|
||||
Layouts,
|
||||
ImmutableLayouts, Layouts,
|
||||
};
|
||||
use common_base::prof_span;
|
||||
use std::sync::Arc;
|
||||
@ -20,7 +20,7 @@ pub struct Pipelines {
|
||||
pub lod_terrain: lod_terrain::LodTerrainPipeline,
|
||||
pub particle: particle::ParticlePipeline,
|
||||
pub clouds: clouds::CloudsPipeline,
|
||||
pub bloom: bloom::BloomPipelines,
|
||||
pub bloom: Option<bloom::BloomPipelines>,
|
||||
pub postprocess: postprocess::PostProcessPipeline,
|
||||
// Consider reenabling at some time
|
||||
// player_shadow: figure::FigurePipeline,
|
||||
@ -40,7 +40,7 @@ pub struct IngamePipelines {
|
||||
lod_terrain: lod_terrain::LodTerrainPipeline,
|
||||
particle: particle::ParticlePipeline,
|
||||
clouds: clouds::CloudsPipeline,
|
||||
bloom: bloom::BloomPipelines,
|
||||
pub bloom: Option<bloom::BloomPipelines>,
|
||||
postprocess: postprocess::PostProcessPipeline,
|
||||
// Consider reenabling at some time
|
||||
// player_shadow: figure::FigurePipeline,
|
||||
@ -126,7 +126,7 @@ impl ShaderModules {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
shaders: &Shaders,
|
||||
mode: &RenderMode,
|
||||
pipeline_modes: &PipelineModes,
|
||||
has_shadow_views: bool,
|
||||
) -> Result<Self, RenderError> {
|
||||
prof_span!(_guard, "ShaderModules::new");
|
||||
@ -151,16 +151,17 @@ impl ShaderModules {
|
||||
#define CLOUD_MODE {}
|
||||
#define LIGHTING_ALGORITHM {}
|
||||
#define SHADOW_MODE {}
|
||||
#define BLOOM {}
|
||||
|
||||
"#,
|
||||
&constants.0,
|
||||
// TODO: Configurable vertex/fragment shader preference.
|
||||
"VOXYGEN_COMPUTATION_PREFERENCE_FRAGMENT",
|
||||
match mode.fluid {
|
||||
match pipeline_modes.fluid {
|
||||
FluidMode::Cheap => "FLUID_MODE_CHEAP",
|
||||
FluidMode::Shiny => "FLUID_MODE_SHINY",
|
||||
},
|
||||
match mode.cloud {
|
||||
match pipeline_modes.cloud {
|
||||
CloudMode::None => "CLOUD_MODE_NONE",
|
||||
CloudMode::Minimal => "CLOUD_MODE_MINIMAL",
|
||||
CloudMode::Low => "CLOUD_MODE_LOW",
|
||||
@ -168,20 +169,25 @@ impl ShaderModules {
|
||||
CloudMode::High => "CLOUD_MODE_HIGH",
|
||||
CloudMode::Ultra => "CLOUD_MODE_ULTRA",
|
||||
},
|
||||
match mode.lighting {
|
||||
match pipeline_modes.lighting {
|
||||
LightingMode::Ashikhmin => "LIGHTING_ALGORITHM_ASHIKHMIN",
|
||||
LightingMode::BlinnPhong => "LIGHTING_ALGORITHM_BLINN_PHONG",
|
||||
LightingMode::Lambertian => "LIGHTING_ALGORITHM_LAMBERTIAN",
|
||||
},
|
||||
match mode.shadow {
|
||||
match pipeline_modes.shadow {
|
||||
ShadowMode::None => "SHADOW_MODE_NONE",
|
||||
ShadowMode::Map(_) if has_shadow_views => "SHADOW_MODE_MAP",
|
||||
ShadowMode::Cheap | ShadowMode::Map(_) => "SHADOW_MODE_CHEAP",
|
||||
},
|
||||
if dbg!(pipeline_modes.bloom) {
|
||||
"BLOOM_ENABLED"
|
||||
} else {
|
||||
"BLOOM_DISABLED"
|
||||
},
|
||||
);
|
||||
|
||||
let anti_alias = shaders
|
||||
.get(match mode.aa {
|
||||
.get(match pipeline_modes.aa {
|
||||
AaMode::None => "antialias.none",
|
||||
AaMode::Fxaa => "antialias.fxaa",
|
||||
AaMode::MsaaX4 => "antialias.msaa-x4",
|
||||
@ -191,7 +197,7 @@ impl ShaderModules {
|
||||
.unwrap();
|
||||
|
||||
let cloud = shaders
|
||||
.get(match mode.cloud {
|
||||
.get(match pipeline_modes.cloud {
|
||||
CloudMode::None => "include.cloud.none",
|
||||
_ => "include.cloud.regular",
|
||||
})
|
||||
@ -234,7 +240,7 @@ impl ShaderModules {
|
||||
create_shader_module(device, &mut compiler, glsl, kind, &file_name, &options)
|
||||
};
|
||||
|
||||
let selected_fluid_shader = ["fluid-frag.", match mode.fluid {
|
||||
let selected_fluid_shader = ["fluid-frag.", match pipeline_modes.fluid {
|
||||
FluidMode::Cheap => "cheap",
|
||||
FluidMode::Shiny => "shiny",
|
||||
}]
|
||||
@ -317,7 +323,7 @@ struct PipelineNeeds<'a> {
|
||||
device: &'a wgpu::Device,
|
||||
layouts: &'a Layouts,
|
||||
shaders: &'a ShaderModules,
|
||||
mode: &'a RenderMode,
|
||||
pipeline_modes: &'a PipelineModes,
|
||||
sc_desc: &'a wgpu::SwapChainDescriptor,
|
||||
}
|
||||
|
||||
@ -380,7 +386,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
device,
|
||||
layouts,
|
||||
shaders,
|
||||
mode,
|
||||
pipeline_modes,
|
||||
sc_desc,
|
||||
} = needs;
|
||||
|
||||
@ -416,7 +422,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.debug_frag,
|
||||
&layouts.global,
|
||||
&layouts.debug,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"debug pipeline creation",
|
||||
@ -431,7 +437,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.skybox_vert,
|
||||
&shaders.skybox_frag,
|
||||
&layouts.global,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"skybox pipeline creation",
|
||||
@ -447,7 +453,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.figure_frag,
|
||||
&layouts.global,
|
||||
&layouts.figure,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"figure pipeline creation",
|
||||
@ -463,7 +469,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.terrain_frag,
|
||||
&layouts.global,
|
||||
&layouts.terrain,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"terrain pipeline creation",
|
||||
@ -479,7 +485,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.fluid_frag,
|
||||
&layouts.global,
|
||||
&layouts.terrain,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"fluid pipeline creation",
|
||||
@ -496,7 +502,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&layouts.global,
|
||||
&layouts.sprite,
|
||||
&layouts.terrain,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"sprite pipeline creation",
|
||||
@ -511,7 +517,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.particle_vert,
|
||||
&shaders.particle_frag,
|
||||
&layouts.global,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"particle pipeline creation",
|
||||
@ -526,7 +532,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.lod_terrain_vert,
|
||||
&shaders.lod_terrain_frag,
|
||||
&layouts.global,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"lod terrain pipeline creation",
|
||||
@ -542,7 +548,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.clouds_frag,
|
||||
&layouts.global,
|
||||
&layouts.clouds,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"clouds pipeline creation",
|
||||
@ -552,15 +558,17 @@ fn create_ingame_and_shadow_pipelines(
|
||||
let create_bloom = || {
|
||||
bloom_task.run(
|
||||
|| {
|
||||
bloom::BloomPipelines::new(
|
||||
device,
|
||||
&shaders.blit_vert,
|
||||
&shaders.dual_downsample_filtered_frag,
|
||||
&shaders.dual_downsample_frag,
|
||||
&shaders.dual_upsample_frag,
|
||||
wgpu::TextureFormat::Rgba16Float,
|
||||
&layouts.bloom,
|
||||
)
|
||||
pipeline_modes.bloom.then(|| {
|
||||
bloom::BloomPipelines::new(
|
||||
device,
|
||||
&shaders.blit_vert,
|
||||
&shaders.dual_downsample_filtered_frag,
|
||||
&shaders.dual_downsample_frag,
|
||||
&shaders.dual_upsample_frag,
|
||||
wgpu::TextureFormat::Rgba16Float,
|
||||
&layouts.bloom,
|
||||
)
|
||||
})
|
||||
},
|
||||
"bloom pipelines creation",
|
||||
)
|
||||
@ -614,7 +622,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.point_light_shadows_vert,
|
||||
&layouts.global,
|
||||
&layouts.terrain,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"point shadow pipeline creation",
|
||||
@ -629,7 +637,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.light_shadows_directed_vert,
|
||||
&layouts.global,
|
||||
&layouts.terrain,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"terrain directed shadow pipeline creation",
|
||||
@ -644,7 +652,7 @@ fn create_ingame_and_shadow_pipelines(
|
||||
&shaders.light_shadows_figure_vert,
|
||||
&layouts.global,
|
||||
&layouts.figure,
|
||||
mode.aa,
|
||||
pipeline_modes.aa,
|
||||
)
|
||||
},
|
||||
"figure directed shadow pipeline creation",
|
||||
@ -706,9 +714,9 @@ fn create_ingame_and_shadow_pipelines(
|
||||
/// NOTE: this tries to use all the CPU cores to complete as soon as possible
|
||||
pub(super) fn initial_create_pipelines(
|
||||
device: Arc<wgpu::Device>,
|
||||
layouts: Arc<Layouts>,
|
||||
layouts: Layouts,
|
||||
shaders: Shaders,
|
||||
mode: RenderMode,
|
||||
pipeline_modes: PipelineModes,
|
||||
sc_desc: wgpu::SwapChainDescriptor,
|
||||
has_shadow_views: bool,
|
||||
) -> Result<
|
||||
@ -721,7 +729,7 @@ pub(super) fn initial_create_pipelines(
|
||||
prof_span!(_guard, "initial_create_pipelines");
|
||||
|
||||
// Process shaders into modules
|
||||
let shader_modules = ShaderModules::new(&device, &shaders, &mode, has_shadow_views)?;
|
||||
let shader_modules = ShaderModules::new(&device, &shaders, &pipeline_modes, has_shadow_views)?;
|
||||
|
||||
// Create threadpool for parallel portion
|
||||
let pool = rayon::ThreadPoolBuilder::new()
|
||||
@ -733,7 +741,7 @@ pub(super) fn initial_create_pipelines(
|
||||
device: &device,
|
||||
layouts: &layouts,
|
||||
shaders: &shader_modules,
|
||||
mode: &mode,
|
||||
pipeline_modes: &pipeline_modes,
|
||||
sc_desc: &sc_desc,
|
||||
};
|
||||
|
||||
@ -760,7 +768,7 @@ pub(super) fn initial_create_pipelines(
|
||||
device: &device,
|
||||
layouts: &layouts,
|
||||
shaders: &shader_modules,
|
||||
mode: &mode,
|
||||
pipeline_modes: &pipeline_modes,
|
||||
sc_desc: &sc_desc,
|
||||
};
|
||||
|
||||
@ -776,14 +784,25 @@ pub(super) fn initial_create_pipelines(
|
||||
/// Use this to recreate all the pipelines in the background.
|
||||
/// TODO: report progress
|
||||
/// NOTE: this tries to use all the CPU cores to complete as soon as possible
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(super) fn recreate_pipelines(
|
||||
device: Arc<wgpu::Device>,
|
||||
layouts: Arc<Layouts>,
|
||||
immutable_layouts: Arc<ImmutableLayouts>,
|
||||
shaders: Shaders,
|
||||
mode: RenderMode,
|
||||
pipeline_modes: PipelineModes,
|
||||
sc_desc: wgpu::SwapChainDescriptor,
|
||||
has_shadow_views: bool,
|
||||
) -> PipelineCreation<Result<(Pipelines, ShadowPipelines), RenderError>> {
|
||||
) -> PipelineCreation<
|
||||
Result<
|
||||
(
|
||||
Pipelines,
|
||||
ShadowPipelines,
|
||||
PipelineModes,
|
||||
Arc<postprocess::PostProcessLayout>,
|
||||
),
|
||||
RenderError,
|
||||
>,
|
||||
> {
|
||||
prof_span!(_guard, "recreate_pipelines");
|
||||
|
||||
// Create threadpool for parallel portion
|
||||
@ -811,20 +830,32 @@ pub(super) fn recreate_pipelines(
|
||||
|
||||
// Process shaders into modules
|
||||
let guard = shader_task.start("process shaders");
|
||||
let shader_modules = match ShaderModules::new(&device, &shaders, &mode, has_shadow_views) {
|
||||
Ok(modules) => modules,
|
||||
Err(err) => {
|
||||
result_send.send(Err(err)).expect("Channel disconnected");
|
||||
return;
|
||||
},
|
||||
};
|
||||
let shader_modules =
|
||||
match ShaderModules::new(&device, &shaders, &pipeline_modes, has_shadow_views) {
|
||||
Ok(modules) => modules,
|
||||
Err(err) => {
|
||||
result_send.send(Err(err)).expect("Channel disconnected");
|
||||
return;
|
||||
},
|
||||
};
|
||||
drop(guard);
|
||||
|
||||
// Create new postprocess layouts
|
||||
let postprocess_layouts = Arc::new(postprocess::PostProcessLayout::new(
|
||||
&device,
|
||||
&pipeline_modes,
|
||||
));
|
||||
|
||||
let layouts = Layouts {
|
||||
immutable: immutable_layouts,
|
||||
postprocess: postprocess_layouts,
|
||||
};
|
||||
|
||||
let needs = PipelineNeeds {
|
||||
device: &device,
|
||||
layouts: &layouts,
|
||||
shaders: &shader_modules,
|
||||
mode: &mode,
|
||||
pipeline_modes: &pipeline_modes,
|
||||
sc_desc: &sc_desc,
|
||||
};
|
||||
|
||||
@ -837,7 +868,12 @@ pub(super) fn recreate_pipelines(
|
||||
|
||||
// Send them
|
||||
result_send
|
||||
.send(Ok((Pipelines::consolidate(interface, ingame), shadow)))
|
||||
.send(Ok((
|
||||
Pipelines::consolidate(interface, ingame),
|
||||
shadow,
|
||||
pipeline_modes,
|
||||
layouts.postprocess,
|
||||
)))
|
||||
.expect("Channel disconnected");
|
||||
});
|
||||
|
||||
|
@ -518,7 +518,7 @@ impl FigureMgr {
|
||||
let ray_direction = scene_data.get_sun_dir();
|
||||
let is_daylight = ray_direction.z < 0.0/*0.6*/;
|
||||
// Are shadows enabled at all?
|
||||
let can_shadow_sun = renderer.render_mode().shadow.is_map() && is_daylight;
|
||||
let can_shadow_sun = renderer.pipeline_modes().shadow.is_map() && is_daylight;
|
||||
let Dependents {
|
||||
proj_mat: _,
|
||||
view_mat: _,
|
||||
|
@ -681,7 +681,7 @@ impl Scene {
|
||||
|
||||
let sun_dir = scene_data.get_sun_dir();
|
||||
let is_daylight = sun_dir.z < 0.0;
|
||||
if renderer.render_mode().shadow.is_map() && (is_daylight || !lights.is_empty()) {
|
||||
if renderer.pipeline_modes().shadow.is_map() && (is_daylight || !lights.is_empty()) {
|
||||
let fov = self.camera.get_fov();
|
||||
let aspect_ratio = self.camera.get_aspect_ratio();
|
||||
|
||||
@ -1062,7 +1062,7 @@ impl Scene {
|
||||
let camera_data = (&self.camera, scene_data.figure_lod_render_distance);
|
||||
|
||||
// would instead have this as an extension.
|
||||
if drawer.render_mode().shadow.is_map() && (is_daylight || !self.light_data.is_empty()) {
|
||||
if drawer.pipeline_modes().shadow.is_map() && (is_daylight || !self.light_data.is_empty()) {
|
||||
if is_daylight {
|
||||
prof_span!("directed shadows");
|
||||
if let Some(mut shadow_pass) = drawer.shadow_pass() {
|
||||
|
@ -1244,7 +1244,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
return min.partial_cmple(&max).reduce_and();
|
||||
};
|
||||
let (visible_light_volume, visible_psr_bounds) = if ray_direction.z < 0.0
|
||||
&& renderer.render_mode().shadow.is_map()
|
||||
&& renderer.pipeline_modes().shadow.is_map()
|
||||
{
|
||||
let visible_bounding_box = math::Aabb::<f32> {
|
||||
min: math::Vec3::from(visible_bounding_box.min - focus_off),
|
||||
|
@ -1483,8 +1483,7 @@ impl PlayState for SessionState {
|
||||
second_pass.draw_clouds();
|
||||
}
|
||||
}
|
||||
// Bloom
|
||||
// TODO: make optional
|
||||
// Bloom (call does nothing if bloom is off)
|
||||
{
|
||||
prof_span!("bloom");
|
||||
drawer.run_bloom_passes()
|
||||
|
@ -43,6 +43,7 @@ pub struct GraphicsSettings {
|
||||
pub window_size: [u16; 2],
|
||||
pub fullscreen: FullScreenSettings,
|
||||
pub lod_detail: u32,
|
||||
pub bloom_enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for GraphicsSettings {
|
||||
@ -62,6 +63,7 @@ impl Default for GraphicsSettings {
|
||||
window_size: [1280, 720],
|
||||
fullscreen: FullScreenSettings::default(),
|
||||
lod_detail: 250,
|
||||
bloom_enabled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -791,8 +791,7 @@ impl Window {
|
||||
let physical = self.window.inner_size();
|
||||
|
||||
self.renderer
|
||||
.on_resize(Vec2::new(physical.width, physical.height))
|
||||
.unwrap();
|
||||
.on_resize(Vec2::new(physical.width, physical.height));
|
||||
// TODO: update users of this event with the fact that it is now the physical
|
||||
// size
|
||||
let winit::dpi::PhysicalSize { width, height } = physical;
|
||||
|
Loading…
Reference in New Issue
Block a user