using System;
// Ported from https://github.com/Tobski/simple_vulkan_synchronization - commit a4c7ede63d29e2612d5ae1545d3b507c506fc5ed

// Copyright (c) 2017-2019 Tobias Hector

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//// Simpler Vulkan Synchronization ////
/*
In an effort to make Vulkan synchronization more accessible, I created this
stb-inspired single-header library in order to somewhat simplify the core
synchronization mechanisms in Vulkan - pipeline barriers and events.

Rather than the complex maze of enums and bit flags in Vulkan - many
combinations of which are invalid or nonsensical - this library collapses
this to a much shorter list of 40 distinct usage types, and a couple of
options for handling image layouts.

Use of other synchronization mechanisms such as semaphores, fences and render
passes are not addressed in this API at present.

USAGE

   #define the symbol THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_IMPLEMENTATION in
   *one* C/C++ file before the #include of this file; the implementation
   will be generated in that file.

VERSION

	alpha.9

	Alpha.9 adds the thsvsGetAccessInfo function to translate access types into a thsvsVkAccessInfo.


VERSION HISTORY

	alpha.8

	Alpha.8 adds a host preinitialization state for linear images, as well as a number of new access sets for extensions released since the last update.
	
	alpha.7

	Alpha.7 incorporates a number of fixes from @gwihlidal, and fixes
	handling of pipeline stages in the presence of multiple access types or
	barriers in light of other recent changes.

	alpha.6

	Alpha.6 fixes a typo (VK_ACCESS_TYPE_MEMORY_READ|WRITE_BIT should have been VK_ACCESS_MEMORY_READ|WRITE_BIT), and sets the pipeline stage src and dst flag bits to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT and VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT during initialization, not 0 as per alpha.5

	alpha.5

	Alpha.5 now correctly zeroes out the pipeline stage flags before trying to incrementally set bits on them... common theme here, whoops.

	alpha.4

	Alpha.4 now correctly zeroes out the access types before trying to incrementally set bits on them (!)

	alpha.3

	Alpha.3 changes the following:

	Uniform and vertex buffer access in one enum, matching D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER:
	 - THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER_OR_VERTEX_BUFFER

	Color read *and* write access, matching D3D12_RESOURCE_STATE_RENDER_TARGET:
	 - THSVS_ACCESS_COLOR_ATTACHMENT_READ_WRITE

	Also the "THSVS_ACCESS_*_SHADER_READ_SAMPLED_IMAGE" enums have been renamed to the form "THSVS_ACCESS_*_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER"

	alpha.2

	Alpha.2 adds four new resource states for "ANY SHADER ACCESS":
	 - THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER
	 - THSVS_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE
	 - THSVS_ACCESS_ANY_SHADER_READ_OTHER
	 - THSVS_ACCESS_ANY_SHADER_WRITE

	alpha.1

	Alpha.1 adds three new resource states:
	 - THSVS_ACCESS_GENERAL (Any access on the device)
	 - THSVS_ACCESS_DEPTH_ATTACHMENT_WRITE_STENCIL_READ_ONLY (Write access to only the depth aspect of a depth/stencil attachment)
	 - THSVS_ACCESS_STENCIL_ATTACHMENT_WRITE_DEPTH_READ_ONLY (Write access to only the stencil aspect of a depth/stencil attachment)

	It also fixes a couple of typos, and adds clarification as to when extensions need to be enabled to use a feature.

	alpha.0

	This is the very first public release of this library; future revisions
	of this API may change the API in an incompatible manner as feedback is
	received.
	Once the version becomes stable, incompatible changes will only be made
	to major revisions of the API - minor revisions will only contain
	bug fixes or minor additions.

MEMORY ALLOCATION

	The thsvsCmdPipelineBarrier and thWaitEvents commands allocate temporary
	storage for the Vulkan barrier equivalents in order to pass them to the
	respective Vulkan commands.

	These use the `THSVS_TEMP_ALLOC(size)` and `THSVS_TEMP_FREE(x)` macros,
	which are by default set to alloca(size) and ((void)(x)), respectively.
	If you don't want to use stack space or would rather use your own
	allocation strategy, these can be overridden by defining these macros
	in before #include-ing the header file with
	THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_IMPLEMENTATION defined.

	I'd rather avoid the need for these allocations in what are likely to be
	high-traffic commands, but currently just want to ship something - may
	revisit this at a future date based on feedback.

EXPRESSIVENESS COMPARED TO RAW VULKAN

	Despite the fact that this API is fairly simple, it expresses 99% of
	what you'd actually ever want to do in practice.
	Adding the missing expressiveness would result in increased complexity
	which didn't seem worth the trade off - however I would consider adding
	something for them in future if it becomes an issue.

	Here's a list of known things you can't express:

	* Execution only dependencies cannot be expressed.
	  These are occasionally useful in conjunction with semaphores, or when
	  trying to be clever with scheduling - but their usage is both limited
	  and fairly tricky to get right anyway.
	* Depth/Stencil Input Attachments can be read in a shader using either
	  VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL or
	  VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL - this library
	  *always* uses VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL.
	  It's possible (though highly unlikely) when aliasing images that this
	  results in unnecessary transitions.

ERROR CHECKS

	By default, as with the Vulkan API, this library does NOT check for
	errors.
	However, a number of optional error checks (THSVS_ERROR_CHECK_*) can be
	enabled by uncommenting the relevant #defines.
	Currently, error checks simply assert at the point a failure is detected
	and do not output an error message.
	I certainly do not claim they capture *all* possible errors, but they
	capture what should be some of the more common ones.
	Use of the Vulkan Validation Layers in tandem with this library is
	strongly recommended:
		https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers

ISSUES

	This header was clean of warnings using -Wall as of time of publishing
	on both gcc 4.8.4 and clang 3.5, using the c99 standard.

	There's a potential pitfall in thsvsCmdPipelineBarrier and thsvsCmdWaitEvents
	where alloca is used for temporary allocations. See MEMORY ALLOCATION
	for more information.

	Testing of this library is so far extremely limited with no immediate
	plans to add to that - so there's bound to be some amount of bugs.
	Please raise these issues on the repo issue tracker, or provide a fix
	via a pull request yourself if you're so inclined.
*/


