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