6.4 执行工作
在前一节,你看到了如何使用vkCreateComputePipelines()构造一个计算管线并把大绑定到一个命令缓冲区。一旦管线被绑定,你可以用它来执行工作。
计算着色器作为计算管线的一部分,以分组的形式来执行,分组成为本地工作组。这些工作逻辑上速度一致的执行,在着色器里被指定了固定的大小。本地工作组最大个数一般比较小,但是至少是128调用 × 128 调用× 64 调用。还有,在单一一个本地工作组里最大调用个数也比总容量较小,且要求只能是128调用。因此原因,本地工作组从较大的组开始,优势被称为全局工作组或者分发大小。从计算着色器中开始任务因此被称为分发任务,或者分发。本地工作组逻辑上是一个三维结构,或者调用立体,计算一个或两个温度可以是单个调用,以保持工作组在该方向上扁平。同样,这些本地工作组在三维上一起被分发,即使一个或多个维度是一个工作组深度。
用计算管线可用来分发任务的命令是vkCmdDispatch(),其原型如下:
voidvkCmdDispatch (
VkCommandBuffer commandBuffer,
uint32_t x,
uint32_t y,
uint32_t z);
将要执行任务的命令缓冲区通过commandBuffer传递。x,y,z每一个维度中的本地工作组数量通过x,y,z参数传递。一个有效的计算管线必须绑定到命令缓冲区的VK_PIPELINE_BIND_POINT_COMPUTE绑定点。当命令被设备执行是,一个x × y× z大小的全局工作组开始执行所绑定管线的着色器。
极有可能一个本地工作组在有效维度上与全局工作组不同。例如,可以存在一个32 × 32 × 1分发64 × 1 × 1的本地工作组。
在vkCmdDispatch()中能用参数指定工作组的个数之外,也可能做到间接分发,在工作组中分发的个数来自缓冲区对象。这允许分发大小在使用一个缓冲区来间接分发构造命令缓冲区 然后把缓冲区内容写入主机端之后计算。缓冲区的内容可被设备更新,来给设备提供工作。
vkCmdDispatchIndirect()的原型如下:
voidvkCmdDispatchIndirect (
VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset);
包含该命令的命令缓冲区通过commandBuffer传递。和vkCmdDispatch()中传递的分发个数不一样,工作组中每一个维度的大小被存储在三个连续的uint32_t的变量里,其在缓冲区对象buffer中起始偏移位置是offset。缓冲区中参数基本上代表了一个VkDispatchIndirectCommand类型的数据,定义为:
typedefstruct VkDispatchIndirectCommand {
uint32_t x;
uint32_t y;
uint32_t z;
}VkDispatchIndirectCommand;
缓冲区中的内容在设备执行的命令缓冲区中vkCmdDispatchIndirect()命令到达之前不会被读取。
工作组每一个维度的最大个数可通过检查vkGetPhysicalDeviceProperties()调用得来的设备的VkPhysicalDeviceLimits类型数据的maxComputeWorkGroupCount成员来获知,在第一章“Vulkan简介”中奖结果。在vkCmdDispatch()调用中超过了这个限制或者在vkCmdDispatchIndirect()里使用了超出限定值的将会导致为定义(很有可能是坏的)的行为。