Push constant updates

Push constants are specially designed to update the shader constant data using the command buffer instead of updating the resources with the write or copy descriptors.

Note

Push constants offer a high-speed optimized path to update the constant data in the pipeline.

In this section, we will quickly implement an example to demonstrate a push constant. We will learn how push constants are used with command buffers to update the resource contents in the shader. This example defines two types of resources in the fragment shader—constColor and mixerValue—within the push constant uniform block pushConstantsColorBlock. The constColor resource contains an integer value that is used as a flag to render the rotating cube in a solid color (red, green, or blue). The mixerValue resource is a floating value that mixes with the cube color.

Defining the push constant resource in the shader

The push constant resource in the shader is defined using the push_constant keyword in a layout that indicates it is a push constant block. In the following code, we have modified the existing fragment shader and added two push constant variables, namely constColor and mixerValue. If the value of constColor is either 1, 2, or 3, then a solid geometry color (red, green, or blue) is rendered. Otherwise, the original color is mixed with mixerValue:

// Fragment shader
#version 450
layout (location = 0) in vec4 color;
layout (location = 0) out vec4 outColor;
layout(push_constant) uniform colorBlock {

    int constColor;

    float mixerValue;

} pushConstantsColorBlock;

 

vec4 red   = vec4(1.0, 0.0, 0.0, 1.0);

vec4 green = vec4(0.0, 1.0, 0.0, 1.0);

vec4 blue  = vec4(0.0, 0.0, 1.0, 1.0);

void main() {
    if (pushConstantsColorBlock.constColor == 1)

       outColor = red;

    else if (pushConstantsColorBlock.constColor == 2)

       outColor = green;

    else if (pushConstantsColorBlock.constColor == 3)

       outColor = blue;

    else

       outColor = color*pushConstantsColorBlock.mixerValue;
}

In the next section, we will update this shader push constant resource in the pipeline layout.

Updating the pipeline layout with the push constant

Update the pipeline layout indicating the push constant ranges. The push constant range is defined in a single pipeline layout using the VkPushConstantRange structure. The pipeline layout also needs to be informed how many push constants can be accessed by each stage of the pipeline.

The following is the syntax of this structure:

typedef struct VkPushConstantRange { 
    VkShaderStageFlags    stageFlags; 
    uint32_t              offset; 
    uint32_t              size; 
} VkPushConstantRange; 

The various fields of the VkPushConstantRange structure are defined here:

Parameters

Description

stageFlags

This field indicates the shader stage to which this push constant range belongs. If stageFlags is not defined with the shader stage, then accessing the push constant resource member from that shader stage will produce an instance where undefined data would be read.

offset

This is the start offset of the push constant range specified in bytes and is a multiple of four.

size

This field is also specified in bytes and is a multiple of four, indicating the size of the push constant range.

Update pushConstantRangeCount of VkPipelineLayoutCreateInfo with the push constant range count and pPushConstantRanges with a pointer to an array of VkPushConstantRange:

void VulkanDrawable::createPipelineLayout() 
{ 
    // Setup the push constant range

    const unsigned pushConstantRangeCount = 1;

    VkPushConstantRange pushConstantRanges[pushConstantRangeCount]={};
    
    pushConstantRanges[0].stageFlags     = VK_SHADER_STAGE_FRAGMENT_BIT;
       
    pushConstantRanges[0].offset         = 0;

    pushConstantRanges[0].size                = 8;
   // Create the pipeline layout with the help of descriptor layout. 
   VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {}; 
   pPipelineLayoutCreateInfo.sType     =  
               VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 
   pPipelineLayoutCreateInfo.pNext                       = NULL; 
   pPipelineLayoutCreateInfo.pushConstantRangeCount =  
                   
                     pushConstantRangeCount;

   pPipelineLayoutCreateInfo.pPushConstantRanges =
                    
                     pushConstantRanges; 
   pPipelineLayoutCreateInfo.setLayoutCount  = 
                     (uint32_t)descLayout.size(); 
   pPipelineLayoutCreateInfo.pSetLayouts = descLayout.data(); 
 
   VkResult  result; 
   result = vkCreatePipelineLayout(deviceObj->device,  
           &pPipelineLayoutCreateInfo, NULL, &pipelineLayout); 
   assert(result == VK_SUCCESS); 
} 

Updating the resource data

The resource data can be updated using the vkCmdPushConstants() API. In order to use this API, allocate a command buffer called cmdPushConstant, update the resource data with the appropriate values, and execute vkCmdPushConstants(). The following is the syntax of this API:

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

The various fields of the vkCmdPushConstants structure are defined here:

Parameters

Description

commandBuffer

This is the command buffer object (VkCommandBuffer) that will be used to record the push constant update.

layout

This is VkPipelineLayout object that will be used to program the push constant updates.

stageFlag

This specifies the shader stage that will utilize the push constants in the updated range. The shader stage is indicated using a bitmask of VkShaderStageFlagBits.

offset

This starts the offset in bytes specifying the push constant range for the update.

size

This refers to the size (in bytes) of the push constant range to be updated.

pValues

This is an array containing the new push constant values.

The size of the push constant must never exceed the size specified in VkPhysicalDeviceProperties::limits::maxPushConstantsSize.

The following is the implementation of the push constants where the push constant is executed using the allocated command buffer cmdPushConstant. There are two push constant resource variables: constColorRGBFlag and mixerValue. These are set with the desired values and specified in the vkCmdPushConstants() API:

void VulkanRenderer::createPushConstants() 
{ 
    // Allocate and start recording the push constant buffer. 
    CommandBufferMgr::allocCommandBuffer(&deviceObj->device,  
                           cmdPool, &cmdPushConstant); 
    CommandBufferMgr::beginCommandBuffer(cmdPushConstant); 
 
    enum ColorFlag { 
       RED         = 1, 
       GREEN       = 2, 
       BLUE        = 3, 
       MIXED_COLOR       = 4, 
    }; 
 
    float mixerValue       = 0.3f; 
    unsigned constColorRGBFlag   = BLUE; 

    
    // Create push constant data, this contain a constant

    // color flag and mixer value for non-const color 
    unsigned pushConstants[2]    = {}; 
    pushConstants[0]       = constColorRGBFlag; 
    memcpy(&pushConstants[1], &mixerValue, sizeof(float)); 
 
    // Check if number of push constants does
 
    // not exceed the allowed size 
    int maxPushContantSize = getDevice()->gpuProps. 
                           limits.maxPushConstantsSize; 
 
    if (sizeof(pushConstants) > maxPushContantSize) { 
        assert(0); 
     printf("Push constant size is greater than expected, 
               max allow size is %d", maxPushContantSize); 
    } 
 
    for each (VulkanDrawable* drawableObj in drawableList) 
    { 
        vkCmdPushConstants(cmdPushConstant,  
         drawableObj->pipelineLayout, 
         VK_SHADER_STAGE_FRAGMENT_BIT,  
         0, sizeof(pushConstants), pushConstants); 
    } 
 
    CommandBufferMgr::endCommandBuffer(cmdPushConstant); 
    CommandBufferMgr::submitCommandBuffer(deviceObj->queue, 
         &cmdPushConstant); 
} 

The following is the output rendering the cube geometry with solid colors. In this example, constColor must be 1, 2, or 3 in order to produce the solid color:

Updating the resource data

The following is the output of the original colored cube blended with the mixer value; for this output, constColor must not be 1, 2, or 3:

Updating the resource data

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.7.102