Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
The Modern Vulkan Cookbook

You're reading from   The Modern Vulkan Cookbook A practical guide to 3D graphics and advanced real-time rendering techniques in Vulkan

Arrow left icon
Product type Paperback
Published in Apr 2024
Publisher Packt
ISBN-13 9781803239989
Length 334 pages
Edition 1st Edition
Languages
Tools
Concepts
Arrow right icon
Authors (2):
Arrow left icon
Preetish Kakkar Preetish Kakkar
Author Profile Icon Preetish Kakkar
Preetish Kakkar
Mauricio Maurer Mauricio Maurer
Author Profile Icon Mauricio Maurer
Mauricio Maurer
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Chapter 1: Vulkan Core Concepts 2. Chapter 2: Working with Modern Vulkan FREE CHAPTER 3. Chapter 3: Implementing GPU-Driven Rendering 4. Chapter 4: Exploring Techniques for Lighting, Shading, and Shadows 5. Chapter 5: Deciphering Order-Independent Transparency 6. Chapter 6: Anti-Aliasing Techniques 7. Chapter 7: Ray Tracing and Hybrid Rendering 8. Chapter 8: Extended Reality with OpenXR 9. Chapter 9: Debugging and Performance Measurement Techniques 10. Index 11. Other Books You May Enjoy

Implementing MDI and PVP

MDI and PVP are features of modern graphics APIs that allow for greater flexibility and efficiency in vertex processing.

MDI allows issuing multiple draw calls with a single command, each of which derives its parameters from a buffer stored in the device (hence the indirect term). This is particularly useful because those parameters can be modified in the GPU itself.

With PVP, each shader instance retrieves its vertex data based on its index and instance IDs instead of being initialized with the vertex’s attributes. This allows for flexibility because the vertex attributes and their format are not baked into the pipeline and can be changed solely based on the shader code.

In the first sub-recipe, we will focus on the implementation of MDI, demonstrating how this powerful tool can streamline your graphics operations by allowing multiple draw calls to be issued from a single command, with parameters that can be modified directly in the GPU. In the following sub-recipe, we will guide you through the process of setting up PVP, highlighting how the flexibility of this feature can enhance your shader code by enabling changes to vertex attributes without modifying the pipeline.

Implementing MDI

For using MDI, we store all mesh data belonging to the scene in one big buffer for all the meshes’ vertices and another one for the meshes’ indices, with the data for each mesh stored sequentially, as depicted in Figure 2.12.

The drawing parameters are stored in an extra buffer. They must be stored sequentially, one for each mesh, although they don’t have to be provided in the same order as the meshes:

Figure 2.12 – MDI data layout

Figure 2.12 – MDI data layout

We will now learn how to implement MDI using the Vulkan API.

Getting ready

In the repository, we provide a utility function to decompose an EngineCore::Model object into multiple buffers suitable for an MDI implementation, called EngineCore::convertModel2OneBuffer(), located in GLBLoader.cpp.

How to do it…

Let’s begin by looking at the indirect draw parameters’ buffer.

The commands are stored following the same layout as the VkDrawIndexedIndirectCommand structure:

typedef struct VkDrawIndexedIndirectCommand {
    uint32_t    indexCount;
    uint32_t    instanceCount;
    uint32_t    firstIndex;
    int32_t     vertexOffset;
    uint32_t    firstInstance;
} VkDrawIndexedIndirectCommand;

indexCount specifies how many indices are part of this command and, in our case, is the number of indices for a mesh. One command reflects one mesh, so its instanceCount value is one. The firstVertex member is the index of the first index element in the buffer to use for this mesh, while vertexOffset points to the first vertex element in the buffer to use. An example with the correct offsets is shown in Figure 2.12.

Once the vertex, index, and indirect commands buffers are bound, calling vkCmdDrawIndexedIndirect consists of providing the buffer with the indirect commands and an offset into the buffer. The rest is done by the device:

VkCommandBuffer commandBuffer;  // Valid Command Bufer
VkBuffer indirectCmdBuffer;     // Valid buffer w/
                                // indirect commands
uint32_t meshCount;  // Number of indirect commands in
                     // the buffer
uint32_t offset = 0; // Offset into the indirect commands
                     // buffer
vkCmdDrawIndexedIndirect(
    commandBuffer, indirectCmdBuffer, offset,
    meshCount,
    sizeof(VkDrawIndexedIndirectDrawCommand));

In this recipe, we learned how to utilize vkCmdDrawIndexedIndirect, a key function in Vulkan that allows for high-efficiency drawing.

Using PVP

The PVP technique allows vertex data and their attributes to be extracted from buffers with custom code instead of relying on the pipeline to provide them to vertex shaders.

Getting ready

We will use the following structures to perform the extraction of vertex data – the Vertex structure, which encodes the vertex’s position (pos), normal, UV coordinates (uv), and its material index (material):

struct Vertex {
    vec3 pos;
    vec3 normal;
    vec2 uv;
    int material;
};

We will also use a buffer object, referred to in the shader as VertexBuffer:

layout(set = 2, binding = 0) readonly buffer VertexBuffer
{
    Vertex vertices[];
} vertexBuffer;

Next, we will learn how to use the vertexBuffer object to access vertex data.

How to do it…

The shader code used to access the vertex data looks like this:

void main() {
  Vertex vertex = vertexBuffer.vertices[gl_VertexIndex];
}

Note that the vertex and its attributes are not declared as inputs to the shader. gl_VertexIndex is automatically computed and provided to the shader based on the draw call and the parameters recorded in the indirect command retrieved from the indirect command buffer.

Index and vertex buffers

Note that both the index and vertex buffers are still provided and bound to the pipeline before the draw call is issued. The index buffer must have the VK_BUFFER_USAGE_INDEX_BUFFER_BIT flag enabled for the technique to work.

You have been reading a chapter from
The Modern Vulkan Cookbook
Published in: Apr 2024
Publisher: Packt
ISBN-13: 9781803239989
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime