aboutsummaryrefslogtreecommitdiff
path: root/docs/amber_script.md
blob: 7c78d822b338c901b7013ec8312c8a1ae832d72c (plain)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
# AmberScript
 * DRAFT

This document defines the script input language for the Amber system. The format
is based on the Talvos format, VkRunner format, and VkScript proposed format.

## Specification
All amber scripts must start with `#!amber` as the first line. Comments are
specified by a # character and continue to the end of the line, except in
inlined shader source code, where AmberScript comments are not
possible. Keywords are case sensitive. All names are made up of ASCII
characters, and delimited by whitespace.

TODO(dneto): What characters are valid in a name?

### Number literals

Literal numbers are normally presented in decimal form.  They are interpreted
as integers or floating point depending on context: a command parameter is
predefined as either integral or floating point, or the data type is
user-specified (such as for buffer data).

Hex values: Whenever an integer is expected, you may use a hexadecimal number,
which is the characters `0x` followed by hexadecimal digits.

### Requesting features

If specific device features are required you can use the `DEVICE_FEATURE`
command to enable them.

```groovy
DEVICE_FEATURE vertexPipelineStoresAndAtomics
DEVICE_FEATURE VariablePointerFeatures.variablePointersStorageBuffer
```

Currently each of the items in `VkPhysicalDeviceFeatures` are recognized along
with:
 * `VariablePointerFeatures.variablePointers`
 * `VariablePointerFeatures.variablePointersStorageBuffer`
 * `Float16Int8Features.shaderFloat16`
 * `Float16Int8Features.shaderInt8`
 * `Storage8BitFeatures.storageBuffer8BitAccess`
 * `Storage8BitFeatures.uniformAndStorageBuffer8BitAccess`
 * `Storage8BitFeatures.storagePushConstant8`
 * `Storage16BitFeatures.storageBuffer16BitAccess`
 * `Storage16BitFeatures.uniformAndStorageBuffer16BitAccess`
 * `Storage16BitFeatures.storagePushConstant16`
 * `Storage16BitFeatures.storageInputOutput16`
 * `SubgroupSizeControl.subgroupSizeControl`
 * `SubgroupSizeControl.computeFullSubgroups`
 * `SubgroupSupportedOperations.basic`
 * `SubgroupSupportedOperations.vote`
 * `SubgroupSupportedOperations.arithmetic`
 * `SubgroupSupportedOperations.ballot`
 * `SubgroupSupportedOperations.shuffle`
 * `SubgroupSupportedOperations.shuffleRelative`
 * `SubgroupSupportedOperations.clustered`
 * `SubgroupSupportedOperations.quad`
 * `SubgroupSupportedStages.vertex`
 * `SubgroupSupportedStages.tessellationControl`
 * `SubgroupSupportedStages.tessellationEvaluation`
 * `SubgroupSupportedStages.geometry`
 * `SubgroupSupportedStages.fragment`
 * `SubgroupSupportedStages.compute`


Extensions can be enabled with the `DEVICE_EXTENSION` and `INSTANCE_EXTENSION`
commands.

```groovy
DEVICE_EXTENSION VK_KHR_get_physical_device_properties2
INSTANCE_EXTENSION VK_KHR_storage_buffer_storage_class
```

### Setting Engine Configuration

In some instances there is extra data we want to provide to an engine for
configuration purposes. The `SET ENGINE_DATA` command allows that for the given
set of data types.

#### Engine Data Variables
  * `fence_timeout_ms`  - value must be a single uint32 in milliseconds.

```groovy
SET ENGINE_DATA {engine data variable} {value}*
```

### Virtual File Store

Each amber script contains a virtual file system that can store files of textual
data. This lets you bundle multiple source files into a single, hermetic amber
script file.

Virtual files are declared using the `VIRTUAL_FILE` command:

```groovy
VIRTUAL_FILE {path}
 {file-content}
END
```

Paths must be unique.

Shaders can directly reference these virtual files for their source. \
HLSL shaders that `#include` other `.hlsl` files will first check the virtual
file system, before falling back to the standard file system.

### Shaders

Shader programs are declared using the `SHADER` command. \
Shaders can be declared as `PASSTHROUGH`, with inlined source or using source
from a `VIRTUAL_FILE`.

Pass-through shader:

```groovy
# Creates a passthrough vertex shader. The shader passes the vec4 at input
# location 0 through to the `gl_Position`.
SHADER vertex {shader_name} PASSTHROUGH
```

Shader using inlined source:

```groovy
# Creates a shader of |shader_type| with the given |shader_name|. The shader
# will be of |shader_format|. The shader source then follows and is terminated
# with the |END| tag.
SHADER {shader_type} {shader_name} {shader_format} [ TARGET_ENV {target_env} ]
{shader_source}
END
```

Shader using source from `VIRTUAL_FILE`:

```groovy
# Creates a shader of |shader_type| with the given |shader_name|. The shader
# will be of |shader_format|. The shader will use the virtual file with |path|.
SHADER {shader_type} {shader_name} {shader_format} [ TARGET_ENV {target_env} ] VIRTUAL_FILE {path}
```

`{shader_name}` is used to identify the shader to attach to `PIPELINE`s,

`{shader_type}` and `{shader_format}` are described below:

#### Shader Type
 * `vertex`
 * `fragment`
 * `geometry`
 * `tessellation_evaluation`
 * `tessellation_control`
 * `compute`
 * `multi`

The compute pipeline can only contain compute shaders. The graphics pipeline
can not contain compute shaders, and must contain a vertex shader and a fragment
shader.

The provided `multi` shader can only be used with `SPIRV-ASM` and `SPIRV-HEX`
and allows for providing multiple shaders in a single module (so the `vertex`
and `fragment` shaders can be provided together.)

