多线程渲染已经听了很久了,然而ES时代,这个事情完全不知从何下手。然而Vulkan引入了queue、command buffer等概念,终于开启了多线程渲染的篇章。然而多线程渲染更重要的是同步问题。本节主要就是说同步问题

https://blog.csdn.net/u010281924/article/details/105379542/、https://zhuanlan.zhihu.com/p/80692115


在Vulkan中,对资源访问的同步工作主要由应用程序负责。命令的执行顺序也几乎没有隐式保证,都是需要显式指定。memory caches和其它优化也是显式管理的,由应用程序控制数据流。

虽然command之间存在一些隐式保证,但Vulkan供暧了五种显式同步机制:

  • Fences:fence可用于与主机通信,表明设备上某些任务的执行已完成。fence是同步gpu执行队列和渲染线程
  • Semaphores:Semaphores可用于控制跨多个queue的资源访问。sephmore可以同步队列。
  • Events:Event提供一个细粒度的synchronization primitive,可以被command buffer或者host signaled,也可以在command buffer上等待、或者host 查询。event是cmd-barrier的升级版,barrier的wait和signal在同一个地方,event的wait和signal可以在两个地方。
  • Pipeline Barriers:Pipeline Barriers提供一个command buffer内部的synchronization control,但只在一个点上,然而拆分成signal和wait操作。barrier是防止指令乱序(资源读写乱序)
  • Render Passes:Render passes基于本章的内容,为大多数渲染任务,提供一个有效的synchronization framework。许多需要应用程序使用其它同步方案的情况,都可以更加有效作为render pass的一部分。

an operation 是指要在host、device或者外部实体(比如表现引擎)上执行的一些工作。Synchronization command 引入显式的执行依赖关系,以及由命令的两个同步作用域定义的两组操作之间的内存依赖关系。

同步作用域定义了同步命令能够创建执行依赖项的其它操作。任何不在同步命令的同步作用域中的操作类型都不会包含在生成的依赖项中。例如,对于很多同步命令,同步作用域可以仅限于在特性管道阶段中执行的操作,这允许从依赖项中排除其它管道阶段。根据特定命令,还可以使用其它范围选项。

执行依赖关系,是一种保证,对于两组操作,第一组操作必须发生在第二组操作之前。如果一个操作发生在另一个操作之前,那么第一个操作必须在第二个操作启动之前完成。更准确的说:

  • A和B是两个独立的操作
  • S是一个同步命令
  • As和Bs是S的同步作用域
  • A'是A和As的交集
  • B'是B和Bs的交际
  • 将A、S、B submit for execution。按照上面的顺序,会在A'和B'之间,产生一个execution dependency E
  • Ececution dependency E使得A'在B'之前发生。

execution dependency chain是一个,在第一个依赖项A'和最后一个依赖项B'形成happens-before关系的一系列execution dependencies。对于每一个连续的execution dependencies,如果第一个依赖项中的Bs和第二个依赖项中的As的交际不是空集,则存在一个chain。一个execution dependency chain中的一个单独的extension denpendency可以通过在execution depenencies的描述中替换以下内容来描述:

  • S是一系列synchronization commands来生成一个execution dependency chain
  • As是S中第一个command 的第一个同步作用域
  • Bs是S中最后一个command 的第二个同步作用域

execution dependencies不足以保证第一组操作中写入的值可以在另一组操作中读取。

其它还有三种操作用于控制内存访问。

  • Availability操作使得由指定内存写访问生成的值,可供memory domain用于将来的访问。在对同一内存位置进行后续写入(weather it is made available or not)或者释放内存之前,任何可用值都保持可用。
  • Memory domain 操作导致源 memory domain 可写 avaliable 的,变得对目标memory domain avaiable(例如:host domain availiable的变得,对device domain也 available)。
  • Visibility操作使得memory domain avaiable的值,对特定内存访问可见。

Availiability、visibility、memory domain以及memory domain操作在之后的章节会详细说明。Availability、Visibility、Domain操作定义了执行这些操作的API。

内存依赖是一个execution dependency,包含了availability和visibiliy操作:1.第一个系列的操作 happens-before availability操作,2.availability操作 happens-before visibility操作,3.visibility操作 happens-before 第二个系列的操作。

一旦写入之对特定类型的内存访问可见,就可以通过该类型的内存访问来读取和写入它们。Vulkan中的大部分同步命令都定义了内存依赖关系。

