3636#include " ../dxvk/rtx_render/rtx_dlfg.h"
3737// NV-DXVK end
3838
39+ // NV-DXVK start: FSR FG integration
40+ #include " ../dxvk/rtx_render/rtx_fsr_framegen.h"
41+ // NV-DXVK end
42+
3943namespace dxvk {
4044 // NV-DXVK start: App Controlled FSE
4145 enum FSEState {
@@ -406,22 +410,41 @@ namespace dxvk {
406410 if (m_dlfgPresenter == nullptr ) {
407411 return true ;
408412 }
413+ } else if (m_context->isFSRFGEnabled ()) {
414+ // FSR FG is enabled - need FSR FG presenter
415+ if (m_fsrfgPresenter == nullptr ) {
416+ Logger::info (" NeedRecreatePresenter: FSR FG enabled but no FSR FG presenter, need to recreate" );
417+ return true ;
418+ }
419+ } else if (m_fsrfgPresenter != nullptr ) {
420+ // FSR FG presenter exists but FSR FG is disabled - recreate a normal presenter
421+ // so present mode / vsync behavior is restored and future FG mode switches are clean.
422+ Logger::info (" NeedRecreatePresenter: FSR FG disabled with FSR presenter active, recreating presenter" );
423+ return true ;
409424 } else {
410425 if (m_presenter == nullptr ) {
411426 return true ;
412427 }
413428 }
414429
415430 // one must be null, one must be non-null
416- assert (m_presenter != nullptr || m_dlfgPresenter != nullptr );
417- assert (m_presenter == nullptr || m_dlfgPresenter == nullptr );
431+ assert (m_presenter != nullptr || m_dlfgPresenter != nullptr || m_fsrfgPresenter != nullptr );
432+ assert (( m_presenter == nullptr ) + ( m_dlfgPresenter == nullptr ) + (m_fsrfgPresenter == nullptr ) >= 2 );
418433 return false ;
419434 }
420435
421436 vk::Presenter* D3D9SwapChainEx::GetPresenter () const {
422- const auto presenter = m_presenter != nullptr ? m_presenter.ptr () : m_dlfgPresenter.ptr ();
437+ // NV-DXVK: Return whichever presenter is active (normal, DLFG, or FSR FG)
438+ vk::Presenter* presenter = nullptr ;
439+ if (m_presenter != nullptr ) {
440+ presenter = m_presenter.ptr ();
441+ } else if (m_dlfgPresenter != nullptr ) {
442+ presenter = m_dlfgPresenter.ptr ();
443+ } else if (m_fsrfgPresenter != nullptr ) {
444+ presenter = m_fsrfgPresenter.ptr ();
445+ }
423446
424- // Note: The returned presenter must be non-null as one of the two presenters must be non-null at all times,
447+ // Note: The returned presenter must be non-null as one of the presenters must be non-null at all times,
425448 // and because code will blindly dereference this returned pointer.
426449 assert (presenter != nullptr );
427450
@@ -1350,13 +1373,40 @@ namespace dxvk {
13501373
13511374 m_device->waitForIdle ();
13521375
1376+ // NV-DXVK start: FSR FG - Capture surface before destroying old presenter
1377+ // This allows reusing the surface when switching presenter types at runtime
1378+ // We call releaseSurface() which sets the presenter's internal handle to VK_NULL_HANDLE
1379+ // so the destructor won't destroy it - we transfer ownership to the new presenter
1380+ VkSurfaceKHR existingSurface = VK_NULL_HANDLE ;
1381+ vk::Presenter* currentPresenter = GetPresenter ();
1382+ if (currentPresenter != nullptr ) {
1383+ existingSurface = currentPresenter->releaseSurface ();
1384+ Logger::info (" CreatePresenter: Captured existing surface for reuse" );
1385+ }
1386+ // NV-DXVK end
1387+
1388+ // Destroy old presenters - must happen before creating new ones
1389+ // to release the swapchain (but surface ownership transferred above)
13531390 m_presenter = nullptr ;
13541391 m_presentStatus.result = VK_SUCCESS ;
13551392
1356- // NV-DXVK start: DLFG integration
1393+ // NV-DXVK start: DLFG/FSR FG integration
13571394 m_dlfgPresenter = nullptr ;
1395+ m_fsrfgPresenter = nullptr ;
1396+
1397+ // Wait after destroying presenters to ensure swapchains are fully released
1398+ m_device->waitForIdle ();
1399+
13581400 const bool dlfgEnabled = m_context->isDLFGEnabled ();
1359- DxvkDeviceQueue presentQueue = dlfgEnabled ? m_device->queues ().present : m_device->queues ().graphics ;
1401+ const bool fsrfgEnabled = m_context->isFSRFGEnabled ();
1402+ // Only create FSR FG presenter if enabled - runtime enabling requires restart
1403+ // This avoids VK_ERROR_NATIVE_WINDOW_IN_USE_KHR crash at startup
1404+ const bool fsrfgSupported = DxvkFSRFrameGen::supportsFSRFrameGen ();
1405+ const bool createFsrfgPresenter = fsrfgEnabled && fsrfgSupported && !dlfgEnabled;
1406+ Logger::info (str::format (" CreatePresenter: dlfgEnabled=" , dlfgEnabled,
1407+ " , fsrfgEnabled=" , fsrfgEnabled, " , fsrfgSupported=" , fsrfgSupported,
1408+ " , createFsrfgPresenter=" , createFsrfgPresenter));
1409+ DxvkDeviceQueue presentQueue = (dlfgEnabled || createFsrfgPresenter) ? m_device->queues ().present : m_device->queues ().graphics ;
13601410
13611411 vk::PresenterDevice presenterDevice;
13621412 presenterDevice.queueFamily = presentQueue.queueFamily ;
@@ -1372,19 +1422,49 @@ namespace dxvk {
13721422 presenterDesc.numPresentModes = PickPresentModes (false , presenterDesc.presentModes );
13731423 presenterDesc.fullScreenExclusive = PickFullscreenMode ();
13741424
1375- // NV-DXVK start: DLFG integration
1425+ // NV-DXVK start: DLFG/FSR FG integration
13761426 if (dlfgEnabled) {
13771427 // DLFG presents 2 times (1 more frame) in each real frame,
13781428 // increase image count by 1 to avoid resource waiting.
13791429 presenterDesc.imageCount ++;
1430+ // destroy the existing surface if we're creating DLFG presenter
1431+ if (existingSurface != VK_NULL_HANDLE ) {
1432+ m_device->adapter ()->vki ()->vkDestroySurfaceKHR (
1433+ m_device->adapter ()->vki ()->instance (), existingSurface, nullptr );
1434+ existingSurface = VK_NULL_HANDLE ;
1435+ }
13801436 m_dlfgPresenter = new DxvkDLFGPresenter (m_device,
13811437 m_context,
13821438 m_window,
13831439 m_device->adapter ()->vki (),
13841440 m_device->vkd (),
13851441 presenterDevice,
13861442 presenterDesc);
1443+ } else if (createFsrfgPresenter) {
1444+ // Create FSR FG presenter when enabled
1445+ // FFX contexts are created lazily in presentImage() when ready
1446+ // Pass the existing surface to avoid VK_ERROR_NATIVE_WINDOW_IN_USE_KHR
1447+ presenterDesc.imageCount ++;
1448+ m_fsrfgPresenter = new DxvkFSRFGPresenter (m_device,
1449+ m_context,
1450+ m_window,
1451+ m_device->adapter ()->vki (),
1452+ m_device->vkd (),
1453+ presenterDevice,
1454+ presenterDesc,
1455+ existingSurface);
1456+ existingSurface = VK_NULL_HANDLE ; // Ownership transferred
1457+ Logger::info (str::format (" FSR FG: Created FSR FG Presenter for swapchain " ,
1458+ presenterDesc.imageExtent .width , " x" , presenterDesc.imageExtent .height ,
1459+ " (frame generation " , fsrfgEnabled ? " enabled" : " disabled, can be enabled at runtime" , " )" ));
13871460 } else {
1461+ // Regular presenter - needs to destroy existing surface and create new one
1462+ // TODO: Could also add surface reuse to regular presenter
1463+ if (existingSurface != VK_NULL_HANDLE ) {
1464+ m_device->adapter ()->vki ()->vkDestroySurfaceKHR (
1465+ m_device->adapter ()->vki ()->instance (), existingSurface, nullptr );
1466+ existingSurface = VK_NULL_HANDLE ;
1467+ }
13881468 m_presenter = new vk::Presenter (m_window,
13891469 m_device->adapter ()->vki (),
13901470 m_device->vkd (),
0 commit comments