Vulkan® A Specification::Chapter 2::Fundamentals(基本概念)

本文详细介绍了Vulkan图形API的基本概念,包括其架构、执行模式、队列操作、对象模型、数值表达和计算等内容。Vulkan要求本地运行时支持多种数据类型,并确保本地与设备类型表示一致。文章还探讨了不同类型的队列及其功能,以及Vulkan中对象的生命周期管理和错误处理。

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

更新记录:

2020/4/8:: 2基本概念 2.1 本地和设备环境 2.2 执行模式

2020/4/9 修改了2.2[注意]段中一些语句错误

2020/4/9 增加 2.3对象模型,在翻译完2.3后发现2.2.1队列操作忘翻译了,有时间补上。

2020/4/10 增加 2.4应用程序二进制接口 2.5命令/指令(函数)语法和持续时间。2.2.1队列操作忘翻译了,有时间补上。

2020/4/12 补上2.2.1队列操作,2.3.1对象的生命周期忘记翻译了,有时间补上。

2020/4/12 补上2.3.1对象的生命周期, 补上2.3.2外部对象句柄,增加2.5.1检索结果生命周期

2020/4/13 增加2.6线程行为

2020/4/14 增加 2.7 错误,增加2.7.1有效/合法用法 ,增加2.7.2隐示有效/合法用法 ,增加2.7.2.1对象句柄的有效性 ,增加2.7.2.2 指针的有效性 ,增加2.7.2.3字符串的有效性 ,增加2.7.2.4枚举的有效性 ,增加2.7.2.5标志的有效性 ,增加2.7.2.6 结构体类型的有效性

2020/4/15 增加 2.7.2.7结构链的有效性,增加 2.7.2.8 嵌套结构的有效性,增加 2.7.2.9 扩展有效性,增加 2.7.2.10 Vulkan版本的有效性

2020/4/16 增加 2.7.3 返回码,2.8 数值表达和计算,2.8.1 浮点数计算

2020/4/17 增加 2.8.2 浮点格式转换、增加2.8.3 16位浮点数、增加 2.8.4 无符号11位浮点数、增加 2.8.5 无符号10位浮点数、增加2.8.6 一般要求、增加 2.9定点数转换、增加2.9.1将归一化定点小数转换成浮点数、增加2.9.2浮点数转成归一化定点小数、增加2.10常见对象类型、增加2.10.1 偏移、增加2.10.2 大小、增加2.10.3 区域

╭(●`∀´●)╯╰(●’◡’●)╮ (●’◡’●)ノ ヾ(*´▽‘*)ノ

至此Vulkan官方文档第二章翻译完成,请大家如果发现问题及时留言。

╭(●`∀´●)╯╰(●’◡’●)╮ (●’◡’●)ノ ヾ(*´▽‘*)ノ

2基本概念


这一章介绍Vulkan的架构、执行模式(execution model)、API、队列(queue)、管线(pipeline)、数值表示,状态和状态查询和不同类型的对象和着色器(shader)的基本概念。

 

2.1本地(host)和设备(device)环境


说明::

Vulkan中的本地(host)一般是指:原生支持Vulkan的设备(特别是显卡)以外的设备(例如一台主机)。

Vulkan中的设备(device)一般是指: 原生支持Vulkan的设备(特别是显卡)

 

Vulkan要求如下环境:

  1. 本地运行时(runtime)必须支持8,16,32和64位有符号和无符号二进制补码整数,可按照字节寻址。
  2. 本地运行时必须支持32和64位浮点类型
  3. 本地上的类型的表示(representation)和字节序(endianness)与设备上的必须匹配。

注意::

在Vulkan中很多不同的数据和结构类型在本地端和设备端都可以访问。应用需要在两端有效地访问数据以达到高效率可移植的应用。

 

2.2执行模式(execution model)


该小节介绍Vulkan系统的执行模式轮廓。

