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 clear_color: Option<LinearRgba>,
16 is_first_call: Arc<AtomicBool>,
17}
18
19impl ColorAttachment {
20 pub fn new(
21 texture: CachedTexture,
22 resolve_target: Option<CachedTexture>,
23 clear_color: Option<LinearRgba>,
24 ) -> Self {
25 Self {
26 texture,
27 resolve_target,
28 clear_color,
29 is_first_call: Arc::new(AtomicBool::new(true)),
30 }
31 }
32
33 pub fn get_attachment(&self) -> RenderPassColorAttachment<'_> {
38 if let Some(resolve_target) = self.resolve_target.as_ref() {
39 let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);
40
41 RenderPassColorAttachment {
42 view: &resolve_target.default_view,
43 depth_slice: None,
44 resolve_target: Some(&self.texture.default_view),
45 ops: Operations {
46 load: match (self.clear_color, first_call) {
47 (Some(clear_color), true) => LoadOp::Clear(clear_color.into()),
48 (None, _) | (Some(_), false) => LoadOp::Load,
49 },
50 store: StoreOp::Store,
51 },
52 }
53 } else {
54 self.get_unsampled_attachment()
55 }
56 }
57
58 pub fn get_unsampled_attachment(&self) -> RenderPassColorAttachment<'_> {
63 let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);
64
65 RenderPassColorAttachment {
66 view: &self.texture.default_view,
67 depth_slice: None,
68 resolve_target: None,
69 ops: Operations {
70 load: match (self.clear_color, first_call) {
71 (Some(clear_color), true) => LoadOp::Clear(clear_color.into()),
72 (None, _) | (Some(_), false) => LoadOp::Load,
73 },
74 store: StoreOp::Store,
75 },
76 }
77 }
78
79 pub(crate) fn mark_as_cleared(&self) {
80 self.is_first_call.store(false, Ordering::SeqCst);
81 }
82}
83
84#[derive(Clone)]
86pub struct DepthAttachment {
87 pub view: TextureView,
88 clear_value: Option<f32>,
89 is_first_call: Arc<AtomicBool>,
90}
91
92impl DepthAttachment {
93 pub fn new(view: TextureView, clear_value: Option<f32>) -> Self {
94 Self {
95 view,
96 clear_value,
97 is_first_call: Arc::new(AtomicBool::new(clear_value.is_some())),
98 }
99 }
100
101 pub fn get_attachment(&self, store: StoreOp) -> RenderPassDepthStencilAttachment<'_> {
105 let first_call = self
106 .is_first_call
107 .fetch_and(store != StoreOp::Store, Ordering::SeqCst);
108
109 RenderPassDepthStencilAttachment {
110 view: &self.view,
111 depth_ops: Some(Operations {
112 load: if first_call {
113 LoadOp::Clear(self.clear_value.unwrap())
115 } else {
116 LoadOp::Load
117 },
118 store,
119 }),
120 stencil_ops: None,
121 }
122 }
123}
124
125#[derive(Clone)]
128pub struct OutputColorAttachment {
129 pub view: TextureView,
130 pub format: TextureFormat,
131 is_first_call: Arc<AtomicBool>,
132}
133
134impl OutputColorAttachment {
135 pub fn new(view: TextureView, format: TextureFormat) -> Self {
136 Self {
137 view,
138 format,
139 is_first_call: Arc::new(AtomicBool::new(true)),
140 }
141 }
142
143 pub fn get_attachment(&self, clear_color: Option<LinearRgba>) -> RenderPassColorAttachment<'_> {
147 let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);
148
149 RenderPassColorAttachment {
150 view: &self.view,
151 depth_slice: None,
152 resolve_target: None,
153 ops: Operations {
154 load: match (clear_color, first_call) {
155 (Some(clear_color), true) => LoadOp::Clear(clear_color.into()),
156 (None, _) | (Some(_), false) => LoadOp::Load,
157 },
158 store: StoreOp::Store,
159 },
160 }
161 }
162}