//// Optional Error Checking ////
/*
Checks for barriers defining multiple usages that have different layouts
*/
// #define THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT

/*
Checks if an image/buffer barrier is used when a global barrier would suffice
*/
// #define THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER

/*
Checks if a write access is listed alongside any other access - if so it
points to a potential data hazard that you need to synchronize separately.
In some cases it may simply be over-synchronization however, but it's usually
worth checking.
*/
// #define THSVS_ERROR_CHECK_POTENTIAL_HAZARD

/*
Checks if a variety of table lookups (like the access map) are within
a valid range.
*/
// #define THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE

//// Temporary Memory Allocation ////
/*
Override these if you can't afford the stack space or just want to use a
custom temporary allocator.
These are currently used exclusively to allocate Vulkan memory barriers in
the API, one for each Buffer or Image barrier passed into the pipeline and
event functions.
May consider other allocation strategies in future.
*/

#if DEBUG
#define THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
#define THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER
#define THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT
#define THSVS_ERROR_CHECK_POTENTIAL_HAZARD
#endif

namespace Bulkan.Utilities
{
	/*
	ThsvsAccessType defines all potential resource usages in the Vulkan API.
	*/
	/*typedef*/ enum ThsvsAccessType
	{
		THSVS_ACCESS_NONE, // No access. Useful primarily for initialization

	// Read access
		// Requires VK_NV_device_generated_commands to be enabled
		THSVS_ACCESS_COMMAND_BUFFER_READ_NV , // Command buffer read operation as defined by NV_device_generated_commands
		THSVS_ACCESS_INDIRECT_BUFFER , // Read as an indirect buffer for drawing or dispatch
		THSVS_ACCESS_INDEX_BUFFER , // Read as an index buffer for drawing
		THSVS_ACCESS_VERTEX_BUFFER , // Read as a vertex buffer for drawing
		THSVS_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in a vertex shader
		THSVS_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image/uniform texel buffer in a vertex shader
		THSVS_ACCESS_VERTEX_SHADER_READ_OTHER , // Read as any other resource in a vertex shader
		THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in a tessellation control shader
		THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image/uniform texel buffer  in a tessellation control shader
		THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_OTHER , // Read as any other resource in a tessellation control shader
		THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in a tessellation evaluation shader
		THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image/uniform texel buffer in a tessellation evaluation shader
		THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_OTHER , // Read as any other resource in a tessellation evaluation shader
		THSVS_ACCESS_GEOMETRY_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in a geometry shader
		THSVS_ACCESS_GEOMETRY_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image/uniform texel buffer  in a geometry shader
		THSVS_ACCESS_GEOMETRY_SHADER_READ_OTHER , // Read as any other resource in a geometry shader
		THSVS_ACCESS_TASK_SHADER_READ_UNIFORM_BUFFER_NV , // Read as a uniform buffer in a task shader
		THSVS_ACCESS_TASK_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV , // Read as a sampled image/uniform texel buffer in a task shader
		THSVS_ACCESS_TASK_SHADER_READ_OTHER_NV , // Read as any other resource in a task shader
		THSVS_ACCESS_MESH_SHADER_READ_UNIFORM_BUFFER_NV , // Read as a uniform buffer in a mesh shader
		THSVS_ACCESS_MESH_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV , // Read as a sampled image/uniform texel buffer in a mesh shader
		THSVS_ACCESS_MESH_SHADER_READ_OTHER_NV , // Read as any other resource in a mesh shader
		THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_EXT , // Read as a transform feedback counter buffer
		THSVS_ACCESS_FRAGMENT_DENSITY_MAP_READ_EXT , // Read as a fragment density map image
		THSVS_ACCESS_SHADING_RATE_READ_NV , // Read as a shading rate image
		THSVS_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in a fragment shader
		THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image/uniform texel buffer  in a fragment shader
		THSVS_ACCESS_FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT , // Read as an input attachment with a color format in a fragment shader
		THSVS_ACCESS_FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT , // Read as an input attachment with a depth/stencil format in a fragment shader
		THSVS_ACCESS_FRAGMENT_SHADER_READ_OTHER , // Read as any other resource in a fragment shader
		THSVS_ACCESS_COLOR_ATTACHMENT_READ , // Read by standard blending/logic operations or subpass load operations
		THSVS_ACCESS_COLOR_ATTACHMENT_ADVANCED_BLENDING_EXT , // Read by advanced blending, standard blending, logic operations, or subpass load operations
		THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ , // Read by depth/stencil tests or subpass load operations
		THSVS_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in a compute shader
		THSVS_ACCESS_COMPUTE_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image/uniform texel buffer in a compute shader
		THSVS_ACCESS_COMPUTE_SHADER_READ_OTHER , // Read as any other resource in a compute shader
		THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER , // Read as a uniform buffer in any shader
		THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER_OR_VERTEX_BUFFER , // Read as a uniform buffer in any shader, or a vertex buffer
		THSVS_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER , // Read as a sampled image in any shader
		THSVS_ACCESS_ANY_SHADER_READ_OTHER , // Read as any other resource (excluding attachments) in any shader
		THSVS_ACCESS_TRANSFER_READ , // Read as the source of a transfer operation
		THSVS_ACCESS_HOST_READ , // Read on the host

		// Requires VK_KHR_swapchain to be enabled
		THSVS_ACCESS_PRESENT , // Read by the presentation engine (i.e. vkQueuePresentKHR)

		// Requires VK_EXT_conditional_rendering to be enabled
		THSVS_ACCESS_CONDITIONAL_RENDERING_READ_EXT , // Read by conditional rendering

		// Requires VK_NV_ray_tracing to be enabled
		THSVS_ACCESS_RAY_TRACING_SHADER_ACCELERATION_STRUCTURE_READ_NV , // Read by a ray tracing shader as an acceleration structure
		THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_READ_NV , // Read as an acceleration structure during a build

		// Read accesses end
		THSVS_END_OF_READ_ACCESS ,

	// Write access
		// Requires VK_NV_device_generated_commands to be enabled
		THSVS_ACCESS_COMMAND_BUFFER_WRITE_NV , // Command buffer write operation
		THSVS_ACCESS_VERTEX_SHADER_WRITE , // Written as any resource in a vertex shader
		THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_WRITE , // Written as any resource in a tessellation control shader
		THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_WRITE , // Written as any resource in a tessellation evaluation shader
		THSVS_ACCESS_GEOMETRY_SHADER_WRITE , // Written as any resource in a geometry shader

		// Requires VK_NV_mesh_shading to be enabled
		THSVS_ACCESS_TASK_SHADER_WRITE_NV , // Written as any resource in a task shader
		THSVS_ACCESS_MESH_SHADER_WRITE_NV , // Written as any resource in a mesh shader

		// Requires VK_EXT_transform_feedback to be enabled
		THSVS_ACCESS_TRANSFORM_FEEDBACK_WRITE_EXT , // Written as a transform feedback buffer
		THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT , // Written as a transform feedback counter buffer

		THSVS_ACCESS_FRAGMENT_SHADER_WRITE , // Written as any resource in a fragment shader
		THSVS_ACCESS_COLOR_ATTACHMENT_WRITE , // Written as a color attachment during rendering, or via a subpass store op
		THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE , // Written as a depth/stencil attachment during rendering, or via a subpass store op

		// Requires VK_KHR_maintenance2 to be enabled
		THSVS_ACCESS_DEPTH_ATTACHMENT_WRITE_STENCIL_READ_ONLY , // Written as a depth aspect of a depth/stencil attachment during rendering, whilst the stencil aspect is read-only
		THSVS_ACCESS_STENCIL_ATTACHMENT_WRITE_DEPTH_READ_ONLY , // Written as a stencil aspect of a depth/stencil attachment during rendering, whilst the depth aspect is read-only

		THSVS_ACCESS_COMPUTE_SHADER_WRITE , // Written as any resource in a compute shader
		THSVS_ACCESS_ANY_SHADER_WRITE , // Written as any resource in any shader
		THSVS_ACCESS_TRANSFER_WRITE , // Written as the destination of a transfer operation
		THSVS_ACCESS_HOST_PREINITIALIZED , // Data pre-filled by host before device access starts
		THSVS_ACCESS_HOST_WRITE , // Written on the host

		// Requires VK_NV_ray_tracing to be enabled
		THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_WRITE_NV , // Written as an acceleration structure during a build

		THSVS_ACCESS_COLOR_ATTACHMENT_READ_WRITE , // Read or written as a color attachment during rendering
	// General access
		THSVS_ACCESS_GENERAL , // Covers any access - useful for debug, generally avoid for performance reasons

	// Number of access types
		THSVS_NUM_ACCESS_TYPES
	} /* ThsvsAccessType;*/