Note, `SPIRV-ASM` and `SPIRV-HEX` can also be used with each of the other shader
types, but in that case must only provide a single shader type in the module.

#### Shader Format
 * `GLSL`  (with glslang)
 * `HLSL`  (with dxc or glslang if dxc disabled)
 * `SPIRV-ASM` (with spirv-as; specifying `TARGET_ENV` is _highly recommended_
    in this case, as explained below)
 * `SPIRV-HEX` (decoded straight to SPIR-V)
 * `OPENCL-C` (with clspv)

### Target environment

Specifying `TARGET_ENV` is optional and can be used to select a target
SPIR-V environment. For example:

 * `spv1.0`
 * `spv1.5`
 * `vulkan1.0`
 * `vulkan1.2`

Check the help text of the corresponding tool (e.g. spirv-as, glslangValidator)
for the full list. The `SPIRV-HEX` shader format is not affected by the target
environment.

The specified target environment for the shader overrides the default (`spv1.0`)
or the one specified on the command line.

Specifying the target environment when using the `SPIRV-ASM` shader format
is _highly recommended_, otherwise the SPIR-V version of the final SPIR-V binary
shader passed to the graphics device might not be what you expect.
Typically, SPIR-V assembly text will contain a comment near the beginning similar
to `; Version: 1.0` but this is _ignored_ by the spirv-as assembler.
Thus, you should specify the equivalent target environment (e.g. `spv1.0`)
in the `SHADER` command.

Specifying the target environment for other shader formats depends on whether
you want to vary the final SPIR-V shader binary based on the target environment
specified on the command line. For example, you could write one AmberScript file
that contains a GLSL shader without specifying a target environment.
You could then run the AmberScript file several times with different
target environments specified on the command line
(`spv1.0`, `spv1.1`, `spv1.2`, etc.) to test the different SPIR-V shader variants.

### Buffers

An AmberScript buffer represents a set of contiguous bits. This can be used for
either image buffers or, what the target API would refer to as a buffer.

#### Data Types
 * `int8`
 * `int16`
 * `int32`
 * `int64`
 * `uint8`
 * `uint16`
 * `uint32`
 * `uint64`
 * `float16`
 * `float`
 * `double`
 * vec[2,3,4]{type}
 * mat[2,3,4]x[2,3,4]{type}  (mat<columns>x<rows>)
 * Any of the `Image Formats` listed below.
 * For any of the non-Image Formats types above appending '[]' will treat the
    data as an array. e.g. int8[], vec2<float>[]

Sized arrays and structures are not currently representable.

```groovy
# Filling the buffer with a given initializer. Initializer data must be
# of |type|. Buffers are STD430 by default.
BUFFER {name} DATA_TYPE {type} {STD140 | STD430} {initializer}

# Defines a buffer which is filled with data as specified by the `initializer`.
BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
    {initializer}

# Deprecated
# Defines a buffer with width and height and filled by data as specified by the
# `initializer`.
BUFFER {name} DATA_TYPE {type} {STD140 | STD430} WIDTH {w} HEIGHT {h} \
  {initializer}

# Defines a buffer which is filled with binary data from a file specified
# by `FILE`.
BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
    FILE BINARY {file_name}

# Defines a buffer which is filled with text data parsed from a file specified
# by `FILE`.
BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
    FILE TEXT {file_name}

# Creates a buffer which will store the given `FORMAT` of data. These
# buffers are used as image and depth buffers in the `PIPELINE` commands.
# The buffer will be sized based on the `RENDER_SIZE` of the `PIPELINE`.
# For multisampled images use value greater than one for `SAMPLES`. Allowed
# sample counts are 1, 2, 4, 8, 16, 32, and 64. Note that Amber doesn't
# preserve multisampled images across pipelines.
BUFFER {name} FORMAT {format_string} \
    [ MIP_LEVELS _mip_levels_ (default 1) ] \
    [ SAMPLES _samples_ (default 1) ]

# Load buffer data from a PNG image with file name specified by `FILE`.
# The file path is relative to the script file being run. Format specified
# by `FORMAT` must match the image format.
BUFFER {name} FORMAT {format_string} FILE PNG {file_name.png}
```

#### Images

An AmberScript image is a specialized buffer that specifies image-specific
attributes.

##### Dimensionality
 * `DIM_1D` -- A 1-dimensional image
 * `DIM_2D` -- A 2-dimensional image
 * `DIM_3D` -- A 3-dimensional image

```groovy
# Specify an image buffer with a format. HEIGHT is necessary for DIM_2D and
# DIM_3D. DEPTH is necessary for DIM_3D.
IMAGE {name} FORMAT {format_string} [ MIP_LEVELS _mip_levels_ (default 1) ] \
    [ SAMPLES _samples_ (default 1) ] \
    {dimensionality} \
    WIDTH {w} [ HEIGHT {h} [ DEPTH {d} ] ] \
    {initializer}

# Specify an image buffer with a data type. HEIGHT is necessary for DIM_2D and
# DIM_3D. DEPTH is necessary for DIM_3D.
IMAGE {name} DATA_TYPE {type} {dimensionality} \
    WIDTH {w} [ HEIGHT {h} [ DEPTH {d} ] ] \
    {intializer}
```

#### Buffer Initializers

```groovy
# Filling the buffer with a given set of data. The values must be
# of the correct type. The data can be provided as the type or as a hex
# value.
DATA
_value_+
END

```groovy
# Fill the buffer with a single value.
FILL _value_

