Preparing the drawing object

The preparation of the drawing object is implemented in the prepare() function; this function has already been covered in Chapter 7, Buffer Resource, Render Pass, Framebuffer, and Shaders with SPIR-V. For more information, please refer to the subsection Setting the background color in Render Pass instance under Clearing the background color.

Recording Render Pass commands

The Render Pass instance records the command's single subpass at a time. A Render Pass may contain one or more subpasses. For each subpass, the commands are recorded using the vkCmdBeginRenderPass() and vkCmdEndRenderPass() APIs. These two APIs together define a scope under which iterating through different subpasses will record the commands for that particular subpass.

Beginning Render Pass instance recording

The vkCmdBeginRenderPass() API begins Render Pass instance command recording for a given subpass. The following is the specification:

void vkCmdBeginRenderPass( 
  VkCommandBuffer                commandBuffer, 
  const VkRenderPassBeginInfo*   pRenderPassBegin, 
  VkSubpassContents              contents); 

The vkCmdBeginRenderPass API accepts three parameters. The first parameter—commandBuffer of the VkCommandBuffer type—indicates the command buffer into which the commands are recorded. The second parameter—pRenderPassBegin—is a VkRenderPassBeginInfo type control structure into which Render Pass metadata is passed (more information is provided in the following section). The last parameter is of the VkSubpassContents type and indicates where and how the contents will be recorded in the subpass execution.

The following are the two types of VkSubpassContents:

  • VK_SUBPASS_CONTENTS_INLINE: In this type, the primary command buffer directly records the subpass contents and doesn't permit the secondary command buffer to execute within this subpass
  • VK_SUBPASS_CONTENTS_SECONDARY_COMMAND: Here, the secondary command buffer is invoked through primary command buffers and is responsible for recording the subpass contents

Tip

What are primary and secondary command buffers?

The primary command buffer does not have any parent command buffer. However, the secondary command buffers are always executed from the primary command buffers behaving as its parent. The secondary command buffers are not directly submitted into the device queue; these are recorded into the primary command buffer and executed using the vkCmdExecuteCommands() API.  void vkCmdExecuteCommands(   VkCommandBuffer        commandBuffer,   uint32_t               commandBufferCount,   const VkCommandBuffer* pCommandBuffers); This API takes three arguments. The first argument—commandBuffer (of type Vk CommandBuffer)—is the primary command buffer object handle. The second parameter—commandBufferCount(of typeuint32_t)—indicates the total number of secondary command buffers that needs to be invoked under the primary command buffer. The last parameter—pCommandBuffers (of type VkCommandBuffer*)—specifies a complete list of the secondary command buffer objects to be passed in.

Tip

How are secondary command buffers useful?

Secondary command buffers are useful in recording common operations into modular units. These modular capsules can be attached to any of your desired primary buffer as required. In the absence of the secondary command buffer, such common operations will be recorded as part of the primary buffer, making them bulky and resulting in redundancy pollution.

Let's take a look at the VkRenderPassBeginInfo structure syntax and its parameters:

typedef struct VkRenderPassBeginInfo { 
    VkStructureType        sType; 
    const void*            pNext; 
    VkRenderPass           renderPass; 
    VkFramebuffer          framebuffer; 
    VkRect2D               renderArea; 
    uint32_t               clearValueCount; 
    const VkClearValue*    pClearValues; 
} VkRenderPassBeginInfo; 

The following are the various parameters of the VkRenderPassBeginInfo structure:

Parameters

Description

sType

This is the type information of this control structure. It must be specified as VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO.

pNext

This could be a valid pointer to an extension-specific structure or could be NULL.

renderPass

The Render Pass instance consumes the Render Pass object to begin the recording.

framebuffer

The Render Pass is also associated with a VkFramebuffer object that contains color and depth attachments.

renderArea

This field indicates the rectangular region affected as a result of the Render Pass execution.

clearValueCount

This indicates the number of clear values for color or depth.

pClearValues

This field contains the clear values associated with attachments specified in the framebuffer.

Note

While defining the renderArea in the Render Pass instance, if the rendering region is smaller than the framebuffer, then it may cause a performance penalty. In such case, it's advisable either to keep the render area equal to the framebuffer region or to qualify the granularity for the Render Pass. Render area granularity can be checked using the vkGetRenderAreaGranularity() API.

