Vulkan之push constant(vkCmdPushConstants)

在pipeline layout中定义了着色器推送常量,他是通过vulkan的command buffer进行更新着色器中的常量,而不是将常量写入memory或复制命令进行更新。

在实例化VkPipelineLayoutCreateInfo时,对constant进行描述

typedef struct VkPipelineLayoutCreateInfo {
  VkStructureType sType;
  const void* pNext;
  VkPipelineLayoutCreateFlags flags;
  uint32_t setLayoutCount;
  const VkDescriptorSetLayout* pSetLayouts;
  uint32_t pushConstantRangeCount;
  const VkPushConstantRange* pPushConstantRanges;    // 描述常量信息
} VkPipelineLayoutCreateInfo;

build command buffer时,调用下面的接口,将常量数据传给着色器。

void vkCmdPushConstants(
  VkCommandBuffer commandBuffer,
  VkPipelineLayout layout,
  VkShaderStageFlags stageFlags,
  uint32_t offset,
  uint32_t size,
  const void* pValues);

注:

push constant是一种快速修改pipeline中常量的方法,比通过memory保存数据进行更新的方式更好。

在command buffer录制开始时,push constant的值是未定义的,需要调用vkCmdPushConstants进行更新。

下面以vulkan example中pushconstants的例子对使用push constant的方法进行说明。

  • 着色器中存在常量,如下在着色器中定义了pushConsts的结构体
#version 450

layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec3 inColor;

#define lightCount 6

layout (binding = 0) uniform UBO 
{
	mat4 projection;
	mat4 model;
	mat4 view;
} ubo;

// 常量结构体
layout(push_constant) uniform PushConsts {
	vec4 color;
	vec4 position;
} pushConsts;

layout (location = 0) out vec3 outColor;

void main() 
{
	outColor = inColor * pushConsts.color.rgb;	
	vec3 locPos = vec3(ubo.model * vec4(inPos, 1.0));
	vec3 worldPos = locPos + pushConsts.position.xyz;
	gl_Position =  ubo.projection * ubo.view * vec4(worldPos, 1.0);
}
  • 代码中定义与着色器中相同的结构体,代表协议一致
// Color and position data for each sphere is uploaded using push constants
struct SpherePushConstantData {
	glm::vec4 color;
	glm::vec4 position;
};
std::array<SpherePushConstantData, 16> spheres;
  • 在创建pipeline layout时,对pipeline中可访问的push constant的范围进行描述定义
void setupDescriptorSetLayout()
{
    std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
        // Binding 0 : Vertex shader uniform buffer
        vks::initializers::descriptorSetLayoutBinding(
            VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
            VK_SHADER_STAGE_VERTEX_BIT,
            0),
    };

    VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
    VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));

    // 定义pipeline layout中使用的push constant的范围
    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));
}

注:VkPushConstantRange参数中

offset必须小于VkPhysicalDeviceLimits::maxPushConstantsSize,且是4的倍数
size必须大于0,且是4的倍数
size必须小于等于 VkPhysicalDeviceLimits::maxPushConstantsSize减去offset
  • build command buffer中调用draw call之前更新push constant的值到着色器中
uint32_t spherecount = static_cast<uint32_t>(spheres.size());
for (uint32_t j = 0; j < spherecount; j++) {
    // [POI] Pass static sphere data as push constants
    vkCmdPushConstants(
        drawCmdBuffers[i],
        pipelineLayout,
        VK_SHADER_STAGE_VERTEX_BIT,
        0,
        sizeof(SpherePushConstantData),
        &spheres[j]);
    model.draw(drawCmdBuffers[i]);
}

渲染结果如下:

是不是还是挺简单的,如果还有不清楚的地方,可以阅读vulkan example的源码,也可以在此留言。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值