# Fill the buffer with an increasing value from |start| increasing by |inc|.
# Floating point data uses floating point addition to generate increasing
# values. Likewise, integer data uses integer addition to generate increasing
# values.
SERIES_FROM _start_ INC_BY _inc_
```

#### Buffer Copy

```groovy
# Copies all data, values and memory from |buffer_from| to |buffer_to|.
# Both buffers must be declared, and of the same data type.
# Buffers used as copy destination can be used only as copy destination, and as
# argument to an EXPECT command.
COPY {buffer_from} TO {buffer_to}
```

### Samplers

Samplers are used for sampling buffers that are bound to a pipeline as
sampled image or combined image sampler.

#### Filter types
 * `nearest`
 * `linear`

#### Address modes
 * `repeat`
 * `mirrored_repeat`
 * `clamp_to_edge`
 * `clamp_to_border`
 * `mirrored_clamp_to_edge`

#### Border colors
 * `float_transparent_black`
 * `int_transparent_black`
 * `float_opaque_black`
 * `int_opaque_black`
 * `float_opaque_white`
 * `int_opaque_white`

```groovy

# Creates a sampler with |name|.
SAMPLER {name} \
    [ MAG_FILTER {filter_type} (default nearest) ] \
    [ MIN_FILTER {filter_type} (default nearest) ] \
    [ ADDRESS_MODE_U {address_mode} (default repeat) ] \
    [ ADDRESS_MODE_V {address_mode} (default repeat) ] \
    [ ADDRESS_MODE_W {address_mode} (default repeat) ] \
    [ BORDER_COLOR {border_color} (default float_transparent_black) ] \
    [ MIN_LOD _val_ (default 0.0) ] \
    [ MAX_LOD _val_ (default 1.0) ] \
    [ NORMALIZED_COORDS | UNNORMALIZED_COORDS (default NORMALIZED_COORDS) ]
```

Note: unnormalized coordinates will override MIN\_LOD and MAX\_LOD to 0.0.

#### OpenCL Literal Samplers

Literal constant samplers defined in the OpenCL program are automatically
generated and bound to the pipeline in Amber.

Note: currently the border color is always transparent black.

Note: the addressing mode is used for all coordinates currently. Arrayed images
should use `clamp_to_edge` for the array index.

### Pipelines

#### Pipeline type
 * `compute`
 * `graphics`

```groovy
# The PIPELINE command creates a pipeline. This can be either compute or
# graphics. Shaders are attached to the pipeline at pipeline creation time.
PIPELINE {pipeline_type} {pipeline_name}
...
END

# Create a pipeline and inherit from a previously declared pipeline.
DERIVE_PIPELINE {pipeline_name} FROM {parent_pipeline}
...
END
```

### Pipeline Content

The following commands are all specified within the `PIPELINE` command.
```groovy
  # Attach the shader provided by |name_of_shader| to the pipeline with an
  # entry point name of |name|. The provided shader for ATTACH must _not_ be
  # a 'multi' shader.
  ATTACH {name_of_shader} \
      [ ENTRY_POINT {name} (default "main") ]

  # Attach a 'multi' shader to the pipeline of |shader_type| and use the entry
  # point with |name|. The provided shader _must_ be a 'multi' shader.
  ATTACH {name_of_multi_shader} TYPE {shader_type} ENTRY_POINT {name}

  # Attach specialized shader. Specialization can be specified multiple times.
  # Specialization values must be a 32-bit type. Shader type and entry point
  # must be specified prior to specializing the shader.
  ATTACH {name_of_shader} SPECIALIZE _id_ AS uint32 _value_
  ATTACH {name_of_shader} \
      SPECIALIZE _id_ AS uint32 _value_ \
      SPECIALIZE _id_ AS float _value_
```

```groovy
  # Set the SPIRV-Tools optimization passes to use for a given shader. The
  # default is to run no optimization passes.
  SHADER_OPTIMIZATION {shader_name}
    {optimization_name}+
  END
```

```groovy
  # Set the compile options used to compile the given shader. Options are parsed
  # the same as on the command line. Currently, only supported for OPENCL-C shaders.
  COMPILE_OPTIONS {shader_name}
    {option}+
  END
```

```groovy
  # Set the polygon mode used for all drawing with the pipeline.
  # |mode| is fill, line, or point and it defaults to fill.
  POLYGON_MODE {mode}
```

```groovy
  # Set the number of patch control points used by tessellation. The default value is 3.
  PATCH_CONTROL_POINTS {control_points}
```

#### Compare operations
 * `never`
 * `less`
 * `equal`
 * `less_or_equal`
 * `greater`
 * `not_equal`
 * `greater_or_equal`
 * `always`

```groovy
  # Set depth test settings. All enable options are specified with keywords on and off.
  # BOUNDS and BIAS values are specified with decimal numbers. |compare_op| is selected
  # from the list of compare operations above.
  DEPTH
    TEST {test_enable}
    WRITE {write_enable}
    COMPARE_OP {compare_op}
    CLAMP {clamp_enable}
    BOUNDS min {bound_min} max {bounds_max}
    BIAS constant {bias_constant} clamp {bias_clamp} slope {bias_slope}
  END
```

#### Stencil operations
 * `keep`
 * `replace`
 * `increment_and_clamp`
 * `decrement_and_clamp`
 * `invert`
 * `increment_and_wrap`
 * `decrement_and_wrap`

```groovy
  # Set stencil test settings. |face| can be front, back, or front_and_back.
  # |test_enable| is either on or off and affects both faces. |fail_op|, |pass_op|,
  # and |depth_fail_op| are selected from the stencil operations table above,
  # and |compare_op| from the compare operations table. |compare_mask|, |write_mask|,
  # and |reference| are 8bit unsigned integer values (range 0..255).
  STENCIL {face}
    TEST {test_enable}
    FAIL_OP {fail_op}
    PASS_OP {pass_op}
    DEPTH_FAIL_OP {depth_fail_op}
    COMPARE_OP {compare_op}
    COMPARE_MASK {compare_mask}
    WRITE_MASK {write_mask}
    REFERENCE {reference}
  END