一开始Vulkan会暴露给用户一个或者多个设备(具体看电脑硬件配置),每一个设备内部会存在一个或多个异步工作的队列暴露给用户。Vulkan会将这些队列分组/簇(families)。每一个组内部会由一个或多个队列组成,队列是用来处理命令(command)的,如果某些队列被分到了同一个组中的话,说明这些队列被认为互相兼容,具有相似的特征。并且特定组中的队列可以运行特定的命令(command),并不是任意的命令任意的队列都可以处理的。Vulkan中将队列组按功能大致分成了四类:图形类(graphics)、计算类(compute)、转移类(transfer)、稀疏内存管理类( management)。

  1. 图形类主要是进行图形绘制类型的工作
  2. 转移类主要是进行数据复制,清空,等类型的工作。
  3. 稀疏内存管理类::这个不是很清楚。待查阅资料或待好心人指点。

 

注意::

       虽然有四种类型的队列组,但是请注意,并不是说图形类的就只进行图形类操作,其也可以进行计算类和转移类的操作。具体要看具体设备配置,Vulkan中的队列组中的队列会支持一个或多个类型的功能。还要注意的一点就是Vulkan中不同的队列组之间不能直接互相兼容,就算类型功能存在交集。如下图。

 

 

       Vulkan中对于设备的内存(显存和内存)是交由应用负责管理的,这就需要开发人员小心的管理内存(显存和内存)。每一个设备会暴露一个或者多个堆(heap),代表着不同区域的内存区域。堆无非两类:设备域(device local)内存,本地域(host local)内存。(本人认为应该细分为四类:设备域内存、本地域内存、本地可访问(host visible)内存、设备可访问(device visible)内存)

  1. 设备域内存堆::指的是只有设备能访问的设备内存堆
  2. 本地域内存堆::指的是只有本地能访问的本地内存堆
  3. 本地可访问::本地可访问是相对于设备域内存堆。指的是该设备内存堆在本地端可访问
  4. 设备可访问::设备可访问是相对于本地域内存堆。指的是该本地内存堆在设备端可访问。

官方文档将内存分成如下:

  1. 设备域内存堆::指的是只有设备能访问的设备内存。
  2. 设备域内存堆,本地域可访问::指的是该设备内存堆,在本地端可访问。
  3. 本地域内存堆,本地域可访问::指的是本地域的的内存堆,本地端和设备端都可以访问的内存。

在某些架构中,可能仅仅只有一个堆,该堆是本地端和设备端共享(常见于嵌入式系统,比如手机)。

       Vulkan控制设备通过将命令缓存(command Buffer)推送到特定队列中进行运行。命令缓存内部记录着命令(比如绘制命令)。命令缓存和命令对于开发人员是不透明的,需要手动创建命令缓存并且手动塞入命令之后手动推送到队列。一旦构建了一个完整的命令缓存就可以向队列推送多次。多个命令缓存可以在多线程中同时建并工作。

       命令缓存推送到不同的队列可能会异步的执行各个命令缓存中的命令,这可能会导致执行命令顺序的混乱。命令缓存推送到同一个队列需要遵守推送顺序,具体可参考同步章节。队列执行命令相对于本地是异步执行。一旦命令缓存推送到了队列中,控制权会立刻返回(不会等待命令缓存中的命令都执行完之后返回)。应用需要负责本地端和设备端的同步。

 

2.2.1 队列操作


Vulkan中的队列为设备的运行引擎提供了个访问接口。在特定的命令(command)推送到队列中去运行前是记录在命令缓存(command buffer)中,命令缓存是通过推送(queue submission)将一打命令缓存推送到队列中进行运行。之后对于命令的运行默认不再受到本地端的控制,想要控制命令的运行和同步,请参考同步章节。

推送试用vkQueue*函数(比如vkQueueSubmit,vkQueue BindSparse),并且附上一系列的旗语(semaphores),用于等待旗语激活并开始运行指令和当该推送任务完成所需要激活的旗语。旗语的等待和激活是队列操作的一部分。

由于Vulkan的设备一般流水性和并行性运算能力很强,所以队列之间一般是并行运行的。

不同的队列之间执行任务没有隐示的约束,它们可以以任何顺序执行,为了控制执行顺序可以显示的使用旗语和栏栅(fence)。

多个命令缓存提交到单个队列遵守提交顺序,和一些其他的隐示循序保证。

