Skip to content

Instantly share code, notes, and snippets.

@Pikachuxxxx
Created July 26, 2021 13:06
Show Gist options
  • Save Pikachuxxxx/136f0a289593390c1a83704624fe7895 to your computer and use it in GitHub Desktop.
Save Pikachuxxxx/136f0a289593390c1a83704624fe7895 to your computer and use it in GitHub Desktop.
My personal Vulkan Notes (Works on my machine!)

Vulkan Tutorial #graphics

Overview of Vulkan Application

Instance A Vulkan instance is needed to interface/talk to the Vulkan library, basically issue commands related to Drawing and Pipeline

  • It Involves creating a VkApplicationInfo struct and then a VkInstanceCreateInfo struct followed by vkCreateInstance to create the instance
  • We can add Instance Layer and Instance Extensions
  • Instance layers are also called validation layers, they are useful in debugging purposes
  • Instance Extensions are also the global extensions, since it’s a platform agnostic in-order to use Vulkan with extra capabilities for that platform we need some extensions, the extension enabled at instance layer are globally available.
  • For Instance, for windows we need VK_EXT_win32_surface and for rendering onto a window surface we need (not in headless mode for benchmarking) we need a extension called VK_KHR_surface to draw to the the window
  • So check for the extensions before creating the instance

[Instance layers and extensions are global and available across all devices(physical and logical)]

Layers == Validation layers => They Validate stuff (Vulkan provides debugging capabilities by means of error and validation layers.)

Validation Layers aka Instance Layers

  • They support debugging at the global level without driver overhead. They apply to all Vulkan calls.
  • We need to enable VK_LAYER_KHRONOS_validation layer during the creation of Instance to enable debugging using validation layers
  • Vulkan does not come with any validation layers built-in, but the LunarG Vulkan SDK provides a nice set of layers that check for common errors.
  • At the beginning, the system is enumerated for global layers and device-specific extensions; these are exposed by the Vulkan driver. The global layers and extensions can be injected into the instance object to be enabled at the global level. However, enabling the extensions only at the device level will enable them only at that specific device.
  • Once we retrieve the layer property information for each layer, we'll use it to iterate through all the layers in order to query the extensions exposed by each layer.
  • VK_LAYER_LUNARG_standard_validation: This enables all the standard layers in the correct order.

Instance level or Global Extensions

  • Vulkan is a platform agnostic API, which means that you need an extension to interface with the window system.
  • Each layer may be capable of supporting one or more extensions. It can be same, the instance level extension can be same but need not be supported by all validation layers

When pLayerName parameter is NULL, only extensions provided by the Vulkan implementation or by implicitly enabled layers are returned. When pLayerName is the name of a layer, the instance extensions provided by that layer are returned. https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkEnumerateInstanceExtensionProperties.html

// TODO: Some examples of Instance Extensions (global + layer)

VK_KHR_surface is an instance level extension, in fact the entire WSI is instance layered to enable common presentation abstracted behaviour

// TODO: Explain about each validation layer and the global extension + layer extensions in detail

Debug callback - use a explicit struct constructor to track issues at instance creation, use bit files comparison to separate different levels of callback messages severity and types

  • Compare with severity and denote that followed by message type first, then message code and message and report the objects count and the actual objects in a nice formatted way (VkDebugUtilsMessengerEXT)
  • Creation and Destruction symbols for this must be dynamically loaded
  • Use VK_EXT_DEBUG_UTILS_EXTENSION_NAME (not a part of Vulkan core API, so we load creation and destroy functions dynamically) is used that encapsulates the VK_EXT_debug_report and VK_EXT_debug_marker extensions together
  • The callback returns a boolean that indicates if the Vulkan call that triggered the validation layer message should be aborted. If the callback returns true, then the call is aborted with the VK_ERROR_VALIDATION_FAILED_EXT error. This is normally only used to test the validation layers themselves, so you should always return VK_FALSE.

Physical Device

Query the available physics GPUs and select one by checking their features and properties