```

#### Blend factors
* `zero`
* `one`
* `src_color`
* `one_minus_src_color`
* `dst_color`
* `one_minus_dst_color`
* `src_alpha`
* `one_minus_src_alpha`
* `dst_alpha`
* `one_minus_dst_alpha`
* `constant_color`
* `one_minus_constant_color`
* `constant_alpha`
* `one_minus_constant_alpha`
* `src_alpha_saturate`
* `src1_color`
* `one_minus_src1_color`
* `src1_alpha`
* `one_minus_src1_alpha`

#### Blend operations
* `add`
* `substract`
* `reverse_substract`
* `min`
* `max`

The following operations also require VK_EXT_blend_operation_advanced
when using a Vulkan backend.
* `zero`
* `src`
* `dst`
* `src_over`
* `dst_over`
* `src_in`
* `dst_in`
* `src_out`
* `dst_out`
* `src_atop`
* `dst_atop`
* `xor`
* `multiply`
* `screen`
* `overlay`
* `darken`
* `lighten`
* `color_dodge`
* `color_burn`
* `hard_light`
* `soft_light`
* `difference`
* `exclusion`
* `invert`
* `invert_rgb`
* `linear_dodge`
* `linear_burn`
* `vivid_light`
* `linear_light`
* `pin_light`
* `hard_mix`
* `hsl_hue`
* `hsl_saturation`
* `hsl_color`
* `hsl_luminosity`
* `plus`
* `plus_clamped`
* `plus_clamped_alpha`
* `plus_darker`
* `minus`
* `minus_clamped`
* `contrast`
* `invert_org`
* `red`
* `green`
* `blue`

```groovy
  # Enable alpha blending and set blend factors and operations. Available
  # blend factors and operations are listed above.
  BLEND
    SRC_COLOR_FACTOR {src_color_factor}
    DST_COLOR_FACTOR {dst_color_factor}
    COLOR_OP {color_op}
    SRC_ALPHA_FACTOR {src_alpha_factor}
    DST_ALPHA_FACTOR {dst_alpha_factor}
    ALPHA_OP {alpha_op}
  END
```

```groovy
  # Set the size of the render buffers. |width| and |height| are integers and
  # default to 250x250.
  FRAMEBUFFER_SIZE _width_ _height_
```

```groovy
  # Set the viewport size. If no viewport is provided then it defaults to the
  # whole framebuffer size. Depth range defaults to 0 to 1.
  VIEWPORT {x} {y} SIZE {width} {height} [MIN_DEPTH {mind}] [MAX_DEPTH {maxd}]
```

```groovy
  # Set subgroup size control setting. Require that subgroups must be launched
  # with all invocations active for given shader. Allow SubgroupSize to vary
  # for given shader. Require a specific SubgroupSize the for given shader.
  # |fully_populated_enable| and |varying_size_enable| can be on or off.
  # |subgroup_size| can be set one of the values below:
  #  - a power-of-two integer that _must_ be greater or equal to minSubgroupSize
  #    and be less than or equal to maxSubgroupSize
  # - MIN to set the required subgroup size to the minSubgroupSize
  # - MAX to set the required subgroup size to the maxSubgroupSize
  SUBGROUP {name_of_shader}
    FULLY_POPULATED {fully_populated_enable}
    VARYING_SIZE {varying_size_enable}
    REQUIRED_SIZE {subgroup_size}
  END
```

### Pipeline Buffers

#### Buffer Types
 * `uniform`
 * `storage`
 * `uniform_dynamic`
 * `storage_dynamic`
 * `uniform_texel_buffer`
 * `storage_texel_buffer`

TODO(dsinclair): Sync the BufferTypes with the list of Vulkan Descriptor types.

A `pipeline` can have buffers or samplers bound. This includes buffers to
contain image attachment content, depth/stencil content, uniform buffers, etc.

```groovy
  # Attach |buffer_name| as an output color attachment at location |idx|.
  # The provided buffer must be a `FORMAT` buffer. If no color attachments are
  # provided a single attachment with format `B8G8R8A8_UNORM` will be created
  # for graphics pipelines. The MIP level will have a base of |level|.
  BIND BUFFER {buffer_name} AS color LOCATION _idx_ \
      [ BASE_MIP_LEVEL _level_ (default 0) ]

  # Attach |buffer_name| as the depth/stencil buffer. The provided buffer must
  # be a `FORMAT` buffer. If no depth/stencil buffer is specified a default
  # buffer of format `D32_SFLOAT_S8_UINT` will be created for graphics
  # pipelines.
  BIND BUFFER {buffer_name} AS depth_stencil

  # Attach |buffer_name| as a multisample resolve target. The order of resolve
  # target images match with the order of color attachments that have more than
  # one sample.
  BIND BUFFER {buffer_name} AS resolve

  # Attach |buffer_name| as the push_constant buffer. There can be only one
  # push constant buffer attached to a pipeline.
  BIND BUFFER {buffer_name} AS push_constant

  # Bind OpenCL argument buffer by name. Specifying the buffer type is optional.
  # Amber will set the type as appropriate for the argument buffer. All uses
  # of the buffer must have a consistent |buffer_type| across all pipelines.
  BIND BUFFER {buffer_name} [ AS {buffer_type} (default computed)] \
      KERNEL ARG_NAME _name_

  # Bind OpenCL argument buffer by argument ordinal. Arguments use 0-based
  # numbering. Specifying the buffer type is optional. Amber will set the
  # type as appropriate for the argument buffer. All uses of the buffer
  # must have a consistent |buffer_type| across all pipelines.
  BIND BUFFER {buffer_name} [ AS {buffer_type} (default computed)] \
      KERNEL ARG_NUMBER _number_

  # Bind OpenCL argument sampler by argument name.
  BIND SAMPLER {sampler_name} KERNEL ARG_NAME _name_

  # Bind OpenCL argument sampler by argument ordinal. Arguments use 0-based
  # numbering.
  BIND SAMPLER {sampler_name} KERNEL ARG_NUMBER _number_