在栏栅和旗语被激活后,就被认为之前与之相关的命令已经运行结束,之前处理完的内存对于当前任务可用可见。

命令缓存的执行边界处于一打一级命令缓存提交与一打命一级令缓存提交之间(为什么是一打,因为Vulkan一次性可以提交多个命令缓存),一级命令缓存和二级命令缓存之间也存在边界。边界和边界之间没有引入任何执行循序约定。换句话也就是说,当旗语或者栏栅之间提交一打命令缓存(也有可能包括二级命令缓存)时相当于将这一打命令缓存全部记录到一个一级缓存并提交到单个队列中一样,除非重置每一个边界(命令缓存可重置和重复使用,前提是创建时指定可重置属性)。更多信息请参考同步

单个命令缓存中命令和命令之间存在一些隐示的执行顺序保证,但是只是涵盖了执行的一小部分。可以使用同步原语(旗语,栏栅等)主动添加运行循序约束。同步

记录在命令缓存中的命令一般分为三类:

  1. 动作命令::绘制,派遣,清空,拷贝,查询/时间戳和开始/结束子通路(subpass)命令等。
  2. 状态设置::绑定管线(pipeline),描述符集(descriptor sets),缓存,动态阶段,推送恒量,设置渲染通路/子通路的状态命令等
  3. 同步操作::激活/等待事件(event),管线障(pipeline barrier),渲染通路/子通路的依赖命令等。

同步操作为动作命令之间提供显示的执行和内存依赖操作(同步操作)。第二个动作命令依赖于第一个动作命令,也就是说第二个动作命令是在第一个动作命令执行之后执行。对于内存的操作,第二个动作命令会等待第一个动作命令完成后操作对应的内存。如果不进行同步操作,执行顺序将会是交叠在一起,导致执行混乱,这可能会导致数据访问的无效。

设备与本地(host)之间也需要执行同步操作,当命令缓存提交到队列后控制权马上返回给本地应用。应用必须负责同步本地端和设备端。

 

注::

  1. 旗语::同步原语之一,更多信息请参考同步
  2. 栏栅::同步原语之一,更多信息请参考同步
  3. 事件(event)::同步原语之一,更多信息请参考同步
  4. 管线障(pipeline barrier)::同步原语之一,同步
  5. 命令缓存(command buffer)分为两类:一级命令缓存(primary command buffer)和二级命令缓存(secondary command buffer),一级命令缓存可以包含二级命令缓存,反过来不成立。

 

2.3 对象模型


       在Vulkan中对于设备、队列等都是Vulkan对象。这些对象使用句柄来定义。Vulkan中有两类句柄,可派遣(dispatchable)的和不可派遣(non-dispatchable)的。

可派遣类型是一个不透明类型的指针,该指针可以在某些层(layer)被拦截捕获。每一个可派遣句柄的值在Vulkan运行时都是唯一的,换句换说可派遣句柄没有重复的值。

可派遣类型声明如下:

#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;.

VK_DEFINE_HANDLE(dispatchable_name)

       不可派遣类型非常简单,就是一个64位的无符号整型数据(如果是64位平台则是和可派遣声明一样,是一个指针)。该整型数据具体代表什么对象需要看具体实现来确定。Vulkan中不同类型的不可派遣类的句柄不保证唯一性(例如Vulkan中的图片对象和缓对象就是两个不可派遣对象,其句柄可能存在重复)。对于反复创建并销毁回收的不可派遣对象,在重新创建时其句柄可能会是之前回收的句柄值,换句换说不可派遣类型的句柄可回收再利用。

不可派遣类型的声明如下:

#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t

VK_DEFINE_NON_DISPATCHABLE_HANDLE(non-dispatchable_name)

      所有的Vulkan对象创建和分配都是在设备上进行,并且一旦该对象在该设备上创建成功,则该对象属于该设备所有物,如果有多个设备不允许跨设备操作该对象。

