DiligentEngine的API是D3d11和D3D12风格的,vulkan也被封装成了这种风格的API。 在了解Diligent Engine是如何对vulkan进行封装之前,我准备先学习下Vulkan。知乎funchun的编程指南是中文版,英文不好,准备先看一版中文版,回头再去研习其他的内容。

1.Vulkan编程指南阅读摘要

1.1 Vulkan SDK

安装完成之后,安装目录有如下文件。在阅读编程指南的过程中,我并未采用指南中的demo code来进行研究,而是使用的SDK自带的demo进行学习。

1.2 Vulkan SDK Demo

  • validation layers

        /*
    * This is info for a temp callback to use during CreateInstance.
    * After the instance is created, we use the instance-based
    * function to register the final callback.
    */
    VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
    if (demo->validate) {
    // VK_EXT_debug_utils style
    dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
    dbg_messenger_create_info.pNext = NULL;
    dbg_messenger_create_info.flags = ;
    dbg_messenger_create_info.messageSeverity =
    VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
    dbg_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
    VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
    VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
    dbg_messenger_create_info.pfnUserCallback = debug_messenger_callback;
    dbg_messenger_create_info.pUserData = demo;
    inst_info.pNext = &dbg_messenger_create_info;
    }
      if (demo->validate) {
    // Setup VK_EXT_debug_utils function pointers always (we use them for
    // debug labels and names).
    demo->CreateDebugUtilsMessengerEXT =
    (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(demo->inst, "vkCreateDebugUtilsMessengerEXT");
    demo->DestroyDebugUtilsMessengerEXT =
    (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(demo->inst, "vkDestroyDebugUtilsMessengerEXT");
    demo->SubmitDebugUtilsMessageEXT =
    (PFN_vkSubmitDebugUtilsMessageEXT)vkGetInstanceProcAddr(demo->inst, "vkSubmitDebugUtilsMessageEXT");
    demo->CmdBeginDebugUtilsLabelEXT =
    (PFN_vkCmdBeginDebugUtilsLabelEXT)vkGetInstanceProcAddr(demo->inst, "vkCmdBeginDebugUtilsLabelEXT");
    demo->CmdEndDebugUtilsLabelEXT =
    (PFN_vkCmdEndDebugUtilsLabelEXT)vkGetInstanceProcAddr(demo->inst, "vkCmdEndDebugUtilsLabelEXT");
    demo->CmdInsertDebugUtilsLabelEXT =
    (PFN_vkCmdInsertDebugUtilsLabelEXT)vkGetInstanceProcAddr(demo->inst, "vkCmdInsertDebugUtilsLabelEXT");
    demo->SetDebugUtilsObjectNameEXT =
    (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(demo->inst, "vkSetDebugUtilsObjectNameEXT");
    if (NULL == demo->CreateDebugUtilsMessengerEXT || NULL == demo->DestroyDebugUtilsMessengerEXT ||
    NULL == demo->SubmitDebugUtilsMessageEXT || NULL == demo->CmdBeginDebugUtilsLabelEXT ||
    NULL == demo->CmdEndDebugUtilsLabelEXT || NULL == demo->CmdInsertDebugUtilsLabelEXT ||
    NULL == demo->SetDebugUtilsObjectNameEXT) {
    ERR_EXIT("GetProcAddr: Failed to init VK_EXT_debug_utils\n", "GetProcAddr: Failure");
    } err = demo->CreateDebugUtilsMessengerEXT(demo->inst, &dbg_messenger_create_info, NULL, &demo->dbg_messenger);
    switch (err) {
    case VK_SUCCESS:
    break;
    case VK_ERROR_OUT_OF_HOST_MEMORY:
    ERR_EXIT("CreateDebugUtilsMessengerEXT: out of host memory\n", "CreateDebugUtilsMessengerEXT Failure");
    break;
    default:
    ERR_EXIT("CreateDebugUtilsMessengerEXT: unknown failure\n", "CreateDebugUtilsMessengerEXT Failure");
    break;
    }
    }
  • instance extensions
  • CreateVulkanInstance
     const VkApplicationInfo app = {
    .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
    .pNext = NULL,
    .pApplicationName = APP_SHORT_NAME,
    .applicationVersion = ,
    .pEngineName = APP_SHORT_NAME,
    .engineVersion = ,
    .apiVersion = VK_API_VERSION_1_0,
    };
    VkInstanceCreateInfo inst_info = {
    .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
    .pNext = NULL,
    .pApplicationInfo = &app,
    .enabledLayerCount = demo->enabled_layer_count,
    .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
    .enabledExtensionCount = demo->enabled_extension_count,
    .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
    }; /*
    * This is info for a temp callback to use during CreateInstance.
    * After the instance is created, we use the instance-based
    * function to register the final callback.
    */
    VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
    if (demo->validate) {
    // VK_EXT_debug_utils style
    dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
    dbg_messenger_create_info.pNext = NULL;
    dbg_messenger_create_info.flags = ;
    dbg_messenger_create_info.messageSeverity =
    VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
    dbg_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
    VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
    VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
    dbg_messenger_create_info.pfnUserCallback = debug_messenger_callback;
    dbg_messenger_create_info.pUserData = demo;
    inst_info.pNext = &dbg_messenger_create_info;
    } uint32_t gpu_count; err = vkCreateInstance(&inst_info, NULL, &demo->inst);
  • vkEnumeratePhysicalDevices

        /* Make initial call to query gpu_count, then second call for gpu info*/
    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
    assert(!err); if (gpu_count > ) {
    VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
    assert(!err);
    /* For cube demo we just grab the first physical device */
    demo->gpu = physical_devices[];
    free(physical_devices);
    } else {
    ERR_EXIT(
    "vkEnumeratePhysicalDevices reported zero accessible devices.\n\n"
    "Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
    "Please look at the Getting Started guide for additional information.\n",
    "vkEnumeratePhysicalDevices Failure");
    }
        vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
    
        /* Call with NULL data to get count */
    vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_family_count, NULL);
    assert(demo->queue_family_count >= ); demo->queue_props = (VkQueueFamilyProperties *)malloc(demo->queue_family_count * sizeof(VkQueueFamilyProperties));
    vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_family_count, demo->queue_props);
      // Query fine-grained feature support for this device.
    // If app has specific feature requirements it should check supported
    // features based on this query
    VkPhysicalDeviceFeatures physDevFeatures;
    vkGetPhysicalDeviceFeatures(demo->gpu, &physDevFeatures);
  • device extensions需要找到对应的 VK_KHR_SWAPCHAIN_EXTENSION_NAME,这个是一个交换链的扩展
  •     /* Look for device extensions */
    uint32_t device_extension_count = ;
    VkBool32 swapchainExtFound = ;
    demo->enabled_extension_count = ;
    memset(demo->extension_names, , sizeof(demo->extension_names)); err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL, &device_extension_count, NULL);
    assert(!err); if (device_extension_count > ) {
    VkExtensionProperties *device_extensions = malloc(sizeof(VkExtensionProperties) * device_extension_count);
    err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL, &device_extension_count, device_extensions);
    assert(!err); for (uint32_t i = ; i < device_extension_count; i++) {
    if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, device_extensions[i].extensionName)) {
    swapchainExtFound = ;
    demo->extension_names[demo->enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
    }
    assert(demo->enabled_extension_count < );
    } if (demo->VK_KHR_incremental_present_enabled) {
    // Even though the user "enabled" the extension via the command
    // line, we must make sure that it's enumerated for use with the
    // device. Therefore, disable it here, and re-enable it again if
    // enumerated.
    demo->VK_KHR_incremental_present_enabled = false;
    for (uint32_t i = ; i < device_extension_count; i++) {
    if (!strcmp(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, device_extensions[i].extensionName)) {
    demo->extension_names[demo->enabled_extension_count++] = VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME;
    demo->VK_KHR_incremental_present_enabled = true;
    DbgMsg("VK_KHR_incremental_present extension enabled\n");
    }
    assert(demo->enabled_extension_count < );
    }
    if (!demo->VK_KHR_incremental_present_enabled) {
    DbgMsg("VK_KHR_incremental_present extension NOT AVAILABLE\n");
    }
    } if (demo->VK_GOOGLE_display_timing_enabled) {
    // Even though the user "enabled" the extension via the command
    // line, we must make sure that it's enumerated for use with the
    // device. Therefore, disable it here, and re-enable it again if
    // enumerated.
    demo->VK_GOOGLE_display_timing_enabled = false;
    for (uint32_t i = ; i < device_extension_count; i++) {
    if (!strcmp(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, device_extensions[i].extensionName)) {
    demo->extension_names[demo->enabled_extension_count++] = VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME;
    demo->VK_GOOGLE_display_timing_enabled = true;
    DbgMsg("VK_GOOGLE_display_timing extension enabled\n");
    }
    assert(demo->enabled_extension_count < );
    }
    if (!demo->VK_GOOGLE_display_timing_enabled) {
    DbgMsg("VK_GOOGLE_display_timing extension NOT AVAILABLE\n");
    }
    } free(device_extensions);
    } if (!swapchainExtFound) {
    ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
    " extension.\n\nDo you have a compatible Vulkan installable client driver (ICD) installed?\n"
    "Please look at the Getting Started guide for additional information.\n",
    "vkCreateInstance Failure");
    }
  • 凡事带有KHR结尾的函数,都是vulkan对于制定平台的一些扩展, 下面的代码创建一个窗口表面,当然如果你不需要展示图像,这个表面不是必须的。
