-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvma.odin
1619 lines (1500 loc) · 65.9 KB
/
vma.odin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package vma
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
@(require) foreign import stdcpp "system:c++"
}
when ODIN_OS == .Windows {
when ODIN_ARCH == .amd64 {
foreign import vma_lib "vma_windows_x64.lib"
} else when ODIN_ARCH == .arm64 {
foreign import vma_lib "vma_windows_arm64.lib"
}
} else when ODIN_OS == .Darwin {
when ODIN_ARCH == .amd64 {
foreign import vma_lib "vma_darwin_x64.a"
} else when ODIN_ARCH == .arm64 {
foreign import vma_lib "vma_darwin_arm64.a"
}
} else when ODIN_OS == .Linux {
when ODIN_ARCH == .amd64 {
foreign import vma_lib "vma_linux_x64.a"
} else when ODIN_ARCH == .arm64 {
foreign import vma_lib "vma_linux_arm64.a"
}
} else {
#panic("Unsupported platform for VMA library")
}
// Vendor
import vk "vendor:vulkan"
// Flags for created #Allocator.
Allocator_Create_Flags :: bit_set[Allocator_Create_Flag;u32]
Allocator_Create_Flag :: enum u32 {
Externally_Synchronized,
Khr_Dedicated_Allocation,
Khr_Bind_Memory2,
Ext_Memory_Budget,
Amd_Device_Coherent_Memory,
Buffer_Device_Address,
Ext_Memory_Priority,
Khr_Maintenance4,
Khr_Maintenance5,
Khr_External_Memory_Win32,
}
// Intended usage of the allocated memory.
Memory_Usage :: enum u32 {
Unknown,
Gpu_Only,
Cpu_Only,
Cpu_To_Gpu,
Gpu_To_Cpu,
Cpu_Copy,
Gpu_Lazily_Allocated,
Auto,
Auto_Prefer_Device,
Auto_Prefer_Host,
}
// Flags to be passed as Allocation_Create_Info::flags.
Allocation_Create_Flags :: bit_set[Allocation_Create_Flag;u32]
Allocation_Create_Flag :: enum u32 {
Dedicated_Memory = 0,
Never_Allocate = 1,
Mapped = 2,
User_Data_Copy_String = 5,
Upper_Address = 6,
Dont_Bind = 7,
Within_Budget = 8,
Can_Alias = 9,
Host_Access_Sequential_Write = 10,
Host_Access_Random = 11,
Host_Access_Allow_Transfer_Instead = 12,
Strategy_Min_Memory = 16,
Strategy_Min_Time = 17,
Strategy_Min_Offset = 18,
}
ALLOCATION_CREATE_STRATEGY_BEST_FIT :: Allocation_Create_Flags{.Strategy_Min_Memory}
ALLOCATION_CREATE_STRATEGY_FIRST_FIT :: Allocation_Create_Flags{.Strategy_Min_Time}
ALLOCATION_CREATE_STRATEGY_MASK :: Allocation_Create_Flags {
.Strategy_Min_Memory,
.Strategy_Min_Time,
.Strategy_Min_Offset,
}
// Flags to be passed as VmaPoolCreateInfo::flags.
Pool_Create_Flags :: bit_set[Pool_Create_Flag;u32]
Pool_Create_Flag :: enum u32 {
Ignore_Buffer_Image_Granularity = 1,
Linear_Algorithm = 2,
}
POOL_CREATE_ALGORITHM_MASK :: Pool_Create_Flags{.Linear_Algorithm}
// Flags to be passed as VmaDefragmentationInfo::flags.
Defragmentation_Flags :: bit_set[Defragmentation_Flag;u32]
Defragmentation_Flag :: enum u32 {
Algorithm_Fast,
Algorithm_Balanced,
Algorithm_Full,
Algorithm_Extensive,
}
// A bit mask to extract only `ALGORITHM` bits from entire set of flags.
DEFRAGMENTATION_ALGORITHM_MASK :: Defragmentation_Flags {
.Algorithm_Fast,
.Algorithm_Balanced,
.Algorithm_Full,
.Algorithm_Extensive,
}
// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove.
Defragmentation_Move_Operation :: enum u32 {
// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old
// buffer/image has been destroyed. `srcAllocation` should be changed to point to the new
// place. This is the default value set by vm.begin_defragmentation_pass().
Operation_Copy,
// Set this value if you cannot move the allocation. New place reserved at
// `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged.
Operation_Ignore,
// Set this value if you decide to abandon the allocation and you destroyed the
// buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with
// `srcAllocation`, which will be destroyed.
Operation_Destroy,
}
// Flags to be passed as `Virtual_Block_Create_Info.flags`.
Virtual_Block_Create_Flags :: bit_set[Virtual_Block_Create_Flag;u32]
Virtual_Block_Create_Flag :: enum u32 {
Linear_Algorithm,
}
VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK :: Virtual_Block_Create_Flags{.Linear_Algorithm}
// Flags to be passed as Virtual_Allocation_Create_Info.flags.
Virtual_Allocation_Create_Flags :: bit_set[Virtual_Allocation_Create_Flag;u32]
Virtual_Allocation_Create_Flag :: enum u32 {
Upper_Address = 7,
Strategy_Min_Memory = 16,
Strategy_Min_Time = 17,
Strategy_Min_Offset = 18,
}
VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK :: Virtual_Allocation_Create_Flags {
.Strategy_Min_Memory,
.Strategy_Min_Time,
.Strategy_Min_Offset,
}
// Represents main object of this library initialized.
//
// Fill structure `Allocator_Create_Info` and call procedure `create_allocator()` to create it.
// Call procedure `destroy_allocator()` to destroy it.
//
// It is recommended to create just one object of this type per `VkDevice` object, right after
// Vulkan is initialized and keep it alive until before Vulkan device is destroyed.
Allocator :: distinct rawptr
// Represents custom memory pool
//
// Fill structure `Pool_Create_Info` and call procedure `create_pool()` to create it. Call
// procedure `destroy_pool()` to destroy it.
Pool :: distinct rawptr
// Represents single memory allocation.
//
// It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block
// of this type plus unique offset.
//
// There are multiple ways to create such object. You need to fill structure
// VmaAllocationCreateInfo.
//
// Although the library provides convenience procedures that create Vulkan buffer or image,
// allocate memory for it and bind them together, binding of the allocation to a buffer or an
// image is out of scope of the allocation itself. Allocation object can exist without
// buffer/image bound, binding can be done manually by the user, and destruction of it can be
// done independently of destruction of the allocation.
//
// The object also remembers its size and some other information. To retrieve this information,
// use procedure vmaGetAllocationInfo() and inspect returned structure VmaAllocationInfo.
Allocation :: distinct rawptr
// An opaque object that represents started defragmentation process.
Defragmentation_Context :: distinct rawptr
// Represents single memory allocation done inside VmaVirtualBlock.
Virtual_Allocation :: vk.NonDispatchableHandle
// Handle to a virtual block object that allows to use core allocation algorithm without
// allocating any real GPU memory.
Virtual_Block :: distinct rawptr
/* Callback procedure called after successful `vkAllocateMemory`. */
Allocate_Device_Memory_Proc :: #type proc "c" (
allocator: Allocator,
memory_type: u32,
memory: vk.DeviceMemory,
size: vk.DeviceSize,
user_data: rawptr,
)
// Callback procedure called before vkFreeMemory.
Free_Device_Memory_Proc :: #type proc "c" (
allocator: Allocator,
memory_type: u32,
memory: vk.DeviceMemory,
size: vk.DeviceSize,
user_data: rawptr,
)
// Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`.
Device_Memory_Callbacks :: struct {
// Optional, can be nil.
allocate_proc: Allocate_Device_Memory_Proc,
// Optional, can be nil.
free_proc: Free_Device_Memory_Proc,
// Optional, can be nil.
user_data: rawptr,
}
// Pointers to some Vulkan procedures - a subset used by the library.
Vulkan_Functions :: struct {
_unused_1: proc(), // vk.ProcGetInstanceProcAddr
_unused_2: proc(), // vk.ProcGetDeviceProcAddr
get_physical_device_properties: vk.ProcGetPhysicalDeviceProperties,
get_physical_device_memory_properties: vk.ProcGetPhysicalDeviceMemoryProperties,
allocate_memory: vk.ProcAllocateMemory,
free_memory: vk.ProcFreeMemory,
map_memory: vk.ProcMapMemory,
unmap_memory: vk.ProcUnmapMemory,
flush_mapped_memory_ranges: vk.ProcFlushMappedMemoryRanges,
invalidate_mapped_memory_ranges: vk.ProcInvalidateMappedMemoryRanges,
bind_buffer_memory: vk.ProcBindBufferMemory,
bind_image_memory: vk.ProcBindImageMemory,
get_buffer_memory_requirements: vk.ProcGetBufferMemoryRequirements,
get_image_memory_requirements: vk.ProcGetImageMemoryRequirements,
create_buffer: vk.ProcCreateBuffer,
destroy_buffer: vk.ProcDestroyBuffer,
create_image: vk.ProcCreateImage,
destroy_image: vk.ProcDestroyImage,
cmd_copy_buffer: vk.ProcCmdCopyBuffer,
get_buffer_memory_requirements2_khr: vk.ProcGetBufferMemoryRequirements2KHR,
get_image_memory_requirements2_khr: vk.ProcGetImageMemoryRequirements2KHR,
bind_buffer_memory2_khr: vk.ProcBindBufferMemory2KHR,
bind_image_memory2_khr: vk.ProcBindImageMemory2KHR,
get_physical_device_memory_properties2_khr: vk.ProcGetPhysicalDeviceMemoryProperties2KHR,
get_device_buffer_memory_requirements: vk.ProcGetDeviceBufferMemoryRequirementsKHR,
get_device_image_memory_requirements: vk.ProcGetDeviceImageMemoryRequirementsKHR,
get_memory_win32_handle_khr: vk.ProcGetMemoryWin32HandleKHR,
}
// Description of a Allocator to be created.
Allocator_Create_Info :: struct {
// Flags for created allocator.
flags: Allocator_Create_Flags,
// Vulkan physical device.
physical_device: vk.PhysicalDevice,
// Vulkan device.
device: vk.Device,
// Preferred size of a single `vk.DeviceMemory` block to be allocated from large heaps > 1
// GiB. Optional.
preferred_large_heap_block_size: vk.DeviceSize,
// Custom CPU memory allocation callbacks. Optional.
allocation_callbacks: ^vk.AllocationCallbacks,
// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional.
device_memory_callbacks: ^Device_Memory_Callbacks,
heap_size_limit: [^]vk.DeviceSize,
vulkan_functions: ^Vulkan_Functions,
instance: vk.Instance,
vulkan_api_version: u32,
type_external_memory_handle_types: ^vk.ExternalMemoryHandleTypeFlagsKHR,
}
// Information about existing #Allocator object.
Allocator_Info :: struct {
instance: vk.Instance,
physical_device: vk.PhysicalDevice,
device: vk.Device,
}
// Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or
// total.
Statistics :: struct {
block_count: u32,
allocation_count: u32,
block_bytes: vk.DeviceSize,
allocation_bytes: vk.DeviceSize,
}
// More detailed statistics than #VmaStatistics.
Detailed_Statistics :: struct {
// Basic statistics.
statistics: Statistics,
// Number of free ranges of memory between allocations.
unused_range_count: u32,
// Smallest allocation size. `vk.WHOLE_SIZE` if there are 0 allocations.
allocation_size_min: vk.DeviceSize,
// Largest allocation size. 0 if there are 0 allocations.
allocation_size_max: vk.DeviceSize,
// Smallest empty range size. `vk.WHOLE_SIZE` if there are 0 empty ranges.
unused_range_size_min: vk.DeviceSize,
// Largest empty range size. 0 if there are 0 empty ranges.
unused_range_size_max: vk.DeviceSize,
}
// General statistics from current state of the Allocator - total memory usage across all
// memory heaps and types.
Total_Statistics :: struct {
memory_type: [vk.MAX_MEMORY_TYPES]Detailed_Statistics,
memory_heap: [vk.MAX_MEMORY_HEAPS]Detailed_Statistics,
total: Detailed_Statistics,
}
// Statistics of current memory usage and available budget for a specific memory heap.
Budget :: struct {
statistics: Statistics,
usage: vk.DeviceSize,
budget: vk.DeviceSize,
}
// Parameters of new `Allocation`.
Allocation_Create_Info :: struct {
flags: Allocation_Create_Flags,
usage: Memory_Usage,
required_flags: vk.MemoryPropertyFlags,
preferred_flags: vk.MemoryPropertyFlags,
memory_type_bits: u32,
pool: Pool,
user_data: rawptr,
priority: f32,
}
// Describes parameter of created #VmaPool.
Pool_Create_Info :: struct {
memory_type_index: u32,
flags: Pool_Create_Flags,
block_size: vk.DeviceSize,
min_block_count: uint,
max_block_count: uint,
priority: f32,
min_allocation_alignment: vk.DeviceSize,
memory_allocate_next: rawptr,
}
// Parameters of `Allocation` objects, that can be retrieved using procedure
// `get_allocation_info()`.
Allocation_Info :: struct {
memory_type: u32,
device_memory: vk.DeviceMemory,
offset: vk.DeviceSize,
size: vk.DeviceSize,
mapped_data: rawptr,
user_data: rawptr,
name: cstring,
}
// Extended parameters of a #VmaAllocation object that can be retrieved using procedure
// `get_allocation_info2()`.
Allocation_Info2 :: struct {
allocation_info: Allocation_Info,
block_size: vk.DeviceSize,
dedicated_memory: b32,
}
// Callback procedure called during `begin_defragmentation()` to check custom criterion about
// ending current defragmentation pass.
Check_Defragmentation_Break_Proc :: #type proc "c" (user_data: rawptr) -> b32
// Parameters for defragmentation.
Defragmentation_Info :: struct {
// Use combination of #VmaDefragmentationFlagBits.
flags: Defragmentation_Flags,
pool: Pool,
max_bytes_per_pass: vk.DeviceSize,
max_allocations_per_pass: u32,
proc_break_callback: Check_Defragmentation_Break_Proc,
// Optional data to pass to custom callback for stopping pass of defragmentation.
break_callback_user_data: rawptr,
}
// Single move of an allocation to be done for defragmentation.
Defragmentation_Move :: struct {
// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default
// value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.
operation: Defragmentation_Move_Operation,
// Allocation that should be moved.
src_allocation: Allocation,
dst_tmp_allocation: Allocation,
}
Defragmentation_Pass_Move_Info :: struct {
// Number of elements in the `moves` array.
move_count: u32,
moves: [^]Defragmentation_Move,
}
// Statistics returned for defragmentation process in procedure `end_defragmentation()`.
Defragmentation_Stats :: struct {
// Total number of bytes that have been copied while moving allocations to different
// places.
bytes_moved: vk.DeviceSize,
// Total number of bytes that have been released to the system by freeing empty
// `vk.DeviceMemory` objects.
bytes_freed: vk.DeviceSize,
// Number of allocations that have been moved to different places.
allocations_moved: u32,
// Number of empty `vk.DeviceMemory` objects that have been released to the system.
device_memory_blocks_freed: u32,
}
// Parameters of created `Virtual_Block` object to be passed to `create_virtual_block()`.
Virtual_Block_Create_Info :: struct {
size: vk.DeviceSize,
flags: Virtual_Block_Create_Flags,
allocation_callbacks: ^vk.AllocationCallbacks,
}
// Parameters of created virtual allocation to be passed to `virtual_allocate()`.
Virtual_Allocation_Create_Info :: struct {
size: vk.DeviceSize,
alignment: vk.DeviceSize,
flags: Virtual_Allocation_Create_Flags,
user_data: rawptr,
}
// Parameters of an existing virtual allocation, returned by `get_virtual_allocation_info()`.
Virtual_Allocation_Info :: struct {
offset: vk.DeviceSize,
size: vk.DeviceSize,
user_data: rawptr,
}
// Bind vulkan procedures to vma.
create_vulkan_functions :: proc() -> (procedures: Vulkan_Functions) {
procedures = Vulkan_Functions {
get_physical_device_properties = vk.GetPhysicalDeviceProperties,
get_physical_device_memory_properties = vk.GetPhysicalDeviceMemoryProperties,
allocate_memory = vk.AllocateMemory,
free_memory = vk.FreeMemory,
map_memory = vk.MapMemory,
unmap_memory = vk.UnmapMemory,
flush_mapped_memory_ranges = vk.FlushMappedMemoryRanges,
invalidate_mapped_memory_ranges = vk.InvalidateMappedMemoryRanges,
bind_buffer_memory = vk.BindBufferMemory,
bind_image_memory = vk.BindImageMemory,
get_buffer_memory_requirements = vk.GetBufferMemoryRequirements,
get_image_memory_requirements = vk.GetImageMemoryRequirements,
create_buffer = vk.CreateBuffer,
destroy_buffer = vk.DestroyBuffer,
create_image = vk.CreateImage,
destroy_image = vk.DestroyImage,
cmd_copy_buffer = vk.CmdCopyBuffer,
get_buffer_memory_requirements2_khr = vk.GetBufferMemoryRequirements2KHR,
get_image_memory_requirements2_khr = vk.GetImageMemoryRequirements2KHR,
bind_buffer_memory2_khr = vk.BindBufferMemory2KHR,
bind_image_memory2_khr = vk.BindImageMemory2KHR,
get_physical_device_memory_properties2_khr = vk.GetPhysicalDeviceMemoryProperties2KHR,
get_device_buffer_memory_requirements = vk.GetDeviceBufferMemoryRequirements,
get_device_image_memory_requirements = vk.GetDeviceImageMemoryRequirements,
get_memory_win32_handle_khr = vk.GetMemoryWin32HandleKHR,
}
return
}
// odinfmt: disable
@(default_calling_convention = "c")
foreign vma_lib {
// Creates `Allocator` object.
@(link_name = "vmaCreateAllocator")
create_allocator :: proc(
#by_ptr create_info: Allocator_Create_Info,
allocator: ^Allocator) -> vk.Result ---
// Destroys allocator object.
@(link_name = "vmaDestroyAllocator")
destroy_allocator :: proc(allocator: Allocator) ---
// Returns information about existing `Allocator` object - handle to Vulkan device etc.
//
// It might be useful if you want to keep just the `Allocator` handle and fetch other
// required handles to `vk.PhysicalDevice`, `vk.Device` etc. every time using this procedure.
@(link_name = "vmaGetAllocatorInfo")
get_allocator_info :: proc(
allocator: Allocator,
allocator_info: ^Allocator_Info) ---
// `vk.PhysicalDeviceProperties` are fetched from physicalDevice by the allocator. You can
// access it here, without fetching it again on your own.
@(link_name = "vmaGetPhysicalDeviceProperties")
get_physical_device_properties :: proc(
allocator: Allocator,
physical_device_properties: ^^vk.PhysicalDeviceProperties) ---
// `vk.PhysicalDeviceMemoryProperties` are fetched from physicalDevice by the allocator.
// You can access it here, without fetching it again on your own.
@(link_name = "vmaGetMemoryProperties")
get_memory_properties :: proc(
allocator: Allocator,
physical_device_memory_properties: ^^vk.PhysicalDeviceMemoryProperties) ---
// Given Memory Type Index, returns Property Flags of this memory type.
//
// This is just a convenience procedure. Same information can be obtained using
// `get_memory_properties()`.
@(link_name = "vmaGetMemoryTypeProperties")
get_memory_type_properties :: proc(
allocator: Allocator,
memory_type_index: u32,
flags: ^vk.MemoryPropertyFlags) ---
// Sets index of the current frame.
@(link_name = "vmaSetCurrentFrameIndex")
set_current_frame_index :: proc(
allocator: Allocator,
frame_index: u32) ---
// Retrieves statistics from current state of the Allocator.
//
// This procedure is called "calculate" not "get" because it has to traverse all internal
// data structures, so it may be quite slow. Use it for debugging purposes. For faster but
// more brief statistics suitable to be called every frame or every allocation, use
// `get_heap_budgets()`.
//
// Note that when using allocator from multiple threads, returned information may
// immediately become outdated.
@(link_name = "vmaCalculateStatistics")
calculate_statistics :: proc(
allocator: Allocator,
stats: ^Total_Statistics) ---
// Retrieves information about current memory usage and budget for all memory heaps.
//
// `budgets` must point to array with number of elements at least equal to number of
// memory heaps in physical device used.
//
// This procedure is called "get" not "calculate" because it is very fast, suitable to be
// called every frame or every allocation. For more detailed statistics use
// `calculate_statistics()`.
//
// Note that when using allocator from multiple threads, returned information may
// immediately become outdated.
@(link_name = "vmaGetHeapBudgets")
get_heap_budgets :: proc(
allocator: Allocator,
budgets: [^]Budget) ---
// Helps to find `memory_type_index`, given `memory_type_bits` and
// `allocation_create_info`.
//
// This algorithm tries to find a memory type that:
//
// - Is allowed by `memory_type_bits`.
// - Contains all the flags from `allocation_create_info.required_flags`.
// - Matches intended usage.
// - Has as many flags from `allocation_create_info.preferred_flags` as possible.
//
// Returns `ERROR_FEATURE_NOT_PRESENT` if not found. Receiving such result from this
// PROCEDURE or any other allocating PROCEDURE probably means that your device doesn't
// support any memory type with requested features for the specific type of resource you
// want to use it for. Please check parameters of your resource, like image layout (OPTIMAL
// versus LINEAR) or mip level count.
@(link_name = "vmaFindMemoryTypeIndex")
find_memory_type_index :: proc(
allocator: Allocator,
memory_type_bits: u32,
#by_ptr allocation_create_info: Allocation_Create_Info,
memory_type_index: ^u32) -> vk.Result ---
// Helps to find `memory_type_index`, given `vk.BufferCreateInfo` and
// `Allocation_Create_Info`.
//
// It can be useful e.g. to determine value to be used as
// `Pool_Create_Info.memory_type_index`. It internally creates a temporary, dummy buffer
// that never has memory bound.
@(link_name = "vmaFindMemoryTypeIndexForBufferInfo")
find_memory_type_index_for_buffer_info :: proc(
allocator: Allocator,
#by_ptr buffer_create_info: vk.BufferCreateInfo,
#by_ptr allocation_create_info: Allocation_Create_Info,
memory_type_index: ^u32) -> vk.Result ---
// Find `memory_type_index`, given `vk.ImageCreateInfo` and `Allocation_Create_Info`.
//
// It can be useful e.g. to determine value to be used as
// `Pool_Create_Info.memory_type_index`. It internally creates a temporary, dummy image
// that never has memory bound.
@(link_name = "vmaFindMemoryTypeIndexForImageInfo")
find_memory_type_index_for_image_info :: proc(
allocator: Allocator,
#by_ptr image_create_info: vk.ImageCreateInfo,
#by_ptr allocation_create_info: Allocation_Create_Info,
memory_type_index: ^u32) -> vk.Result ---
// Allocates Vulkan device memory and creates `Pool` object.
@(link_name = "vmaCreatePool")
create_pool :: proc(
allocator: Allocator,
#by_ptr create_info: Pool_Create_Info,
pool: ^Pool) -> vk.Result ---
// Destroys `Pool` object and frees Vulkan device memory.
@(link_name = "vmaDestroyPool")
destroy_pool :: proc(
allocator: Allocator,
pool: Pool) ---
// Retrieves statistics of existing `Pool` object.
//
// Note that when using the pool from multiple threads, returned information may
// immediately become outdated.
@(link_name = "vmaGetPoolStatistics")
get_pool_statistics :: proc(
allocator: Allocator,
pool: Pool,
pool_stats: ^Statistics) ---
// Retrieves detailed statistics of existing `Pool` object.
@(link_name = "vmaCalculatePoolStatistics")
calculate_pool_statistics :: proc(
allocator: Allocator,
pool: Pool,
pool_stats: ^Detailed_Statistics) ---
// Checks magic number in margins around all allocations in given memory pool in search for
// corruptions.
@(link_name = "vmaCheckPoolCorruption")
check_pool_corruption :: proc(
allocator: Allocator,
pool: Pool) -> vk.Result ---
// Retrieves name of a custom pool.
//
// After the call `name` is either nil or points to an internally-owned `nil`-terminated
// string containing name of the pool that was previously set. The pointer becomes invalid
// when the pool is destroyed or its name is changed using `set_pool_name()`.
@(link_name = "vmaGetPoolName")
get_pool_name :: proc(
allocator: Allocator,
pool: Pool,
name: ^cstring) ---
// Sets name of a custom pool.
//
// `name` can be either nil or pointer to a `nil`-terminated string with new name for the
// pool. Procedure makes internal copy of the string, so it can be changed or freed
// immediately after this call.
@(link_name = "vmaSetPoolName")
set_pool_name :: proc(
allocator: Allocator,
pool: Pool,
name: cstring) ---
// General purpose memory allocation.
//
// Inputs:
// - `allocator`
// - `memory_requirements`
// - `create_info`
// - [out] `allocation` Handle to allocated memory.
// - [out] `allocation_info` Optional. Information about allocated memory. It can be later
// fetched using PROCEDURE `get_allocation_info()`.
//
// You should free the memory using `free_memory()` or `free_memory_pages()`.
//
// It is recommended to use `allocate_memory_for_buffer()`, `allocate_memory_for_image()`,
// `create_buffer()`, `create_image()` instead whenever possible.
@(link_name = "vmaAllocateMemory")
allocate_memory :: proc(
allocator: Allocator,
#by_ptr memory_requirements: vk.MemoryRequirements,
#by_ptr create_info: Allocation_Create_Info,
allocation: ^Allocation,
allocation_info: ^Allocation_Info) -> vk.Result ---
// General purpose memory allocation for multiple allocation objects at once.
//
// - `allocator` Allocator object.
// - `vk_memory_requirements` Memory requirements for each allocation.
// - `create_info` Creation parameters for each allocation.
// - `allocation_count` Number of allocations to make.
// - [out] `allocations` Pointer to array that will be filled with handles to created
// allocations.
// - [out] `allocation_info` Optional. Pointer to array that will be filled with
// parameters of created allocations.
//
// You should free the memory using `free_memory()` or `free_memory_pages()`.
//
// Word "pages" is just a suggestion to use this PROCEDURE to allocate pieces of memory
// needed for sparse binding. It is just a general purpose allocation PROCEDURE able to
// make multiple allocations at once. It may be internally optimized to be more efficient
// than calling `allocate_memory()` `allocationCount` times.
//
// All allocations are made using same parameters. All of them are created out of the same
// memory pool and type. If any allocation fails, all allocations already made within this
// PROCEDURE call are also freed, so that when returned result is not `.SUCCESS`,
// `allocations` array is always entirely filled with `VK_NULL_HANDLE`.
@(link_name = "vmaAllocateMemoryPages")
allocate_memory_pages :: proc(
allocator: Allocator,
memory_requirements: [^]vk.MemoryRequirements,
create_info: [^]Allocation_Create_Info,
allocation_count: uint,
allocations: [^]Allocation,
allocation_info: [^]Allocation_Info) -> vk.Result ---
// Allocates memory suitable for given `VkBuffer`.
//
// - `allocator`
// - `buffer`
// - `create_info`
// - [out] `allocation` Handle to allocated memory.
// - [out] `allocation_info` Optional. Information about allocated memory. It can be later
// fetched using procedure `get_allocation_info()`.
//
// It only creates #VmaAllocation. To bind the memory to the buffer, use
// `bind_buffer_memory()`.
//
// This is a special-purpose procedure. In most cases you should use `create_buffer()`.
//
// You must free the allocation using `free_memory()` when no longer needed.
@(link_name = "vmaAllocateMemoryForBuffer")
allocate_memory_for_buffer :: proc(
allocator: Allocator,
buffer: vk.Buffer,
#by_ptr create_info: Allocation_Create_Info,
allocation: ^Allocation,
allocation_info: ^Allocation_Info) -> vk.Result ---
// Allocates memory suitable for given `vk.Image`.
//
// - `allocator`
// - `image`
// - `create_info`
// - [out] `allocation` Handle to allocated memory.
// - [out] `allocation_info` Optional. Information about allocated memory. It can be later
// fetched using procedure `get_allocation_info()`.
//
// It only creates #VmaAllocation. To bind the memory to the buffer, use
// `bind_image_memory()`.
//
// This is a special-purpose procedure. In most cases you should use `create_image()`.
//
// You must free the allocation using `free_memory()` when no longer needed.
@(link_name = "vmaAllocateMemoryForImage")
allocate_memory_for_image :: proc(
allocator: Allocator,
image: vk.Image,
#by_ptr create_info: Allocation_Create_Info,
allocation: ^Allocation,
allocation_info: ^Allocation_Info) -> vk.Result ---
// Frees memory previously allocated using `allocate_memory()`,
// `allocate_memory_for_buffer()`, or `allocate_memory_for_image()`.
//
// Passing `nil` as `allocation` is valid. Such procedure call is just skipped.
@(link_name = "vmaFreeMemory")
free_memory :: proc(
allocator: Allocator,
allocation: Allocation) ---
// Frees memory and destroys multiple allocations.
//
// Word "pages" is just a suggestion to use this procedure to free pieces of memory used
// for sparse binding. It is just a general purpose procedure to free memory and destroy
// allocations made using e.g. `allocate_memory()`, `allocate_memory_pages()` and other
// procedures. It may be internally optimized to be more efficient than calling
// `free_memory()` `allocation_count` times.
//
// Allocations in `allocations` array can come from any memory pools and types. Passing
// `nil` as elements of `allocations` array is valid. Such entries are just skipped.
@(link_name = "vmaFreeMemoryPages")
free_memory_pages :: proc(
allocator: Allocator,
allocation_count: uint,
allocations: [^]Allocation) ---
// Returns current information about specified allocation.
//
// Current parameters of given allocation are returned in `allocation_info`.
//
// Although this procedure doesn't lock any mutex, so it should be quite efficient, you
// should avoid calling it too often. You can retrieve same `Allocation_Info` structure
// while creating your resource, from procedure `create_buffer()`, `create_image()`. You
// can remember it if you are sure parameters don't change (e.g. due to defragmentation).
//
// There is also a new procedure `get_allocation_info2()` that offers extended information
// about the allocation, returned using new structure `Allocation_Info2`.
@(link_name = "vmaGetAllocationInfo")
get_allocation_info :: proc(
allocator: Allocator,
allocation: Allocation,
allocation_info: ^Allocation_Info) ---
// Returns extended information about specified allocation.
//
// Current parameters of given allocation are returned in `allocation_info`. Extended
// parameters in structure `Allocation_Info2` include memory block size and a flag telling
// whether the allocation has dedicated memory. It can be useful e.g. for interop with
// OpenGL.
@(link_name = "vmaGetAllocationInfo2")
get_allocation_info2 :: proc(
allocator: Allocator,
allocation: Allocation,
allocation_info: ^Allocation_Info2) ---
// Sets user_data in given allocation to new value.
//
// The value of pointer `user_data` is copied to allocation's `user_data`. It is opaque, so
// you can use it however you want - e.g. as a pointer, ordinal number or some handle to
// you own data.
@(link_name = "vmaSetAllocationUserData")
set_allocation_user_data :: proc(
allocator: Allocator,
allocation: Allocation,
user_data: rawptr) ---
// Sets name in given allocation to new value.
//
// `name` must be either `nil`, or a pointer to a `nil`-terminated string. The procedure makes
// a local copy of the string and sets it as allocation's `name`. The string passed as
// `name` doesn't need to be valid for the whole lifetime of the allocation - you can free
// it after this call. The string previously pointed to by allocation's `name` is freed
// from memory.
@(link_name = "vmaSetAllocationName")
set_allocation_name :: proc(
allocator: Allocator,
allocation: Allocation,
name: cstring) ---
// Given an allocation, returns Win32 handle that may be imported by other processes or
// APIs.
//
// - `target_process` Must be a valid handle to target process or null. If it's null, the
// procedure returns handle for the current process.
// - [out] `handle` Output parameter that returns the handle.
//
// The procedure fills `handle` with handle that can be used in target process. The handle
// is fetched using procedure `vk.GetMemoryWin32HandleKHR`. When no longer needed, you must
// close it using:
//
// ```
// win32.CloseHandle(handle)
// ```
//
// You can close it any time, before or after destroying the allocation object. It is
// reference-counted internally by Windows.
//
// Note the handle is returned for the entire `vk.DeviceMemory` block that the allocation
// belongs to. If the allocation is sub-allocated from a larger block, you may need to
// consider the offset of the allocation (`Allocation_Info.offset`).
//
// If the procedure fails with `vk.ERROR_FEATURE_NOT_PRESENT` error code, please
// double-check that `Vulkan_Functions.get_memory_win32_handle_khr` procedure pointer is
// set, e.g. either by using `VMA_DYNAMIC_VULKAN_FUNCTIONS` or by manually passing it
// through `Allocator_Create_Info.vulkan_functions`.
@(link_name = "vmaGetMemoryWin32Handle")
get_memory_win32_handle :: proc(
allocator: Allocator,
allocation: Allocation,
target_process: vk.HANDLE,
handle: ^vk.HANDLE) -> vk.Result ---
// Given an allocation, returns Property Flags of its memory type.
//
// This is just a convenience procedure. Same information can be obtained using
// `get_allocation_info()` + `get_memory_properties()`.
@(link_name = "vmaGetAllocationMemoryProperties")
get_allocation_memory_properties :: proc(
allocator: Allocator,
allocation: Allocation,
flags: ^vk.MemoryPropertyFlags) ---
// Maps memory represented by given allocation and returns pointer to it.
//
// Maps memory represented by given allocation to make it accessible to CPU code. When
// succeeded, `*data` contains a pointer to the first byte of this memory.
//
// Warning: If the allocation is part of a bigger `VkDeviceMemory` block, the returned
// pointer is correctly offset to the beginning of the region assigned to this particular
// allocation. Unlike the result of `vkMapMemory`, it points to the allocation, not to the
// beginning of the whole block. You should not add VmaAllocationInfo::offset to it!
//
// Mapping is internally reference-counted and synchronized, so despite raw Vulkan
// procedure `vkMapMemory()` cannot be used to map the same block of `VkDeviceMemory`
// multiple times simultaneously, it is safe to call this procedure on allocations assigned
// to the same memory block. Actual Vulkan memory will be mapped on the first mapping and
// unmapped on the last unmapping.
//
// If the procedure succeeded, you must call `unmap_memory()` to unmap the allocation when
// mapping is no longer needed or before freeing the allocation, at the latest.
//
// It is also safe to call this procedure multiple times on the same allocation. You must
// call `unmap_memory()` the same number of times as you called `map_memory()`.
//
// This procedure fails when used on an allocation made in a memory type that is not
// `HOST_VISIBLE`.
//
// This procedure doesn't automatically flush or invalidate caches. If the allocation is
// made from a memory type that is not `HOST_COHERENT`, you also need to use
// `invalidate_allocation()` / `flush_allocation()`, as required by Vulkan specification.
@(link_name = "vmaMapMemory")
map_memory :: proc(
allocator: Allocator,
allocation: Allocation,
data: ^rawptr) -> vk.Result ---
// Unmaps memory represented by given allocation, mapped previously using `map_memory()`.
//
// For details, see the description of `map_memory()`.
//
// This procedure doesn't automatically flush or invalidate caches. If the allocation is
// made from a memory type that is not `HOST_COHERENT`, you also need to use
// `invalidate_allocation()` / `flush_allocation()`, as required by Vulkan specification.
@(link_name = "vmaUnmapMemory")
unmap_memory :: proc(
allocator: Allocator,
allocation: Allocation) ---
// Flushes memory of given allocation.
//
// Calls `vk.FlushMappedMemoryRanges()` for memory associated with the given range of the
// given allocation. It needs to be called after writing to a mapped memory for memory
// types that are not `HOST_COHERENT`. Unmap operation doesn't do that automatically.
//
// - `offset` must be relative to the beginning of the allocation.
// - `size` can be `vk.WHOLE_SIZE`. It means all memory from `offset` to the end of the
// given allocation.
// - `offset` and `size` don't have to be aligned. They are internally rounded down/up to a
// multiple of `nonCoherentAtomSize`.
// - If `size` is 0, this call is ignored.
// - If the memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is
// `HOST_COHERENT`, this call is ignored.
//
// Warning! `offset` and `size` are relative to the contents of the given `allocation`. If
// you mean the whole allocation, you can pass 0 and `vk.WHOLE_SIZE`, respectively. Do not
// pass the allocation's offset as `offset`!!!
//
// This procedure returns the `vk.Result` from `vk.FlushMappedMemoryRanges` if it is
// called, otherwise `vk.SUCCESS`.
@(link_name = "vmaFlushAllocation")
flush_allocation :: proc(
allocator: Allocator,
allocation: Allocation,
offset: vk.DeviceSize,
size: vk.DeviceSize) -> vk.Result ---
// Invalidates memory of given allocation.
//
// Calls `vk.InvalidateMappedMemoryRanges()` for memory associated with the given range of
// the given allocation. It needs to be called before reading from a mapped memory for
// memory types that are not `HOST_COHERENT`. Map operation doesn't do that automatically.
//
// - `offset` must be relative to the beginning of the allocation.
// - `size` can be `vk.WHOLE_SIZE`. It means all memory from `offset` to the end of the
// given allocation.
// - `offset` and `size` don't have to be aligned. They are internally rounded down/up to a
// multiple of `nonCoherentAtomSize`.
// - If `size` is 0, this call is ignored.
// - If the memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is
// `HOST_COHERENT`, this call is ignored.
//
// Warning! `offset` and `size` are relative to the contents of the given `allocation`. If
// you mean the whole allocation, you can pass 0 and `vk.WHOLE_SIZE`, respectively. Do not
// pass the allocation's offset as `offset`!!!
//
// This procedure returns the `VkResult` from `vk.InvalidateMappedMemoryRanges` if it is
// called, otherwise `vk.SUCCESS`.
@(link_name = "vmaInvalidateAllocation")
invalidate_allocation :: proc(
allocator: Allocator,
allocation: Allocation,
offset: vk.DeviceSize,
size: vk.DeviceSize) -> vk.Result ---
// Flushes memory of given set of allocations.
//
// Calls `vk.FlushMappedMemoryRanges()` for memory associated with the given ranges of the
// given allocations.
//
// - `allocator`: The allocator object.
// - `allocation_count`: The number of allocations to flush.
// - `allocations`: An array of allocations to flush.
// - `offsets`: If not `nil`, it must point to an array of offsets of regions to flush,
// relative to the beginning of respective allocations. `nil` means all offsets are zero.
// - `sizes`: If not `nil`, it must point to an array of sizes of regions to flush in
// respective allocations. `nil` means `vk.WHOLE_SIZE` for all allocations.
//
// This procedure returns the `VkResult` from `vk.FlushMappedMemoryRanges` if it is called,
// otherwise `vk.SUCCESS`.
@(link_name = "vmaFlushAllocations")
flush_allocations :: proc(
allocator: Allocator,
allocation_count: u32,
allocations: [^]Allocation,
offsets: [^]vk.DeviceSize,