注::

       1.句柄::一个对象的句柄并不是该对象本身,它代表着该对象,大多数句柄就是一个整数,相当于该对象的ID。使用句柄去控制该句柄所代表的对象是句柄的基本用法。

       2.层(layer)::Vulkan的核心架构中不包括错误检查,异常追踪。这些工作被分离出来放到了各个层(layer)里,每个层功能不同,有查错的,有追踪对象的等等,大体上层(layer)的左右就是错误检查。具体使用哪个层需要自己指定,这样Vulkan就可以丢掉繁重的错误跟踪工作,提高性能。层(layer)一般用于开发阶段,发布时一般会将层注销掉,提高性能。

      3.

#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object

中的##的意思是字符串连接符。将##之前的字符和##之后的字符连接起来。例如

VK_DEFINE_HANDLE(XXX)

等价于

typedef struct XXX##_T* XXX

等价于

typedef struct XXX_T* XXX

 

2.3.1 对象生命周期


Vulkan对象通过调用VkCreate*和vkAllocate*函数进行创建和分配。一旦对象被创建或被分配就被认为不变了,尽管对于某些对象还是可以去修改它的内容。销毁和释放对象通过调用vkDestroy*和vkFree*函数进行。

通过调用vkAllocate*函数为从对象奖池中分配一个对象,当释放该对象时,其会返回对应的对象池中等待以后分配使用。对于调用vkCreate*函数创建对象的频率相对较低,对于分配和释放对象的频率相对较高。对象池用于减少昂贵的对象分配和销毁操作的性能消耗。

Vulkan中对于对象的追踪的工作交给了应用负责,应用负责在对象在被使用时不能被销毁。

在Vulkan函数运行时相应的应用内存的所有权会交付到Vulkan手中,在函数运行结束时会返回给应用,当所有Vulkan函数都运行完成后可以将不再使用的内存释放。

下面列出的对象类型在作为参数传入Vulkan函数时不能释放,并且用这些对象作为参数创建的那些对象不会访问该对象。

  • VkShaderModule
  • VkPipelineCache
  • VkValidationCacheEXT

VkRenderPass对象在作为参数创建完其他对象后,不会再对VkRenderPass对象访问。VkRenderPass在命令缓存(command buffer)中的规则如下所述。

在VkPipelineLayout对象被命令缓存记录命令阶段使用时禁止销毁。

VkDescriptorSetLayout对象是用于创建描述符集(descriptor set)的,在

VkDescriptorSetLayout对象被销毁之后禁止调用vkUpdateDescriptorSets函数。

在设备还在使用某个Vulkan对象时,禁止应用销毁该对象,直到设备完成该对象的操作。

下面列出的Vulkan对象在命令缓存在待定/准备阶段(pending state)时禁止销毁:

  • VkEvent
  • VkQueryPool
  • VkBuffer
  • VkBufferView
  • VkImage
  • VkImageView
  • VkPipeline
  • VkSampler
  • VkSamplerYcbcrConversion
  • VkDescriptorPool
  • VkFramebuffer
  • VkRenderPass
  • VkCommandBuffer
  • VkCommandPool
  • VkDeviceMemory
  • VkDescriptorSet
  • VkIndirectCommandsLayoutNV

当命令缓存在记录和运行阶段使用这些对象时,当发生上述对象的销毁后,命令缓存会进入无效状态。

下列对象在队列使用这些对象运行命令时禁止销毁。

  • VkFence
  • VkSemaphore
  • VkCommandBuffer
  • VkCommandPool

实际上,只要对象不再使用,对于Vulkan对象可以按照任意顺序销毁,即使该对象正在被别的对象使用(例如使用资源(VkImage等)创建视图(VkImageView等),命令缓存中使用某些Vulkan对象(Semaphores等))。除非该对象可以被重置(比如重置命令缓存)。如果可重置对象被重置之后,该对象就可以重置成未使用过的对象,有一个例外,如果当前对象存在父子关系(例如内存和内存池这种通过池分配的对象)时,应用最好不要去销毁父对象,除非销毁父对象时定义好子对象如何销毁(Vulkan中一般,如果存在父子关系,当销毁父对象时会连带这自动将该父对象下面的所有子对象销毁)。

VkCommandPool对象是VkCommandBuffer对象的父对象,VkDescriptorPool对象是VkDescriptorSet对象的父对象。VkDevice是很多对象的父对象。