// Create a WSI surface for the window:
#if defined(VK_USE_PLATFORM_WIN32_KHR)
VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = ;
createInfo.hinstance = demo->connection;
createInfo.hwnd = demo->window; err = vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
  • vkCreateDevice

        VkResult U_ASSERT_ONLY err;
    float queue_priorities[] = {0.0};
    VkDeviceQueueCreateInfo queues[];
    queues[].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queues[].pNext = NULL;
    queues[].queueFamilyIndex = demo->graphics_queue_family_index;
    queues[].queueCount = ;
    queues[].pQueuePriorities = queue_priorities;
    queues[].flags = ; VkDeviceCreateInfo device = {
    .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    .pNext = NULL,
    .queueCreateInfoCount = ,
    .pQueueCreateInfos = queues,
    .enabledLayerCount = ,
    .ppEnabledLayerNames = NULL,
    .enabledExtensionCount = demo->enabled_extension_count,
    .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
    .pEnabledFeatures = NULL, // If specific features are required, pass them in here
    };
    if (demo->separate_present_queue) {
    queues[].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queues[].pNext = NULL;
    queues[].queueFamilyIndex = demo->present_queue_family_index;
    queues[].queueCount = ;
    queues[].pQueuePriorities = queue_priorities;
    queues[].flags = ;
    device.queueCreateInfoCount = ;
    }
    err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
    assert(!err);
  • Get the list of VkFormat's that are supported:

      uint32_t formatCount;
    err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, &formatCount, NULL);
    assert(!err);
    VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
    err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface, &formatCount, surfFormats);
    assert(!err);
    // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
    // the surface has no preferred format. Otherwise, at least one
    // supported format will be returned.
    if (formatCount == && surfFormats[].format == VK_FORMAT_UNDEFINED) {
    demo->format = VK_FORMAT_B8G8R8A8_UNORM;
    } else {
    assert(formatCount >= );
    demo->format = surfFormats[].format;
    }
    demo->color_space = surfFormats[].colorSpace;
    free(surfFormats);
  • 同步
    // Create semaphores to synchronize acquiring presentable buffers before
    // rendering and waiting for drawing to be complete before presenting
    VkSemaphoreCreateInfo semaphoreCreateInfo = {
    .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
    .pNext = NULL,
    .flags = ,
    }; // Create fences that we can use to throttle if we get too far
    // ahead of the image presents
    VkFenceCreateInfo fence_ci = {
    .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = NULL, .flags = VK_FENCE_CREATE_SIGNALED_BIT};
    for (uint32_t i = ; i < FRAME_LAG; i++) {
    err = vkCreateFence(demo->device, &fence_ci, NULL, &demo->fences[i]);
    assert(!err); err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL, &demo->image_acquired_semaphores[i]);
    assert(!err); err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL, &demo->draw_complete_semaphores[i]);
    assert(!err); if (demo->separate_present_queue) {
    err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL, &demo->image_ownership_semaphores[i]);
    assert(!err);
    }
    }
    demo->frame_index = ;
  • Get Memory information and properties
      vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
  • demo_prepare: command buff, depth,mesh data,descriptor layout, render_pass, pipe lines
    static void demo_prepare(struct demo *demo) {
    VkResult U_ASSERT_ONLY err;
    if (demo->cmd_pool == VK_NULL_HANDLE) {
    const VkCommandPoolCreateInfo cmd_pool_info = {
    .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
    .pNext = NULL,
    .queueFamilyIndex = demo->graphics_queue_family_index,
    .flags = ,
    };
    err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL, &demo->cmd_pool);
    assert(!err);
    } const VkCommandBufferAllocateInfo cmd = {
    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    .pNext = NULL,
    .commandPool = demo->cmd_pool,
    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    .commandBufferCount = ,
    };
    err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->cmd);
    assert(!err);
    VkCommandBufferBeginInfo cmd_buf_info = {
    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    .pNext = NULL,
    .flags = ,
    .pInheritanceInfo = NULL,
    };
    err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
    assert(!err); demo_prepare_buffers(demo); if (demo->is_minimized) {
    demo->prepared = false;
    return;
    } demo_prepare_depth(demo);
    demo_prepare_textures(demo);
    demo_prepare_cube_data_buffers(demo); demo_prepare_descriptor_layout(demo);
    demo_prepare_render_pass(demo);
    demo_prepare_pipeline(demo); for (uint32_t i = ; i < demo->swapchainImageCount; i++) {
    err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->swapchain_image_resources[i].cmd);
    assert(!err);
    } if (demo->separate_present_queue) {
    const VkCommandPoolCreateInfo present_cmd_pool_info = {
    .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
    .pNext = NULL,
    .queueFamilyIndex = demo->present_queue_family_index,
    .flags = ,
    };
    err = vkCreateCommandPool(demo->device, &present_cmd_pool_info, NULL, &demo->present_cmd_pool);
    assert(!err);
    const VkCommandBufferAllocateInfo present_cmd_info = {
    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    .pNext = NULL,
    .commandPool = demo->present_cmd_pool,
    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    .commandBufferCount = ,
    };
    for (uint32_t i = ; i < demo->swapchainImageCount; i++) {
    err = vkAllocateCommandBuffers(demo->device, &present_cmd_info,
    &demo->swapchain_image_resources[i].graphics_to_present_cmd);
    assert(!err);
    demo_build_image_ownership_cmd(demo, i);
    }
    } demo_prepare_descriptor_pool(demo);
    demo_prepare_descriptor_set(demo); demo_prepare_framebuffers(demo); for (uint32_t i = ; i < demo->swapchainImageCount; i++) {
    demo->current_buffer = i;
    demo_draw_build_cmd(demo, demo->swapchain_image_resources[i].cmd);
    } /*
    * Prepare functions above may generate pipeline commands
    * that need to be flushed before beginning the render loop.
    */
    demo_flush_init_cmd(demo);
    if (demo->staging_texture.buffer) {
    demo_destroy_texture(demo, &demo->staging_texture);
    } demo->current_buffer = ;
    demo->prepared = true;
    }
  • vulkan都是提前把渲染命令准备好
    /*
    * Prepare functions above may generate pipeline commands
    * that need to be flushed before beginning the render loop.
    */
    demo_flush_init_cmd(demo);
    if (demo->staging_texture.buffer) {
    demo_destroy_texture(demo, &demo->staging_texture);
    } demo->current_buffer = ;
    demo->prepared = true;
  • 渲染主循环

    #if defined(VK_USE_PLATFORM_WIN32_KHR)
    static void demo_run(struct demo *demo) {
    if (!demo->prepared) return; demo_draw(demo);
    demo->curFrame++;
    if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount) {
    PostQuitMessage(validation_error);
    }
    }
    static void demo_draw(struct demo *demo) {
    VkResult U_ASSERT_ONLY err; // Ensure no more than FRAME_LAG renderings are outstanding
    vkWaitForFences(demo->device, , &demo->fences[demo->frame_index], VK_TRUE, UINT64_MAX);
    vkResetFences(demo->device, , &demo->fences[demo->frame_index]); do {
    // Get the index of the next available swapchain image:
    err =
    demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
    demo->image_acquired_semaphores[demo->frame_index], VK_NULL_HANDLE, &demo->current_buffer); if (err == VK_ERROR_OUT_OF_DATE_KHR) {
    // demo->swapchain is out of date (e.g. the window was resized) and
    // must be recreated:
    demo_resize(demo);
    } else if (err == VK_SUBOPTIMAL_KHR) {
    // demo->swapchain is not as optimal as it could be, but the platform's
    // presentation engine will still present the image correctly.
    break;
    } else if (err == VK_ERROR_SURFACE_LOST_KHR) {
    vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
    demo_create_surface(demo);
    demo_resize(demo);
    } else {
    assert(!err);
    }
    } while (err != VK_SUCCESS); demo_update_data_buffer(demo); if (demo->VK_GOOGLE_display_timing_enabled) {
    // Look at what happened to previous presents, and make appropriate
    // adjustments in timing:
    DemoUpdateTargetIPD(demo); // Note: a real application would position its geometry to that it's in
    // the correct locatoin for when the next image is presented. It might
    // also wait, so that there's less latency between any input and when
    // the next image is rendered/presented. This demo program is so
    // simple that it doesn't do either of those.
    } // Wait for the image acquired semaphore to be signaled to ensure
    // that the image won't be rendered to until the presentation
    // engine has fully released ownership to the application, and it is
    // okay to render to the image.
    VkPipelineStageFlags pipe_stage_flags;
    VkSubmitInfo submit_info;
    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    submit_info.pNext = NULL;
    submit_info.pWaitDstStageMask = &pipe_stage_flags;
    pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    submit_info.waitSemaphoreCount = ;
    submit_info.pWaitSemaphores = &demo->image_acquired_semaphores[demo->frame_index];
    submit_info.commandBufferCount = ;
    submit_info.pCommandBuffers = &demo->swapchain_image_resources[demo->current_buffer].cmd;
    submit_info.signalSemaphoreCount = ;
    submit_info.pSignalSemaphores = &demo->draw_complete_semaphores[demo->frame_index];
    err = vkQueueSubmit(demo->graphics_queue, , &submit_info, demo->fences[demo->frame_index]);
    assert(!err); if (demo->separate_present_queue) {
    // If we are using separate queues, change image ownership to the
    // present queue before presenting, waiting for the draw complete
    // semaphore and signalling the ownership released semaphore when finished
    VkFence nullFence = VK_NULL_HANDLE;
    pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    submit_info.waitSemaphoreCount = ;
    submit_info.pWaitSemaphores = &demo->draw_complete_semaphores[demo->frame_index];
    submit_info.commandBufferCount = ;
    submit_info.pCommandBuffers = &demo->swapchain_image_resources[demo->current_buffer].graphics_to_present_cmd;
    submit_info.signalSemaphoreCount = ;
    submit_info.pSignalSemaphores = &demo->image_ownership_semaphores[demo->frame_index];
    err = vkQueueSubmit(demo->present_queue, , &submit_info, nullFence);
    assert(!err);
    } // If we are using separate queues we have to wait for image ownership,
    // otherwise wait for draw complete
    VkPresentInfoKHR present = {
    .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
    .pNext = NULL,
    .waitSemaphoreCount = ,
    .pWaitSemaphores = (demo->separate_present_queue) ? &demo->image_ownership_semaphores[demo->frame_index]
    : &demo->draw_complete_semaphores[demo->frame_index],
    .swapchainCount = ,
    .pSwapchains = &demo->swapchain,
    .pImageIndices = &demo->current_buffer,
    }; VkRectLayerKHR rect;
    VkPresentRegionKHR region;
    VkPresentRegionsKHR regions;
    if (demo->VK_KHR_incremental_present_enabled) {
    // If using VK_KHR_incremental_present, we provide a hint of the region
    // that contains changed content relative to the previously-presented
    // image. The implementation can use this hint in order to save
    // work/power (by only copying the region in the hint). The
    // implementation is free to ignore the hint though, and so we must
    // ensure that the entire image has the correctly-drawn content.
    uint32_t eighthOfWidth = demo->width / ;
    uint32_t eighthOfHeight = demo->height / ; rect.offset.x = eighthOfWidth;
    rect.offset.y = eighthOfHeight;
    rect.extent.width = eighthOfWidth * ;
    rect.extent.height = eighthOfHeight * ;
    rect.layer = ; region.rectangleCount = ;
    region.pRectangles = &rect; regions.sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR;
    regions.pNext = present.pNext;
    regions.swapchainCount = present.swapchainCount;
    regions.pRegions = &region;
    present.pNext = &regions;
    } if (demo->VK_GOOGLE_display_timing_enabled) {
    VkPresentTimeGOOGLE ptime;
    if (demo->prev_desired_present_time == ) {
    // This must be the first present for this swapchain.
    //
    // We don't know where we are relative to the presentation engine's
    // display's refresh cycle. We also don't know how long rendering
    // takes. Let's make a grossly-simplified assumption that the
    // desiredPresentTime should be half way between now and
    // now+target_IPD. We will adjust over time.
    uint64_t curtime = getTimeInNanoseconds();
    if (curtime == ) {
    // Since we didn't find out the current time, don't give a
    // desiredPresentTime:
    ptime.desiredPresentTime = ;
    } else {
    ptime.desiredPresentTime = curtime + (demo->target_IPD >> );
    }
    } else {
    ptime.desiredPresentTime = (demo->prev_desired_present_time + demo->target_IPD);
    }
    ptime.presentID = demo->next_present_id++;
    demo->prev_desired_present_time = ptime.desiredPresentTime; VkPresentTimesInfoGOOGLE present_time = {
    .sType = VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
    .pNext = present.pNext,
    .swapchainCount = present.swapchainCount,
    .pTimes = &ptime,
    };
    if (demo->VK_GOOGLE_display_timing_enabled) {
    present.pNext = &present_time;
    }
    } err = demo->fpQueuePresentKHR(demo->present_queue, &present);
    demo->frame_index += ;
    demo->frame_index %= FRAME_LAG; if (err == VK_ERROR_OUT_OF_DATE_KHR) {
    // demo->swapchain is out of date (e.g. the window was resized) and
    // must be recreated:
    demo_resize(demo);
    } else if (err == VK_SUBOPTIMAL_KHR) {
    // demo->swapchain is not as optimal as it could be, but the platform's
    // presentation engine will still present the image correctly.
    } else if (err == VK_ERROR_SURFACE_LOST_KHR) {
    vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
    demo_create_surface(demo);
    demo_resize(demo);
    } else {
    assert(!err);
    }
    }