```

All BIND BUFFER and BIND SAMPLER commands below define a descriptor set and binding ID.
These commands can be replaced with BIND BUFFER_ARRAY and BIND SAMPLER_ARRAY commands.
In these cases multiple buffer or sampler names need to be provided, separated by spaces.
This creates a descriptor array of buffers or samplers bound to the same descriptor set
and binding ID. An array of dynamic offsets should be provided via `OFFSET offset1 offset2 ...`
when using dynamic buffers with BUFFER_ARRAY. Optional descriptor binding offset(s) and range(s)
can be defined via `DESCRIPTOR_OFFSET offset1 offset2 ...` and 
`DESCRIPTOR_RANGE range1 range2 ...` when using uniform or storage buffers. Offsets and 
ranges can be used also with dynamic buffers.
```groovy
  # Bind the buffer of the given |buffer_type| at the given descriptor set
  # and binding. The buffer will use a byte offset |descriptor_offset| 
  # with range |range|.
  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS {buffer_type} DESCRIPTOR_SET _id_ \
       BINDING _id_ [ DESCRIPTOR_OFFSET _descriptor_offset_ (default 0) ] \ 
       [ DESCRIPTOR_RANGE _range_ (default -1 == VK_WHOLE_SIZE) ]

  # Attach |buffer_name| as a storage image. The MIP level will have a base
  # value of |level|.
  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS storage_image \
      DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ]

  # Attach |buffer_name| as a sampled image.  The MIP level will have a base
  # value of |level|.
  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS sampled_image \
      DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ]

  # Attach |buffer_name| as a combined image sampler. A sampler |sampler_name|
  # must also be specified. The MIP level will have a base value of 0.
  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS combined_image_sampler SAMPLER {sampler_name} \
      DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ]

  # Bind the sampler at the given descriptor set and binding.
  BIND {SAMPLER | SAMPLER_ARRAY} {sampler_name} DESCRIPTOR_SET _id_ BINDING _id_

  # Bind |buffer_name| as dynamic uniform/storage buffer at the given descriptor set
  # and binding. The buffer will use a byte offset |offset| + |descriptor_offset|
  # with range |range|.
  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS {uniform_dynamic | storage_dynamic} \
       DESCRIPTOR_SET _id_ BINDING _id_ OFFSET _offset_ \
       [ DESCRIPTOR_OFFSET _descriptor_offset_ (default 0) ] \ 
       [ DESCRIPTOR_RANGE _range_ (default -1 == VK_WHOLE_SIZE) ]
```

```groovy
  # Set |buffer_name| as the vertex data at location |val|. RATE defines the
  # input rate for vertex attribute reading. OFFSET sets the byte offset for the
  # vertex data within the buffer |buffer_name|, which by default is 0. FORMAT
  # sets the vertex buffer format, which by default is the format of the buffer
  # |buffer_name|. STRIDE sets the byte stride, which by default is the stride
  # of the format (set explicitly via FORMAT or from the format of the buffer
  # |buffer_name|).
  VERTEX_DATA {buffer_name} LOCATION _val_ [ RATE { vertex | instance } (default vertex) ] \
        [ FORMAT {format} ] [ OFFSET {offset} ] [ STRIDE {stride} ]

  # Set |buffer_name| as the index data to use for `INDEXED` draw commands.
  INDEX_DATA {buffer_name}
```

#### OpenCL Plain-Old-Data Arguments
OpenCL kernels can have plain-old-data (pod or pod_ubo in the desriptor map)
arguments set their data via this command. Amber will generate the appropriate
buffers for the pipeline populated with the specified data.

```groovy
  # Set argument |name| to |data_type| with value |val|.
  SET KERNEL ARG_NAME _name_ AS {data_type} _val_

  # Set argument |number| to |data_type| with value |val|.
  # Arguments use 0-based numbering.
  SET KERNEL ARG_NUMBER _number_ AS {data_type} _val_
```

#### Topologies
 * `POINT_LIST`
 * `LINE_LIST`
 * `LINE_LIST_WITH_ADJACENCY`
 * `LINE_STRIP`
 * `LINE_STRIP_WITH_ADJACENCY`
 * `TRIANGLE_LIST`
 * `TRIANGLE_LIST_WITH_ADJACENCY`
 * `TRIANGLE_STRIP`
 * `TRIANGLE_STRIP_WITH_ADJACENCY`
 * `TRIANGLE_fan`
 * `PATCH_LIST`

### Run a pipeline.

When running a `DRAW_ARRAY` command, you must attach the vertex data to the
`PIPELINE` with the `VERTEX_DATA` command.

To run an indexed draw, attach the index data to the `PIPELINE` with an
`INDEX_DATA` command.

For the commands which take a `START_IDX` and a `COUNT` they can be left off the
command (although, `START_IDX` is required if `COUNT` is provided). The default
value for `START_IDX` is 0. The default value for `COUNT` is the item count of
vertex buffer minus the `START_IDX`. The same applies to `START_INSTANCE`
(default 0) and `INSTANCE_COUNT` (default 1).

```groovy
# Run the given |pipeline_name| which must be a `compute` pipeline. The
# pipeline will be run with the given number of workgroups in the |x|, |y|, |z|
# dimensions. Each of the x, y and z values must be a uint32.
RUN {pipeline_name} _x_ _y_ _z_
```

```groovy
# Run the given |pipeline_name| which must be a `graphics` pipeline. The
# rectangle at |x|, |y|, |width|x|height| will be rendered. Ignores VERTEX_DATA
# and INDEX_DATA on the given pipeline.
RUN {pipeline_name} \
  DRAW_RECT POS _x_in_pixels_ _y_in_pixels_ \
  SIZE _width_in_pixels_ _height_in_pixels_