	/*
	ThsvsImageLayout defines a handful of layout options for images.
	Rather than a list of all possible image layouts, this reduced list is
	correlated with the access types to map to the correct Vulkan layouts.
	THSVS_IMAGE_LAYOUT_OPTIMAL is usually preferred.
	*/
	/*typedef*/ enum ThsvsImageLayout
	{
		THSVS_IMAGE_LAYOUT_OPTIMAL, // Choose the most optimal layout for each usage. Performs layout transitions as appropriate for the access.
		THSVS_IMAGE_LAYOUT_GENERAL , // Layout accessible by all Vulkan access types on a device - no layout transitions except for presentation

		// Requires VK_KHR_shared_presentable_image to be enabled. Can only be used for shared presentable images (i.e. single-buffered swap chains).
		THSVS_IMAGE_LAYOUT_GENERAL_AND_PRESENTATION // As GENERAL, but also allows presentation engines to access it - no layout transitions
	} /*ThsvsImageLayout;*/

	/*
	Global barriers define a set of accesses on multiple resources at once.
	If a buffer or image doesn't require a queue ownership transfer, or an image
	doesn't require a layout transition (e.g. you're using one of the GENERAL
	layouts) then a global barrier should be preferred.
	Simply define the previous and next access types of resources affected.
	*/
	/*typedef*/ struct ThsvsGlobalBarrier
	{
		public uint32 prevAccessCount;
		public readonly ThsvsAccessType* pPrevAccesses;
		public uint32 nextAccessCount;
		public readonly ThsvsAccessType* pNextAccesses;
	} /*ThsvsGlobalBarrier;*/

	/*
	Buffer barriers should only be used when a queue family ownership transfer
	is required - prefer global barriers at all other times.

	Access types are defined in the same way as for a global memory barrier, but
	they only affect the buffer range identified by buffer, offset and size,
	rather than all resources.
	srcQueueFamilyIndex and dstQueueFamilyIndex will be passed unmodified into a
	VkBufferMemoryBarrier.

	A buffer barrier defining a queue ownership transfer needs to be executed
	twice - once by a queue in the source queue family, and then once again by a
	queue in the destination queue family, with a semaphore guaranteeing
	execution order between them.
	*/
	/*typedef*/ struct ThsvsBufferBarrier
	{
		public uint32 prevAccessCount;
		public readonly ThsvsAccessType* pPrevAccesses;
		public uint32 nextAccessCount;
		public readonly ThsvsAccessType* pNextAccesses;
		public uint32 srcQueueFamilyIndex;
		public uint32 dstQueueFamilyIndex;
		public VkBuffer buffer;
		public VkDeviceSize offset;
		public VkDeviceSize size;
	} /*ThsvsBufferBarrier;*/