void vkGetRenderAreaGranularity( 
  VkDevice              device, 
  VkRenderPass          renderPass, 
  VkExtent2D*           pGranularity); 

This API accepts three parameters: the first parameter—device—is the VkDevice that is associated with renderPass; the second parameter is the renderPass object; the last parameter retrieves the granularity size in pGranularity.

Transitioning to the next subpass

In a given Render Pass instance, when a subpass recording is finished, the application can switch or transit to the next subpass using the vkCmdNextSubpass() API.

void vkCmdNextSubpass( 
  VkCommandBuffer      commandBuffer, 
  VkSubpassContents    contents); 

This API accepts two parameters as shown in the following table:

Parameters

Description

commandBuffer

This indicates the command buffer into which the commands are recorded.

contents

This indicates where and how the contents will be provided in the next subpass execution. For more information on VkSubpassContents, please refer to the previous subsection—Beginning the Render Pass instance.

Finishing Render Pass instance recording

The vkCmdEndRenderPass() API ends the Render Pass instance command buffer recording for the subpass that is currently being executed. This API takes one parameter specifying the handle of the command buffer on which the recording must be stopped.

void vkCmdEndRenderPass( 
  VkCommandBuffer commandBuffer); 

Implementation

The current subpass is specified with a clear black color, which will paint the swapchain image with this value, making the background appear black. In addition, other parameters, such as the Render Pass object, framebuffer, and dimension, are also specified. There are many other commands that get executed in the Render Pass instance; this will be discussed in the next section, the following implementation shows the Render Pass instance recording using the vkCmdBeginRenderPass()and vkCmdEndRenderPass() APIs:

void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer* cmdDraw) 
{ 
VulkanDevice* deviceObj= rendererObj->getDevice(); 
// Specify the clear color value 
VkClearValue clearValues[2]; 
clearValues[0].color.float32[0]= 0.0f; 
clearValues[0].color.float32[1]= 0.0f; 
clearValues[0].color.float32[2]= 0.0f; 
clearValues[0].color.float32[3]= 0.0f; 
 
// Specify the depth/stencil clear value 
clearValues[1].depthStencil.depth   = 1.0f; 
clearValues[1].depthStencil.stencil = 0; 
 
// Define the VkRenderPassBeginInfo control structure 
VkRenderPassBeginInfo renderPassBegin; 
renderPassBegin.sType                   = 
   VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 
renderPassBegin.pNext                   = NULL; 
renderPassBegin.renderPass              = rendererObj->renderPass; 
renderPassBegin.framebuffer             = rendererObj->
                                          framebuffers[currentImage]; 
renderPassBegin.renderArea.offset.x     = 0; 
renderPassBegin.renderArea.offset.y     = 0; 
renderPassBegin.renderArea.extent.width = rendererObj->width; 
renderPassBegin.renderArea.extent.height= rendererObj->height; 
renderPassBegin.clearValueCount         = 2; 
renderPassBegin.pClearValues            = clearValues; 
 
// Start recording the render pass instance 
vkCmdBeginRenderPass(*cmdDraw, &renderPassBegin, 
  VK_SUBPASS_CONTENTS_INLINE);
 
// Execute the commands as per requirement 
.  .  .  . 
// pipeline bind, geometry, viewport, scissoring


// End of render pass instance recording 
vkCmdEndRenderPass(*cmdDraw); 
.  .  .  . 
} 

Binding pipeline object

In the Render Pass instance, the first thing we will need to do is bind the pipeline using the vkCmdBindPipeline() API. This API binds a specific pipeline (either Graphics or Compute) with the current command buffer that is using this command.

void vkCmdBindPipeline( 
    VkCommandBuffer         commandBuffer, 
    VkPipelineBindPoint     pipelineBindPoint, 
    VkPipeline              pipeline); 

Parameters

Description

commandBuffer

This indicates the command buffer object (used in Render Pass recording) that will be bound to the pipeline object.

pipelineBindPoint

This field indicates the type of the pipeline binding point to which the pipeline object will be bounded. This field is of type VkPipelineBindPoint and can take one of the following two given values:

typedef enum VkPipelineBindPoint {
VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
VK_PIPELINE_BIND_POINT_COMPUTE = 1,
} VkPipelineBindPoint;

The first value indicates the bind point for graphics pipeline and the second for the compute pipeline.

pipeline

This indicates the pipeline object to which the command buffer will be bounded.

