NVIDIAGameWorks / Streamline

Streamline Integration Framework
Other
391 stars 83 forks source link

[Vulkan] VK_ERROR_OUT_OF_POOL_MEMORY in Vulkan::processDescriptors #29

Closed Bizzarrus closed 4 months ago

Bizzarrus commented 7 months ago

Hi :) I tried to integrate Streamline in our Vulkan backend, and when I try to EvaluateFeature(kFeatureNIS), I get a VK_ERROR_OUT_OF_POOL_MEMORY error inside the Vulkan::processDescriptors function.

From what I understand, the issue is that poolSizes only specifies the number of descriptors for a single descriptor set, but the code tries to create 64 descriptor sets, thus the second call of m_ddt.AllocateDescriptorSets fails.

Bizzarrus commented 7 months ago

Proper description of the issue:

  1. in Vulkan::dispatch(...) (vulkan.cpp), there is no error handling for when processDescriptors returns an error. As an result, the issue described here will actually manifest as a nullptr exception, because the pipeline has never been built.
  2. According to this post, the number of descriptors in a descriptor pool must be sufficient for all descriptor sets allocated from that pool - however, SL currently only allocates the number of descriptors for a single descriptor set in Vulkan::processDescriptors (eg `poolSizes specifies 6 descriptors for NIS, but it tries to allocate 64 descriptor sets from that pool)
  3. This only is an issue on AMD cards, as neither the validation layer nor the actual vulkan implementation seem to care about this issue on NVIDIA cards (allocating descriptor sets is successful even if the number of descriptors should be insufficient)

Repro:

  1. Use an AMD card and the latest vulkan SDK, and download the latest SL Sample.
  2. Fix issues in the SL Sample code to be able to run the sample (with NIS) on AMD and Vulkan: 2.1. You'll have to modify the UI code to allow you to enable NIS without enabling DLSS (since DLSS is not available on AMD) 2.2. You'll also have to modify the SLWrapper::FindAdapter to not test for support of DLSS/DLSS_G/Reflex, otherwise it will not give you any adapter 2.3. You might also have to disable the slReflexSleep call in SLWrapper::Callback_FrameCount_Reflex_Sleep_Input_SimStart, as this seem to freeze on a vk semaphore 2.4. You'll also have to modify the code inside SLWrapper::TagResources_DLSS_NIS to actually set the input and output resource states when using vulkan (outputResource.state = uint32_t(vk::ImageLayout::eTransferSrcOptimal); and inputResource.state = uint32_t(vk::ImageLayout::eTransferDstOptimal); worked for me) 2.5. You might also have to add setShaderFloat16(true) to the vk::PhysicalDeviceVulkan12Features() when creating the vulkan device
  3. Run the SL Sample with -vk -debug
  4. Turn NIS on. You should get an immediate crash saying something about nullptr access when trying to bind the pipeline (or an error about out of pool memory, if you already fixed the missing error check).

Proposed fix:

  1. In the Vulkan::dispatch function, if processDescriptors returns something other than ComputeStatus::eOk, this error should be returned immediately instead of continuing the function code.
  2. In the Vulkan::processDescriptors function, multiply ps.descriptorCount with thread.kernel->numDescriptors to allocate sufficient descriptors for all descriptor sets.