```

```groovy
# Run the given |pipeline_name| which must be a `graphics` pipeline. The
# grid at |x|, |y|, |width|x|height|, |columns|x|rows| will be rendered.
# Ignores VERTEX_DATA and INDEX_DATA on the given pipeline.
# For columns, rows of (5, 4) a total of 5*4=20 rectangles will be drawn.
RUN {pipeline_name} \
  DRAW_GRID POS _x_in_pixels_ _y_in_pixels_ \
  SIZE _width_in_pixels_ _height_in_pixels_ \
  CELLS _columns_of_cells_ _rows_of_cells_
```

```groovy
# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
# data must be attached to the pipeline.

# A start index of |value| will be used and the count of |count_value| items
# will be processed. The draw is instanced if |inst_count_value| is greater
# than one. In case of instanced draw |inst_value| controls the starting
# instance ID.
RUN {pipeline_name} DRAW_ARRAY AS {topology} \
    [ START_IDX _value_ (default 0) ] \
    [ COUNT _count_value_ (default vertex_buffer size - start_idx) ] \
    [ START_INSTANCE _inst_value_ (default 0) ] \
    [ INSTANCE_COUNT _inst_count_value_ (default 1) ]
```

```groovy
# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
# data and  index data must be attached to the pipeline. The vertices will be
# drawn using the given |topology|.
#
# A start index of |value| will be used and the count of |count_value| items
# will be processed. The draw is instanced if |inst_count_value| is greater
# than one. In case of instanced draw |inst_value| controls the starting
# instance ID.
RUN {pipeline_name} DRAW_ARRAY AS {topology} INDEXED \
    [ START_IDX _value_ (default 0) ] \
    [ COUNT _count_value_ (default index_buffer size - start_idx) ] \
    [ START_INSTANCE _inst_value_ (default 0) ] \
    [ INSTANCE_COUNT _inst_count_value_ (default 1) ]
```

### Repeating commands

```groovy
# It is sometimes useful to run a given draw command multiple times. This can be
# to detect deterministic rendering or other features.
REPEAT {count}
{command}+
END
```

The commands which can be used inside a `REPEAT` block are:
  * `CLEAR`
  * `CLEAR_COLOR`
  * `CLEAR_DEPTH`
  * `CLEAR_STENCIL`
  * `COPY`
  * `EXPECT`
  * `RUN`

### Commands

```groovy
# Sets the clear color to use for |pipeline| which must be a graphics
# pipeline. The colors are integers from 0 - 255.  Defaults to (0, 0, 0, 0)
CLEAR_COLOR {pipeline} _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_ _a (0 - 255)_

# Sets the depth clear value to use for |pipeline| which must be a graphics
# pipeline. |value| must be a decimal number.
CLEAR_DEPTH {pipeline} _value_

# Sets the stencil clear value to use for |pipeline| which must be a graphics
# pipeline. |value| must be an integer from 0 - 255.
CLEAR_STENCIL {pipeline} _value_

# Instructs the |pipeline| which must be a graphics pipeline to execute the
# clear command.
CLEAR {pipeline}
```

### Expectations

#### Comparators
 * `EQ`
 * `NE`
 * `LT`
 * `LE`
 * `GT`
 * `GE`
 * `EQ_RGB`
 * `EQ_RGBA`
 * `EQ_BUFFER`
 * `RMSE_BUFFER`
 * `EQ_HISTOGRAM_EMD_BUFFER`

```groovy
# Checks that |buffer_name| at |x| has the given |value|s when compared
# with the given |comparator|.
EXPECT {buffer_name} IDX _x_ {comparator} _value_+

# Checks that |buffer_name| at |x| has values within |tolerance| of |value|
# The |tolerance| can be specified as 1-4 float values separated by spaces.
# The tolerances may be given as a percentage by placing a '%' symbol after
# the value. If less tolerance values are provided then are needed for a given
# data component the default tolerance will be applied.
EXPECT {buffer_name} IDX _x_ TOLERANCE _tolerance_{1,4} EQ _value_+

# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
# given |r|, |g|, |b| values. Each r, g, b value is an integer from 0-255.
EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \
  SIZE _width_in_pixels_ _height_in_pixels_ \
  EQ_RGB _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_

# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
# given |r|, |g|, |b|, |a| values. Each r, g, b, a value is an integer
# from 0-255.
EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \
  SIZE _width_in_pixels_ _height_in_pixels_ \
  EQ_RGBA _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_ _a (0 - 255)_

# Checks that |buffer_1| contents are equal to those of |buffer_2|
EXPECT {buffer_1} EQ_BUFFER {buffer_2}

# Checks that the Root Mean Square Error when comparing |buffer_1| to
# |buffer_2| is less than or equal to |tolerance|. Note, |tolerance| is a
# unit-less number.
EXPECT {buffer_1} RMSE_BUFFER {buffer_2} TOLERANCE _value_

# Checks that the Earth Mover's Distance when comparing histograms of
# |buffer_1| to |buffer_2| is less than or equal to |tolerance|.
# Note, |tolerance| is a unit-less number.
EXPECT {buffer_1} EQ_HISTOGRAM_EMD_BUFFER {buffer_2} TOLERANCE _value_
```

## Examples

### Compute Shader

```groovy
#!amber
# Simple amber compute shader.

SHADER compute kComputeShader GLSL
#version 450

layout(binding = 3) buffer block {
  vec2 values[];
};