Each pipeline—graphics or compute—is very specific to the commands that it affect once bounded:

  • Compute pipeline: When the pipeline is bound to VK_PIPELINE_BIND_POINT_COMPUTE, only the vkCmdDispatch and vkCmdDispatchIndirect commands behavior can be controlled. Any other command under this pipeline state will remain unaffected. For more information on these commands, please refer to the official Vulkan specification documentation at https://www.khronos.org/registry/vulkan/specs/1.0/xhtml/vkspec.html.
  • Graphics pipeline: When the pipeline is bound to VK_PIPELINE_BIND_POINT_GRAPHICS, the vkCmdDraw, vkCmdDrawIndexed, vkCmdDrawIndirect, and vkCmdDrawIndexedIndirect commands can be controlled. Any other command under this pipeline state will remain unaffected.

Implementation

The following code shows the binding of the graphics pipeline with the existing command buffer object cmdDraw, The pipeline object is connected with the graphics bind point (VK_PIPELINE_BIND_POINT_GRAPHICS):

void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer* cmdDraw){ 
   .  .  .  . 
   // Bound the command buffer with the graphics pipeline 
   vkCmdBindPipeline(*cmdDraw, VK_PIPELINE_BIND_POINT_GRAPHICS, 
   *pipeline); 
   .  .  .  . 
} 

Note

For more information on pipeline creation and the pipeline object specified in the implementation, please refer to Chapter 8, Pipelines and Pipeline State Management.

Specifying drawing object geometry information

The geometry information for the drawing object can be specified using the vertex buffer. Remember, we built the buffer resource in Chapter 7, Buffer Resource, Render Pass, Framebuffer, and Shaders with SPIR-V and stored the vertex information in the VertexBuffer.buf of the VulkanDrawble class.

Note

For more information on , and to recap, vertex buffer building, please refer to the Understanding the buffer resource and Creating geometry with buffer resource section in Chapter 7, Buffer Resource, Render Pass, Framebuffer, and Shaders with SPIR-V.

Vertex data contains vertex position and color information together in an interleaved form. Bind this vertex data to the command buffer under the graphics pipeline state using the vkCmdBindVertexBuffers() API. This command bounds a specific vertex buffer to a command buffer on a per-draw basis.

void vkCmdBindVertexBuffers( 
    VkCommandBuffer                             commandBuffer, 
    uint32_t                                    firstBinding, 
    uint32_t                                    bindingCount, 
    const VkBuffer*                             pBuffers, 
    const VkDeviceSize*                         pOffsets); 

The following table lists the fields and indicates the description of each parameter:

Parameters

Description

commandBuffer

This is the command buffer object into which the vkCmdBindVertexBuffers command will be recorded.

firstBinding

This field indicates the index of the vertex input binding, which will be updated by the command.

bindingCount

This indicates the number of vertex input bindings whose state will be updated by the command.

pBuffers

This field is an array of the VkBuffer vertex buffer handles that are passed into.

pOffsets

This field is an array of vertex buffer offsets.

Implementation

Bind the command buffer object with the necessary information to pick the geometry data using the vkCmdBindVertexBuffer() API; this API takes the vertex buffer information of the drawing object that we are interested in to draw on the display:

void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer* cmdDraw){ 
   .  .  .  . 
   // Bound the vertex buffer with the command buffer 
   vkCmdBindVertexBuffers(*cmdDraw, 0, 1, &VertexBuffer.buf, 
   offsets); 
   .  .  .  . 
} 

Defining a dynamic viewport

A viewport determines the portion of the drawing surface region on which the drawing object primitives will be rendered. In Chapter 8, Pipelines and Pipeline State Management, we learned to manage viewport state under the graphics pipeline in the Viewport management subsection under Understanding the Pipeline State Objects (PSO) and created a pipeline state object. Viewport parameters can be controlled statically or dynamically:

  • Statical control: If the dynamic state VK_DYNAMIC_STATE_VIEWPORT is disabled, then the viewport parameters are not supposed to be changed and specified once the viewport pipeline state object is created using the VkPipelineViewportStateCreateInfo class' member variable pViewport.
  • Dynamical control: On the other hand, when the dynamic state VK_DYNAMIC_STATE_VIEWPORT is enabled while creating the pipeline state object, then the viewport transformation parameters are allowed to be changed at runtime. These parameters can be controlled dynamically at runtime using the vkCmdSetViewport() API. The following is the syntax and description of this API:
void vkCmdSetViewport( 
    VkCommandBuffer   commandBuffer, 
    uint32_t          firstViewport, 
    uint32_t          viewportCount, 
    const VkViewport* pViewports); 

The fields and a description of each parameter follow:

Parameters

Description

commandBuffer

This field specifies the command buffer object that will be used to record this command.

firstViewport

The firstViewport is an index into the internal viewports array, indicating the first viewport that requires to be updated.

viewportCount

These are the total number of viewports in the pViewport whose parameters will be updated by the command.

pViewports

This is a pointer array of the VkViewport structure specifying the dimensions of the viewport region.

typedef struct VkViewport { 
    float    x; 
    float    y; 
    float    width; 
    float    height; 
    float    minDepth; 
    float    maxDepth; 
} VkViewport; 

The fields and a description of each parameter follow:

Parameters

Description

x, y

This is the upper-left corner of the viewport (x, y).

width, height

This indicates the width and height of the viewport.

minDepth, maxDepth

This is the depth range for the viewport. minDepth could be greater than or equal to maxDepth.

Implementation

The viewport is initialized using the initViewport() function by passing the current command buffer object into which the vkCmdSetViewport() command will be recorded. The vkCmdSetViewport() API sets the viewport parameters, which are dynamically set in the viewport region, specifying the upper-left dimension and depth information of the viewable region:

void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer* cmdDraw){ 
   .  .  .  . 
   // Define the dynamic viewport here. 
   initViewports(cmdDraw); 
   .  .  .  . 
} 
 
void VulkanDrawable::initViewports(VkCommandBuffer* cmd) 
{ 
   viewport.height   = (float)rendererObj->height; 
   viewport.width    = (float)rendererObj->width; 
   viewport.minDepth = (float) 0.0f; 
   viewport.maxDepth = (float) 1.0f; 
   viewport.x        = 0; 
   viewport.y        = 0; 
   vkCmdSetViewport(*cmd, 0, NUMBER_OF_VIEWPORTS, &viewport); 
} 

Scissoring

A scissor defines a rectangular region; any framebuffer fragment's location (x, y) falling outside this rectangular region is discarded.

If this pipeline state object is not created with the dynamic state VK_DYNAMIC_STATE_VIEWPORT enabled, then scissor rectangles are controlled using the VkPipelineViewportStateCreateInfo class's member variable pScissors. On the other hand, if the pipeline state object is created with the dynamic state VK_DYNAMIC_STATE_VIEWPORT enabled, then the scissor rectangle parameter can be specified and controlled dynamically using the vkCmdSetScissor() API.

Similar to viewport parameters, scissor parameters can be controlled statically or dynamically:

  • Static control: When viewport parameters are not expected to change, then it means the viewing dimensions are fixed. This can be indicated to the underlying pipeline using dynamic states by disabling the VK_DYNAMIC_STATE_VIEWPORT. Such a case informs the pipeline about the static nature of the viewport, which could be beneficial for decision-making and avoiding any kind of housekeeping that the viewports dynamic factors required. For static viewport configuration, the scissor parameters read from the viewport pipeline state object VkPipelineViewportStateCreateInfo class's member variable pScissors.
  • Dynamical control: On the other hand, if the dynamic state VK_DYNAMIC_STATE_VIEWPORT is enabled, scissor parameters can be changed dynamically and specified through a special API called vkCmdSetViewport(). The following is the syntax and description of this API:
      void vkCmdSetScissor( 
       VkCommandBuffer commandBuffer, 
       uint32_t        firstScissor, 
       uint32_t        scissorCount, 
       const VkRect2D* pScissors); 

The fields and a description of each parameter follow:

Parameters

Description

commandBuffer

This field specifies the command buffer object that will be used to record this command.

firstScissor

The firstScissor is an index to the internal scissors array, indicating the first scissor to be updated.

scissorCount

This is the total number of scissors in the pScissors array, whose parameters will be updated by the command.

pScissors

This is a pointer to an array of the VkRect2D structure specifying the 2D dimensions of the scissor area.

Implementation

Scissoring is initialized using the initScissors() function specifying the non-clipping region. Anything outside this rectangular region will be discarded. The vkCmdSetScissor() API sets the scissoring parameters, which can be dynamically set, indicating the rectangular dimensions used for single or multiple scissoring:

