用于间接计算着色器分派的 Vulkan 内存屏障
Vulkan memory barrier for indirect compute shader dispatch
我有两个计算着色器,第一个修改 DispatchIndirectCommand
缓冲区,稍后由第二个使用。
// This is the code of the first shader
struct DispatchIndirectCommand{
uint x;
uint y;
uint z;
};
restrict layout(std430, set = 0, binding = 5) buffer Indirect{
DispatchIndirectCommand[1] dispatch_indirect;
};
void main(){
// some stuff
dispatch_indirect[0].x = number_of_groups; // I used debugPrintfEXT to make sure that this number is correct
}
我执行如下
vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, first_shader);
vkCmdDispatch(cmd_buffer, x, 1, 1);
vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, second_shader);
vkCmdDispatchIndirect(cmd_buffer, indirect_buffer, 0);
问题是第一个着色器所做的更改没有反映在第二个着色器中。
// This is the code of the second shader
void main(){
debugPrintfEXT("%d", gl_GlobalInvocationID.x); //this seems to never be called
}
我用 VkDispatchIndirectCommand{.x=0,.y=1,.z=1}
初始化 indirect_buffer
,似乎第二个着色器总是用 x==0
执行,因为 debugPrintfEXT
从不打印任何东西。我试着添加一个内存屏障,比如
VkBufferMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.srcQueueFamilyIndex = queue_idx;
barrier.dstQueueFamilyIndex = queue_idx;
barrier.buffer = indirect_buffer;
barrier.offset = 0;
barrier.size = sizeof_indirect_buffer;
不过,这似乎没有什么区别。似乎有效的是当我使用
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ;
当我使用此类访问标志时,所有计算着色器都可以正常工作。但是,我收到验证错误
Validation Error: [ VUID-vkCmdPipelineBarrier-dstAccessMask-02816 ] Object 0: handle = 0x5561b60356c8, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x69c8467d | vkCmdPipelineBarrier(): .pMemoryBarriers[1].dstAccessMask bit VK_ACCESS_INDIRECT_COMMAND_READ_BIT is not supported by stage mask (VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT). The Vulkan spec states: The dstAccessMask member of each element of pMemoryBarriers must only include access flags that are supported by one or more of the pipeline stages in dstStageMask, as specified in the table of supported access types (https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#VUID-vkCmdPipelineBarrier-dstAccessMask-02816)
Vulkan 的 documentation 声明
VK_ACCESS_INDIRECT_COMMAND_READ_BIT specifies read access to indirect command data read as part of an indirect build, trace, drawing or dispatching command. Such access occurs in the VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT pipeline stage
看起来真的很混乱。它明明提到了“调度命令”,但同时又说阶段必须是VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
而不是VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
。是规范 contradictory/imprecise 还是我遗漏了什么?
您似乎在采用试错策略。不要在低级 API 中使用这种策略,一般情况下最好在计算机工程中使用。迟早你会遇到一些东西,当你测试它时看起来它可以工作,但无论如何都是无效代码。规范确实告诉了你确切的做法,所以你从来没有正当理由尝试任何其他标志或完全没有障碍。
如您所见,间接读取的适当访问标志是 VK_ACCESS_INDIRECT_COMMAND_READ_BIT
。正如规范中所说,适当的阶段是 VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
.
所以你的情况的障碍可能应该是:
srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
阶段标志的名称有点令人困惑,但规范在其他方面非常清楚,它适用于计算:
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
specifies the stage of the pipeline where VkDrawIndirect*
/ VkDispatchIndirect*
/ VkTraceRaysIndirect*
data structures are consumed.
还有:
For the compute pipeline, the following stages occur in this order:
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
PS:也相关 GitHub 问题:KhronosGroup/Vulkan-Docs#176
我有两个计算着色器,第一个修改 DispatchIndirectCommand
缓冲区,稍后由第二个使用。
// This is the code of the first shader
struct DispatchIndirectCommand{
uint x;
uint y;
uint z;
};
restrict layout(std430, set = 0, binding = 5) buffer Indirect{
DispatchIndirectCommand[1] dispatch_indirect;
};
void main(){
// some stuff
dispatch_indirect[0].x = number_of_groups; // I used debugPrintfEXT to make sure that this number is correct
}
我执行如下
vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, first_shader);
vkCmdDispatch(cmd_buffer, x, 1, 1);
vkCmdBindPipeline(cmd_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, second_shader);
vkCmdDispatchIndirect(cmd_buffer, indirect_buffer, 0);
问题是第一个着色器所做的更改没有反映在第二个着色器中。
// This is the code of the second shader
void main(){
debugPrintfEXT("%d", gl_GlobalInvocationID.x); //this seems to never be called
}
我用 VkDispatchIndirectCommand{.x=0,.y=1,.z=1}
初始化 indirect_buffer
,似乎第二个着色器总是用 x==0
执行,因为 debugPrintfEXT
从不打印任何东西。我试着添加一个内存屏障,比如
VkBufferMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.srcQueueFamilyIndex = queue_idx;
barrier.dstQueueFamilyIndex = queue_idx;
barrier.buffer = indirect_buffer;
barrier.offset = 0;
barrier.size = sizeof_indirect_buffer;
不过,这似乎没有什么区别。似乎有效的是当我使用
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ;
当我使用此类访问标志时,所有计算着色器都可以正常工作。但是,我收到验证错误
Validation Error: [ VUID-vkCmdPipelineBarrier-dstAccessMask-02816 ] Object 0: handle = 0x5561b60356c8, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x69c8467d | vkCmdPipelineBarrier(): .pMemoryBarriers[1].dstAccessMask bit VK_ACCESS_INDIRECT_COMMAND_READ_BIT is not supported by stage mask (VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT). The Vulkan spec states: The dstAccessMask member of each element of pMemoryBarriers must only include access flags that are supported by one or more of the pipeline stages in dstStageMask, as specified in the table of supported access types (https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#VUID-vkCmdPipelineBarrier-dstAccessMask-02816)
Vulkan 的 documentation 声明
VK_ACCESS_INDIRECT_COMMAND_READ_BIT specifies read access to indirect command data read as part of an indirect build, trace, drawing or dispatching command. Such access occurs in the VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT pipeline stage
看起来真的很混乱。它明明提到了“调度命令”,但同时又说阶段必须是VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
而不是VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
。是规范 contradictory/imprecise 还是我遗漏了什么?
您似乎在采用试错策略。不要在低级 API 中使用这种策略,一般情况下最好在计算机工程中使用。迟早你会遇到一些东西,当你测试它时看起来它可以工作,但无论如何都是无效代码。规范确实告诉了你确切的做法,所以你从来没有正当理由尝试任何其他标志或完全没有障碍。
如您所见,间接读取的适当访问标志是 VK_ACCESS_INDIRECT_COMMAND_READ_BIT
。正如规范中所说,适当的阶段是 VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
.
所以你的情况的障碍可能应该是:
srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
阶段标志的名称有点令人困惑,但规范在其他方面非常清楚,它适用于计算:
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
specifies the stage of the pipeline whereVkDrawIndirect*
/VkDispatchIndirect*
/VkTraceRaysIndirect*
data structures are consumed.
还有:
For the compute pipeline, the following stages occur in this order:
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
PS:也相关 GitHub 问题:KhronosGroup/Vulkan-Docs#176