下列对象对于销毁有限制条件。

  • VkQueue对象不能显示的销毁,当VkDevice被显示的销毁时该对象连带着销毁。
  • 销毁一个池对象将会隐示连带着销毁从该池中分配的所有子对象。例如销毁VkCommandPool对象将会销毁所有从该对象中分配的VkCommandBuffer对象。
  • VkDevice对象,在该对象上的所有VkQueue对象都处于空闲状态,并且用该对象创建的所有子对象都销毁时才可以销毁该VkDevice对象。子对象包括:
  1. VkFence
  2. VkSemaphore
  3. VkEvent
  4. VkQueryPool
  5. VkBuffer
  6. VkBufferView
  7. VkImage
  8. VkImageView
  9. VkShaderModule
  10. VkPipelineCache
  11. VkPipeline
  12. VkPipelineLayout
  13. VkSampler
  14. VkSamplerYcbcrConversion
  15. VkDescriptorSetLayout
  16. VkDescriptorPool
  17. VkFramebuffer
  18. VkRenderPass
  19. VkCommandPool
  20. VkCommandBuffer
  21. VkDeviceMemory
  22. VkValidationCacheEXT
  • VkPhysicalDevice对象不能显示销毁,当VkInstance对象销毁时VkPhysicalDeivce对象自动隐示销毁。
  • VkInstance对象在所有VkDevice销毁后才可以销毁。
  • 作为管线库(pipeline library)所创建的VkPipeline对象,该作为管线库所创建的VkPipeline对象可以绑定多个VkPipeline对象,当所有绑定的VkPipeline对象销毁时,该作为管线库的VkPipeline对象方可销毁。(管线库好像是个扩展功能,具体不知道是个啥,待以后查资料或好心人指点)
  • 当创建图形着色器组(graphics shader groups)时所指定的VkPipeline对象,该VkPipeline对象和管线库VkPipeline对象类似,当所有图形着色器组创建时所指定的VkPipeline对象销毁后,该VkPipeline对象方可销毁。(图形着色器组好像是个NVIDIA扩展功能,具体不知道是个啥,待以后查资料或好心人指点)

 

注::

1描述符集(descriptor set)和描述符集布局(descriptor set layout)::描述符(descriptor)用于定义着色器(shader)与外部数据的交互接口,多的描述符组成了一个描述符集(descriptor set),描述符集布局(descriptor set layout)定义了描述符集接口的布局。(此处的交互接口说白了就是着色器中定义的变量)。

 

2.3.2外部对象句柄


Vulkan中对于对象的创建和分配都限制在VkDevice对象范围上进行的,跨设备,也就是跨VkDevice对象,访问跨VkDevice下面的子对象是不被允许的。像这样是别的VkDevice对象下的对象的话,叫做该设备对象的外部对象,简称外部对象。想要将外部对象变成本设备的内部对象的话,必须从源作用域中导出一个外部句柄,然后将其导入目标作用域。

 

注::

1.外部句柄和其对应的相关的资源可能多种多样,但是基本上都是可以通过进程(process)和API边界共享。(该处的进程和API边界不知道什么意思,代好心人指点)

 

2.4应用程序二进制接口(Application Binary Interface/ABI)


       当前系统上支持哪个版本(Windows、Mac、Linux等)的Vulkan是看当前的平台和具体实现。在很多平台上本规范中是通过使用C接口共享库(shared library/动态库)来描述。本规范对其做出了一些规范性要求。

       动态库的实现必须使用对应平台标准的C编译器编译的默认应用程序二进制接口(ABI),或者提供自定义API头文件使得应用使用自定义程序二进制接口。程序二进制接口指的是C中数据的结构大小,内存对齐,布局和函数的调用约定、C函数和动态库中符号的对应约定等。在Vulkan中对于这些约定的定义位于vk_platform.h的头文件中。

       Vulkan的动态库名称以”vk”开头,之后跟上数字或者大写字符作为标识。开发人员不得对Vulkan中已经定义的宏等数据做出重定义(就是不要动我定义好的东西)。

       动态库为实现支持的最高版本命令和窗口整合(window system integration)集提供符号集,并且也提供扩展的符号集。

