1use async_std::stream::StreamExt;
2use futures_util::FutureExt;
3pub use peridot_archive as archive;
4pub use peridot_math as math;
5
6use bedrock::{self as br, VkHandle};
7use parking_lot::RwLock;
8use std::cell::{Ref, RefCell};
9use std::collections::VecDeque;
10use std::ffi::CStr;
11use std::ops::{Deref, DerefMut};
12use std::sync::Arc;
13use std::time::{Duration, Instant as InstantTimer};
14
15mod graphics;
16pub use self::graphics::{
17 CBSubmissionType, CommandBundle, DeviceObject, Graphics, InstanceObject, LocalCommandBundle,
18 MemoryTypeManager, VulkanExtension, VulkanGfx,
19};
20mod state_track;
21mod window;
22pub use self::window::SurfaceInfo;
23mod resource;
24pub use self::resource::*;
25#[cfg(feature = "debug")]
26mod debug;
27pub mod utils;
28pub use self::utils::*;
29
30mod asset;
31pub use self::asset::*;
32mod batch;
33pub use self::batch::*;
34mod input;
35pub use self::input::*;
36pub mod audio;
37mod model;
38pub use self::model::*;
39mod presenter;
40pub use self::presenter::*;
41
42pub mod mthelper;
43#[allow(unused_imports)]
44use mthelper::DynamicMutabilityProvider;
45use mthelper::{DynamicMut, MappableGuardObject, MappableMutGuardObject};
46
47#[cfg(feature = "derive")]
48pub use peridot_derive::*;
49
50pub trait NativeLinker: Sized {
51 type AssetLoader: PlatformAssetLoader;
52 type Presenter: PlatformPresenter;
53
54 fn instance_extensions(&self) -> Vec<&CStr>;
55 fn device_extensions(&self) -> Vec<&CStr>;
56
57 fn asset_loader(&self) -> &Self::AssetLoader;
58 fn new_presenter(&self, g: &Graphics) -> Self::Presenter;
59
60 fn rendering_precision(&self) -> f32 {
61 1.0
62 }
63}
64
65pub trait EngineEvents<PL: NativeLinker>: Sized {
66 fn init(_e: &mut Engine<PL>) -> Self;
67
68 fn update(&mut self, _e: &mut Engine<PL>, _on_back_buffer_of: u32, _delta_time: Duration) {}
70
71 fn discard_back_buffer_resources(&mut self) {}
73
74 fn on_resize(&mut self, _e: &mut Engine<PL>, _new_size: math::Vector2<usize>) {}
77
78 fn store_render_resources(&mut self, _e: &mut Engine<PL>) {}
82
83 fn recover_render_resources(&mut self, _e: &mut Engine<PL>) {}
85}
86
87impl<PL: NativeLinker> EngineEvents<PL> for () {
88 fn init(_e: &mut Engine<PL>) -> Self {
89 ()
90 }
91}
92
93#[repr(transparent)]
95#[derive(Clone, Copy)]
96pub struct SparseResidencySupportBits(u16);
97impl SparseResidencySupportBits {
98 pub const EMPTY: Self = Self(0);
99 pub const BUFFER: Self = Self(0x0001);
100 pub const IMAGE_2D: Self = Self(0x0002);
101 pub const IMAGE_3D: Self = Self(0x0004);
102 pub const SAMPLE2: Self = Self(0x0008);
103 pub const SAMPLE4: Self = Self(0x0010);
104 pub const SAMPLE8: Self = Self(0x0020);
105 pub const SAMPLE16: Self = Self(0x0040);
106 pub const SAMPLE32: Self = Self(0x0080);
107 pub const ALIASED: Self = Self(0x0100);
108
109 pub const fn buffer(self) -> Self {
110 Self(self.0 | Self::BUFFER.0)
111 }
112 pub const fn image_2d(self) -> Self {
113 Self(self.0 | Self::IMAGE_2D.0)
114 }
115 pub const fn image_3d(self) -> Self {
116 Self(self.0 | Self::IMAGE_3D.0)
117 }
118 pub const fn sample2(self) -> Self {
119 Self(self.0 | Self::SAMPLE2.0)
120 }
121 pub const fn sample4(self) -> Self {
122 Self(self.0 | Self::SAMPLE4.0)
123 }
124 pub const fn sample8(self) -> Self {
125 Self(self.0 | Self::SAMPLE8.0)
126 }
127 pub const fn sample16(self) -> Self {
128 Self(self.0 | Self::SAMPLE16.0)
129 }
130 pub const fn aliased(self) -> Self {
131 Self(self.0 | Self::ALIASED.0)
132 }
133
134 const fn has_buffer(self) -> bool {
135 (self.0 & Self::BUFFER.0) != 0
136 }
137 const fn has_image_2d(self) -> bool {
138 (self.0 & Self::IMAGE_2D.0) != 0
139 }
140 const fn has_image_3d(self) -> bool {
141 (self.0 & Self::IMAGE_3D.0) != 0
142 }
143 const fn has_sample2(self) -> bool {
144 (self.0 & Self::SAMPLE2.0) != 0
145 }
146 const fn has_sample4(self) -> bool {
147 (self.0 & Self::SAMPLE4.0) != 0
148 }
149 const fn has_sample8(self) -> bool {
150 (self.0 & Self::SAMPLE8.0) != 0
151 }
152 const fn has_sample16(self) -> bool {
153 (self.0 & Self::SAMPLE16.0) != 0
154 }
155 const fn has_aliased(self) -> bool {
156 (self.0 & Self::ALIASED.0) != 0
157 }
158}
159pub trait FeatureRequests {
160 const ENABLE_GEOMETRY_SHADER: bool = false;
161 const ENABLE_TESSELLATION_SHADER: bool = false;
162 const USE_STORAGE_BUFFERS_IN_VERTEX_SHADER: bool = false;
163 const SPARSE_BINDING: bool = false;
164 const SPARSE_RESIDENCY_SUPPORT_BITS: SparseResidencySupportBits =
165 SparseResidencySupportBits::EMPTY;
166
167 fn requested_features() -> br::vk::VkPhysicalDeviceFeatures {
168 br::vk::VkPhysicalDeviceFeatures {
169 geometryShader: Self::ENABLE_GEOMETRY_SHADER as _,
170 tessellationShader: Self::ENABLE_TESSELLATION_SHADER as _,
171 vertexPipelineStoresAndAtomics: Self::USE_STORAGE_BUFFERS_IN_VERTEX_SHADER as _,
172 sparseBinding: Self::SPARSE_BINDING as _,
173 sparseResidencyBuffer: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_buffer() as _,
174 sparseResidencyImage2D: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_image_2d() as _,
175 sparseResidencyImage3D: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_image_3d() as _,
176 sparseResidency2Samples: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_sample2() as _,
177 sparseResidency4Samples: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_sample4() as _,
178 sparseResidency8Samples: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_sample8() as _,
179 sparseResidency16Samples: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_sample16() as _,
180 sparseResidencyAliased: Self::SPARSE_RESIDENCY_SUPPORT_BITS.has_aliased() as _,
181 ..Default::default()
182 }
183 }
184}
185
186pub enum EngineEvent {
187 Shutdown,
188 Resize(math::Vector2<u32>),
189}
190
191pub struct FrameData {
192 pub delta_time: Duration,
193 pub backbuffer_index: u32,
194}
195
196pub enum Event {
197 NextFrame,
198 Shutdown,
199 Resize(math::Vector2<u32>),
200}
201
202#[derive(Debug)]
203pub enum PrepareFrameError {
204 FramebufferOutOfDate,
205}
206
207pub struct EngineEventReceiver {
208 frame_timing_receiver: async_std::channel::Receiver<()>,
209 other_events_receiver: async_std::channel::Receiver<EngineEvent>,
210}
211impl EngineEventReceiver {
212 pub async fn wait_for_event(&mut self) -> Option<Event> {
213 futures_util::select! {
214 e = self.frame_timing_receiver.next().fuse() => match e {
215 Some(()) => Some(Event::NextFrame),
216 None => None,
217 },
218 e = self.other_events_receiver.next().fuse() => match e {
219 Some(EngineEvent::Shutdown) => Some(Event::Shutdown),
220 Some(EngineEvent::Resize(ns)) => Some(Event::Resize(ns)),
221 None => None,
222 }
223 }
224 }
225}
226
227pub struct NextEventFuture<'e> {
228 queue: &'e RefCell<VecDeque<Event>>,
229 queue_waker: &'e RefCell<Vec<core::task::Waker>>,
230}
231impl core::future::Future for NextEventFuture<'_> {
232 type Output = Event;
233
234 #[inline]
235 fn poll(
236 self: std::pin::Pin<&mut Self>,
237 cx: &mut std::task::Context<'_>,
238 ) -> std::task::Poll<Self::Output> {
239 if let Some(e) = self.queue.borrow_mut().pop_front() {
240 core::task::Poll::Ready(e)
241 } else {
242 self.queue_waker.borrow_mut().push(cx.waker().clone());
243 core::task::Poll::Pending
244 }
245 }
246}
247
248pub struct EventQueue {
249 queue: RefCell<VecDeque<Event>>,
250 queue_waker: RefCell<Vec<core::task::Waker>>,
251}
252impl EventQueue {
253 pub fn new() -> Self {
254 Self {
255 queue: RefCell::new(VecDeque::new()),
256 queue_waker: RefCell::new(Vec::new()),
257 }
258 }
259
260 pub fn enqueue(&self, event: Event) {
261 self.queue.borrow_mut().push_back(event);
262 for w in core::mem::replace(&mut *self.queue_waker.borrow_mut(), Vec::new()) {
263 w.wake();
264 }
265 }
266
267 #[inline(always)]
268 pub fn next_event<'q>(&'q self) -> impl core::future::Future<Output = Event> + 'q {
269 NextEventFuture {
270 queue: &self.queue,
271 queue_waker: &self.queue_waker,
272 }
273 }
274}
275
276struct LastRenderingCompletionFence {
277 handle: br::vk::VkFence,
278 device: VulkanGfx,
279 used: bool,
280}
281impl Drop for LastRenderingCompletionFence {
282 fn drop(&mut self) {
283 unsafe {
284 br::vkfn_wrapper::destroy_fence(self.device.native_ptr(), self.handle, None);
285 }
286 }
287}
288impl LastRenderingCompletionFence {
289 pub fn new(device: &VulkanGfx) -> br::Result<Self> {
290 let handle = unsafe {
291 br::vkfn_wrapper::create_fence(device.0.device, &br::FenceCreateInfo::new(0), None)?
292 };
293
294 Ok(Self {
295 handle,
296 device: device.clone(),
297 used: false,
298 })
299 }
300
301 pub fn wait(&mut self) -> br::Result<()> {
302 if self.used {
303 unsafe {
304 br::vkfn_wrapper::wait_for_fences(
305 self.device.0.device,
306 &[self.handle],
307 true,
308 u64::MAX,
309 )?;
310 br::vkfn_wrapper::reset_fences(
311 self.device.0.device,
312 &[br::VkHandleRefMut::dangling(self.handle)],
313 )?;
314 }
315 self.used = false;
316 }
317
318 Ok(())
319 }
320
321 #[must_use]
322 pub fn r#use(&mut self) -> br::VkHandleRefMut<br::vk::VkFence> {
323 self.used = true;
324
325 unsafe { br::VkHandleRefMut::dangling(self.handle) }
326 }
327}
328
329pub struct Engine<'q, NL: NativeLinker> {
330 native_link: NL,
331 presenter: NL::Presenter,
332 pub(self) g: Graphics,
333 ip: InputProcess,
334 game_timer: GameTimer,
335 last_rendering_completion: LastRenderingCompletionFence,
336 audio_mixer: Arc<RwLock<audio::Mixer>>,
337 request_resize: bool,
338 engine_events_sender: async_std::channel::Sender<EngineEvent>,
339 receivers: core::cell::UnsafeCell<EngineEventReceiver>,
340 shared_event_queue: &'q EventQueue,
341}
342impl<'q, PL: NativeLinker> Engine<'q, PL> {
343 pub fn new(
344 name: &str,
345 version: br::Version,
346 native_link: PL,
347 requested_features: br::vk::VkPhysicalDeviceFeatures,
348 engine_events_bus: (
349 async_std::channel::Sender<EngineEvent>,
350 async_std::channel::Receiver<EngineEvent>,
351 ),
352 frame_timing_receiver: async_std::channel::Receiver<()>,
353 shared_event_queue: &'q EventQueue,
354 ) -> Self {
355 let mut g = Graphics::new(
356 name,
357 version,
358 native_link.instance_extensions(),
359 native_link.device_extensions(),
360 requested_features,
361 );
362 let presenter = native_link.new_presenter(&g);
363 g.submit_commands(|r| presenter.emit_initialize_back_buffer_commands(r))
364 .expect("Initializing Back Buffers");
365
366 let last_rendering_completion = match LastRenderingCompletionFence::new(&g.gfx_device) {
367 Ok(x) => x,
368 Err(e) => {
369 tracing::error!(cause = ?e, "Faield to create last rendering completion fence");
370 std::process::abort();
371 }
372 };
373
374 Self {
375 ip: InputProcess::new().into(),
376 game_timer: GameTimer::new(),
377 last_rendering_completion,
378 audio_mixer: Arc::new(RwLock::new(audio::Mixer::new())),
379 native_link,
380 g,
381 presenter,
382 request_resize: false,
383 engine_events_sender: engine_events_bus.0,
384 receivers: core::cell::UnsafeCell::new(EngineEventReceiver {
385 frame_timing_receiver,
386 other_events_receiver: engine_events_bus.1,
387 }),
388 shared_event_queue,
389 }
390 }
391
392 pub fn post_init(&mut self) {
393 tracing::trace!("PostInit BaseEngine...");
394 }
395}
396impl<'q, NL: NativeLinker> Engine<'q, NL> {
397 pub fn event_receivers(&self) -> &mut EngineEventReceiver {
398 unsafe { &mut *self.receivers.get() }
399 }
400
401 #[inline(always)]
402 pub fn next_event(&self) -> impl core::future::Future<Output = Event> + 'q {
403 self.shared_event_queue.next_event()
404 }
405
406 pub async fn quit(&self) {
407 if let Err(e) = self.engine_events_sender.send(EngineEvent::Shutdown).await {
408 tracing::warn!(cause = ?e, "Engine has already shutting down");
409 }
410 }
411
412 pub const fn graphics(&self) -> &Graphics {
413 &self.g
414 }
415 pub fn graphics_mut(&mut self) -> &mut Graphics {
416 &mut self.g
417 }
418
419 pub const fn graphics_device(&self) -> &VulkanGfx {
420 &self.g.gfx_device
421 }
422 pub const fn graphics_queue_family_index(&self) -> u32 {
423 self.g.graphics_queue_family_index()
424 }
425 pub const fn transfer_queue_family_index(&self) -> u32 {
427 self.g.graphics_queue.family
428 }
429
430 pub fn back_buffer_format(&self) -> br::vk::VkFormat {
431 self.presenter.format()
432 }
433 pub fn back_buffer_size(&self) -> peridot_math::Vector2<u32> {
434 self.presenter.back_buffer_size()
435 }
436 pub fn back_buffer_count(&self) -> usize {
437 self.presenter.back_buffer_count()
438 }
439 pub fn back_buffer(&self, index: usize) -> Option<br::VkHandleRef<br::vk::VkImage>> {
440 self.presenter.back_buffer(index)
441 }
442 pub fn iter_back_buffers<'s>(
443 &'s self,
444 ) -> impl Iterator<Item = br::VkHandleRef<'s, br::vk::VkImage>> + 's {
445 (0..self.back_buffer_count())
446 .map(move |x| self.back_buffer(x).expect("unreachable while iteration"))
447 }
448 pub fn requesting_back_buffer_layout(&self) -> (br::ImageLayout, br::PipelineStageFlags) {
449 self.presenter.requesting_back_buffer_layout()
450 }
451 pub fn back_buffer_attachment_desc(&self) -> br::vk::VkAttachmentDescription {
452 let (ol, _) = self.requesting_back_buffer_layout();
453
454 br::vk::VkAttachmentDescription::new(self.back_buffer_format(), ol, ol)
455 }
456
457 pub fn screen_size(&self) -> peridot_math::Vector2<u32> {
458 self.presenter.current_geometry_extent()
459 }
460
461 pub fn input(&self) -> &InputProcess {
462 &self.ip
463 }
464 pub fn input_mut(&mut self) -> &mut InputProcess {
465 &mut self.ip
466 }
467
468 pub fn submit_commands(
469 &mut self,
470 generator: impl for<'a> FnOnce(br::CmdRecord<'a, VulkanGfx>) -> br::CmdRecord<'a, VulkanGfx>,
471 ) -> br::Result<()> {
472 self.g.submit_commands(generator)
473 }
474 pub fn submit_buffered_commands(
475 &mut self,
476 batches: &[br::SubmitInfo],
477 fence: &mut impl br::VkHandleMut<Handle = br::vk::VkFence>,
478 ) -> br::Result<()> {
479 self.g.submit_buffered_commands(batches, fence)
480 }
481
482 #[cfg(feature = "mt")]
483 pub fn submit_commands_async<'s>(
487 &'s self,
488 generator: impl for<'a> FnOnce(br::CmdRecord<'a, VulkanGfx>) -> br::CmdRecord<'a, VulkanGfx>
489 + 's,
490 ) -> br::Result<impl std::future::Future<Output = br::Result<()>> + 's> {
491 self.g.submit_commands_async(generator)
492 }
493
494 #[inline]
495 pub const fn audio_mixer(&self) -> &Arc<RwLock<audio::Mixer>> {
496 &self.audio_mixer
497 }
498}
499impl<PL: NativeLinker> Engine<'_, PL> {
500 pub fn load<A: FromAsset>(&self, path: &str) -> Result<A, A::Error> {
501 A::from_asset(self.native_link.asset_loader().get(path, A::EXT)?)
502 }
503 pub fn streaming<A: FromStreamingAsset>(&self, path: &str) -> Result<A, A::Error> {
504 A::from_asset(
505 self.native_link
506 .asset_loader()
507 .get_streaming(path, A::EXT)?,
508 )
509 }
510
511 pub fn rendering_precision(&self) -> f32 {
512 self.native_link.rendering_precision()
513 }
514}
515impl<PL: NativeLinker> Engine<'_, PL> {
516 pub fn prepare_frame(&mut self) -> Result<FrameData, PrepareFrameError> {
517 if let Err(e) = self.last_rendering_completion.wait() {
518 tracing::warn!(cause = ?e, "Failed to wait last command completion");
519 }
520
521 let dt = self.game_timer.delta_time();
522 let backbuffer_index = match self.presenter.next_back_buffer_index() {
523 Err(e) if e == br::vk::VK_ERROR_OUT_OF_DATE_KHR || e == br::vk::VK_SUBOPTIMAL_KHR => {
524 return Err(PrepareFrameError::FramebufferOutOfDate);
525 }
526 e => e.expect("Acquiring available back-buffer index failed"),
527 };
528
529 self.ip.prepare_for_frame(dt);
530
531 Ok(FrameData {
532 delta_time: dt,
533 backbuffer_index,
534 })
535 }
536
537 pub fn do_render(
562 &mut self,
563 bb_index: u32,
564 copy_submission: Option<SubmissionBatchBuilder>,
565 render_submission: SubmissionBatchBuilder,
566 ) -> br::Result<()> {
567 let pr = self.presenter.render_and_present(
568 &mut self.g,
569 &mut self.last_rendering_completion.r#use(),
570 bb_index,
571 render_submission,
572 copy_submission,
573 );
574
575 match pr {
576 Err(e) if e == br::vk::VK_ERROR_OUT_OF_DATE_KHR || e == br::vk::VK_SUBOPTIMAL_KHR => {
577 self.request_resize = true;
579
580 Ok(())
581 }
582 v => v,
583 }
584 }
585
586 pub fn wait_for_last_rendering_completion(&mut self) -> br::Result<()> {
587 self.last_rendering_completion.wait()
588 }
589
590 pub fn resize_presenter_backbuffers(&mut self, new_size: math::Vector2<u32>) {
591 let needs_re_init_back_buffers = self
592 .presenter
593 .resize(&self.g, math::Vector2(new_size.0 as _, new_size.1 as _));
594 if needs_re_init_back_buffers {
595 let pres = &self.presenter;
596
597 self.g
598 .submit_commands(|r| pres.emit_initialize_back_buffer_commands(r))
599 .expect("Initializing Back Buffers");
600 }
601 }
602
603 pub fn sound_backend_callback(&self, output_buffer: &mut [f32]) {
623 for (n, r) in output_buffer.iter_mut().enumerate() {
624 *r = (440.0 * n as f32 / 44100.0).to_radians().sin() * 0.1;
625 }
626 }
627}
628impl<NL: NativeLinker> Drop for Engine<'_, NL> {
629 fn drop(&mut self) {
630 if let Err(e) = self.g.wait_operations() {
631 tracing::warn!(cause = ?e, "Failed to wait device operations at drop");
632 }
633 }
634}
635
636pub struct LateInit<T>(RefCell<Option<T>>);
637impl<T> LateInit<T> {
638 pub fn new() -> Self {
639 LateInit(RefCell::new(None))
640 }
641 pub fn init(&self, v: T) {
642 *self.0.borrow_mut() = v.into();
643 }
644 pub fn get(&self) -> Ref<T> {
645 Ref::map(self.0.borrow(), |x| x.as_ref().expect("uninitialized"))
646 }
647}
648
649pub struct Discardable1<T>(Option<T>);
650impl<T> Discardable1<T> {
651 pub const fn new() -> Self {
652 Self(None)
653 }
654
655 pub fn set(&mut self, v: T) {
656 self.0 = Some(v);
657 }
658
659 pub fn get<'v>(&'v self) -> &'v T {
660 self.0.as_ref().expect("value unset")
661 }
662
663 pub fn get_mut<'v>(&'v mut self) -> &'v mut T {
664 self.0.as_mut().expect("value unset")
665 }
666
667 pub fn discard(&mut self) {
668 self.0 = None;
669 }
670
671 pub fn take(&mut self) -> Option<T> {
672 self.0.take()
673 }
674
675 pub const fn is_available(&self) -> bool {
676 self.0.is_some()
677 }
678}
679impl<T> From<T> for Discardable1<T> {
680 #[inline(always)]
681 fn from(value: T) -> Self {
682 Self(Some(value))
683 }
684}
685
686pub struct Discardable<T>(DynamicMut<Option<T>>);
687impl<T> Discardable<T> {
688 pub fn new() -> Self {
689 Discardable(DynamicMut::new(None))
690 }
691 pub fn set(&self, v: T) {
692 *self.0.borrow_mut() = v.into();
693 }
694 pub fn set_lw(&mut self, v: T) {
695 *self.0.get_mut() = v.into();
696 }
697
698 pub fn get<'v>(&'v self) -> impl Deref<Target = T> + 'v {
699 self.0
700 .borrow()
701 .map_guarded_value(|x| x.as_ref().expect("uninitialized"))
702 }
703
704 pub fn get_mut<'v>(&'v self) -> impl Deref<Target = T> + DerefMut + 'v {
705 self.0
706 .borrow_mut()
707 .map_guarded_value(|x| x.as_mut().expect("uninitialized"))
708 }
709
710 pub fn get_mut_lw(&mut self) -> &mut T {
711 self.0.get_mut().as_mut().expect("uninitialized")
712 }
713 pub fn discard(&self) {
714 *self.0.borrow_mut() = None;
715 }
716 pub fn discard_lw(&mut self) {
717 drop(self.0.get_mut().take());
718 }
719 pub fn take_lw(&mut self) -> Option<T> {
720 self.0.get_mut().take()
721 }
722 pub fn is_available(&self) -> bool {
723 self.0.borrow().is_some()
724 }
725}
726impl<T> From<T> for Discardable<T> {
727 fn from(v: T) -> Self {
728 Discardable(DynamicMut::new(Some(v)))
729 }
730}
731
732pub struct GameTimer(Option<InstantTimer>);
733impl GameTimer {
734 pub fn new() -> Self {
735 GameTimer(None)
736 }
737 pub fn delta_time(&mut self) -> Duration {
738 let d = self
739 .0
740 .as_ref()
741 .map_or_else(|| Duration::new(0, 0), |it| it.elapsed());
742 self.0 = InstantTimer::now().into();
743
744 return d;
745 }
746}
747
748pub enum SubpassDependencyTemplates {}
749impl SubpassDependencyTemplates {
750 pub fn to_color_attachment_in(
751 from_subpass: Option<u32>,
752 occurrence_subpass: u32,
753 by_region: bool,
754 ) -> br::vk::VkSubpassDependency {
755 br::vk::VkSubpassDependency {
756 dstSubpass: occurrence_subpass,
757 srcSubpass: from_subpass.unwrap_or(br::vk::VK_SUBPASS_EXTERNAL),
758 dstStageMask: br::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT.0,
759 dstAccessMask: br::AccessFlags::COLOR_ATTACHMENT.write,
760 dependencyFlags: if by_region {
761 br::vk::VK_DEPENDENCY_BY_REGION_BIT
762 } else {
763 0
764 },
765 srcStageMask: br::PipelineStageFlags::TOP_OF_PIPE.0,
766 srcAccessMask: 0,
767 }
768 }
769}
770
771pub struct LayoutedPipeline<Pipeline: br::Pipeline, Layout: br::PipelineLayout>(Pipeline, Layout);
772impl<Pipeline: br::Pipeline, Layout: br::PipelineLayout> LayoutedPipeline<Pipeline, Layout> {
773 pub const fn combine(p: Pipeline, layout: Layout) -> Self {
774 Self(p, layout)
775 }
776
777 pub const fn pipeline(&self) -> &Pipeline {
778 &self.0
779 }
780
781 pub const fn layout(&self) -> &Layout {
782 &self.1
783 }
784
785 #[inline(always)]
786 pub fn bind<'r, Device: ?Sized>(
787 &self,
788 rec: br::CmdRecord<'r, Device>,
789 ) -> br::CmdRecord<'r, Device> {
790 rec.bind_pipeline(br::PipelineBindPoint::Graphics, &self.0)
791 }
792}