Available和visible的特定内存访问由内存依赖项的访问范围定义。在内存依赖项的第一个访问作用域中,且发生在A'中的任何类型的访问都是Available的。在内存依赖项的第二个访问作用域中,且发生在B'中的任何类型的访问都是Visble的。任何不在同步命令访问范围内的操作类型都不会包含在结果依赖项中。

memory dependency强制两组操作的 availability和visibility的内存访问和执行顺序。添加到execution dependency chains:

  • a为A'的memory accesses
  • b为B'的memory accesses
  • as为S中第一个命令的第一个访问范围
  • bs为S中最后一个命令的第二个访问范围
  • a'为a和as的交集
  • b'为b和bs的交集
  • 将A、S、B submit for execution。按照上面的顺序,会在A'和B'之间,产生一个memory dependency m
  • Memory dependency m带来:在a'中写的内存变成available,可写的available内存,包括a'中的,会对b' visible

Execution和memory dependencies被用于解决数据危害,即确保读写操作以明确定义的顺序进行。write-after-read的危害可以通过execution dependency解决,但是read-after-write和write-after-write危害需要在它们之间包含适当的memory dependencies。如果应用程序不包含解决这些危险的依赖项,那么内存访问的结果和执行顺序是未定义的。

Image Layout Transitions

Pipeline Stages

Access Types

Vulkan中的内存,可以被shader指令以及pipeline中的部分fixed-function stage访问。access type将会被 descriptor type使用,或者用于指出 fixed-function stage 如何访问内存。

一些同步指令会将以 access type为参数来 define access scopes of a memory dependency。如果一个同步指令包含 source access mask,则它的第一个 access scope 值包含 access type指定的这些。相同的,如果一个同步指令包含 destination access mask,则它的第二个 access scope只包含 access type指定的这些。

VkMemoryBarrier2KHR、VkImageMemoryBarrier2KHR、VkBufferMemoryBarrier2KHR 中的srcAccessMask 和 dstAccessMask可以设置如下值,来规定access behavior

  	// Provided by VK_VERSION_1_3
// Flag bits for VkAccessFlagBits2
typedef VkFlags64 VkAccessFlagBits2;
static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0ULL;
//no accesses
static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 0x00000001ULL; 
//特指indirect draw或者dispatch 从 indirect buffer 读取 command data 的 read access。发生在 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT pipeline stage。
static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 0x00000002ULL;
//特指indexed draw 读取 index buffer(通过 vkCmdBindIndexBuffer 绑定) 的 read access。发生在 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT pipeline stage。
static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004ULL; 
//特指 draw 读取 vertex buffer(通过 vkCmdBindVertexBuffers 绑定) 的 read access。发生在 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT pipeline stage。
static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 0x00000008ULL;
//特指在任意 shader pipeline stage 读取 uniform bufer 的 read access。
static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 0x00000010ULL; 
//特指 render pass 的fragment shading中 读取 input attachment 的 read access。发生在 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT pipeline stage。
static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 0x00000020ULL;
//相当于 VK_ACCESS_2_UNIFORM_READ_BIT | VK_ACCESS_2_SHADER_SAMPLED_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_READ_BIT
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 0x00000040ULL;
//等同于 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ULL; 
static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 0x00000080ULL;
//特指对color attachment的read access,比如通过 blending 、logic operations或者特定的subpass load operation。发生在 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage
static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100ULL; 
//特指在renderpass 或者特定的subpass load and store operations中对color 、resolve、depth/stencil resolve attachment的write access。发生在 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage
static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200ULL;
//特指 depth/stencil operation或者特定的subpass load operation 中对depth/stencil attachment的read access。发生在 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT 或者 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT pipeline stage
static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT =  0x00000400ULL;
//特指 depth/stencil operation或者特定的subpass load and store operation 中对depth/stencil attachment的write access。发生在 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT 或者 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT pipeline stage
static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 0x00000800ULL;
//特指在 copy operation 中对 image 或者buffer 的read access。发生在 VK_PIPELINE_STAGE_2_COPY_BIT, VK_PIPELINE_STAGE_2_BLIT_BIT, or VK_PIPELINE_STAGE_2_RESOLVE_BIT pipeline stages
static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ULL; 
static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 0x00001000ULL;
//特指在 clear/copy operation 中对 image 或者buffer 的write access。发生在 VK_PIPELINE_STAGE_2_COPY_BIT, VK_PIPELINE_STAGE_2_BLIT_BIT, VK_PIPELINE_STAGE_2_CLEAR_BIT, or VK_PIPELINE_STAGE_2_RESOLVE_BIT pipeline stages
static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ULL; 
static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 0x00002000ULL;
//特指 host操作中的 read access。该类型的access并非通过resource来操作,而是直接针对memory。发生在 VK_PIPELINE_STAGE_2_HOST_BIT pipeline stage
static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 0x00004000ULL;
//特指 host操作中的 write access。该类型的access并非通过resource来操作,而是直接针对memory。发生在 VK_PIPELINE_STAGE_2_HOST_BIT pipeline stage
static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 0x00008000ULL;
//特指所有的read access。It is always valid in any access mask。相当于设置了所有的 READ access flags
static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ULL; static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 0x00010000ULL;
//特指所有的write access。It is always valid in any access mask。相当于设置了所有的 WRITE access flags
static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ULL; 
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 0x100000000ULL;
//特指在任意 shader pipeline stage 读取 uniform texel bufer 或 sampled image 的 read access。
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 0x200000000ULL; 
//特指在任意 shader pipeline stage 读取 storage buffer、physical storage buffer、storage texel buffer、storage image 的 read access。
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ULL;
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 0x400000000ULL;
//特指在任意 shader pipeline stage 写入 storage buffer、physical storage buffer、storage texel buffer、storage image 的 write access。
static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ULL; 
  