(说白了,Vulkan对于各种名称等都给你定义好了,拿来用即可)。

 

2.5 命令/指令(函数)语法和持续时间


       该规范规定Vulkan使用C99标准,如果是C++或者JavaScript会有更加严格的参数传递和面向对象标准。

       Vulkan使用标准的C格式定义变量(例如stdint.h),除了下文所说的和某些指定的地方。

       VkBool32代表布尔值True和False,C中没有内部定义的布尔值:

typedef uint32_t Vkbool32;

       VK_TRUE代表着布尔值True(值为1),VK_FALSE代表布尔值False(值为0),Vulkan返回的VkBool32的值无非是VK_TRUE或者VK_FALSE。在需要传入VkBool32类型的参数时禁止传入除VK_TRUE和VK_FALSE的其他值。

       VkDeviceSize代表设备内存大小和偏移量。

    typedef uint64_t VkDeviceSize;

       VkDeviceAddresss代表物理缓存(buffer)地址值。

 typedef uint64_t VkDeviceAddress;

        Vulkan创建对象使用vkCreate*函数并且需要提供Vk*CreateInfo结构体用于创建对象。销毁对象使用vkDestroy*函数销毁。在vkCreate*函数的最后一个参数一般是一个名叫pAllocator的参数,该参数为指向自定义的分配器指针,该参数可以为空指针(nullptr),如果为空指针则使用Vulkan内置的分配器分配,具体请参考[链接]内存分配[链接]章节。

      如果创建的Vulkan是从Vulkan的对象池(pool)中分配创建的话,则调用vkAllocate*函数并且提供Vk*AllocateInfo结构体用于从该对象池中分配对象。

      Vulkan中的命令(Command)记录在命令缓存中(Command Buffer),并且命令函数命名为vkCmd*(比如绘制命令,拷贝命令等)。每一个命令一般都会有使用限制,并不是可以随便调用的。对于一级命令缓存(primary command buffer)和二级命令缓存(secondary command buffer),渲染通路(render pass)的内部和外部,一个或多个支持的队列类型,在Vulkan中都会有一些调用限制,并不是可以对其随意操作的。

       指令/命令(函数)的调用持续时间为开始调用到返回这段时间。

       注::

       命令缓存(command buffer)分为两类:一级命令缓存(primary command buffer)和二级命令缓存(secondary command buffer)。

 

2.5.1检索结果的生命周期


Vulkan中获取/检索信息通过调用vkGet*和vkEnumerate*函数获取。除非某些函数有另外说明,否则获取的信息将是恒定不变的。也就是当传入相同的参数调用同一个信息检索函数多次返回的结果是一样的。

 

2.6 线程行为


       Vulkan的设计初衷就是通过主机端的多线程特性为应用提供优良的弹性性能。Vulkan中的所有函数都支持多线程同时调用,但是某些需要传入这些函数的参数需要外部同步(互斥)。也就是说,这就需要同一时刻对于同一个参数的访问保证只能有一个线程对其访问。

       更确切的说,Vulkan函数仅仅使用简单的存储去更新Vulkan对象的状态。一个外部同步声明变量在程序运行时该变量的内容可能会更新成任意值。如果两个函数操作同一个变量,如果最后操作该变量的函数进行外部同步,则该函数需要保证没有别的函数同时调用该变量,如果有必要的话,这两个同时调用的函数需要提供合适的内存障(memeory barrier)。

 

       注::

       原本内存障是基于ARM处理器架构的(多见于移动端,嵌入端),该处理器相对于我们常见的x86/x64处理器要更加低耗。幸运的是,在很多高级别的同步机制中(例如Linux中的

pthread库),内存障是这些高级互斥机制的一部分,Vulkan对象通过内存障来达到高级互斥的相同目的(目的:互斥竞争资源)。

      

       相似的应用需要保证Vulkan函数在调用时,避免潜在的内存数据和对象所有权的混乱(2.3.1所述)。应用可能在任意时刻通过调用Vulkan函数获取的应用内存所有权进行读取,并且可能会向该非常量合格内存(non-const qualified memory)中写入。当参数引用的是非常量内存时本规范并不会标记其为外部同步。(这段不知道说的啥,待好心人指点)

       如果应用使用延迟本地操作(deferred host operation)调用Vulkan函数,并且延迟操作成功的话,在延迟操作结束之前,对象的参数和应用内存可能会在任意时刻被访问。

 

       注::

  1. 延迟本地操作::非核心标准,为扩展标准。Vulkan的某些函数调用工作对于CPU来说非常昂贵。这些工作会装载到后台多线程上,并且多CPU同时(并行)运行。延迟操作允许应用和驱动将这些昂贵的工作使用应用端线程池进行调用。

 