最终图形画出来的效果如下图所示。

总结

这里我只是简单的了解了Vulkan渲染的流程,但是其中的概念不是很清晰。按照张静的观点,Vulkan 很酷很炫,但是不适合你,早点分手吧 ,似乎

学习vulkan是一件得不偿失的事情,我自己思考了下,我为什么要学这个呢?

1) 我对图形API感兴趣,我想知道他是怎么和硬件结合的,Vulkan就是图形API内的汇编,吃透了他,估计其他的几种API都不是问题,手动狗头;

2) 工作需要,如果我要想采用商用引擎来接入合作项目,那必须对底层的硬件调用有所了解,这样才能做深入的定制集成;

3) 性能优化是我给自己的定位,如果我连这些都不清楚,如何优化。

所以不要再犹豫了,学哪个都不容易,坚持下去吧,一年之后再看。

Reference:

1、知乎Vulkan-高性能渲染

2、Life of a triangle - NVIDIA's logical pipeline

3、Round Robin 算法

4、NVIDIA Developer Vulkan

5、Vulkan SDK Tutorial

6、Vulkan In 30 Minutes

7、Vulkan Notes

8、GDC  2016 Talk

9、知乎: Vulkan编程指南

10、Shader交叉编译之梦

11、游戏引擎随笔: 现代图形API

