Vulkan® A Specification::Chapter 6::Synchronization and Cache Control(同步与缓存控制)

原文链接:https://vulkan.lunarg.com/doc/view/1.2.131.2/windows/chunked_spec/chap6.html#synchronization

更新记录:

2020/4/3:: 6同步与缓存控制,6.1运行和内存依赖 ,6.1.1图片布局转换

2020/4/4::6.1.2管线阶段

2020/4/5::6.1.3访问类型

2020/4/8::修复了表格内数据看不见的情况,增加了6.1.4帧缓存区域依赖

6.同步与缓存控制


同步访问数据是Vulkan应用的基本能力,在主机端(host)调用指令的顺序和那些在设备端(device)调用的指令之间没有隐含的同步保证(假如说host端和device端有一块两方共享的内存,访问该内存时需要同步操作),这需要开发人员显示的做出同步保证。内存缓存和其他优化也需要显示的管理,也就是说应用底层下那些庞大的数据流动完全需要开发人员主动的显示管理。

在Vulkan中有一些隐示同步保证位于Vulkan命令(Commands)之间,在Vulkan中有5种显示同步机制原语:

Fence(栏栅)

       用于同步主机端和设备端。当设备端的某些任务完成时,可以通过Fence获得该完成状态。

Semaphores(旗语,信号量)

       用于多个设备队列(queue)之间的资源访问同步

Events(事件)

       事件提供了一个细粒度的同步,可通过主机端或者Vulkan命令缓存(command buffer)中的命令(command)激活该事件。其可在命令缓存内等待。主机端可以主动获取Events的状态。

Pipeline Barriers(管线障)

       管线障同Events一样,同样提供命令缓存(command buffer)内部同步控制,和Events的不同的是Pipeline Barriers只能同步一个特定点,而不能像Events那样既可以被唤醒也可以等待。

Render Passes(渲染通路)

       Render Passes对于渲染任务提供了一个非常有用的同步框架。其可以有效地实现某些其他同步原语相同的功能。

 

6.1运行和内存依赖


在本机,外设甚至是显示器,在他们内部执行一项操作(operation),操作内部都是由很多小指令组成。同步指令通过指定同步范围(synchronization scopes),在两个操作集之间提供了显示的执行依赖(execution dependencies)和内存依赖(memory dependencies)。

       当同步范围内执行同步命令时可以保证执行间的依赖。任何其他不在同步范围内的操作不会进行执行之间的依赖。例如对于很多同步指令,同步范围可以精确到特定的渲染管线阶段(pipeline stags),这将会将其他管线阶段排除在同步范围之外。

       对于不同的同步指令,同步范围不尽相同。

       一个执行依赖,一般是指两个不同的操作集的运行顺序,第一个操作集必须在第二个操作集开始执行前执行结束。

       仅仅使用执行依赖不足以保证从一个操作集产生的数据在另一个操作集中有效。

       三种额外的操作类型用于控制内存访问。可用性操作(Availability Operations)使得特定内存写入所产生的数据可用,可在将来访问。如果任何已经可用的数据再次发生往该可用数据所在的内存中写入数据时,或者将这一部分清空,都将会导致该内存下的数据不可用。内存域操作(Memory Domain Operation)使得对于源内存域的写入在目标内存域可用,例如本机(host)和设备(device)公享同一块内存,在本机端对其写入,对于设备端是可用的,反之亦然。可见性操作(Visibility Operations)使得对于一块可用内存对于访问操作可见。

       一个内存依赖是一个包含可用性操作和可见性操作的执行依赖。运行顺序如下:

  1. 第一个操作集完成后执行可用性操作。
  2. 可用性操作完成后执行可见性操作。
  3. 可见性操作完成后执行第二个操作集。

一旦写完数据对于特定的内存访问类型完成了可见性操作,就可以通过该类型的内存访问类型完成读写。Vulkan中大多数的同步指令都定义了内存依赖。

       内存依赖的可用性和可见性是通过定义访问域(access scopes)来设置的。访问域一般是成对出现的。第一个访问域控制内存的可用性,第二个访问域控制内存的可见性。

 

