如何在Vulkan主机端C/C++程序中创建可动态设置大小的shared共享缓冲区
你之前的三种尝试不符合GLSL与Vulkan的标准约束:shared修饰的内存属于工作组本地存储,不绑定描述集,且数组大小必须是管线创建前可确定的常量,不能用运行时动态更新的uniform值定义大小,因此编译报错。
以下是两种可行的实现方案:
方案1:特化常量实现(推荐)
这是最贴合需求的标准实现,支持你在主机端创建管线时指定任意大小的shared内存,适配绝大多数场景。
GLSL 着色器修改
// foo.comp #version 450 // 定义ID为0的特化常量,默认值可随意指定 layout(constant_id = 0) const uint SHARED_BUFFER_SIZE = 64; layout(binding=0) buffer dstBuffer{ uint dst[]; }; layout(binding=1) buffer srcBuffer{ uint src[]; }; // 用特化常量作为shared数组大小,编译可通过 shared uint buf[SHARED_BUFFER_SIZE]; void main() { // 后续正常使用buf即可 }
主机端C++ 管线创建代码
在创建计算管线时,通过特化信息传入你需要的shared内存大小:
// 运行时确定你需要的shared数组大小,这里以256为例 const uint32_t targetSharedSize = 256; // 配置特化常量映射 VkSpecializationMapEntry specEntry = { .constantID = 0, // 和GLSL中定义的constant_id对应 .offset = 0, .size = sizeof(uint32_t) }; VkSpecializationInfo specInfo = { .mapEntryCount = 1, .pMapEntries = &specEntry, .dataSize = sizeof(targetSharedSize), .pData = &targetSharedSize }; // 计算着色器阶段创建时传入特化信息 VkPipelineShaderStageCreateInfo computeStageInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_COMPUTE_BIT, .module = yourCompiledShaderModule, .pName = "main", .pSpecializationInfo = &specInfo }; // 后续按正常流程创建计算管线即可,此时着色器内的shared数组大小就是你指定的targetSharedSize
如果需要使用不同大小的shared内存,只需创建多个管线变体,每个传入不同的特化值,调度时绑定对应管线即可。
方案2:固定最大容量的动态裁剪实现
如果你不想创建多管线变体,且shared内存的大小波动范围不大,可以用该方案:
GLSL 着色器修改
// foo.comp #version 450 // 定义你场景下需要的最大shared容量 #define MAX_SUPPORTED_SHARED_SIZE 1024 shared uint buf[MAX_SUPPORTED_SHARED_SIZE]; // 用uniform传入本次调度实际使用的大小 layout(binding=2) uniform SharedConfig { uint actualUsedSize; }; layout(binding=0) buffer dstBuffer{ uint dst[]; }; layout(binding=1) buffer srcBuffer{ uint src[]; }; void main() { // 访问时仅操作actualUsedSize以内的下标 if (gl_LocalInvocationID.x < actualUsedSize) { buf[gl_LocalInvocationID.x] = src[gl_GlobalInvocationID.x]; } // 其余逻辑正常实现 }
该方案的缺点是会占用MAX_SUPPORTED_SHARED_SIZE对应的本地内存空间,可能降低单个计算单元可并行的工作组数量,仅适合shared大小波动小的场景。
内容的提问来源于stack exchange,提问作者user5297047
相关产品推荐
相关产品推荐

