{"id":19817173,"url":"https://github.com/nvpro-samples/vk_async_resources","last_synced_at":"2025-05-01T11:30:27.741Z","repository":{"id":86083488,"uuid":"225588170","full_name":"nvpro-samples/vk_async_resources","owner":"nvpro-samples","description":"Sample showcasing lifetime management and resource transfers in Vulkan","archived":false,"fork":false,"pushed_at":"2024-01-17T16:45:55.000Z","size":175,"stargazers_count":22,"open_issues_count":0,"forks_count":3,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-01-18T00:36:32.310Z","etag":null,"topics":["staging-transfers","transfer-queue","vulkan"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nvpro-samples.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-12-03T10:05:00.000Z","updated_at":"2023-12-26T06:04:21.000Z","dependencies_parsed_at":"2023-11-20T22:46:00.341Z","dependency_job_id":null,"html_url":"https://github.com/nvpro-samples/vk_async_resources","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_async_resources","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_async_resources/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_async_resources/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_async_resources/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nvpro-samples","download_url":"https://codeload.github.com/nvpro-samples/vk_async_resources/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224253417,"owners_count":17280934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["staging-transfers","transfer-queue","vulkan"],"created_at":"2024-11-12T10:11:55.455Z","updated_at":"2024-11-12T10:11:55.558Z","avatar_url":"https://github.com/nvpro-samples.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vk_async_resources\n\n![screenshot](doc/screenshot.png)\n\n## About\n\nThis sample showcases several framework helper classes to aid\ndevelopment with Vulkan using its C api.\n\n- Resource and Memory Management\n- DescriptorSet Utilities\n- Asynchronous Staging Transfers\n- Runtime GLSL Shaders to SPIR-V\n- Interaction with Swapchains\n\n## Resource And Staging Operations\n\nThis sample in particular demonstrates asynchronous resource creation\nand transfers by creating a torus with different subdivision every couple\nframes.\n\n\u003e WARNING: The torus will flicker if recreation is active,\n\u003e this is intentional\n\nYou should see that if the asynchronous path is activated (default)\nthe average frame time shown in the UI is faster.\n\nCompared to OpenGL you have more responsibilities in Vulkan.\nFor example you cannot just `glDelete` but have to ensure the objects\nare not currently used by the device. Look for `unusedResources` array\nusage.\n\nFurthermore when you did trigger uploads in OpenGL by `glBufferSubData` or\n`glBufferStorage` the driver managed the upload for you through the use of\n**staging buffers**. In Vulkan these buffers would be allocated\nwith the following memory properties that depend on the direction of the\ntransfer:\n\n``` cpp\nVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n(toDevice ? VK_MEMORY_PROPERTY_HOST_COHERENT_BIT : VK_MEMORY_PROPERTY_HOST_CACHED_BIT)\n```\n\nIn Vulkan you want to avoid interfering with the graphics workload and make use\nof dedicated transfer queues. You should copy the data into a temporary staging\nmemory and then copy from this staging resource into the finale resource using\nthe transfer queue. Look for code related to the `useAsync` path that makes use\nof `nvvk::StagingMemoryManager`.\n\nWhile it may be simpler and more convenient to synchronize the device with the\nhost and avoid deferring operations, this simple approach can create stuttering\nand wastes performance.\n\nDepending on the usage-scenario such synchronization may be totally fine\n(window resizing, major scene loading operations, no continous redraw etc.),\nbut in general you should design for leveraging the asynchronous capabilities\nof Vulkan.\n\n\n\u003e The following graphs don't represent time accurately, but are for illustration\n\u003e purposes only.\n\n### Blocking / Synchronous Transfer\n\nThe naive approach is to wait for the device, do the upload, release temporary \nresources and then prepare the next frame and submit it. This means a lot of idle time\nboth on the device and the host. The benefit is that due to the blocking\nsynchronization you can easily delete resources directly as the device\nis not using them in-flight.\n\nIf there are major changes in your application that cause \nlow responsiveness anyway, this could be acceptable, but otherwise would \nseverely impact interactivity and suffer from non-optimal total transfer\ntimes.\n\n\u003e Note: Several of our samples do this for the sake of simplicity and reducing\n\u003e the complexity of the samples. But most of them also only have to load\n\u003e resources once and are rather static afterwards.\n\n~~~\n        --------------------------------------------------------------------------\u003e\nGraphics: ...  Render Frame |      transfer           |  IDLE :(\n        --------------------------------------------------------------------------\u003e\nHost    : | wait | IDLE :(  | submit \u0026 wait | IDLE :( | release ... prep Frame + 1\n~~~\n\n### Single Queue Transfer\n\nFor devices that support only one combined graphics and transfer queue \nyou would schedule the transfer into the main queue prior the rendering\noperations for the next frame.\n\nAll `vkQueueSubmit` operations on the same queue are processed in order.\n\nThis time we need to use a `VkFence` to know when it's safe to\nrelease the resources used for staging Operations. \n\nWe would not wait for the fence but rather check for completion (which is what\nwe do in this sample)\n\nAlternatively we setup our render system that we guarantee that \nthe host never is more than N frames ahead of the device and then\nsimply release resources from N frames ago.\n\nThe downside of this approach is that we now impact the overall frame time\ndepending on how much transfer work needs to be done. This can\nresult in stuttering if there is a lot of data.\nThe benefit is that your updates are done in pipeline with the rest of the\nframe, so the update process is safe and won't interfere with data being\nused.\n\n~~~\nF: staging fence -\u003e signals ability to release staging resources\n\n        ----------------------------------------------------------------------\u003e\nGraphics:   Render Frame     | transfer | signal F | Render Frame + 1 ...\n        ----------------------------------------------------------------------\u003e\nHost    : | submit |  ... prep Frame + 1 ...          | check F | try release |\n~~~\n\n### Asynchronous Queue Transfer\n\nHere we can overlap the transfer to the device in a non-blocking way.\nBoth rendering and transfer operations can continue. A lot of \ndevices support this kind workflow.\n\nCompared to the previous approach we need to use a `VkSemaphore` to ensure\nthat our graphics work doesn't start until the transfer has completed.\n\nIt is not that much more complex compared to the previous approach but\nmaximizes the utilization of the various device engines.\n\nHowever, there is one caveat, the target buffers must not be in-flight while\nthe async transfer is done. That means for initial buffer uploads the async\nqueue is ideal, if you want to update existing content, you either have to\ndouble-buffer (alternating the buffers used every other frame to avoid\nthe in-flight scenario), or use the above single queue mechanism.\nIf \"updates\" are a bit more rare and not as data heavy, the two approaches\nshould complement each other.\n\n~~~\nF: staging fence     -\u003e signals ability to release staging resources\nS: staging semaphore -\u003e signals that transfer completed\n\n        ----------------------------------------------------------------------\u003e\nGraphics: ...  Render Frame                 | wait S | Render Frame + 1 ...\n        ----------------------------------------------------------------------\u003e\nTransfer:          | transfer | signal F, S | \n        ----------------------------------------------------------------------\u003e\nHost    : | submit |  ... prep Frame + 1 ...     | check F | try release | ..\n~~~\n\n## Highlights\n\n- `Sample` : implements the sample. The sample itself is designed to run without \n  a window. It is created from an existing `nvvk::Context` and also makes use of \n  the sample specific `FrameBuffer` utility class.\n- `Sample::init` : here you will find the setup of generic utility classes that\n  would be typical for Vulkan samples.\n- `Sample::initTest` : initializes the resources for rendering the torus scene.\n- `Sample::initTestGeometry` : sets up the vertex/index buffers for the torus and\n  also showcases the staging transfers.\n- `SampleWindow` : derives from `NVPWindow` and creates a `VkSurfaceKHR` for it\n  that is used with the `nvvk::SwapChain`. It also handles the events for the sample.\n- `main` : Sets up `nvvk::Context` and implements the principle hot loop.\n\n## Building\nMake sure to have installed a recent [Vulkan-SDK](http://lunarg.com/vulkan-sdk/). \nAlways use 64-bit build configurations.\n\nIdeally, clone this and other interesting [nvpro-samples](https://github.com/nvpro-samples) repositories into a common subdirectory. You will always need [nvpro_core](https://github.com/nvpro-samples/nvpro_core). The nvpro_core is searched either as a subdirectory of the sample, or one directory up.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvpro-samples%2Fvk_async_resources","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnvpro-samples%2Fvk_async_resources","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvpro-samples%2Fvk_async_resources/lists"}