void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer* cmdDraw){ 
   .  .  .  . 
   // Define the scissor here.
initScissors(cmdDraw); 
   .  .  .  . 
} 
void VulkanDrawable::initScissors(VkCommandBuffer* cmd) 
{ 
   scissor.extent.width    = rendererObj->width; 
   scissor.extent.height   = rendererObj->height; 
   scissor.offset.x        = 0; 
   scissor.offset.y        = 0; 
   vkCmdSetScissor(*cmd, 0, NUMBER_OF_SCISSORS, &scissor); 
} 

Draw command

The draw command helps in assembling the primitives. Vulkan supports index- and nonindex-based draw commands. A draw command can affect the framebuffer by the order in which fragments are ordered. In cases where multiple instances of a draw command are used, the API order is used to process the draw commands. For nonindex-based commands, the rule is to put primitives with lowered number instances earlier in the order. For index-based commands, the primitive with a lower number of vertex index values is placed earlier in the API order.

Vulkan renders drawing objects by recording draw commands in the command buffer. There are four different drawing commands available in Vulkan, which are broadly divided into the following two types of categories:

  • The first type (vkCmdDraw and vkCmdDrawIndexed) specifies the drawing parameters in the command buffer object itself
  • In contrast, the second type (vkCmdDrawIndirect and vkCmdDrawIndexedIndirect) uses buffer memory to read the parameters from a drawing API, which is suffixed with the Indirect keyword and is of the latter type; otherwise, it's the former one

vkCmdDraw command

The vkCmdDraw() API reads the drawing parameters from the command buffer; the vertex information is accessed in the form of an array in sequential order, starting from the first vertex (firstVertex) to the total number of vertices specified by the vertexCount. The vkCmdDraw API renders primitives specified by the input assembly state under the pipeline state object using vertex array data information.

This API supports instancing, which allows efficient rendering of an object multiple times without calling multiple draw commands. Such drawing features are very helpful in situations such as crowd simulation, tree rendering, clone patterns, and so on. The total number of drawing instances is specified using instanceCount, starting from the first instance index indicated by firstInstance.

void vkCmdDraw( 
    VkCommandBuffer commandBuffer, 
    uint32_t        vertexCount, 
    uint32_t        instanceCount, 
    uint32_t        firstVertex, 
    uint32_t        firstInstance); 

The fields and a description of each parameter follow:

Parameters

Description

commandBuffer

This field specifies the command buffer object (VkCommandBuffer) into which the recording is performed.

vertexCount

This is the total count of the vertex intended to draw.

instanceCount

This field indicates the total number of instances to be drawn using this command.

firstVertex

This field specifies the very first vertex index from which the vertices are read in order to draw them.

firstInstance

This field specifies the very first instance ID of the instance to draw.

The present example in this chapter makes use of the following command:

vkCmdDraw(*cmdDraw, 3, 1, 0, 0); 

This command consumes the following triangle data, which represents three vertices in the interleaved form, hence the second parameter is specified as 3; since there is only one instance, the third parameter is 1. The drawing should start from the first vertex, which is indicated by index 0 as the fourth parameter. The last parameter is 0, pointing to the first instance ID:

struct VertexWithColor 
    { 
      float x, y, z, w;   // Vertex Position 
      float r, g, b, a;   // Color format Red, Green, Blue, Alpha 
    }; 
 
    static const VertexWithColor triangleData[] = 
    { 
      { 0.0f,  1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0 },/*Vertex0*/ 
      { 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0 },/*Vertex1*/ 
      {-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0 },/*Vertex2*/ 
    }; 

Note

Another type of drawing command used in this chapter is the vkCmdDrawIndexed() API. This API renders indexed geometry. For detailed information, please refer to the Rendering an indexed geometry section at the end of this chapter. But before jumping to this section, you must work through all the remaining sections to understand the rendering of drawing objects in Vulkan.

Implementing drawing object preparation

The drawing object's preparation process is executed inside the recordCommandBuffer function of the VulkanDrawable class. This function records the commands associated with the drawing object for each swapchain buffer in a separate command buffer object (cmdDraw). The process includes the following steps.

Record the Render Pass instance using the vkCmdBeginRenderPass() API; this accepts the VkRenderPassBeginInfo class's object (renderPassBegin) as an input parameter, which contains the Render Pass and framebuffer objects that indicate the attachments, subpasses, and image views associated with this Render Pass instance. For more information on Render Pass and framebuffer objects, please refer to Chapter 7, Buffer Resource, Render Pass, Framebuffer, and Shaders with SPIR-V.