如果 application希望针对多个pipeline stage选择所有的access type,那么可以使用 VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT。This is particularly useful when specifying stages that only have a single access type.

VkAccessFlags2 可以是 0 或者 VkAccessFlagBits2 的组合。

  	// Provided by VK_VERSION_1_3
typedef VkFlags64 VkAccessFlags2;
  

VkSubpassDependency、VkMemoryBarrier、VkBufferMemoryBarrier、VkImageMemoryBarrier 中的srcAccessMask 和 dstAccessMask可以设置如下值,来规定access behavior,这些值的意义和 VkAccessFlags2中相同

  	// Provided by VK_VERSION_1_0
typedef enum VkAccessFlagBits { 
	VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, 
	//特指indirect draw或者dispatch 读取 indirect command data 的 read access。发生在 VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT pipeline stage。
	VK_ACCESS_INDEX_READ_BIT = 0x00000002, 
	//特指indexed draw 读取 index buffer(通过 vkCmdBindIndexBuffer 绑定) 的 read access。发生在 VK_PIPELINE_STAGE_VERTEX_INPUT_BIT pipeline stage。
	VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, 
	//特指 draw 读取 vertex buffer(通过 vkCmdBindVertexBuffers 绑定) 的 read access。发生在 VK_PIPELINE_STAGE_VERTEX_INPUT_BIT pipeline stage。
	VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, 
	//特指在任意 shader pipeline stage 读取 uniform bufer 的 read access。
	VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, 
	//特指 render pass 的fragment shading中 读取 input attachment 的 read access。发生在 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT pipeline stage。
	VK_ACCESS_SHADER_READ_BIT = 0x00000020, 
	//特指在任意 shader pipeline stage 读取 uniform bufer、uniform texel buffer、sampled image、storage buffer、physical storage buffer、storage texel buffer、storage image 的 read access。
	VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, 
	//特指在任意 shader pipeline stage 写入 storage buffer、physical storage buffer、storage texel buffer、storage image 的 write access。
	VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, 
	//特指对color attachment的read access,比如通过 blending 、logic operations或者特定的subpass load operation。
	VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, 
	//特指在renderpass 或者特定的subpass load and store operations中对color 、resolve、depth/stencil resolve attachment的write access。发生在 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT pipeline stage
	VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, 
	//特指 depth/stencil operation或者特定的subpass load operation 中对depth/stencil attachment的read access。发生在 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT 或者 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT pipeline stage
	VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, 
	//特指 depth/stencil operation或者特定的subpass load and store operation 中对depth/stencil attachment的write access。发生在 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT 或者 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT pipeline stage
	VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, 
	//特指在 copy operation 中对 image 或者buffer 的read access。发生在 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT pipeline stages
	VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, 
	//特指在 clear/copy operation 中对 image 或者buffer 的write access。发生在 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT pipeline stages
	VK_ACCESS_HOST_READ_BIT = 0x00002000, 
	//特指 host操作中的 read access。该类型的access并非通过resource来操作,而是直接针对memory。发生在 VK_PIPELINE_STAGE_HOST_BIT pipeline stage
	VK_ACCESS_HOST_WRITE_BIT = 0x00004000, 
	//特指 host操作中的 write access。该类型的access并非通过resource来操作,而是直接针对memory。发生在 VK_PIPELINE_STAGE_HOST_BIT pipeline stage
	VK_ACCESS_MEMORY_READ_BIT = 0x00008000, 
	//特指所有的read access。It is always valid in any access mask。相当于设置了所有的 READ access flags
	VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
	//特指所有的write access。It is always valid in any access mask。相当于设置了所有的 WRITE access flags
    // Provided by VK_VERSION_1_3
VK_ACCESS_NONE = 0, } VkAccessFlagBits;
  

