@@ -83,6 +83,11 @@ uintptr_t WSIPlatform::get_fullscreen_monitor()
83
83
return 0 ;
84
84
}
85
85
86
+ uintptr_t WSIPlatform::get_native_window ()
87
+ {
88
+ return 0 ;
89
+ }
90
+
86
91
const VkApplicationInfo *WSIPlatform::get_application_info ()
87
92
{
88
93
return nullptr ;
@@ -158,6 +163,12 @@ bool WSI::init_device()
158
163
device = Util::make_handle<Device>();
159
164
device->set_context (*context);
160
165
platform->event_device_created (device.get ());
166
+
167
+ #ifdef _WIN32
168
+ dxgi.reset (new DXGIInteropSwapchain);
169
+ if (!dxgi->init_interop_device (*device))
170
+ dxgi.reset ();
171
+ #endif
161
172
return true ;
162
173
}
163
174
@@ -166,24 +177,106 @@ bool WSI::init_device(DeviceHandle device_handle)
166
177
VK_ASSERT (context);
167
178
device = std::move (device_handle);
168
179
platform->event_device_created (device.get ());
180
+
181
+ #ifdef _WIN32
182
+ dxgi.reset (new DXGIInteropSwapchain);
183
+ if (!dxgi->init_interop_device (*device))
184
+ dxgi.reset ();
185
+ #endif
169
186
return true ;
170
187
}
171
188
189
+ #ifdef _WIN32
190
+ bool WSI::init_surface_swapchain_dxgi (unsigned width, unsigned height)
191
+ {
192
+ if (!dxgi)
193
+ return false ;
194
+
195
+ // Anything fancy like compute present cannot use DXGI.
196
+ if (current_extra_usage)
197
+ return false ;
198
+
199
+ HWND hwnd = reinterpret_cast <HWND>(platform->get_native_window ());
200
+ if (!hwnd)
201
+ return false ;
202
+
203
+ VkSurfaceFormatKHR format = {};
204
+ switch (current_backbuffer_format)
205
+ {
206
+ case BackbufferFormat::UNORM:
207
+ format = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
208
+ break ;
209
+
210
+ case BackbufferFormat::sRGB :
211
+ format = { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
212
+ break ;
213
+
214
+ case BackbufferFormat::HDR10:
215
+ format = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_HDR10_ST2084_EXT };
216
+ break ;
217
+ }
218
+
219
+ constexpr unsigned num_images = 3 ;
220
+
221
+ if (!dxgi->init_swapchain (hwnd, format, width, height, num_images))
222
+ return false ;
223
+
224
+ LOGI (" Initialized DXGI interop swapchain!\n " );
225
+
226
+ swapchain_width = width;
227
+ swapchain_height = height;
228
+ swapchain_aspect_ratio = platform->get_aspect_ratio ();
229
+ swapchain_current_prerotate = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
230
+ swapchain_surface_format = dxgi->get_current_surface_format ();
231
+ has_acquired_swapchain_index = false ;
232
+
233
+ const uint32_t queue_present_support = 1u << context->get_queue_info ().family_indices [QUEUE_INDEX_GRAPHICS];
234
+ device->set_swapchain_queue_family_support (queue_present_support);
235
+
236
+ swapchain_images.clear ();
237
+ for (unsigned i = 0 ; i < num_images; i++)
238
+ swapchain_images.push_back (dxgi->get_vulkan_image (i));
239
+
240
+ device->init_swapchain (swapchain_images, swapchain_width, swapchain_height,
241
+ swapchain_surface_format.format ,
242
+ swapchain_current_prerotate,
243
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
244
+ platform->get_frame_timer ().reset ();
245
+
246
+ platform->event_swapchain_destroyed ();
247
+ platform->event_swapchain_created (device.get (), swapchain, swapchain_width, swapchain_height,
248
+ swapchain_aspect_ratio, num_images,
249
+ swapchain_surface_format.format ,
250
+ swapchain_surface_format.colorSpace ,
251
+ swapchain_current_prerotate);
252
+
253
+ return true ;
254
+ }
255
+ #endif
256
+
172
257
bool WSI::init_surface_swapchain ()
173
258
{
174
259
VK_ASSERT (surface == VK_NULL_HANDLE);
175
260
VK_ASSERT (context);
176
261
VK_ASSERT (device);
177
262
263
+ unsigned width = platform->get_surface_width ();
264
+ unsigned height = platform->get_surface_height ();
265
+
266
+ #ifdef _WIN32
267
+ if (init_surface_swapchain_dxgi (width, height))
268
+ return true ;
269
+ else
270
+ dxgi.reset ();
271
+ #endif
272
+
178
273
surface = platform->create_surface (context->get_instance (), context->get_gpu ());
179
274
if (surface == VK_NULL_HANDLE)
180
275
{
181
276
LOGE (" Failed to create VkSurfaceKHR.\n " );
182
277
return false ;
183
278
}
184
279
185
- unsigned width = platform->get_surface_width ();
186
- unsigned height = platform->get_surface_height ();
187
280
swapchain_aspect_ratio = platform->get_aspect_ratio ();
188
281
189
282
VkBool32 supported = VK_FALSE;
@@ -368,6 +461,11 @@ void WSI::drain_swapchain(bool in_tear_down)
368
461
369
462
void WSI::tear_down_swapchain ()
370
463
{
464
+ #ifdef _WIN32
465
+ // We only do explicit teardown on exit.
466
+ dxgi.reset ();
467
+ #endif
468
+
371
469
drain_swapchain (true );
372
470
platform->event_swapchain_destroyed ();
373
471
table->vkDestroySwapchainKHR (context->get_device (), swapchain, nullptr );
@@ -468,6 +566,55 @@ void WSI::set_low_latency_mode(bool enable)
468
566
low_latency_mode_enable = enable;
469
567
}
470
568
569
+ #ifdef _WIN32
570
+ bool WSI::begin_frame_dxgi ()
571
+ {
572
+ Semaphore acquire;
573
+
574
+ while (!acquire)
575
+ {
576
+ if (!dxgi->acquire (acquire, swapchain_index))
577
+ return false ;
578
+
579
+ acquire->signal_external ();
580
+ has_acquired_swapchain_index = true ;
581
+
582
+ // Poll after acquire as well for optimal latency.
583
+ platform->poll_input ();
584
+
585
+ // Polling input may trigger a resize event. Trying to present in that situation without ResizeBuffers
586
+ // cause wonky issues on DXGI.
587
+ if (platform->should_resize ())
588
+ update_framebuffer (platform->get_surface_width (), platform->get_surface_height ());
589
+
590
+ // If update_framebuffer caused a resize, we won't have an acquire index anymore, reacquire.
591
+ if (!has_acquired_swapchain_index)
592
+ acquire.reset ();
593
+ }
594
+
595
+ auto wait_ts = device->write_calibrated_timestamp ();
596
+ if (!dxgi->wait_latency (present_frame_latency))
597
+ {
598
+ LOGE (" Failed to wait on latency handle.\n " );
599
+ return false ;
600
+ }
601
+ device->register_time_interval (" WSI" , std::move (wait_ts), device->write_calibrated_timestamp (),
602
+ " DXGI wait latency" );
603
+
604
+ auto frame_time = platform->get_frame_timer ().frame ();
605
+ auto elapsed_time = platform->get_frame_timer ().get_elapsed ();
606
+
607
+ smooth_frame_time = frame_time;
608
+ smooth_elapsed_time = elapsed_time;
609
+
610
+ platform->event_frame_tick (frame_time, elapsed_time);
611
+ platform->event_swapchain_index (device.get (), swapchain_index);
612
+ device->set_acquire_semaphore (swapchain_index, std::move (acquire));
613
+
614
+ return true ;
615
+ }
616
+ #endif
617
+
471
618
bool WSI::begin_frame ()
472
619
{
473
620
if (frame_is_external)
@@ -478,26 +625,38 @@ bool WSI::begin_frame()
478
625
#endif
479
626
480
627
device->next_frame_context ();
628
+ external_release.reset ();
481
629
482
630
#ifdef VULKAN_WSI_TIMING_DEBUG
483
631
auto next_frame_end = Util::get_current_time_nsecs ();
484
632
LOGI (" Waited for vacant frame context for %.3f ms.\n " , (next_frame_end - next_frame_start) * 1e-6 );
485
633
#endif
486
634
487
- if (swapchain == VK_NULL_HANDLE || platform->should_resize () || swapchain_is_suboptimal)
488
- update_framebuffer (platform->get_surface_width (), platform->get_surface_height ());
635
+ #ifdef _WIN32
636
+ if (dxgi)
637
+ {
638
+ if (platform->should_resize ())
639
+ update_framebuffer (platform->get_surface_width (), platform->get_surface_height ());
640
+
641
+ if (has_acquired_swapchain_index)
642
+ return true ;
643
+ return begin_frame_dxgi ();
644
+ }
645
+ else
646
+ #endif
647
+ {
648
+ if (swapchain == VK_NULL_HANDLE || platform->should_resize () || swapchain_is_suboptimal)
649
+ update_framebuffer (platform->get_surface_width (), platform->get_surface_height ());
650
+ if (has_acquired_swapchain_index)
651
+ return true ;
652
+ }
489
653
490
654
if (swapchain == VK_NULL_HANDLE)
491
655
{
492
656
LOGE (" Completely lost swapchain. Cannot continue.\n " );
493
657
return false ;
494
658
}
495
659
496
- if (has_acquired_swapchain_index)
497
- return true ;
498
-
499
- external_release.reset ();
500
-
501
660
VkResult result;
502
661
do
503
662
{
@@ -597,6 +756,17 @@ bool WSI::begin_frame()
597
756
return true ;
598
757
}
599
758
759
+ #ifdef _WIN32
760
+ bool WSI::end_frame_dxgi ()
761
+ {
762
+ auto release = device->consume_release_semaphore ();
763
+ VK_ASSERT (release);
764
+ VK_ASSERT (release->is_signalled ());
765
+ VK_ASSERT (!release->is_pending_wait ());
766
+ return dxgi->present (std::move (release), current_present_mode == PresentMode::SyncToVBlank);
767
+ }
768
+ #endif
769
+
600
770
bool WSI::end_frame ()
601
771
{
602
772
device->end_frame_context ();
@@ -616,10 +786,16 @@ bool WSI::end_frame()
616
786
617
787
has_acquired_swapchain_index = false ;
618
788
789
+ #ifdef _WIN32
790
+ if (dxgi)
791
+ return end_frame_dxgi ();
792
+ #endif
793
+
619
794
auto release = device->consume_release_semaphore ();
620
795
VK_ASSERT (release);
621
796
VK_ASSERT (release->is_signalled ());
622
797
VK_ASSERT (!release->is_pending_wait ());
798
+
623
799
auto release_semaphore = release->get_semaphore ();
624
800
VK_ASSERT (release_semaphore != VK_NULL_HANDLE);
625
801
@@ -752,12 +928,22 @@ void WSI::update_framebuffer(unsigned width, unsigned height)
752
928
{
753
929
if (context && device)
754
930
{
755
- drain_swapchain ( false );
756
- if (blocking_init_swapchain (width, height) )
931
+ # ifdef _WIN32
932
+ if (dxgi )
757
933
{
758
- device->init_swapchain (swapchain_images, swapchain_width, swapchain_height, swapchain_surface_format.format ,
759
- swapchain_current_prerotate,
760
- current_extra_usage | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
934
+ if (!init_surface_swapchain_dxgi (width, height))
935
+ LOGE (" Failed to resize DXGI swapchain.\n " );
936
+ }
937
+ else
938
+ #endif
939
+ {
940
+ drain_swapchain (false );
941
+ if (blocking_init_swapchain (width, height))
942
+ {
943
+ device->init_swapchain (swapchain_images, swapchain_width, swapchain_height,
944
+ swapchain_surface_format.format , swapchain_current_prerotate,
945
+ current_extra_usage | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
946
+ }
761
947
}
762
948
}
763
949
@@ -770,6 +956,15 @@ bool WSI::update_active_presentation_mode(PresentMode mode)
770
956
if (current_present_mode == mode)
771
957
return true ;
772
958
959
+ #ifdef _WIN32
960
+ // We set this on Present time.
961
+ if (dxgi)
962
+ {
963
+ current_present_mode = mode;
964
+ return true ;
965
+ }
966
+ #endif
967
+
773
968
for (auto m : present_mode_compat_group)
774
969
{
775
970
bool match = false ;
0 commit comments