Rating system for physical device selection, check the spec for VkPhysicalDeviceFeatures and VkPhysicalDeviceProperties

  • All commands are deferred in Vulkan they are recorded onto a buffer aka command buffer that are allocated from a pool
  • Now this buffer contains some commands that can be sent to a queue to be executed by the GPU, these queues can exist in parallel and accept only compatible commands
  • By compatible we mean are they draw/compute.transfer commands, they(command buffers with recorded deferred commands) must be sent to right queue
  • We need to find the Queue family that supports rendering and later that has supports to execute presentation commands inorder to present onto the screen
  • So first find the Queue family that supports graphics and then find the queue in that family that supports the graphics related commands we want to execute
  • We query the properties, extension and features along with memory types supported for further evaluation and usage

Logical Device Logical Device in Vulkan is used to allocate resources unlike the instance which is used to draw and manage the pipeline

  • Simple wrapper around the actual GPU with the selection of features we want to use from the GPU
  • We use the logical device to now actually create the Queues now that we know what the GPU can support(resource allocation in action)
  • We pass the indices of the Graphics families that has support we need , graphics related + those that support our commands
  • Enable the device level extensions (such as ray tracing etc, that are not global to the Vulkan API) but depend on the Device and supported by the vendors and 3rd party (software based extensions)
  • These extensions for example include VK_NV_ray_tracing for RTX cards and VK_KHR_swapchain if the GPU has presentation capabilities(could be just a Compute GPU)
  • Device Extensions > instance extensions(usually stagnant and debug related)
  • Pass these two (QueuesCreation details + Selected physical device features) to the Device create info along with the GPU extensions we want to use to create the device object

Queues - The queues are automatically created along with the logical device, but we don't have a handle to interface with them yet. So we store their handles along with the Family indices they belong to.

  • As we have seen that each family has multiple types of queues supported, we get the type of queue we need from that particular family
  • Also for example the graphics queue in family 1 and 3 could have different support, like in family 1 the graphics queue may not have support presentation queue, where as the one in family 3 can support it, then in this case the graphics family index is 0 and present family index is 3, or could be same as well.
  • Btw what kind of other types of queue does a graphics queue can support apart from presentation form now?
  • // TODO: Print the queue features/ explore the spec and API for more details on the queue family type and queue types available

Surface

  • Ofc we have enabled the surface extension (assuming our GPU can actually present to a screen and isn’t just a Compute GPU) we use that extensions features to perform platform agnostic presentation
  • Use the WSI instance level extensions to enable the functionality

Why are surface/WSi instance level extensions and VK_KHR_swapchain is device level extension? (If we can present or make surface don’t we need a swapchain?)

Also Why don’t we no longer need to load the WSI extensions symbols dynamically? Has it changed as the specification was updated?

  • Surface capabilities play a crucial role in selecting the GPU we need to so that they are created right after the instance
  • Although the Vulkan implementation may support window system integration, that does not mean that every device in the system supports it. Therefore we need to extend isDeviceSuitable to ensure that a device can present images to the surface we created.
  • So that’s why instance vs device(it’s available API wide and hence a global extension at instance level)
  • Surface is just a logical abstraction over all platforms or no platforms(Headless mode)
  • // TODO: Explain how headless mode works
  • // TODO: more about how surface helps in drawing stuff (raw capabilities)
  • Since the presentation is a queue-specific (also device specific as well) feature, we find a queue family(graphics queue family to be specific) that supports presenting to the surface we created and create a queue out of it for processing the surface related commands
  • Use vkGetPhysicalDeviceSurfaceSupportKHR to check for presentation support
  • It's actually possible that the queue families supporting drawing commands and the ones supporting presentation do not overlap, but they usually do
  • // TODO: What are the types of Queue Families? Graphics, Compute and Transfer How Queue and Queue Family works?
  • So Every QueueFamily has multiple queue of different types (G, C, T), so since a family can have a graphics queue but they need not support presentation commands, the graphics queue that support those can be in another QueueFamilies graphics queue
  • Automatically deleted, we need not do it explicitly, we only have to take care of the swapchainKHR and delete it explicitly

