bevy_render/texture/
texture_attachment.rs1use super::CachedTexture;
2use crate::render_resource::{TextureFormat, TextureView};
3use alloc::sync::Arc;
4use bevy_color::LinearRgba;
5use core::sync::atomic::{AtomicBool, Ordering};
6use wgpu::{
7 Color as WgpuColor, LoadOp, Operations, RenderPassColorAttachment,
8 RenderPassDepthStencilAttachment, StoreOp,
9};
10
11#[derive(Clone)]
13pub struct ColorAttachment {
14 pub texture: CachedTexture,
15 pub resolve_target: Option<CachedTexture>,
16 pub previous_frame_texture: Option<CachedTexture>,
17 clear_color: Option<WgpuColor>,
18 is_first_call: Arc<AtomicBool>,
19}
20
21impl ColorAttachment {
22 pub fn new(
23 texture: CachedTexture,
24 resolve_target: Option<CachedTexture>,
25 previous_frame_texture: Option<CachedTexture>,
26 clear_color: Option<WgpuColor>,
27 ) -> Self {
28 Self {
29 texture,
30 resolve_target,
31 previous_frame_texture,
32 clear_color,
33 is_first_call: Arc::new(AtomicBool::new(true)),
34 }
35 }
36
37 pub fn get_attachment(&self) -> RenderPassColorAttachment<'_> {
42 if let Some(resolve_target) = self.resolve_target.as_ref() {
43 let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);
44
45 RenderPassColorAttachment {
46 view: &resolve_target.default_view,
47 depth_slice: None,
48 resolve_target: Some(&self.texture.default_view),
49 ops: Operations {
50 load: match (self.clear_color, first_call) {
51 (Some(clear_color), true) => LoadOp::Clear(clear_color),
52 (None, _) | (Some(_), false) => LoadOp::Load,
53 },
54 store: StoreOp::Store,
55 },
56 }
57 } else {
58 self.get_unsampled_attachment()
59 }
60 }
61
62 pub fn get_unsampled_attachment(&self) -> RenderPassColorAttachment<'_> {
67 let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);
68
69 RenderPassColorAttachment {
70 view: &self.texture.default_view,
71 depth_slice: None,
72 resolve_target: None,
73 ops: Operations {
74 load: match (self.clear_color, first_call) {
75 (Some(clear_color), true) => LoadOp::Clear(clear_color),
76 (None, _) | (Some(_), false) => LoadOp::Load,
77 },
78 store: StoreOp::Store,
79 },
80 }
81 }
82
83 pub(crate) fn mark_as_cleared(&self) {
84 self.is_first_call.store(false, Ordering::SeqCst);
85 }
86}
87
88#[derive(Clone)]
90pub struct DepthAttachment {
91 pub view: TextureView,
92 clear_value: Option<f32>,
93 is_first_call: Arc<AtomicBool>,
94}
95
96impl DepthAttachment {
97 pub fn new(view: TextureView, clear_value: Option<f32>) -> Self {
98 Self {
99 view,
100 clear_value,
101 is_first_call: Arc::new(AtomicBool::new(clear_value.is_some())),
102 }
103 }
104
105 pub fn get_attachment(&self, store: StoreOp) -> RenderPassDepthStencilAttachment<'_> {
109 let first_call = self
110 .is_first_call
111 .fetch_and(store != StoreOp::Store, Ordering::Relaxed);
112
113 RenderPassDepthStencilAttachment {
114 view: &self.view,
115 depth_ops: Some(Operations {
116 load: if first_call {
117 LoadOp::Clear(self.clear_value.unwrap())
119 } else {
120 LoadOp::Load
121 },
122 store,
123 }),
124 stencil_ops: None,
125 }
126 }
127
128 pub fn prepare_for_new_frame(&self) {
131 self.is_first_call.store(true, Ordering::Relaxed);
132 }
133}
134
135#[derive(Clone)]
138pub struct OutputColorAttachment {
139 pub view: TextureView,
140 pub view_format: TextureFormat,
141 is_first_call: Arc<AtomicBool>,
142}
143
144impl OutputColorAttachment {
145 pub fn new(view: TextureView, view_format: TextureFormat) -> Self {
146 Self {
147 view,
148 view_format,
149 is_first_call: Arc::new(AtomicBool::new(true)),
150 }
151 }
152
153 pub fn get_attachment(&self, clear_color: Option<LinearRgba>) -> RenderPassColorAttachment<'_> {
157 let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);
158
159 RenderPassColorAttachment {
160 view: &self.view,
161 depth_slice: None,
162 resolve_target: None,
163 ops: Operations {
164 load: match (clear_color, first_call) {
165 (Some(clear_color), true) => LoadOp::Clear(clear_color.into()),
166 (None, _) | (Some(_), false) => LoadOp::Load,
167 },
168 store: StoreOp::Store,
169 },
170 }
171 }
172
173 pub fn needs_present(&self) -> bool {
177 !self.is_first_call.load(Ordering::SeqCst)
178 }
179}