### Vulkan Application Interface Implementation Source: https://github.com/arm-software/vulkan-sdk/blob/master/README.md Example C++ code demonstrating the implementation of the VulkanApplication interface and the MaliSDK::create_application() factory function for new samples. ```cpp #include "framework/application.hpp" #include "framework/context.hpp" #include "framework/common.hpp" #include "framework/assets.hpp" #include "platform/platform.hpp" class MyVulkanApplication : public VulkanApplication { // ... }; VulkanApplication* MaliSDK::create_application() { return new MyVulkanApplication(); } ``` -------------------------------- ### Vulkan Compute Pipeline Layout Bindings Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/basic_compute.dox Sets up descriptor set layout bindings for a Vulkan compute pipeline. This example defines bindings for storage buffers used by the compute shader. ```c VkDescriptorSetLayoutBinding bindings[2] = { { 0 } }; bindings[0].binding = 0; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bindings[0].descriptorCount = 1; bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; bindings[1].binding = 1; bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; bindings[1].descriptorCount = 1; bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; ``` -------------------------------- ### Build Vulkan Samples for Linux Desktop and ARM Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/building_the_samples.dox Commands to build Vulkan samples for different Linux environments. Requires shaderc to be installed for SPIR-V compilation. Includes options for desktop Linux (xcb) and ARMv7 hardfloat Linux (display with a specific toolchain). ```bash git submodule init git submodule update mkdir build cd build # For desktop Linux cmake .. -DPLATFORM=xcb -DTESTS:BOOL=ON # For ARMv7 hardfloat Linux cmake .. -DPLATFORM=display -DTESTS:BOOL=ON -DCMAKE_TOOLCHAIN_FILE=../toolchains/armhf.cmake # Other platforms include wayland, xcb, png (default). make -j8 ctest # Runs all samples for a few seconds. ``` -------------------------------- ### Begin Vulkan Render Pass Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Initiates a Vulkan render pass, specifying clear color values, the target framebuffer, render pass object, and rendering extents. This setup is essential before issuing drawing commands. ```cpp // Set clear color values. VkClearValue clearValue; clearValue.color.float32[0] = 0.1f; clearValue.color.float32[1] = 0.1f; clearValue.color.float32[2] = 0.2f; clearValue.color.float32[3] = 1.0f; // Begin the render pass. VkRenderPassBeginInfo rpBegin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; rpBegin.renderPass = renderPass; rpBegin.framebuffer = backbuffer.framebuffer; rpBegin.renderArea.extent.width = width; rpBegin.renderArea.extent.height = height; rpBegin.clearValueCount = 1; rpBegin.pClearValues = &clearValue; vkCmdBeginRenderPass(cmd, &rpBegin, VK_SUBPASS_CONTENTS_INLINE); ``` -------------------------------- ### Recreate Swapchain with Old Swapchain Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Handles the recreation of a Vulkan swapchain when it becomes outdated, for example, due to window resizing. It reuses the old swapchain handle to efficiently create a new one and then destroys the old one. ```cpp VkSwapchainCreateInfoKHR info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; ... info.oldSwapchain = oldSwapchain; VK_CHECK(fpCreateSwapchainKHR(device, &info, nullptr, &swapchain)); if (oldSwapchain != VK_NULL_HANDLE) fpDestroySwapchainKHR(device, oldSwapchain, nullptr); ``` -------------------------------- ### Load Mipmapped Texture with Pre-generated Mipmaps Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/mipmapping.dox Example function call to load a texture with pre-generated mipmaps by providing a vector of paths to the different mip level image assets. ```cpp // Load texture with pre-generated mipmaps. vector pPaths = { "textures/T_Speaker_512.png", "textures/T_Speaker_256.png", "textures/T_Speaker_128.png", "textures/T_Speaker_64.png", "textures/T_Speaker_32.png", "textures/T_Speaker_16.png", "textures/T_Speaker_8.png", "textures/T_Speaker_4.png", "textures/T_Speaker_2.png", "textures/T_Speaker_1.png" }; textures[0] = createMipmappedTextureFromAssets(pPaths); ``` -------------------------------- ### Create Depth Buffer Image Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/spinning_cube.dox Create a `VkImage` for the depth buffer using `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT` and `VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT`. This setup is suitable for depth buffers that are cleared at the start and discarded at the end of a subpass, potentially allowing for memory optimizations. ```c static const VkFormat depthBufferFormat = VK_FORMAT_D16_UNORM; VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.format = depthBufferFormat; imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.extent.depth = 1; imageInfo.mipLevels = 1; imageInfo.arrayLayers = 1; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VK_CHECK(vkCreateImage(device, &imageInfo, nullptr, &depthBufferImage)); ``` -------------------------------- ### Get Swapchain Images Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Retrieves the images associated with a Vulkan swapchain. This is necessary to know which images can be rendered to. The number of images is first queried, then the images themselves are fetched. ```cpp uint32_t imageCount; VK_CHECK(fpGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr)); swapchainImages.resize(imageCount); VK_CHECK(fpGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data())); ``` -------------------------------- ### Creating a Vulkan Instance Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Initialize a Vulkan instance, which is the first entry point into Vulkan, by providing application and instance creation information. ```c++ VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; app.pApplicationName = "Mali SDK"; app.applicationVersion = 0; app.pEngineName = "Mali SDK"; app.engineVersion = 0; // API version used. What matters for compatibility is major (1) and minor (0) versions. app.apiVersion = VK_MAKE_VERSION(1, 0, 13); VkInstanceCreateInfo instanceInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; instanceInfo.pApplicationInfo = &app; if (useInstanceExtensions) { instanceInfo.enabledExtensionCount = requiredInstanceExtensions.size(); instanceInfo.ppEnabledExtensionNames = requiredInstanceExtensions.data(); } VkResult res = vkCreateInstance(&instanceInfo, nullptr, &instance); ``` -------------------------------- ### Build Samples for Desktop Linux Source: https://github.com/arm-software/vulkan-sdk/blob/master/README.md Builds samples for desktop Linux using CMake and Make. This process generates PNG images by default, useful for development and screenshots. It supports X11 or Wayland backends via CMake flags. ```bash mkdir build cd build cmake .. make -j8 ``` ```bash cmake .. -DPLATFORM=wayland # or xcb for X11 ``` -------------------------------- ### Add New Sample Structure Source: https://github.com/arm-software/vulkan-sdk/blob/master/README.md Steps to create a new sample based on an existing one. This involves copying files, updating CMakeLists.txt, and modifying Android manifest and string resources. ```bash cd samples $EDITOR CMakeLists.txt # add_subdirectory(newsample) mkdir newsample cp -r hellotriangle/{CMakeLists.txt,app,build.gradle,settings.gradle} newsample/ $EDITOR CMakeLists.txt # Edit add_sample $EDITOR app/AndroidManifest.xml # Edit manifest:package $EDITOR app/res/values/strings.xml # Edit resources:string ``` -------------------------------- ### Begin Frame for Fence and Command Managers Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Initializes the frame's resources, including waiting for and resetting fences, and preparing command managers for new commands. ```cpp void Context::PerFrame::beginFrame() { fenceManager.beginFrame(); commandManager.beginFrame(); for (auto &pManager : secondaryCommandManagers) pManager->beginFrame(); } ``` ```cpp void FenceManager::beginFrame() { // If we have outstanding fences for this swapchain image, wait for them to complete first. // Normally, this doesn't really block at all, // since we're waiting for old frames to have been completed, but just in case. if (count != 0) { vkWaitForFences(device, count, fences.data(), true, UINT64_MAX); vkResetFences(device, count, fences.data()); } count = 0; } ``` -------------------------------- ### Handling Window Initialization in NativeActivity Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Callback function to handle Android system events, specifically the APP_CMD_INIT_WINDOW command to obtain the ANativeWindow handle. ```c++ static void engineHandleCmd(android_app *pApp, int32_t cmd) { switch (cmd) { case APP_CMD_INIT_WINDOW: ANativeWindow *pWindow = state->pApp->window; // Pass pWindow on to the application somehow. break; } } ``` -------------------------------- ### Define Vertex Attributes and Binding Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Specifies the vertex attributes (Position and Color) and the vertex buffer binding description, including format and offset. This setup is crucial for the vertex shader to correctly interpret incoming vertex data. ```c++ // Specify our two attributes, Position and Color. VkVertexInputAttributeDescription attributes[2] = { { 0 } }; attributes[0].location = 0; // Position in shader specifies layout(location = 0) to link with this attribute. attributes[0].binding = 0; attributes[0].format = VK_FORMAT_R32G32B32A32_SFLOAT; attributes[0].offset = 0; attributes[1].location = 1; // Color in shader specifies layout(location = 1) to link with this attribute. attributes[1].binding = 0; attributes[1].format = VK_FORMAT_R32G32B32A32_SFLOAT; attributes[1].offset = 4 * sizeof(float); // We have one vertex buffer, with stride 8 floats (vec4 + vec4). VkVertexInputBindingDescription binding = { 0 }; binding.binding = 0; binding.stride = sizeof(Vertex); binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; ``` -------------------------------- ### Vulkan Subpass Description for MSAA Resolve Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/multisampling.dox Defines a VkSubpassDescription for a render pass that includes both a multisampled color attachment and a non-multisampled resolve attachment. This setup enables the efficient resolve of multisampled data to the backbuffer at the end of the subpass. ```c++ // We have one subpass. // This subpass has 2 color attachments. First is multisampled, other is not. VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; VkAttachmentReference resolveRef = { 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; VkSubpassDescription subpass = { 0 }; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; // At end of sub-pass, resolve the multisampled color to backbuffer. subpass.pColorAttachments = &colorRef; subpass.pResolveAttachments = &resolveRef; // Finally, create the renderpass. VkRenderPassCreateInfo rpInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; rpInfo.attachmentCount = 2; rpInfo.pAttachments = attachments; rpInfo.subpassCount = 1; rpInfo.pSubpasses = &subpass; VK_CHECK(vkCreateRenderPass(pContext->getDevice(), &rpInfo, nullptr, &renderPass)); ``` -------------------------------- ### Create Vulkan Application Instance Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox This function is called to create an instance of the Vulkan application. It's part of the sample structure where the main loop is external. ```cpp VulkanApplication *MaliSDK::createApplication() { return new HelloTriangle(); } ``` -------------------------------- ### Add Static Library Source: https://github.com/arm-software/vulkan-sdk/blob/master/framework/CMakeLists.txt Creates a static library named 'framework' using the source and header files found by globbing. Ensure all necessary source files are included. ```cmake add_library(framework STATIC ${sources} ${sources-headers} ${device-sources} ${device-sources-headers}) ``` -------------------------------- ### Initialize and Update Git Submodules Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/building_the_samples.dox Ensures all necessary submodules are initialized and updated before building. This is a prerequisite for building the samples. ```bash git submodule init git submodule update ``` -------------------------------- ### Begin Secondary Command Buffer Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/multithreading.dox Configures and begins a secondary command buffer, specifying usage flags and inheritance information. This includes the render pass, framebuffer, and subpass details. ```cpp VkCommandBufferBeginInfo secondaryBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkCommandBufferInheritanceInfo inheritance = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO }; secondaryBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; secondaryBeginInfo.pInheritanceInfo = &inheritance; inheritance.renderPass = renderPass; inheritance.framebuffer = backbuffer.framebuffer; inheritance.subpass = 0; vkBeginCommandBuffer(secondaryCmd, &secondaryBeginInfo); ``` -------------------------------- ### Initialize Pipeline Layout Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/rotating_texture.dox Creates a Vulkan descriptor set layout and pipeline layout. This involves defining bindings for uniform buffers and image samplers, specifying their types, counts, and shader stages. ```cpp void RotatingTexture::initPipelineLayout() { VkDevice device = pContext->getDevice(); VkDescriptorSetLayoutBinding bindings[2] = { { 0 } }; bindings[0].binding = 0; bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; bindings[0].descriptorCount = 1; bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; bindings[1].binding = 1; bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; bindings[1].descriptorCount = 1; bindings[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; info.bindingCount = 2; info.pBindings = bindings; VK_CHECK(vkCreateDescriptorSetLayout(device, &info, nullptr, &setLayout)); VkPipelineLayoutCreateInfo layoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; layoutInfo.setLayoutCount = 1; layoutInfo.pSetLayouts = &setLayout; VK_CHECK(vkCreatePipelineLayout(device, &layoutInfo, nullptr, &pipelineLayout)); } ``` -------------------------------- ### Begin Render Pass with Secondary Command Buffers Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/multithreading.dox Initiates a render pass, specifying that secondary command buffers will be used for submitting work. This allows for parallel command buffer generation. ```cpp vkCmdBeginRenderPass(cmd, &rpBegin, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); unsigned numThreads = threadPool.getWorkerThreadCount(); vector commandBuffers(numThreads); for (unsigned i = 0; i < numThreads; i++) { VkCommandBuffer secondaryCmd = pContext->requestSecondaryCommandBuffer(i); commandBuffers[i] = secondaryCmd; ... } ``` -------------------------------- ### Create Vulkan Compute Pipeline Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/basic_compute.dox Initializes and creates a Vulkan compute pipeline. This involves setting up the pipeline layout, descriptor sets, and shader stage information. ```c initComputePipelineLayout(); initComputeDescriptorSet(); VkComputePipelineCreateInfo info = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; info.stage.module = loadShaderModule(device, "shaders/particle.comp.spv"); info.stage.pName = "main"; info.layout = computePipeline.pipelineLayout; VK_CHECK(vkCreateComputePipelines(device, pipelineCache, 1, &info, nullptr, &computePipeline.pipeline)); // Pipeline is baked, we can delete the shader module now. vkDestroyShaderModule(device, info.stage.module, nullptr); ``` -------------------------------- ### Enable Validation Layers in Instance Creation (C++) Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/validation_layers.dox Configures the `VkInstanceCreateInfo` structure to enable the selected validation layers. This should only be done if validation layers were successfully found and enabled. ```cpp #if ENABLE_VALIDATION_LAYERS if (!activeLayers.empty()) { instanceInfo.enabledLayerCount = activeLayers.size(); instanceInfo.ppEnabledLayerNames = activeLayers.data(); LOGI("Using Vulkan instance validation layers.\n"); } #endif ``` -------------------------------- ### Initialize Vulkan Application and Vertex Buffer Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Initializes the Vulkan application context, creates the vertex buffer for the triangle, and sets up a pipeline cache for reusable compiled pipelines. ```cpp bool HelloTriangle::initialize(Context *pContext) { this->pContext = pContext; // Create the vertex buffer. initVertexBuffer(); // Create a pipeline cache (although we'll only create one pipeline). VkPipelineCacheCreateInfo pipelineCacheInfo = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VK_CHECK(vkCreatePipelineCache(pContext->getDevice(), &pipelineCacheInfo, nullptr, &pipelineCache)); return true; } ``` -------------------------------- ### Create Vulkan Swapchain Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Initializes the creation of a Vulkan swapchain. This involves setting up the VkSwapchainCreateInfoKHR structure with the target surface and other necessary parameters. ```cpp VkSwapchainCreateInfoKHR info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; info.surface = surface; ... VK_CHECK(fpCreateSwapchainKHR(device, &info, nullptr, &swapchain)); ``` -------------------------------- ### Adding Static Library Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/png/CMakeLists.txt Defines a static library named 'platform-png' using the discovered source and header files. ```cmake add_library(platform-png STATIC ${sources} ${sources-headers}) ``` -------------------------------- ### Image Memory Barrier Transitions for Mipmapping Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/mipmapping.dox Demonstrates the image memory barrier transitions required for mipmap generation. This includes transitioning previous mip levels to SHADER_READ_ONLY_OPTIMAL and current levels to TRANSFER_SRC_OPTIMAL or SHADER_READ_ONLY_OPTIMAL. ```C++ // Transition the previous mip level into a SHADER_READ_ONLY_OPTIMAL layout. imageMemoryBarrier(cmd, image, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, i - 1, 1); if (i + 1 < mipLevelCount) { // Transition the current mip level into a TRANSFER_SRC_OPTIMAL layout, to be used as the source for the next one. imageMemoryBarrier(cmd, image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, i, 1); } else { // If this is the last iteration of the loop, transition the mip level directly to a SHADER_READ_ONLY_OPTIMAL layout. imageMemoryBarrier(cmd, image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, i, 1); } ``` -------------------------------- ### Creating a Vulkan Device Queue Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Define the creation information for a Vulkan device queue, specifying the queue family index and priority. ```c++ static const float one = 1.0f; VkDeviceQueueCreateInfo queueInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; queueInfo.queueFamilyIndex = graphicsQueueIndex; queueInfo.queueCount = 1; queueInfo.pQueuePriorities = &one; ``` -------------------------------- ### Enable Validation Layers in Device Creation (C++) Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/validation_layers.dox Configures the `VkDeviceCreateInfo` structure to enable the selected validation layers for the logical device. This follows the same logic as enabling instance layers. ```cpp activeLayers.clear(); // On desktop, the LunarG loader exposes a meta-layer that combines all // relevant validation layers. addSupportedLayers(activeLayers, deviceLayers, pMetaLayers, NELEMS(pMetaLayers)); // On Android, add all relevant layers one by one. if (activeLayers.empty()) { addSupportedLayers(activeLayers, deviceLayers, pValidationLayers, NELEMS(pValidationLayers)); } #if ENABLE_VALIDATION_LAYERS if (!activeLayers.empty()) { deviceInfo.enabledLayerCount = activeLayers.size(); deviceInfo.ppEnabledLayerNames = activeLayers.data(); LOGI("Using Vulkan device validation layers.\n"); } #endif ``` -------------------------------- ### Create Image Views and Framebuffers Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Creates VkImageViews and VkFramebuffers for each swapchain image. Image views define how to interpret an image, and framebuffers link these views to a render pass for rendering. ```c++ for (auto image : newBackbuffers) { // Create an image view which we can render into. VkImageViewCreateInfo view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; view.viewType = VK_IMAGE_VIEW_TYPE_2D; view.format = dim.format; view.image = image; view.subresourceRange.baseMipLevel = 0; view.subresourceRange.baseArrayLayer = 0; view.subresourceRange.levelCount = 1; view.subresourceRange.layerCount = 1; view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view.components.r = VK_COMPONENT_SWIZZLE_R; view.components.g = VK_COMPONENT_SWIZZLE_G; view.components.b = VK_COMPONENT_SWIZZLE_B; view.components.a = VK_COMPONENT_SWIZZLE_A; VK_CHECK(vkCreateImageView(device, &view, nullptr, &backbuffer.view)); // Build the framebuffer. VkFramebufferCreateInfo fbInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; fbInfo.renderPass = renderPass; fbInfo.attachmentCount = 1; fbInfo.pAttachments = &backbuffer.view; fbInfo.width = width; fbInfo.height = height; fbInfo.layers = 1; VK_CHECK(vkCreateFramebuffer(device, &fbInfo, nullptr, &backbuffer.framebuffer)); backbuffers.push_back(backbuffer); } ``` -------------------------------- ### Discover Source and Header Files Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/android/CMakeLists.txt Dynamically finds all .cpp and .hpp files in the current directory for inclusion in the library. ```cmake file(GLOB sources *.cpp) file(GLOB sources-headers *.hpp) ``` -------------------------------- ### Create Vulkan Device Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Configures and creates a Vulkan logical device. Ensure necessary extensions and features are enabled before creation. Load device-specific symbols after successful creation. ```cpp VkPhysicalDeviceFeatures features = { false }; VkDeviceCreateInfo deviceInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; deviceInfo.queueCreateInfoCount = 1; deviceInfo.pQueueCreateInfos = &queueInfo; if (useDeviceExtensions) { deviceInfo.enabledExtensionCount = requiredDeviceExtensions.size(); deviceInfo.ppEnabledExtensionNames = requiredDeviceExtensions.data(); } deviceInfo.pEnabledFeatures = &features; VK_CHECK(vkCreateDevice(gpu, &deviceInfo, nullptr, &device)); if (FAILED(loadDeviceSymbols())) return RESULT_ERROR_GENERIC; vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue); ``` -------------------------------- ### Configure Wait Semaphore and Stage Mask Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Sets up the wait semaphore and destination stage mask for submitting a command buffer. Ensures rendering stages wait for the semaphore. ```c const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; info.waitSemaphoreCount = acquireSemaphore != VK_NULL_HANDLE ? 1 : 0; info.pWaitSemaphores = &acquireSemaphore; info.pWaitDstStageMask = &waitStage; ``` -------------------------------- ### Create Optimal Tiled Texture Image Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/rotating_texture.dox Creates a 2D Vulkan image with optimal tiling for sampling and transfer operations. The image format and usage flags should be set appropriately. ```cpp // We will transition the actual texture into a proper layout before transfering any data, so leave it as undefined. VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; info.imageType = VK_IMAGE_TYPE_2D; info.format = VK_FORMAT_R8G8B8A8_UNORM; info.extent.width = width; info.extent.height = height; info.extent.depth = 1; info.mipLevels = 1; info.arrayLayers = 1; info.samples = VK_SAMPLE_COUNT_1_BIT; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.tiling = VK_IMAGE_TILING_OPTIMAL; info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Create texture. VK_CHECK(vkCreateImage(device, &info, nullptr, &image)); ``` -------------------------------- ### Enumerate Instance Layer Properties (C++) Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/validation_layers.dox Queries the Vulkan instance for available layer properties. This is a prerequisite for enabling specific validation layers. ```cpp uint32_t instanceLayerCount; VK_CHECK(vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr)); vector instanceLayers(instanceLayerCount); VK_CHECK(vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers.data())); ``` -------------------------------- ### Linking Libraries Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/png/CMakeLists.txt Links the 'platform-png' library against 'framework' and 'platform-asset-manager'. ```cmake target_link_libraries(platform-png framework platform-asset-manager) ``` -------------------------------- ### Submit Swapchain Command Buffer Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Submits a command buffer that interacts with the swapchain, ensuring proper synchronization using Vulkan semaphores. It waits for the swapchain acquire semaphore and signals the swapchain release semaphore upon completion. ```cpp void Context::submitSwapchain(VkCommandBuffer cmd) { submitCommandBuffer(cmd, getSwapchainAcquireSemaphore(), getSwapchainReleaseSemaphore()); } ``` -------------------------------- ### Link Platform Libraries Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/CMakeLists.txt Links the 'platform' library with 'framework' and a platform-specific library. Also links 'platform-wsi' with 'vulkan-stub' and 'platform-asset-manager' with 'framework'. ```cmake target_link_libraries(platform framework platform-${PLATFORM}) target_link_libraries(platform-wsi vulkan-stub) target_link_libraries(platform-asset-manager framework) ``` -------------------------------- ### Draw Calls with Instancing Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/multithreading.dox This snippet demonstrates how to issue multiple draw calls for instanced rendering, optimizing for scenarios with many instances per draw call. It binds descriptor sets and then iterates to draw. ```cpp vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr); for (unsigned baseInstance = beginInstance; baseInstance < endInstance;) { unsigned instancesToDraw = glm::min(endInstance - baseInstance, unsigned(MAX_INSTANCES_PER_DRAW_CALL)); vkCmdDraw(cmd, 4, instancesToDraw, 0, baseInstance); baseInstance += instancesToDraw; } ``` -------------------------------- ### Set Include Directories Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/android/CMakeLists.txt Specifies include paths for NDK-provided native app glue and CPU features, making their headers available during compilation. ```cmake target_include_directories(platform-android PRIVATE ${ANDROID_NDK}/sources/android/native_app_glue ${ANDROID_NDK}/sources/android/cpufeatures) ``` -------------------------------- ### Create Sampler Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/rotating_texture.dox Creates a Vulkan sampler object with bilinear filtering and clamp-to-edge addressing modes. This sampler defines how the texture will be sampled in the shader. ```cpp // Finally, create a sampler. VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; samplerInfo.magFilter = VK_FILTER_LINEAR; samplerInfo.minFilter = VK_FILTER_LINEAR; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.mipLodBias = 0.0f; samplerInfo.maxAnisotropy = 1.0f; samplerInfo.compareEnable = false; samplerInfo.minLod = 0.0f; samplerInfo.maxLod = 0.0f; VkSampler sampler; VK_CHECK(vkCreateSampler(device, &samplerInfo, nullptr, &sampler)); ``` -------------------------------- ### Define Platform WSI Static Library Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/CMakeLists.txt Defines a static library for Window System Integration (WSI) with its specific source and header files. ```cmake add_library(platform-wsi STATIC wsi/wsi.cpp wsi/wsi.hpp) ``` -------------------------------- ### Present Swapchain Image Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Presents a rendered swapchain image to the screen. This function takes the index of the image that has been rendered to and waits on a release semaphore before presenting. It handles suboptimal or outdated swapchain conditions. ```cpp Result WSIPlatform::presentImage(unsigned index) { VkResult result; VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; present.swapchainCount = 1; present.pSwapchains = &swapchain; present.pImageIndices = &index; present.pResults = &result; present.waitSemaphoreCount = 1; present.pWaitSemaphores = &pContext->getSwapchainReleaseSemaphore(); VkResult res = fpQueuePresentKHR(queue, &present); if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) return RESULT_ERROR_OUTDATED_SWAPCHAIN; else if (res != VK_SUCCESS) return RESULT_ERROR_GENERIC; else return RESULT_SUCCESS; } ``` -------------------------------- ### Map and Dump Data to Buffer Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox This snippet shows how to map a Vulkan buffer's memory, copy initial data into it using memcpy, and then unmap the memory. It's a common way to upload data to GPU buffers. ```cpp // Map the memory and dump data in there. if (pInitialData) { void *pData; VK_CHECK(vkMapMemory(device, buffer.memory, 0, size, 0, &pData)); memcpy(pData, pInitialData, size); vkUnmapMemory(device, buffer.memory); } ``` -------------------------------- ### Select and Enable Validation Layers (C++) Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/validation_layers.dox Selects available validation layers based on platform (desktop meta-layer vs. Android individual layers) and logs whether they were found. This logic is used for both instance and device layer selection. ```cpp { // On desktop, the LunarG loader exposes a meta-layer that combines all // relevant validation layers. vector activeLayers; addSupportedLayers(activeLayers, instanceLayers, pMetaLayers, NELEMS(pMetaLayers)); // On Android, add all relevant layers one by one. if (activeLayers.empty()) { addSupportedLayers(activeLayers, instanceLayers, pValidationLayers, NELEMS(pValidationLayers)); } if (activeLayers.empty()) LOGI("Did not find validation layers.\n"); else LOGI("Found validation layers!\n"); } ``` -------------------------------- ### Create Pipeline Layout with Push Constant Support Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/spinning_cube.dox Configure `VkPipelineLayoutCreateInfo` to include push constant ranges. This involves defining `VkPushConstantRange` specifying the shader stage, offset, and size of the push constant data. ```c VkPipelineLayoutCreateInfo layoutInfo; ... // Setup the push constants. It's a single mat4 in the vertex shader. VkPushConstantRange pushConstantInfo = { 0 }; pushConstantInfo.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; pushConstantInfo.offset = 0; pushConstantInfo.size = sizeof(mat4); layoutInfo.pushConstantRangeCount = 1; layoutInfo.pPushConstantRanges = &pushConstantInfo; ``` -------------------------------- ### Create Vulkan Surface for Android Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Creates a Vulkan surface compatible with Android windows. This function retrieves the necessary function pointer for vkCreateAndroidSurfaceKHR and uses the provided native window to create the surface. ```cpp VkSurfaceKHR AndroidPlatform::createSurface() { VkSurfaceKHR surface; auto fpCreateAndroidSurfaceKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR")); if (!fpCreateAndroidSurfaceKHR) return VK_NULL_HANDLE; VkAndroidSurfaceCreateInfoKHR info = { VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; info.window = pNativeWindow; VK_CHECK(fpCreateAndroidSurfaceKHR(instance, &info, nullptr, &surface)); return surface; } ``` -------------------------------- ### Complete Render Pass Initialization with Depth Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/spinning_cube.dox Completes the VkRenderPassCreateInfo by including the depth buffer attachment description. This ensures the render pass is aware of all attachments. ```c++ VkRenderPassCreateInfo rpInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; rpInfo.attachmentCount = 2; rpInfo.pAttachments = attachments; rpInfo... ``` -------------------------------- ### Generating Initial Particle Data Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/basic_compute.dox This code generates randomized initial positions, velocities, and colors for particles. It then creates Vulkan buffers for this data, suitable for use as vertex and storage buffers. ```cpp uniform_real_distribution uniform(-1.0f, 1.0f); mt19937 engine; for (unsigned i = 0; i < NUM_PARTICLES; i++) { positions.push_back(vec2(0.2f * uniform(engine), 0.2f * uniform(engine))); float velocity = 0.008f + 0.003f * uniform(engine); float angle = 100.0f * uniform(engine); velocities.push_back(velocity * vec2(glm::cos(angle), glm::sin(angle))); float y = 0.8f + 0.2f * uniform(engine); float saturation = 0.8f + 0.2f * uniform(engine); float hue = 100.0f * uniform(engine); float u = saturation * glm::cos(hue); float v = saturation * glm::sin(hue); vec3 rgb = mat3(1.0f, 1.0f, 1.0f, 0.0f, -0.39465f, 2.03211f, 1.13983f, -0.58060f, 0.0f) * vec3(y, u, v); colors.push_back(vec4(rgb, 0.4f)); } positionBuffer = createBuffer(positions.data(), positions.size() * sizeof(vec2), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); velocityBuffer = createBuffer(velocities.data(), velocities.size() * sizeof(vec2), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); colorBuffer = createBuffer(colors.data(), colors.size() * sizeof(vec4), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); ``` -------------------------------- ### Set Public and Private Include Directories for Platform Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/CMakeLists.txt Configures include directories for the 'platform' library. Public directories are accessible to targets linking to 'platform', while private directories are only for internal use. ```cmake target_include_directories(platform PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include) ``` -------------------------------- ### Copy and Transition First Mip Level Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/mipmapping.dox Copies the first mip level from staging buffer to the image and transitions its layout from TRANSFER_DST_OPTIMAL to TRANSFER_SRC_OPTIMAL, preparing it for mipmap generation. ```cpp VkBufferImageCopy region = {}; region.bufferOffset = 0; region.bufferRowLength = mipLevels[0].width; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.mipLevel = 0; region.imageSubresource.layerCount = 1; region.imageExtent.width = mipLevels[0].width; region.imageExtent.height = mipLevels[0].height; region.imageExtent.depth = 1; // Copy the buffer for the first mip level to our optimally tiled image. vkCmdCopyBufferToImage(cmd, mipLevels[0].stagingBuffer.buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); // Transition first mip level into a TRANSFER_SRC_OPTIMAL layout. // We need to wait for first CopyBuffer to complete before we can transition away from TRANSFER_DST_OPTIMAL, so use VK_PIPELINE_STAGE_TRANSFER_BIT as the srcStageMask. imageMemoryBarrier(cmd, image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 0, 1); ``` -------------------------------- ### Create Vulkan Buffer Object Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Creates a Vulkan buffer with specified usage flags and size. This is the first step before allocating memory for the buffer. ```cpp Buffer buffer; VkDevice device = pContext->getDevice(); VkBufferCreateInfo info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; info.usage = usage; info.size = size; VK_CHECK(vkCreateBuffer(device, &info, nullptr, &buffer.buffer)); ``` -------------------------------- ### Query Layer Extensions (C++) Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/validation_layers.dox Iterates through available instance layers to query and collect their supported extensions. Useful for checking if layers expose specific functionalities like VK_EXT_debug_report. ```cpp // A layer could have VK_EXT_debug_report extension. for (auto &layer : instanceLayers) { uint32_t count; VK_CHECK(vkEnumerateInstanceExtensionProperties(layer.layerName, &count, nullptr)); vector extensions(count); VK_CHECK(vkEnumerateInstanceExtensionProperties(layer.layerName, &count, extensions.data())); for (auto &ext : extensions) instanceExtensions.push_back(ext); } ``` -------------------------------- ### Create Staging Buffer Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/rotating_texture.dox Creates a Vulkan buffer with TRANSFER_SRC usage to hold texture data for copying. The buffer size should match the texture data. ```cpp Buffer stagingBuffer = createBuffer(buffer.data(), width * height * 4, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); ``` -------------------------------- ### Load Mip Levels from Assets Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/mipmapping.dox Initializes mip level data structures and loads texture data from specified asset paths into staging buffers. Requires TRANSFER_SRC_BIT for buffer usage. ```cpp vector mipLevels; unsigned mipLevelCount; for (auto &pPath : pPaths) { MipLevel mipLevel; if (FAILED(loadRgba8888TextureFromAsset(pPath, &mipLevel.buffer, &mipLevel.width, &mipLevel.height))) { LOGE("Failed to load texture from asset.\n"); abort(); } // Copy commands such as vkCmdCopyBufferToImage will need TRANSFER_SRC_BIT. mipLevel.stagingBuffer = createBuffer(mipLevel.buffer.data(), mipLevel.width * mipLevel.height * 4, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); mipLevels.push_back(mipLevel); } // Get the number of mip levels based on the number of loaded sources. mipLevelCount = mipLevels.size(); ``` -------------------------------- ### Configure Blending and Depth/Stencil for Lighting Pass Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/multipass.dox Sets up additive blending and configures depth/stencil testing for the lighting pass. Depth writes are disabled, and stencil testing ensures lights are only applied where geometry was previously rendered. ```c++ VkPipelineColorBlendAttachmentState colorBlendState = {}; colorBlendState.blendEnable = true; colorBlendState.colorWriteMask = 0xf; colorBlendState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendState.colorBlendOp = VK_BLEND_OP_ADD; colorBlendState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendState.alphaBlendOp = VK_BLEND_OP_ADD; ``` ```c++ depthStencilInfo.depthTestEnable = true; depthStencilInfo.depthWriteEnable = false; depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; depthStencilInfo.depthBoundsTestEnable = false; depthStencilInfo.stencilTestEnable = true; depthStencilInfo.front.passOp = VK_STENCIL_OP_KEEP; depthStencilInfo.front.failOp = VK_STENCIL_OP_KEEP; depthStencilInfo.front.depthFailOp = VK_STENCIL_OP_KEEP; depthStencilInfo.front.compareOp = VK_COMPARE_OP_EQUAL; depthStencilInfo.front.compareMask = 0xff; depthStencilInfo.front.writeMask = 0x0; depthStencilInfo.front.reference = 1; depthStencilInfo.back = depthStencilInfo.front; ``` -------------------------------- ### Compute Shader Synchronization and Dispatch Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/basic_compute.dox This snippet demonstrates how to synchronize compute shaders with vertex shaders using memory barriers. It also shows how to bind a compute pipeline and dispatch a compute job. ```cpp // Compute // First, we have to wait until previous vertex shader invocations have completed // since we will overwrite the vertex buffer used in previous frame here. // // We only need execution barriers here and no memory barrier since we have a write-after-read hazard. // Write-after-read only requires execution barriers. // We have not touched the memory written by compute earlier, so no memory synchronization is needed. memoryBarrier(cmd, 0, 0, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); // Bind the compute pipeline. vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.pipeline); // Bind descriptor set. vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.pipelineLayout, 0, 1, &computePipeline.descriptorSet, 0, nullptr); // Dispatch compute job. vkCmdDispatch(cmd, (positionBuffer.size / sizeof(vec2)) / NUM_PARTICLES_PER_WORKGROUP, 1, 1); // Barrier between compute and vertex shading. memoryBarrier(cmd, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT); ``` -------------------------------- ### Enable Depth Testing in Graphics Pipeline Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/spinning_cube.dox Configures the VkPipelineDepthStencilStateCreateInfo to enable depth testing and writing, and sets the depth comparison operation. This is essential for correct depth-based rendering. ```c++ VkPipelineDepthStencilStateCreateInfo depthStencil = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; depthStencil.depthTestEnable = true; depthStencil.depthWriteEnable = true; depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; depthStencil.depthBoundsTestEnable = false; depthStencil.stencilTestEnable = false; ``` -------------------------------- ### Configure Include Directories Source: https://github.com/arm-software/vulkan-sdk/blob/master/framework/CMakeLists.txt Sets the public and private include directories for the 'framework' target. This allows the library to find its own headers and headers from other linked libraries. ```cmake target_include_directories(framework PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/glm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include) ``` -------------------------------- ### Copy Buffer to Image Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/rotating_texture.dox Copies data from a staging buffer to the optimally tiled texture image. Requires transitioning the image layout to TRANSFER_DST_OPTIMAL before the copy. ```cpp VkBufferImageCopy region; memset(®ion, 0, sizeof(region)); region.bufferOffset = 0; region.bufferRowLength = width; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; region.imageExtent.depth = 1; // Copy the buffer to our optimally tiled image. vkCmdCopyBufferToImage(cmd, stagingBuffer.buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); ``` -------------------------------- ### Add Static Library in CMake Source: https://github.com/arm-software/vulkan-sdk/blob/master/platform/xcb/CMakeLists.txt Defines a static library named 'platform-xcb' and includes collected source and header files. ```cmake add_library(platform-xcb STATIC ${sources} ${sources-headers}) ``` -------------------------------- ### Submit Command Buffer with Semaphores Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Submits a command buffer to the Vulkan queue for execution. It utilizes semaphores for synchronization between GPU operations and a fence for CPU-GPU synchronization. ```cpp void Context::submitCommandBuffer(VkCommandBuffer cmd, VkSemaphore acquireSemaphore, VkSemaphore releaseSemaphore) { // All queue submissions get a fence that CPU will wait // on for synchronization purposes. VkFence fence = getFenceManager().requestClearedFence(); VkSubmitInfo info = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; info.commandBufferCount = 1; info.pCommandBuffers = &cmd; const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; info.waitSemaphoreCount = acquireSemaphore != VK_NULL_HANDLE ? 1 : 0; info.pWaitSemaphores = &acquireSemaphore; info.pWaitDstStageMask = &waitStage; info.signalSemaphoreCount = releaseSemaphore != VK_NULL_HANDLE ? 1 : 0; info.pSignalSemaphores = &releaseSemaphore; VK_CHECK(vkQueueSubmit(queue, 1, &info, fence)); } ``` -------------------------------- ### Android Native Activity Entry Point Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/creating_vulkan_window.dox Implement the android_main function in your native code to serve as the entry point for your Android application using NativeActivity. ```c++ // platform/android/android.cpp #include "android_native_app_glue.h" void android_main(android_app *state) { // Implement application here! for (;;) { ... ALooper_pollAll(&event); event->handle(); } } ``` -------------------------------- ### Enumerate Device Layer Properties (C++) Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/validation_layers.dox Queries the physical device for available layer properties. Similar to instance layer enumeration, this is used to find layers that can be enabled for the device. ```cpp uint32_t deviceLayerCount; VK_CHECK(vkEnumerateDeviceLayerProperties(gpu, &deviceLayerCount, nullptr)); vector deviceLayers(deviceLayerCount); VK_CHECK(vkEnumerateDeviceLayerProperties(gpu, &deviceLayerCount, deviceLayers.data())); ``` -------------------------------- ### Request Primary Command Buffer Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Requests a primary command buffer from the context, which is essential for recording rendering commands. The command buffer is managed per frame and tied to the swapchain index. ```c++ // Request a fresh command buffer. VkCommandBuffer cmd = pContext->requestPrimaryCommandBuffer(); ``` ```c++ VkCommandBuffer Context::requestPrimaryCommandBuffer() { return perFrame[swapchainIndex]->commandManager.requestCommandBuffer(); } ``` -------------------------------- ### Verify ADB Device Connection Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/getting_started_guide.dox Use this command to verify that your device is connected and recognized by ADB. Ensure USB debugging is enabled on your device. ```bash $ adb devices XXXXXXXXXXXXXXX device ``` -------------------------------- ### Create Subpass Dependency for External Events Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/hellotriangle.dox Establishes a dependency to synchronize with external events, such as a WSI semaphore. Ensures layout transitions occur after semaphore signaling. ```c // Create a dependency to external events. // We need to wait for the WSI semaphore to signal. // Only pipeline stages which depend on COLOR_ATTACHMENT_OUTPUT_BIT will // actually wait for the semaphore, so we must also wait for that pipeline stage. VkSubpassDependency dependency = { 0 }; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // We are creating a write-after-read dependency (presentation must be done reading), so we don't need memory barrier. dependency.srcAccessMask = 0; // The layout transition to COLOR_ATTACHMENT_OPTIMAL will imply a memory barrier for the relevant access bits, so we don't have to do it. dependency.dstAccessMask = 0; ``` -------------------------------- ### Configure Pipeline for 4x MSAA Source: https://github.com/arm-software/vulkan-sdk/blob/master/doxygen/tutorials/multisampling.dox Specify 4x multisampling for the pipeline. Ensure sample shading is disabled if not needed. ```c++ // Render with 4x MSAA. VkPipelineMultisampleStateCreateInfo multisample = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; multisample.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT; multisample.sampleShadingEnable = false; multisample.alphaToCoverageEnable = false; multisample.alphaToOneEnable = false; ```