创建着色器模块

要将着色器字节码在管线上使用,还需要使用VkShaderModule对象。让我们添加一个叫做createShaderModule的函数来完成VkShaderModule对象的创建:

VkShaderModule createShaderModule(const std::vector<char>& code)
{

}

createShaderModule函数使用我们读取的着色器字节码数组作为参数来创建VkShaderModule对象。

创建着色器模块非常简单,只需要通过VkShaderModuleCreateInfo结构体指定存储字节码的数组和数组长度即可。但需要注意一点,我们需要先将存储字节码的数组指针转换为const uint32_t*变量类型,来匹配结构体中的字节码指针的变量类型。这里,我们使用C++的reinterpret_cast完成变量类型转换。此外,我们指定的指针指向的地址应该符合uint32_t变量类型的内存对齐方式。我们这里使用的std::vector,它的默认分配器分配的内存的地址符合这一要求。

VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());

接着,我们调用vkCreateShaderModule函数创建VkShaderModule对象:

VkShaderModule shaderModule;
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
    throw std::runtime_error("failed to create shader module!");
}

和之前调用其它创建Vulkan对象的函数相同,调用vkCreateShaderModule函数需要逻辑设备对象,指向要创建对象信息的结构体,可选的自定义分配器以及用于存储返回的创建的对象句柄的内存地址。调用vkCreateShaderModule函数后,我们就可以立即释放掉存储着色器字节码的数组内存。最后,不要忘记返回创建的着色器模块对象:

return shaderModule;

着色器模块对象只在管线创建时需要,所以,不需要将它定义为一个成员变量,我们将它作为一个局部变量定义在createGraphicsPipeline函数中:

VkShaderModule vertShaderModule;
VkShaderModule fragShaderModule;

调用我们编写的辅助函数创建着色器模块对象:

vertShaderModule = createShaderModule(vertShaderCode);
fragShaderModule = createShaderModule(fragShaderCode);

我们需要在createGraphicsPipeline函数返回前,也就是createGraphicsPipeline函数的尾部,清除创建的着色器模块对象:

...
    vkDestroyShaderModule(device, fragShaderModule, nullptr);
    vkDestroyShaderModule(device, vertShaderModule, nullptr);
}