• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# AmberScript
2 * DRAFT
3
4This document defines the script input language for the Amber system. The format
5is based on the Talvos format, VkRunner format, and VkScript proposed format.
6
7## Specification
8All amber scripts must start with `#!amber` as the first line. Comments are
9specified by a # character and continue to the end of the line, except in
10inlined shader source code, where AmberScript comments are not
11possible. Keywords are case sensitive. All names are made up of ASCII
12characters, and delimited by whitespace.
13
14TODO(dneto): What characters are valid in a name?
15
16### Number literals
17
18Literal numbers are normally presented in decimal form.  They are interpreted
19as integers or floating point depending on context: a command parameter is
20predefined as either integral or floating point, or the data type is
21user-specified (such as for buffer data).
22
23Hex values: Whenever an integer is expected, you may use a hexadecimal number,
24which is the characters `0x` followed by hexadecimal digits.
25
26### Requesting features
27
28If specific device features are required you can use the `DEVICE_FEATURE`
29command to enable them.
30
31```groovy
32DEVICE_FEATURE vertexPipelineStoresAndAtomics
33DEVICE_FEATURE VariablePointerFeatures.variablePointersStorageBuffer
34```
35
36Currently each of the items in `VkPhysicalDeviceFeatures` are recognized along
37with:
38 * `VariablePointerFeatures.variablePointers`
39 * `VariablePointerFeatures.variablePointersStorageBuffer`
40 * `Float16Int8Features.shaderFloat16`
41 * `Float16Int8Features.shaderInt8`
42 * `Storage8BitFeatures.storageBuffer8BitAccess`
43 * `Storage8BitFeatures.uniformAndStorageBuffer8BitAccess`
44 * `Storage8BitFeatures.storagePushConstant8`
45 * `Storage16BitFeatures.storageBuffer16BitAccess`
46 * `Storage16BitFeatures.uniformAndStorageBuffer16BitAccess`
47 * `Storage16BitFeatures.storagePushConstant16`
48 * `Storage16BitFeatures.storageInputOutput16`
49 * `SubgroupSizeControl.subgroupSizeControl`
50 * `SubgroupSizeControl.computeFullSubgroups`
51 * `SubgroupSupportedOperations.basic`
52 * `SubgroupSupportedOperations.vote`
53 * `SubgroupSupportedOperations.arithmetic`
54 * `SubgroupSupportedOperations.ballot`
55 * `SubgroupSupportedOperations.shuffle`
56 * `SubgroupSupportedOperations.shuffleRelative`
57 * `SubgroupSupportedOperations.clustered`
58 * `SubgroupSupportedOperations.quad`
59 * `SubgroupSupportedStages.vertex`
60 * `SubgroupSupportedStages.tessellationControl`
61 * `SubgroupSupportedStages.tessellationEvaluation`
62 * `SubgroupSupportedStages.geometry`
63 * `SubgroupSupportedStages.fragment`
64 * `SubgroupSupportedStages.compute`
65
66
67Extensions can be enabled with the `DEVICE_EXTENSION` and `INSTANCE_EXTENSION`
68commands.
69
70```groovy
71DEVICE_EXTENSION VK_KHR_get_physical_device_properties2
72INSTANCE_EXTENSION VK_KHR_storage_buffer_storage_class
73```
74
75### Setting Engine Configuration
76
77In some instances there is extra data we want to provide to an engine for
78configuration purposes. The `SET ENGINE_DATA` command allows that for the given
79set of data types.
80
81#### Engine Data Variables
82  * `fence_timeout_ms`  - value must be a single uint32 in milliseconds.
83
84```groovy
85SET ENGINE_DATA {engine data variable} {value}*
86```
87
88### Virtual File Store
89
90Each amber script contains a virtual file system that can store files of textual
91data. This lets you bundle multiple source files into a single, hermetic amber
92script file.
93
94Virtual files are declared using the `VIRTUAL_FILE` command:
95
96```groovy
97VIRTUAL_FILE {path}
98 {file-content}
99END
100```
101
102Paths must be unique.
103
104Shaders can directly reference these virtual files for their source. \
105HLSL shaders that `#include` other `.hlsl` files will first check the virtual
106file system, before falling back to the standard file system.
107
108### Shaders
109
110Shader programs are declared using the `SHADER` command. \
111Shaders can be declared as `PASSTHROUGH`, with inlined source or using source
112from a `VIRTUAL_FILE`.
113
114Pass-through shader:
115
116```groovy
117# Creates a passthrough vertex shader. The shader passes the vec4 at input
118# location 0 through to the `gl_Position`.
119SHADER vertex {shader_name} PASSTHROUGH
120```
121
122Shader using inlined source:
123
124```groovy
125# Creates a shader of |shader_type| with the given |shader_name|. The shader
126# will be of |shader_format|. The shader source then follows and is terminated
127# with the |END| tag.
128SHADER {shader_type} {shader_name} {shader_format} [ TARGET_ENV {target_env} ]
129{shader_source}
130END
131```
132
133Shader using source from `VIRTUAL_FILE`:
134
135```groovy
136# Creates a shader of |shader_type| with the given |shader_name|. The shader
137# will be of |shader_format|. The shader will use the virtual file with |path|.
138SHADER {shader_type} {shader_name} {shader_format} [ TARGET_ENV {target_env} ] VIRTUAL_FILE {path}
139```
140
141`{shader_name}` is used to identify the shader to attach to `PIPELINE`s,
142
143`{shader_type}` and `{shader_format}` are described below:
144
145#### Shader Type
146 * `vertex`
147 * `fragment`
148 * `geometry`
149 * `tessellation_evaluation`
150 * `tessellation_control`
151 * `compute`
152 * `multi`
153
154The compute pipeline can only contain compute shaders. The graphics pipeline
155can not contain compute shaders, and must contain a vertex shader and a fragment
156shader.
157
158The provided `multi` shader can only be used with `SPIRV-ASM` and `SPIRV-HEX`
159and allows for providing multiple shaders in a single module (so the `vertex`
160and `fragment` shaders can be provided together.)
161
162Note, `SPIRV-ASM` and `SPIRV-HEX` can also be used with each of the other shader
163types, but in that case must only provide a single shader type in the module.
164
165#### Shader Format
166 * `GLSL`  (with glslang)
167 * `HLSL`  (with dxc or glslang if dxc disabled)
168 * `SPIRV-ASM` (with spirv-as; specifying `TARGET_ENV` is _highly recommended_
169    in this case, as explained below)
170 * `SPIRV-HEX` (decoded straight to SPIR-V)
171 * `OPENCL-C` (with clspv)
172
173### Target environment
174
175Specifying `TARGET_ENV` is optional and can be used to select a target
176SPIR-V environment. For example:
177
178 * `spv1.0`
179 * `spv1.5`
180 * `vulkan1.0`
181 * `vulkan1.2`
182
183Check the help text of the corresponding tool (e.g. spirv-as, glslangValidator)
184for the full list. The `SPIRV-HEX` shader format is not affected by the target
185environment.
186
187The specified target environment for the shader overrides the default (`spv1.0`)
188or the one specified on the command line.
189
190Specifying the target environment when using the `SPIRV-ASM` shader format
191is _highly recommended_, otherwise the SPIR-V version of the final SPIR-V binary
192shader passed to the graphics device might not be what you expect.
193Typically, SPIR-V assembly text will contain a comment near the beginning similar
194to `; Version: 1.0` but this is _ignored_ by the spirv-as assembler.
195Thus, you should specify the equivalent target environment (e.g. `spv1.0`)
196in the `SHADER` command.
197
198Specifying the target environment for other shader formats depends on whether
199you want to vary the final SPIR-V shader binary based on the target environment
200specified on the command line. For example, you could write one AmberScript file
201that contains a GLSL shader without specifying a target environment.
202You could then run the AmberScript file several times with different
203target environments specified on the command line
204(`spv1.0`, `spv1.1`, `spv1.2`, etc.) to test the different SPIR-V shader variants.
205
206### Buffers
207
208An AmberScript buffer represents a set of contiguous bits. This can be used for
209either image buffers or, what the target API would refer to as a buffer.
210
211#### Data Types
212 * `int8`
213 * `int16`
214 * `int32`
215 * `int64`
216 * `uint8`
217 * `uint16`
218 * `uint32`
219 * `uint64`
220 * `float16`
221 * `float`
222 * `double`
223 * vec[2,3,4]{type}
224 * mat[2,3,4]x[2,3,4]{type}  (mat<columns>x<rows>)
225 * Any of the `Image Formats` listed below.
226 * For any of the non-Image Formats types above appending '[]' will treat the
227    data as an array. e.g. int8[], vec2<float>[]
228
229Sized arrays and structures are not currently representable.
230
231```groovy
232# Filling the buffer with a given initializer. Initializer data must be
233# of |type|. Buffers are STD430 by default.
234BUFFER {name} DATA_TYPE {type} {STD140 | STD430} {initializer}
235
236# Defines a buffer which is filled with data as specified by the `initializer`.
237BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
238    {initializer}
239
240# Deprecated
241# Defines a buffer with width and height and filled by data as specified by the
242# `initializer`.
243BUFFER {name} DATA_TYPE {type} {STD140 | STD430} WIDTH {w} HEIGHT {h} \
244  {initializer}
245
246# Defines a buffer which is filled with binary data from a file specified
247# by `FILE`.
248BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
249    FILE BINARY {file_name}
250
251# Defines a buffer which is filled with text data parsed from a file specified
252# by `FILE`.
253BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
254    FILE TEXT {file_name}
255
256# Creates a buffer which will store the given `FORMAT` of data. These
257# buffers are used as image and depth buffers in the `PIPELINE` commands.
258# The buffer will be sized based on the `RENDER_SIZE` of the `PIPELINE`.
259# For multisampled images use value greater than one for `SAMPLES`. Allowed
260# sample counts are 1, 2, 4, 8, 16, 32, and 64. Note that Amber doesn't
261# preserve multisampled images across pipelines.
262BUFFER {name} FORMAT {format_string} \
263    [ MIP_LEVELS _mip_levels_ (default 1) ] \
264    [ SAMPLES _samples_ (default 1) ]
265
266# Load buffer data from a PNG image with file name specified by `FILE`.
267# The file path is relative to the script file being run. Format specified
268# by `FORMAT` must match the image format.
269BUFFER {name} FORMAT {format_string} FILE PNG {file_name.png}
270```
271
272#### Images
273
274An AmberScript image is a specialized buffer that specifies image-specific
275attributes.
276
277##### Dimensionality
278 * `DIM_1D` -- A 1-dimensional image
279 * `DIM_2D` -- A 2-dimensional image
280 * `DIM_3D` -- A 3-dimensional image
281
282```groovy
283# Specify an image buffer with a format. HEIGHT is necessary for DIM_2D and
284# DIM_3D. DEPTH is necessary for DIM_3D.
285IMAGE {name} FORMAT {format_string} [ MIP_LEVELS _mip_levels_ (default 1) ] \
286    [ SAMPLES _samples_ (default 1) ] \
287    {dimensionality} \
288    WIDTH {w} [ HEIGHT {h} [ DEPTH {d} ] ] \
289    {initializer}
290
291# Specify an image buffer with a data type. HEIGHT is necessary for DIM_2D and
292# DIM_3D. DEPTH is necessary for DIM_3D.
293IMAGE {name} DATA_TYPE {type} {dimensionality} \
294    WIDTH {w} [ HEIGHT {h} [ DEPTH {d} ] ] \
295    {intializer}
296```
297
298#### Buffer Initializers
299
300```groovy
301# Filling the buffer with a given set of data. The values must be
302# of the correct type. The data can be provided as the type or as a hex
303# value.
304DATA
305_value_+
306END
307
308```groovy
309# Fill the buffer with a single value.
310FILL _value_
311
312# Fill the buffer with an increasing value from |start| increasing by |inc|.
313# Floating point data uses floating point addition to generate increasing
314# values. Likewise, integer data uses integer addition to generate increasing
315# values.
316SERIES_FROM _start_ INC_BY _inc_
317```
318
319#### Buffer Copy
320
321```groovy
322# Copies all data, values and memory from |buffer_from| to |buffer_to|.
323# Both buffers must be declared, and of the same data type.
324# Buffers used as copy destination can be used only as copy destination, and as
325# argument to an EXPECT command.
326COPY {buffer_from} TO {buffer_to}
327```
328
329### Samplers
330
331Samplers are used for sampling buffers that are bound to a pipeline as
332sampled image or combined image sampler.
333
334#### Filter types
335 * `nearest`
336 * `linear`
337
338#### Address modes
339 * `repeat`
340 * `mirrored_repeat`
341 * `clamp_to_edge`
342 * `clamp_to_border`
343 * `mirrored_clamp_to_edge`
344
345#### Border colors
346 * `float_transparent_black`
347 * `int_transparent_black`
348 * `float_opaque_black`
349 * `int_opaque_black`
350 * `float_opaque_white`
351 * `int_opaque_white`
352
353```groovy
354
355# Creates a sampler with |name|.
356SAMPLER {name} \
357    [ MAG_FILTER {filter_type} (default nearest) ] \
358    [ MIN_FILTER {filter_type} (default nearest) ] \
359    [ ADDRESS_MODE_U {address_mode} (default repeat) ] \
360    [ ADDRESS_MODE_V {address_mode} (default repeat) ] \
361    [ ADDRESS_MODE_W {address_mode} (default repeat) ] \
362    [ BORDER_COLOR {border_color} (default float_transparent_black) ] \
363    [ MIN_LOD _val_ (default 0.0) ] \
364    [ MAX_LOD _val_ (default 1.0) ] \
365    [ NORMALIZED_COORDS | UNNORMALIZED_COORDS (default NORMALIZED_COORDS) ]
366```
367
368Note: unnormalized coordinates will override MIN\_LOD and MAX\_LOD to 0.0.
369
370#### OpenCL Literal Samplers
371
372Literal constant samplers defined in the OpenCL program are automatically
373generated and bound to the pipeline in Amber.
374
375Note: currently the border color is always transparent black.
376
377Note: the addressing mode is used for all coordinates currently. Arrayed images
378should use `clamp_to_edge` for the array index.
379
380### Pipelines
381
382#### Pipeline type
383 * `compute`
384 * `graphics`
385
386```groovy
387# The PIPELINE command creates a pipeline. This can be either compute or
388# graphics. Shaders are attached to the pipeline at pipeline creation time.
389PIPELINE {pipeline_type} {pipeline_name}
390...
391END
392
393# Create a pipeline and inherit from a previously declared pipeline.
394DERIVE_PIPELINE {pipeline_name} FROM {parent_pipeline}
395...
396END
397```
398
399### Pipeline Content
400
401The following commands are all specified within the `PIPELINE` command.
402```groovy
403  # Attach the shader provided by |name_of_shader| to the pipeline with an
404  # entry point name of |name|. The provided shader for ATTACH must _not_ be
405  # a 'multi' shader.
406  ATTACH {name_of_shader} \
407      [ ENTRY_POINT {name} (default "main") ]
408
409  # Attach a 'multi' shader to the pipeline of |shader_type| and use the entry
410  # point with |name|. The provided shader _must_ be a 'multi' shader.
411  ATTACH {name_of_multi_shader} TYPE {shader_type} ENTRY_POINT {name}
412
413  # Attach specialized shader. Specialization can be specified multiple times.
414  # Specialization values must be a 32-bit type. Shader type and entry point
415  # must be specified prior to specializing the shader.
416  ATTACH {name_of_shader} SPECIALIZE _id_ AS uint32 _value_
417  ATTACH {name_of_shader} \
418      SPECIALIZE _id_ AS uint32 _value_ \
419      SPECIALIZE _id_ AS float _value_
420```
421
422```groovy
423  # Set the SPIRV-Tools optimization passes to use for a given shader. The
424  # default is to run no optimization passes.
425  SHADER_OPTIMIZATION {shader_name}
426    {optimization_name}+
427  END
428```
429
430```groovy
431  # Set the compile options used to compile the given shader. Options are parsed
432  # the same as on the command line. Currently, only supported for OPENCL-C shaders.
433  COMPILE_OPTIONS {shader_name}
434    {option}+
435  END
436```
437
438```groovy
439  # Set the polygon mode used for all drawing with the pipeline.
440  # |mode| is fill, line, or point and it defaults to fill.
441  POLYGON_MODE {mode}
442```
443
444```groovy
445  # Set the number of patch control points used by tessellation. The default value is 3.
446  PATCH_CONTROL_POINTS {control_points}
447```
448
449#### Compare operations
450 * `never`
451 * `less`
452 * `equal`
453 * `less_or_equal`
454 * `greater`
455 * `not_equal`
456 * `greater_or_equal`
457 * `always`
458
459```groovy
460  # Set depth test settings. All enable options are specified with keywords on and off.
461  # BOUNDS and BIAS values are specified with decimal numbers. |compare_op| is selected
462  # from the list of compare operations above.
463  DEPTH
464    TEST {test_enable}
465    WRITE {write_enable}
466    COMPARE_OP {compare_op}
467    CLAMP {clamp_enable}
468    BOUNDS min {bound_min} max {bounds_max}
469    BIAS constant {bias_constant} clamp {bias_clamp} slope {bias_slope}
470  END
471```
472
473#### Stencil operations
474 * `keep`
475 * `replace`
476 * `increment_and_clamp`
477 * `decrement_and_clamp`
478 * `invert`
479 * `increment_and_wrap`
480 * `decrement_and_wrap`
481
482```groovy
483  # Set stencil test settings. |face| can be front, back, or front_and_back.
484  # |test_enable| is either on or off and affects both faces. |fail_op|, |pass_op|,
485  # and |depth_fail_op| are selected from the stencil operations table above,
486  # and |compare_op| from the compare operations table. |compare_mask|, |write_mask|,
487  # and |reference| are 8bit unsigned integer values (range 0..255).
488  STENCIL {face}
489    TEST {test_enable}
490    FAIL_OP {fail_op}
491    PASS_OP {pass_op}
492    DEPTH_FAIL_OP {depth_fail_op}
493    COMPARE_OP {compare_op}
494    COMPARE_MASK {compare_mask}
495    WRITE_MASK {write_mask}
496    REFERENCE {reference}
497  END
498```
499
500```groovy
501  # Set the size of the render buffers. |width| and |height| are integers and
502  # default to 250x250.
503  FRAMEBUFFER_SIZE _width_ _height_
504```
505
506```groovy
507  # Set the viewport size. If no viewport is provided then it defaults to the
508  # whole framebuffer size. Depth range defaults to 0 to 1.
509  VIEWPORT {x} {y} SIZE {width} {height} [MIN_DEPTH {mind}] [MAX_DEPTH {maxd}]
510```
511
512```groovy
513  # Set subgroup size control setting. Require that subgroups must be launched
514  # with all invocations active for given shader. Allow SubgroupSize to vary
515  # for given shader. Require a specific SubgroupSize the for given shader.
516  # |fully_populated_enable| and |varying_size_enable| can be on or off.
517  # |subgroup_size| can be set one of the values below:
518  #  - a power-of-two integer that _must_ be greater or equal to minSubgroupSize
519  #    and be less than or equal to maxSubgroupSize
520  # - MIN to set the required subgroup size to the minSubgroupSize
521  # - MAX to set the required subgroup size to the maxSubgroupSize
522  SUBGROUP {name_of_shader}
523    FULLY_POPULATED {fully_populated_enable}
524    VARYING_SIZE {varying_size_enable}
525    REQUIRED_SIZE {subgroup_size}
526  END
527```
528
529### Pipeline Buffers
530
531#### Buffer Types
532 * `uniform`
533 * `storage`
534 * `uniform_dynamic`
535 * `storage_dynamic`
536 * `uniform_texel_buffer`
537 * `storage_texel_buffer`
538
539TODO(dsinclair): Sync the BufferTypes with the list of Vulkan Descriptor types.
540
541A `pipeline` can have buffers or samplers bound. This includes buffers to
542contain image attachment content, depth/stencil content, uniform buffers, etc.
543
544```groovy
545  # Attach |buffer_name| as an output color attachment at location |idx|.
546  # The provided buffer must be a `FORMAT` buffer. If no color attachments are
547  # provided a single attachment with format `B8G8R8A8_UNORM` will be created
548  # for graphics pipelines. The MIP level will have a base of |level|.
549  BIND BUFFER {buffer_name} AS color LOCATION _idx_ \
550      [ BASE_MIP_LEVEL _level_ (default 0) ]
551
552  # Attach |buffer_name| as the depth/stencil buffer. The provided buffer must
553  # be a `FORMAT` buffer. If no depth/stencil buffer is specified a default
554  # buffer of format `D32_SFLOAT_S8_UINT` will be created for graphics
555  # pipelines.
556  BIND BUFFER {buffer_name} AS depth_stencil
557
558  # Attach |buffer_name| as the push_constant buffer. There can be only one
559  # push constant buffer attached to a pipeline.
560  BIND BUFFER {buffer_name} AS push_constant
561
562  # Bind OpenCL argument buffer by name. Specifying the buffer type is optional.
563  # Amber will set the type as appropriate for the argument buffer. All uses
564  # of the buffer must have a consistent |buffer_type| across all pipelines.
565  BIND BUFFER {buffer_name} [ AS {buffer_type} (default computed)] \
566      KERNEL ARG_NAME _name_
567
568  # Bind OpenCL argument buffer by argument ordinal. Arguments use 0-based
569  # numbering. Specifying the buffer type is optional. Amber will set the
570  # type as appropriate for the argument buffer. All uses of the buffer
571  # must have a consistent |buffer_type| across all pipelines.
572  BIND BUFFER {buffer_name} [ AS {buffer_type} (default computed)] \
573      KERNEL ARG_NUMBER _number_
574
575  # Bind OpenCL argument sampler by argument name.
576  BIND SAMPLER {sampler_name} KERNEL ARG_NAME _name_
577
578  # Bind OpenCL argument sampler by argument ordinal. Arguments use 0-based
579  # numbering.
580  BIND SAMPLER {sampler_name} KERNEL ARG_NUMBER _number_
581```
582
583All BIND BUFFER and BIND SAMPLER commands below define a descriptor set and binding ID.
584These commands can be replaced with BIND BUFFER_ARRAY and BIND SAMPLER_ARRAY commands.
585In these cases multiple buffer or sampler names need to be provided, separated by spaces.
586This creates a descriptor array of buffers or samplers bound to the same descriptor set
587and binding ID. An array of dynamic offsets should be provided via `OFFSET offset1 offset2 ...`
588when using dynamic buffers with BUFFER_ARRAY. Optional descriptor binding offset(s) and range(s)
589can be defined via `DESCRIPTOR_OFFSET offset1 offset2 ...` and
590`DESCRIPTOR_RANGE range1 range2 ...` when using uniform or storage buffers. Offsets and
591ranges can be used also with dynamic buffers.
592```groovy
593  # Bind the buffer of the given |buffer_type| at the given descriptor set
594  # and binding. The buffer will use a byte offset |descriptor_offset|
595  # with range |range|.
596  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS {buffer_type} DESCRIPTOR_SET _id_ \
597       BINDING _id_ [ DESCRIPTOR_OFFSET _descriptor_offset_ (default 0) ] \
598       [ DESCRIPTOR_RANGE _range_ (default -1 == VK_WHOLE_SIZE) ]
599
600  # Attach |buffer_name| as a storage image. The MIP level will have a base
601  # value of |level|.
602  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS storage_image \
603      DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ]
604
605  # Attach |buffer_name| as a sampled image.  The MIP level will have a base
606  # value of |level|.
607  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS sampled_image \
608      DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ]
609
610  # Attach |buffer_name| as a combined image sampler. A sampler |sampler_name|
611  # must also be specified. The MIP level will have a base value of 0.
612  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS combined_image_sampler SAMPLER {sampler_name} \
613      DESCRIPTOR_SET _id_ BINDING _id_ [ BASE_MIP_LEVEL _level_ (default 0) ]
614
615  # Bind the sampler at the given descriptor set and binding.
616  BIND {SAMPLER | SAMPLER_ARRAY} {sampler_name} DESCRIPTOR_SET _id_ BINDING _id_
617
618  # Bind |buffer_name| as dynamic uniform/storage buffer at the given descriptor set
619  # and binding. The buffer will use a byte offset |offset| + |descriptor_offset|
620  # with range |range|.
621  BIND {BUFFER | BUFFER_ARRAY} {buffer_name} AS {uniform_dynamic | storage_dynamic} \
622       DESCRIPTOR_SET _id_ BINDING _id_ OFFSET _offset_ \
623       [ DESCRIPTOR_OFFSET _descriptor_offset_ (default 0) ] \
624       [ DESCRIPTOR_RANGE _range_ (default -1 == VK_WHOLE_SIZE) ]
625```
626
627```groovy
628  # Set |buffer_name| as the vertex data at location |val|. RATE defines the
629  # input rate for vertex attribute reading. OFFSET sets the byte offset for the
630  # vertex data within the buffer |buffer_name|, which by default is 0. FORMAT
631  # sets the vertex buffer format, which by default is the format of the buffer
632  # |buffer_name|. STRIDE sets the byte stride, which by default is the stride
633  # of the format (set explicitly via FORMAT or from the format of the buffer
634  # |buffer_name|).
635  VERTEX_DATA {buffer_name} LOCATION _val_ [ RATE { vertex | instance } (default vertex) ] \
636        [ FORMAT {format} ] [ OFFSET {offset} ] [ STRIDE {stride} ]
637
638  # Set |buffer_name| as the index data to use for `INDEXED` draw commands.
639  INDEX_DATA {buffer_name}
640```
641
642#### OpenCL Plain-Old-Data Arguments
643OpenCL kernels can have plain-old-data (pod or pod_ubo in the desriptor map)
644arguments set their data via this command. Amber will generate the appropriate
645buffers for the pipeline populated with the specified data.
646
647```groovy
648  # Set argument |name| to |data_type| with value |val|.
649  SET KERNEL ARG_NAME _name_ AS {data_type} _val_
650
651  # Set argument |number| to |data_type| with value |val|.
652  # Arguments use 0-based numbering.
653  SET KERNEL ARG_NUMBER _number_ AS {data_type} _val_
654```
655
656#### Topologies
657 * `POINT_LIST`
658 * `LINE_LIST`
659 * `LINE_LIST_WITH_ADJACENCY`
660 * `LINE_STRIP`
661 * `LINE_STRIP_WITH_ADJACENCY`
662 * `TRIANGLE_LIST`
663 * `TRIANGLE_LIST_WITH_ADJACENCY`
664 * `TRIANGLE_STRIP`
665 * `TRIANGLE_STRIP_WITH_ADJACENCY`
666 * `TRIANGLE_fan`
667 * `PATCH_LIST`
668
669### Run a pipeline.
670
671When running a `DRAW_ARRAY` command, you must attach the vertex data to the
672`PIPELINE` with the `VERTEX_DATA` command.
673
674To run an indexed draw, attach the index data to the `PIPELINE` with an
675`INDEX_DATA` command.
676
677For the commands which take a `START_IDX` and a `COUNT` they can be left off the
678command (although, `START_IDX` is required if `COUNT` is provided). The default
679value for `START_IDX` is 0. The default value for `COUNT` is the item count of
680vertex buffer minus the `START_IDX`. The same applies to `START_INSTANCE`
681(default 0) and `INSTANCE_COUNT` (default 1).
682
683```groovy
684# Run the given |pipeline_name| which must be a `compute` pipeline. The
685# pipeline will be run with the given number of workgroups in the |x|, |y|, |z|
686# dimensions. Each of the x, y and z values must be a uint32.
687RUN {pipeline_name} _x_ _y_ _z_
688```
689
690```groovy
691# Run the given |pipeline_name| which must be a `graphics` pipeline. The
692# rectangle at |x|, |y|, |width|x|height| will be rendered. Ignores VERTEX_DATA
693# and INDEX_DATA on the given pipeline.
694RUN {pipeline_name} \
695  DRAW_RECT POS _x_in_pixels_ _y_in_pixels_ \
696  SIZE _width_in_pixels_ _height_in_pixels_
697```
698
699```groovy
700# Run the given |pipeline_name| which must be a `graphics` pipeline. The
701# grid at |x|, |y|, |width|x|height|, |columns|x|rows| will be rendered.
702# Ignores VERTEX_DATA and INDEX_DATA on the given pipeline.
703# For columns, rows of (5, 4) a total of 5*4=20 rectangles will be drawn.
704RUN {pipeline_name} \
705  DRAW_GRID POS _x_in_pixels_ _y_in_pixels_ \
706  SIZE _width_in_pixels_ _height_in_pixels_ \
707  CELLS _columns_of_cells_ _rows_of_cells_
708```
709
710```groovy
711# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
712# data must be attached to the pipeline.
713
714# A start index of |value| will be used and the count of |count_value| items
715# will be processed. The draw is instanced if |inst_count_value| is greater
716# than one. In case of instanced draw |inst_value| controls the starting
717# instance ID.
718RUN {pipeline_name} DRAW_ARRAY AS {topology} \
719    [ START_IDX _value_ (default 0) ] \
720    [ COUNT _count_value_ (default vertex_buffer size - start_idx) ] \
721    [ START_INSTANCE _inst_value_ (default 0) ] \
722    [ INSTANCE_COUNT _inst_count_value_ (default 1) ]
723```
724
725```groovy
726# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
727# data and  index data must be attached to the pipeline. The vertices will be
728# drawn using the given |topology|.
729#
730# A start index of |value| will be used and the count of |count_value| items
731# will be processed. The draw is instanced if |inst_count_value| is greater
732# than one. In case of instanced draw |inst_value| controls the starting
733# instance ID.
734RUN {pipeline_name} DRAW_ARRAY AS {topology} INDEXED \
735    [ START_IDX _value_ (default 0) ] \
736    [ COUNT _count_value_ (default index_buffer size - start_idx) ] \
737    [ START_INSTANCE _inst_value_ (default 0) ] \
738    [ INSTANCE_COUNT _inst_count_value_ (default 1) ]
739```
740
741### Repeating commands
742
743```groovy
744# It is sometimes useful to run a given draw command multiple times. This can be
745# to detect deterministic rendering or other features.
746REPEAT {count}
747{command}+
748END
749```
750
751The commands which can be used inside a `REPEAT` block are:
752  * `CLEAR`
753  * `CLEAR_COLOR`
754  * `CLEAR_DEPTH`
755  * `CLEAR_STENCIL`
756  * `COPY`
757  * `EXPECT`
758  * `RUN`
759
760### Commands
761
762```groovy
763# Sets the clear color to use for |pipeline| which must be a graphics
764# pipeline. The colors are integers from 0 - 255.  Defaults to (0, 0, 0, 0)
765CLEAR_COLOR {pipeline} _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_ _a (0 - 255)_
766
767# Sets the depth clear value to use for |pipeline| which must be a graphics
768# pipeline. |value| must be a decimal number.
769CLEAR_DEPTH {pipeline} _value_
770
771# Sets the stencil clear value to use for |pipeline| which must be a graphics
772# pipeline. |value| must be an integer from 0 - 255.
773CLEAR_STENCIL {pipeline} _value_
774
775# Instructs the |pipeline| which must be a graphics pipeline to execute the
776# clear command.
777CLEAR {pipeline}
778```
779
780### Expectations
781
782#### Comparators
783 * `EQ`
784 * `NE`
785 * `LT`
786 * `LE`
787 * `GT`
788 * `GE`
789 * `EQ_RGB`
790 * `EQ_RGBA`
791 * `EQ_BUFFER`
792 * `RMSE_BUFFER`
793 * `EQ_HISTOGRAM_EMD_BUFFER`
794
795```groovy
796# Checks that |buffer_name| at |x| has the given |value|s when compared
797# with the given |comparator|.
798EXPECT {buffer_name} IDX _x_ {comparator} _value_+
799
800# Checks that |buffer_name| at |x| has values within |tolerance| of |value|
801# The |tolerance| can be specified as 1-4 float values separated by spaces.
802# The tolerances may be given as a percentage by placing a '%' symbol after
803# the value. If less tolerance values are provided then are needed for a given
804# data component the default tolerance will be applied.
805EXPECT {buffer_name} IDX _x_ TOLERANCE _tolerance_{1,4} EQ _value_+
806
807# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
808# given |r|, |g|, |b| values. Each r, g, b value is an integer from 0-255.
809EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \
810  SIZE _width_in_pixels_ _height_in_pixels_ \
811  EQ_RGB _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_
812
813# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
814# given |r|, |g|, |b|, |a| values. Each r, g, b, a value is an integer
815# from 0-255.
816EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \
817  SIZE _width_in_pixels_ _height_in_pixels_ \
818  EQ_RGBA _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_ _a (0 - 255)_
819
820# Checks that |buffer_1| contents are equal to those of |buffer_2|
821EXPECT {buffer_1} EQ_BUFFER {buffer_2}
822
823# Checks that the Root Mean Square Error when comparing |buffer_1| to
824# |buffer_2| is less than or equal to |tolerance|. Note, |tolerance| is a
825# unit-less number.
826EXPECT {buffer_1} RMSE_BUFFER {buffer_2} TOLERANCE _value_
827
828# Checks that the Earth Mover's Distance when comparing histograms of
829# |buffer_1| to |buffer_2| is less than or equal to |tolerance|.
830# Note, |tolerance| is a unit-less number.
831EXPECT {buffer_1} EQ_HISTOGRAM_EMD_BUFFER {buffer_2} TOLERANCE _value_
832```
833
834## Examples
835
836### Compute Shader
837
838```groovy
839#!amber
840# Simple amber compute shader.
841
842SHADER compute kComputeShader GLSL
843#version 450
844
845layout(binding = 3) buffer block {
846  vec2 values[];
847};
848
849void main() {
850  values[gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x] =
851                gl_WorkGroupID.xy;
852}
853END  # shader
854
855BUFFER kComputeBuffer DATA_TYPE vec2<int32> SIZE 524288 FILL 0
856
857PIPELINE compute kComputePipeline
858  ATTACH kComputeShader
859  BIND BUFFER kComputeBuffer AS storage DESCRIPTOR_SET 0 BINDING 3
860END  # pipeline
861
862RUN kComputePipeline 256 256 1
863
864# Four corners
865EXPECT kComputeBuffer IDX 0 EQ 0 0
866EXPECT kComputeBuffer IDX 2040 EQ 255 0
867EXPECT kComputeBuffer IDX 522240 EQ 0 255
868EXPECT kComputeBuffer IDX 524280 EQ 255 255
869
870# Center
871EXPECT kComputeBuffer IDX 263168 EQ 128 128
872```
873
874### Entry Points
875
876```groovy
877#!amber
878
879SHADER vertex kVertexShader PASSTHROUGH
880
881SHADER fragment kFragmentShader SPIRV-ASM
882              OpCapability Shader
883          %1 = OpExtInstImport "GLSL.std.450"
884               OpMemoryModel Logical GLSL450
885
886; two entrypoints
887               OpEntryPoint Fragment %red "red" %color
888               OpEntryPoint Fragment %green "green" %color
889
890               OpExecutionMode %red OriginUpperLeft
891               OpExecutionMode %green OriginUpperLeft
892               OpSource GLSL 430
893               OpName %red "red"
894               OpDecorate %color Location 0
895       %void = OpTypeVoid
896          %3 = OpTypeFunction %void
897      %float = OpTypeFloat 32
898    %v4float = OpTypeVector %float 4
899%_ptr_Output_v4float = OpTypePointer Output %v4float
900      %color = OpVariable %_ptr_Output_v4float Output
901    %float_1 = OpConstant %float 1
902    %float_0 = OpConstant %float 0
903  %red_color = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
904%green_color = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
905
906; this entrypoint outputs a red color
907        %red = OpFunction %void None %3
908          %5 = OpLabel
909               OpStore %color %red_color
910               OpReturn
911               OpFunctionEnd
912
913; this entrypoint outputs a green color
914      %green = OpFunction %void None %3
915          %6 = OpLabel
916               OpStore %color %green_color
917               OpReturn
918               OpFunctionEnd
919END  # shader
920
921BUFFER kImgBuffer FORMAT R8G8B8A8_UINT
922
923PIPELINE graphics kRedPipeline
924  ATTACH kVertexShader ENTRY_POINT main
925  SHADER_OPTIMIZATION kVertexShader
926    --eliminate-dead-branches
927    --merge-return
928    --eliminate-dead-code-aggressive
929  END
930  ATTACH kFragmentShader ENTRY_POINT red
931
932  FRAMEBUFFER_SIZE 256 256
933  BIND BUFFER kImgBuffer AS color LOCATION 0
934END  # pipeline
935
936PIPELINE graphics kGreenPipeline
937  ATTACH kVertexShader
938  ATTACH kFragmentShader ENTRY_POINT green
939
940  FRAMEBUFFER_SIZE 256 256
941  BIND BUFFER kImgBuffer AS color LOCATION 0
942END  # pipeline
943
944RUN kRedPipeline DRAW_RECT POS 0 0 SIZE 256 256
945RUN kGreenPipeline DRAW_RECT POS 128 128 SIZE 256 256
946
947EXPECT kImgBuffer IDX 0 0 SIZE 127 127 EQ_RGB 255 0 0
948EXPECT kImgBuffer IDX 128 128 SIZE 128 128 EQ_RGB 0 255 0
949```
950
951### Buffers
952
953```groovy
954#!amber
955
956SHADER vertex kVertexShader GLSL
957  #version 430
958
959  layout(location = 0) in vec4 position;
960  layout(location = 1) in vec4 color_in;
961  layout(location = 0) out vec4 color_out;
962
963  void main() {
964    gl_Position = position;
965    color_out = color_in;
966  }
967END  # shader
968
969SHADER fragment kFragmentShader GLSL
970  #version 430
971
972  layout(location = 0) in vec4 color_in;
973  layout(location = 0) out vec4 color_out;
974
975  void main() {
976    color_out = color_in;
977  }
978END  # shader
979
980BUFFER kPosData DATA_TYPE vec2<int32> DATA
981# Top-left
982-1 -1  
983 0 -1  
984-1  0
985 0  0
986# Top-right
987 0 -1  
988 1 -1  
989 0  0
990 1  0
991# Bottom-left
992-1  0
993 0  0
994-1  1
995 0  1
996# Bottom-right
997 0  0
998 1  0
999 0  1
1000 1  1
1001END
1002
1003BUFFER kColorData DATA_TYPE uint32 DATA
1004# red
10050xff0000ff
10060xff0000ff
10070xff0000ff
10080xff0000ff
1009
1010# green
10110xff00ff00
10120xff00ff00
10130xff00ff00
10140xff00ff00
1015
1016# blue
10170xffff0000
10180xffff0000
10190xffff0000
10200xffff0000
1021
1022# purple
10230xff800080
10240xff800080
10250xff800080
10260xff800080
1027END
1028
1029BUFFER kIndices DATA_TYPE int32 DATA
10300  1  2    2  1  3
10314  5  6    6  5  7
10328  9  10   10 9  11
103312 13 14   14 13 15
1034END
1035
1036PIPELINE graphics kGraphicsPipeline
1037  ATTACH kVertexShader
1038  ATTACH kFragmentShader
1039
1040  VERTEX_DATA kPosData LOCATION 0
1041  VERTEX_DATA kColorData LOCATION 1
1042  INDEX_DATA kIndices
1043END  # pipeline
1044
1045CLEAR_COLOR kGraphicsPipeline 255 0 0 255
1046CLEAR kGraphicsPipeline
1047
1048RUN kGraphicsPipeline DRAW_ARRAY AS TRIANGLE_LIST START_IDX 0 COUNT 24
1049```
1050
1051### OpenCL-C Shaders
1052
1053```groovy
1054SHADER compute my_shader OPENCL-C
1055kernel void line(const int* in, global int* out, int m, int b) {
1056  *out = *in * m + b;
1057}
1058END
1059
1060BUFFER in_buf DATA_TYPE int32 DATA 4 END
1061BUFFER out_buf DATA_TYPE int32 DATA 0 END
1062
1063PIPELINE compute my_pipeline
1064  ATTACH my_shader ENTRY_POINT line
1065  COMPILE_OPTIONS
1066    -cluster-pod-kernel-args
1067    -pod-ubo
1068    -constant-args-ubo
1069    -max-ubo-size=128
1070  END
1071  BIND BUFFER in_buf KERNEL ARG_NAME in
1072  BIND BUFFER out_buf KERNEL ARG_NAME out
1073  SET KERNEL ARG_NAME m AS int32 3
1074  SET KERNEL ARG_NAME b AS int32 1
1075END
1076
1077RUN my_pipeline 1 1 1
1078
1079EXPECT out_buf EQ IDX 0 EQ 13
1080```
1081
1082### Image Formats
1083  * `A1R5G5B5_UNORM_PACK16`
1084  * `A2B10G10R10_SINT_PACK32`
1085  * `A2B10G10R10_SNORM_PACK32`
1086  * `A2B10G10R10_SSCALED_PACK32`
1087  * `A2B10G10R10_UINT_PACK32`
1088  * `A2B10G10R10_UNORM_PACK32`
1089  * `A2B10G10R10_USCALED_PACK32`
1090  * `A2R10G10B10_SINT_PACK32`
1091  * `A2R10G10B10_SNORM_PACK32`
1092  * `A2R10G10B10_SSCALED_PACK32`
1093  * `A2R10G10B10_UINT_PACK32`
1094  * `A2R10G10B10_UNORM_PACK32`
1095  * `A2R10G10B10_USCALED_PACK32`
1096  * `A8B8G8R8_SINT_PACK32`
1097  * `A8B8G8R8_SNORM_PACK32`
1098  * `A8B8G8R8_SRGB_PACK32`
1099  * `A8B8G8R8_SSCALED_PACK32`
1100  * `A8B8G8R8_UINT_PACK32`
1101  * `A8B8G8R8_UNORM_PACK32`
1102  * `A8B8G8R8_USCALED_PACK32`
1103  * `B10G11R11_UFLOAT_PACK32`
1104  * `B4G4R4A4_UNORM_PACK16`
1105  * `B5G5R5A1_UNORM_PACK16`
1106  * `B5G6R5_UNORM_PACK16`
1107  * `B8G8R8A8_SINT`
1108  * `B8G8R8A8_SNORM`
1109  * `B8G8R8A8_SRGB`
1110  * `B8G8R8A8_SSCALED`
1111  * `B8G8R8A8_UINT`
1112  * `B8G8R8A8_UNORM`
1113  * `B8G8R8A8_USCALED`
1114  * `B8G8R8_SINT`
1115  * `B8G8R8_SNORM`
1116  * `B8G8R8_SRGB`
1117  * `B8G8R8_SSCALED`
1118  * `B8G8R8_UINT`
1119  * `B8G8R8_UNORM`
1120  * `B8G8R8_USCALED`
1121  * `D16_UNORM`
1122  * `D16_UNORM_S8_UINT`
1123  * `D24_UNORM_S8_UINT`
1124  * `D32_SFLOAT`
1125  * `D32_SFLOAT_S8_UINT`
1126  * `R16G16B16A16_SFLOAT`
1127  * `R16G16B16A16_SINT`
1128  * `R16G16B16A16_SNORM`
1129  * `R16G16B16A16_SSCALED`
1130  * `R16G16B16A16_UINT`
1131  * `R16G16B16A16_UNORM`
1132  * `R16G16B16A16_USCALED`
1133  * `R16G16B16_SFLOAT`
1134  * `R16G16B16_SINT`
1135  * `R16G16B16_SNORM`
1136  * `R16G16B16_SSCALED`
1137  * `R16G16B16_UINT`
1138  * `R16G16B16_UNORM`
1139  * `R16G16B16_USCALED`
1140  * `R16G16_SFLOAT`
1141  * `R16G16_SINT`
1142  * `R16G16_SNORM`
1143  * `R16G16_SSCALED`
1144  * `R16G16_UINT`
1145  * `R16G16_UNORM`
1146  * `R16G16_USCALED`
1147  * `R16_SFLOAT`
1148  * `R16_SINT`
1149  * `R16_SNORM`
1150  * `R16_SSCALED`
1151  * `R16_UINT`
1152  * `R16_UNORM`
1153  * `R16_USCALED`
1154  * `R32G32B32A32_SFLOAT`
1155  * `R32G32B32A32_SINT`
1156  * `R32G32B32A32_UINT`
1157  * `R32G32B32_SFLOAT`
1158  * `R32G32B32_SINT`
1159  * `R32G32B32_UINT`
1160  * `R32G32_SFLOAT`
1161  * `R32G32_SINT`
1162  * `R32G32_UINT`
1163  * `R32_SFLOAT`
1164  * `R32_SINT`
1165  * `R32_UINT`
1166  * `R4G4B4A4_UNORM_PACK16`
1167  * `R4G4_UNORM_PACK8`
1168  * `R5G5B5A1_UNORM_PACK16`
1169  * `R5G6B5_UNORM_PACK16`
1170  * `R64G64B64A64_SFLOAT`
1171  * `R64G64B64A64_SINT`
1172  * `R64G64B64A64_UINT`
1173  * `R64G64B64_SFLOAT`
1174  * `R64G64B64_SINT`
1175  * `R64G64B64_UINT`
1176  * `R64G64_SFLOAT`
1177  * `R64G64_SINT`
1178  * `R64G64_UINT`
1179  * `R64_SFLOAT`
1180  * `R64_SINT`
1181  * `R64_UINT`
1182  * `R8G8B8A8_SINT`
1183  * `R8G8B8A8_SNORM`
1184  * `R8G8B8A8_SRGB`
1185  * `R8G8B8A8_SSCALED`
1186  * `R8G8B8A8_UINT`
1187  * `R8G8B8A8_UNORM`
1188  * `R8G8B8A8_USCALED`
1189  * `R8G8B8_SINT`
1190  * `R8G8B8_SNORM`
1191  * `R8G8B8_SRGB`
1192  * `R8G8B8_SSCALED`
1193  * `R8G8B8_UINT`
1194  * `R8G8B8_UNORM`
1195  * `R8G8B8_USCALED`
1196  * `R8G8_SINT`
1197  * `R8G8_SNORM`
1198  * `R8G8_SRGB`
1199  * `R8G8_SSCALED`
1200  * `R8G8_UINT`
1201  * `R8G8_UNORM`
1202  * `R8G8_USCALED`
1203  * `R8_SINT`
1204  * `R8_SNORM`
1205  * `R8_SRGB`
1206  * `R8_SSCALED`
1207  * `R8_UINT`
1208  * `R8_UNORM`
1209  * `R8_USCALED`
1210  * `S8_UINT`
1211  * `X8_D24_UNORM_PACK32`
1212