void main() {
  values[gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x] =
                gl_WorkGroupID.xy;
}
END  # shader

BUFFER kComputeBuffer DATA_TYPE vec2<int32> SIZE 524288 FILL 0

PIPELINE compute kComputePipeline
  ATTACH kComputeShader
  BIND BUFFER kComputeBuffer AS storage DESCRIPTOR_SET 0 BINDING 3
END  # pipeline

RUN kComputePipeline 256 256 1

# Four corners
EXPECT kComputeBuffer IDX 0 EQ 0 0
EXPECT kComputeBuffer IDX 2040 EQ 255 0
EXPECT kComputeBuffer IDX 522240 EQ 0 255
EXPECT kComputeBuffer IDX 524280 EQ 255 255

# Center
EXPECT kComputeBuffer IDX 263168 EQ 128 128
```

### Entry Points

```groovy
#!amber

SHADER vertex kVertexShader PASSTHROUGH

SHADER fragment kFragmentShader SPIRV-ASM
              OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450

; two entrypoints
               OpEntryPoint Fragment %red "red" %color
               OpEntryPoint Fragment %green "green" %color

               OpExecutionMode %red OriginUpperLeft
               OpExecutionMode %green OriginUpperLeft
               OpSource GLSL 430
               OpName %red "red"
               OpDecorate %color Location 0
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
      %float = OpTypeFloat 32
    %v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
      %color = OpVariable %_ptr_Output_v4float Output
    %float_1 = OpConstant %float 1
    %float_0 = OpConstant %float 0
  %red_color = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
%green_color = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1

; this entrypoint outputs a red color
        %red = OpFunction %void None %3
          %5 = OpLabel
               OpStore %color %red_color
               OpReturn
               OpFunctionEnd

; this entrypoint outputs a green color
      %green = OpFunction %void None %3
          %6 = OpLabel
               OpStore %color %green_color
               OpReturn
               OpFunctionEnd
END  # shader

BUFFER kImgBuffer FORMAT R8G8B8A8_UINT

PIPELINE graphics kRedPipeline
  ATTACH kVertexShader ENTRY_POINT main
  SHADER_OPTIMIZATION kVertexShader
    --eliminate-dead-branches
    --merge-return
    --eliminate-dead-code-aggressive
  END
  ATTACH kFragmentShader ENTRY_POINT red

  FRAMEBUFFER_SIZE 256 256
  BIND BUFFER kImgBuffer AS color LOCATION 0
END  # pipeline

PIPELINE graphics kGreenPipeline
  ATTACH kVertexShader
  ATTACH kFragmentShader ENTRY_POINT green

  FRAMEBUFFER_SIZE 256 256
  BIND BUFFER kImgBuffer AS color LOCATION 0
END  # pipeline

RUN kRedPipeline DRAW_RECT POS 0 0 SIZE 256 256
RUN kGreenPipeline DRAW_RECT POS 128 128 SIZE 256 256

EXPECT kImgBuffer IDX 0 0 SIZE 127 127 EQ_RGB 255 0 0
EXPECT kImgBuffer IDX 128 128 SIZE 128 128 EQ_RGB 0 255 0
```

### Buffers

```groovy
#!amber

SHADER vertex kVertexShader GLSL
  #version 430

  layout(location = 0) in vec4 position;
  layout(location = 1) in vec4 color_in;
  layout(location = 0) out vec4 color_out;

  void main() {
    gl_Position = position;
    color_out = color_in;
  }
END  # shader

SHADER fragment kFragmentShader GLSL
  #version 430

  layout(location = 0) in vec4 color_in;
  layout(location = 0) out vec4 color_out;

  void main() {
    color_out = color_in;
  }
END  # shader

BUFFER kPosData DATA_TYPE vec2<int32> DATA
# Top-left
-1 -1  
 0 -1  
-1  0
 0  0
# Top-right
 0 -1  
 1 -1  
 0  0
 1  0
# Bottom-left
-1  0
 0  0
-1  1
 0  1
# Bottom-right
 0  0
 1  0
 0  1
 1  1
END

BUFFER kColorData DATA_TYPE uint32 DATA
# red
0xff0000ff
0xff0000ff
0xff0000ff
0xff0000ff

# green
0xff00ff00
0xff00ff00
0xff00ff00
0xff00ff00

# blue
0xffff0000
0xffff0000
0xffff0000
0xffff0000

# purple
0xff800080
0xff800080
0xff800080
0xff800080
END

BUFFER kIndices DATA_TYPE int32 DATA
0  1  2    2  1  3
4  5  6    6  5  7
8  9  10   10 9  11
12 13 14   14 13 15
END

PIPELINE graphics kGraphicsPipeline
  ATTACH kVertexShader
  ATTACH kFragmentShader

  VERTEX_DATA kPosData LOCATION 0
  VERTEX_DATA kColorData LOCATION 1
  INDEX_DATA kIndices
END  # pipeline

CLEAR_COLOR kGraphicsPipeline 255 0 0 255
CLEAR kGraphicsPipeline

RUN kGraphicsPipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 24
```

### OpenCL-C Shaders

```groovy
SHADER compute my_shader OPENCL-C
kernel void line(const int* in, global int* out, int m, int b) {
  *out = *in * m + b;
}
END

BUFFER in_buf DATA_TYPE int32 DATA 4 END
BUFFER out_buf DATA_TYPE int32 DATA 0 END

PIPELINE compute my_pipeline
  ATTACH my_shader ENTRY_POINT line
  COMPILE_OPTIONS
    -cluster-pod-kernel-args
    -pod-ubo
    -constant-args-ubo
    -max-ubo-size=128
  END
  BIND BUFFER in_buf KERNEL ARG_NAME in
  BIND BUFFER out_buf KERNEL ARG_NAME out
  SET KERNEL ARG_NAME m AS int32 3
  SET KERNEL ARG_NAME b AS int32 1