注意:

       执行依赖和内存依赖是用于解决“数据危害”的。即、确保读取和写入的顺序以明确的顺序进行。写后读(write-after-read)可以使用执行依赖解决,但是读后写(read-after-write)和写后写(write-after-write)需要合适的内存依赖在他们之间。如果一个应用不解决“数据危机”的话,对于数据操作的结果是未定义的。读后读(read-after-read)并不修改数据,并不需要同步操作。

       写后读(write-after-read):未同步情况下,两个操作集,一个读,一个写,当对一块内存进行写操作时,这时同时进行读操作,读取的结果很大程度上可能是未定义的数据结果。

读后写(read-after-write):未同步情况下,两个操作集,一个读,一个写,当对一块内存进行读操作时,这时同时进行写操作,写入的结果很大程度上可能是未定义的数据结果。

写后写(write-after-write) :未同步情况下,两个操作集,都是写,当对一块内存进行写操作时,这时同时进行写操作,写入的结果很大程度上可能是未定义的数据结果。

 

 

6.1.1 图片布局(Image Layout)转换


图片子资源(Image Subresources)可以从一种布局转换成另一种布局作为内存依赖的一部分(例如通过显示的使用图片障(VkImageMemoryBarrier)或者隐示的使用渲染通路(Render Passes))。布局转换是发生在可用性操作之后,可见性操作之前。图片布局转换可能会在整个图片子资源所在的内存上进行读写操作,所以应用必须确保在格式转换发生前所有要写的内存已经可用。可用的内存自动的就对图片转换操作可用,图片转换写入的内存自动可用。

       布局转换总是发生在图片的某项子资源上,转换时需要指定旧布局(当前布局)和新布局。如果旧布局不支持新布局,进行转换。旧布局必须匹配当前图片子资源的布局,有一个例外就是:旧布局可以总是置成VK_IMAGE_LAYOUT_UNDEFINED,尽管这样做的话将会使得图片的子资源的内容无效化。

       由于图片布局转化可能需要对内存进行读写访问,如果布局转换影响力图片子资源的内存的话,如果当前转换的图片子资源的内存是平等内存(Peer Memory)的话,给该图片子资源分配内存的堆(heap)必须支持VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT和VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT 能力。

注:平等内存该段,本人未曾见过这种情况,不太清楚具体是什么意思,只是翻译出来,待好心人指点。通过查阅Vulkan文档目前所知平等内存好像是在GPU组中使用,假如说一台电脑上插上了三块显卡,通过某种技术可将三块显卡合成一块逻辑显卡,每块显卡上的内存是平等共享的。平等内存可能说的是这个东西。不知是否正确,待好心人指正。

注意:

       如果旧布局置成VK_IMAGE_LAYOUT_UNDEFINED,这样做的话将会使得图片的子资源的内容无效化。使用该功能可以避免昂贵的布局转换操作。

       应用必须确保所有对于旧布局的图片访问操作完成,之后对于图片布局的转换,需要在所有对新布局操作之前。图片布局转换内部隐示的读写内存,所以不定义内存依赖将会导致数据竞争(data race)。

       图片布局转换和内存混叠(memory aliasing)交互进行。

 

说明:

图片子资源:图片是由一个个颜色块组成,每个颜色块都对应着颜色的数据。实际上该数据可以是任何数。如果记录着颜色,那么图片的其中一项子资源对应着颜色资源,如果记录着深度,那么图片的其中一项子资源对应着深度信息。但是深度信息也可以解释成颜色信息。可以理解成不同的子资源对于图片中所记录的数据解释不同。

内存混叠:根据Vulkan文档描述,内存混叠是指两个资源在底层存储的内存通过对齐存在交集。不知是否正确,待好心人指正。

对齐:请百度内存对齐。该功能正常是由编译器负责,除非开发底层要不然基本没接触过。

 

6.1.2 管线阶段


