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