	/*
	Image barriers should only be used when a queue family ownership transfer
	or an image layout transition is required - prefer global barriers at all
	other times.
	In general it is better to use image barriers with THSVS_IMAGE_LAYOUT_OPTIMAL
	than it is to use global barriers with images using either of the
	THSVS_IMAGE_LAYOUT_GENERAL* layouts.

	Access types are defined in the same way as for a global memory barrier, but
	they only affect the image subresource range identified by image and
	subresourceRange, rather than all resources.
	srcQueueFamilyIndex, dstQueueFamilyIndex, image, and subresourceRange will
	be passed unmodified into a VkImageMemoryBarrier.

	An image barrier defining a queue ownership transfer needs to be executed
	twice - once by a queue in the source queue family, and then once again by a
	queue in the destination queue family, with a semaphore guaranteeing
	execution order between them.

	If discardContents is set to true, the contents of the image become
	undefined after the barrier is executed, which can result in a performance
	boost over attempting to preserve the contents.
	This is particularly useful for transient images where the contents are
	going to be immediately overwritten. A good example of when to use this is
when an application re-uses a presented image after vkAcquireNextImageKHR.
	*/
	/*typedef*/ struct ThsvsImageBarrier
	{
		public uint32 prevAccessCount;
		public readonly ThsvsAccessType* pPrevAccesses;
		public uint32 nextAccessCount;
		public readonly ThsvsAccessType* pNextAccesses;
		public ThsvsImageLayout prevLayout;
		public ThsvsImageLayout nextLayout;
		public VkBool32 discardContents;
		public uint32 srcQueueFamilyIndex;
		public uint32 dstQueueFamilyIndex;
		public VkImage image;
		public VkImageSubresourceRange subresourceRange;
	} /*ThsvsImageBarrier;*/

