Merge b0303fe359
into 877d278785
This commit is contained in:
commit
b096b10465
@ -467,6 +467,9 @@ tonemapping_luts = ["bevy_internal/tonemapping_luts", "ktx2", "bevy_image/zstd"]
|
||||
# Include SMAA Look Up Tables KTX2 Files
|
||||
smaa_luts = ["bevy_internal/smaa_luts"]
|
||||
|
||||
# NVIDIA Deep Learning Super Sampling
|
||||
dlss = ["bevy_internal/dlss"]
|
||||
|
||||
# Enable AccessKit on Unix backends (currently only works with experimental screen readers and forks.)
|
||||
accesskit_unix = ["bevy_internal/accesskit_unix"]
|
||||
|
||||
@ -1012,7 +1015,7 @@ doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.anti_aliasing]
|
||||
name = "Anti-aliasing"
|
||||
description = "Compares different anti-aliasing methods"
|
||||
description = "Compares different anti-aliasing techniques supported by Bevy"
|
||||
category = "3D Rendering"
|
||||
# TAA not supported by WebGL
|
||||
wasm = false
|
||||
|
@ -13,6 +13,7 @@ trace = []
|
||||
webgl = []
|
||||
webgpu = []
|
||||
smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
|
||||
dlss = ["dep:dlss_wgpu"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
@ -30,6 +31,7 @@ bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" }
|
||||
|
||||
# other
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
dlss_wgpu = { git = "https://github.com/bevyengine/dlss_wgpu", optional = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
29
crates/bevy_anti_aliasing/src/dlss/extract.rs
Normal file
29
crates/bevy_anti_aliasing/src/dlss/extract.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use super::{prepare::ViewDlssContext, Dlss};
|
||||
use bevy_ecs::{
|
||||
query::With,
|
||||
system::{Commands, ResMut},
|
||||
};
|
||||
use bevy_render::{
|
||||
camera::{Camera, MainPassResolutionOverride, Projection},
|
||||
sync_world::RenderEntity,
|
||||
view::Hdr,
|
||||
MainWorld,
|
||||
};
|
||||
|
||||
pub fn extract_dlss(mut commands: Commands, mut main_world: ResMut<MainWorld>) {
|
||||
let mut cameras_3d = main_world
|
||||
.query_filtered::<(RenderEntity, &Camera, &Projection, Option<&mut Dlss>), With<Hdr>>();
|
||||
|
||||
for (entity, camera, camera_projection, mut dlss) in cameras_3d.iter_mut(&mut main_world) {
|
||||
let has_perspective_projection = matches!(camera_projection, Projection::Perspective(_));
|
||||
let mut entity_commands = commands
|
||||
.get_entity(entity)
|
||||
.expect("Camera entity wasn't synced.");
|
||||
if dlss.is_some() && camera.is_active && has_perspective_projection {
|
||||
entity_commands.insert(dlss.as_deref().unwrap().clone());
|
||||
dlss.as_mut().unwrap().reset = false;
|
||||
} else {
|
||||
entity_commands.remove::<(Dlss, ViewDlssContext, MainPassResolutionOverride)>();
|
||||
}
|
||||
}
|
||||
}
|
116
crates/bevy_anti_aliasing/src/dlss/mod.rs
Normal file
116
crates/bevy_anti_aliasing/src/dlss/mod.rs
Normal file
@ -0,0 +1,116 @@
|
||||
//! NVIDIA Deep Learning Super Sampling (DLSS).
|
||||
//!
|
||||
//! DLSS uses machine learning models to upscale and anti-alias images.
|
||||
//!
|
||||
//! Requires a NVIDIA RTX GPU, and the Windows/Linux Vulkan rendering backend. Does not work on other platforms.
|
||||
//!
|
||||
//! See https://github.com/bevyengine/dlss_wgpu for licensing requirements and setup instructions.
|
||||
//!
|
||||
//! # Usage
|
||||
//! 1. Enable Bevy's `dlss` feature
|
||||
//! 2. During app setup, insert the `DlssProjectId` resource before `DefaultPlugins`
|
||||
//! 3. Check for the presence of `Option<Res<DlssSupported>>` at runtime to see if DLSS is supported on the current machine
|
||||
//! 4. Add the `Dlss` component to your camera entity, optionally setting a specific `DlssPerfQualityMode` (defaults to `Auto`)
|
||||
//! 5. Optionally add sharpening via `ContrastAdaptiveSharpening`
|
||||
//! 6. Custom rendering code, including third party crates, should account for the optional `MainPassResolutionOverride` to work with DLSS (see the `custom_render_phase` example)
|
||||
|
||||
mod extract;
|
||||
mod node;
|
||||
mod prepare;
|
||||
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_core_pipeline::{
|
||||
core_3d::graph::{Core3d, Node3d},
|
||||
prepass::{DepthPrepass, MotionVectorPrepass},
|
||||
};
|
||||
use bevy_ecs::{
|
||||
component::Component, prelude::ReflectComponent, resource::Resource,
|
||||
schedule::IntoScheduleConfigs,
|
||||
};
|
||||
use bevy_reflect::{prelude::ReflectDefault, reflect_remote, Reflect};
|
||||
use bevy_render::{
|
||||
camera::{MipBias, TemporalJitter},
|
||||
render_graph::{RenderGraphExt, ViewNodeRunner},
|
||||
renderer::RenderDevice,
|
||||
view::{prepare_view_targets, prepare_view_uniforms, Hdr},
|
||||
ExtractSchedule, Render, RenderApp, RenderSystems,
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tracing::info;
|
||||
|
||||
pub use bevy_render::{DlssProjectId, DlssSupported};
|
||||
pub use dlss_wgpu::DlssPerfQualityMode;
|
||||
|
||||
pub struct DlssPlugin;
|
||||
|
||||
impl Plugin for DlssPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<Dlss>();
|
||||
}
|
||||
|
||||
fn finish(&self, app: &mut App) {
|
||||
if app.world().get_resource::<DlssSupported>().is_none() {
|
||||
info!("DLSS is not supported on this system");
|
||||
return;
|
||||
}
|
||||
|
||||
let dlss_project_id = app.world().resource::<DlssProjectId>().0;
|
||||
|
||||
let render_app = app.get_sub_app_mut(RenderApp).unwrap();
|
||||
let render_device = render_app.world().resource::<RenderDevice>().clone();
|
||||
|
||||
let dlss_sdk =
|
||||
dlss_wgpu::DlssSdk::new(dlss_project_id, render_device.wgpu_device().clone());
|
||||
if dlss_sdk.is_err() {
|
||||
app.world_mut().remove_resource::<DlssSupported>();
|
||||
info!("DLSS is not supported on this system");
|
||||
return;
|
||||
}
|
||||
|
||||
render_app
|
||||
.insert_resource(DlssSdk(dlss_sdk.unwrap()))
|
||||
.add_systems(ExtractSchedule, extract::extract_dlss)
|
||||
.add_systems(
|
||||
Render,
|
||||
prepare::prepare_dlss
|
||||
.in_set(RenderSystems::ManageViews)
|
||||
.before(prepare_view_targets),
|
||||
)
|
||||
.add_render_graph_node::<ViewNodeRunner<node::DlssNode>>(Core3d, Node3d::Dlss)
|
||||
.add_render_graph_edges(
|
||||
Core3d,
|
||||
(
|
||||
Node3d::EndMainPass,
|
||||
Node3d::MotionBlur, // Running before DLSS reduces edge artifacts and noise
|
||||
Node3d::Dlss,
|
||||
Node3d::Bloom,
|
||||
Node3d::Tonemapping,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Camera component to enable DLSS.
|
||||
#[derive(Component, Reflect, Clone, Default)]
|
||||
#[reflect(Component, Default)]
|
||||
#[require(TemporalJitter, MipBias, DepthPrepass, MotionVectorPrepass, Hdr)]
|
||||
pub struct Dlss {
|
||||
#[reflect(remote = DlssPerfQualityModeRemoteReflect)]
|
||||
pub perf_quality_mode: DlssPerfQualityMode,
|
||||
pub reset: bool,
|
||||
}
|
||||
|
||||
#[reflect_remote(DlssPerfQualityMode)]
|
||||
#[derive(Default)]
|
||||
enum DlssPerfQualityModeRemoteReflect {
|
||||
#[default]
|
||||
Auto,
|
||||
Dlaa,
|
||||
Quality,
|
||||
Balanced,
|
||||
Performance,
|
||||
UltraPerformance,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
struct DlssSdk(Arc<Mutex<dlss_wgpu::DlssSdk>>);
|
85
crates/bevy_anti_aliasing/src/dlss/node.rs
Normal file
85
crates/bevy_anti_aliasing/src/dlss/node.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use super::{prepare::ViewDlssContext, Dlss};
|
||||
use bevy_core_pipeline::prepass::ViewPrepassTextures;
|
||||
use bevy_ecs::{query::QueryItem, world::World};
|
||||
use bevy_render::{
|
||||
camera::{MainPassResolutionOverride, TemporalJitter},
|
||||
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
|
||||
renderer::{RenderAdapter, RenderContext},
|
||||
view::ViewTarget,
|
||||
};
|
||||
use dlss_wgpu::{DlssExposure, DlssRenderParameters, DlssTexture};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DlssNode;
|
||||
|
||||
impl ViewNode for DlssNode {
|
||||
type ViewQuery = (
|
||||
&'static Dlss,
|
||||
&'static ViewDlssContext,
|
||||
&'static MainPassResolutionOverride,
|
||||
&'static TemporalJitter,
|
||||
&'static ViewTarget,
|
||||
&'static ViewPrepassTextures,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext,
|
||||
(
|
||||
dlss,
|
||||
dlss_context,
|
||||
resolution_override,
|
||||
temporal_jitter,
|
||||
view_target,
|
||||
prepass_textures,
|
||||
): QueryItem<Self::ViewQuery>,
|
||||
world: &World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let adapter = world.resource::<RenderAdapter>();
|
||||
let (Some(prepass_motion_vectors_texture), Some(prepass_depth_texture)) =
|
||||
(&prepass_textures.motion_vectors, &prepass_textures.depth)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let view_target = view_target.post_process_write();
|
||||
|
||||
let render_resolution = resolution_override.0;
|
||||
let render_parameters = DlssRenderParameters {
|
||||
color: DlssTexture {
|
||||
texture: &view_target.source_texture,
|
||||
view: &view_target.source,
|
||||
},
|
||||
depth: DlssTexture {
|
||||
texture: &prepass_depth_texture.texture.texture,
|
||||
view: &prepass_depth_texture.texture.default_view,
|
||||
},
|
||||
motion_vectors: DlssTexture {
|
||||
texture: &prepass_motion_vectors_texture.texture.texture,
|
||||
view: &prepass_motion_vectors_texture.texture.default_view,
|
||||
},
|
||||
exposure: DlssExposure::Automatic, // TODO
|
||||
bias: None, // TODO
|
||||
dlss_output: DlssTexture {
|
||||
texture: &view_target.destination_texture,
|
||||
view: &view_target.destination,
|
||||
},
|
||||
reset: dlss.reset,
|
||||
jitter_offset: -temporal_jitter.offset,
|
||||
partial_texture_size: Some(render_resolution),
|
||||
motion_vector_scale: Some(-render_resolution.as_vec2()),
|
||||
};
|
||||
|
||||
let command_encoder = render_context.command_encoder();
|
||||
let mut dlss_context = dlss_context.context.lock().unwrap();
|
||||
|
||||
command_encoder.push_debug_group("dlss");
|
||||
dlss_context
|
||||
.render(render_parameters, command_encoder, &adapter)
|
||||
.expect("Failed to render DLSS");
|
||||
command_encoder.pop_debug_group();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
117
crates/bevy_anti_aliasing/src/dlss/prepare.rs
Normal file
117
crates/bevy_anti_aliasing/src/dlss/prepare.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use super::{Dlss, DlssSdk};
|
||||
use bevy_core_pipeline::{
|
||||
core_3d::Camera3d,
|
||||
prepass::{DepthPrepass, MotionVectorPrepass},
|
||||
};
|
||||
use bevy_diagnostic::FrameCount;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
query::With,
|
||||
system::{Commands, Query, Res},
|
||||
};
|
||||
use bevy_math::Vec4Swizzles;
|
||||
use bevy_render::{
|
||||
camera::{CameraMainTextureUsages, MainPassResolutionOverride, MipBias, TemporalJitter},
|
||||
render_resource::TextureUsages,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
view::ExtractedView,
|
||||
};
|
||||
use dlss_wgpu::{DlssContext, DlssFeatureFlags, DlssPerfQualityMode};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct ViewDlssContext {
|
||||
pub context: Mutex<DlssContext>,
|
||||
pub perf_quality_mode: DlssPerfQualityMode,
|
||||
pub feature_flags: DlssFeatureFlags,
|
||||
}
|
||||
|
||||
pub fn prepare_dlss(
|
||||
mut query: Query<
|
||||
(
|
||||
Entity,
|
||||
&ExtractedView,
|
||||
&Dlss,
|
||||
&mut Camera3d,
|
||||
&mut CameraMainTextureUsages,
|
||||
&mut TemporalJitter,
|
||||
&mut MipBias,
|
||||
Option<&mut ViewDlssContext>,
|
||||
),
|
||||
(
|
||||
With<Camera3d>,
|
||||
With<TemporalJitter>,
|
||||
With<DepthPrepass>,
|
||||
With<MotionVectorPrepass>,
|
||||
),
|
||||
>,
|
||||
dlss_sdk: Res<DlssSdk>,
|
||||
render_device: Res<RenderDevice>,
|
||||
render_queue: Res<RenderQueue>,
|
||||
frame_count: Res<FrameCount>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for (
|
||||
entity,
|
||||
view,
|
||||
dlss,
|
||||
mut camera_3d,
|
||||
mut camera_main_texture_usages,
|
||||
mut temporal_jitter,
|
||||
mut mip_bias,
|
||||
mut dlss_context,
|
||||
) in &mut query
|
||||
{
|
||||
camera_main_texture_usages.0 |= TextureUsages::STORAGE_BINDING;
|
||||
|
||||
let mut depth_texture_usages = TextureUsages::from(camera_3d.depth_texture_usages);
|
||||
depth_texture_usages |= TextureUsages::TEXTURE_BINDING;
|
||||
camera_3d.depth_texture_usages = depth_texture_usages.into();
|
||||
|
||||
let upscaled_resolution = view.viewport.zw();
|
||||
|
||||
let dlss_feature_flags = DlssFeatureFlags::LowResolutionMotionVectors
|
||||
| DlssFeatureFlags::InvertedDepth
|
||||
| DlssFeatureFlags::HighDynamicRange
|
||||
| DlssFeatureFlags::AutoExposure; // TODO
|
||||
|
||||
match dlss_context.as_deref_mut() {
|
||||
Some(dlss_context)
|
||||
if upscaled_resolution
|
||||
== dlss_context.context.lock().unwrap().upscaled_resolution()
|
||||
&& dlss.perf_quality_mode == dlss_context.perf_quality_mode
|
||||
&& dlss_feature_flags == dlss_context.feature_flags =>
|
||||
{
|
||||
let dlss_context = dlss_context.context.lock().unwrap();
|
||||
temporal_jitter.offset =
|
||||
dlss_context.suggested_jitter(frame_count.0, dlss_context.render_resolution());
|
||||
}
|
||||
_ => {
|
||||
let dlss_context = DlssContext::new(
|
||||
upscaled_resolution,
|
||||
dlss.perf_quality_mode,
|
||||
dlss_feature_flags,
|
||||
Arc::clone(&dlss_sdk.0),
|
||||
render_device.wgpu_device(),
|
||||
&render_queue,
|
||||
)
|
||||
.expect("Failed to create DlssContext");
|
||||
|
||||
let render_resolution = dlss_context.render_resolution();
|
||||
temporal_jitter.offset =
|
||||
dlss_context.suggested_jitter(frame_count.0, render_resolution);
|
||||
mip_bias.0 = dlss_context.suggested_mip_bias(render_resolution);
|
||||
|
||||
commands.entity(entity).insert((
|
||||
ViewDlssContext {
|
||||
context: Mutex::new(dlss_context),
|
||||
perf_quality_mode: dlss.perf_quality_mode,
|
||||
feature_flags: dlss_feature_flags,
|
||||
},
|
||||
MainPassResolutionOverride(render_resolution),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ use smaa::SmaaPlugin;
|
||||
use taa::TemporalAntiAliasPlugin;
|
||||
|
||||
pub mod contrast_adaptive_sharpening;
|
||||
#[cfg(feature = "dlss")]
|
||||
pub mod dlss;
|
||||
pub mod fxaa;
|
||||
pub mod smaa;
|
||||
pub mod taa;
|
||||
@ -21,6 +23,13 @@ pub mod taa;
|
||||
pub struct AntiAliasingPlugin;
|
||||
impl Plugin for AntiAliasingPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.add_plugins((FxaaPlugin, SmaaPlugin, TemporalAntiAliasPlugin, CasPlugin));
|
||||
app.add_plugins((
|
||||
FxaaPlugin,
|
||||
SmaaPlugin,
|
||||
TemporalAntiAliasPlugin,
|
||||
CasPlugin,
|
||||
#[cfg(feature = "dlss")]
|
||||
dlss::DlssPlugin,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -80,14 +80,20 @@ impl Viewport {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_override(
|
||||
&self,
|
||||
pub fn from_viewport_and_override(
|
||||
viewport: Option<&Self>,
|
||||
main_pass_resolution_override: Option<&MainPassResolutionOverride>,
|
||||
) -> Self {
|
||||
let mut viewport = self.clone();
|
||||
) -> Option<Self> {
|
||||
let mut viewport = viewport.cloned();
|
||||
|
||||
if let Some(override_size) = main_pass_resolution_override {
|
||||
viewport.physical_size = **override_size;
|
||||
if viewport.is_none() {
|
||||
viewport = Some(Viewport::default());
|
||||
}
|
||||
|
||||
viewport.as_mut().unwrap().physical_size = **override_size;
|
||||
}
|
||||
|
||||
viewport
|
||||
}
|
||||
}
|
||||
@ -101,7 +107,7 @@ impl Viewport {
|
||||
/// * Insert this component on a 3d camera entity in the render world.
|
||||
/// * The resolution override must be smaller than the camera's viewport size.
|
||||
/// * The resolution override is specified in physical pixels.
|
||||
#[derive(Component, Reflect, Deref)]
|
||||
#[derive(Component, Reflect, Deref, Debug)]
|
||||
#[reflect(Component)]
|
||||
pub struct MainPassResolutionOverride(pub UVec2);
|
||||
|
||||
|
@ -2,6 +2,7 @@ use crate::{
|
||||
core_3d::Opaque3d,
|
||||
skybox::{SkyboxBindGroup, SkyboxPipelineId},
|
||||
};
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_ecs::{prelude::World, query::QueryItem};
|
||||
use bevy_render::{
|
||||
camera::{ExtractedCamera, MainPassResolutionOverride},
|
||||
@ -91,8 +92,10 @@ impl ViewNode for MainOpaquePass3dNode {
|
||||
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
|
||||
let pass_span = diagnostics.pass_span(&mut render_pass, "main_opaque_pass_3d");
|
||||
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
// Opaque draws
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::{Camera3d, ViewTransmissionTexture};
|
||||
use crate::core_3d::Transmissive3d;
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_image::ToExtents;
|
||||
use bevy_render::{
|
||||
@ -110,8 +111,11 @@ impl ViewNode for MainTransmissivePass3dNode {
|
||||
let mut render_pass =
|
||||
render_context.begin_tracked_render_pass(render_pass_descriptor);
|
||||
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) = Viewport::from_viewport_and_override(
|
||||
camera.viewport.as_ref(),
|
||||
resolution_override,
|
||||
) {
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
if let Err(err) = transmissive_phase.render(&mut render_pass, world, view_entity) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::core_3d::Transparent3d;
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_render::{
|
||||
camera::{ExtractedCamera, MainPassResolutionOverride},
|
||||
@ -69,8 +70,10 @@ impl ViewNode for MainTransparentPass3dNode {
|
||||
|
||||
let pass_span = diagnostics.pass_span(&mut render_pass, "main_transparent_pass_3d");
|
||||
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {
|
||||
|
@ -29,8 +29,9 @@ pub mod graph {
|
||||
EndMainPass,
|
||||
Wireframe,
|
||||
LateDownsampleDepth,
|
||||
Taa,
|
||||
MotionBlur,
|
||||
Taa,
|
||||
Dlss,
|
||||
Bloom,
|
||||
AutoExposure,
|
||||
DepthOfField,
|
||||
|
@ -1,3 +1,4 @@
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_render::camera::MainPassResolutionOverride;
|
||||
use bevy_render::experimental::occlusion_culling::OcclusionCulling;
|
||||
@ -221,8 +222,10 @@ fn run_deferred_prepass<'w>(
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
// Opaque draws
|
||||
|
@ -1,3 +1,4 @@
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_render::{
|
||||
camera::{ExtractedCamera, MainPassResolutionOverride},
|
||||
@ -63,8 +64,10 @@ impl ViewNode for OitResolveNode {
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
render_pass.set_render_pipeline(pipeline);
|
||||
|
@ -1,3 +1,4 @@
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_ecs::{prelude::*, query::QueryItem};
|
||||
use bevy_render::{
|
||||
camera::{ExtractedCamera, MainPassResolutionOverride},
|
||||
@ -186,8 +187,10 @@ fn run_prepass<'w>(
|
||||
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
|
||||
let pass_span = diagnostics.pass_span(&mut render_pass, label);
|
||||
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
// Opaque draws
|
||||
|
@ -73,6 +73,9 @@ tonemapping_luts = ["bevy_core_pipeline/tonemapping_luts"]
|
||||
# Include SMAA LUT KTX2 Files
|
||||
smaa_luts = ["bevy_anti_aliasing/smaa_luts"]
|
||||
|
||||
# NVIDIA Deep Learning Super Sampling
|
||||
dlss = ["bevy_anti_aliasing/dlss", "bevy_render/dlss"]
|
||||
|
||||
# Audio format support (vorbis is enabled by default)
|
||||
flac = ["bevy_audio/flac"]
|
||||
mp3 = ["bevy_audio/mp3"]
|
||||
|
@ -10,6 +10,7 @@ use crate::{
|
||||
MeshViewBindGroup, PrepassViewBindGroup, ViewEnvironmentMapUniformOffset, ViewFogUniformOffset,
|
||||
ViewLightProbesUniformOffset, ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset,
|
||||
};
|
||||
use bevy_camera::Viewport;
|
||||
use bevy_core_pipeline::prepass::{
|
||||
MotionVectorPrepass, PreviousViewUniformOffset, ViewPrepassTextures,
|
||||
};
|
||||
@ -102,8 +103,10 @@ impl ViewNode for MeshletMainOpaquePass3dNode {
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
render_pass.set_bind_group(
|
||||
@ -223,8 +226,10 @@ impl ViewNode for MeshletPrepassNode {
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
if view_has_motion_vector_prepass {
|
||||
@ -354,8 +359,10 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
if view_has_motion_vector_prepass {
|
||||
|
@ -51,6 +51,7 @@ webgpu = ["wgpu/webgpu"]
|
||||
detailed_trace = []
|
||||
## Adds serialization support through `serde`.
|
||||
serialize = ["bevy_mesh/serialize"]
|
||||
dlss = ["dep:dlss_wgpu"]
|
||||
|
||||
[dependencies]
|
||||
# bevy
|
||||
@ -102,6 +103,7 @@ wgpu = { version = "25", default-features = false, features = [
|
||||
"fragile-send-sync-non-atomic-wasm",
|
||||
] }
|
||||
naga = { version = "25", features = ["wgsl-in"] }
|
||||
dlss_wgpu = { git = "https://github.com/bevyengine/dlss_wgpu", optional = true }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
bytemuck = { version = "1.5", features = ["derive", "must_cast"] }
|
||||
downcast-rs = { version = "2", default-features = false, features = ["std"] }
|
||||
|
@ -109,7 +109,7 @@ use crate::{
|
||||
mesh::{MeshPlugin, MorphPlugin, RenderMesh},
|
||||
render_asset::prepare_assets,
|
||||
render_resource::{PipelineCache, Shader, ShaderLoader},
|
||||
renderer::{render_system, RenderInstance},
|
||||
renderer::render_system,
|
||||
settings::RenderCreation,
|
||||
storage::StoragePlugin,
|
||||
view::{ViewPlugin, WindowRenderPlugin},
|
||||
@ -118,11 +118,9 @@ use alloc::sync::Arc;
|
||||
use bevy_app::{App, AppLabel, Plugin, SubApp};
|
||||
use bevy_asset::{AssetApp, AssetServer};
|
||||
use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
|
||||
use bevy_utils::WgpuWrapper;
|
||||
use bitflags::bitflags;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use std::sync::Mutex;
|
||||
use tracing::debug;
|
||||
|
||||
/// Inline shader as an `embedded_asset` and load it permanently.
|
||||
///
|
||||
@ -355,6 +353,14 @@ impl Plugin for RenderPlugin {
|
||||
.ok()
|
||||
.cloned();
|
||||
let settings = render_creation.clone();
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
let dlss_project_id = app
|
||||
.world()
|
||||
.get_resource::<DlssProjectId>()
|
||||
.expect("The `dlss` feature is enabled, but DlssProjectId was not added to the App before DefaultPlugins.")
|
||||
.0;
|
||||
|
||||
let async_renderer = async move {
|
||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
||||
backends,
|
||||
@ -403,25 +409,17 @@ impl Plugin for RenderPlugin {
|
||||
force_fallback_adapter,
|
||||
};
|
||||
|
||||
let (device, queue, adapter_info, render_adapter) =
|
||||
renderer::initialize_renderer(
|
||||
&instance,
|
||||
&settings,
|
||||
&request_adapter_options,
|
||||
desired_adapter_name,
|
||||
)
|
||||
.await;
|
||||
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
|
||||
debug!("Configured wgpu adapter Features: {:#?}", device.features());
|
||||
let mut future_render_resources_inner =
|
||||
future_render_resources_wrapper.lock().unwrap();
|
||||
*future_render_resources_inner = Some(RenderResources(
|
||||
device,
|
||||
queue,
|
||||
adapter_info,
|
||||
render_adapter,
|
||||
RenderInstance(Arc::new(WgpuWrapper::new(instance))),
|
||||
));
|
||||
let render_resources = renderer::initialize_renderer(
|
||||
instance,
|
||||
&settings,
|
||||
&request_adapter_options,
|
||||
desired_adapter_name,
|
||||
#[cfg(feature = "dlss")]
|
||||
dlss_project_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
*future_render_resources_wrapper.lock().unwrap() = Some(render_resources);
|
||||
};
|
||||
// In wasm, spawn a task and detach it for execution
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@ -490,6 +488,16 @@ impl Plugin for RenderPlugin {
|
||||
if let Some(future_render_resources) =
|
||||
app.world_mut().remove_resource::<FutureRenderResources>()
|
||||
{
|
||||
#[cfg(feature = "dlss")]
|
||||
let RenderResources(
|
||||
device,
|
||||
queue,
|
||||
adapter_info,
|
||||
render_adapter,
|
||||
instance,
|
||||
dlss_available,
|
||||
) = future_render_resources.0.lock().unwrap().take().unwrap();
|
||||
#[cfg(not(feature = "dlss"))]
|
||||
let RenderResources(device, queue, adapter_info, render_adapter, instance) =
|
||||
future_render_resources.0.lock().unwrap().take().unwrap();
|
||||
|
||||
@ -503,6 +511,11 @@ impl Plugin for RenderPlugin {
|
||||
.insert_resource(render_adapter.clone())
|
||||
.insert_resource(compressed_image_format_support);
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
if let Some(dlss_available) = dlss_available {
|
||||
app.insert_resource(dlss_available);
|
||||
}
|
||||
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
|
||||
render_app
|
||||
@ -659,3 +672,16 @@ pub fn get_mali_driver_version(adapter: &RenderAdapter) -> Option<u32> {
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Application-specific ID for DLSS.
|
||||
///
|
||||
/// See the DLSS programming guide for more info.
|
||||
#[cfg(feature = "dlss")]
|
||||
#[derive(Resource)]
|
||||
pub struct DlssProjectId(pub bevy_asset::uuid::Uuid);
|
||||
|
||||
/// When DLSS is supported by the current system, this resource will exist in the main world.
|
||||
/// Otherwise this resource will be absent.
|
||||
#[cfg(feature = "dlss")]
|
||||
#[derive(Resource, Clone, Copy)]
|
||||
pub struct DlssSupported;
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
render_graph::RenderGraph,
|
||||
render_phase::TrackedRenderPass,
|
||||
render_resource::RenderPassDescriptor,
|
||||
settings::{WgpuSettings, WgpuSettingsPriority},
|
||||
settings::{RenderResources, WgpuSettings, WgpuSettingsPriority},
|
||||
view::{ExtractedWindows, ViewTarget},
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
@ -175,15 +175,16 @@ fn find_adapter_by_name(
|
||||
/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
|
||||
/// for the specified backend.
|
||||
pub async fn initialize_renderer(
|
||||
instance: &Instance,
|
||||
instance: Instance,
|
||||
options: &WgpuSettings,
|
||||
request_adapter_options: &RequestAdapterOptions<'_, '_>,
|
||||
desired_adapter_name: Option<String>,
|
||||
) -> (RenderDevice, RenderQueue, RenderAdapterInfo, RenderAdapter) {
|
||||
#[cfg(feature = "dlss")] dlss_project_id: bevy_asset::uuid::Uuid,
|
||||
) -> RenderResources {
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
let mut selected_adapter = desired_adapter_name.and_then(|adapter_name| {
|
||||
find_adapter_by_name(
|
||||
instance,
|
||||
&instance,
|
||||
options,
|
||||
request_adapter_options.compatible_surface,
|
||||
&adapter_name,
|
||||
@ -358,24 +359,47 @@ pub async fn initialize_renderer(
|
||||
};
|
||||
}
|
||||
|
||||
let (device, queue) = adapter
|
||||
.request_device(&wgpu::DeviceDescriptor {
|
||||
label: options.device_label.as_ref().map(AsRef::as_ref),
|
||||
required_features: features,
|
||||
required_limits: limits,
|
||||
memory_hints: options.memory_hints.clone(),
|
||||
// See https://github.com/gfx-rs/wgpu/issues/5974
|
||||
trace: Trace::Off,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let queue = Arc::new(WgpuWrapper::new(queue));
|
||||
let adapter = Arc::new(WgpuWrapper::new(adapter));
|
||||
(
|
||||
let device_descriptor = wgpu::DeviceDescriptor {
|
||||
label: options.device_label.as_ref().map(AsRef::as_ref),
|
||||
required_features: features,
|
||||
required_limits: limits,
|
||||
memory_hints: options.memory_hints.clone(),
|
||||
// See https://github.com/gfx-rs/wgpu/issues/5974
|
||||
trace: Trace::Off,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "dlss"))]
|
||||
let (device, queue) = adapter.request_device(&device_descriptor).await.unwrap();
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
let mut dlss_supported = false;
|
||||
#[cfg(feature = "dlss")]
|
||||
let (device, queue) = {
|
||||
match dlss_wgpu::request_device(dlss_project_id, &adapter, &device_descriptor) {
|
||||
Ok(x) => {
|
||||
dlss_supported = true;
|
||||
x
|
||||
}
|
||||
// Fallback to standard device request
|
||||
Err(_) => adapter.request_device(&device_descriptor).await.unwrap(),
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
|
||||
debug!("Configured wgpu adapter Features: {:#?}", device.features());
|
||||
|
||||
RenderResources(
|
||||
RenderDevice::from(device),
|
||||
RenderQueue(queue),
|
||||
RenderQueue(Arc::new(WgpuWrapper::new(queue))),
|
||||
RenderAdapterInfo(WgpuWrapper::new(adapter_info)),
|
||||
RenderAdapter(adapter),
|
||||
RenderAdapter(Arc::new(WgpuWrapper::new(adapter))),
|
||||
RenderInstance(Arc::new(WgpuWrapper::new(instance))),
|
||||
#[cfg(feature = "dlss")]
|
||||
if dlss_supported {
|
||||
Some(crate::DlssSupported)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -148,11 +148,12 @@ impl Default for WgpuSettings {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RenderResources(
|
||||
pub RenderDevice,
|
||||
pub RenderQueue,
|
||||
pub RenderAdapterInfo,
|
||||
pub RenderAdapter,
|
||||
pub RenderInstance,
|
||||
pub(crate) RenderDevice,
|
||||
pub(crate) RenderQueue,
|
||||
pub(crate) RenderAdapterInfo,
|
||||
pub(crate) RenderAdapter,
|
||||
pub(crate) RenderInstance,
|
||||
#[cfg(feature = "dlss")] pub(crate) Option<crate::DlssSupported>,
|
||||
);
|
||||
|
||||
/// An enum describing how the renderer will initialize resources. This is used when creating the [`RenderPlugin`](crate::RenderPlugin).
|
||||
@ -176,7 +177,16 @@ impl RenderCreation {
|
||||
adapter: RenderAdapter,
|
||||
instance: RenderInstance,
|
||||
) -> Self {
|
||||
RenderResources(device, queue, adapter_info, adapter, instance).into()
|
||||
RenderResources(
|
||||
device,
|
||||
queue,
|
||||
adapter_info,
|
||||
adapter,
|
||||
instance,
|
||||
#[cfg(feature = "dlss")]
|
||||
None,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ pub mod window;
|
||||
|
||||
use bevy_camera::{
|
||||
primitives::Frustum, CameraMainTextureUsages, ClearColor, ClearColorConfig, Exposure,
|
||||
MainPassResolutionOverride,
|
||||
};
|
||||
use bevy_diagnostic::FrameCount;
|
||||
pub use visibility::*;
|
||||
@ -901,6 +902,7 @@ pub fn prepare_view_uniforms(
|
||||
Option<&Frustum>,
|
||||
Option<&TemporalJitter>,
|
||||
Option<&MipBias>,
|
||||
Option<&MainPassResolutionOverride>,
|
||||
)>,
|
||||
frame_count: Res<FrameCount>,
|
||||
) {
|
||||
@ -913,13 +915,23 @@ pub fn prepare_view_uniforms(
|
||||
else {
|
||||
return;
|
||||
};
|
||||
for (entity, extracted_camera, extracted_view, frustum, temporal_jitter, mip_bias) in &views {
|
||||
for (
|
||||
entity,
|
||||
extracted_camera,
|
||||
extracted_view,
|
||||
frustum,
|
||||
temporal_jitter,
|
||||
mip_bias,
|
||||
resolution_override,
|
||||
) in &views
|
||||
{
|
||||
let viewport = extracted_view.viewport.as_vec4();
|
||||
let unjittered_projection = extracted_view.clip_from_view;
|
||||
let mut clip_from_view = unjittered_projection;
|
||||
|
||||
if let Some(temporal_jitter) = temporal_jitter {
|
||||
temporal_jitter.jitter_projection(&mut clip_from_view, viewport.zw());
|
||||
let jitter_view_size = resolution_override.map_or(viewport.zw(), |v| v.0.as_vec2());
|
||||
temporal_jitter.jitter_projection(&mut clip_from_view, jitter_view_size);
|
||||
}
|
||||
|
||||
let view_from_clip = clip_from_view.inverse();
|
||||
|
@ -141,6 +141,9 @@ impl ViewNode for SolariLightingNode {
|
||||
});
|
||||
let pass_span = diagnostics.pass_span(&mut pass, "solari_lighting");
|
||||
|
||||
let dx = solari_lighting_resources.view_size.x.div_ceil(8);
|
||||
let dy = solari_lighting_resources.view_size.y.div_ceil(8);
|
||||
|
||||
pass.set_bind_group(0, scene_bindings, &[]);
|
||||
pass.set_bind_group(
|
||||
1,
|
||||
@ -156,16 +159,16 @@ impl ViewNode for SolariLightingNode {
|
||||
0,
|
||||
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
|
||||
);
|
||||
pass.dispatch_workgroups(viewport.x.div_ceil(8), viewport.y.div_ceil(8), 1);
|
||||
pass.dispatch_workgroups(dx, dy, 1);
|
||||
|
||||
pass.set_pipeline(di_spatial_and_shade_pipeline);
|
||||
pass.dispatch_workgroups(viewport.x.div_ceil(8), viewport.y.div_ceil(8), 1);
|
||||
pass.dispatch_workgroups(dx, dy, 1);
|
||||
|
||||
pass.set_pipeline(gi_initial_and_temporal_pipeline);
|
||||
pass.dispatch_workgroups(viewport.x.div_ceil(8), viewport.y.div_ceil(8), 1);
|
||||
pass.dispatch_workgroups(dx, dy, 1);
|
||||
|
||||
pass.set_pipeline(gi_spatial_and_shade_pipeline);
|
||||
pass.dispatch_workgroups(viewport.x.div_ceil(8), viewport.y.div_ceil(8), 1);
|
||||
pass.dispatch_workgroups(dx, dy, 1);
|
||||
|
||||
pass_span.end(&mut pass);
|
||||
drop(pass);
|
||||
|
@ -9,7 +9,7 @@ use bevy_ecs::{
|
||||
use bevy_image::ToExtents;
|
||||
use bevy_math::UVec2;
|
||||
use bevy_render::{
|
||||
camera::ExtractedCamera,
|
||||
camera::{ExtractedCamera, MainPassResolutionOverride},
|
||||
render_resource::{
|
||||
Buffer, BufferDescriptor, BufferUsages, Texture, TextureDescriptor, TextureDimension,
|
||||
TextureUsages, TextureView, TextureViewDescriptor,
|
||||
@ -37,16 +37,24 @@ pub struct SolariLightingResources {
|
||||
|
||||
pub fn prepare_solari_lighting_resources(
|
||||
query: Query<
|
||||
(Entity, &ExtractedCamera, Option<&SolariLightingResources>),
|
||||
(
|
||||
Entity,
|
||||
&ExtractedCamera,
|
||||
Option<&SolariLightingResources>,
|
||||
Option<&MainPassResolutionOverride>,
|
||||
),
|
||||
With<SolariLighting>,
|
||||
>,
|
||||
render_device: Res<RenderDevice>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for (entity, camera, solari_lighting_resources) in &query {
|
||||
let Some(view_size) = camera.physical_viewport_size else {
|
||||
for (entity, camera, solari_lighting_resources, resolution_override) in &query {
|
||||
let Some(mut view_size) = camera.physical_viewport_size else {
|
||||
continue;
|
||||
};
|
||||
if let Some(MainPassResolutionOverride(resolution_override)) = resolution_override {
|
||||
view_size = *resolution_override;
|
||||
}
|
||||
|
||||
if solari_lighting_resources.map(|r| r.view_size) == Some(view_size) {
|
||||
continue;
|
||||
|
@ -80,6 +80,7 @@ The default feature set enables most of the expected features of a game engine,
|
||||
|debug_glam_assert|Enable assertions in debug builds to check the validity of parameters passed to glam|
|
||||
|default_no_std|Recommended defaults for no_std applications|
|
||||
|detailed_trace|Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in|
|
||||
|dlss|NVIDIA Deep Learning Super Sampling|
|
||||
|dynamic_linking|Force dynamic linking, which improves iterative compile times|
|
||||
|embedded_watcher|Enables watching in memory asset providers for Bevy Asset hot-reloading|
|
||||
|experimental_bevy_feathers|Feathers widget collection.|
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! This example compares MSAA (Multi-Sample Anti-aliasing), FXAA (Fast Approximate Anti-aliasing), and TAA (Temporal Anti-aliasing).
|
||||
//! Compares different anti-aliasing techniques supported by Bevy.
|
||||
|
||||
use std::{f32::consts::PI, fmt::Write};
|
||||
|
||||
@ -21,12 +21,22 @@ use bevy::{
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
use bevy::anti_aliasing::dlss::{Dlss, DlssPerfQualityMode, DlssProjectId, DlssSupported};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
let mut app = App::new();
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
app.insert_resource(DlssProjectId(bevy_asset::uuid::uuid!(
|
||||
"5417916c-0291-4e3f-8f65-326c1858ab96"
|
||||
)));
|
||||
|
||||
app.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, (modify_aa, modify_sharpening, update_ui))
|
||||
.run();
|
||||
.add_systems(Update, (modify_aa, modify_sharpening, update_ui));
|
||||
|
||||
app.run();
|
||||
}
|
||||
|
||||
type TaaComponents = (
|
||||
@ -37,9 +47,31 @@ type TaaComponents = (
|
||||
MotionVectorPrepass,
|
||||
);
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
type DlssComponents = (
|
||||
Dlss,
|
||||
TemporalJitter,
|
||||
MipBias,
|
||||
DepthPrepass,
|
||||
MotionVectorPrepass,
|
||||
);
|
||||
#[cfg(not(feature = "dlss"))]
|
||||
type DlssComponents = ();
|
||||
|
||||
fn modify_aa(
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
camera: Single<
|
||||
#[cfg(feature = "dlss")] camera: Single<
|
||||
(
|
||||
Entity,
|
||||
Option<&mut Fxaa>,
|
||||
Option<&mut Smaa>,
|
||||
Option<&TemporalAntiAliasing>,
|
||||
&mut Msaa,
|
||||
Option<&mut Dlss>,
|
||||
),
|
||||
With<Camera>,
|
||||
>,
|
||||
#[cfg(not(feature = "dlss"))] camera: Single<
|
||||
(
|
||||
Entity,
|
||||
Option<&mut Fxaa>,
|
||||
@ -49,8 +81,12 @@ fn modify_aa(
|
||||
),
|
||||
With<Camera>,
|
||||
>,
|
||||
#[cfg(feature = "dlss")] dlss_supported: Option<Res<DlssSupported>>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
#[cfg(feature = "dlss")]
|
||||
let (camera_entity, fxaa, smaa, taa, mut msaa, dlss) = camera.into_inner();
|
||||
#[cfg(not(feature = "dlss"))]
|
||||
let (camera_entity, fxaa, smaa, taa, mut msaa) = camera.into_inner();
|
||||
let mut camera = commands.entity(camera_entity);
|
||||
|
||||
@ -60,7 +96,8 @@ fn modify_aa(
|
||||
camera
|
||||
.remove::<Fxaa>()
|
||||
.remove::<Smaa>()
|
||||
.remove::<TaaComponents>();
|
||||
.remove::<TaaComponents>()
|
||||
.remove::<DlssComponents>();
|
||||
}
|
||||
|
||||
// MSAA
|
||||
@ -68,7 +105,8 @@ fn modify_aa(
|
||||
camera
|
||||
.remove::<Fxaa>()
|
||||
.remove::<Smaa>()
|
||||
.remove::<TaaComponents>();
|
||||
.remove::<TaaComponents>()
|
||||
.remove::<DlssComponents>();
|
||||
|
||||
*msaa = Msaa::Sample4;
|
||||
}
|
||||
@ -92,6 +130,7 @@ fn modify_aa(
|
||||
camera
|
||||
.remove::<Smaa>()
|
||||
.remove::<TaaComponents>()
|
||||
.remove::<DlssComponents>()
|
||||
.insert(Fxaa::default());
|
||||
}
|
||||
|
||||
@ -125,6 +164,7 @@ fn modify_aa(
|
||||
camera
|
||||
.remove::<Fxaa>()
|
||||
.remove::<TaaComponents>()
|
||||
.remove::<DlssComponents>()
|
||||
.insert(Smaa::default());
|
||||
}
|
||||
|
||||
@ -150,8 +190,43 @@ fn modify_aa(
|
||||
camera
|
||||
.remove::<Fxaa>()
|
||||
.remove::<Smaa>()
|
||||
.remove::<DlssComponents>()
|
||||
.insert(TemporalAntiAliasing::default());
|
||||
}
|
||||
|
||||
// DLSS
|
||||
#[cfg(feature = "dlss")]
|
||||
if keys.just_pressed(KeyCode::Digit6) && dlss.is_none() && dlss_supported.is_some() {
|
||||
*msaa = Msaa::Off;
|
||||
camera
|
||||
.remove::<Fxaa>()
|
||||
.remove::<Smaa>()
|
||||
.remove::<TaaComponents>()
|
||||
.insert(Dlss::default());
|
||||
}
|
||||
|
||||
// DLSS Settings
|
||||
#[cfg(feature = "dlss")]
|
||||
if let Some(mut dlss) = dlss {
|
||||
if keys.just_pressed(KeyCode::KeyZ) {
|
||||
dlss.perf_quality_mode = DlssPerfQualityMode::Auto;
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyX) {
|
||||
dlss.perf_quality_mode = DlssPerfQualityMode::UltraPerformance;
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyC) {
|
||||
dlss.perf_quality_mode = DlssPerfQualityMode::Performance;
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyV) {
|
||||
dlss.perf_quality_mode = DlssPerfQualityMode::Balanced;
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyB) {
|
||||
dlss.perf_quality_mode = DlssPerfQualityMode::Quality;
|
||||
}
|
||||
if keys.just_pressed(KeyCode::KeyN) {
|
||||
dlss.perf_quality_mode = DlssPerfQualityMode::Dlaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn modify_sharpening(
|
||||
@ -179,7 +254,18 @@ fn modify_sharpening(
|
||||
}
|
||||
|
||||
fn update_ui(
|
||||
camera: Single<
|
||||
#[cfg(feature = "dlss")] camera: Single<
|
||||
(
|
||||
Option<&Fxaa>,
|
||||
Option<&Smaa>,
|
||||
Option<&TemporalAntiAliasing>,
|
||||
&ContrastAdaptiveSharpening,
|
||||
&Msaa,
|
||||
Option<&Dlss>,
|
||||
),
|
||||
With<Camera>,
|
||||
>,
|
||||
#[cfg(not(feature = "dlss"))] camera: Single<
|
||||
(
|
||||
Option<&Fxaa>,
|
||||
Option<&Smaa>,
|
||||
@ -190,22 +276,35 @@ fn update_ui(
|
||||
With<Camera>,
|
||||
>,
|
||||
mut ui: Single<&mut Text>,
|
||||
#[cfg(feature = "dlss")] dlss_supported: Option<Res<DlssSupported>>,
|
||||
) {
|
||||
#[cfg(feature = "dlss")]
|
||||
let (fxaa, smaa, taa, cas, msaa, dlss) = *camera;
|
||||
#[cfg(not(feature = "dlss"))]
|
||||
let (fxaa, smaa, taa, cas, msaa) = *camera;
|
||||
|
||||
let ui = &mut ui.0;
|
||||
*ui = "Antialias Method\n".to_string();
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
let dlss_none = dlss.is_none();
|
||||
#[cfg(not(feature = "dlss"))]
|
||||
let dlss_none = true;
|
||||
|
||||
draw_selectable_menu_item(
|
||||
ui,
|
||||
"No AA",
|
||||
'1',
|
||||
*msaa == Msaa::Off && fxaa.is_none() && taa.is_none() && smaa.is_none(),
|
||||
*msaa == Msaa::Off && fxaa.is_none() && taa.is_none() && smaa.is_none() && dlss_none,
|
||||
);
|
||||
draw_selectable_menu_item(ui, "MSAA", '2', *msaa != Msaa::Off);
|
||||
draw_selectable_menu_item(ui, "FXAA", '3', fxaa.is_some());
|
||||
draw_selectable_menu_item(ui, "SMAA", '4', smaa.is_some());
|
||||
draw_selectable_menu_item(ui, "TAA", '5', taa.is_some());
|
||||
#[cfg(feature = "dlss")]
|
||||
if dlss_supported.is_some() {
|
||||
draw_selectable_menu_item(ui, "DLSS", '6', dlss.is_some());
|
||||
}
|
||||
|
||||
if *msaa != Msaa::Off {
|
||||
ui.push_str("\n----------\n\nSample Count\n");
|
||||
@ -241,6 +340,28 @@ fn update_ui(
|
||||
draw_selectable_menu_item(ui, "Ultra", 'R', smaa.preset == SmaaPreset::Ultra);
|
||||
}
|
||||
|
||||
#[cfg(feature = "dlss")]
|
||||
if let Some(dlss) = dlss {
|
||||
let pqm = dlss.perf_quality_mode;
|
||||
ui.push_str("\n----------\n\nQuality\n");
|
||||
draw_selectable_menu_item(ui, "Auto", 'Z', pqm == DlssPerfQualityMode::Auto);
|
||||
draw_selectable_menu_item(
|
||||
ui,
|
||||
"UltraPerformance",
|
||||
'X',
|
||||
pqm == DlssPerfQualityMode::UltraPerformance,
|
||||
);
|
||||
draw_selectable_menu_item(
|
||||
ui,
|
||||
"Performance",
|
||||
'C',
|
||||
pqm == DlssPerfQualityMode::Performance,
|
||||
);
|
||||
draw_selectable_menu_item(ui, "Balanced", 'V', pqm == DlssPerfQualityMode::Balanced);
|
||||
draw_selectable_menu_item(ui, "Quality", 'B', pqm == DlssPerfQualityMode::Quality);
|
||||
draw_selectable_menu_item(ui, "DLAA", 'N', pqm == DlssPerfQualityMode::Dlaa);
|
||||
}
|
||||
|
||||
ui.push_str("\n----------\n\n");
|
||||
draw_selectable_menu_item(ui, "Sharpening", '0', cas.enabled);
|
||||
|
||||
@ -260,7 +381,7 @@ fn setup(
|
||||
) {
|
||||
// Plane
|
||||
commands.spawn((
|
||||
Mesh3d(meshes.add(Plane3d::default().mesh().size(50.0, 50.0))),
|
||||
Mesh3d(meshes.add(Plane3d::default().mesh().size(20.0, 20.0))),
|
||||
MeshMaterial3d(materials.add(Color::srgb(0.1, 0.2, 0.1))),
|
||||
));
|
||||
|
||||
|
@ -142,7 +142,7 @@ Example | Description
|
||||
[3D Viewport To World](../examples/3d/3d_viewport_to_world.rs) | Demonstrates how to use the `Camera::viewport_to_world` method
|
||||
[Animated Material](../examples/3d/animated_material.rs) | Shows how to animate material properties
|
||||
[Anisotropy](../examples/3d/anisotropy.rs) | Displays an example model with anisotropy
|
||||
[Anti-aliasing](../examples/3d/anti_aliasing.rs) | Compares different anti-aliasing methods
|
||||
[Anti-aliasing](../examples/3d/anti_aliasing.rs) | Compares different anti-aliasing techniques supported by Bevy
|
||||
[Atmosphere](../examples/3d/atmosphere.rs) | A scene showcasing pbr atmospheric scattering
|
||||
[Atmospheric Fog](../examples/3d/atmospheric_fog.rs) | A scene showcasing the atmospheric fog effect
|
||||
[Auto Exposure](../examples/3d/auto_exposure.rs) | A scene showcasing auto exposure
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use bevy::camera::Viewport;
|
||||
use bevy::pbr::SetMeshViewEmptyBindGroup;
|
||||
use bevy::{
|
||||
core_pipeline::core_3d::graph::{Core3d, Node3d},
|
||||
@ -611,8 +612,10 @@ impl ViewNode for CustomDrawNode {
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
|
||||
if let Some(viewport) = camera.viewport.as_ref() {
|
||||
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
|
||||
if let Some(viewport) =
|
||||
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
|
||||
{
|
||||
render_pass.set_camera_viewport(&viewport);
|
||||
}
|
||||
|
||||
// Render the phase
|
||||
|
34
release-content/release-notes/dlss.md
Normal file
34
release-content/release-notes/dlss.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Deep Learning Super Sampling (DLSS)
|
||||
authors: ["@JMS55"]
|
||||
pull_requests: [19817, 19864]
|
||||
---
|
||||
|
||||
For users with NVIDIA RTX GPUs, Bevy now offers yet another form of anti-aliasing: DLSS.
|
||||
|
||||
Try it out by running Bevy's anti_aliasing example: `cargo run --example anti_aliasing --features dlss --release` (after performing setup from https://github.com/bevyengine/dlss_wgpu).
|
||||
|
||||
Additionally, we've open sourced https://github.com/bevyengine/dlss_wgpu as a standalone crate to help other wgpu-based renderers integrate DLSS.
|
||||
|
||||
Compared to Bevy's built-in TAA, DLSS:
|
||||
* Is much higher quality
|
||||
* Supports upscaling in addition to anti-aliasing, leading to much cheaper render times, particularly when used with GPU-heavy features like Bevy Solari
|
||||
* Requires a NVIDIA RTX GPU
|
||||
* Requires running via the Vulkan backend on Windows/Linux (no macOS, web, or mobile support)
|
||||
|
||||
To use DLSS in your app:
|
||||
* See https://github.com/bevyengine/dlss_wgpu for licensing requirements and setup instructions
|
||||
* Enable Bevy's `dlss` feature
|
||||
* Insert the `DlssProjectId` resource before `DefaultPlugins` when setting up your app
|
||||
* Check for the presence of `Option<Res<DlssSupported>>` at runtime to see if DLSS is supported on the current machine
|
||||
* Add the `Dlss` component to your camera entity, optionally setting a specific `DlssPerfQualityMode` (defaults to `Auto`)
|
||||
* Optionally add sharpening via `ContrastAdaptiveSharpening`
|
||||
* Custom rendering code, including third party crates, should account for the optional `MainPassResolutionOverride` to work with DLSS (see the `custom_render_phase` example)
|
||||
|
||||
Note that DLSS integration is expected to have some bugs in this release related to certain rendering effects not respecting upscaling settings, and possible issues with transparencies or camera exposure. Please report any bugs encountered.
|
||||
|
||||
Other temporal upscalers like AMD's FidelityFX™ Super Resolution (FSR), Intel's Xe Super Sampling XeSS (XeSS), and Apple's MTLFXTemporalScaler are not integrated in this release. However they all use similar APIs, and would not be a challenge to integrate in future releases.
|
||||
|
||||
Support for other swapchain-related features like frame interpolation/extrapolation, latency reduction, or dynamic resolution scaling are not currently planned, but support for DLSS Ray Reconstruction for use in Bevy Solari _is_ planned for a future release.
|
||||
|
||||
Special thanks to @cwfitzgerald for helping with the [`wgpu`](https://github.com/gfx-rs/wgpu) backend interop APIs.
|
Loading…
Reference in New Issue
Block a user