• 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 `VariablePointerFeatures.variablePointers` and
38`VariablePointerFeatures.variablePointersStorageBuffer`.
39
40Extensions can be enabled with the `DEVICE_EXTENSION` and `INSTANCE_EXTENSION`
41commands.
42
43```groovy
44DEVICE_EXTENSION VK_KHR_get_physical_device_properties2
45INSTANCE_EXTENSION VK_KHR_storage_buffer_storage_class
46```
47
48### Setting Engine Configuration
49
50In some instances there is extra data we want to provide to an engine for
51configuration purposes. The `SET ENGINE_DATA` command allows that for the given
52set of data types.
53
54#### Engine Data Variables
55  * `fence_timeout_ms`  - value must be a single uint32 in milliseconds.
56
57```groovy
58SET ENGINE_DATA {engine data variable} {value}*
59```
60
61### Shaders
62
63#### Shader Type
64 * `vertex`
65 * `fragment`
66 * `geometry`
67 * `tessellation_evaluation`
68 * `tessellation_control`
69 * `compute`
70 * `multi`
71
72The compute pipeline can only contain compute shaders. The graphics pipeline
73can not contain compute shaders, and must contain a vertex shader and a fragment
74shader.
75
76The provided `multi` shader can only be used with `SPIRV-ASM` and `SPIRV-HEX`
77and allows for providing multiple shaders in a single module (so the `vertex`
78and `fragment` shaders can be provided together.)
79
80Note, `SPIRV-ASM` and `SPIRV-HEX` can also be used with each of the other shader
81types, but in that case must only provide a single shader type in the module.
82
83#### Shader Format
84 * `GLSL`  (with glslang)
85 * `HLSL`  (with dxc or glslang if dxc disabled)  -- future
86 * `SPIRV-ASM` (with spirv-as)
87 * `SPIRV-HEX` (decoded straight to SPIR-V)
88 * `OPENCL-C` (with clspv)
89
90```groovy
91# Creates a passthrough vertex shader. The shader passes the vec4 at input
92# location 0 through to the `gl_Position`.
93SHADER vertex {shader_name} PASSTHROUGH
94
95# Creates a shader of |shader_type| with the given |shader_name|. The shader
96# will be of |shader_format|. The shader should then be inlined before the
97# |END| tag.
98SHADER {shader_type} {shader_name} {shader_format}
99...
100END
101```
102
103### Buffers
104
105An AmberScript buffer represents a set of contiguous bits. This can be used for
106either image buffers or, what the target API would refer to as a buffer.
107
108#### Data Types
109 * `int8`
110 * `int16`
111 * `int32`
112 * `int64`
113 * `uint8`
114 * `uint16`
115 * `uint32`
116 * `uint64`
117 * `float`
118 * `double`
119 * vec[2,3,4]{type}
120 * mat[2,3,4]x[2,3,4]{type}  (mat<columns>x<rows>)
121 * Any of the `Image Formats` listed below.
122
123Sized arrays and structures are not currently representable.
124
125```groovy
126# Filling the buffer with a given set of data. The values must be
127# of |type| data. The data can be provided as the type or as a hex value.
128# Buffers are STD430 by default.
129BUFFER {name} DATA_TYPE {type} {STD140 | STD430} DATA
130_value_+
131END
132
133# Defines a buffer which is filled with data as specified by the `initializer`.
134BUFFER {name} DATA_TYPE {type} {STD140 | STD430} SIZE _size_in_items_ \
135    {initializer}
136
137# Creates a buffer which will store the given `FORMAT` of data. These
138# buffers are used as image and depth buffers in the `PIPELINE` commands.
139# The buffer will be sized based on the `RENDER_SIZE` of the `PIPELINE`.
140BUFFER {name} FORMAT {format_string}
141```
142
143#### Buffer Initializers
144
145```groovy
146# Fill the buffer with a single value.
147FILL _value_
148
149# Fill the buffer with an increasing value from |start| increasing by |inc|.
150# Floating point data uses floating point addition to generate increasing
151# values. Likewise, integer data uses integer addition to generate increasing
152# values.
153SERIES_FROM _start_ INC_BY _inc_
154```
155
156#### Buffer Copy
157
158```groovy
159# Copies all data, values and memory from |buffer_from| to |buffer_to|.
160# Both buffers must be declared, and of the same data type.
161# Buffers used as copy destination can be used only as copy destination, and as
162# argument to an EXPECT command.
163COPY {buffer_from} TO {buffer_to}
164```
165
166### Pipelines
167
168#### Pipeline type
169 * `compute`
170 * `graphics`
171
172```groovy
173# The PIPELINE command creates a pipeline. This can be either compute or
174# graphics. Shaders are attached to the pipeline at pipeline creation time.
175PIPELINE {pipeline_type} {pipeline_name}
176...
177END
178
179# Create a pipeline and inherit from a previously declared pipeline.
180DERIVE_PIPELINE {pipeline_name} FROM {parent_pipeline}
181...
182END
183```
184
185### Pipeline Content
186
187The following commands are all specified within the `PIPELINE` command.
188```groovy
189  # Attach the shader provided by |name_of_shader| to the pipeline and set
190  # the entry point to be |name|. The provided shader for ATTACH must _not_ be
191  # a 'multi' shader.
192  ATTACH {name_of_shader} ENTRY_POINT {name}
193
194  # Attach the shader provided by |name_of_shader| to the pipeline and set
195  # the entry point to be 'main'. The provided shader for ATTACH must _not_ be
196  # a 'multi' shader.
197  ATTACH {name_of_shader}
198
199  # Attach a 'multi' shader to the pipeline of |shader_type| and use the entry
200  # point with |name|. The provided shader _must_ be a 'multi' shader.
201  ATTACH {name_of_multi_shader} TYPE {shader_type} ENTRY_POINT {name}
202
203  # Attach specialized shader. Specialization can be specified multiple times.
204  # Specialization values must be a 32-bit type. Shader type and entry point
205  # must be specified prior to specializing the shader.
206  ATTACH {name_of_shader} SPECIALIZE 1 AS uint32 4
207  ATTACH {name_of_shader} SPECIALIZE 1 AS uint32 4 SPECIALIZE 4 AS float 1.0
208```
209
210```groovy
211  # Set the SPIRV-Tools optimization passes to use for a given shader. The
212  # default is to run no optimization passes.
213  SHADER_OPTIMIZATION {shader_name}
214    {optimization_name}+
215  END
216```
217
218```groovy
219  # Set the compile options used to compile the given shader. Options are parsed
220  # the same as on the command line. Currently, only supported for OPENCL-C shaders.
221  COMPILE_OPTIONS {shader_name}
222    {option}+
223  END
224```
225
226```groovy
227  # Set the size of the render buffers. |width| and |height| are integers and
228  # default to 250x250.
229  FRAMEBUFFER_SIZE _width_ _height_
230```
231
232### Pipeline Buffers
233
234#### Buffer Types
235 * `uniform`
236 * `storage`
237
238TODO(dsinclair): Sync the BufferTypes with the list of Vulkan Descriptor types.
239
240A `pipeline` can have buffers bound. This includes buffers to contain image
241attachment content, depth/stencil content, uniform buffers, etc.
242
243```groovy
244  # Attach |buffer_name| as an output color attachment at location |idx|.
245  # The provided buffer must be a `FORMAT` buffer. If no color attachments are
246  # provided a single attachment with format `B8G8R8A8_UNORM` will be created
247  # for graphics pipelines.
248  BIND BUFFER {buffer_name} AS color LOCATION _idx_
249
250  # Attach |buffer_name| as the depth/stencil buffer. The provided buffer must
251  # be a `FORMAT` buffer. If no depth/stencil buffer is specified a default
252  # buffer of format `D32_SFLOAT_S8_UINT` will be created for graphics
253  # pipelines.
254  BIND BUFFER {buffer_name} AS depth_stencil
255
256  # Attach |buffer_name| as the push_constant buffer. There can be only one
257  # push constant buffer attached to a pipeline.
258  BIND BUFFER <buffer_name> AS push_constant
259
260  # Bind the buffer of the given |buffer_type| at the given descriptor set
261  # and binding. The buffer will use a start index of 0.
262  BIND BUFFER {buffer_name} AS {buffer_type} DESCRIPTOR_SET _id_ \
263       BINDING _id_
264
265  # Bind the sampler at the given descriptor set and binding.
266  BIND SAMPLER {sampler_name} DESCRIPTOR_SET _id_ BINDING _id_
267
268  # Bind OpenCL argument buffer by name. Specifying the buffer type is optional.
269  # Amber will set the type as appropriate for the argument buffer. All uses
270  # of the buffer must have a consistent |buffer_type| across all pipelines.
271  BIND BUFFER {buffer_name} [AS {buffer_type}] KERNEL ARG_NAME _name_
272
273  # Bind OpenCL argument buffer by argument ordinal. Arguments use 0-based
274  # numbering. Specifying the buffer type is optional. Amber will set the
275  # type as appropriate for the argument buffer. All uses of the buffer
276  # must have a consistent |buffer_type| across all pipelines.
277  BIND BUFFER {buffer_name} [AS {buffer_type}] KERNEL ARG_NUMBER _number_
278```
279
280```groovy
281  # Set |buffer_name| as the vertex data at location |val|.
282  VERTEX_DATA {buffer_name} LOCATION _val_
283
284  # Set |buffer_name| as the index data to use for `INDEXED` draw commands.
285  INDEX_DATA {buffer_name}
286```
287
288#### OpenCL Plain-Old-Data Arguments
289OpenCL kernels can have plain-old-data (pod or pod_ubo in the desriptor map)
290arguments set their data via this command. Amber will generate the appropriate
291buffers for the pipeline populated with the specified data.
292
293```groovy
294  # Set argument |name| to |data_type| with value |val|.
295  SET KERNEL ARG_NAME _name_ AS {data_type} _val_
296
297  # Set argument |number| to |data_type| with value |val|.
298  # Arguments use 0-based numbering.
299  SET KERNEL ARG_NUMBER _number_ AS {data_type} _val_
300```
301
302#### Topologies
303 * `point_list`
304 * `line_list`
305 * `line_list_with_adjacency`
306 * `line_strip`
307 * `line_strip_with_adjacency`
308 * `triangle_list`
309 * `triangle_list_with_adjacency`
310 * `triangle_strip`
311 * `triangle_strip_with_adjacency`
312 * `triangle_fan`
313 * `patch_list`
314
315### Run a pipeline.
316
317When running a `DRAW_ARRAY` command, you must attach the vertex data to the
318`PIPELINE` with the `VERTEX_DATA` command.
319
320To run an indexed draw, attach the index data to the `PIPELINE` with an
321`INDEX_DATA` command.
322
323For the commands which take a `START_IDX` and a `COUNT` they can be left off the
324command (although, `START_IDX` is required if `COUNT` is provided). The default
325value for `START_IDX` is 0. The default value for `COUNT` is the item count of
326vertex buffer minus the `START_IDX`.
327
328```groovy
329# Run the given |pipeline_name| which must be a `compute` pipeline. The
330# pipeline will be run with the given number of workgroups in the |x|, |y|, |z|
331# dimensions. Each of the x, y and z values must be a uint32.
332RUN {pipeline_name} _x_ _y_ _z_
333
334# Run the given |pipeline_name| which must be a `graphics` pipeline. The
335# rectangle at |x|, |y|, |width|x|height| will be rendered. Ignores VERTEX_DATA
336# and INDEX_DATA on the given pipeline.
337RUN {pipeline_name} \
338  DRAW_RECT POS _x_in_pixels_ _y_in_pixels_ \
339  SIZE _width_in_pixels_ _height_in_pixels_
340```
341
342```groovy
343# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
344# data must be attached to the pipeline. A start index of 0 will be used
345# and a count of the number of elements in the vertex buffer.
346RUN {pipeline_name} DRAW_ARRAY AS {topology}
347
348# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
349# data must be attached to the pipeline. A start index of |value| will be used
350# and a count of the number of items from |value| to the end of the vertex
351# buffer.
352RUN {pipeline_name} DRAW_ARRAY AS {topology} START_IDX _value_
353
354# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
355# data must be attached to the pipeline. A start index of |value| will be used
356# and a count |count_value| will be used.
357RUN {pipeline_name} DRAW_ARRAY AS {topology} START_IDX _value_ \
358  COUNT _count_value_
359```
360
361```groovy
362# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
363# data and  index data must be attached to the pipeline. The vertices will be
364# drawn using the given |topology|. A start index of 0 will be used and the
365# count will be determined by the size of the index data buffer.
366RUN {pipeline_name} DRAW_ARRAY AS {topology} INDEXED
367
368# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
369# data and  index data must be attached to the pipeline. The vertices will be
370# drawn using the given |topology|. A start index of |value| will be used and
371# the count will be determined by the size of the index data buffer.
372RUN {pipeline_name} DRAW_ARRAY AS {topology} INDEXED START_IDX _value_
373
374# Run the |pipeline_name| which must be a `graphics` pipeline. The vertex
375# data and  index data must be attached to the pipeline. The vertices will be
376# drawn using the given |topology|. A start index of |value| will be used and
377# the count of |count_value| items will be processed.
378RUN {pipeline_name} DRAW_ARRAY AS {topology} INDEXED \
379  START_IDX _value_ COUNT _count_value_
380```
381
382### Repeating commands
383
384```groovy
385# It is sometimes useful to run a given draw command multiple times. This can be
386# to detect deterministic rendering or other features.
387REPEAT {count}
388{command}+
389END
390```
391
392The commands which can be used inside a `REPEAT` block are:
393  * `CLEAR`
394  * `CLEAR_COLOR`
395  * `COPY`
396  * `EXPECT`
397  * `RUN`
398
399### Commands
400
401```groovy
402# Sets the clear color to use for |pipeline| which must be a graphics
403# pipeline. The colors are integers from 0 - 255.
404CLEAR_COLOR {pipeline} _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_ _a (0 - 255)_
405
406# Instructs the |pipeline| which must be a graphics pipeline to execute the
407# clear command.
408CLEAR {pipeline}
409```
410
411### Expectations
412
413#### Comparators
414 * `EQ`
415 * `NE`
416 * `LT`
417 * `LE`
418 * `GT`
419 * `GE`
420 * `EQ_RGB`
421 * `EQ_RGBA`
422 * `EQ_BUFFER`
423 * `RMSE_BUFFER`
424 * `EQ_HISTOGRAM_EMD_BUFFER`
425
426```groovy
427# Checks that |buffer_name| at |x| has the given |value|s when compared
428# with the given |comparator|.
429EXPECT {buffer_name} IDX _x_ {comparator} _value_+
430
431# Checks that |buffer_name| at |x| has values within |tolerance| of |value|
432# The |tolerance| can be specified as 1-4 float values separated by spaces.
433# The tolerances may be given as a percentage by placing a '%' symbol after
434# the value. If less tolerance values are provided then are needed for a given
435# data component the default tolerance will be applied.
436EXPECT {buffer_name} IDX _x_ TOLERANCE _tolerance_{1,4} EQ _value_+
437
438# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
439# given |r|, |g|, |b| values. Each r, g, b value is an integer from 0-255.
440EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \
441  SIZE _width_in_pixels_ _height_in_pixels_ \
442  EQ_RGB _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_
443
444# Checks that |buffer_name| at |x|, |y| for |width|x|height| pixels has the
445# given |r|, |g|, |b|, |a| values. Each r, g, b, a value is an integer
446# from 0-255.
447EXPECT {buffer_name} IDX _x_in_pixels_ _y_in_pixels_ \
448  SIZE _width_in_pixels_ _height_in_pixels_ \
449  EQ_RGBA _r (0 - 255)_ _g (0 - 255)_ _b (0 - 255)_ _a (0 - 255)_
450
451# Checks that |buffer_1| contents are equal to those of |buffer_2|
452EXPECT {buffer_1} EQ_BUFFER {buffer_2}
453
454# Checks that the Root Mean Square Error when comparing |buffer_1| to
455# |buffer_2| is less than or equal to |tolerance|. Note, |tolerance| is a
456# unit-less number.
457EXPECT {buffer_1} RMSE_BUFFER {buffer_2} TOLERANCE _value_
458
459# Checks that the Earth Mover's Distance when comparing histograms of
460# |buffer_1| to |buffer_2| is less than or equal to |tolerance|.
461# Note, |tolerance| is a unit-less number.
462EXPECT {buffer_1} EQ_HISTOGRAM_EMD_BUFFER {buffer_2} TOLERANCE _value_
463```
464
465## Examples
466
467### Compute Shader
468
469```groovy
470#!amber
471# Simple amber compute shader.
472
473SHADER compute kComputeShader GLSL
474#version 450
475
476layout(binding = 3) buffer block {
477  vec2 values[];
478};
479
480void main() {
481  values[gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x] =
482                gl_WorkGroupID.xy;
483}
484END  # shader
485
486BUFFER kComputeBuffer DATA_TYPE vec2<int32> SIZE 524288 FILL 0
487
488PIPELINE compute kComputePipeline
489  ATTACH kComputeShader
490  BIND BUFFER kComputeBuffer AS storage DESCRIPTOR_SET 0 BINDING 3
491END  # pipeline
492
493RUN kComputePipeline 256 256 1
494
495# Four corners
496EXPECT kComputeBuffer IDX 0 EQ 0 0
497EXPECT kComputeBuffer IDX 2040 EQ 255 0
498EXPECT kComputeBuffer IDX 522240 EQ 0 255
499EXPECT kComputeBuffer IDX 524280 EQ 255 255
500
501# Center
502EXPECT kComputeBuffer IDX 263168 EQ 128 128
503```
504
505### Entry Points
506
507```groovy
508#!amber
509
510SHADER vertex kVertexShader PASSTHROUGH
511
512SHADER fragment kFragmentShader SPIRV-ASM
513              OpCapability Shader
514          %1 = OpExtInstImport "GLSL.std.450"
515               OpMemoryModel Logical GLSL450
516
517; two entrypoints
518               OpEntryPoint Fragment %red "red" %color
519               OpEntryPoint Fragment %green "green" %color
520
521               OpExecutionMode %red OriginUpperLeft
522               OpExecutionMode %green OriginUpperLeft
523               OpSource GLSL 430
524               OpName %red "red"
525               OpDecorate %color Location 0
526       %void = OpTypeVoid
527          %3 = OpTypeFunction %void
528      %float = OpTypeFloat 32
529    %v4float = OpTypeVector %float 4
530%_ptr_Output_v4float = OpTypePointer Output %v4float
531      %color = OpVariable %_ptr_Output_v4float Output
532    %float_1 = OpConstant %float 1
533    %float_0 = OpConstant %float 0
534  %red_color = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
535%green_color = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1
536
537; this entrypoint outputs a red color
538        %red = OpFunction %void None %3
539          %5 = OpLabel
540               OpStore %color %red_color
541               OpReturn
542               OpFunctionEnd
543
544; this entrypoint outputs a green color
545      %green = OpFunction %void None %3
546          %6 = OpLabel
547               OpStore %color %green_color
548               OpReturn
549               OpFunctionEnd
550END  # shader
551
552BUFFER kImgBuffer FORMAT R8G8B8A8_UINT
553
554PIPELINE graphics kRedPipeline
555  ATTACH kVertexShader ENTRY_POINT main
556  SHADER_OPTIMIZATION kVertexShader
557    --eliminate-dead-branches
558    --merge-return
559    --eliminate-dead-code-aggressive
560  END
561  ATTACH kFragmentShader ENTRY_POINT red
562
563  FRAMEBUFFER_SIZE 256 256
564  BIND BUFFER kImgBuffer AS color LOCATION 0
565END  # pipeline
566
567PIPELINE graphics kGreenPipeline
568  ATTACH kVertexShader
569  ATTACH kFragmentShader ENTRY_POINT green
570
571  FRAMEBUFFER_SIZE 256 256
572  BIND BUFFER kImgBuffer AS color LOCATION 0
573END  # pipeline
574
575RUN kRedPipeline DRAW_RECT POS 0 0 SIZE 256 256
576RUN kGreenPipeline DRAW_RECT POS 128 128 SIZE 256 256
577
578EXPECT kImgBuffer IDX 0 0 SIZE 127 127 EQ_RGB 255 0 0
579EXPECT kImgBuffer IDX 128 128 SIZE 128 128 EQ_RGB 0 255 0
580```
581
582### Buffers
583
584```groovy
585#!amber
586
587SHADER vertex kVertexShader GLSL
588  #version 430
589
590  layout(location = 0) in vec4 position;
591  layout(location = 1) in vec4 color_in;
592  layout(location = 0) out vec4 color_out;
593
594  void main() {
595    gl_Position = position;
596    color_out = color_in;
597  }
598END  # shader
599
600SHADER fragment kFragmentShader GLSL
601  #version 430
602
603  layout(location = 0) in vec4 color_in;
604  layout(location = 0) out vec4 color_out;
605
606  void main() {
607    color_out = color_in;
608  }
609END  # shader
610
611BUFFER kPosData DATA_TYPE vec2<int32> DATA
612# Top-left
613-1 -1  
614 0 -1  
615-1  0
616 0  0
617# Top-right
618 0 -1  
619 1 -1  
620 0  0
621 1  0
622# Bottom-left
623-1  0
624 0  0
625-1  1
626 0  1
627# Bottom-right
628 0  0
629 1  0
630 0  1
631 1  1
632END
633
634BUFFER kColorData DATA_TYPE uint32 DATA
635# red
6360xff0000ff
6370xff0000ff
6380xff0000ff
6390xff0000ff
640
641# green
6420xff00ff00
6430xff00ff00
6440xff00ff00
6450xff00ff00
646
647# blue
6480xffff0000
6490xffff0000
6500xffff0000
6510xffff0000
652
653# purple
6540xff800080
6550xff800080
6560xff800080
6570xff800080
658END
659
660BUFFER kIndices DATA_TYPE int32 DATA
6610  1  2    2  1  3
6624  5  6    6  5  7
6638  9  10   10 9  11
66412 13 14   14 13 15
665END
666
667PIPELINE graphics kGraphicsPipeline
668  ATTACH kVertexShader
669  ATTACH kFragmentShader
670
671  VERTEX_DATA kPosData LOCATION 0
672  VERTEX_DATA kColorData LOCATION 1
673  INDEX_DATA kIndices
674END  # pipeline
675
676CLEAR_COLOR kGraphicsPipeline 255 0 0 255
677CLEAR kGraphicsPipeline
678
679RUN kGraphicsPipeline DRAW_ARRAY AS triangle_list START_IDX 0 COUNT 24
680```
681
682### OpenCL-C Shaders
683
684```groovy
685SHADER compute my_shader OPENCL-C
686kernel void line(const int* in, global int* out, int m, int b) {
687  *out = *in * m + b;
688}
689END
690
691BUFFER in_buf DATA_TYPE int32 DATA 4 END
692BUFFER out_buf DATA_TYPE int32 DATA 0 END
693
694PIPELINE compute my_pipeline
695  ATTACH my_shader ENTRY_POINT line
696  COMPILE_OPTIONS
697    -cluster-pod-kernel-args
698    -pod-ubo
699    -constant-args-ubo
700    -max-ubo-size=128
701  END
702  BIND BUFFER in_buf KERNEL ARG_NAME in
703  BIND BUFFER out_buf KERNEL ARG_NAME out
704  SET KERNEL ARG_NAME m AS int32 3
705  SET KERNEL ARG_NAME b AS int32 1
706END
707
708RUN my_pipeline 1 1 1
709
710EXPECT out_buf EQ IDX 0 EQ 13
711```
712
713### Image Formats
714  * `A1R5G5B5_UNORM_PACK16`
715  * `A2B10G10R10_SINT_PACK32`
716  * `A2B10G10R10_SNORM_PACK32`
717  * `A2B10G10R10_SSCALED_PACK32`
718  * `A2B10G10R10_UINT_PACK32`
719  * `A2B10G10R10_UNORM_PACK32`
720  * `A2B10G10R10_USCALED_PACK32`
721  * `A2R10G10B10_SINT_PACK32`
722  * `A2R10G10B10_SNORM_PACK32`
723  * `A2R10G10B10_SSCALED_PACK32`
724  * `A2R10G10B10_UINT_PACK32`
725  * `A2R10G10B10_UNORM_PACK32`
726  * `A2R10G10B10_USCALED_PACK32`
727  * `A8B8G8R8_SINT_PACK32`
728  * `A8B8G8R8_SNORM_PACK32`
729  * `A8B8G8R8_SRGB_PACK32`
730  * `A8B8G8R8_SSCALED_PACK32`
731  * `A8B8G8R8_UINT_PACK32`
732  * `A8B8G8R8_UNORM_PACK32`
733  * `A8B8G8R8_USCALED_PACK32`
734  * `B10G11R11_UFLOAT_PACK32`
735  * `B4G4R4A4_UNORM_PACK16`
736  * `B5G5R5A1_UNORM_PACK16`
737  * `B5G6R5_UNORM_PACK16`
738  * `B8G8R8A8_SINT`
739  * `B8G8R8A8_SNORM`
740  * `B8G8R8A8_SRGB`
741  * `B8G8R8A8_SSCALED`
742  * `B8G8R8A8_UINT`
743  * `B8G8R8A8_UNORM`
744  * `B8G8R8A8_USCALED`
745  * `B8G8R8_SINT`
746  * `B8G8R8_SNORM`
747  * `B8G8R8_SRGB`
748  * `B8G8R8_SSCALED`
749  * `B8G8R8_UINT`
750  * `B8G8R8_UNORM`
751  * `B8G8R8_USCALED`
752  * `D16_UNORM`
753  * `D16_UNORM_S8_UINT`
754  * `D24_UNORM_S8_UINT`
755  * `D32_SFLOAT`
756  * `D32_SFLOAT_S8_UINT`
757  * `R16G16B16A16_SFLOAT`
758  * `R16G16B16A16_SINT`
759  * `R16G16B16A16_SNORM`
760  * `R16G16B16A16_SSCALED`
761  * `R16G16B16A16_UINT`
762  * `R16G16B16A16_UNORM`
763  * `R16G16B16A16_USCALED`
764  * `R16G16B16_SFLOAT`
765  * `R16G16B16_SINT`
766  * `R16G16B16_SNORM`
767  * `R16G16B16_SSCALED`
768  * `R16G16B16_UINT`
769  * `R16G16B16_UNORM`
770  * `R16G16B16_USCALED`
771  * `R16G16_SFLOAT`
772  * `R16G16_SINT`
773  * `R16G16_SNORM`
774  * `R16G16_SSCALED`
775  * `R16G16_UINT`
776  * `R16G16_UNORM`
777  * `R16G16_USCALED`
778  * `R16_SFLOAT`
779  * `R16_SINT`
780  * `R16_SNORM`
781  * `R16_SSCALED`
782  * `R16_UINT`
783  * `R16_UNORM`
784  * `R16_USCALED`
785  * `R32G32B32A32_SFLOAT`
786  * `R32G32B32A32_SINT`
787  * `R32G32B32A32_UINT`
788  * `R32G32B32_SFLOAT`
789  * `R32G32B32_SINT`
790  * `R32G32B32_UINT`
791  * `R32G32_SFLOAT`
792  * `R32G32_SINT`
793  * `R32G32_UINT`
794  * `R32_SFLOAT`
795  * `R32_SINT`
796  * `R32_UINT`
797  * `R4G4B4A4_UNORM_PACK16`
798  * `R4G4_UNORM_PACK8`
799  * `R5G5B5A1_UNORM_PACK16`
800  * `R5G6B5_UNORM_PACK16`
801  * `R64G64B64A64_SFLOAT`
802  * `R64G64B64A64_SINT`
803  * `R64G64B64A64_UINT`
804  * `R64G64B64_SFLOAT`
805  * `R64G64B64_SINT`
806  * `R64G64B64_UINT`
807  * `R64G64_SFLOAT`
808  * `R64G64_SINT`
809  * `R64G64_UINT`
810  * `R64_SFLOAT`
811  * `R64_SINT`
812  * `R64_UINT`
813  * `R8G8B8A8_SINT`
814  * `R8G8B8A8_SNORM`
815  * `R8G8B8A8_SRGB`
816  * `R8G8B8A8_SSCALED`
817  * `R8G8B8A8_UINT`
818  * `R8G8B8A8_UNORM`
819  * `R8G8B8A8_USCALED`
820  * `R8G8B8_SINT`
821  * `R8G8B8_SNORM`
822  * `R8G8B8_SRGB`
823  * `R8G8B8_SSCALED`
824  * `R8G8B8_UINT`
825  * `R8G8B8_UNORM`
826  * `R8G8B8_USCALED`
827  * `R8G8_SINT`
828  * `R8G8_SNORM`
829  * `R8G8_SRGB`
830  * `R8G8_SSCALED`
831  * `R8G8_UINT`
832  * `R8G8_UNORM`
833  * `R8G8_USCALED`
834  * `R8_SINT`
835  * `R8_SNORM`
836  * `R8_SRGB`
837  * `R8_SSCALED`
838  * `R8_UINT`
839  * `R8_UNORM`
840  * `R8_USCALED`
841  * `S8_UINT`
842  * `X8_D24_UNORM_PACK32`
843