	public static
	{
		private static mixin THSVS_TEMP_ALLOC(uint size){
			void* data = scope:: uint8[size]*;
			data
		}

		private static mixin THSVS_TEMP_FREE(void* memory){
			
		}

		/*typedef*/ struct ThsvsVkAccessInfo
		{
			public VkPipelineStageFlags stageMask;
			public VkAccessFlags accessMask;
			public VkImageLayout imageLayout;
		} /* ThsvsVkAccessInfo;*/

		public static ThsvsVkAccessInfo[(int)ThsvsAccessType.THSVS_NUM_ACCESS_TYPES] ThsvsAccessMap = .( // THSVS_ACCESS_NONE
			.()
			{
				stageMask = 0,
				accessMask = 0,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // Read Access
			// THSVS_ACCESS_COMMAND_BUFFER_READ_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV,
				accessMask = .VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_INDIRECT_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
				accessMask = .VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_INDEX_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
				accessMask = .VK_ACCESS_INDEX_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_VERTEX_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
				accessMask = .VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_VERTEX_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_GEOMETRY_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_GEOMETRY_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_GEOMETRY_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TASK_SHADER_READ_UNIFORM_BUFFER_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_TASK_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_TASK_SHADER_READ_OTHER_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_MESH_SHADER_READ_UNIFORM_BUFFER_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_MESH_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_MESH_SHADER_READ_OTHER_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_EXT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
				accessMask = .VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_FRAGMENT_DENSITY_MAP_READ_EXT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT,
				accessMask = .VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT,
				imageLayout = .VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT
			}, // THSVS_ACCESS_SHADING_RATE_READ_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, // .VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV
				accessMask = .VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,//.VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV,
				imageLayout = .VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR//.VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV
			}, // THSVS_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
				accessMask = .VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
				accessMask = .VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_FRAGMENT_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_COLOR_ATTACHMENT_READ
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
				accessMask = .VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
			}, // THSVS_ACCESS_COLOR_ATTACHMENT_ADVANCED_BLENDING_EXT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
				accessMask = .VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT,
				imageLayout = .VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
			}, // THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | .VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
				accessMask = .VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_COMPUTE_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_COMPUTE_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER_OR_VERTEX_BUFFER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
				accessMask = .VK_ACCESS_UNIFORM_READ_BIT | .VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_ANY_SHADER_READ_OTHER
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
				accessMask = .VK_ACCESS_SHADER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TRANSFER_READ
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TRANSFER_BIT,
				accessMask = .VK_ACCESS_TRANSFER_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
			}, // THSVS_ACCESS_HOST_READ
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_HOST_BIT,
				accessMask = .VK_ACCESS_HOST_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_PRESENT
				.()
			{
				stageMask = 0,
				accessMask = 0,
				imageLayout = .VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
			}, // THSVS_ACCESS_CONDITIONAL_RENDERING_READ_EXT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT,
				accessMask = .VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_RAY_TRACING_SHADER_ACCELERATION_STRUCTURE_READ_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
				accessMask = .VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_READ_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
				accessMask = .VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_END_OF_READ_ACCESS
				.()
			{
				stageMask = 0,
				accessMask = 0,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // Write access
			// THSVS_ACCESS_COMMAND_BUFFER_WRITE_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV,
				accessMask = .VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_VERTEX_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_GEOMETRY_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TASK_SHADER_WRITE_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_MESH_SHADER_WRITE_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TRANSFORM_FEEDBACK_WRITE_EXT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
				accessMask = .VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
				accessMask = .VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_FRAGMENT_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_COLOR_ATTACHMENT_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
				accessMask = .VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
			}, // THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | .VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
				accessMask = .VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
			}, // THSVS_ACCESS_DEPTH_ATTACHMENT_WRITE_STENCIL_READ_ONLY
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | .VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
				accessMask = .VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | .VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL
			}, // THSVS_ACCESS_STENCIL_ATTACHMENT_WRITE_DEPTH_READ_ONLY
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | .VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
				accessMask = .VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | .VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
			}, // THSVS_ACCESS_COMPUTE_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_ANY_SHADER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
				accessMask = .VK_ACCESS_SHADER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_TRANSFER_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_TRANSFER_BIT,
				accessMask = .VK_ACCESS_TRANSFER_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
			}, // THSVS_ACCESS_HOST_PREINITIALIZED
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_HOST_BIT,
				accessMask = .VK_ACCESS_HOST_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_PREINITIALIZED
			}, // THSVS_ACCESS_HOST_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_HOST_BIT,
				accessMask = .VK_ACCESS_HOST_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}, // THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_WRITE_NV
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
				accessMask = .VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
				imageLayout = .VK_IMAGE_LAYOUT_UNDEFINED
			}, // THSVS_ACCESS_COLOR_ATTACHMENT_READ_WRITE
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
				accessMask = .VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | .VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
			}, // THSVS_ACCESS_GENERAL
				.()
			{
				stageMask = .VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
				accessMask = .VK_ACCESS_MEMORY_READ_BIT | .VK_ACCESS_MEMORY_WRITE_BIT,
				imageLayout = .VK_IMAGE_LAYOUT_GENERAL
			}
				);

		/*
		Mapping function that translates a set of accesses into the corresponding
		pipeline stages, VkAccessFlags, and image layout.
		*/
		public static void thsvsGetAccessInfo(
		    uint32               accessCount,
		    in ThsvsAccessType* pAccesses,
		    VkPipelineStageFlags*  pStageMask,
		    VkAccessFlags*         pAccessMask,
		    VkImageLayout*         pImageLayout,
		    bool*                  pHasWriteAccess)
		{
		    *pStageMask   = 0;
		    *pAccessMask  = 0;
		    *pImageLayout = .VK_IMAGE_LAYOUT_UNDEFINED;
		    *pHasWriteAccess = false;

		    for (uint32 i = 0; i < accessCount; ++i)
		    {
		        ThsvsAccessType access = pAccesses[i];
		        ThsvsVkAccessInfo* pAccessInfo = &ThsvsAccessMap[(int)access];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the previous access index is a valid range for the lookup
		        Runtime.Assert(access < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(access < .THSVS_END_OF_READ_ACCESS || accessCount == 1);
#endif

		        *pStageMask |= pAccessInfo.stageMask;

		        if (access > .THSVS_END_OF_READ_ACCESS)
		            *pHasWriteAccess = true;

		        *pAccessMask |= pAccessInfo.accessMask;

		        VkImageLayout layout = pAccessInfo.imageLayout;

#if THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT
		        Runtime.Assert(*pImageLayout == .VK_IMAGE_LAYOUT_UNDEFINED ||
		               *pImageLayout == layout);
#endif

		        *pImageLayout = layout;
		    }
		}

		/*
		Mapping function that translates a global barrier into a set of source and
		destination pipeline stages, and a VkMemoryBarrier, that can be used with
		Vulkan's synchronization methods.
		*/
		public static void thsvsGetVulkanMemoryBarrier(
		    in ThsvsGlobalBarrier thBarrier,
		    VkPipelineStageFlags*     pSrcStages,
		    VkPipelineStageFlags*     pDstStages,
		    VkMemoryBarrier*          pVkBarrier)
		{
		    *pSrcStages               = 0;
		    *pDstStages               = 0;
		    pVkBarrier.sType         = .VK_STRUCTURE_TYPE_MEMORY_BARRIER;
		    pVkBarrier.pNext         = null;
		    pVkBarrier.srcAccessMask = 0;
		    pVkBarrier.dstAccessMask = 0;

		    for (uint32 i = 0; i < thBarrier.prevAccessCount; ++i)
		    {
		        ThsvsAccessType prevAccess = thBarrier.pPrevAccesses[i];
		        ThsvsVkAccessInfo* pPrevAccessInfo = &ThsvsAccessMap[(int)prevAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the previous access index is a valid range for the lookup
		        Runtime.Assert(prevAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(prevAccess < .THSVS_END_OF_READ_ACCESS || thBarrier.prevAccessCount == 1);
#endif

		        *pSrcStages |= pPrevAccessInfo.stageMask;

		        // Add appropriate availability operations - for writes only.
		        if (prevAccess > .THSVS_END_OF_READ_ACCESS)
		            pVkBarrier.srcAccessMask |= pPrevAccessInfo.accessMask;
		    }

		    for (uint32 i = 0; i < thBarrier.nextAccessCount; ++i)
		    {
		        ThsvsAccessType nextAccess = thBarrier.pNextAccesses[i];
		        ThsvsVkAccessInfo* pNextAccessInfo = &ThsvsAccessMap[(int)nextAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the next access index is a valid range for the lookup
		        Runtime.Assert(nextAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(nextAccess < .THSVS_END_OF_READ_ACCESS || thBarrier.nextAccessCount == 1);
#endif
		        *pDstStages |= pNextAccessInfo.stageMask;

		        // Add visibility operations as necessary.
		        // If the src access mask is zero, this is a WAR hazard (or for some reason a "RAR"),
		        // so the dst access mask can be safely zeroed as these don't need visibility.
		        if (pVkBarrier.srcAccessMask != 0)
		            pVkBarrier.dstAccessMask |= pNextAccessInfo.accessMask;
		    }

		    // Ensure that the stage masks are valid if no stages were determined
		    if (*pSrcStages == 0)
		        *pSrcStages = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
		    if (*pDstStages == 0)
		        *pDstStages = .VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
		}

		/*
		Mapping function that translates a buffer barrier into a set of source and
		destination pipeline stages, and a VkBufferMemoryBarrier, that can be used
		with Vulkan's synchronization methods.
		*/
		public static void thsvsGetVulkanBufferMemoryBarrier(
		    in ThsvsBufferBarrier thBarrier,
		    VkPipelineStageFlags*     pSrcStages,
		    VkPipelineStageFlags*     pDstStages,
		    VkBufferMemoryBarrier*    pVkBarrier)
		{
		    *pSrcStages                     = 0;
		    *pDstStages                     = 0;
		    pVkBarrier.sType               = .VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
		    pVkBarrier.pNext               = null;
		    pVkBarrier.srcAccessMask       = 0;
		    pVkBarrier.dstAccessMask       = 0;
		    pVkBarrier.srcQueueFamilyIndex = thBarrier.srcQueueFamilyIndex;
		    pVkBarrier.dstQueueFamilyIndex = thBarrier.dstQueueFamilyIndex;
		    pVkBarrier.buffer              = thBarrier.buffer;
		    pVkBarrier.offset              = (uint64)thBarrier.offset;
		    pVkBarrier.size                = (uint64)thBarrier.size;

#if THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER
		    Runtime.Assert(pVkBarrier.srcQueueFamilyIndex != pVkBarrier.dstQueueFamilyIndex);
#endif

		    for (uint32 i = 0; i < thBarrier.prevAccessCount; ++i)
		    {
		        ThsvsAccessType prevAccess = thBarrier.pPrevAccesses[i];
		        ThsvsVkAccessInfo* pPrevAccessInfo = &ThsvsAccessMap[(int)prevAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the previous access index is a valid range for the lookup
		        Runtime.Assert(prevAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(prevAccess < .THSVS_END_OF_READ_ACCESS || thBarrier.prevAccessCount == 1);
#endif

		        *pSrcStages |= pPrevAccessInfo.stageMask;

		        // Add appropriate availability operations - for writes only.
		        if (prevAccess > .THSVS_END_OF_READ_ACCESS)
		            pVkBarrier.srcAccessMask |= pPrevAccessInfo.accessMask;
		    }

		    for (uint32 i = 0; i < thBarrier.nextAccessCount; ++i)
		    {
		        ThsvsAccessType nextAccess = thBarrier.pNextAccesses[i];
		        ThsvsVkAccessInfo* pNextAccessInfo = &ThsvsAccessMap[(int)nextAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the next access index is a valid range for the lookup
		        Runtime.Assert(nextAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(nextAccess < .THSVS_END_OF_READ_ACCESS || thBarrier.nextAccessCount == 1);
#endif

		        *pDstStages |= pNextAccessInfo.stageMask;

		        // Add visibility operations as necessary.
		        // If the src access mask is zero, this is a WAR hazard (or for some reason a "RAR"),
		        // so the dst access mask can be safely zeroed as these don't need visibility.
		        if (pVkBarrier.srcAccessMask != 0)
		            pVkBarrier.dstAccessMask |= pNextAccessInfo.accessMask;
		    }

		    // Ensure that the stage masks are valid if no stages were determined
		    if (*pSrcStages == 0)
		        *pSrcStages = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
		    if (*pDstStages == 0)
		        *pDstStages = .VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
		}

		/*
		Mapping function that translates an image barrier into a set of source and
		destination pipeline stages, and a VkBufferMemoryBarrier, that can be used
		with Vulkan's synchronization methods.
		*/
		public static void thsvsGetVulkanImageMemoryBarrier(
		    in ThsvsImageBarrier thBarrier,
		    VkPipelineStageFlags*    pSrcStages,
		    VkPipelineStageFlags*    pDstStages,
		    VkImageMemoryBarrier*    pVkBarrier)
		{
		    *pSrcStages                     = 0;
		    *pDstStages                     = 0;
		    pVkBarrier.sType               = .VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
		    pVkBarrier.pNext               = null;
		    pVkBarrier.srcAccessMask       = 0;
		    pVkBarrier.dstAccessMask       = 0;
		    pVkBarrier.srcQueueFamilyIndex = thBarrier.srcQueueFamilyIndex;
		    pVkBarrier.dstQueueFamilyIndex = thBarrier.dstQueueFamilyIndex;
		    pVkBarrier.image               = thBarrier.image;
		    pVkBarrier.subresourceRange    = thBarrier.subresourceRange;
		    pVkBarrier.oldLayout           = .VK_IMAGE_LAYOUT_UNDEFINED;
		    pVkBarrier.newLayout           = .VK_IMAGE_LAYOUT_UNDEFINED;

		    for (uint32 i = 0; i < thBarrier.prevAccessCount; ++i)
		    {
		        ThsvsAccessType prevAccess = thBarrier.pPrevAccesses[i];
		        ThsvsVkAccessInfo* pPrevAccessInfo = &ThsvsAccessMap[(int)prevAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the previous access index is a valid range for the lookup
		        Runtime.Assert(prevAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(prevAccess < .THSVS_END_OF_READ_ACCESS || thBarrier.prevAccessCount == 1);
#endif

		        *pSrcStages |= pPrevAccessInfo.stageMask;

		        // Add appropriate availability operations - for writes only.
		        if (prevAccess > .THSVS_END_OF_READ_ACCESS)
		            pVkBarrier.srcAccessMask |= pPrevAccessInfo.accessMask;

		        if (thBarrier.discardContents == VulkanNative.VK_TRUE)
		        {
		            pVkBarrier.oldLayout = .VK_IMAGE_LAYOUT_UNDEFINED;
		        }
		        else
		        {
		            VkImageLayout layout = .VK_IMAGE_LAYOUT_UNDEFINED;

		            switch(thBarrier.prevLayout)
		            {
		                case .THSVS_IMAGE_LAYOUT_GENERAL:
		                    if (prevAccess == .THSVS_ACCESS_PRESENT)
		                        layout = .VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
		                    else
		                        layout = .VK_IMAGE_LAYOUT_GENERAL;
		                    break;
		                case .THSVS_IMAGE_LAYOUT_OPTIMAL:
		                    layout = pPrevAccessInfo.imageLayout;
		                    break;
		                case .THSVS_IMAGE_LAYOUT_GENERAL_AND_PRESENTATION:
		                    layout = .VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
		                    break;
		            }


#if THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT
		            Runtime.Assert(pVkBarrier.oldLayout == .VK_IMAGE_LAYOUT_UNDEFINED ||
		                   pVkBarrier.oldLayout == layout);
#endif
		            pVkBarrier.oldLayout = layout;
		        }
		    }

		    for (uint32 i = 0; i < thBarrier.nextAccessCount; ++i)
		    {
		        ThsvsAccessType nextAccess = thBarrier.pNextAccesses[i];
		        ThsvsVkAccessInfo* pNextAccessInfo = &ThsvsAccessMap[(int)nextAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the next access index is a valid range for the lookup
		        Runtime.Assert(nextAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

#if THSVS_ERROR_CHECK_POTENTIAL_HAZARD
		        // Asserts that the access is a read, else it's a write and it should appear on its own.
		        Runtime.Assert(nextAccess < .THSVS_END_OF_READ_ACCESS || thBarrier.nextAccessCount == 1);
#endif

		        *pDstStages |= pNextAccessInfo.stageMask;

		        // Add visibility operations as necessary.
		        // If the src access mask is zero, this is a WAR hazard (or for some reason a "RAR"),
		        // so the dst access mask can be safely zeroed as these don't need visibility.
		        if (pVkBarrier.srcAccessMask != 0)
		            pVkBarrier.dstAccessMask |= pNextAccessInfo.accessMask;

		        VkImageLayout layout = .VK_IMAGE_LAYOUT_UNDEFINED;
		        switch(thBarrier.nextLayout)
		        {
		            case .THSVS_IMAGE_LAYOUT_GENERAL:
		                if (nextAccess == .THSVS_ACCESS_PRESENT)
		                    layout = .VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
		                else
		                    layout = .VK_IMAGE_LAYOUT_GENERAL;
		                break;
		            case .THSVS_IMAGE_LAYOUT_OPTIMAL:
		                layout = pNextAccessInfo.imageLayout;
		                break;
		            case .THSVS_IMAGE_LAYOUT_GENERAL_AND_PRESENTATION:
		                layout = .VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
		                break;
		        }

#if THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT
		        Runtime.Assert(pVkBarrier.newLayout == .VK_IMAGE_LAYOUT_UNDEFINED ||
		               pVkBarrier.newLayout == layout);
#endif
		        pVkBarrier.newLayout = layout;
		    }

#if THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER
		    Runtime.Assert(pVkBarrier.newLayout != pVkBarrier.oldLayout ||
		           pVkBarrier.srcQueueFamilyIndex != pVkBarrier.dstQueueFamilyIndex);
#endif

		    // Ensure that the stage masks are valid if no stages were determined
		    if (*pSrcStages == 0)
		        *pSrcStages = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
		    if (*pDstStages == 0)
		        *pDstStages = .VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
		}

		/*
		Simplified wrapper around vkCmdPipelineBarrier.

		The mapping functions defined above are used to translate the passed in
		barrier definitions into a set of pipeline stages and native Vulkan memory
		barriers to be passed to vkCmdPipelineBarrier.

		commandBuffer is passed unmodified to vkCmdPipelineBarrier.
		*/
		public static void thsvsCmdPipelineBarrier(
		    VkCommandBuffer           commandBuffer,
		    in ThsvsGlobalBarrier* pGlobalBarrier,
		    uint32                  bufferBarrierCount,
		    in ThsvsBufferBarrier* pBufferBarriers,
		    uint32                  imageBarrierCount,
		    in ThsvsImageBarrier*  pImageBarriers)
		{
		    VkMemoryBarrier        memoryBarrier;
		    // Vulkan pipeline barrier command parameters
		    //                     commandBuffer;
		    VkPipelineStageFlags   srcStageMask             = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
		    VkPipelineStageFlags   dstStageMask             = .VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
		    uint32               memoryBarrierCount       = (pGlobalBarrier != null) ? 1 : 0;
		    VkMemoryBarrier*       pMemoryBarriers          = (pGlobalBarrier != null) ? &memoryBarrier : null;
		    uint32               bufferMemoryBarrierCount = bufferBarrierCount;
		    VkBufferMemoryBarrier* pBufferMemoryBarriers    = null;
		    uint32               imageMemoryBarrierCount  = imageBarrierCount;
		    VkImageMemoryBarrier*  pImageMemoryBarriers     = null;

		    // Global memory barrier
		    if (pGlobalBarrier != null)
		    {
		        VkPipelineStageFlags tempSrcStageMask = 0;
		        VkPipelineStageFlags tempDstStageMask = 0;
		        thsvsGetVulkanMemoryBarrier(*pGlobalBarrier, &tempSrcStageMask, &tempDstStageMask, pMemoryBarriers);
		        srcStageMask |= tempSrcStageMask;
		        dstStageMask |= tempDstStageMask;
		    }

		    // Buffer memory barriers
		    if (bufferBarrierCount > 0)
		    {
		        pBufferMemoryBarriers = (VkBufferMemoryBarrier*)THSVS_TEMP_ALLOC!(sizeof(VkBufferMemoryBarrier) * bufferMemoryBarrierCount);

		        VkPipelineStageFlags tempSrcStageMask = 0;
		        VkPipelineStageFlags tempDstStageMask = 0;
		        for (uint32 i = 0; i < bufferBarrierCount; ++i)
		        {
		            thsvsGetVulkanBufferMemoryBarrier(pBufferBarriers[i], &tempSrcStageMask, &tempDstStageMask, &pBufferMemoryBarriers[i]);
		            srcStageMask |= tempSrcStageMask;
		            dstStageMask |= tempDstStageMask;
		        }
		    }

		    // Image memory barriers
		    if (imageBarrierCount > 0)
		    {
		        pImageMemoryBarriers = (VkImageMemoryBarrier*)THSVS_TEMP_ALLOC!(sizeof(VkImageMemoryBarrier) * imageMemoryBarrierCount);

		        VkPipelineStageFlags tempSrcStageMask = 0;
		        VkPipelineStageFlags tempDstStageMask = 0;
		        for (uint32 i = 0; i < imageBarrierCount; ++i)
		        {
		            thsvsGetVulkanImageMemoryBarrier(pImageBarriers[i], &tempSrcStageMask, &tempDstStageMask, &pImageMemoryBarriers[i]);
		            srcStageMask |= tempSrcStageMask;
		            dstStageMask |= tempDstStageMask;
		        }
		    }

		    VulkanNative.vkCmdPipelineBarrier(
		        commandBuffer,
		        srcStageMask,
		        dstStageMask,
		        0,
		        memoryBarrierCount,
		        pMemoryBarriers,
		        bufferMemoryBarrierCount,
		        pBufferMemoryBarriers,
		        imageMemoryBarrierCount,
		        pImageMemoryBarriers);

		    THSVS_TEMP_FREE!(pBufferMemoryBarriers);
		    THSVS_TEMP_FREE!(pImageMemoryBarriers);
		}

		/*
		Wrapper around vkCmdSetEvent.

		Sets an event when the accesses defined by pPrevAccesses are completed.

		commandBuffer and event are passed unmodified to vkCmdSetEvent.
		*/
		public static void thsvsCmdSetEvent(
		    VkCommandBuffer           commandBuffer,
		    VkEvent                   event,
		    uint32                  prevAccessCount,
		    in ThsvsAccessType*    pPrevAccesses)
		{
		    VkPipelineStageFlags stageMask = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;

		    for (uint32 i = 0; i < prevAccessCount; ++i)
		    {
		        ThsvsAccessType prevAccess = pPrevAccesses[i];
		        ThsvsVkAccessInfo* pPrevAccessInfo = &ThsvsAccessMap[(int)prevAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the previous access index is a valid range for the lookup
		        Runtime.Assert(prevAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

		        stageMask |= pPrevAccessInfo.stageMask;
		    }

		    VulkanNative.vkCmdSetEvent(
		        commandBuffer,
		        event,
		        stageMask);
		}

		/*
		Wrapper around vkCmdResetEvent.

		Resets an event when the accesses defined by pPrevAccesses are completed.

		commandBuffer and event are passed unmodified to vkCmdResetEvent.
		*/
		public static void thsvsCmdResetEvent(
		    VkCommandBuffer           commandBuffer,
		    VkEvent                   event,
		    uint32                  prevAccessCount,
		    in ThsvsAccessType*    pPrevAccesses)
		{
		    VkPipelineStageFlags stageMask = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;

		    for (uint32 i = 0; i < prevAccessCount; ++i)
		    {
		        ThsvsAccessType prevAccess = pPrevAccesses[i];
		        ThsvsVkAccessInfo* pPrevAccessInfo = &ThsvsAccessMap[(int)prevAccess];

#if THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
		        // Asserts that the previous access index is a valid range for the lookup
		        Runtime.Assert(prevAccess < .THSVS_NUM_ACCESS_TYPES);
#endif

		        stageMask |= pPrevAccessInfo.stageMask;
		    }

		    VulkanNative.vkCmdResetEvent(
		        commandBuffer,
		        event,
		        stageMask);
		}

		/*
		Simplified wrapper around vkCmdWaitEvents.

		The mapping functions defined above are used to translate the passed in
		barrier definitions into a set of pipeline stages and native Vulkan memory
		barriers to be passed to vkCmdPipelineBarrier.

		commandBuffer, eventCount, and pEvents are passed unmodified to
		vkCmdWaitEvents.
		*/
		public static void thsvsCmdWaitEvents(
		    VkCommandBuffer           commandBuffer,
		    uint32                  eventCount,
		    in VkEvent*            pEvents,
		    in ThsvsGlobalBarrier* pGlobalBarrier,
		    uint32                  bufferBarrierCount,
		    in ThsvsBufferBarrier* pBufferBarriers,
		    uint32                  imageBarrierCount,
		    in ThsvsImageBarrier*  pImageBarriers)
		{
		    VkMemoryBarrier        memoryBarrier;
		    // Vulkan pipeline barrier command parameters
		    //                     commandBuffer;
		    //                     eventCount;
		    //                     pEvents;
		    VkPipelineStageFlags   srcStageMask             = .VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
		    VkPipelineStageFlags   dstStageMask             = .VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
		    uint32               memoryBarrierCount       = (pGlobalBarrier != null) ? 1 : 0;
		    VkMemoryBarrier*       pMemoryBarriers          = (pGlobalBarrier != null) ? &memoryBarrier : null;
		    uint32               bufferMemoryBarrierCount = bufferBarrierCount;
		    VkBufferMemoryBarrier* pBufferMemoryBarriers    = null;
		    uint32               imageMemoryBarrierCount  = imageBarrierCount;
		    VkImageMemoryBarrier*  pImageMemoryBarriers     = null;

		    // Global memory barrier
		    if (pGlobalBarrier != null)
		    {
		        VkPipelineStageFlags tempSrcStageMask = 0;
		        VkPipelineStageFlags tempDstStageMask = 0;
		        thsvsGetVulkanMemoryBarrier(*pGlobalBarrier, &tempSrcStageMask, &tempDstStageMask, pMemoryBarriers);
		        srcStageMask |= tempSrcStageMask;
		        dstStageMask |= tempDstStageMask;
		    }

		    // Buffer memory barriers
		    if (bufferBarrierCount > 0)
		    {
		        pBufferMemoryBarriers = (VkBufferMemoryBarrier*)THSVS_TEMP_ALLOC!(sizeof(VkBufferMemoryBarrier) * bufferMemoryBarrierCount);

		        VkPipelineStageFlags tempSrcStageMask = 0;
		        VkPipelineStageFlags tempDstStageMask = 0;
		        for (uint32 i = 0; i < bufferBarrierCount; ++i)
		        {
		            thsvsGetVulkanBufferMemoryBarrier(pBufferBarriers[i], &tempSrcStageMask, &tempDstStageMask, &pBufferMemoryBarriers[i]);
		            srcStageMask |= tempSrcStageMask;
		            dstStageMask |= tempDstStageMask;
		        }
		    }

		    // Image memory barriers
		    if (imageBarrierCount > 0)
		    {
		        pImageMemoryBarriers = (VkImageMemoryBarrier*)THSVS_TEMP_ALLOC!(sizeof(VkImageMemoryBarrier) * imageMemoryBarrierCount);

		        VkPipelineStageFlags tempSrcStageMask = 0;
		        VkPipelineStageFlags tempDstStageMask = 0;
		        for (uint32 i = 0; i < imageBarrierCount; ++i)
		        {
		            thsvsGetVulkanImageMemoryBarrier(pImageBarriers[i], &tempSrcStageMask, &tempDstStageMask, &pImageMemoryBarriers[i]);
		            srcStageMask |= tempSrcStageMask;
		            dstStageMask |= tempDstStageMask;
		        }
		    }

		    VulkanNative.vkCmdWaitEvents(
		        commandBuffer,
		        eventCount,
		        pEvents,
		        srcStageMask,
		        dstStageMask,
		        memoryBarrierCount,
		        pMemoryBarriers,
		        bufferMemoryBarrierCount,
		        pBufferMemoryBarriers,
		        imageMemoryBarrierCount,
		        pImageMemoryBarriers);

		    THSVS_TEMP_FREE!(pBufferMemoryBarriers);
		    THSVS_TEMP_FREE!(pImageMemoryBarriers);
		}
	}
}