目录
Push Constants
prepare
-
loadAssets: 加载模型等资源
-
setupSpheres: 为球模型设置随机颜色
-
prepareUniformBuffers
- updateUniformBuffers
-
setupDescriptorSetLayout:正常操作,常量在此处进行设置
// Define the push constant range used by the pipeline layout // Note that the spec only requires a minimum of 128 bytes, so for passing larger blocks of data you'd use UBOs or SSBOs VkPushConstantRange pushConstantRange{}; pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; pushConstantRange.offset = 0; pushConstantRange.size = sizeof(SpherePushConstantData); VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1); pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
-
setupDescriptorSet
-
preparePipelines
-
setupDescriptorPool
-
setupDescriptorSet
-
buildCommandBuffers:常量绑定在这里
vkCmdPushConstants( drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(SpherePushConstantData), &spheres[j]); model.draw(drawCmdBuffers[i]);
-
shader中常量的获取
layout(push_constant) uniform PushConsts { vec4 color; vec4 position; } pushConsts;
render
- draw
- updateUniformBuffers
小结
常量的设置比较简单,setupDescriptorSetLayout中设置, buildCommandBuffers中绑定,shader获取即可。
Specialization Constants
prepare
-
loadAssets:
-
prepareUniformBuffers
- updateUniformBuffers
-
setupDescriptorSetLayout:与常量不同 Specialization Constants 设置只在 preparePipelines 中
-
preparePipelines
// Host data to take specialization constants from // 常量结构体定义,命名随意,只要靠绑定id获取值 struct SpecializationData { // Sets the lighting model used in the fragment "uber" shader uint32_t lightingModel; // Parameter for the toon shading part of the fragment shader float toonDesaturationFactor = 0.5f; } specializationData; // Each shader constant of a shader stage corresponds to one map entry //绑定常量实体 std::array<VkSpecializationMapEntry, 2> specializationMapEntries; // Shader bindings based on specialization constants are marked by the new "constant_id" layout qualifier: // layout (constant_id = 0) const int LIGHTING_MODEL = 0; // layout (constant_id = 1) const float PARAM_TOON_DESATURATION = 0.0f; // Map entry for the lighting model to be used by the fragment shader //id是shader中获取值的索引 specializationMapEntries[0].constantID = 0; specializationMapEntries[0].size = sizeof(specializationData.lightingModel); specializationMapEntries[0].offset = 0; // Map entry for the toon shader parameter specializationMapEntries[1].constantID = 1; specializationMapEntries[1].size = sizeof(specializationData.toonDesaturationFactor); specializationMapEntries[1].offset = offsetof(SpecializationData, toonDesaturationFactor); // Prepare specialization info block for the shader stage VkSpecializationInfo specializationInfo{}; specializationInfo.dataSize = sizeof(specializationData); specializationInfo.mapEntryCount = static_cast<uint32_t>(specializationMapEntries.size()); specializationInfo.pMapEntries = specializationMapEntries.data(); specializationInfo.pData = &specializationData; // Create pipelines // All pipelines will use the same "uber" shader and specialization constants to change branching and parameters of that shader shaderStages[0] = loadShader(getShadersPath() + "specializationconstants/uber.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getShadersPath() + "specializationconstants/uber.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); // Specialization info is assigned is part of the shader stage (modul) and must be set after creating the module and before creating the pipeline //选择常量绑定在哪个shader中 shaderStages[1].pSpecializationInfo = &specializationInfo;
- setupDescriptorPool
- setupDescriptorSet
- buildCommandBuffers
- shader中常量的获取
//变量名称可以自定义 layout (constant_id = 0) const int LIGHTING_MODEL = 0; layout (constant_id = 1) const float PARAM_TOON_DESATURATION = 0.0f;
render
- draw
- updateUniformBuffers
小结
Specialization 常量是shader域绑定的,只在preparePipelines中设置即可。与 Constants 的区别是,Specialization Constants 作用域是shader域,而 Constants 的作用域为 pipeline。
Texture Mapping
prepare
- loadTexture: 加载图片
- ktx_uint8_t *textureData 从读图API中将纹理读入
- 纹理结构体
VkSampler sampler; VkImage image; VkImageLayout imageLayout; VkDeviceMemory deviceMemory; VkImageView view; uint32_t width, height; //从textureData 中获取 uint32_t mipLevels; //从textureData 中获取
- 官方给出两种将图片资源导入GPU的方式, 一种是线性式平铺, 一种是优化式平铺.
- 线性平铺是可以直接将存储图片信息的内存空间数据直接复制到GPU上, 因此对于纹理的格式和功能支持非常有限
- vkCreateImage
- vkGetImageMemoryRequirements
- vkAllocateMemory
- vkBindImageMemory
- vkMapMemory – memcpy – vkUnmapMemory
- vkCmdPipelineBarrier: 直接将图片从 HOST Barrier 到 FRAGMENT_SHADER
- flushCommandBuffer
- 优化式平铺将图片内存空间数据与硬件支持的功能进行匹配, 然后生成specific layout, 这样能支持更多格式和相应功能. 而且Copy速度更快. 但是这种方式存储图片信息, 是存储在drive中, 主机无法访问.
- vkCreateBuffer: 创建stagingBuffer
- vkGetBufferMemoryRequirements: 申请buffer使用的内存
- vkAllocateMemory: 分配内存
- vkBindBufferMemory: 绑定内存
- vkMapMemory – memcpy – vkUnmapMemory: 将图片信息复制到 host local staging buffer (specific layout)
- std::vector bufferCopyRegions: 为每个 mip 设置缓冲区复制区域
- vkCreateImage: Create optimal tiled target image on the device
- 其中主要的是 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
- vkGetImageMemoryRequirements: 申请内存
- vkAllocateMemory: 分配内存
- vkBindImageMemory: 绑定资源
- createCommandBuffer:创建复制命令
- imageMemoryBarrier:: Image memory barriers for the texture image
- 为每个pipeline 设置 image layout 过度,下面的操作就是从stagingBuffer中将图片数据复制到GPU
- vkCmdPipelineBarrier:从 HOST Barrier 到 TRANSFER
- vkCmdCopyBufferToImage:Copy mip levels from staging buffer
- vkCmdPipelineBarrier:从TRANSFER Barrier 到 FRAGMENT_SHADER
- flushCommandBuffer
- vkFreeMemory:Clean up staging resources
- vkDestroyBuffer:Clean up staging resources
- 线性平铺是可以直接将存储图片信息的内存空间数据直接复制到GPU上, 因此对于纹理的格式和功能支持非常有限
- ktxTexture_Destroy:释放从磁盘读取图片的内存
- vkCreateSampler
- vkCreateImageView
- generateQuad:创建一个面片
- setupVertexDescriptions
- prepareUniformBuffers
- updateUniformBuffers
- setupDescriptorSetLayout
- preparePipelines
- setupDescriptorPool
- setupDescriptorSet
- buildCommandBuffers
render
- draw
小结
本节主要讲如何更高效的读取贴图。与一般的直接从本地读取贴图数据,然后直接复制到GPU相比,使用 specific layout,能支持更多的格式和功能。并且有更高效的性能。