1use {
2 crate::{
3 command::Encoder,
4 resource::{Handle, Image},
5 },
6 rendy_core::hal::{buffer, image, memory::Barrier, pso, Backend},
7 std::ops::Range,
8};
9
10#[derive(Debug)]
12struct ImageBarrier<B: Backend> {
13 pub states: Range<image::State>,
15 pub target: Handle<Image<B>>,
17 pub range: image::SubresourceRange,
19 }
22
23impl<B: Backend> ImageBarrier<B> {
24 fn raw(&self) -> Barrier<'_, B> {
25 Barrier::Image {
26 states: self.states.clone(),
27 target: self.target.raw(),
28 families: None,
29 range: self.range.clone(),
30 }
31 }
32}
33
34#[derive(Debug)]
37pub struct Barriers<B: Backend> {
38 before_stages: pso::PipelineStage,
39 before_buffer_access: buffer::Access,
40 before_image_access: image::Access,
41 before_image_transitions: Vec<ImageBarrier<B>>,
42 target_stages: pso::PipelineStage,
43 target_buffer_access: buffer::Access,
44 target_image_access: image::Access,
45 after_stages: pso::PipelineStage,
46 after_buffer_access: buffer::Access,
47 after_image_access: image::Access,
48 after_image_transitions: Vec<ImageBarrier<B>>,
49}
50
51impl<B: Backend> Barriers<B> {
52 pub fn new(
54 target_stages: pso::PipelineStage,
55 target_buffer_access: buffer::Access,
56 target_image_access: image::Access,
57 ) -> Self {
58 Self {
59 before_stages: pso::PipelineStage::empty(),
60 before_buffer_access: buffer::Access::empty(),
61 before_image_access: image::Access::empty(),
62 before_image_transitions: Vec::new(),
63 target_stages,
64 target_buffer_access,
65 target_image_access,
66 after_stages: pso::PipelineStage::empty(),
67 after_buffer_access: buffer::Access::empty(),
68 after_image_access: image::Access::empty(),
69 after_image_transitions: Vec::new(),
70 }
71 }
72
73 pub fn add_image(
75 &mut self,
76 image: Handle<Image<B>>,
77 image_range: rendy_core::hal::image::SubresourceRange,
78 last_stage: pso::PipelineStage,
79 last_access: rendy_core::hal::image::Access,
80 last_layout: rendy_core::hal::image::Layout,
81 target_layout: image::Layout,
82 next_stage: pso::PipelineStage,
83 next_access: rendy_core::hal::image::Access,
84 next_layout: rendy_core::hal::image::Layout,
85 ) {
86 self.before_stages |= last_stage;
87 self.before_image_access |= last_access;
88 self.after_stages |= next_stage;
89 self.after_image_access |= next_access;
90
91 if last_layout != target_layout {
92 log::trace!(
93 "Transition last: {:?}",
94 (last_access, last_layout)..(self.target_image_access, target_layout)
95 );
96 self.before_image_transitions.push(ImageBarrier {
97 states: (last_access, last_layout)..(self.target_image_access, target_layout),
98 target: image.clone(),
99 range: image_range.clone(),
100 });
101 }
102
103 if next_layout != target_layout {
104 log::trace!(
105 "Transition next: {:?}",
106 (self.target_image_access, target_layout)..(next_access, next_layout)
107 );
108 self.after_image_transitions.push(ImageBarrier {
109 states: (self.target_image_access, target_layout)..(next_access, next_layout),
110 target: image,
111 range: image_range,
112 })
113 }
114 }
115
116 pub fn add_buffer(
118 &mut self,
119 last_stage: pso::PipelineStage,
120 last_access: rendy_core::hal::buffer::Access,
121 next_stage: pso::PipelineStage,
122 next_access: rendy_core::hal::buffer::Access,
123 ) {
124 self.before_stages |= last_stage;
125 self.before_buffer_access |= last_access;
126 self.after_stages |= next_stage;
127 self.after_buffer_access |= next_access;
128 }
129
130 pub fn encode_before<C, L>(&mut self, encoder: &mut Encoder<'_, B, C, L>) {
132 if !self.before_stages.is_empty() {
133 let transitions = self.before_image_transitions.iter().map(|b| b.raw());
134 let all_images = Some(Barrier::AllImages(
135 self.before_image_access..self.target_image_access,
136 ))
137 .filter(|_| !self.before_image_access.is_empty());
138 let all_buffers = Some(Barrier::AllBuffers(
139 self.before_buffer_access..self.target_buffer_access,
140 ))
141 .filter(|_| !self.before_buffer_access.is_empty());
142
143 unsafe {
144 encoder.pipeline_barrier(
145 self.before_stages..self.target_stages,
146 rendy_core::hal::memory::Dependencies::empty(),
147 transitions.chain(all_images).chain(all_buffers),
148 );
149 }
150 } else {
151 assert_eq!(self.before_image_transitions.len(), 0);
152 }
153
154 self.before_stages = pso::PipelineStage::empty();
155 self.before_image_access = image::Access::empty();
156 self.before_buffer_access = buffer::Access::empty();
157 self.before_image_transitions.clear();
158 }
159
160 pub fn encode_after<C, L>(&mut self, encoder: &mut Encoder<'_, B, C, L>) {
162 if !self.target_stages.is_empty() {
163 let transitions = self.after_image_transitions.iter().map(|b| b.raw());
164 let all_images = Some(Barrier::AllImages(
165 self.target_image_access..self.after_image_access,
166 ))
167 .filter(|_| !self.after_image_access.is_empty());
168 let all_buffers = Some(Barrier::AllBuffers(
169 self.target_buffer_access..self.after_buffer_access,
170 ))
171 .filter(|_| !self.after_buffer_access.is_empty());
172
173 unsafe {
174 encoder.pipeline_barrier(
175 self.target_stages..self.after_stages,
176 rendy_core::hal::memory::Dependencies::empty(),
177 transitions.chain(all_images).chain(all_buffers),
178 );
179 }
180 } else {
181 assert_eq!(self.after_image_transitions.len(), 0);
182 }
183
184 self.after_stages = pso::PipelineStage::empty();
185 self.after_image_access = image::Access::empty();
186 self.after_buffer_access = buffer::Access::empty();
187 self.after_image_transitions.clear();
188 }
189}