12、SPIR-V

13、Khronos Vulkan Registry : vulkan specifics

14、vulkan踩坑记

15、Vulkan C++ examples and demos

16、NVIDIA GameWorks Graphics Samples

Vulkan SDK Demo 之一 熟悉的更多相关文章

  1. Vulkan SDK 之 Instance

    上一篇 Vulkan SDK Demo 熟悉 粗略的了解了下,一个app是如何调用vulkan的api来展示一个立方体的,但是对其中的每一个api了解并不深刻,后面的系列会根据sample的tutor ...

  2. 使用 Android Studio 跑新浪微博SDK Demo遇到的问题及解决

    概述 这是新浪微博官方 Android SDK Demo 使用 Android Studio 导入.编译并运行通过的版本. 源码:WeiboSdkDemo 官方项目请点击: weibo_android ...

  3. 微博开发平台java SDK demo学习之friendships

    本文解释了在java SDK的demo中与feiendships有关的功能 截图如下: 关注一个用户(需要知道该用户uid) 取消关注一个用户(用户uid) 获取用户粉丝列表(授权用户的screen_ ...

  4. Java版 人脸识别SDK demo

    虹软人脸识别SDK之Java版,支持SDK 1.1+,以及当前最新版本2.0,滴滴,抓紧上车! 前言 由于业务需求,最近跟人脸识别杠上了,本以为虹软提供的SDK是那种面向开发语言的,结果是一堆dll· ...

  5. iOS app支付宝接口调用的一点总结(补充支付宝SDK&Demo下载地址)

    由于app内需要用到支付功能,选择了当前最流行的支付宝进行支付.在进行内嵌支付宝功能开发时,被它狠狠的耍了一把. 根据支付宝开发文档,参考demo代码.将相关支付功能加到了自己的代码中.一些根据文档来 ...

  6. 转:iOS app支付宝接口调用的一点总结(补充支付宝SDK&Demo下载地址)

    iosiOSIOS文档服务器测试电话 由于app内需要用到支付功能,选择了当前最流行的支付宝进行支付.在进行内嵌支付宝功能开发时,被它狠狠的耍了一把. 根据支付宝开发文档,参考demo代码.将相关支付 ...

  7. 微信JS SDK Demo 官方案例[转]

    摘要: 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用 ...

  8. 微博开发平台java SDK demo学习之examples(demo)

    本文介绍demo中函数的功能分块 账号 评论 收藏 关系/好友分组 地理信息 OAuth2(开发指南) 位置服务(开发指南)

  9. 微信JS SDK Demo

    微信JS-SDK 分享到朋友圈 分享给朋友 分享到QQ 拍照或从手机相册中选图 识别音频并返回识别结果 使用微信内置地图查看位置原文:http://www.cnblogs.com/txw1958/p/ ...

随机推荐

  1. spring security几大核心组件

    一.SecurityContext 安全上下文,用户通过Spring Security 的校验之后,验证信息存储在SecurityContext中 SecurityContext接口只定义了两个方法, ...

  2. Vue中全局监听键盘事件

    全局监听enter键,是把监听事件绑定到document上 常用的keyCode键盘编码在这里:https://www.cnblogs.com/wbyixx/p/12029508.html creat ...

  3. Linux操作系统服务器学习笔记一

    初识Linux: Linux 是什么? Linux是一套免费使用和自由传播的类Unix操作系统,是一个多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和网络协议 ...

  4. 十一 Spring的AOP开发的相关术语

    SpringAOP简介: AOP思想最早是由AOP联盟组织提出的.Spring使用这种思想最好的框架. Spring的AOP有自己实现的方式,但是非常繁琐.AspectJ是一个AOP框架,Spring ...

  5. VM安装linux操作系统详细教程

    1.首先我们新建一个虚拟机,先不安装操作系统,稍后再对其安装Linux系统. 新建虚拟机步骤如下: 打开VMware软件,菜单栏点击“文件(F)”–>选择“新建虚拟机(N)”,如下图1,(或者直 ...

  6. python批量提取哔哩哔哩bilibili视频

    # -*- coding: utf-8 -*- """ Created on Tue Jan 29 13:26:41 2019 @author: kwy "&q ...

  7. Codeforces #617 (Div. 3)B. Food Buying

    Mishka wants to buy some food in the nearby shop. Initially, he has ss burles on his card. Mishka ca ...

  8. MFC TreeControl简单应用

    目录 1. TreeControl添加节点 2. TreeControl菜单 3. TreeControl修改节点 4. TreeControl查找节点 5. TreeControl折叠展开节点 6. ...

  9. python爬虫(七) mozillacookiejar

    MozillaCookiejar 保存百度得Cookiejar信息: from urllib import request from urllib import parse from http.coo ...

  10. Encoding.UTF8 与 new UTF8Encoding(false) 有什么区别?

    System.Text.Encoding.UTF8 是一个静态实例,它省略了 BOM,而 new UTF8Encoding(false) 创建的实例是含有 BOM 的. BOM,即 Byte Orde ...