• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Amber
2
3Amber is a multi-API shader test framework. Graphics and compute bugs can be
4captured and communicated through a scripting interface. This removes the need
5to program to the low level interface when reproducing bugs.
6
7Amber is broken into multiple layers: the applications, the parsing components
8and the script execution.
9
10## Applications
11There are currently two applications, the `[amber](../samples/amber.cc)`
12application and the Amber integration into the
13[Vulkan Conformance Test Suite 'CTS'](https://github.com/KhronosGroup/VK-GL-CTS/tree/master/external/vulkancts/modules/vulkan/amber). These applications are responsible
14for configuring the script execution environment (setting up Vulkan, Dawn or
15another engine), calling into the parsing code to generate a test script and
16then passing that script into the script execution component.
17
18We require the application to configure the execution engine. This allows the
19application to handle loading function pointers, doing configuration and other
20setups as required. There are no hardcoded assumptions in Amber as to how you're
21setting up the API to be tested.
22
23This engine configuration is done through the `VulkanEngineConfig` in
24`amber/amber_vulkan.h` or the `DawnEngineConfig` in `amber/amber_dawn.h`.
25
26The sample application does this configuration through the config_helper
27classes. `samples/config_helper_vulkan.*` and `samples/config_helper_dawn.*`.
28For the CTS, the Vulkan engine is already configured and we just set the
29`VulkanEngineConfig` as needed.
30
31Accessing Amber itself is done through the `Amber` class in `amber/amber.h`. We
32require the application to parse and execute a script as two separate steps.
33This separation allows for the shaders to be retrieved after a parse command
34and then pre-compiled and passed into the execution. Passing the compiled
35shaders is optional.
36
37### Delegate
38A delegate object can be provided to Amber, for observing internal operations as
39the script is executed. The delegate can be a null pointer, to indicate no
40observations are requested.
41
42If the delegate is provided and the `LogGraphicsCalls` method returns
43`true` then the Vulkan API wrappers will call `Log` for each call into Vulkan.
44If the `LogGraphicsCallsTime` also returns `true` then timings for those
45Vulkan calls will also be recorded. The timestamps are retrieved from the
46`GetTimestampNS` callback.
47
48### Buffer Extractions
49Amber can be instructed to retrieve the contents of buffers when execution is
50complete. This is done through the `extractions` list in the Amber `Options`
51structure. You must set the `buffer_name` for each of the buffers you want to
52extract. When Amber completes it will fill out the `width`, `height` and set
53of `Value` objects for that buffer.
54
55### Execution
56There are two methods to execute a parsed script: `Execute` and
57`ExecuteWithShaderData`. They both accept the `Recipe` and `Options`, the
58`ExecuteWithShaderData` also accepts a map of shader name to data. The data
59is the compiled SPIR-V binary for the shader. This allows you to compile and
60cache the shader if needed.
61
62## Parsing component
63Amber can use scripts written in two dialects:
64[AmberScript](amber_script.md), and [VkScript](vk_script.md). The `AmberScript`
65parser will be used if the first 7 characters of the script are
66`#!amber`, otherwise the `VkScript` parser will be used. The parsers both
67generate a `Script` which is our representation of the script file.
68
69### AmberScript
70The AmberScript format maps closely to the format stored in the script objects.
71As such, there is a single Parser class for AmberScript which produces all of
72the needed script components.
73
74### VkScript
75For VkScript we do a bit of work to make the script match AmberScript. A default
76pipeline is generated and all content in the script is considered part of the
77generated pipeline. We generate names for all of the buffers in the file. The
78framebuffer is named `framebuffer`. The generated depth buffer is named
79`depth_buffer`. For other buffers, we generate a name of `AutoBuf-<num>` where
80the number is the current number of buffers seen counting from 0.
81
82The VkScript parser is broken into three major chunks. The `Parser`,
83`SectionParser` and `CommandParser`. The `Parser` is the overall driver for the
84parser. The `SectionParser` breaks the input file into the overall chunks (each
85of the sections separated by the \[blocks]). The `CommandParser` parses the
86`[test]` section specifically. For other sections they're parsed directly in
87the `Parser` object.
88
89### Parsed Representation
90The `Script` object owns all of the pipelines, buffers, shaders, and command
91objects. Other objects hold pointers but the script holds the `unique_ptr` for
92these objects.
93
94```
95                                        +--------+                 +--------------+
96                                        | Script |---------------->| Requirements |
97                                        +--------+                 +--------------+
98                                             |
99             +------------------+------------+--------+----------------------+
100             |                  |                     |                      |
101             v                  v                     v                      v
102      +---------+          +---------+        +---------+            +---------+
103      |  +--------+        |  +---------+     |  +----------+        |  +---------+
104      +--|  +--------+     +--|  +--------+   +--|  +----------+     +--|  +---------+
105         +--| Shader |        +--| Buffer |      +--| Pipeline |        +--| Command |
106            +--------+           +--------+         +----------+           +---------+
107               ^                  ^  ^                 |  |  ^               |    |
108               |                  |  |                 |  |  +---------------+    |
109Entry point    |                  |  +-----------------+  |                       |
110Optimizations  |                  |  Descriptor Set       |                       |
111Type           |                  |  Binding              |                       |
112Compiled Shader|                  |  Attachment Location  |                       |
113               |                  |                       |                       |
114               +------------------------------------------+                       |
115                                  |                                               |
116                                  +-----------------------------------------------+
117                                                        BufferCommand
118```
119
120A `Script` contains shaders, pipelines, buffers, and commands. Pipelines
121contain shaders and buffers. An Amber buffer corresponds to either a buffer
122resource or an image resource in the backend engine's API.
123Script execution assumes that after executing a command, each `Buffer` object
124has a reference to the latest data for that buffer or image copied into
125the buffers memory. This means that a draw command will need to copy buffer data to
126the device, execute the draw, and then copy the device data back into the
127buffer. Amber does not do any extra calls to fill the buffers. Then engine must
128keep that data in sync.
129
130The `Pipeline` object holds the context for a given set of tests. This includes
131shaders, colour attachments, depth/stencil attachment, data buffers, etc. The
132colour attachments will have their `Attachment Location` while data buffers
133will have a `Descriptor Set` and `Binding` provided.
134
135## Execution
136When the script is executed the pipeline shaders will be compiled, if not
137provided through the shader map. This will fill in the `Compiled Shader` data
138in the each pipeline shader object. The `CreatePipeline` call will then be
139executed for a given pipeline.
140
141With the pipelines created the `Command` objects will be executed. Each
142`Command` knows the Amber `Pipeline` associated with it, that `Pipeline` pointer
143is provided in the command execution and can be used to lookup the
144engine-specific representation of a pipeline.
145
146When the `Probe` and `ProbeSSBO` commands are encountered they are not passed
147to the engine but sent to the `Verifier`. This will validate that the data
148in the specified buffer matches the test data. As mentioned above, this assumes
149that the Amber `Buffer` is kept up to date with the current device memory as we
150do not attempt to fill in the buffers before executing the `Probe*` calls.
151