某些access type只能在特定的pipeline stage使用。同步命令中如果包含stage mask和access mask,将使用它们共同来定义access scopes-只有特定的stage对应特定的access type才会被包含在access scope中。当一个access flag不匹配对应的stage mask,application则必须不能在同步命令中指定它。下表指出每个access flag对应的pipeline stage

  	VK_ACCESS_INDIRECT_COMMAND_READ_BIT
  			VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
  	VK_ACCESS_INDEX_READ_BIT
  			VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
  	VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT
  			VK_PIPELINE_STAGE_VERTEX_INPUT_BIT
  	VK_ACCESS_UNIFORM_READ_BIT
  			VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
  			VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  			VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
  	VK_ACCESS_SHADER_READ_BIT
  			VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
  			VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  			VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
  	VK_ACCESS_SHADER_WRITE_BIT
  			VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
  			VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
  			VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
  	VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
  			VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  	VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
  			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  	VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
  			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
  	VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
  			VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
  			VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
  	VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
  			VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
  			VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
  	VK_ACCESS_TRANSFER_READ_BIT
  			VK_PIPELINE_STAGE_TRANSFER_BIT
  	VK_ACCESS_TRANSFER_WRITE_BIT
  			VK_PIPELINE_STAGE_TRANSFER_BIT
  	VK_ACCESS_HOST_READ_BIT
  			VK_PIPELINE_STAGE_HOST_BIT
  	VK_ACCESS_HOST_WRITE_BIT
  			VK_PIPELINE_STAGE_HOST_BIT
  	VK_ACCESS_MEMORY_READ_BIT
  			Any
  	VK_ACCESS_MEMORY_WRITE_BIT
  			Any
  

VkAccessFlags 可以是 0 或者 VkAccessFlagBits 的组合。

  	   // Provided by VK_VERSION_1_0
typedef VkFlags VkAccessFlags;
  

If a memory object does not have the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT property, then vkFlushMappedMemoryRanges must be called in order to guarantee that writes to the memory object from the host are made available to the host domain, where they can be further made available to the device domain via a domain operation. Similarly, vkInvalidateMappedMemoryRanges must be called to guarantee that writes which are available to the host domain are made visible to host operations.

If the memory object does have the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT property flag, writes to the memory object from the host are automatically made available to the host domain. Similarly, writes made available to the host domain are automatically made visible to the host.

Queue submission commands automatically perform a domain operation from host to device for all writes performed before the command executes, so in most cases an explicit memory barrier is not needed for this case. In the few circumstances where a submit does not occur between the host write and the device read access, writes can be made available by using an explicit memory barrier.

Framebuffer Region Dependencies

View-Local Dependencies

Device-Local Dependencies

Implicit Synchronization Guarantees

VkResult vkCreateFence( VkDevice device, const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);

FFence::FFence(FVulkanDevice* InDevice, FFenceManager* InOwner, bool bCreateSignaled)

void vkDestroyFence( VkDevice device, VkFence fence, const VkAllocationCallbacks* pAllocator);

inline void FFenceManager::DestroyFence(FFence* Fence)

VkResult vkGetFenceStatus( VkDevice device, VkFence fence);

bool FFenceManager::CheckFenceState(FFence* Fence)

VkResult vkResetFences( VkDevice device, uint32_t fenceCount, const VkFence* pFences);

void FFenceManager::ResetFence(FFence* Fence)

