-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Initial DLSS implementation #19864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial DLSS implementation #19864
Changes from 70 commits
c75b2b4
af1b47c
eb8c77f
951c3f9
742ebfa
463c66d
950f3e8
bf56980
6b960b0
cf1a1f7
1b71463
10c96e8
04f488b
e2a9761
fda09d1
ab113c8
5ab0093
baa2668
e2d8a9e
8084745
e202226
1701bb1
6f9114b
484310d
27f40ef
d962a37
baa46ae
a6751bd
b89387d
b0303fe
ded4b9f
497e85f
e33d1f0
3499283
733017a
e66ba3f
1bce5f5
f707d2d
97989d1
4d7a107
8c7df68
546244a
da757a8
40acb71
24c6bce
f644683
6225e61
975a10b
4c87049
b6412b5
e2f6ec4
f205394
160c386
9cb2e1a
890bc71
73c35a7
b6aaea4
817cd14
e954fc9
622522c
d7cde18
9209d3b
53e1c2f
548b53d
45d6f3c
4eeab79
73ff83f
a406188
2bf8837
7b3f14b
3bfd551
c349dcd
da202cc
bbf69b3
9374266
20b7d61
4d6d6ad
11ad770
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| use super::{prepare::DlssRenderContext, Dlss, DlssFeature}; | ||
| use bevy_camera::{Camera, MainPassResolutionOverride, Projection}; | ||
| use bevy_ecs::{ | ||
| query::{Has, With}, | ||
| system::{Commands, Query, ResMut}, | ||
| }; | ||
| use bevy_render::{sync_world::RenderEntity, view::Hdr, MainWorld}; | ||
|
|
||
| pub fn extract_dlss<F: DlssFeature>( | ||
| mut commands: Commands, | ||
| mut main_world: ResMut<MainWorld>, | ||
| cleanup_query: Query<Has<Dlss<F>>>, | ||
| ) { | ||
| let mut cameras_3d = main_world | ||
| .query_filtered::<(RenderEntity, &Camera, &Projection, Option<&mut Dlss<F>>), 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 if cleanup_query.get(entity) == Ok(true) { | ||
| entity_commands.remove::<(Dlss<F>, DlssRenderContext<F>, MainPassResolutionOverride)>(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,305 @@ | ||
| //! 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. | ||
| //! | ||
JMS55 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| //! # 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<DlssSuperResolutionSupported>>` 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_math::{UVec2, Vec2}; | ||
| use bevy_reflect::{reflect_remote, Reflect}; | ||
| use bevy_render::{ | ||
| camera::{MipBias, TemporalJitter}, | ||
| render_graph::{RenderGraphExt, ViewNodeRunner}, | ||
| renderer::{RenderDevice, RenderQueue}, | ||
| texture::CachedTexture, | ||
| view::{prepare_view_targets, Hdr}, | ||
| ExtractSchedule, Render, RenderApp, RenderSystems, | ||
| }; | ||
| use dlss_wgpu::{ | ||
| ray_reconstruction::{ | ||
| DlssRayReconstruction, DlssRayReconstructionDepthMode, DlssRayReconstructionRoughnessMode, | ||
| }, | ||
| super_resolution::DlssSuperResolution, | ||
| }; | ||
| use std::{ | ||
| marker::PhantomData, | ||
| ops::Deref, | ||
| sync::{Arc, Mutex}, | ||
| }; | ||
| use tracing::info; | ||
|
|
||
| pub use bevy_render::{ | ||
| DlssProjectId, DlssRayReconstructionSupported, DlssSuperResolutionSupported, | ||
| }; | ||
| pub use dlss_wgpu::DlssPerfQualityMode; | ||
|
|
||
| pub struct DlssPlugin; | ||
|
|
||
| impl Plugin for DlssPlugin { | ||
| fn build(&self, app: &mut App) { | ||
| app.register_type::<Dlss<DlssSuperResolutionFeature>>() | ||
| .register_type::<Dlss<DlssRayReconstructionFeature>>(); | ||
| } | ||
|
|
||
| fn finish(&self, app: &mut App) { | ||
| if app | ||
| .world() | ||
| .get_resource::<DlssSuperResolutionSupported>() | ||
| .is_none() | ||
| { | ||
| info!("DLSS is not supported on this system"); | ||
| return; | ||
| } | ||
|
|
||
| let dlss_project_id = app.world().resource::<DlssProjectId>().0; | ||
JMS55 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| 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::<DlssSuperResolutionSupported>(); | ||
| info!("DLSS is not supported on this system"); | ||
| return; | ||
| } | ||
|
|
||
| render_app | ||
| .insert_resource(DlssSdk(dlss_sdk.unwrap())) | ||
| .add_systems( | ||
| ExtractSchedule, | ||
| ( | ||
| extract::extract_dlss::<DlssSuperResolutionFeature>, | ||
| extract::extract_dlss::<DlssRayReconstructionFeature>, | ||
| ), | ||
| ) | ||
| .add_systems( | ||
| Render, | ||
| ( | ||
| prepare::prepare_dlss::<DlssSuperResolutionFeature>, | ||
| prepare::prepare_dlss::<DlssRayReconstructionFeature>, | ||
| ) | ||
| .in_set(RenderSystems::ManageViews) | ||
| .before(prepare_view_targets), | ||
| ) | ||
| .add_render_graph_node::<ViewNodeRunner<node::DlssNode<DlssSuperResolutionFeature>>>( | ||
| Core3d, | ||
| Node3d::DlssSuperResolution, | ||
| ) | ||
| .add_render_graph_node::<ViewNodeRunner<node::DlssNode<DlssRayReconstructionFeature>>>( | ||
| Core3d, | ||
| Node3d::DlssRayReconstruction, | ||
| ) | ||
| .add_render_graph_edges( | ||
| Core3d, | ||
| ( | ||
| Node3d::EndMainPass, | ||
| Node3d::MotionBlur, // Running before DLSS reduces edge artifacts and noise | ||
| Node3d::DlssSuperResolution, | ||
| Node3d::DlssRayReconstruction, | ||
| Node3d::Bloom, | ||
| Node3d::Tonemapping, | ||
| ), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /// Camera component to enable DLSS. | ||
| #[derive(Component, Reflect, Clone)] | ||
| #[reflect(Component)] | ||
| #[require(TemporalJitter, MipBias, DepthPrepass, MotionVectorPrepass, Hdr)] | ||
| pub struct Dlss<F: DlssFeature = DlssSuperResolutionFeature> { | ||
| /// How much upscaling should be applied. | ||
| #[reflect(remote = DlssPerfQualityModeRemoteReflect)] | ||
| pub perf_quality_mode: DlssPerfQualityMode, | ||
| /// Set to true to delete the saved temporal history (past frames). | ||
| /// | ||
| /// Useful for preventing ghosting when the history is no longer | ||
| /// representative of the current frame, such as in sudden camera cuts. | ||
| /// | ||
| /// After setting this to true, it will automatically be toggled | ||
| /// back to false at the end of the frame. | ||
| pub reset: bool, | ||
| #[reflect(ignore)] | ||
| pub _phantom_data: PhantomData<F>, | ||
| } | ||
|
|
||
| impl Default for Dlss<DlssSuperResolutionFeature> { | ||
| fn default() -> Self { | ||
| Self { | ||
| perf_quality_mode: Default::default(), | ||
| reset: Default::default(), | ||
| _phantom_data: Default::default(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| pub trait DlssFeature: Reflect + Clone + Default { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add docs here? Becuase
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The trait isn't meant to be implemented by users, or really even used. It exists just so that the public If you think it's clearer, I could delete the generics, and just copy paste duplicate the systems? The
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah gotcha, I kinda assumed it was for this kind of unification. Yeah, idk, tbh I think a little copy/paste might be cleaner although I understand it's also a little gross. I'll let others way in and don't think it should block. |
||
| type Context: Send; | ||
|
|
||
| fn upscaled_resolution(context: &Self::Context) -> UVec2; | ||
|
|
||
| fn render_resolution(context: &Self::Context) -> UVec2; | ||
|
|
||
| fn suggested_jitter( | ||
| context: &Self::Context, | ||
| frame_number: u32, | ||
| render_resolution: UVec2, | ||
| ) -> Vec2; | ||
|
|
||
| fn suggested_mip_bias(context: &Self::Context, render_resolution: UVec2) -> f32; | ||
|
|
||
| fn new_context( | ||
| upscaled_resolution: UVec2, | ||
| perf_quality_mode: DlssPerfQualityMode, | ||
| feature_flags: dlss_wgpu::DlssFeatureFlags, | ||
| sdk: Arc<Mutex<dlss_wgpu::DlssSdk>>, | ||
| device: &RenderDevice, | ||
| queue: &RenderQueue, | ||
| ) -> Result<Self::Context, dlss_wgpu::DlssError>; | ||
| } | ||
|
|
||
| /// DLSS Super Resolution. | ||
| /// | ||
| /// Only available when the [`DlssSuperResolutionSupported`] resource exists. | ||
| #[derive(Reflect, Clone, Default)] | ||
| pub struct DlssSuperResolutionFeature; | ||
|
|
||
| impl DlssFeature for DlssSuperResolutionFeature { | ||
| type Context = DlssSuperResolution; | ||
|
|
||
| fn upscaled_resolution(context: &Self::Context) -> UVec2 { | ||
| context.upscaled_resolution() | ||
| } | ||
|
|
||
| fn render_resolution(context: &Self::Context) -> UVec2 { | ||
| context.render_resolution() | ||
| } | ||
|
|
||
| fn suggested_jitter( | ||
| context: &Self::Context, | ||
| frame_number: u32, | ||
| render_resolution: UVec2, | ||
| ) -> Vec2 { | ||
| context.suggested_jitter(frame_number, render_resolution) | ||
| } | ||
|
|
||
| fn suggested_mip_bias(context: &Self::Context, render_resolution: UVec2) -> f32 { | ||
| context.suggested_mip_bias(render_resolution) | ||
| } | ||
|
|
||
| fn new_context( | ||
| upscaled_resolution: UVec2, | ||
| perf_quality_mode: DlssPerfQualityMode, | ||
| feature_flags: dlss_wgpu::DlssFeatureFlags, | ||
| sdk: Arc<Mutex<dlss_wgpu::DlssSdk>>, | ||
| device: &RenderDevice, | ||
| queue: &RenderQueue, | ||
| ) -> Result<Self::Context, dlss_wgpu::DlssError> { | ||
| DlssSuperResolution::new( | ||
| upscaled_resolution, | ||
| perf_quality_mode, | ||
| feature_flags, | ||
| sdk, | ||
| device.wgpu_device(), | ||
| queue.deref(), | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| /// DLSS Ray Reconstruction. | ||
| /// | ||
| /// Only available when the [`DlssRayReconstructionSupported`] resource exists. | ||
| #[derive(Reflect, Clone, Default)] | ||
| pub struct DlssRayReconstructionFeature; | ||
|
|
||
| impl DlssFeature for DlssRayReconstructionFeature { | ||
| type Context = DlssRayReconstruction; | ||
|
|
||
| fn upscaled_resolution(context: &Self::Context) -> UVec2 { | ||
| context.upscaled_resolution() | ||
| } | ||
|
|
||
| fn render_resolution(context: &Self::Context) -> UVec2 { | ||
| context.render_resolution() | ||
| } | ||
|
|
||
| fn suggested_jitter( | ||
| context: &Self::Context, | ||
| frame_number: u32, | ||
| render_resolution: UVec2, | ||
| ) -> Vec2 { | ||
| context.suggested_jitter(frame_number, render_resolution) | ||
| } | ||
|
|
||
| fn suggested_mip_bias(context: &Self::Context, render_resolution: UVec2) -> f32 { | ||
| context.suggested_mip_bias(render_resolution) | ||
| } | ||
|
|
||
| fn new_context( | ||
| upscaled_resolution: UVec2, | ||
| perf_quality_mode: DlssPerfQualityMode, | ||
| feature_flags: dlss_wgpu::DlssFeatureFlags, | ||
| sdk: Arc<Mutex<dlss_wgpu::DlssSdk>>, | ||
| device: &RenderDevice, | ||
| queue: &RenderQueue, | ||
| ) -> Result<Self::Context, dlss_wgpu::DlssError> { | ||
| DlssRayReconstruction::new( | ||
| upscaled_resolution, | ||
| perf_quality_mode, | ||
| feature_flags, | ||
| DlssRayReconstructionRoughnessMode::Packed, | ||
| DlssRayReconstructionDepthMode::Hardware, | ||
| sdk, | ||
| device.wgpu_device(), | ||
| queue.deref(), | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| /// Additional textures needed as inputs for [`DlssRayReconstructionFeature`]. | ||
| #[derive(Component)] | ||
| pub struct ViewDlssRayReconstructionTextures { | ||
| pub diffuse_albedo: CachedTexture, | ||
| pub specular_albedo: CachedTexture, | ||
| pub normal_roughness: CachedTexture, | ||
| pub specular_motion_vectors: CachedTexture, | ||
| } | ||
|
|
||
| #[reflect_remote(DlssPerfQualityMode)] | ||
| #[derive(Default)] | ||
| enum DlssPerfQualityModeRemoteReflect { | ||
| #[default] | ||
| Auto, | ||
| Dlaa, | ||
| Quality, | ||
| Balanced, | ||
| Performance, | ||
| UltraPerformance, | ||
| } | ||
|
|
||
| #[derive(Resource)] | ||
| struct DlssSdk(Arc<Mutex<dlss_wgpu::DlssSdk>>); | ||
Uh oh!
There was an error while loading. Please reload this page.