调用一个同步指令,其内部由很多小操作组成。这些小操作按照逻辑顺序一步步的执行,这些逻辑顺序Vulkan中称之为管线阶段(Pipeline Stage)。不同的同步指令中同步的管线阶段也不尽相同,并且和当前命令缓存(Command Buffer)中记录的指令(Command)相关。例如绘制指令、分配指令、复制指令、清空指令和同步指令,这些指令中指定的管线阶段都不尽相同。事实上同步指令并不会在指定的管线阶段上执行,但是同步指令会在VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT和VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT这两个阶段执行。

 

注意:

同步指令并不会在指定的管线阶段上执行,但是其他命令仍可以通过VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT和VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT这两个阶段与其(其他同步指令)同步。

 

 

执行通过管线必须遵守隐示顺序,特别是管道阶段的顺序。如果没有顺序保障,执行将是混乱的。

某些同步指令在运行之前需要指定要同步的管线阶段参数,限制该指令的同步范围。这将会带来非常良好的粒度(grained)控制。通过制定管线阶段来避免不必要的停顿和缓存刷新。

管线阶段如下所示:

typedef enum VkPipelineStageFlagBits {

    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001,

    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002,

    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004,

    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008,

    VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010,

    VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020,

    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040,

    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080,

    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100,

    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200,

    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400,

    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800,

    VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000,

    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000,

    VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,

    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,

    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,

    VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000,

    VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000,

    VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,

    VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000,

    VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000,

    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000,

    VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,

    VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,

    VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000,

    VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF

} VkPipelineStageFlagBits;

 

  • VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT::开始阶段
  • VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT::绘制/间接绘制阶段
  • VK_PIPELINE_STAGE_VERTEX_INPUT_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_EARLY_FRAGMENT_TESTS_BIT::片元早期测试阶段(深度和模板测试早于片元着色器阶段),该阶段也包括向帧缓存中存储深度和模板数据的阶段。
  • VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT::片元后期测试阶段(深度和模板测试晚于片元着色器阶段),该阶段也包括向帧缓存中存储深度、模板和颜色数据的阶段。
  • VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT::颜色输出阶段
  • VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT::计算着色器阶段
  • VK_PIPELINE_STAGE_TRANSFER_BIT::移动阶段,其包括所有的复制、清除(除了 vkCmdClearAttachments)和vkCmdCopyQueryPoolResults指令
  • VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT::结束阶段
  • VK_PIPELINE_STAGE_HOST_BIT::本地阶段
  • VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT::所有图形阶段,包括(逻辑或):

               VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

               VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT

               VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV

               VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV

               VK_PIPELINE_STAGE_VERTEX_INPUT_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_EARLY_FRAGMENT_TESTS_BIT

               VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT

               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

               VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

               VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT

               VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT

               VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV

               VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT

  • VK_PIPELINE_STAGE_ALL_COMMANDS_BIT::所有指令阶段,表示当前使用队列支持的所有管线阶段(逻辑或)
  • VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT::移动反馈扩展阶段
  • VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT::条件渲染扩展阶段
  • VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX::NVIDIA指令处理阶段
  • VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV::NVIDIA图片着色域阶段
  • VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV::NVIDIA光线追踪着色器阶段
  • VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV::NVIDIA加速阶段
  • VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV ::NVIDIA任务着色器阶段
  • VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV ::NVIDIA网格着色器阶段,
  • VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT::片元密度图读取扩展阶段

片元密度不太清楚具体是个啥,先码上,待查阅资料或好心人指点。目前看片元密度好像是个扩展功能。

注意:

当执行依赖在目标阶段掩码(destination stage mask)为

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT时Vulkan仅仅是跳过该阶段的运行,就好像该阶段没有做任何执行似的,这一情况很难观察到。事实上该阶段并不会延迟之后指令的运行。VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT也是如此,其并不会等待之前的指令完成。(这段好像在说VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT和

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT这两个阶段是逻辑上构造的两个虚构阶段,也许可以方便代码的结构组织和理解)。