VkResult vkWaitForFences( VkDevice device, uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);

bool FFenceManager::WaitForFence(FFence* Fence, uint64 TimeInNanoseconds)

Importing Fence Payloads

VkResult vkCreateSemaphore( VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore);

FSemaphore::FSemaphore(FVulkanDevice& InDevice) :

void vkDestroySemaphore( VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator);

VkResult vkGetSemaphoreCounterValue( VkDevice device, VkSemaphore semaphore, uint64_t* pValue);

VkResult vkWaitSemaphores( VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);

VkResult vkSignalSemaphore( VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);

Importing Semaphore Payloads

VkResult vkCreateEvent( VkDevice device, const VkEventCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkEvent* pEvent);

FGPUEvent::FGPUEvent(FVulkanDevice* InDevice)

FVulkanQueryPool::FVulkanQueryPool(FVulkanDevice* InDevice, FVulkanCommandBufferManager* CommandBufferManager, uint32 InMaxQueries, VkQueryType InQueryType, bool bInShouldAddReset)

void vkDestroyEvent( VkDevice device, VkEvent event, const VkAllocationCallbacks* pAllocator);

FVulkanQueryPool::~FVulkanQueryPool()

VkResult vkGetEventStatus( VkDevice device, VkEvent event);

bool FVulkanOcclusionQueryPool::InternalTryGetResults(bool bWait)

VkResult vkSetEvent( VkDevice device, VkEvent event);

VkResult vkResetEvent( VkDevice device, VkEvent event);

void FVulkanOcclusionQueryPool::Reset(FVulkanCmdBuffer* InCmdBuffer, uint32 InFrameNumber)

void vkCmdSetEvent( VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);

void FVulkanOcclusionQueryPool::Reset(FVulkanCmdBuffer* InCmdBuffer, uint32 InFrameNumber)

void vkCmdResetEvent( VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask);

void vkCmdWaitEvents( VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent* pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);

void vkCmdPipelineBarrier( VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier* pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier* pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier* pImageMemoryBarriers);

void FVulkanCommandListContext::RHIBeginTransitions(TArrayView<.const FRHITransition*> Transitions)

void FVulkanPipelineBarrier::Execute(VkCommandBuffer CmdBuffer)

void FVulkanCmdBuffer::BeginUniformUpdateBarrier()

void FVulkanCmdBuffer::EndUniformUpdateBarrier()

void* FVulkanResourceMultiBuffer::Lock(bool bFromRenderingThread, EResourceLockMode LockMode, uint32 Size, uint32 Offset)

void FVulkanOcclusionQueryPool::Reset(FVulkanCmdBuffer* InCmdBuffer, uint32 InFrameNumber)

void FVulkanDynamicRHI::RHIReadSurfaceData(FRHITexture* TextureRHI, FIntRect Rect, TArray<.FColor>& OutData, FReadSurfaceDataFlags InFlags)

void FVulkanDynamicRHI::RHIReadSurfaceFloatData(FRHITexture* TextureRHI, FIntRect Rect, TArray<.FFloat16Color>& OutData, ECubeFace CubeFace,int32 ArrayIndex,int32 MipIndex)

void FVulkanDynamicRHI::RHIRead3DSurfaceFloatData(FRHITexture* TextureRHI,FIntRect InRect,FIntPoint ZMinMax,TArray<.FFloat16Color>& OutData)

inline void HeavyWeightBarrier(VkCommandBuffer CmdBuffer)

void FVulkanCommandListContext::RHICopyBufferRegion(FRHIVertexBuffer* DstBuffer, uint64 DstOffset, FRHIVertexBuffer* SrcBuffer, uint64 SrcOffset, uint64 NumBytes)

Subpass Self-dependency

Memory Barriers

Queue Family Ownership Transfer

VkResult vkQueueWaitIdle( VkQueue queue);

VkResult vkDeviceWaitIdle( VkDevice device);

void FVulkanDevice::WaitUntilIdle()

Host Write Ordering Guarantees

Synchronization and Multiple Physical Devices

本节教程就到此结束,希望大家继续阅读我之后的教程。

谢谢大家,再见!


原创技术文章,撰写不易,转载请注明出处:电子设备中的画家|王烁 于 2021 年 5 月 10 日发表,原文链接(http://geekfaner.com/shineengine/blog17_Vulkanv1.2_3.html)