10
10
using System . Runtime . InteropServices ;
11
11
using Silk . NET . Core ;
12
12
using Silk . NET . Core . Native ;
13
+ using Silk . NET . Maths ;
13
14
using Silk . NET . Vulkan ;
14
15
using Silk . NET . Vulkan . Extensions . EXT ;
15
16
using Silk . NET . Vulkan . Extensions . KHR ;
@@ -22,6 +23,7 @@ public class HelloTriangleApplication
22
23
{
23
24
public const bool EnableValidationLayers = true ;
24
25
public const int MaxFramesInFlight = 8 ;
26
+ public const bool EventBasedRendering = false ;
25
27
26
28
public void Run ( )
27
29
{
@@ -63,6 +65,8 @@ public void Run()
63
65
private Fence [ ] _imagesInFlight ;
64
66
private uint _currentFrame ;
65
67
68
+ private bool _framebufferResized = false ;
69
+
66
70
private Vk _vk ;
67
71
private KhrSurface _vkSurface ;
68
72
private KhrSwapchain _vkSwapchain ;
@@ -74,13 +78,22 @@ public void Run()
74
78
private void InitWindow ( )
75
79
{
76
80
var opts = WindowOptions . DefaultVulkan ;
81
+ opts . IsEventDriven = EventBasedRendering ;
77
82
_window = Window . Create ( opts ) ;
78
83
if ( _window ? . VkSurface is null )
79
84
{
80
85
throw new NotSupportedException ( "Windowing platform doesn't support Vulkan." ) ;
81
86
}
82
87
83
88
_window . Initialize ( ) ;
89
+ _window . FramebufferResize += OnFramebufferResize ;
90
+ }
91
+
92
+ private void OnFramebufferResize ( Vector2D < int > size )
93
+ {
94
+ _framebufferResized = true ;
95
+ RecreateSwapChain ( ) ;
96
+ _window . DoRender ( ) ;
84
97
}
85
98
86
99
private void InitVulkan ( )
@@ -113,9 +126,19 @@ private unsafe void DrawFrame(double obj)
113
126
_vk . WaitForFences ( _device , 1 , in fence , Vk . True , ulong . MaxValue ) ;
114
127
115
128
uint imageIndex ;
116
- _vkSwapchain . AcquireNextImage
129
+ Result result = _vkSwapchain . AcquireNextImage
117
130
( _device , _swapchain , ulong . MaxValue , _imageAvailableSemaphores [ _currentFrame ] , default , & imageIndex ) ;
118
131
132
+ if ( result == Result . ErrorOutOfDateKhr )
133
+ {
134
+ RecreateSwapChain ( ) ;
135
+ return ;
136
+ }
137
+ else if ( result != Result . Success && result != Result . SuboptimalKhr )
138
+ {
139
+ throw new Exception ( "failed to acquire swap chain image!" ) ;
140
+ }
141
+
119
142
if ( _imagesInFlight [ imageIndex ] . Handle != 0 )
120
143
{
121
144
_vk . WaitForFences ( _device , 1 , in _imagesInFlight [ imageIndex ] , Vk . True , ulong . MaxValue ) ;
@@ -165,14 +188,26 @@ private unsafe void DrawFrame(double obj)
165
188
PImageIndices = & imageIndex
166
189
} ;
167
190
168
- _vkSwapchain . QueuePresent ( _presentQueue , & presentInfo ) ;
191
+ result = _vkSwapchain . QueuePresent ( _presentQueue , & presentInfo ) ;
192
+ }
193
+
194
+ if ( result == Result . ErrorOutOfDateKhr || result == Result . SuboptimalKhr || _framebufferResized )
195
+ {
196
+ _framebufferResized = false ;
197
+ RecreateSwapChain ( ) ;
198
+ }
199
+ else if ( result != Result . Success )
200
+ {
201
+ throw new Exception ( "failed to present swap chain image!" ) ;
169
202
}
170
203
171
204
_currentFrame = ( _currentFrame + 1 ) % MaxFramesInFlight ;
172
205
}
173
206
174
207
private unsafe void Cleanup ( )
175
208
{
209
+ CleanupSwapchain ( ) ;
210
+
176
211
for ( var i = 0 ; i < MaxFramesInFlight ; i ++ )
177
212
{
178
213
_vk . DestroySemaphore ( _device , _renderFinishedSemaphores [ i ] , null ) ;
@@ -182,11 +217,29 @@ private unsafe void Cleanup()
182
217
183
218
_vk . DestroyCommandPool ( _device , _commandPool , null ) ;
184
219
220
+ _vk . DestroyDevice ( _device , null ) ;
221
+
222
+ if ( EnableValidationLayers )
223
+ {
224
+ _debugUtils . DestroyDebugUtilsMessenger ( _instance , _debugMessenger , null ) ;
225
+ }
226
+
227
+ _vkSurface . DestroySurface ( _instance , _surface , null ) ;
228
+ _vk . DestroyInstance ( _instance , null ) ;
229
+ }
230
+
231
+ private unsafe void CleanupSwapchain ( )
232
+ {
185
233
foreach ( var framebuffer in _swapchainFramebuffers )
186
234
{
187
235
_vk . DestroyFramebuffer ( _device , framebuffer , null ) ;
188
236
}
189
237
238
+ fixed ( CommandBuffer * buffers = _commandBuffers )
239
+ {
240
+ _vk . FreeCommandBuffers ( _device , _commandPool , ( uint ) _commandBuffers . Length , buffers ) ;
241
+ }
242
+
190
243
_vk . DestroyPipeline ( _device , _graphicsPipeline , null ) ;
191
244
_vk . DestroyPipelineLayout ( _device , _pipelineLayout , null ) ;
192
245
_vk . DestroyRenderPass ( _device , _renderPass , null ) ;
@@ -197,15 +250,6 @@ private unsafe void Cleanup()
197
250
}
198
251
199
252
_vkSwapchain . DestroySwapchain ( _device , _swapchain , null ) ;
200
- _vk . DestroyDevice ( _device , null ) ;
201
-
202
- if ( EnableValidationLayers )
203
- {
204
- _debugUtils . DestroyDebugUtilsMessenger ( _instance , _debugMessenger , null ) ;
205
- }
206
-
207
- _vkSurface . DestroySurface ( _instance , _surface , null ) ;
208
- _vk . DestroyInstance ( _instance , null ) ;
209
253
}
210
254
211
255
private unsafe void CreateInstance ( )
@@ -324,8 +368,13 @@ private unsafe uint DebugCallback
324
368
void * pUserData
325
369
)
326
370
{
327
- Console . WriteLine
328
- ( $ "{ messageSeverity } { messageTypes } " + Marshal . PtrToStringAnsi ( ( nint ) pCallbackData ->PMessage ) ) ;
371
+ if ( messageSeverity > DebugUtilsMessageSeverityFlagsEXT . DebugUtilsMessageSeverityVerboseBitExt )
372
+ {
373
+ Console . WriteLine
374
+ ( $ "{ messageSeverity } { messageTypes } " + Marshal . PtrToStringAnsi ( ( nint ) pCallbackData ->PMessage ) ) ;
375
+
376
+ }
377
+
329
378
return Vk . False ;
330
379
}
331
380
@@ -363,101 +412,93 @@ private unsafe void PickPhysicalDevice()
363
412
throw new Exception ( "No suitable device." ) ;
364
413
}
365
414
366
- private static readonly ConcurrentDictionary < PhysicalDevice , SwapChainSupportDetails > _swapChainSupportDetailsCache
367
- = new ConcurrentDictionary < PhysicalDevice , SwapChainSupportDetails > ( ) ;
415
+ // Caching the returned values breaks the ability for resizing the window
368
416
private unsafe SwapChainSupportDetails QuerySwapChainSupport ( PhysicalDevice device )
369
417
{
370
- return _swapChainSupportDetailsCache . GetOrAdd ( device , d =>
371
- {
372
- var details = new SwapChainSupportDetails ( ) ;
373
- _vkSurface . GetPhysicalDeviceSurfaceCapabilities ( d , _surface , out var surfaceCapabilities ) ;
374
- details . Capabilities = surfaceCapabilities ;
418
+ var details = new SwapChainSupportDetails ( ) ;
419
+ _vkSurface . GetPhysicalDeviceSurfaceCapabilities ( device , _surface , out var surfaceCapabilities ) ;
420
+ details . Capabilities = surfaceCapabilities ;
375
421
376
- var formatCount = 0u ;
377
- _vkSurface . GetPhysicalDeviceSurfaceFormats ( d , _surface , & formatCount , null ) ;
422
+ var formatCount = 0u ;
423
+ _vkSurface . GetPhysicalDeviceSurfaceFormats ( device , _surface , & formatCount , null ) ;
378
424
379
- if ( formatCount != 0 )
380
- {
381
- details . Formats = new SurfaceFormatKHR [ formatCount ] ;
425
+ if ( formatCount != 0 )
426
+ {
427
+ details . Formats = new SurfaceFormatKHR [ formatCount ] ;
382
428
383
- using var mem = GlobalMemory . Allocate ( ( int ) formatCount * sizeof ( SurfaceFormatKHR ) ) ;
384
- var formats = ( SurfaceFormatKHR * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
429
+ using var mem = GlobalMemory . Allocate ( ( int ) formatCount * sizeof ( SurfaceFormatKHR ) ) ;
430
+ var formats = ( SurfaceFormatKHR * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
385
431
386
- _vkSurface . GetPhysicalDeviceSurfaceFormats ( d , _surface , & formatCount , formats ) ;
432
+ _vkSurface . GetPhysicalDeviceSurfaceFormats ( device , _surface , & formatCount , formats ) ;
387
433
388
- for ( var i = 0 ; i < formatCount ; i ++ )
389
- {
390
- details . Formats [ i ] = formats [ i ] ;
391
- }
434
+ for ( var i = 0 ; i < formatCount ; i ++ )
435
+ {
436
+ details . Formats [ i ] = formats [ i ] ;
392
437
}
438
+ }
393
439
394
- var presentModeCount = 0u ;
395
- _vkSurface . GetPhysicalDeviceSurfacePresentModes ( d , _surface , & presentModeCount , null ) ;
440
+ var presentModeCount = 0u ;
441
+ _vkSurface . GetPhysicalDeviceSurfacePresentModes ( device , _surface , & presentModeCount , null ) ;
396
442
397
- if ( presentModeCount != 0 )
398
- {
399
- details . PresentModes = new PresentModeKHR [ presentModeCount ] ;
443
+ if ( presentModeCount != 0 )
444
+ {
445
+ details . PresentModes = new PresentModeKHR [ presentModeCount ] ;
400
446
401
- using var mem = GlobalMemory . Allocate ( ( int ) presentModeCount * sizeof ( PresentModeKHR ) ) ;
402
- var modes = ( PresentModeKHR * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
447
+ using var mem = GlobalMemory . Allocate ( ( int ) presentModeCount * sizeof ( PresentModeKHR ) ) ;
448
+ var modes = ( PresentModeKHR * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
403
449
404
- _vkSurface . GetPhysicalDeviceSurfacePresentModes ( d , _surface , & presentModeCount , modes ) ;
450
+ _vkSurface . GetPhysicalDeviceSurfacePresentModes ( device , _surface , & presentModeCount , modes ) ;
405
451
406
- for ( var i = 0 ; i < presentModeCount ; i ++ )
407
- {
408
- details . PresentModes [ i ] = modes [ i ] ;
409
- }
452
+ for ( var i = 0 ; i < presentModeCount ; i ++ )
453
+ {
454
+ details . PresentModes [ i ] = modes [ i ] ;
410
455
}
456
+ }
411
457
412
- return details ;
413
- } ) ;
458
+ return details ;
414
459
}
415
460
416
461
private unsafe bool CheckDeviceExtensionSupport ( PhysicalDevice device )
417
462
{
418
463
return _deviceExtensions . All ( ext => _vk . IsDeviceExtensionPresent ( device , ext ) ) ;
419
464
}
420
465
421
- private static readonly ConcurrentDictionary < PhysicalDevice , QueueFamilyIndices > _queueFamilyIndicesCache
422
- = new ConcurrentDictionary < PhysicalDevice , QueueFamilyIndices > ( ) ;
466
+ // Caching these values might have unintended side effects
423
467
private unsafe QueueFamilyIndices FindQueueFamilies ( PhysicalDevice device )
424
468
{
425
- return _queueFamilyIndicesCache . GetOrAdd ( device , d =>
426
- {
427
- var indices = new QueueFamilyIndices ( ) ;
469
+ var indices = new QueueFamilyIndices ( ) ;
428
470
429
- uint queryFamilyCount = 0 ;
430
- _vk . GetPhysicalDeviceQueueFamilyProperties ( d , & queryFamilyCount , null ) ;
471
+ uint queryFamilyCount = 0 ;
472
+ _vk . GetPhysicalDeviceQueueFamilyProperties ( device , & queryFamilyCount , null ) ;
431
473
432
- using var mem = GlobalMemory . Allocate ( ( int ) queryFamilyCount * sizeof ( QueueFamilyProperties ) ) ;
433
- var queueFamilies = ( QueueFamilyProperties * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
474
+ using var mem = GlobalMemory . Allocate ( ( int ) queryFamilyCount * sizeof ( QueueFamilyProperties ) ) ;
475
+ var queueFamilies = ( QueueFamilyProperties * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
434
476
435
- _vk . GetPhysicalDeviceQueueFamilyProperties ( d , & queryFamilyCount , queueFamilies ) ;
436
- for ( var i = 0u ; i < queryFamilyCount ; i ++ )
477
+ _vk . GetPhysicalDeviceQueueFamilyProperties ( device , & queryFamilyCount , queueFamilies ) ;
478
+ for ( var i = 0u ; i < queryFamilyCount ; i ++ )
479
+ {
480
+ var queueFamily = queueFamilies [ i ] ;
481
+ // note: HasFlag is slow on .NET Core 2.1 and below.
482
+ // if you're targeting these versions, use ((queueFamily.QueueFlags & QueueFlags.QueueGraphicsBit) != 0)
483
+ if ( queueFamily . QueueFlags . HasFlag ( QueueFlags . QueueGraphicsBit ) )
437
484
{
438
- var queueFamily = queueFamilies [ i ] ;
439
- // note: HasFlag is slow on .NET Core 2.1 and below.
440
- // if you're targeting these versions, use ((queueFamily.QueueFlags & QueueFlags.QueueGraphicsBit) != 0)
441
- if ( queueFamily . QueueFlags . HasFlag ( QueueFlags . QueueGraphicsBit ) )
442
- {
443
- indices . GraphicsFamily = i ;
444
- }
485
+ indices . GraphicsFamily = i ;
486
+ }
445
487
446
- _vkSurface . GetPhysicalDeviceSurfaceSupport ( d , i , _surface , out var presentSupport ) ;
488
+ _vkSurface . GetPhysicalDeviceSurfaceSupport ( device , i , _surface , out var presentSupport ) ;
447
489
448
- if ( presentSupport == Vk . True )
449
- {
450
- indices . PresentFamily = i ;
451
- }
490
+ if ( presentSupport == Vk . True )
491
+ {
492
+ indices . PresentFamily = i ;
493
+ }
452
494
453
- if ( indices . IsComplete ( ) )
454
- {
455
- break ;
456
- }
495
+ if ( indices . IsComplete ( ) )
496
+ {
497
+ break ;
457
498
}
499
+ }
458
500
459
- return indices ;
460
- } ) ;
501
+ return indices ;
461
502
}
462
503
463
504
public struct QueueFamilyIndices
@@ -481,7 +522,9 @@ public struct SwapChainSupportDetails
481
522
private unsafe void CreateLogicalDevice ( )
482
523
{
483
524
var indices = FindQueueFamilies ( _physicalDevice ) ;
484
- var uniqueQueueFamilies = new [ ] { indices . GraphicsFamily . Value , indices . PresentFamily . Value } ;
525
+ var uniqueQueueFamilies = indices . GraphicsFamily . Value == indices . PresentFamily . Value
526
+ ? new [ ] { indices . GraphicsFamily . Value }
527
+ : new [ ] { indices . GraphicsFamily . Value , indices . PresentFamily . Value } ;
485
528
486
529
using var mem = GlobalMemory . Allocate ( ( int ) uniqueQueueFamilies . Length * sizeof ( DeviceQueueCreateInfo ) ) ;
487
530
var queueCreateInfos = ( DeviceQueueCreateInfo * ) Unsafe . AsPointer ( ref mem . GetPinnableReference ( ) ) ;
@@ -624,6 +667,30 @@ private unsafe void CreateSwapChain()
624
667
_swapchainExtent = extent ;
625
668
}
626
669
670
+ private unsafe void RecreateSwapChain ( )
671
+ {
672
+ Vector2D < int > framebufferSize = _window . FramebufferSize ;
673
+
674
+ while ( framebufferSize . X == 0 || framebufferSize . Y == 0 )
675
+ {
676
+ framebufferSize = _window . FramebufferSize ;
677
+ _window . DoEvents ( ) ;
678
+ }
679
+
680
+ _ = _vk . DeviceWaitIdle ( _device ) ;
681
+
682
+ CleanupSwapchain ( ) ;
683
+
684
+ CreateSwapChain ( ) ;
685
+ CreateImageViews ( ) ;
686
+ CreateRenderPass ( ) ;
687
+ CreateGraphicsPipeline ( ) ;
688
+ CreateFramebuffers ( ) ;
689
+ CreateCommandBuffers ( ) ;
690
+
691
+ _imagesInFlight = new Fence [ _swapchainImages . Length ] ;
692
+ }
693
+
627
694
private Extent2D ChooseSwapExtent ( SurfaceCapabilitiesKHR capabilities )
628
695
{
629
696
if ( capabilities . CurrentExtent . Width != uint . MaxValue )
@@ -632,7 +699,7 @@ private Extent2D ChooseSwapExtent(SurfaceCapabilitiesKHR capabilities)
632
699
}
633
700
634
701
var actualExtent = new Extent2D
635
- { Height = ( uint ) _window . Size . Y , Width = ( uint ) _window . Size . X } ;
702
+ { Height = ( uint ) _window . FramebufferSize . Y , Width = ( uint ) _window . FramebufferSize . X } ;
636
703
actualExtent . Width = new [ ]
637
704
{
638
705
capabilities . MinImageExtent . Width ,
0 commit comments