当定义了一个内存依赖时,当只是使用VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT和

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT时将不会导致任何的可用性和可见性,因为这两个阶段不会访问任何内存。

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT和 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT这两个阶段在要求执行依赖进行布局转换(layout transition)和队列所有权(queue ownership)操作时是非常有用的。例如在队列之间使用旗语(semaphore)。

 

如果一个同步指令包括源管线阶段掩码(source stage mask)参数的话,那么在源管线阶段掩码参数中指定的管线阶段将会是第一个同步范围,该同步范围用于访问内存。如果一个同步指令包括目标管线阶段掩码(destination stage mask)参数的话,那么在目标管线阶段掩码参数中指定的管线阶段将会是第二个同步范围,该同步范围用于访问内存。

 

注意:

在源管线阶段掩码参数中包括的每一个管线阶段之前,在逻辑上存在一个早期管线阶段,相似的,目的管线阶段掩码参数中的每一个管辖阶段之前,在逻辑上也存在一个早期管线阶段。但是早期的逻辑管线阶段并不会影响访问的范围。

 

某些管线阶段只有特定的队列支持该阶段,也就是说,不同的队列类型对于管线阶段的支持不尽相同。下面指出队列与管线阶段的对应关系:

支持的管线阶段标志位

管线阶段标志位

支持的队列类型

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

无特定要求

VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT

VK_QUEUE_GRAPHICS_BIT

或VK_QUEUE_COMPUTE_BIT

VK_PIPELINE_STAGE_VERTEX_INPUT_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_VERTEX_SHADER_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT

VK_QUEUE_COMPUTE_BIT

VK_PIPELINE_STAGE_TRANSFER_BIT

VK_QUEUE_GRAPHICS_BIT或VK_QUEUE_COMPUTE_BIT 或VK_QUEUE_TRANSFER_BIT

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

无特定要求

VK_PIPELINE_STAGE_HOST_BIT

无特定要求

VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_ALL_COMMANDS_BIT

无特定要求

VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT

VK_QUEUE_GRAPHICS_BIT 或 VK_QUEUE_COMPUTE_BIT

VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX

VK_QUEUE_GRAPHICS_BIT 或 VK_QUEUE_COMPUTE_BIT

VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV

VK_QUEUE_GRAPHICS_BIT

VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV

VK_QUEUE_COMPUTE_BIT

VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV

VK_QUEUE_COMPUTE_BIT

VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT

VK_QUEUE_GRAPHICS_BIT

 

各个管线阶段运行是按照一定顺序进行的,逻辑上较早的阶段不可能运行在逻辑上较晚的阶段之后,同理逻辑上较晚阶段不可能运行在逻辑上较早的阶段之前。

 

注意:

Vulkan同步操作可能不能支持所有的管线阶段,如果源管线阶段中有不支持的阶段,可以使用任何逻辑上支持的较晚的阶段代替,同理如果目的管线阶段有不支持的阶段,可以使用任何逻辑上支持的较早的阶段代替。例如,如果无法在顶点着色器阶段结束时立马唤醒事件(events)的话,之后也许将会在颜色输出阶段唤醒事件。

如果做出了这样的替换,替换一定不能影响到执行和内存依赖,或者管线障。

 

各个管线阶段的执行顺序是按照当前命令所用到的管线类型而定,描述如下:

对于基于图形图元管线(就是最常见的光栅化那一套),其运行顺序如下:

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT

VK_PIPELINE_STAGE_VERTEX_INPUT_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_TRANSFORM_FEEDBACK_BIT_EXT

VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV

VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT

VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT

VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT

VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

 

基于图形网格(graphics mesh shading)的管线,其顺序如下:

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT

VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV

VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV

VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV

VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT

VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT

VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT

VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

 

对于片元密度图(fragment density map)附件(attachment),如果存在该附件,对于该附件的读取是没有固定的阶段顺序的,但是可以确定对于其的读取会发生在VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT阶段之前。

VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT

 

对于计算管线,执行顺序如下:

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT

VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

 

条件渲染阶段在图形管线和计算管线中都存在,对于该阶段没有固定的执行顺序:

VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT

 

对于转移管线(transfer pipeline),其执行顺序如下:

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

VK_PIPELINE_STAGE_TRANSFER_BIT

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

 

对于本地(host)操作,只会有一个阶段触发:

VK_PIPELINE_STAGE_HOST_BIT

 

对于命令处理管线(command processing pipeline),其执行顺序如下:

VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT

VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX

VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT

 

对于光线追踪管线(ray tracing shader pipeline),只会有一个阶段相应:

VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV

 

对于光线追踪加速结构体操作,只会有一个阶段相应:

VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV

 

6.1.3 访问类型(Access Type)


Vulkan中对于内存访问可以通过着色器和一些固定的管线阶段。访问类型(access type)是描述符(descripter type)和固定管线阶段用于如何访问内存的定义。每一个访问类型都由VkAccessFlagBits其中一个位标志(bit flag)定义。

某些同步指令任务需要指定访问类型参数,定义内存依赖的访问范围,如果一个同步指令含有一个源访问掩码(source access mask),那么源访问掩码中含有的访问类型将会是第一个访问范围,如果一个同步指令含有目标访问掩码(destination access mask),那么目标访问掩码中包含的访问类型将会是第二个访问范围。

各个访问类型定义如下:

typedef enum VkAccessFlagBits {

    VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001,

    VK_ACCESS_INDEX_READ_BIT = 0x00000002,

    VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004,

    VK_ACCESS_UNIFORM_READ_BIT = 0x00000008,

    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010,

    VK_ACCESS_SHADER_READ_BIT = 0x00000020,

    VK_ACCESS_SHADER_WRITE_BIT = 0x00000040,

    VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080,

    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100,

    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200,

    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400,

    VK_ACCESS_TRANSFER_READ_BIT = 0x00000800,

    VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000,

    VK_ACCESS_HOST_READ_BIT = 0x00002000,

    VK_ACCESS_HOST_WRITE_BIT = 0x00004000,

    VK_ACCESS_MEMORY_READ_BIT = 0x00008000,

    VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,

    VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,

    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,

    VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,

    VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000,

    VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,

    VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,

    VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT=0x00080000,

    VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,

    VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000,

    VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000,

    VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000,

    VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF

} VkAccessFlagBits;

  • VK_ACCESS_INDIRECT_COMMAND_READ_BIT::读取间接命令数据,作为间接命令和调度命令的一部分。
  • VK_ACCESS_INDEX_READ_BIT::读取索引缓存,作为索引绘制命令的一部分。
  • VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT::读取顶点缓存,作为绘制指令的一部分。
  • VK_ACCESS_UNIFORM_READ_BIT:: 读取uniform缓存
  • VK_ACCESS_INPUT_ATTACHMENT_READ_BIT::读取输入附件(input attachment),在渲染通路(render pass)运行片元着色器时
  • VK_ACCESS_SHADER_READ_BIT::读取存储缓存(storage buffer),物理存储缓存(physical stirage buffer),纹素/纹理缓存(uniform texel buffer),纹素/纹理存储缓存(storage texel buffer),采样图片(sampled image)或者存储图片( storage image)。
  • VK_ACCESS_SHADER_WRITE_BIT::写入存储缓存 (storage buffer),物理存储缓存(physical storage buffer), 纹素/纹理存储缓存(storage texel buffer)或存储图片(storage image)。
  • VK_ACCESS_COLOR_ATTACHMENT_READ_BIT::读取颜色附件(color attachment),例如通过混合(blending),逻辑操作(logic operation),或者通过当前子通路(subpass)的装载操作(load operation),他不包括高级混合操作(advance blending operation)。
  • VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT::写入颜色附件(color attachment),采样附件(resolve attachment)或者深度/模板采样附件(depth/stencil resolve attachment)。在渲染通路(reander pass)运行的时候或者当前子通路加载和存储操作(subpass load and store operation)时
  • VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT::读取深度/模板附件(depth/stencil attachment),通过深度/模板操作或者当前子通路加载和存储操作(subpass load and store operation)。
  • VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT::写入深度/模板附件(depth/stencil attachment),通过深度/模板操作或者当前子通路加载和存储操作(subpass load and store operation)。
  • VK_ACCESS_TRANSFER_READ_BIT::读取图片(image)或者缓存(buffer)通过复制操作
  • VK_ACCESS_TRANSFER_WRITE_BIT::写入图片(image)或者缓存(buffer)通过清空或者复制操作
  • VK_ACCESS_HOST_READ_BIT::本地的读操作,不是在资源(例如图片和缓存)上读,而是直接读内存。
  • VK_ACCESS_HOST_WRITE_BIT::本地的写操作,不是在资源(例如图片和缓存)上写,而是直接写内存。
  • VK_ACCESS_MEMORY_READ_BIT::所有读,相当于包括所有的读取
  • VK_ACCESS_MEMORY_WRITE_BIT::所有写,相当于包括所有的写入
  • VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT::写入转移回馈缓存(tranform feedback buffer)当转移回馈激活时。
  • VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT::读取转移回馈计数缓存(tranform feedback counter buffer)当vkCmdBeginTransformFeedbackEXT运行时。
  • VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT::写入转移回馈计数缓存(tranform feedback counter buffer)当vkCmdBeginTransformFeedbackEXT运行时。
  • VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT::读取谓词(predicate),作为条件渲染的一部分
  • VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX::从VkBuffer中读取,输入到vkCmdProcessCommandsNVX中。
  • VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX::在vkCmdProcessCommandsNVX.中写入目标命令缓存(command buffer)
  • VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT::类似于VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,但是包括高级混合操作。
  • VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV::NVIDIA读取着色率图片(shading rate image),作为绘制命令的一部分,通过vkCmdBindShadingRateImageNV绑定。
  • VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV::NVIDIA读取加速结构(acceleration structure)作为追踪(trace)和建立(build)命令的一部分。
  • VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVNVIDIA写入加速结构(acceleration structure)作为建立(build)命令的一部分。
  • VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT::读取片元密度图附件(fragment density map attachment),在动态片元密度图操作时。

 

