vk_sync/
lib.rs

1//! In an effort to make Vulkan synchronization more accessible, this library
2//! provides a simplification of core synchronization mechanisms such as
3//! pipeline barriers and events.
4//!
5//! Rather than the complex maze of enums and bit flags in Vulkan - many
6//! combinations of which are invalid or nonsensical - this library collapses
7//! this to a much shorter list of ~40 distinct usage types, and a couple of
8//! options for handling image layouts.
9//!
10//! Additionally, these usage types provide an easier mapping to other graphics
11//! APIs like DirectX 12.
12//!
13//! Use of other synchronization mechanisms such as semaphores, fences and render
14//! passes are not addressed in this library at present.
15
16extern crate ash;
17
18pub type BufferType = ash::vk::Buffer;
19pub type ImageType = ash::vk::Image;
20pub type ImageSubresourceRangeType = ash::vk::ImageSubresourceRange;
21
22pub mod cmd;
23
24/// Defines all potential resource usages
25#[derive(Debug, Copy, Clone, PartialEq)]
26pub enum AccessType {
27	/// No access. Useful primarily for initialization
28	Nothing,
29
30	/// Command buffer read operation as defined by `NVX_device_generated_commands`
31	CommandBufferReadNVX,
32
33	/// Read as an indirect buffer for drawing or dispatch
34	IndirectBuffer,
35
36	/// Read as an index buffer for drawing
37	IndexBuffer,
38
39	/// Read as a vertex buffer for drawing
40	VertexBuffer,
41
42	/// Read as a uniform buffer in a vertex shader
43	VertexShaderReadUniformBuffer,
44
45	/// Read as a sampled image/uniform texel buffer in a vertex shader
46	VertexShaderReadSampledImageOrUniformTexelBuffer,
47
48	/// Read as any other resource in a vertex shader
49	VertexShaderReadOther,
50
51	/// Read as a uniform buffer in a tessellation control shader
52	TessellationControlShaderReadUniformBuffer,
53
54	/// Read as a sampled image/uniform texel buffer in a tessellation control shader
55	TessellationControlShaderReadSampledImageOrUniformTexelBuffer,
56
57	/// Read as any other resource in a tessellation control shader
58	TessellationControlShaderReadOther,
59
60	/// Read as a uniform buffer in a tessellation evaluation shader
61	TessellationEvaluationShaderReadUniformBuffer,
62
63	/// Read as a sampled image/uniform texel buffer in a tessellation evaluation shader
64	TessellationEvaluationShaderReadSampledImageOrUniformTexelBuffer,
65
66	/// Read as any other resource in a tessellation evaluation shader
67	TessellationEvaluationShaderReadOther,
68
69	/// Read as a uniform buffer in a geometry shader
70	GeometryShaderReadUniformBuffer,
71
72	/// Read as a sampled image/uniform texel buffer in a geometry shader
73	GeometryShaderReadSampledImageOrUniformTexelBuffer,
74
75	/// Read as any other resource in a geometry shader
76	GeometryShaderReadOther,
77
78	/// Read as a uniform buffer in a fragment shader
79	FragmentShaderReadUniformBuffer,
80
81	/// Read as a sampled image/uniform texel buffer in a fragment shader
82	FragmentShaderReadSampledImageOrUniformTexelBuffer,
83
84	/// Read as an input attachment with a color format in a fragment shader
85	FragmentShaderReadColorInputAttachment,
86
87	/// Read as an input attachment with a depth/stencil format in a fragment shader
88	FragmentShaderReadDepthStencilInputAttachment,
89
90	/// Read as any other resource in a fragment shader
91	FragmentShaderReadOther,
92
93	/// Read by blending/logic operations or subpass load operations
94	ColorAttachmentRead,
95
96	/// Read by depth/stencil tests or subpass load operations
97	DepthStencilAttachmentRead,
98
99	/// Read as a uniform buffer in a compute shader
100	ComputeShaderReadUniformBuffer,
101
102	/// Read as a sampled image/uniform texel buffer in a compute shader
103	ComputeShaderReadSampledImageOrUniformTexelBuffer,
104
105	/// Read as any other resource in a compute shader
106	ComputeShaderReadOther,
107
108	/// Read as a uniform buffer in any shader
109	AnyShaderReadUniformBuffer,
110
111	/// Read as a uniform buffer in any shader, or a vertex buffer
112	AnyShaderReadUniformBufferOrVertexBuffer,
113
114	/// Read as a sampled image in any shader
115	AnyShaderReadSampledImageOrUniformTexelBuffer,
116
117	/// Read as any other resource (excluding attachments) in any shader
118	AnyShaderReadOther,
119
120	/// Read as the source of a transfer operation
121	TransferRead,
122
123	/// Read on the host
124	HostRead,
125
126	/// Read by the presentation engine (i.e. `vkQueuePresentKHR`)
127	Present,
128
129	/// Command buffer write operation as defined by `NVX_device_generated_commands`
130	CommandBufferWriteNVX,
131
132	/// Written as any resource in a vertex shader
133	VertexShaderWrite,
134
135	/// Written as any resource in a tessellation control shader
136	TessellationControlShaderWrite,
137
138	/// Written as any resource in a tessellation evaluation shader
139	TessellationEvaluationShaderWrite,
140
141	/// Written as any resource in a geometry shader
142	GeometryShaderWrite,
143
144	/// Written as any resource in a fragment shader
145	FragmentShaderWrite,
146
147	/// Written as a color attachment during rendering, or via a subpass store op
148	ColorAttachmentWrite,
149
150	/// Written as a depth/stencil attachment during rendering, or via a subpass store op
151	DepthStencilAttachmentWrite,
152
153	/// Written as a depth aspect of a depth/stencil attachment during rendering, whilst the
154	/// stencil aspect is read-only. Requires `VK_KHR_maintenance2` to be enabled.
155	DepthAttachmentWriteStencilReadOnly,
156
157	/// Written as a stencil aspect of a depth/stencil attachment during rendering, whilst the
158	/// depth aspect is read-only. Requires `VK_KHR_maintenance2` to be enabled.
159	StencilAttachmentWriteDepthReadOnly,
160
161	/// Written as any resource in a compute shader
162	ComputeShaderWrite,
163
164	/// Written as any resource in any shader
165	AnyShaderWrite,
166
167	/// Written as the destination of a transfer operation
168	TransferWrite,
169
170	/// Written on the host
171	HostWrite,
172
173	/// Read or written as a color attachment during rendering
174	ColorAttachmentReadWrite,
175
176	/// Covers any access - useful for debug, generally avoid for performance reasons
177	General,
178}
179
180impl Default for AccessType {
181	fn default() -> Self {
182		AccessType::Nothing
183	}
184}
185
186/// Defines a handful of layout options for images.
187/// Rather than a list of all possible image layouts, this reduced list is
188/// correlated with the access types to map to the correct Vulkan layouts.
189/// `Optimal` is usually preferred.
190#[derive(Debug, Copy, Clone, PartialEq)]
191pub enum ImageLayout {
192	/// Choose the most optimal layout for each usage. Performs layout transitions as appropriate for the access.
193	Optimal,
194
195	/// Layout accessible by all Vulkan access types on a device - no layout transitions except for presentation
196	General,
197
198	/// Similar to `General`, but also allows presentation engines to access it - no layout transitions.
199	/// Requires `VK_KHR_shared_presentable_image` to be enabled, and this can only be used for shared presentable
200	/// images (i.e. single-buffered swap chains).
201	GeneralAndPresentation,
202}
203
204impl Default for ImageLayout {
205	fn default() -> Self {
206		ImageLayout::Optimal
207	}
208}
209
210/// Global barriers define a set of accesses on multiple resources at once.
211/// If a buffer or image doesn't require a queue ownership transfer, or an image
212/// doesn't require a layout transition (e.g. you're using one of the
213/// `ImageLayout::General*` layouts) then a global barrier should be preferred.
214///
215/// Simply define the previous and next access types of resources affected.
216#[derive(Debug, Default, Clone)]
217pub struct GlobalBarrier<'a> {
218	pub previous_accesses: &'a [AccessType],
219	pub next_accesses: &'a [AccessType],
220}
221
222/// Buffer barriers should only be used when a queue family ownership transfer
223/// is required - prefer global barriers at all other times.
224///
225/// Access types are defined in the same way as for a global memory barrier, but
226/// they only affect the buffer range identified by `buffer`, `offset` and `size`,
227/// rather than all resources.
228///
229/// `src_queue_family_index` and `dst_queue_family_index` will be passed unmodified
230/// into a buffer memory barrier.
231///
232/// A buffer barrier defining a queue ownership transfer needs to be executed
233/// twice - once by a queue in the source queue family, and then once again by a
234/// queue in the destination queue family, with a semaphore guaranteeing
235/// execution order between them.
236#[derive(Debug, Default, Clone)]
237pub struct BufferBarrier<'a> {
238	pub previous_accesses: &'a [AccessType],
239	pub next_accesses: &'a [AccessType],
240	pub src_queue_family_index: u32,
241	pub dst_queue_family_index: u32,
242	pub buffer: BufferType,
243	pub offset: usize,
244	pub size: usize,
245}
246
247/// Image barriers should only be used when a queue family ownership transfer
248/// or an image layout transition is required - prefer global barriers at all
249/// other times.
250///
251/// In general it is better to use image barriers with `ImageLayout::Optimal`
252/// than it is to use global barriers with images using either of the
253/// `ImageLayout::General*` layouts.
254///
255/// Access types are defined in the same way as for a global memory barrier, but
256/// they only affect the image subresource range identified by `image` and
257/// `range`, rather than all resources.
258///
259/// `src_queue_family_index`, `dst_queue_family_index`, `image`, and `range` will
260/// be passed unmodified into an image memory barrier.
261///
262/// An image barrier defining a queue ownership transfer needs to be executed
263/// twice - once by a queue in the source queue family, and then once again by a
264/// queue in the destination queue family, with a semaphore guaranteeing
265/// execution order between them.
266///
267/// If `discard_contents` is set to true, the contents of the image become
268/// undefined after the barrier is executed, which can result in a performance
269/// boost over attempting to preserve the contents. This is particularly useful
270/// for transient images where the contents are going to be immediately overwritten.
271/// A good example of when to use this is when an application re-uses a presented
272/// image after acquiring the next swap chain image.
273#[derive(Debug, Default, Clone)]
274pub struct ImageBarrier<'a> {
275	pub previous_accesses: &'a [AccessType],
276	pub next_accesses: &'a [AccessType],
277	pub previous_layout: ImageLayout,
278	pub next_layout: ImageLayout,
279	pub discard_contents: bool,
280	pub src_queue_family_index: u32,
281	pub dst_queue_family_index: u32,
282	pub image: ImageType,
283	pub range: ImageSubresourceRangeType,
284}
285
286/// Mapping function that translates a global barrier into a set of source and
287/// destination pipeline stages, and a memory barrier, that can be used with
288/// Vulkan synchronization methods.
289pub fn get_memory_barrier(
290	barrier: &GlobalBarrier,
291) -> (
292	ash::vk::PipelineStageFlags,
293	ash::vk::PipelineStageFlags,
294	ash::vk::MemoryBarrier,
295) {
296	let mut src_stages = ash::vk::PipelineStageFlags::empty();
297	let mut dst_stages = ash::vk::PipelineStageFlags::empty();
298
299	let mut memory_barrier = ash::vk::MemoryBarrier::default();
300
301	for previous_access in barrier.previous_accesses {
302		let previous_info = get_access_info(*previous_access);
303
304		src_stages |= previous_info.stage_mask;
305
306		// Add appropriate availability operations - for writes only.
307		if is_write_access(*previous_access) {
308			memory_barrier.src_access_mask |= previous_info.access_mask;
309		}
310	}
311
312	for next_access in barrier.next_accesses {
313		let next_info = get_access_info(*next_access);
314
315		dst_stages |= next_info.stage_mask;
316
317		// Add visibility operations as necessary.
318		// If the src access mask, this is a WAR hazard (or for some reason a "RAR"),
319		// so the dst access mask can be safely zeroed as these don't need visibility.
320		if memory_barrier.src_access_mask != ash::vk::AccessFlags::empty() {
321			memory_barrier.dst_access_mask |= next_info.access_mask;
322		}
323	}
324
325	// Ensure that the stage masks are valid if no stages were determined
326	if src_stages == ash::vk::PipelineStageFlags::empty() {
327		src_stages = ash::vk::PipelineStageFlags::TOP_OF_PIPE;
328	}
329
330	if dst_stages == ash::vk::PipelineStageFlags::empty() {
331		dst_stages = ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
332	}
333
334	(src_stages, dst_stages, memory_barrier)
335}
336
337/// Mapping function that translates a buffer barrier into a set of source and
338/// destination pipeline stages, and a buffer memory barrier, that can be used
339/// with Vulkan synchronization methods.
340pub fn get_buffer_memory_barrier(
341	barrier: &BufferBarrier,
342) -> (
343	ash::vk::PipelineStageFlags,
344	ash::vk::PipelineStageFlags,
345	ash::vk::BufferMemoryBarrier,
346) {
347	let mut src_stages = ash::vk::PipelineStageFlags::empty();
348	let mut dst_stages = ash::vk::PipelineStageFlags::empty();
349
350	let mut buffer_barrier = ash::vk::BufferMemoryBarrier {
351		src_queue_family_index: barrier.src_queue_family_index,
352		dst_queue_family_index: barrier.dst_queue_family_index,
353		buffer: barrier.buffer,
354		offset: barrier.offset as u64,
355		size: barrier.size as u64,
356		..Default::default()
357	};
358
359	for previous_access in barrier.previous_accesses {
360		let previous_info = get_access_info(*previous_access);
361
362		src_stages |= previous_info.stage_mask;
363
364		// Add appropriate availability operations - for writes only.
365		if is_write_access(*previous_access) {
366			buffer_barrier.src_access_mask |= previous_info.access_mask;
367		}
368	}
369
370	for next_access in barrier.next_accesses {
371		let next_info = get_access_info(*next_access);
372
373		dst_stages |= next_info.stage_mask;
374
375		// Add visibility operations as necessary.
376		// If the src access mask, this is a WAR hazard (or for some reason a "RAR"),
377		// so the dst access mask can be safely zeroed as these don't need visibility.
378		if buffer_barrier.src_access_mask != ash::vk::AccessFlags::empty() {
379			buffer_barrier.dst_access_mask |= next_info.access_mask;
380		}
381	}
382
383	// Ensure that the stage masks are valid if no stages were determined
384	if src_stages == ash::vk::PipelineStageFlags::empty() {
385		src_stages = ash::vk::PipelineStageFlags::TOP_OF_PIPE;
386	}
387
388	if dst_stages == ash::vk::PipelineStageFlags::empty() {
389		dst_stages = ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
390	}
391
392	(src_stages, dst_stages, buffer_barrier)
393}
394
395/// Mapping function that translates an image barrier into a set of source and
396/// destination pipeline stages, and an image memory barrier, that can be used
397/// with Vulkan synchronization methods.
398pub fn get_image_memory_barrier(
399	barrier: &ImageBarrier,
400) -> (
401	ash::vk::PipelineStageFlags,
402	ash::vk::PipelineStageFlags,
403	ash::vk::ImageMemoryBarrier,
404) {
405	let mut src_stages = ash::vk::PipelineStageFlags::empty();
406	let mut dst_stages = ash::vk::PipelineStageFlags::empty();
407
408	let mut image_barrier = ash::vk::ImageMemoryBarrier {
409		src_queue_family_index: barrier.src_queue_family_index,
410		dst_queue_family_index: barrier.dst_queue_family_index,
411		image: barrier.image,
412		subresource_range: barrier.range,
413		..Default::default()
414	};
415
416	for previous_access in barrier.previous_accesses {
417		let previous_info = get_access_info(*previous_access);
418
419		src_stages |= previous_info.stage_mask;
420
421		// Add appropriate availability operations - for writes only.
422		if is_write_access(*previous_access) {
423			image_barrier.src_access_mask |= previous_info.access_mask;
424		}
425
426		if barrier.discard_contents {
427			image_barrier.old_layout = ash::vk::ImageLayout::UNDEFINED;
428		} else {
429			let layout = match barrier.previous_layout {
430				ImageLayout::General => {
431					if *previous_access == AccessType::Present {
432						ash::vk::ImageLayout::PRESENT_SRC_KHR
433					} else {
434						ash::vk::ImageLayout::GENERAL
435					}
436				}
437				ImageLayout::Optimal => previous_info.image_layout,
438				ImageLayout::GeneralAndPresentation => {
439					unimplemented!()
440					// TODO: layout = ash::vk::ImageLayout::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
441				}
442			};
443
444			image_barrier.old_layout = layout;
445		}
446	}
447
448	for next_access in barrier.next_accesses {
449		let next_info = get_access_info(*next_access);
450
451		dst_stages |= next_info.stage_mask;
452
453		// Add visibility operations as necessary.
454		// If the src access mask, this is a WAR hazard (or for some reason a "RAR"),
455		// so the dst access mask can be safely zeroed as these don't need visibility.
456		if image_barrier.src_access_mask != ash::vk::AccessFlags::empty() {
457			image_barrier.dst_access_mask |= next_info.access_mask;
458		}
459
460		let layout = match barrier.next_layout {
461			ImageLayout::General => {
462				if *next_access == AccessType::Present {
463					ash::vk::ImageLayout::PRESENT_SRC_KHR
464				} else {
465					ash::vk::ImageLayout::GENERAL
466				}
467			}
468			ImageLayout::Optimal => next_info.image_layout,
469			ImageLayout::GeneralAndPresentation => {
470				unimplemented!()
471				// TODO: layout = ash::vk::ImageLayout::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
472			}
473		};
474
475		image_barrier.new_layout = layout;
476	}
477
478	// Ensure that the stage masks are valid if no stages were determined
479	if src_stages == ash::vk::PipelineStageFlags::empty() {
480		src_stages = ash::vk::PipelineStageFlags::TOP_OF_PIPE;
481	}
482
483	if dst_stages == ash::vk::PipelineStageFlags::empty() {
484		dst_stages = ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
485	}
486
487	(src_stages, dst_stages, image_barrier)
488}
489
490pub(crate) struct AccessInfo {
491	pub(crate) stage_mask: ash::vk::PipelineStageFlags,
492	pub(crate) access_mask: ash::vk::AccessFlags,
493	pub(crate) image_layout: ash::vk::ImageLayout,
494}
495
496pub(crate) fn get_access_info(access_type: AccessType) -> AccessInfo {
497	match access_type {
498		AccessType::Nothing => AccessInfo {
499			stage_mask: ash::vk::PipelineStageFlags::empty(),
500			access_mask: ash::vk::AccessFlags::empty(),
501			image_layout: ash::vk::ImageLayout::UNDEFINED,
502		},
503		AccessType::CommandBufferReadNVX => AccessInfo {
504			stage_mask: ash::vk::PipelineStageFlags::COMMAND_PROCESS_NVX,
505			access_mask: ash::vk::AccessFlags::COMMAND_PROCESS_READ_NVX,
506			image_layout: ash::vk::ImageLayout::UNDEFINED,
507		},
508		AccessType::IndirectBuffer => AccessInfo {
509			stage_mask: ash::vk::PipelineStageFlags::DRAW_INDIRECT,
510			access_mask: ash::vk::AccessFlags::INDIRECT_COMMAND_READ,
511			image_layout: ash::vk::ImageLayout::UNDEFINED,
512		},
513		AccessType::IndexBuffer => AccessInfo {
514			stage_mask: ash::vk::PipelineStageFlags::VERTEX_INPUT,
515			access_mask: ash::vk::AccessFlags::INDEX_READ,
516			image_layout: ash::vk::ImageLayout::UNDEFINED,
517		},
518		AccessType::VertexBuffer => AccessInfo {
519			stage_mask: ash::vk::PipelineStageFlags::VERTEX_INPUT,
520			access_mask: ash::vk::AccessFlags::VERTEX_ATTRIBUTE_READ,
521			image_layout: ash::vk::ImageLayout::UNDEFINED,
522		},
523		AccessType::VertexShaderReadUniformBuffer => AccessInfo {
524			stage_mask: ash::vk::PipelineStageFlags::VERTEX_SHADER,
525			access_mask: ash::vk::AccessFlags::SHADER_READ,
526			image_layout: ash::vk::ImageLayout::UNDEFINED,
527		},
528		AccessType::VertexShaderReadSampledImageOrUniformTexelBuffer => AccessInfo {
529			stage_mask: ash::vk::PipelineStageFlags::VERTEX_SHADER,
530			access_mask: ash::vk::AccessFlags::SHADER_READ,
531			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
532		},
533		AccessType::VertexShaderReadOther => AccessInfo {
534			stage_mask: ash::vk::PipelineStageFlags::VERTEX_SHADER,
535			access_mask: ash::vk::AccessFlags::SHADER_READ,
536			image_layout: ash::vk::ImageLayout::GENERAL,
537		},
538		AccessType::TessellationControlShaderReadUniformBuffer => AccessInfo {
539			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER,
540			access_mask: ash::vk::AccessFlags::UNIFORM_READ,
541			image_layout: ash::vk::ImageLayout::UNDEFINED,
542		},
543		AccessType::TessellationControlShaderReadSampledImageOrUniformTexelBuffer => AccessInfo {
544			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER,
545			access_mask: ash::vk::AccessFlags::SHADER_READ,
546			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
547		},
548		AccessType::TessellationControlShaderReadOther => AccessInfo {
549			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER,
550			access_mask: ash::vk::AccessFlags::SHADER_READ,
551			image_layout: ash::vk::ImageLayout::GENERAL,
552		},
553		AccessType::TessellationEvaluationShaderReadUniformBuffer => AccessInfo {
554			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER,
555			access_mask: ash::vk::AccessFlags::UNIFORM_READ,
556			image_layout: ash::vk::ImageLayout::UNDEFINED,
557		},
558		AccessType::TessellationEvaluationShaderReadSampledImageOrUniformTexelBuffer => {
559			AccessInfo {
560				stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER,
561				access_mask: ash::vk::AccessFlags::SHADER_READ,
562				image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
563			}
564		}
565		AccessType::TessellationEvaluationShaderReadOther => AccessInfo {
566			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER,
567			access_mask: ash::vk::AccessFlags::SHADER_READ,
568			image_layout: ash::vk::ImageLayout::GENERAL,
569		},
570		AccessType::GeometryShaderReadUniformBuffer => AccessInfo {
571			stage_mask: ash::vk::PipelineStageFlags::GEOMETRY_SHADER,
572			access_mask: ash::vk::AccessFlags::UNIFORM_READ,
573			image_layout: ash::vk::ImageLayout::UNDEFINED,
574		},
575		AccessType::GeometryShaderReadSampledImageOrUniformTexelBuffer => AccessInfo {
576			stage_mask: ash::vk::PipelineStageFlags::GEOMETRY_SHADER,
577			access_mask: ash::vk::AccessFlags::SHADER_READ,
578			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
579		},
580		AccessType::GeometryShaderReadOther => AccessInfo {
581			stage_mask: ash::vk::PipelineStageFlags::GEOMETRY_SHADER,
582			access_mask: ash::vk::AccessFlags::SHADER_READ,
583			image_layout: ash::vk::ImageLayout::GENERAL,
584		},
585		AccessType::FragmentShaderReadUniformBuffer => AccessInfo {
586			stage_mask: ash::vk::PipelineStageFlags::FRAGMENT_SHADER,
587			access_mask: ash::vk::AccessFlags::UNIFORM_READ,
588			image_layout: ash::vk::ImageLayout::UNDEFINED,
589		},
590		AccessType::FragmentShaderReadSampledImageOrUniformTexelBuffer => AccessInfo {
591			stage_mask: ash::vk::PipelineStageFlags::FRAGMENT_SHADER,
592			access_mask: ash::vk::AccessFlags::SHADER_READ,
593			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
594		},
595		AccessType::FragmentShaderReadColorInputAttachment => AccessInfo {
596			stage_mask: ash::vk::PipelineStageFlags::FRAGMENT_SHADER,
597			access_mask: ash::vk::AccessFlags::INPUT_ATTACHMENT_READ,
598			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
599		},
600		AccessType::FragmentShaderReadDepthStencilInputAttachment => AccessInfo {
601			stage_mask: ash::vk::PipelineStageFlags::FRAGMENT_SHADER,
602			access_mask: ash::vk::AccessFlags::INPUT_ATTACHMENT_READ,
603			image_layout: ash::vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL,
604		},
605		AccessType::FragmentShaderReadOther => AccessInfo {
606			stage_mask: ash::vk::PipelineStageFlags::FRAGMENT_SHADER,
607			access_mask: ash::vk::AccessFlags::SHADER_READ,
608			image_layout: ash::vk::ImageLayout::GENERAL,
609		},
610		AccessType::ColorAttachmentRead => AccessInfo {
611			stage_mask: ash::vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
612			access_mask: ash::vk::AccessFlags::COLOR_ATTACHMENT_READ,
613			image_layout: ash::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
614		},
615		AccessType::DepthStencilAttachmentRead => AccessInfo {
616			stage_mask: ash::vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
617				| ash::vk::PipelineStageFlags::LATE_FRAGMENT_TESTS,
618			access_mask: ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
619			image_layout: ash::vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL,
620		},
621		AccessType::ComputeShaderReadUniformBuffer => AccessInfo {
622			stage_mask: ash::vk::PipelineStageFlags::COMPUTE_SHADER,
623			access_mask: ash::vk::AccessFlags::UNIFORM_READ,
624			image_layout: ash::vk::ImageLayout::UNDEFINED,
625		},
626		AccessType::ComputeShaderReadSampledImageOrUniformTexelBuffer => AccessInfo {
627			stage_mask: ash::vk::PipelineStageFlags::COMPUTE_SHADER,
628			access_mask: ash::vk::AccessFlags::SHADER_READ,
629			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
630		},
631		AccessType::ComputeShaderReadOther => AccessInfo {
632			stage_mask: ash::vk::PipelineStageFlags::COMPUTE_SHADER,
633			access_mask: ash::vk::AccessFlags::SHADER_READ,
634			image_layout: ash::vk::ImageLayout::GENERAL,
635		},
636		AccessType::AnyShaderReadUniformBuffer => AccessInfo {
637			stage_mask: ash::vk::PipelineStageFlags::ALL_COMMANDS,
638			access_mask: ash::vk::AccessFlags::UNIFORM_READ,
639			image_layout: ash::vk::ImageLayout::UNDEFINED,
640		},
641		AccessType::AnyShaderReadUniformBufferOrVertexBuffer => AccessInfo {
642			stage_mask: ash::vk::PipelineStageFlags::ALL_COMMANDS,
643			access_mask: ash::vk::AccessFlags::UNIFORM_READ
644				| ash::vk::AccessFlags::VERTEX_ATTRIBUTE_READ,
645			image_layout: ash::vk::ImageLayout::UNDEFINED,
646		},
647		AccessType::AnyShaderReadSampledImageOrUniformTexelBuffer => AccessInfo {
648			stage_mask: ash::vk::PipelineStageFlags::ALL_COMMANDS,
649			access_mask: ash::vk::AccessFlags::SHADER_READ,
650			image_layout: ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
651		},
652		AccessType::AnyShaderReadOther => AccessInfo {
653			stage_mask: ash::vk::PipelineStageFlags::ALL_COMMANDS,
654			access_mask: ash::vk::AccessFlags::SHADER_READ,
655			image_layout: ash::vk::ImageLayout::GENERAL,
656		},
657		AccessType::TransferRead => AccessInfo {
658			stage_mask: ash::vk::PipelineStageFlags::TRANSFER,
659			access_mask: ash::vk::AccessFlags::TRANSFER_READ,
660			image_layout: ash::vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
661		},
662		AccessType::HostRead => AccessInfo {
663			stage_mask: ash::vk::PipelineStageFlags::HOST,
664			access_mask: ash::vk::AccessFlags::HOST_READ,
665			image_layout: ash::vk::ImageLayout::GENERAL,
666		},
667		AccessType::Present => AccessInfo {
668			stage_mask: ash::vk::PipelineStageFlags::empty(),
669			access_mask: ash::vk::AccessFlags::empty(),
670			image_layout: ash::vk::ImageLayout::PRESENT_SRC_KHR,
671		},
672		AccessType::CommandBufferWriteNVX => AccessInfo {
673			stage_mask: ash::vk::PipelineStageFlags::COMMAND_PROCESS_NVX,
674			access_mask: ash::vk::AccessFlags::COMMAND_PROCESS_WRITE_NVX,
675			image_layout: ash::vk::ImageLayout::UNDEFINED,
676		},
677		AccessType::VertexShaderWrite => AccessInfo {
678			stage_mask: ash::vk::PipelineStageFlags::VERTEX_SHADER,
679			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
680			image_layout: ash::vk::ImageLayout::GENERAL,
681		},
682		AccessType::TessellationControlShaderWrite => AccessInfo {
683			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER,
684			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
685			image_layout: ash::vk::ImageLayout::GENERAL,
686		},
687		AccessType::TessellationEvaluationShaderWrite => AccessInfo {
688			stage_mask: ash::vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER,
689			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
690			image_layout: ash::vk::ImageLayout::GENERAL,
691		},
692		AccessType::GeometryShaderWrite => AccessInfo {
693			stage_mask: ash::vk::PipelineStageFlags::GEOMETRY_SHADER,
694			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
695			image_layout: ash::vk::ImageLayout::GENERAL,
696		},
697		AccessType::FragmentShaderWrite => AccessInfo {
698			stage_mask: ash::vk::PipelineStageFlags::FRAGMENT_SHADER,
699			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
700			image_layout: ash::vk::ImageLayout::GENERAL,
701		},
702		AccessType::ColorAttachmentWrite => AccessInfo {
703			stage_mask: ash::vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
704			access_mask: ash::vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
705			image_layout: ash::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
706		},
707		AccessType::DepthStencilAttachmentWrite => AccessInfo {
708			stage_mask: ash::vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
709				| ash::vk::PipelineStageFlags::LATE_FRAGMENT_TESTS,
710			access_mask: ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
711			image_layout: ash::vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
712		},
713		AccessType::DepthAttachmentWriteStencilReadOnly => AccessInfo {
714			stage_mask: ash::vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
715				| ash::vk::PipelineStageFlags::LATE_FRAGMENT_TESTS,
716			access_mask: ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE
717				| ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
718			image_layout: ash::vk::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
719		},
720		AccessType::StencilAttachmentWriteDepthReadOnly => AccessInfo {
721			stage_mask: ash::vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
722				| ash::vk::PipelineStageFlags::LATE_FRAGMENT_TESTS,
723			access_mask: ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE
724				| ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
725			image_layout: ash::vk::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
726		},
727		AccessType::ComputeShaderWrite => AccessInfo {
728			stage_mask: ash::vk::PipelineStageFlags::COMPUTE_SHADER,
729			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
730			image_layout: ash::vk::ImageLayout::GENERAL,
731		},
732		AccessType::AnyShaderWrite => AccessInfo {
733			stage_mask: ash::vk::PipelineStageFlags::ALL_COMMANDS,
734			access_mask: ash::vk::AccessFlags::SHADER_WRITE,
735			image_layout: ash::vk::ImageLayout::GENERAL,
736		},
737		AccessType::TransferWrite => AccessInfo {
738			stage_mask: ash::vk::PipelineStageFlags::TRANSFER,
739			access_mask: ash::vk::AccessFlags::TRANSFER_WRITE,
740			image_layout: ash::vk::ImageLayout::TRANSFER_DST_OPTIMAL,
741		},
742		AccessType::HostWrite => AccessInfo {
743			stage_mask: ash::vk::PipelineStageFlags::HOST,
744			access_mask: ash::vk::AccessFlags::HOST_WRITE,
745			image_layout: ash::vk::ImageLayout::GENERAL,
746		},
747		AccessType::ColorAttachmentReadWrite => AccessInfo {
748			stage_mask: ash::vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
749			access_mask: ash::vk::AccessFlags::COLOR_ATTACHMENT_READ
750				| ash::vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
751			image_layout: ash::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
752		},
753		AccessType::General => AccessInfo {
754			stage_mask: ash::vk::PipelineStageFlags::ALL_COMMANDS,
755			access_mask: ash::vk::AccessFlags::MEMORY_READ | ash::vk::AccessFlags::MEMORY_WRITE,
756			image_layout: ash::vk::ImageLayout::GENERAL,
757		},
758	}
759}
760
761pub(crate) fn is_write_access(access_type: AccessType) -> bool {
762	match access_type {
763		AccessType::CommandBufferWriteNVX => true,
764		AccessType::VertexShaderWrite => true,
765		AccessType::TessellationControlShaderWrite => true,
766		AccessType::TessellationEvaluationShaderWrite => true,
767		AccessType::GeometryShaderWrite => true,
768		AccessType::FragmentShaderWrite => true,
769		AccessType::ColorAttachmentWrite => true,
770		AccessType::DepthStencilAttachmentWrite => true,
771		AccessType::DepthAttachmentWriteStencilReadOnly => true,
772		AccessType::StencilAttachmentWriteDepthReadOnly => true,
773		AccessType::ComputeShaderWrite => true,
774		AccessType::AnyShaderWrite => true,
775		AccessType::TransferWrite => true,
776		AccessType::HostWrite => true,
777		AccessType::ColorAttachmentReadWrite => true,
778		AccessType::General => true,
779		_ => false,
780	}
781}