Path: blob/main/crates/bevy_render/src/texture/texture_attachment.rs
9367 views
use super::CachedTexture;1use crate::render_resource::{TextureFormat, TextureView};2use alloc::sync::Arc;3use bevy_color::LinearRgba;4use core::sync::atomic::{AtomicBool, Ordering};5use wgpu::{6LoadOp, Operations, RenderPassColorAttachment, RenderPassDepthStencilAttachment, StoreOp,7};89/// A wrapper for a [`CachedTexture`] that is used as a [`RenderPassColorAttachment`].10#[derive(Clone)]11pub struct ColorAttachment {12pub texture: CachedTexture,13pub resolve_target: Option<CachedTexture>,14pub previous_frame_texture: Option<CachedTexture>,15clear_color: Option<LinearRgba>,16is_first_call: Arc<AtomicBool>,17}1819impl ColorAttachment {20pub fn new(21texture: CachedTexture,22resolve_target: Option<CachedTexture>,23previous_frame_texture: Option<CachedTexture>,24clear_color: Option<LinearRgba>,25) -> Self {26Self {27texture,28resolve_target,29previous_frame_texture,30clear_color,31is_first_call: Arc::new(AtomicBool::new(true)),32}33}3435/// Get this texture view as an attachment. The attachment will be cleared with a value of36/// `clear_color` if this is the first time calling this function, otherwise it will be loaded.37///38/// The returned attachment will always have writing enabled (`store: StoreOp::Load`).39pub fn get_attachment(&self) -> RenderPassColorAttachment<'_> {40if let Some(resolve_target) = self.resolve_target.as_ref() {41let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);4243RenderPassColorAttachment {44view: &resolve_target.default_view,45depth_slice: None,46resolve_target: Some(&self.texture.default_view),47ops: Operations {48load: match (self.clear_color, first_call) {49(Some(clear_color), true) => LoadOp::Clear(clear_color.into()),50(None, _) | (Some(_), false) => LoadOp::Load,51},52store: StoreOp::Store,53},54}55} else {56self.get_unsampled_attachment()57}58}5960/// Get this texture view as an attachment, without the resolve target. The attachment will be cleared with61/// a value of `clear_color` if this is the first time calling this function, otherwise it will be loaded.62///63/// The returned attachment will always have writing enabled (`store: StoreOp::Load`).64pub fn get_unsampled_attachment(&self) -> RenderPassColorAttachment<'_> {65let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);6667RenderPassColorAttachment {68view: &self.texture.default_view,69depth_slice: None,70resolve_target: None,71ops: Operations {72load: match (self.clear_color, first_call) {73(Some(clear_color), true) => LoadOp::Clear(clear_color.into()),74(None, _) | (Some(_), false) => LoadOp::Load,75},76store: StoreOp::Store,77},78}79}8081pub(crate) fn mark_as_cleared(&self) {82self.is_first_call.store(false, Ordering::SeqCst);83}84}8586/// A wrapper for a [`TextureView`] that is used as a depth-only [`RenderPassDepthStencilAttachment`].87#[derive(Clone)]88pub struct DepthAttachment {89pub view: TextureView,90clear_value: Option<f32>,91is_first_call: Arc<AtomicBool>,92}9394impl DepthAttachment {95pub fn new(view: TextureView, clear_value: Option<f32>) -> Self {96Self {97view,98clear_value,99is_first_call: Arc::new(AtomicBool::new(clear_value.is_some())),100}101}102103/// Get this texture view as an attachment. The attachment will be cleared with a value of104/// `clear_value` if this is the first time calling this function with `store` == [`StoreOp::Store`],105/// and a clear value was provided, otherwise it will be loaded.106pub fn get_attachment(&self, store: StoreOp) -> RenderPassDepthStencilAttachment<'_> {107let first_call = self108.is_first_call109.fetch_and(store != StoreOp::Store, Ordering::SeqCst);110111RenderPassDepthStencilAttachment {112view: &self.view,113depth_ops: Some(Operations {114load: if first_call {115// If first_call is true, then a clear value will always have been provided in the constructor116LoadOp::Clear(self.clear_value.unwrap())117} else {118LoadOp::Load119},120store,121}),122stencil_ops: None,123}124}125}126127/// A wrapper for a [`TextureView`] that is used as a [`RenderPassColorAttachment`] for a view128/// target's final output texture.129#[derive(Clone)]130pub struct OutputColorAttachment {131pub view: TextureView,132pub view_format: TextureFormat,133is_first_call: Arc<AtomicBool>,134}135136impl OutputColorAttachment {137pub fn new(view: TextureView, view_format: TextureFormat) -> Self {138Self {139view,140view_format,141is_first_call: Arc::new(AtomicBool::new(true)),142}143}144145/// Get this texture view as an attachment. The attachment will be cleared with a value of146/// the provided `clear_color` if this is the first time calling this function, otherwise it147/// will be loaded.148pub fn get_attachment(&self, clear_color: Option<LinearRgba>) -> RenderPassColorAttachment<'_> {149let first_call = self.is_first_call.fetch_and(false, Ordering::SeqCst);150151RenderPassColorAttachment {152view: &self.view,153depth_slice: None,154resolve_target: None,155ops: Operations {156load: match (clear_color, first_call) {157(Some(clear_color), true) => LoadOp::Clear(clear_color.into()),158(None, _) | (Some(_), false) => LoadOp::Load,159},160store: StoreOp::Store,161},162}163}164165/// Returns `true` if this attachment has been written to by a render pass.166// we re-use is_first_call atomic to track usage, which assumes that calls to get_attachment167// are always consumed by a render pass that writes to the attachment168pub fn needs_present(&self) -> bool {169!self.is_first_call.load(Ordering::SeqCst)170}171}172173174