-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy paththsvs_simpler_vulkan_synchronization.h
1395 lines (1190 loc) · 61.6 KB
/
thsvs_simpler_vulkan_synchronization.h
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
// Copyright (c) 2017-2019 Tobias Hector
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//// Simpler Vulkan Synchronization ////
/*
In an effort to make Vulkan synchronization more accessible, I created this
stb-inspired single-header library in order to somewhat simplify the core
synchronization mechanisms in Vulkan - pipeline barriers and events.
Rather than the complex maze of enums and bit flags in Vulkan - many
combinations of which are invalid or nonsensical - this library collapses
this to a much shorter list of 40 distinct usage types, and a couple of
options for handling image layouts.
Use of other synchronization mechanisms such as semaphores, fences and render
passes are not addressed in this API at present.
USAGE
#define the symbol THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_IMPLEMENTATION in
*one* C/C++ file before the #include of this file; the implementation
will be generated in that file.
VERSION
alpha.9
Alpha.9 adds the thsvsGetAccessInfo function to translate access types into a thsvsVkAccessInfo.
VERSION HISTORY
alpha.8
Alpha.8 adds a host preinitialization state for linear images, as well as a number of new access sets for extensions released since the last update.
alpha.7
Alpha.7 incorporates a number of fixes from @gwihlidal, and fixes
handling of pipeline stages in the presence of multiple access types or
barriers in light of other recent changes.
alpha.6
Alpha.6 fixes a typo (VK_ACCESS_TYPE_MEMORY_READ|WRITE_BIT should have been VK_ACCESS_MEMORY_READ|WRITE_BIT), and sets the pipeline stage src and dst flag bits to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT and VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT during initialization, not 0 as per alpha.5
alpha.5
Alpha.5 now correctly zeroes out the pipeline stage flags before trying to incrementally set bits on them... common theme here, whoops.
alpha.4
Alpha.4 now correctly zeroes out the access types before trying to incrementally set bits on them (!)
alpha.3
Alpha.3 changes the following:
Uniform and vertex buffer access in one enum, matching D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER:
- THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER_OR_VERTEX_BUFFER
Color read *and* write access, matching D3D12_RESOURCE_STATE_RENDER_TARGET:
- THSVS_ACCESS_COLOR_ATTACHMENT_READ_WRITE
Also the "THSVS_ACCESS_*_SHADER_READ_SAMPLED_IMAGE" enums have been renamed to the form "THSVS_ACCESS_*_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER"
alpha.2
Alpha.2 adds four new resource states for "ANY SHADER ACCESS":
- THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER
- THSVS_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE
- THSVS_ACCESS_ANY_SHADER_READ_OTHER
- THSVS_ACCESS_ANY_SHADER_WRITE
alpha.1
Alpha.1 adds three new resource states:
- THSVS_ACCESS_GENERAL (Any access on the device)
- THSVS_ACCESS_DEPTH_ATTACHMENT_WRITE_STENCIL_READ_ONLY (Write access to only the depth aspect of a depth/stencil attachment)
- THSVS_ACCESS_STENCIL_ATTACHMENT_WRITE_DEPTH_READ_ONLY (Write access to only the stencil aspect of a depth/stencil attachment)
It also fixes a couple of typos, and adds clarification as to when extensions need to be enabled to use a feature.
alpha.0
This is the very first public release of this library; future revisions
of this API may change the API in an incompatible manner as feedback is
received.
Once the version becomes stable, incompatible changes will only be made
to major revisions of the API - minor revisions will only contain
bug fixes or minor additions.
MEMORY ALLOCATION
The thsvsCmdPipelineBarrier and thWaitEvents commands allocate temporary
storage for the Vulkan barrier equivalents in order to pass them to the
respective Vulkan commands.
These use the `THSVS_TEMP_ALLOC(size)` and `THSVS_TEMP_FREE(x)` macros,
which are by default set to alloca(size) and ((void)(x)), respectively.
If you don't want to use stack space or would rather use your own
allocation strategy, these can be overridden by defining these macros
in before #include-ing the header file with
THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_IMPLEMENTATION defined.
I'd rather avoid the need for these allocations in what are likely to be
high-traffic commands, but currently just want to ship something - may
revisit this at a future date based on feedback.
EXPRESSIVENESS COMPARED TO RAW VULKAN
Despite the fact that this API is fairly simple, it expresses 99% of
what you'd actually ever want to do in practice.
Adding the missing expressiveness would result in increased complexity
which didn't seem worth the trade off - however I would consider adding
something for them in future if it becomes an issue.
Here's a list of known things you can't express:
* Execution only dependencies cannot be expressed.
These are occasionally useful in conjunction with semaphores, or when
trying to be clever with scheduling - but their usage is both limited
and fairly tricky to get right anyway.
* Depth/Stencil Input Attachments can be read in a shader using either
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL or
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL - this library
*always* uses VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL.
It's possible (though highly unlikely) when aliasing images that this
results in unnecessary transitions.
ERROR CHECKS
By default, as with the Vulkan API, this library does NOT check for
errors.
However, a number of optional error checks (THSVS_ERROR_CHECK_*) can be
enabled by uncommenting the relevant #defines.
Currently, error checks simply assert at the point a failure is detected
and do not output an error message.
I certainly do not claim they capture *all* possible errors, but they
capture what should be some of the more common ones.
Use of the Vulkan Validation Layers in tandem with this library is
strongly recommended:
https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers
ISSUES
This header was clean of warnings using -Wall as of time of publishing
on both gcc 4.8.4 and clang 3.5, using the c99 standard.
There's a potential pitfall in thsvsCmdPipelineBarrier and thsvsCmdWaitEvents
where alloca is used for temporary allocations. See MEMORY ALLOCATION
for more information.
Testing of this library is so far extremely limited with no immediate
plans to add to that - so there's bound to be some amount of bugs.
Please raise these issues on the repo issue tracker, or provide a fix
via a pull request yourself if you're so inclined.
*/
#ifndef THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_H
#define THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_H 1
#include <stdint.h>
/*
ThsvsAccessType defines all potential resource usages in the Vulkan API.
*/
typedef enum ThsvsAccessType {
THSVS_ACCESS_NONE, // No access. Useful primarily for initialization
// Read access
// Requires VK_NV_device_generated_commands to be enabled
THSVS_ACCESS_COMMAND_BUFFER_READ_NV, // Command buffer read operation as defined by NV_device_generated_commands
THSVS_ACCESS_INDIRECT_BUFFER, // Read as an indirect buffer for drawing or dispatch
THSVS_ACCESS_INDEX_BUFFER, // Read as an index buffer for drawing
THSVS_ACCESS_VERTEX_BUFFER, // Read as a vertex buffer for drawing
THSVS_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in a vertex shader
THSVS_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, // Read as a sampled image/uniform texel buffer in a vertex shader
THSVS_ACCESS_VERTEX_SHADER_READ_OTHER, // Read as any other resource in a vertex shader
THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in a tessellation control shader
THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, // Read as a sampled image/uniform texel buffer in a tessellation control shader
THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_OTHER, // Read as any other resource in a tessellation control shader
THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in a tessellation evaluation shader
THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, // Read as a sampled image/uniform texel buffer in a tessellation evaluation shader
THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_OTHER, // Read as any other resource in a tessellation evaluation shader
THSVS_ACCESS_GEOMETRY_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in a geometry shader
THSVS_ACCESS_GEOMETRY_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER,// Read as a sampled image/uniform texel buffer in a geometry shader
THSVS_ACCESS_GEOMETRY_SHADER_READ_OTHER, // Read as any other resource in a geometry shader
THSVS_ACCESS_TASK_SHADER_READ_UNIFORM_BUFFER_NV, // Read as a uniform buffer in a task shader
THSVS_ACCESS_TASK_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV, // Read as a sampled image/uniform texel buffer in a task shader
THSVS_ACCESS_TASK_SHADER_READ_OTHER_NV, // Read as any other resource in a task shader
THSVS_ACCESS_MESH_SHADER_READ_UNIFORM_BUFFER_NV, // Read as a uniform buffer in a mesh shader
THSVS_ACCESS_MESH_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV, // Read as a sampled image/uniform texel buffer in a mesh shader
THSVS_ACCESS_MESH_SHADER_READ_OTHER_NV, // Read as any other resource in a mesh shader
THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_EXT, // Read as a transform feedback counter buffer
THSVS_ACCESS_FRAGMENT_DENSITY_MAP_READ_EXT, // Read as a fragment density map image
THSVS_ACCESS_SHADING_RATE_READ_NV, // Read as a shading rate image
THSVS_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in a fragment shader
THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER,// Read as a sampled image/uniform texel buffer in a fragment shader
THSVS_ACCESS_FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT, // Read as an input attachment with a color format in a fragment shader
THSVS_ACCESS_FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT, // Read as an input attachment with a depth/stencil format in a fragment shader
THSVS_ACCESS_FRAGMENT_SHADER_READ_OTHER, // Read as any other resource in a fragment shader
THSVS_ACCESS_COLOR_ATTACHMENT_READ, // Read by standard blending/logic operations or subpass load operations
THSVS_ACCESS_COLOR_ATTACHMENT_ADVANCED_BLENDING_EXT, // Read by advanced blending, standard blending, logic operations, or subpass load operations
THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ, // Read by depth/stencil tests or subpass load operations
THSVS_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in a compute shader
THSVS_ACCESS_COMPUTE_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, // Read as a sampled image/uniform texel buffer in a compute shader
THSVS_ACCESS_COMPUTE_SHADER_READ_OTHER, // Read as any other resource in a compute shader
THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER, // Read as a uniform buffer in any shader
THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER_OR_VERTEX_BUFFER, // Read as a uniform buffer in any shader, or a vertex buffer
THSVS_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER, // Read as a sampled image in any shader
THSVS_ACCESS_ANY_SHADER_READ_OTHER, // Read as any other resource (excluding attachments) in any shader
THSVS_ACCESS_TRANSFER_READ, // Read as the source of a transfer operation
THSVS_ACCESS_HOST_READ, // Read on the host
// Requires VK_KHR_swapchain to be enabled
THSVS_ACCESS_PRESENT, // Read by the presentation engine (i.e. vkQueuePresentKHR)
// Requires VK_EXT_conditional_rendering to be enabled
THSVS_ACCESS_CONDITIONAL_RENDERING_READ_EXT, // Read by conditional rendering
// Requires VK_NV_ray_tracing to be enabled
THSVS_ACCESS_RAY_TRACING_SHADER_ACCELERATION_STRUCTURE_READ_NV, // Read by a ray tracing shader as an acceleration structure
THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_READ_NV, // Read as an acceleration structure during a build
// Read accesses end
THSVS_END_OF_READ_ACCESS,
// Write access
// Requires VK_NV_device_generated_commands to be enabled
THSVS_ACCESS_COMMAND_BUFFER_WRITE_NV, // Command buffer write operation
THSVS_ACCESS_VERTEX_SHADER_WRITE, // Written as any resource in a vertex shader
THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_WRITE, // Written as any resource in a tessellation control shader
THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_WRITE, // Written as any resource in a tessellation evaluation shader
THSVS_ACCESS_GEOMETRY_SHADER_WRITE, // Written as any resource in a geometry shader
// Requires VK_NV_mesh_shading to be enabled
THSVS_ACCESS_TASK_SHADER_WRITE_NV, // Written as any resource in a task shader
THSVS_ACCESS_MESH_SHADER_WRITE_NV, // Written as any resource in a mesh shader
// Requires VK_EXT_transform_feedback to be enabled
THSVS_ACCESS_TRANSFORM_FEEDBACK_WRITE_EXT, // Written as a transform feedback buffer
THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT, // Written as a transform feedback counter buffer
THSVS_ACCESS_FRAGMENT_SHADER_WRITE, // Written as any resource in a fragment shader
THSVS_ACCESS_COLOR_ATTACHMENT_WRITE, // Written as a color attachment during rendering, or via a subpass store op
THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE, // Written as a depth/stencil attachment during rendering, or via a subpass store op
// Requires VK_KHR_maintenance2 to be enabled
THSVS_ACCESS_DEPTH_ATTACHMENT_WRITE_STENCIL_READ_ONLY, // Written as a depth aspect of a depth/stencil attachment during rendering, whilst the stencil aspect is read-only
THSVS_ACCESS_STENCIL_ATTACHMENT_WRITE_DEPTH_READ_ONLY, // Written as a stencil aspect of a depth/stencil attachment during rendering, whilst the depth aspect is read-only
THSVS_ACCESS_COMPUTE_SHADER_WRITE, // Written as any resource in a compute shader
THSVS_ACCESS_ANY_SHADER_WRITE, // Written as any resource in any shader
THSVS_ACCESS_TRANSFER_WRITE, // Written as the destination of a transfer operation
THSVS_ACCESS_HOST_PREINITIALIZED, // Data pre-filled by host before device access starts
THSVS_ACCESS_HOST_WRITE, // Written on the host
// Requires VK_NV_ray_tracing to be enabled
THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_WRITE_NV, // Written as an acceleration structure during a build
THSVS_ACCESS_COLOR_ATTACHMENT_READ_WRITE, // Read or written as a color attachment during rendering
// General access
THSVS_ACCESS_GENERAL, // Covers any access - useful for debug, generally avoid for performance reasons
// Number of access types
THSVS_NUM_ACCESS_TYPES
} ThsvsAccessType;
/*
ThsvsImageLayout defines a handful of layout options for images.
Rather than a list of all possible image layouts, this reduced list is
correlated with the access types to map to the correct Vulkan layouts.
THSVS_IMAGE_LAYOUT_OPTIMAL is usually preferred.
*/
typedef enum ThsvsImageLayout {
THSVS_IMAGE_LAYOUT_OPTIMAL, // Choose the most optimal layout for each usage. Performs layout transitions as appropriate for the access.
THSVS_IMAGE_LAYOUT_GENERAL, // Layout accessible by all Vulkan access types on a device - no layout transitions except for presentation
// Requires VK_KHR_shared_presentable_image to be enabled. Can only be used for shared presentable images (i.e. single-buffered swap chains).
THSVS_IMAGE_LAYOUT_GENERAL_AND_PRESENTATION // As GENERAL, but also allows presentation engines to access it - no layout transitions
} ThsvsImageLayout;
/*
Global barriers define a set of accesses on multiple resources at once.
If a buffer or image doesn't require a queue ownership transfer, or an image
doesn't require a layout transition (e.g. you're using one of the GENERAL
layouts) then a global barrier should be preferred.
Simply define the previous and next access types of resources affected.
*/
typedef struct ThsvsGlobalBarrier {
uint32_t prevAccessCount;
const ThsvsAccessType* pPrevAccesses;
uint32_t nextAccessCount;
const ThsvsAccessType* pNextAccesses;
} ThsvsGlobalBarrier;
/*
Buffer barriers should only be used when a queue family ownership transfer
is required - prefer global barriers at all other times.
Access types are defined in the same way as for a global memory barrier, but
they only affect the buffer range identified by buffer, offset and size,
rather than all resources.
srcQueueFamilyIndex and dstQueueFamilyIndex will be passed unmodified into a
VkBufferMemoryBarrier.
A buffer barrier defining a queue ownership transfer needs to be executed
twice - once by a queue in the source queue family, and then once again by a
queue in the destination queue family, with a semaphore guaranteeing
execution order between them.
*/
typedef struct ThsvsBufferBarrier {
uint32_t prevAccessCount;
const ThsvsAccessType* pPrevAccesses;
uint32_t nextAccessCount;
const ThsvsAccessType* pNextAccesses;
uint32_t srcQueueFamilyIndex;
uint32_t dstQueueFamilyIndex;
VkBuffer buffer;
VkDeviceSize offset;
VkDeviceSize size;
} ThsvsBufferBarrier;
/*
Image barriers should only be used when a queue family ownership transfer
or an image layout transition is required - prefer global barriers at all
other times.
In general it is better to use image barriers with THSVS_IMAGE_LAYOUT_OPTIMAL
than it is to use global barriers with images using either of the
THSVS_IMAGE_LAYOUT_GENERAL* layouts.
Access types are defined in the same way as for a global memory barrier, but
they only affect the image subresource range identified by image and
subresourceRange, rather than all resources.
srcQueueFamilyIndex, dstQueueFamilyIndex, image, and subresourceRange will
be passed unmodified into a VkImageMemoryBarrier.
An image barrier defining a queue ownership transfer needs to be executed
twice - once by a queue in the source queue family, and then once again by a
queue in the destination queue family, with a semaphore guaranteeing
execution order between them.
If discardContents is set to true, the contents of the image become
undefined after the barrier is executed, which can result in a performance
boost over attempting to preserve the contents.
This is particularly useful for transient images where the contents are
going to be immediately overwritten. A good example of when to use this is
when an application re-uses a presented image after vkAcquireNextImageKHR.
*/
typedef struct ThsvsImageBarrier {
uint32_t prevAccessCount;
const ThsvsAccessType* pPrevAccesses;
uint32_t nextAccessCount;
const ThsvsAccessType* pNextAccesses;
ThsvsImageLayout prevLayout;
ThsvsImageLayout nextLayout;
VkBool32 discardContents;
uint32_t srcQueueFamilyIndex;
uint32_t dstQueueFamilyIndex;
VkImage image;
VkImageSubresourceRange subresourceRange;
} ThsvsImageBarrier;
/*
Mapping function that translates a set of accesses into the corresponding
pipeline stages, VkAccessFlags, and image layout.
*/
void thsvsGetAccessInfo(
uint32_t accessCount,
const ThsvsAccessType* pAccesses,
VkPipelineStageFlags* pStageMask,
VkAccessFlags* pAccessMask,
VkImageLayout* pImageLayout,
bool* pHasWriteAccess);
/*
Mapping function that translates a global barrier into a set of source and
destination pipeline stages, and a VkMemoryBarrier, that can be used with
Vulkan's synchronization methods.
*/
void thsvsGetVulkanMemoryBarrier(
const ThsvsGlobalBarrier& thBarrier,
VkPipelineStageFlags* pSrcStages,
VkPipelineStageFlags* pDstStages,
VkMemoryBarrier* pVkBarrier);
/*
Mapping function that translates a buffer barrier into a set of source and
destination pipeline stages, and a VkBufferMemoryBarrier, that can be used
with Vulkan's synchronization methods.
*/
void thsvsGetVulkanBufferMemoryBarrier(
const ThsvsBufferBarrier& thBarrier,
VkPipelineStageFlags* pSrcStages,
VkPipelineStageFlags* pDstStages,
VkBufferMemoryBarrier* pVkBarrier);
/*
Mapping function that translates an image barrier into a set of source and
destination pipeline stages, and a VkBufferMemoryBarrier, that can be used
with Vulkan's synchronization methods.
*/
void thsvsGetVulkanImageMemoryBarrier(
const ThsvsImageBarrier& thBarrier,
VkPipelineStageFlags* pSrcStages,
VkPipelineStageFlags* pDstStages,
VkImageMemoryBarrier* pVkBarrier);
/*
Simplified wrapper around vkCmdPipelineBarrier.
The mapping functions defined above are used to translate the passed in
barrier definitions into a set of pipeline stages and native Vulkan memory
barriers to be passed to vkCmdPipelineBarrier.
commandBuffer is passed unmodified to vkCmdPipelineBarrier.
*/
void thsvsCmdPipelineBarrier(
VkCommandBuffer commandBuffer,
const ThsvsGlobalBarrier* pGlobalBarrier,
uint32_t bufferBarrierCount,
const ThsvsBufferBarrier* pBufferBarriers,
uint32_t imageBarrierCount,
const ThsvsImageBarrier* pImageBarriers);
/*
Wrapper around vkCmdSetEvent.
Sets an event when the accesses defined by pPrevAccesses are completed.
commandBuffer and event are passed unmodified to vkCmdSetEvent.
*/
void thsvsCmdSetEvent(
VkCommandBuffer commandBuffer,
VkEvent event,
uint32_t prevAccessCount,
const ThsvsAccessType* pPrevAccesses);
/*
Wrapper around vkCmdResetEvent.
Resets an event when the accesses defined by pPrevAccesses are completed.
commandBuffer and event are passed unmodified to vkCmdResetEvent.
*/
void thsvsCmdResetEvent(
VkCommandBuffer commandBuffer,
VkEvent event,
uint32_t prevAccessCount,
const ThsvsAccessType* pPrevAccesses);
/*
Simplified wrapper around vkCmdWaitEvents.
The mapping functions defined above are used to translate the passed in
barrier definitions into a set of pipeline stages and native Vulkan memory
barriers to be passed to vkCmdPipelineBarrier.
commandBuffer, eventCount, and pEvents are passed unmodified to
vkCmdWaitEvents.
*/
void thsvsCmdWaitEvents(
VkCommandBuffer commandBuffer,
uint32_t eventCount,
const VkEvent* pEvents,
const ThsvsGlobalBarrier* pGlobalBarrier,
uint32_t bufferBarrierCount,
const ThsvsBufferBarrier* pBufferBarriers,
uint32_t imageBarrierCount,
const ThsvsImageBarrier* pImageBarriers);
#endif // THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_H
#ifdef THSVS_SIMPLER_VULKAN_SYNCHRONIZATION_IMPLEMENTATION
#include <stdlib.h>
//// Optional Error Checking ////
/*
Checks for barriers defining multiple usages that have different layouts
*/
// #define THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT
/*
Checks if an image/buffer barrier is used when a global barrier would suffice
*/
// #define THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER
/*
Checks if a write access is listed alongside any other access - if so it
points to a potential data hazard that you need to synchronize separately.
In some cases it may simply be over-synchronization however, but it's usually
worth checking.
*/
// #define THSVS_ERROR_CHECK_POTENTIAL_HAZARD
/*
Checks if a variety of table lookups (like the access map) are within
a valid range.
*/
// #define THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
//// Temporary Memory Allocation ////
/*
Override these if you can't afford the stack space or just want to use a
custom temporary allocator.
These are currently used exclusively to allocate Vulkan memory barriers in
the API, one for each Buffer or Image barrier passed into the pipeline and
event functions.
May consider other allocation strategies in future.
*/
// Alloca inclusion code below copied from
// https://github.com/nothings/stb/blob/master/stb_vorbis.c
// find definition of alloca if it's not in stdlib.h:
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h>
#endif
#if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
#include <alloca.h>
#endif
#if defined(THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE) || \
defined(THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER) || \
defined(THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT) || \
defined(THSVS_ERROR_CHECK_POTENTIAL_HAZARD)
#include <assert.h>
#endif
#if !defined(THSVS_TEMP_ALLOC)
#define THSVS_TEMP_ALLOC(size) (alloca(size))
#endif
#if !defined(THSVS_TEMP_FREE)
#define THSVS_TEMP_FREE(x) ((void)(x))
#endif
typedef struct ThsvsVkAccessInfo {
VkPipelineStageFlags stageMask;
VkAccessFlags accessMask;
VkImageLayout imageLayout;
} ThsvsVkAccessInfo;
const ThsvsVkAccessInfo ThsvsAccessMap[THSVS_NUM_ACCESS_TYPES] = {
// THSVS_ACCESS_NONE
{ 0,
0,
VK_IMAGE_LAYOUT_UNDEFINED},
// Read Access
// THSVS_ACCESS_COMMAND_BUFFER_READ_NV
{ VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV,
VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_INDIRECT_BUFFER
{ VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_INDEX_BUFFER
{ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
VK_ACCESS_INDEX_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_VERTEX_BUFFER
{ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_VERTEX_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
{ VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_VERTEX_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
{ VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
{ VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_GEOMETRY_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_GEOMETRY_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
{ VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_GEOMETRY_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TASK_SHADER_READ_UNIFORM_BUFFER_NV
{ VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_TASK_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV
{ VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_TASK_SHADER_READ_OTHER_NV
{ VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_MESH_SHADER_READ_UNIFORM_BUFFER_NV
{ VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_MESH_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER_NV
{ VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_MESH_SHADER_READ_OTHER_NV
{ VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_EXT
{ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_FRAGMENT_DENSITY_MAP_READ_EXT
{ VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT,
VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT,
VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT},
// THSVS_ACCESS_SHADING_RATE_READ_NV
{ VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV,
VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV,
VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV},
// THSVS_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_FRAGMENT_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
{ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_FRAGMENT_SHADER_READ_COLOR_INPUT_ATTACHMENT
{ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_FRAGMENT_SHADER_READ_DEPTH_STENCIL_INPUT_ATTACHMENT
{ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_FRAGMENT_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_COLOR_ATTACHMENT_READ
{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
// THSVS_ACCESS_COLOR_ATTACHMENT_ADVANCED_BLENDING_EXT
{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
// THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ
{ VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_COMPUTE_SHADER_READ_SAMPLED_IMAGE_OR_UNIFORM_TEXEL_BUFFER
{ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_COMPUTE_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER
{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_UNIFORM_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_ANY_SHADER_READ_UNIFORM_BUFFER_OR_VERTEX_BUFFER
{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_ANY_SHADER_READ_SAMPLED_IMAGE
{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL},
// THSVS_ACCESS_ANY_SHADER_READ_OTHER
{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TRANSFER_READ
{ VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL},
// THSVS_ACCESS_HOST_READ
{ VK_PIPELINE_STAGE_HOST_BIT,
VK_ACCESS_HOST_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_PRESENT
{ 0,
0,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR},
// THSVS_ACCESS_CONDITIONAL_RENDERING_READ_EXT
{ VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT,
VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_RAY_TRACING_SHADER_ACCELERATION_STRUCTURE_READ_NV
{ VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV,
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_READ_NV
{ VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV,
VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_END_OF_READ_ACCESS
{ 0,
0,
VK_IMAGE_LAYOUT_UNDEFINED},
// Write access
// THSVS_ACCESS_COMMAND_BUFFER_WRITE_NV
{ VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV,
VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_VERTEX_SHADER_WRITE
{ VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TESSELLATION_CONTROL_SHADER_WRITE
{ VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TESSELLATION_EVALUATION_SHADER_WRITE
{ VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_GEOMETRY_SHADER_WRITE
{ VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TASK_SHADER_WRITE_NV
{ VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_MESH_SHADER_WRITE_NV
{ VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TRANSFORM_FEEDBACK_WRITE_EXT
{ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT
{ VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_FRAGMENT_SHADER_WRITE
{ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_COLOR_ATTACHMENT_WRITE
{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
// THSVS_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE
{ VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL},
// THSVS_ACCESS_DEPTH_ATTACHMENT_WRITE_STENCIL_READ_ONLY
{ VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR},
// THSVS_ACCESS_STENCIL_ATTACHMENT_WRITE_DEPTH_READ_ONLY
{ VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR},
// THSVS_ACCESS_COMPUTE_SHADER_WRITE
{ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_ANY_SHADER_WRITE
{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_TRANSFER_WRITE
{ VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL},
// THSVS_ACCESS_HOST_PREINITIALIZED
{ VK_PIPELINE_STAGE_HOST_BIT,
VK_ACCESS_HOST_WRITE_BIT,
VK_IMAGE_LAYOUT_PREINITIALIZED},
// THSVS_ACCESS_HOST_WRITE
{ VK_PIPELINE_STAGE_HOST_BIT,
VK_ACCESS_HOST_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL},
// THSVS_ACCESS_ACCELERATION_STRUCTURE_BUILD_WRITE_NV
{ VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV,
VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV,
VK_IMAGE_LAYOUT_UNDEFINED},
// THSVS_ACCESS_COLOR_ATTACHMENT_READ_WRITE
{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL},
// THSVS_ACCESS_GENERAL
{ VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
VK_IMAGE_LAYOUT_GENERAL}
};
void thsvsGetAccessInfo(
uint32_t accessCount,
const ThsvsAccessType* pAccesses,
VkPipelineStageFlags* pStageMask,
VkAccessFlags* pAccessMask,
VkImageLayout* pImageLayout,
bool* pHasWriteAccess)
{
*pStageMask = 0;
*pAccessMask = 0;
*pImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
*pHasWriteAccess = false;
for (uint32_t i = 0; i < accessCount; ++i)
{
ThsvsAccessType access = pAccesses[i];
const ThsvsVkAccessInfo* pAccessInfo = &ThsvsAccessMap[access];
#ifdef THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
// Asserts that the previous access index is a valid range for the lookup
assert(access < THSVS_NUM_ACCESS_TYPES);
#endif
#ifdef THSVS_ERROR_CHECK_POTENTIAL_HAZARD
// Asserts that the access is a read, else it's a write and it should appear on its own.
assert(access < THSVS_END_OF_READ_ACCESS || accessCount == 1);
#endif
*pStageMask |= pAccessInfo->stageMask;
if (access > THSVS_END_OF_READ_ACCESS)
*pHasWriteAccess = true;
*pAccessMask |= pAccessInfo->accessMask;
VkImageLayout layout = pAccessInfo->imageLayout;
#ifdef THSVS_ERROR_CHECK_MIXED_IMAGE_LAYOUT
assert(*pImageLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
*pImageLayout == layout);
#endif
*pImageLayout = layout;
}
}
void thsvsGetVulkanMemoryBarrier(
const ThsvsGlobalBarrier& thBarrier,
VkPipelineStageFlags* pSrcStages,
VkPipelineStageFlags* pDstStages,
VkMemoryBarrier* pVkBarrier)
{
*pSrcStages = 0;
*pDstStages = 0;
pVkBarrier->sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
pVkBarrier->pNext = NULL;
pVkBarrier->srcAccessMask = 0;
pVkBarrier->dstAccessMask = 0;
for (uint32_t i = 0; i < thBarrier.prevAccessCount; ++i)
{
ThsvsAccessType prevAccess = thBarrier.pPrevAccesses[i];
const ThsvsVkAccessInfo* pPrevAccessInfo = &ThsvsAccessMap[prevAccess];
#ifdef THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
// Asserts that the previous access index is a valid range for the lookup
assert(prevAccess < THSVS_NUM_ACCESS_TYPES);
#endif
#ifdef THSVS_ERROR_CHECK_POTENTIAL_HAZARD
// Asserts that the access is a read, else it's a write and it should appear on its own.
assert(prevAccess < THSVS_END_OF_READ_ACCESS || thBarrier.prevAccessCount == 1);
#endif
*pSrcStages |= pPrevAccessInfo->stageMask;
// Add appropriate availability operations - for writes only.
if (prevAccess > THSVS_END_OF_READ_ACCESS)
pVkBarrier->srcAccessMask |= pPrevAccessInfo->accessMask;
}
for (uint32_t i = 0; i < thBarrier.nextAccessCount; ++i)
{
ThsvsAccessType nextAccess = thBarrier.pNextAccesses[i];
const ThsvsVkAccessInfo* pNextAccessInfo = &ThsvsAccessMap[nextAccess];
#ifdef THSVS_ERROR_CHECK_ACCESS_TYPE_IN_RANGE
// Asserts that the next access index is a valid range for the lookup
assert(nextAccess < THSVS_NUM_ACCESS_TYPES);
#endif
#ifdef THSVS_ERROR_CHECK_POTENTIAL_HAZARD
// Asserts that the access is a read, else it's a write and it should appear on its own.
assert(nextAccess < THSVS_END_OF_READ_ACCESS || thBarrier.nextAccessCount == 1);
#endif
*pDstStages |= pNextAccessInfo->stageMask;
// Add visibility operations as necessary.
// If the src access mask is zero, this is a WAR hazard (or for some reason a "RAR"),
// so the dst access mask can be safely zeroed as these don't need visibility.
if (pVkBarrier->srcAccessMask != 0)
pVkBarrier->dstAccessMask |= pNextAccessInfo->accessMask;
}
// Ensure that the stage masks are valid if no stages were determined
if (*pSrcStages == 0)
*pSrcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
if (*pDstStages == 0)
*pDstStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
void thsvsGetVulkanBufferMemoryBarrier(
const ThsvsBufferBarrier& thBarrier,
VkPipelineStageFlags* pSrcStages,
VkPipelineStageFlags* pDstStages,
VkBufferMemoryBarrier* pVkBarrier)
{
*pSrcStages = 0;
*pDstStages = 0;
pVkBarrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
pVkBarrier->pNext = NULL;
pVkBarrier->srcAccessMask = 0;
pVkBarrier->dstAccessMask = 0;
pVkBarrier->srcQueueFamilyIndex = thBarrier.srcQueueFamilyIndex;
pVkBarrier->dstQueueFamilyIndex = thBarrier.dstQueueFamilyIndex;
pVkBarrier->buffer = thBarrier.buffer;
pVkBarrier->offset = thBarrier.offset;
pVkBarrier->size = thBarrier.size;
#ifdef THSVS_ERROR_CHECK_COULD_USE_GLOBAL_BARRIER
assert(pVkBarrier->srcQueueFamilyIndex != pVkBarrier->dstQueueFamilyIndex);
#endif
for (uint32_t i = 0; i < thBarrier.prevAccessCount; ++i)
{