The other information the renderPassBegin carries is the extent of the drawing region on the framebuffer. In addition, the clear values for color, depth, or stencil image are also set inside. This information clears the buffer attachments associated with the specified clear value. For example, the clear value associated with the color buffer attachment works like a background color.

Note

The last parameter passed into the vkCmdBeginRenderPass is VK_SUBPASS_CONTENTS_INLINE; it indicates that only primary command buffers are supposed to record the subpass contents, and within this subpass, the secondary commands will not be executed.

Use vkCmdBindPipeline()and bind the command buffer with the graphics pipeline object that we created in Chapter 8, Pipelines and Pipeline State Management.

For dynamically setting the viewport and scissoring region, use initViewports() and initScissors() and set the vkCmdSetViewport() and vkCmdSetScissor() APIs with the required rectangular region dimensions.

Note

When the vkCmdSetViewport() and vkCmdSetScissor()APIs are used during runtime to specify the viewport and scissor dimensions, the dynamic states (VkDynamicState) must be enabled with VK_DYNAMIC_STATE_VIEWPORT.

Specify the draw command using the non-indexed drawing API vkCmdDraw(). The first argument specifies the command buffer object (VkCommandBuffer) into which the drawing command will be recorded. The second argument 3 specifies the number of vertices the geometry is intended to draw. The third argument 1 specifies that there needs to draw single instance at a time. The fourth argument specifies the first vertex index (0) to draw; the last argument 0 specifies the first index to be used for instance-based drawing responsible for controlling the rate at which data advances from an instanced array.

Finish the Render Pass instance recording using vkCmdEndRenderPass()and passing the current command buffer object into it.

The recording of the command buffer is implemented as follows:

void VulkanDrawable::recordCommandBuffer(int currentImage, VkCommandBuffer* cmdDraw) 
{ 
   VulkanDevice* deviceObj             = rendererObj->getDevice(); 
   VkClearValue clearValues[2]; 
   clearValues[0].color.float32[0]     = 0.0f; 
   clearValues[0].color.float32[1]     = 0.0f; 
   clearValues[0].color.float32[2]     = 0.0f; 
   clearValues[0].color.float32[3]     = 0.0f; 
   clearValues[1].depthStencil.depth   = 1.0f; 
   clearValues[1].depthStencil.stencil = 0; 
 
   VkRenderPassBeginInfo renderPassBegin; 
   renderPassBegin.sType                    = VK_STRUCTURE_TYPE_
                                            RENDER_PASS-_BEGIN_INFO; 
   renderPassBegin.pNext                    = NULL; 
   renderPassBegin.renderPass               = rendererObj->renderPass; 
   renderPassBegin.framebuffer              = rendererObj-> 
                                            framebuffers[currentImage]; 
   renderPassBegin.renderArea.offset.x      = 0; 
   renderPassBegin.renderArea.offset.y      = 0; 
   renderPassBegin.renderArea.extent.width  = rendererObj->width; 
   renderPassBegin.renderArea.extent.height = rendererObj->height; 
   renderPassBegin.clearValueCount          = 2; 
   renderPassBegin.pClearValues             = clearValues; 
 
   // Start recording the render pass instance 
   vkCmdBeginRenderPass(*cmdDraw, &renderPassBegin, 
   VK_SUBPASS_CONTENTS_INLINE); 
 
   // Bound the command buffer with the graphics pipeline 
   vkCmdBindPipeline(*cmdDraw, VK_PIPELINE_BIND_POINT_GRAPHICS, 
   *pipeline); 
 
   // Bound the command buffer with the graphics pipeline 
   const VkDeviceSize offsets[1] = { 0 }; 
   vkCmdBindVertexBuffers(*cmdDraw, 0, 1, &VertexBuffer.buf, 
   offsets); 
 
   // Define the dynamic viewport here 
   initViewports(cmdDraw); 
 
   // Define the scissoring 
   initScissors(cmdDraw); 
 
   // Issue the draw command with 3 vertex, 1 instance starting

   // from first vertex 
   vkCmdDraw(*cmdDraw, 3, 1, 0, 0); 
 
   // End of render pass instance recording 
   vkCmdEndRenderPass(*cmdDraw); 
 
} 
..................Content has been hidden....................

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