Swapchain

The swap chain is essentially a queue of images that are waiting to be presented to the screen. Double/Triple or even more buffers can be used to smooth out frame transition and move and frames can be skipped which results in stuttering

So when we are waiting for a pre-made frame to be completely scanned we write to more and more back buffers (assuming it takes faster to write to it than to read, it not the FPS is usually pretty less aka stuttering, which happens inevitably)(ofc it can take more time to scan than to write to framebuffer) we write the next frame to another buffer, if it still takes more time to finish scanning we write to another triple buffer (anything more than 3 is usually more slow) so this was we don’t skip over any new frames because it didn’t finish scanning the previous frames yet.[https://en.wikipedia.org/wiki/Multiple_buffering#Quad_buffering]

[https://youtu.be/bMxNN9dO4cI?t=268] // TODO: Explain the concept from the Chili video right from scan lines to vsync and double/triple/multi buffering // TODO: Explain about multi buffer synchronisation works and how OpenGL chooses stalling vs how we can choose between screen tearing and app stalling while swapping buffers in Vulkan [Write an article]

  • VSync makes us wait until a vertical scan is finished before we flip buffers
  • Not all graphics cards are capable of presenting images directly to a screen for various reasons, for example because they are designed for servers and don't have any display outputs. But they still can have surface capabilities (idk what purpose these surface capabilities provide in this case maybe present it to a headless/imaginary surface for benchmarking or some other buffer to store that data and transmit over network to be presented by the GPU on that network)
  • Just checking if a swap chain is available is not sufficient, because it may not actually be compatible with our window surface
  • We need to check if our GPU can support presenting and then get the swapchain properties such as
    1. Surface capabilities - number of images in the swapchain(whiteout about more than 3?), dimensions of those images
    2. Surface formats supported
    3. Available presentation modes

What’s BGRA and BGRA_UNORM formats?

  • Now that we know what kind swapchain is supported we make one with best features for optimal use just like when we choose some physical device features while making a logical device
  • The surface formats are the color space and image format style used to store the pixel data
  • The presentation mode tells how to show the image on the screen
    • It tells whether we should stall the app(so that the scanning is done and we get another buffer to write onto and the scanning can be done from the waiting frame) or transfer immediately for scanning or to use which back buffer to present that image
    • VK_PRESENT_MODE_IMMEDIATE_KHR: Images submitted by your application are transferred to the screen right away, which may result in tearing.
    • VK_PRESENT_MODE_FIFO_KHR: The swap chain is a queue where the display takes an image from the front of the queue when the display is refreshed and the program inserts rendered images at the back of the queue. If the queue is full then the program has to wait. This is most similar to vertical sync as found in modern games. The moment that the display is refreshed is known as "vertical blank".
    • VK_PRESENT_MODE_FIFO_RELAXED_KHR: This mode only differs from the previous one if the application is late and the queue was empty at the last vertical blank. Instead of waiting for the next vertical blank, the image is transferred right away when it finally arrives. This may result in visible tearing.?????????????????????????????????
    • VK_PRESENT_MODE_MAILBOX_KHR: This is another variation of the second mode. Instead of blocking the application when the queue is full, the images that are already queued are simply replaced with the newer ones. This mode can be used to render frames as fast as possible while still avoiding tearing, resulting in fewer latency issues than standard vertical sync. This is commonly known as "triple buffering", although the existence of three buffers alone does not necessarily mean that the framerate is unlocked.
    • VK_PRESENT_MODE_MAILBOX_KHR : It allows us to avoid tearing while still maintaining a fairly low latency by rendering new images that are as up-to-date as possible right until the vertical blank. So it replaces the last image only if the front image hasn’t been presented for scanning. It might stall while we still write to it if the scaliness are finished, and used the same frame buffer to read again until this Is finished rendering (assuming scanning rendering is that fast) // refresh rate vs app frame rate causes frame to scanline latency
  • The swap extent is the resolution of the swap chain images.
  • Get the desired format, extent and present modes and supply it to the Create Info
  • Next get the image count, support triple buffering and bound check
  • The imageUsage bit field specifies what kind of operations we'll use the images in the swap chain for, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT for color attachment and VK_IMAGE_USAGE_TRANSFER_DST_BIT as the name suggest used to transfer to another destination for post processing
  • We'll be drawing on the images in the swap chain from the graphics queue and then submitting them on the presentation queue (assuming they’re on different queues for maximum compaitability)
  • Hence proper sharing permissions and synchronisation must be done
  • The sharing mode is of 2 types :
    • VK_SHARING_MODE_EXCLUSIVE : An image is owned by one queue family at a time and ownership must be explicitly transferred before using it in another queue family. This option offers the best performance.
    • VK_SHARING_MODE_CONCURRENT : Images can be used across multiple queue families without explicit ownership transfers. concurrent mode requires you to specify at least two distinct queue families.
  • Hence we use exclusive mode if they belong to same queue family or for better performance, ofc we need to specify between which queues the ownership will be shared in advance to the swapchain create Info, combine the queuefamily indices together and pass them if using exclusive mode
  • The compositeAlpha field specifies if the alpha channel should be used for blending with other windows in the window system.
  • If the clipped member is set to VK_TRUE then that means that we don't care about the color of pixels that are obscured, for example because another window is in front of them.

Swapchain Images

  • Now that we have the swapchain to manage the image targets we render stuff onto to, we need those images to actually write data onto them
  • Retrieve the VkImages and also store the swapchain capabilities, format and extents

Image View

An image view is quite literally a view into an image. It describes how to access the image and which part of the image to access.

  • Use the swapchain images to create the views for them, components allows swizzling of color channels, i.e. swap the color channel for the image with final frame buffer
  • Subresource describe what shall we be doing with the image, (we already specified image usage while creating the swapchain) hence these both must match createInfo.subresourceRange.baseMipLevel = 0; ???? (Could be the starting miplevel, usually the largest image miplevel starts from 0 so this is it) createInfo.subresourceRange.levelCount = 1; ???? (Total miplevels for the image view image )

Graphics Pipeline

The input assembler collects the raw vertex data from the buffers you specify and may also use an index buffer to repeat certain elements without having to duplicate the vertex data itself. It assembles the Input data together based on the topology we set (default triangles)

The graphics pipeline in Vulkan is almost completely immutable, so you must recreate the pipeline from scratch if you want to change shaders, bind different framebuffers or change the blend function.

Sign of the Y coordinates is flipped. The Z coordinate now uses the same range as it does in Direct3D, from 0 to 1.

The Vulkan SDK includes libshaderc, which is a library to compile GLSL code to SPIR-V from within your program.

Shaders

  • Convert GLSL into SPIR-V Byte code using glslc or shaderc library and load into a binary blob
  • Create the shader module to contain the blob
  • Use the shader module to create the pipelineshaderStageCreateInfo —> Identifies what type of shader stage this module corresponds to (Vertex, Tessellation, Geometry or Pixel shader)
  • Similar to DirectX = pBlob —> Vertexshader —>VSSetshader(but this is done again) in Vulkan we have an extra stage of creating the shader module and VkPipelineShaderStageCreateInfo is provided later in the pipeline create Info

Fixed Functions

Vertex Input (similar to glVertexAttribPointer)

  • We use vertex descriptors to describe the vertex attributes and bindings
  • Vertex Bindings : spacing between data and whether the data is per-vertex or per-instance
  • Attribute Descriptors : type of the attributes passed to the vertex shader, which binding to load them from and at which offset (index in glVertexArtibPointer, which input variables in GLSL these inverted data correspond to in the shader)
  • In-vertex data alignment —> Attribute, Vertex offset in the Vertex Buffer —> Descriptor

Input Assembly

  • Tells how to assemble input, which topology to use

Viewport and Scissor

  • Viewport : A viewport basically describes the region of the framebuffer that the output will be rendered to. Doesn’t discard anything
  • Scissor : scissor rectangles define in which regions pixels will actually be stored. Hence any pixels outside of scissor will be discarded by the rasterizer
  • Create the viewport state create info

Everything in Graphics Pipeline requires a State Create Info struct to be later used to create the Pipeline

Rasterizer

  • The rasterizer takes the geometry that is shaped by the vertices from the vertex shader and turns it into fragments to be colored by the fragment shader. Converts the pixels from screenspace (NDC) to pixels in the visible screen
  • Also performs depth testing, face culling, occlusion and rejection and polygon fill mode

Multisampling

  • Ummm…. Anti-aliasing we don’t want that do we? For now let’s disable it

Depth and Stencil Testing

  • Later nullptr as of now

Color Blending

  • After a fragment shader has returned a color, it needs to be combined with the color that is already in the framebuffer. This transformation is known as color blending.
  • Tell which color channel bits to write to
  • new_color = src_color * src_color_blend_factor (color_blend_operation{+/-/*//}) dst_color * dst_color_blend_factor
  • new_color_alpha = src_color_alpha * src_color_alpha_blend_factor (alpha_blend_operation{+/-/*//}) dst_color_alpha * dst_color_alpha_blend_factor
  • The factor and operations are defined in the struct
  • There are two types of structs to configure color blending. The first struct, VkPipelineColorBlendAttachmentState contains the configuration per attached framebuffer and the second struct, VkPipelineColorBlendStateCreateInfo contains the global color blending settings.

Pipeline Layout

  • Uniforms in shaders are passed through push constants using this struct object

Render Pass

  • A render pass represents a collection of attachments, subpasses, and dependencies between the subpasses, and describes how the attachments are used over the course of the subpasses. and the rendering work that is performed using them
  • We tell what frame buffer attachments will be used, how man of them and how their contents should be used throughout the rendering. All this is encapsulated in a render pass object
  • Attachment : describes the properties of an attachment including its format, sample count, and how its contents are treated at the beginning and end of each render pass instance.
    • The attachment parameter specifies which attachment to reference by its index in the attachment descriptions array. If the array consists of a single VkAttachmentDescription, its index is 0.
  • Attachment Reference : Every subpass references one or more of the attachments that we've described using the structure in the previous sections. These references are themselves VkAttachmentReference
    • The attachment parameter specifies which attachment to reference by its index in the attachment descriptions array.
  • Subpass : represents a phase of rendering that reads and writes a subset of the attachments in a render pass. Rendering commands are recorded into a particular subpass of a render pass instance.
  • subpass description : describes the subset of attachments that is involved in the execution of a subpass.
  • Render pass and a framebuffer define the complete render target state for one or more subpasses as well as the algorithmic dependencies between the subpasses.
  • A subpass uses an attachment if the attachment is a color, depth/stencil, resolve, depth/stencil resolve, fragment shading rate, or input attachment for that subpass, it doesn’t use that attachment if it marked as preserved

Attachment Creation

  • Firstly we have a single color attachment, provide that followed by the load and store operation that tell what to do with the image in the frame buffer after and before rendering
  • Load op and store op apply to color and depth buffer where as stenciloadop and stencilstoreop apply to stencil buffer
  • The loadOp and storeOp determine what to do with the data in the attachment before rendering and after rendering. We have the following choices for loadOp:
    • VK_ATTACHMENT_LOAD_OP_LOAD: Preserve the existing contents of the attachment
    • VK_ATTACHMENT_LOAD_OP_CLEAR: Clear the values to a constant at the start
    • VK_ATTACHMENT_LOAD_OP_DONT_CARE: Existing contents are undefined; we don't care about them
  • Textures and framebuffers in Vulkan are represented by VkImage objects with a certain pixel format, however the layout of the pixels in memory can change (this done internally by the Vulkan API) based on what you're trying to do with an image
    • VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: Images used as color attachment
    • VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: Images to be presented in the swap chain
    • VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: Images to be used as destination for a memory copy operation
  • The initialLayout specifies which layout the image will have before the render pass begins. The finalLayout specifies the layout to automatically transition to when the render pass finishes.
  • We don’t care what initial layout is, but we wan’t it to be ready for presentation after rendering hence we use the final layout as VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, initial can be either undefined or color attachment optimal (test both and see)
  • Using the VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL for initialLayout caused compatibility issues with command buffer images, that must be properly taken care of

Vulkan will automatically transition the attachment to attachment reference layout ???? What’s the point? AttachmentDescription imagelayouts vs Attachment reference layout? Which will be used? And when? What will take precedence? If separate where are they used?

Render pass collection of subpasses —> Sets rendering options Subpasses —> one or more attachments—> tells how to treat the frame buffer and rendered output before presentation during each subpass

—> Add draw commands go through these subpasses in a render pass and use these attachments to be manipulated by surpass and it’s corresponding attachments

Subpass Represents a phase of rendering that reads and writes a subset of the attachments in a render pass. Rendering commands are recorded into a particular subpass of a render pass instance. These attachments reads and writes to the frame buffer using the render pass render options and

  • Renderpass and subpasses use a bunch of attachments to tell how to treat the frame buffer contents, how to see them, the right way to see them

  • After we set the proper and desired ways to see them we use the draw commands aka rendering commands to manipulate contents(these need the right content format to manipulate them, and those are properly done by multiple combinations of the subpasses)

Subpasses tell in a Cascading way on how to treat the contents of the pipeline at various stages (input binding, color attachments, depth/stencil testing and multisample etc)

Creating the Graphics Pipeline

  • Use the pipeline create info to attach all the shader/fixed function and pipeline layout(push constant aka uniforms) and render passes to the final pipeline object

Drawing

Framebuffers

  • Use the rendepass and swopchian extents and all the attachments to the frame buffer
  • Ofc which combination of them will be used will be decided by the individual subpasses and how they will be used

Command Pool

  • Requires the queue family index so that it can give out command buffer that are compatible by that queue

All commands start with vkCmdXXXX

Command Buffers

  • Drawing operations and memory transfers, are not executed directly using function calls.
  • First allocate the command buffers from the command pool
  • We gave to record all of them into command buffer object and send into the respective queue that supports these commands to execute them
  • Commands buffers that hold the commands are allocated from the command pool
  • We have to record a command buffer for every image in the swap chain
  • The level parameter specifies if the allocated command buffers are primary or secondary command buffers.
    • VK_COMMAND_BUFFER_LEVEL_PRIMARY: Can be submitted to a queue for execution, but cannot be called from other command buffers.
    • VK_COMMAND_BUFFER_LEVEL_SECONDARY: Cannot be submitted directly, but can be called from primary command buffers. Helpful to reuse common operations from primary command buffers.
  • Now being recording onto them, The flags parameter specifies how we're going to use the command buffer. The following values are available:
    • VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT: The command buffer will be rerecorded right after executing it once.
    • VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT: This is a secondary command buffer that will be entirely within a single render pass.
    • VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT: The command buffer can be resubmitted while it is also already pending execution.
  • It's not possible to append commands to a buffer at a later time.

Starting the Render Pass

  • Use a renderpassBeginInfo struct, it takes in the frambufffers and swapchain extent and the clear color
  • The vkCmdBeginRenderPass requires this

Now Bind the pipeline before using the Draw commands

Use vkCmdDraw to draw

End render pass and end recording CommandBuffer

Drawing Frame

  • Acquire an image from the swap chain
  • Execute the command buffer with that image as attachment in the framebuffer
  • Return the image to the swap chain for presentation
  • We need to explicitly synchronise these operations

Synchronization in Vulkan * Semaphore: This synchronizes work across multiple queues or a coarse-grained command buffer submission in a single queue. * Events: Events controls fine-grained synchronization and are applied on a single queue, allowing us to synchronize work within a single command buffer or sequence of command buffers submitted to a single queue. The host can also participate in event-based synchronization. * Fences: These allow synchronization between the host and device. * Pipeline barriers: A pipeline barrier is an inserted instruction that ensures that commands prior to it must be executed before commands specified after it in the command buffer.

Acquiring an image from the swap chain

Back to frame buffer and low-level V-Sync working, so once we render a image we send it for presentation and while that is being scanned we try to write for another image but if that is already rendered and then application is stalled and waits for an image to be given to write onto

So we have a semaphore to know when a image was given to use to draw to it, and then another to tell that we have finished rendering so that we can stop the rendering and draw to another third back buffer

Submitting the command buffer

So we use the imageAvailableSemaphore to wait for the swapchain to give us an image to render onto

  • The first three parameters specify which semaphores to wait on before execution begins and in which stage(s) of the pipeline to wait. We want to wait with writing colors to the image until it's available, so we're specifying the stage of the graphics pipeline that writes to the color attachment. That means that theoretically the implementation can already start executing our vertex shader and such while the image is not yet available.
  • The next two parameters specify which command buffers to actually submit for execution. As mentioned earlier, we should submit the command buffer that binds the swap chain image we just acquired as color attachment.

We can now submit the command buffer to the graphics queue using vkQueueSubmit(already know which commands to execute because the pool was created with that queue index in mind)

Subpass Dependencies ???????????????

  • Remember that the subpasses in a render pass automatically take care of image layout transitions.
  • These transitions are controlled by subpass dependencies, which specify memory and execution dependencies between subpasses

Presentation

  • Provide all the swapchain and semaphores to the creation struct to perform the final presentation

You can also wait for operations in a specific command queue to be finished with vkQueueWaitIdle

// TODO: More about synchornization and Frame in Flight in detail Frames in flight

  • Used more than one back buffer to write onto
  • Use 2 imageAvailableSemaphores to tell that it’s ready to write onto and render is finished while one is being presented/scanned onto the display Fences are used to perform CPU-GPU sync, in this case we wait until the rendering is finished before we submit in to GPU Semaphores help us sync the image acquisition for rendering stuff and fences sync the rendering completion to the frame that is flight/rendering process before we submit it to

Recreating Swapchain

  • Re-create all the resources such as graphics pipeline, swap chain, render pass and commas buffer and pool and re-allocate them and he re-record the commands onto them and submit them again for section and presentation

Vertex bufers

Vertex Data Description to Vulkan

  • A vertex binding describes at which rate to load data from memory throughout the vertices.
  • In the vertex shaders layout (location = x) for every in-vertex attirbute this is passed to Vulkan using the Attribute Descriptiors, this is used Tod describe the internal arrangement of the Vertex data
  • Pass these to the vertex input create info struct so that the Input assembly stage can understand how to assemble the vertex buffer

Buffer Creation

  • Fill the create Info, for the memory requirements fo the buffer pass the buffer and ask for the memory requirements

Graphics cards can offer different types of memory to allocate from. Each type of memory varies in terms of allowed operations and performance characteristics. [Do more research on this! Get more deets]

  • Query for the GPU memory type support and (check what type memory this buffer needs, query for that memory support and get the index and pass this index while creating memory for the buffer)
  • Set the properties type of the memory type while getting the index
  • Ignorer to add data to it, we do it from cpu side, we use vkMapbuffer and it gives us a block of memory and cpu side and we copy data onto it and then unmap it

Staging Buffer

  • It would be inefficient to use the buffer on the CPU side, so we use a intermediate staging buffer on the CPU side to upload the data to and a final vertex buffer that resides on the GPU
  • Then use a copy command move the data from the CPU staging buffer to GPU final vertex buffer whenever we want to update the buffer contents
  • The buffer copy command requires a queue family that supports transfer operations, which is indicated using VK_QUEUE_TRANSFER_BIT
  • Modify QueueFamilyIndices and findQueueFamilies to explicitly look for a queue family with the VK_QUEUE_TRANSFER_BIT bit, but not the VK_QUEUE_GRAPHICS_BIT.
  • // TODO: Finish this!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment