Fix imgui causing a crash when using DLSSG on Vulkan

Slopped.
This commit is contained in:
FakeMichau committed 2026-10-13 01:29:24 +02:00
1 parent e7e28a2a34
commit 01195e9bfe
6 files changed
+73 -97

No files matched your search

-1
View File
@@ -194,7 +194,6 @@ class State
bool dlssgDebugView = false;
bool dlssgInterpolatedOnly = false;
uint64_t dlssgLastFrame = 0;
uint32_t delayMenuRenderBy = 0;
// FSR Common
float lastFsrCameraNear = 0.0f;
-16
View File
@@ -7,8 +7,6 @@
#include <nvapi/fakenvapi.h>
#include <misc/IdentifyGpu.h>
#include <hooks/Reflex_Hooks.h>
#include <menu/menu_overlay_base.h>
#include <framegen/nvngx/Nvngx_FG.h>
#include <framegen/xefg/XeFG_Dx12.h>
#include <proxies/KernelBase_Proxy.h>
@@ -1349,20 +1347,6 @@ sl::Result StreamlineHooks::hkslDLSSGSetOptions(const sl::ViewportHandle& viewpo
newOptions.dynamicTargetFrameRate = Config::Instance()->FGDLSSGFramerateTargetDMFG.value();
}
if (state.swapchainApi == API::Vulkan)
{
// Only matters for Vulkan, DX doesn't use this delay
if (dlssgPotentiallyActive && !MenuOverlayBase::IsVisible())
state.delayMenuRenderBy = 10;
if (MenuOverlayBase::IsVisible())
{
newOptions.mode = sl::DLSSGMode::eOff;
newOptions.flags |= sl::DLSSGFlags::eRetainResourcesWhenOff;
ReflexHooks::setDlssgFrameCount(0);
}
}
LOG_TRACE("DLSSG Modified Mode: {}", magic_enum::enum_name(newOptions.mode));
if (dlssgPotentiallyActive && state.streamlineVersion >= feature_version { 2, 7, 1 })
@@ -1328,6 +1328,12 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
bd->VulkanInitInfo.MinImageCount = min_image_count;
}
void ImGui_ImplVulkan_SetQueue(VkQueue queue)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
bd->VulkanInitInfo.Queue = queue;
}
// Register a texture by creating a descriptor
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
@@ -114,6 +114,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(bool shutdown_platform
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
IMGUI_IMPL_API void ImGui_ImplVulkan_SetQueue(VkQueue queue); // Queue used for texture uploads
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex);
-6
View File
@@ -5027,12 +5027,6 @@ void MenuCommon::RenderFrameGenerationRuntimeSettings(RenderMenuContext& ctx)
"GPUs under Windows\nCan cause stutters, so best to use only when necessary");
}
}
else if (state.swapchainApi == Vulkan)
{
ImGui::TextColored(toneMapColor(ImVec4(1.f, 0.8f, 0.f, 1.f)),
"DLSSG is purposefully disabled when this menu is visible");
ImGui::Spacing();
}
}
bool isLoaded = false;
+66 -74
View File
@@ -554,11 +554,11 @@ bool MenuOverlayVk::QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo)
{
auto semaphoreIndex = _frameCount % _scImageCount;
// With DLSSG the present comes from Streamline's thread, while the game's queue
// can be waiting on that thread. Using the presenting queue avoids a deadlock.
ImGui_ImplVulkan_SetQueue(queue);
ImGui_ImplVulkan_NewFrame();
if (State::Instance().delayMenuRenderBy > 0)
State::Instance().delayMenuRenderBy--;
// Blur images are only created once the menu is opened, menu decides if they are used
bool blurReady = false;
if (_menuBlur || MenuOverlayBase::IsVisible())
@@ -576,81 +576,73 @@ bool MenuOverlayVk::QueuePresent(VkQueue queue, VkPresentInfoKHR* pPresentInfo)
if (MenuOverlayBase::RenderMenu())
{
if (State::Instance().delayMenuRenderBy == 0)
uint32_t idx = pPresentInfo->pImageIndices[0];
ImGui_ImplVulkanH_Frame* fd = &_ImVulkan_Frames[idx];
const bool blurMenu = blurReady && MenuCommon::BackgroundBlurUsed();
vkWaitForFences(_ImVulkan_Info.Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX);
vkResetFences(_ImVulkan_Info.Device, 1, &fd->Fence);
{
uint32_t idx = pPresentInfo->pImageIndices[0];
ImGui_ImplVulkanH_Frame* fd = &_ImVulkan_Frames[idx];
const bool blurMenu = blurReady && MenuCommon::BackgroundBlurUsed();
vkWaitForFences(_ImVulkan_Info.Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX);
vkResetFences(_ImVulkan_Info.Device, 1, &fd->Fence);
{
vkResetCommandPool(_ImVulkan_Info.Device, fd->CommandPool, 0);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(fd->CommandBuffer, &info);
}
// Needs to be outside of the render pass
if (blurMenu)
_menuBlur->Dispatch(fd->CommandBuffer, fd->Backbuffer);
{
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = _vkRenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = static_cast<uint32_t>(ImGui::GetIO().DisplaySize.x);
info.renderArea.extent.height = static_cast<uint32_t>(ImGui::GetIO().DisplaySize.y);
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer);
auto ecbResult = vkEndCommandBuffer(fd->CommandBuffer);
if (ecbResult != VK_SUCCESS)
{
LOG_ERROR("vkQueueSubmit error: {0:X}", (UINT) ecbResult);
return false;
}
// Submit queue and semaphores
LOG_DEBUG("waitSemaphoreCount: {0}", pPresentInfo->waitSemaphoreCount);
// Blur copies the image with a transfer, so everything has to wait for the game
VkPipelineStageFlags waitStages[8];
std::fill(std::begin(waitStages), std::end(waitStages),
blurMenu ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &fd->CommandBuffer;
submit_info.pWaitDstStageMask = waitStages;
submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount;
submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &_ImVulkan_Semaphores[semaphoreIndex];
auto qResult = vkQueueSubmit(_ImVulkan_Info.Queue, 1, &submit_info, fd->Fence);
if (qResult != VK_SUCCESS)
{
LOG_ERROR("vkQueueSubmit error: {0:X}", (UINT) qResult);
return false;
}
pPresentInfo->waitSemaphoreCount = 1;
pPresentInfo->pWaitSemaphores = &_ImVulkan_Semaphores[semaphoreIndex];
vkResetCommandPool(_ImVulkan_Info.Device, fd->CommandPool, 0);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(fd->CommandBuffer, &info);
}
else
// Needs to be outside of the render pass
if (blurMenu)
_menuBlur->Dispatch(fd->CommandBuffer, fd->Backbuffer);
{
// To make RenderMenu happy as it expects this
ImGui::Render();
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = _vkRenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = static_cast<uint32_t>(ImGui::GetIO().DisplaySize.x);
info.renderArea.extent.height = static_cast<uint32_t>(ImGui::GetIO().DisplaySize.y);
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer);
auto ecbResult = vkEndCommandBuffer(fd->CommandBuffer);
if (ecbResult != VK_SUCCESS)
{
LOG_ERROR("vkQueueSubmit error: {0:X}", (UINT) ecbResult);
return false;
}
// Submit queue and semaphores
LOG_DEBUG("waitSemaphoreCount: {0}", pPresentInfo->waitSemaphoreCount);
// Blur copies the image with a transfer, so everything has to wait for the game
VkPipelineStageFlags waitStages[8];
std::fill(std::begin(waitStages), std::end(waitStages),
blurMenu ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &fd->CommandBuffer;
submit_info.pWaitDstStageMask = waitStages;
submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount;
submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &_ImVulkan_Semaphores[semaphoreIndex];
auto qResult = vkQueueSubmit(queue, 1, &submit_info, fd->Fence);
if (qResult != VK_SUCCESS)
{
LOG_ERROR("vkQueueSubmit error: {0:X}", (UINT) qResult);
return false;
}
pPresentInfo->waitSemaphoreCount = 1;
pPresentInfo->pWaitSemaphores = &_ImVulkan_Semaphores[semaphoreIndex];
}
}