目录
计算着色器用于通用计算任务,与图形管线独立,可以用于加速计算密集型任务。
1. 编写计算着色器
计算着色器 (compute_shader.glsl)
#version 450
layout(local_size_x = 16, local_size_y = 16) in;
layout(set = 0, binding = 0) buffer InputOutputBuffer {
float data[];
} bufferData;
void main() {
uint index = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * gl_NumWorkGroups.x * gl_WorkGroupSize.x;
bufferData.data[index] = bufferData.data[index] * 2.0;
}
编译计算着色器:
glslc compute_shader.glsl -o compute_shader.spv
2. 创建计算管线
加载着色器模块
VkShaderModule createShaderModule(const std::vector<char>& code) {
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
VkShaderModule shaderModule;
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
throw std::runtime_error("failed to create shader module!");
}
return shaderModule;
}
创建计算管线
VkPipeline computePipeline;
VkPipelineLayout computePipelineLayout;
void createComputePipeline() {
auto computeShaderCode = readFile("compute_shader.spv");
VkShaderModule computeShaderModule = createShaderModule(computeShaderCode);
VkPipelineShaderStageCreateInfo computeShaderStageInfo{};
computeShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
computeShaderStageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT;
computeShaderStageInfo.module = computeShaderModule;
computeShaderStageInfo.pName = "main";
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &computePipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("failed to create compute pipeline layout!");
}
VkComputePipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
pipelineInfo.stage = computeShaderStageInfo;
pipelineInfo.layout = computePipelineLayout;
if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &computePipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create compute pipeline!");
}
vkDestroyShaderModule(device, computeShaderModule, nullptr);
}
- VkPipelineShaderStageCreateInfo 结构体定义计算着色器阶段的信息。
- VkPipelineLayoutCreateInfo 结构体包含创建管线布局的信息。
- VkComputePipelineCreateInfo 结构体包含创建计算管线的信息。
- vkCreateComputePipelines 函数创建计算管线。
3. 执行计算任务
创建命令缓冲
VkCommandBuffer computeCommandBuffer;
void createComputeCommandBuffer() {
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1;
if (vkAllocateCommandBuffers(device, &allocInfo, &computeCommandBuffer) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate compute command buffer!");
}
}
记录计算命令缓冲
void recordComputeCommandBuffer() {
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
if (vkBeginCommandBuffer(computeCommandBuffer, &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("failed to begin recording compute command buffer!");
}
vkCmdBindPipeline(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
vkCmdBindDescriptorSets(computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
vkCmdDispatch(computeCommandBuffer, (uint32_t)ceil(WIDTH / 16.0), (uint32_t)ceil(HEIGHT / 16.0), 1);
if (vkEndCommandBuffer(computeCommandBuffer) != VK_SUCCESS) {
throw std::runtime_error("failed to record compute command buffer!");
}
}
- vkCmdBindPipeline 函数绑定计算管线。
- vkCmdBindDescriptorSets 函数绑定描述符集。
- vkCmdDispatch 函数执行计算着色器,指定工作组的数量。
提交计算命令缓冲
void submitComputeCommandBuffer() {
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &computeCommandBuffer;
if (vkQueueSubmit(computeQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) {
throw std::runtime_error("failed to submit compute command buffer!");
}
vkQueueWaitIdle(computeQueue);
}
- VkSubmitInfo 结构体包含提交信息。
- vkQueueSubmit 函数提交命令缓冲到计算队列。
- vkQueueWaitIdle 函数等待计算队列完成。