END

RUN my_pipeline 1 1 1

EXPECT out_buf EQ IDX 0 EQ 13
```

### Image Formats
  * `A1R5G5B5_UNORM_PACK16`
  * `A2B10G10R10_SINT_PACK32`
  * `A2B10G10R10_SNORM_PACK32`
  * `A2B10G10R10_SSCALED_PACK32`
  * `A2B10G10R10_UINT_PACK32`
  * `A2B10G10R10_UNORM_PACK32`
  * `A2B10G10R10_USCALED_PACK32`
  * `A2R10G10B10_SINT_PACK32`
  * `A2R10G10B10_SNORM_PACK32`
  * `A2R10G10B10_SSCALED_PACK32`
  * `A2R10G10B10_UINT_PACK32`
  * `A2R10G10B10_UNORM_PACK32`
  * `A2R10G10B10_USCALED_PACK32`
  * `A8B8G8R8_SINT_PACK32`
  * `A8B8G8R8_SNORM_PACK32`
  * `A8B8G8R8_SRGB_PACK32`
  * `A8B8G8R8_SSCALED_PACK32`
  * `A8B8G8R8_UINT_PACK32`
  * `A8B8G8R8_UNORM_PACK32`
  * `A8B8G8R8_USCALED_PACK32`
  * `B10G11R11_UFLOAT_PACK32`
  * `B4G4R4A4_UNORM_PACK16`
  * `B5G5R5A1_UNORM_PACK16`
  * `B5G6R5_UNORM_PACK16`
  * `B8G8R8A8_SINT`
  * `B8G8R8A8_SNORM`
  * `B8G8R8A8_SRGB`
  * `B8G8R8A8_SSCALED`
  * `B8G8R8A8_UINT`
  * `B8G8R8A8_UNORM`
  * `B8G8R8A8_USCALED`
  * `B8G8R8_SINT`
  * `B8G8R8_SNORM`
  * `B8G8R8_SRGB`
  * `B8G8R8_SSCALED`
  * `B8G8R8_UINT`
  * `B8G8R8_UNORM`
  * `B8G8R8_USCALED`
  * `D16_UNORM`
  * `D16_UNORM_S8_UINT`
  * `D24_UNORM_S8_UINT`
  * `D32_SFLOAT`
  * `D32_SFLOAT_S8_UINT`
  * `R16G16B16A16_SFLOAT`
  * `R16G16B16A16_SINT`
  * `R16G16B16A16_SNORM`
  * `R16G16B16A16_SSCALED`
  * `R16G16B16A16_UINT`
  * `R16G16B16A16_UNORM`
  * `R16G16B16A16_USCALED`
  * `R16G16B16_SFLOAT`
  * `R16G16B16_SINT`
  * `R16G16B16_SNORM`
  * `R16G16B16_SSCALED`
  * `R16G16B16_UINT`
  * `R16G16B16_UNORM`
  * `R16G16B16_USCALED`
  * `R16G16_SFLOAT`
  * `R16G16_SINT`
  * `R16G16_SNORM`
  * `R16G16_SSCALED`
  * `R16G16_UINT`
  * `R16G16_UNORM`
  * `R16G16_USCALED`
  * `R16_SFLOAT`
  * `R16_SINT`
  * `R16_SNORM`
  * `R16_SSCALED`
  * `R16_UINT`
  * `R16_UNORM`
  * `R16_USCALED`
  * `R32G32B32A32_SFLOAT`
  * `R32G32B32A32_SINT`
  * `R32G32B32A32_UINT`
  * `R32G32B32_SFLOAT`
  * `R32G32B32_SINT`
  * `R32G32B32_UINT`
  * `R32G32_SFLOAT`
  * `R32G32_SINT`
  * `R32G32_UINT`
  * `R32_SFLOAT`
  * `R32_SINT`
  * `R32_UINT`
  * `R4G4B4A4_UNORM_PACK16`
  * `R4G4_UNORM_PACK8`
  * `R5G5B5A1_UNORM_PACK16`
  * `R5G6B5_UNORM_PACK16`
  * `R64G64B64A64_SFLOAT`
  * `R64G64B64A64_SINT`
  * `R64G64B64A64_UINT`
  * `R64G64B64_SFLOAT`
  * `R64G64B64_SINT`
  * `R64G64B64_UINT`
  * `R64G64_SFLOAT`
  * `R64G64_SINT`
  * `R64G64_UINT`
  * `R64_SFLOAT`
  * `R64_SINT`
  * `R64_UINT`
  * `R8G8B8A8_SINT`
  * `R8G8B8A8_SNORM`
  * `R8G8B8A8_SRGB`
  * `R8G8B8A8_SSCALED`
  * `R8G8B8A8_UINT`
  * `R8G8B8A8_UNORM`
  * `R8G8B8A8_USCALED`
  * `R8G8B8_SINT`
  * `R8G8B8_SNORM`
  * `R8G8B8_SRGB`
  * `R8G8B8_SSCALED`
  * `R8G8B8_UINT`
  * `R8G8B8_UNORM`
  * `R8G8B8_USCALED`
  * `R8G8_SINT`
  * `R8G8_SNORM`
  * `R8G8_SRGB`
  * `R8G8_SSCALED`
  * `R8G8_UINT`
  * `R8G8_UNORM`
  * `R8G8_USCALED`
  * `R8_SINT`
  * `R8_SNORM`
  * `R8_SRGB`
  * `R8_SSCALED`
  * `R8_UINT`
  * `R8_UNORM`
  * `R8_USCALED`
  * `S8_UINT`
  * `X8_D24_UNORM_PACK32`