某些访问类型是有特定的某些管线阶段去执行的,同步命令的访问范围是由两个访问范围(access scope)参数指定的,如果应用实现不应该在同步命令中添加管线阶段所不支持的访问类型。

下表表示对于特定的访问类型所支持的管线阶段。

following table lists, for each access flag, which pipeline stages can perform that type of access.

 

访问类型

支持的管线状态

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_TASK_SHADER_BIT_NV, 

VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,

VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,

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_TASK_SHADER_BIT_NV, 

VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,

VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,

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_TASK_SHADER_BIT_NV, 

VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,

VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,

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

任何

VK_ACCESS_MEMORY_WRITE_BIT

任何

VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT

VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX

VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX

VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX

VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX

VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT

VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT

VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV

VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV

VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT

VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT

VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT

VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT

VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT

VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT

VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV

VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,

VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV

VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV

VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV

VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT

VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT

如果内存对象没有VK_MEMORY_PROPERTY_HOST_COHERENT_BIT属性(创建时指定)时,当本地端写入当前内存对象时必须主动调用vkFlushMappedMemoryRanges使得本地端可用,之后设备端就可以通过设备端操作得到可用的内存对象(中的数据)。相应的在写入前应当放弃当前旧的无效的数据调用 vkInvalidateMappedMemoryRanges来放弃当前内存对象中的旧的无效的数据。

如果内存对象中有VK_MEMORY_PROPERTY_HOST_COHERENT_BIT属性(创建时指定)时,不需要主动调用任何函数,Vulkan自动同步数据。

 

注意::

vkQueueSubmit在真正运行之前,该函数自动进行本地端和设备端的端(域)的所有写操作,所以此时并不需要显示的使用内存障(memory barriers)。在本地端的写入并且在设备端的读取,基本上都会发生提交(submit)操作,此时可以使用内存障(memory barriers)来使得有效写入。

 