Vulkan中很多对象是不可变的,也就是说一旦该对象创建完成就不能更改。这些不变的对象永远不需要进行外部同步,除非该对象在别的线程上被使用时,该对象不能被销毁。在一些特殊的情况下易边的对象参数Vulkan在内部会进行内部同步,而不需要进行外部同步。函数调用所使用的参数如果没有标识需要外部同步则说明该参数要么不需要同步,要么是内部同步参数(Vulkan API文档中对于每一个函数中需要外部同步的每一个参数都作出了标记,标记在名为”Host Synchronization”说明框中,例如vkAcquireNextImageKHR函数)。

另外与命令(command)相关的某些对象(例如命令池(command pools)和描述符池(descriptor pools))可能会受到命令的影响,也必须要外部同步。

       如下记录了需要外部同步的函数参数(太多了懒得翻译修改了,自己翻译吧,也不难):

  • The instance parameter in vkDestroyInstance
  • The device parameter in vkDestroyDevice
  • The queue parameter in vkQueueSubmit
  • The fence parameter in vkQueueSubmit
  • The queue parameter in vkQueueWaitIdle
  • The memory parameter in vkFreeMemory
  • The memory parameter in vkMapMemory
  • The memory parameter in vkUnmapMemory
  • The buffer parameter in vkBindBufferMemory
  • The image parameter in vkBindImageMemory
  • The queue parameter in vkQueueBindSparse
  • The fence parameter in vkQueueBindSparse
  • The fence parameter in vkDestroyFence
  • The semaphore parameter in vkDestroySemaphore
  • The event parameter in vkDestroyEvent
  • The event parameter in vkSetEvent
  • The event parameter in vkResetEvent
  • The queryPool parameter in vkDestroyQueryPool
  • The buffer parameter in vkDestroyBuffer
  • The bufferView parameter in vkDestroyBufferView
  • The image parameter in vkDestroyImage
  • The imageView parameter in vkDestroyImageView
  • The shaderModule parameter in vkDestroyShaderModule
  • The pipelineCache parameter in vkDestroyPipelineCache
  • The dstCache parameter in vkMergePipelineCaches
  • The pipeline parameter in vkDestroyPipeline
  • The pipelineLayout parameter in vkDestroyPipelineLayout
  • The sampler parameter in vkDestroySampler
  • The descriptorSetLayout parameter in vkDestroyDescriptorSetLayout
  • The descriptorPool parameter in vkDestroyDescriptorPool
  • The descriptorPool parameter in vkResetDescriptorPool
  • The descriptorPool member of the pAllocateInfo parameter in vkAllocateDescriptorSets
  • The descriptorPool parameter in vkFreeDescriptorSets
  • The framebuffer parameter in vkDestroyFramebuffer
  • The renderPass parameter in vkDestroyRenderPass
  • The commandPool parameter in vkDestroyCommandPool
  • The commandPool parameter in vkResetCommandPool
  • The commandPool member of the pAllocateInfo parameter in vkAllocateCommandBuffers
  • The commandPool parameter in vkFreeCommandBuffers
  • The commandBuffer parameter in vkBeginCommandBuffer
  • The commandBuffer parameter in vkEndCommandBuffer
  • The commandBuffer parameter in vkResetCommandBuffer
  • The commandBuffer parameter in vkCmdBindPipeline
  • The commandBuffer parameter in vkCmdSetViewport
  • The commandBuffer parameter in vkCmdSetScissor
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值