Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/texture/texture_attachment.rs
9367 views
1
use super::CachedTexture;
2
use crate::render_resource::{TextureFormat, TextureView};
3
use alloc::sync::Arc;
4
use bevy_color::LinearRgba;
5
use core::sync::atomic::{AtomicBool, Ordering};
6
use wgpu::{
7
LoadOp, Operations, RenderPassColorAttachment, RenderPassDepthStencilAttachment, StoreOp,
8
};
9
10
/// A wrapper for a [`CachedTexture`] that is used as a [`RenderPassColorAttachment`].
11
#[derive(Clone)]
12
pub 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
20
impl 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
/// Get this texture view as an attachment. The attachment will be cleared with a value of
37
/// `clear_color` if this is the first time calling this function, otherwise it will be loaded.
38
///
39
/// The returned attachment will always have writing enabled (`store: StoreOp::Load`).
40
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
/// Get this texture view as an attachment, without the resolve target. The attachment will be cleared with
62
/// a value of `clear_color` if this is the first time calling this function, otherwise it will be loaded.
63
///
64
/// The returned attachment will always have writing enabled (`store: StoreOp::Load`).
65
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
/// A wrapper for a [`TextureView`] that is used as a depth-only [`RenderPassDepthStencilAttachment`].
88
#[derive(Clone)]
89
pub struct DepthAttachment {
90
pub view: TextureView,
91
clear_value: Option<f32>,
92
is_first_call: Arc<AtomicBool>,
93
}
94
95
impl 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
/// Get this texture view as an attachment. The attachment will be cleared with a value of
105
/// `clear_value` if this is the first time calling this function with `store` == [`StoreOp::Store`],
106
/// and a clear value was provided, otherwise it will be loaded.
107
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
// If first_call is true, then a clear value will always have been provided in the constructor
117
LoadOp::Clear(self.clear_value.unwrap())
118
} else {
119
LoadOp::Load
120
},
121
store,
122
}),
123
stencil_ops: None,
124
}
125
}
126
}
127
128
/// A wrapper for a [`TextureView`] that is used as a [`RenderPassColorAttachment`] for a view
129
/// target's final output texture.
130
#[derive(Clone)]
131
pub struct OutputColorAttachment {
132
pub view: TextureView,
133
pub view_format: TextureFormat,
134
is_first_call: Arc<AtomicBool>,
135
}
136
137
impl 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
/// Get this texture view as an attachment. The attachment will be cleared with a value of
147
/// the provided `clear_color` if this is the first time calling this function, otherwise it
148
/// will be loaded.
149
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
/// Returns `true` if this attachment has been written to by a render pass.
167
// we re-use is_first_call atomic to track usage, which assumes that calls to get_attachment
168
// are always consumed by a render pass that writes to the attachment
169
pub fn needs_present(&self) -> bool {
170
!self.is_first_call.load(Ordering::SeqCst)
171
}
172
}
173
174