6.1.4 帧缓存区域依赖(Framebuffer Region Dependencies)


       管线阶段中有一部分用于操作帧缓存的阶段,这些阶段叫做帧缓存管线阶段(framebuffer-space pipeline stages)。包括:

  1. VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
  2. VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
  3. VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT
  4. VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT

 

帧缓存区域依赖有两个:

  1. 本地帧缓存(区域)依赖(framebuffer-local dependency)
  2. 全局帧缓存(区域)依赖(framebuffer-global dependency)

 

帧缓存区是由一系列“点”(sample)组成(该点可理解为像素点),使用(x,y,layer,sample)来定义帧缓存上的一个点。

 

 

如图所示,图中framebuffer0、framebuffer1、...都是一个帧缓存,图中每一个帧缓存有两个层(layer0,layer1),帧缓存的层最简单的也是最常见的是一个层,但是如果有别的需求可以有多个层,图中为举例说明画了两个层。之后图中橘黄色框出来的网状处是帧缓存的某个“点”,注意该点是由16个子点组成(不一定是16个点,可以是其他个数,比如1,2,4,8等,为举例说明画出16个点),这16个点就是采样点,就是(x,y,layer,sample)中的sample。Vulkan最后会将这16个点采样成一个点,这就是常说的多采样、抗锯齿。

       注意::该图只是示意性的,真正的帧缓存中的数据是由Vulkan资源实例,图片(VkImage)或缓存(VkBuffer)绑定到某个帧缓存中来确定,也就是说一个帧缓存中有多少数据,有多少layer,有几个采样点是由绑定的那个资源实例所确定的。

 

       一个帧缓存区域是由一组点(x,y,layer,sampler)组成(上图中的一组橘黄色框)。如果同步的帧缓存区域包括了整个帧缓存那么就是全局帧缓存(区域)依赖,如果只是包含了一部分则是本地帧缓存(区域)依赖。如果当前管线阶段不是帧缓存管线阶段的话,那该依赖既不是全局帧缓存(区域)依赖也不是本地帧缓存(区域)依赖。

       对于源同步范围和目标同步范围,两个同步范围必须指定为同一个帧缓存区域,否则不保证不同帧缓存区域间的依赖。

       如果源同步范围操作某一个帧缓存区域中的采样点为N个,如果目标同步范围同步的采样点为M个,当N不等于M时按照N来确定,换句话说,其为像素粒度依赖。如果相等就按照采样点数进行,换句话说,其为采样点粒度依赖。

 

       注意::

事实上像素粒度依赖和采样点粒度依赖意味着,如果一个输入附件(input attachment)中的采样点个数和管线中的resterizationSamples参数指定的采样点个数不相同的话,之后就算片元(fragment)使用的是本地帧缓存(区域)依赖也可以访问输入附件中的任意一个像素。如果输入附件中的采样点数和管线中相同的话,片元只能访问输入的SampleMask所涉及的采样点(例如片元操作在帧缓存(区域)依赖操作完所有涉及的点之后进行)。

 

如果同步命令中包括dependencyFlags参数的话,如果指定了

VK_DEPENDENCY_BY_REGION_BIT标志位的话,说明对于帧缓存管线阶段中的帧缓存定义了一个本地帧缓存(区域)依赖。如果没有指定任何标志位,或者没有指定

VK_DEPENDENCY_BY_REGION_BIT标志位的话,说明定义了一个全局帧缓存(区域)依赖。

VK_DEPENDENCY_BY_REGION_BIT对于那些非帧缓存管线阶段的管线阶段不起作用。

 

       注意::

地帧缓存(区域)依赖对于大多数硬件架构是最佳选择,特别是基于瓦片(块)的硬件架构,这些架构可以在一个瓦片中存储一块完整的帧缓存区域而不需要额外的存储区域进行存储。而使用全局帧缓存(区域)依赖将会强制所有实现刷新内存或者高级别缓存,这将破坏任何潜在的优化。

 

未完待续,接下来是本地视图依赖(view-local dependencies)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值