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. android 支持上拉加载,下拉刷新的列表控件SwipeRefreshLayout的二次封装

    上拉加载,下拉刷新的列表控件,大家一定都封装过,或者使用过 源代码,我会在最后贴出来 这篇代码主要是为了解决两个问题 1.滑动冲突得问题 2.listview无数据时,无数据布局的展示问题 下方列出的 ...

  2. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 表格:在 <tbody> 内添加斑马线形式的条纹 ( IE8 不支持)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. IntelliJ IDEA常用快捷键大全

    如果想要非常高效的使用IDEA这款工具,应该掌握图中已被标记的快捷键. 另: 代码实时模板生成:psvm/sout/ifn等 按Tab键快速生成模板. 转载请保留或注明出处:http://www.cn ...

  4. Java基础 -4

    IF分支结构 在程序开发的过程中 一共会存在有三组程序逻辑:顺序结构.分支结构.循环结构 if分支结构主要是针对关系表达式进行判断处理的分支操作. if判断 public static void ma ...

  5. DuiLib中FlashDemo的例子经验杂粹1

    转载:https://www.jianshu.com/p/3e958ae9e5ab 最近用duilib做个东西,经常卡壳 ,而且以前学的现在又忘.现在觉得应该好好做笔记,以前老是觉得博客是很郑重的东西 ...

  6. 碰到的问题——建设基于TensorFlow的深度学习环境

    1.解决jupyter notebook问题:socket.error: [Errno 99] Cannot assign requested address 首先要生成一个jupyter的配置文件: ...

  7. Redis的C++与JavaScript访问操作

    上篇简单介绍了Redis及其安装部署,这篇记录一下如何用C++语言和JavaScript语言访问操作Redis 1. Redis的接口访问方式(通用接口或者语言接口) 很多语言都包含Redis支持,R ...

  8. Centos7 更新配置为阿里源步骤

    一.yum更换配置源过程 1.备份原有的.repo源文件 首先需要将之前的源进行备份(一般重要的配置文件都需要有备份的意识) # 进入源配置目录 cd /etc/yum.repos.d # 创建备份文 ...

  9. Wepy框架和mpVue框架的比较及使用mpVue框架需要注意的点

    Wepy框架 它是一款类Vue框架,在代码风格上借鉴了Vue,本身和Vue没有任何关系. mpVue框架 它是从整个Vue的核心代码上经过二次开发而形成的一个框架,相当于是给Vue本身赋能,增加了开发 ...

  10. python之闭包,装饰器

    目录 函数对象 :相当于变量名 函数对象的作用: 1. 可以引用 2. 可以作为函数的返回值 3. 可以作为容器的元素 4. 可以作为函数的参数 闭包 定义: 如果在一个函数的内部定义了另一个函数,外 ...