bevy_core_pipeline/upscaling/
node.rs1use crate::{blit::BlitPipeline, upscaling::ViewUpscalingPipeline};
2use bevy_camera::{CameraOutputMode, ClearColor, ClearColorConfig};
3use bevy_ecs::prelude::*;
4use bevy_render::{
5 camera::ExtractedCamera,
6 diagnostic::RecordDiagnostics,
7 render_resource::{BindGroup, PipelineCache, RenderPassDescriptor, TextureViewId},
8 renderer::{RenderContext, ViewQuery},
9 view::ViewTarget,
10};
11
12#[derive(Default)]
13pub struct UpscalingBindGroupCache {
14 cached: Option<(TextureViewId, BindGroup)>,
15}
16
17pub fn upscaling(
18 view: ViewQuery<(
19 &ViewTarget,
20 &ViewUpscalingPipeline,
21 Option<&ExtractedCamera>,
22 )>,
23 pipeline_cache: Res<PipelineCache>,
24 blit_pipeline: Res<BlitPipeline>,
25 clear_color_global: Res<ClearColor>,
26 mut cache: Local<UpscalingBindGroupCache>,
27 mut ctx: RenderContext,
28) {
29 let (target, upscaling_target, camera) = view.into_inner();
30
31 let clear_color = if let Some(camera) = camera {
32 match camera.output_mode {
33 CameraOutputMode::Write { clear_color, .. } => clear_color,
34 CameraOutputMode::Skip => return,
35 }
36 } else {
37 ClearColorConfig::Default
38 };
39 let clear_color = match clear_color {
40 ClearColorConfig::Default => Some(clear_color_global.0),
41 ClearColorConfig::Custom(color) => Some(color),
42 ClearColorConfig::None => None,
43 };
44 let converted_clear_color = clear_color.map(Into::into);
45
46 let main_texture_view = target.main_texture_view();
48
49 let bind_group = match &mut cache.cached {
50 Some((id, bind_group)) if main_texture_view.id() == *id => bind_group,
51 cached => {
52 let bind_group = blit_pipeline.create_bind_group(
53 ctx.render_device(),
54 main_texture_view,
55 &pipeline_cache,
56 );
57
58 let (_, bind_group) = cached.insert((main_texture_view.id(), bind_group));
59 bind_group
60 }
61 };
62
63 let Some(out_attachment) = target.out_texture_color_attachment(converted_clear_color) else {
64 return;
65 };
66
67 let pass_descriptor = RenderPassDescriptor {
68 label: Some("upscaling"),
69 color_attachments: &[Some(out_attachment)],
70 depth_stencil_attachment: None,
71 timestamp_writes: None,
72 occlusion_query_set: None,
73 multiview_mask: None,
74 };
75
76 let Some(pipeline) = pipeline_cache.get_render_pipeline(upscaling_target.0) else {
77 #[cfg(target_os = "macos")]
79 ctx.command_encoder().begin_render_pass(&pass_descriptor);
80 return;
81 };
82
83 let diagnostics = ctx.diagnostic_recorder();
84 let diagnostics = diagnostics.as_deref();
85 let time_span = diagnostics.time_span(ctx.command_encoder(), "upscaling");
86
87 {
88 let mut render_pass = ctx.command_encoder().begin_render_pass(&pass_descriptor);
89
90 if let Some(camera) = camera
91 && let Some(viewport) = &camera.viewport
92 {
93 let size = viewport.physical_size;
94 let position = viewport.physical_position;
95 render_pass.set_scissor_rect(position.x, position.y, size.x, size.y);
96 }
97
98 render_pass.set_pipeline(pipeline);
99 render_pass.set_bind_group(0, bind_group, &[]);
100 render_pass.draw(0..3, 0..1);
101 }
102
103 time_span.end(ctx.command_encoder());
104}