#
tokens: 49143/50000 51/78 files (page 1/7)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 7. Use http://codebase.md/mehmetoguzderin/shaderc-vkrunner-mcp?page={x} to view the full context.

# Directory Structure

```
├── .devcontainer
│   ├── devcontainer.json
│   ├── docker-compose.yml
│   └── Dockerfile
├── .gitattributes
├── .github
│   └── workflows
│       └── build-push-image.yml
├── .gitignore
├── .vscode
│   └── mcp.json
├── Cargo.lock
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── README.adoc
├── shaderc-vkrunner-mcp.jpg
├── src
│   └── main.rs
└── vkrunner
    ├── .editorconfig
    ├── .gitignore
    ├── .gitlab-ci.yml
    ├── build.rs
    ├── Cargo.toml
    ├── COPYING
    ├── examples
    │   ├── compute-shader.shader_test
    │   ├── cooperative-matrix.shader_test
    │   ├── depth-buffer.shader_test
    │   ├── desc_set_and_binding.shader_test
    │   ├── entrypoint.shader_test
    │   ├── float-framebuffer.shader_test
    │   ├── frexp.shader_test
    │   ├── geometry.shader_test
    │   ├── indices.shader_test
    │   ├── layouts.shader_test
    │   ├── properties.shader_test
    │   ├── push-constants.shader_test
    │   ├── require-subgroup-size.shader_test
    │   ├── row-major.shader_test
    │   ├── spirv.shader_test
    │   ├── ssbo.shader_test
    │   ├── tolerance.shader_test
    │   ├── tricolore.shader_test
    │   ├── ubo.shader_test
    │   ├── vertex-data-piglit.shader_test
    │   └── vertex-data.shader_test
    ├── include
    │   ├── vk_video
    │   │   ├── vulkan_video_codec_av1std_decode.h
    │   │   ├── vulkan_video_codec_av1std_encode.h
    │   │   ├── vulkan_video_codec_av1std.h
    │   │   ├── vulkan_video_codec_h264std_decode.h
    │   │   ├── vulkan_video_codec_h264std_encode.h
    │   │   ├── vulkan_video_codec_h264std.h
    │   │   ├── vulkan_video_codec_h265std_decode.h
    │   │   ├── vulkan_video_codec_h265std_encode.h
    │   │   ├── vulkan_video_codec_h265std.h
    │   │   └── vulkan_video_codecs_common.h
    │   └── vulkan
    │       ├── vk_platform.h
    │       ├── vulkan_core.h
    │       └── vulkan.h
    ├── precompile-script.py
    ├── README.md
    ├── scripts
    │   └── update-vulkan.sh
    ├── src
    │   └── main.rs
    ├── test-build.sh
    └── vkrunner
        ├── allocate_store.rs
        ├── buffer.rs
        ├── compiler
        │   └── fake_process.rs
        ├── compiler.rs
        ├── config.rs
        ├── context.rs
        ├── enum_table.rs
        ├── env_var_test.rs
        ├── executor.rs
        ├── fake_vulkan.rs
        ├── features.rs
        ├── flush_memory.rs
        ├── format_table.rs
        ├── format.rs
        ├── half_float.rs
        ├── hex.rs
        ├── inspect.rs
        ├── lib.rs
        ├── logger.rs
        ├── make-enums.py
        ├── make-features.py
        ├── make-formats.py
        ├── make-pipeline-key-data.py
        ├── make-vulkan-funcs-data.py
        ├── parse_num.rs
        ├── pipeline_key_data.rs
        ├── pipeline_key.rs
        ├── pipeline_set.rs
        ├── requirements.rs
        ├── result.rs
        ├── script.rs
        ├── shader_stage.rs
        ├── slot.rs
        ├── small_float.rs
        ├── source.rs
        ├── stream.rs
        ├── temp_file.rs
        ├── tester.rs
        ├── tolerance.rs
        ├── util.rs
        ├── vbo.rs
        ├── vk.rs
        ├── vulkan_funcs_data.rs
        ├── vulkan_funcs.rs
        ├── window_format.rs
        └── window.rs
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
/target

```

--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------

```
* text=auto eol=lf

```

--------------------------------------------------------------------------------
/vkrunner/.gitignore:
--------------------------------------------------------------------------------

```
/Cargo.lock
/target
/tmp-build

```

--------------------------------------------------------------------------------
/vkrunner/.editorconfig:
--------------------------------------------------------------------------------

```
# To use this config on you editor, follow the instructions at:
# http://editorconfig.org

root = true

[*]
charset = utf-8
insert_final_newline = true
tab_width = 8

[*.{c,h,cpp,hpp,cc,hh}]
indent_style = space
indent_size = 8

[{Makefile*,*.mk}]
indent_style = tab

[{*.py,SCons*}]
indent_style = space
indent_size = 4

```

--------------------------------------------------------------------------------
/vkrunner/.gitlab-ci.yml:
--------------------------------------------------------------------------------

```yaml
include:
- project: 'freedesktop/ci-templates'
  ref: ea3f77641d91765396beba192b8defd3085fa343
  file: '/templates/fedora.yml'

stages:
  - prep
  - test

variables:
  FDO_UPSTREAM_REPO: mesa/vkrunner

.vkrunner.fedora:42:
  variables:
    FDO_DISTRIBUTION_VERSION: 42
    FDO_DISTRIBUTION_TAG: '2025-04-17.1'

build-fedora-container:
  extends:
  - .fdo.container-build@fedora
  - .vkrunner.fedora:42
  stage: prep
  variables:
    FDO_DISTRIBUTION_PACKAGES: "cargo bindgen-cli glslang"

cargo-test:
  extends:
  - .fdo.distribution-image@fedora
  - .vkrunner.fedora:42
  stage: test
  script:
    - cargo test

```

--------------------------------------------------------------------------------
/vkrunner/README.md:
--------------------------------------------------------------------------------

```markdown
# VkRunner

VkRunner is a Vulkan shader tester based on `shader_runner` in
[Piglit](https://piglit.freedesktop.org/). The goal is to make it be
able to test scripts as similar to Piglit’s shader_test format as
possible.

## Building

VkRunner requires Cargo and a rust compiler to build.

To build it type:

```
cargo build
```

Can can then run VkRunner by typing:

```
cargo run
```

## Installing

The vkrunner binary can be installed like so:

```
cargo install --path . --root <install_root>
```

## Running

VkRunner requires glslangValidator to compile GLSL to SPIR-V. It is
invoked on the fly while executing the test. It must either be
available in your path or you can set the variable
`PIGLIT_GLSLANG_VALIDATOR_BINARY` to point to it. It can be obtained
from [here](https://github.com/KhronosGroup/glslang/).

## [test] section:

The `[test]` section supports the following commands:

> draw rect [ortho] [patch] _x_ _y_ _width_ _height_

Draws a rectangle at the given normalised coordinates. The vertices
will be uploaded at vertex input location 0 as a vec3. Remember that
Vulkan’s normalised coordinate system is different from OpenGL’s. If
`ortho` is specified then the coordinates are scaled from the range
[0,window size] to [-1,1] to make it easier to specify the positions
in pixels. If `patch` is given then a patch topology will be used with
a patch size of four.

> draw arrays [indexed] [instanced] _topology_ _firstVertex_ _vertexCount_ [_instanceCount_]

Calls `vkCmdDraw` with the given parameters. The vertex data will be
sourced from the `[vertex data]` section. The _topology_ should be one
of the values of VkPrimitiveTopology minus the VK\_PRIMITIVE\_TOPOLOGY
prefix. Alternatively it can be a GLenum value as used in Piglit.

If `indexed` is specified then `vkCmdDrawIndexed` will be use to draw
the primitive instead. The indices will be sourced from the
`[indices]` section. _vertexCount_ will be used as the index count,
_firstVertex_ becomes the vertex offset and _firstIndex_ will always
be zero.

> compute _x_ _y_ _z_

Dispatch the compute shader with the given parameters.

> [relative] probe [rect] (rgb|rgba) (_x_, _y_[, _width_, _height_]) (_r_, _g_, _b_[, _a_])

Verifies that a given rectangle matches the given colour. If the
command begins with the keyword `relative` then the coordinates are
normalised from 0.0 to 1.0, otherwise they are pixel coordinates.
Either way the origin is the top-left corner of the image. If `rect`
is not specified then the width and height are set to 1 pixel. The
alpha component of the image can be ignored or not by specifying
either `rgb` or `rgba`.

> probe all (rgb|rgba) _r_ _g_ _b_ [_a_]

The same as above except that it probes the entire window.

> push _type_ _offset_ _values_…

Sets a push constant at the given offset. Note that unlike Piglit, the
offset is a byte offset into the push constant buffer rather than a
uniform location. For a description of how the arguments work see
“Setting buffer subdata” below.

> (ubo|ssbo) _binding_ subdata _type_ _offset_ _values_…

Sets a value within a uniform or storage buffer. The first time a
value is set within a buffer it will be created with the minimum size
needed to contain all of the values set on it via test commands. It
will then be bound to the descriptor set at the given binding point.
The rest of the arguments are used as described in “Setting buffer
subdata” below.

Note that the buffer is just updated by writing into a memory mapped
view of it which means that if you do an update, draw call, update and
then another draw call both draws will use the values from the second
update. This is because the draws are not flushed until the next probe
command or the test completes.

> (ubo|ssbo) _binding_ _size_

Sets the size of a uniform or storage buffer. This is optional if
there are buffer subdata commands because in that case it will just
take the size of the largest offset.

> probe ssbo _type_ _binding_ _offset_ _comparison_ _values_…

Probes a value in the storage buffer at _binding_. The _comparison_
can be one of `==`, `!=`, `<`, `>=`, `>`, `<=` or `~=`. If the type
has more than one component then they are compared individually until
one of them fails the comparison. `~=` is the same with `==` but `~=`
allows errors for `double` or `float` type numbers while `==` does
not. Allowed errors can be set by the following `tolerance` command.
See [examples/tolerance.shader_test](examples/tolerance.shader_test)
for the usage of `~=`. Multiple values can be listed to compare an
array of values. In that case the buffer is assumed to have the layout
specified with the last `ssbo layout` command.

> tolerance _tolerance0 tolerance1 tolerance2 tolerance3_

Sets four tolerances i.e., allowed errors. `vecN` type values will
use first `N` tolerances among those four. Each column of `matMxN` type
values will also use first `N` tolerances. `float` and `double` type
values will use only the first tolerance. Each tolerance value can be
an `double` type real number or percentage e.g., `0.01%`. `tolerance`
command can be also used for comparisons of pixels. See
[examples/tolerance.shader_test]( examples/tolerance.shader_test) for
the usage of `tolerance` command.

> tolerance _tolerance0_

Sets a tolerance i.e., an allowed error. If this command is set, all
components of `vecN` and `matMxN` type values will use the same
tolerance. Each tolerance value can be an `double` type real number or
percentage e.g., `0.01%`. See [examples/tolerance.shader_test](
examples/tolerance.shader_test) for the usage of `tolerance` command.

> push layout [std140|std430] [row_major|column_major]

> ssbo layout [std140|std430] [row_major|column_major]

> ubo layout [std140|std430] [row_major|column_major]

Sets the expected layout for subsequent commands that operate on push
constants, SSBOs and UBOs respectively. All layouts default to std430
and column_major except the UBO layout which defaults to std140. This
matches the defaults in GLSL. If row_major or column_major is not
specified then it will be set back to column_major (ie, it does not
leave it at as row_major if a previous layout command set it to that).
Note that setting the matrix major axis only affects the layout of the
data in memory. The values are still specified in test commands in
column-major order.

> clear color _r_ _g_ _b_ _a_

Sets the color to use for subsequent clear commands. Defaults to all
zeros.

> clear depth _value_

Sets the value to clear the depth buffer to in subsequent clear
commands. Defaults to 1.0.

> clear stencil _value_

Sets the value to clear the stencil buffer to in subsequent clear
commands. Defaults to 0.

> clear

Clears the entire framebuffer to the previously set clear color, depth
and stencil values.

> patch parameter vertices _vertices_

Sets the number of control points for tessellation patches in
subsequent draw calls. Defaults to 3.

> topology, primitiveRestartEnable, patchControlPoints,
> depthClampEnable, rasterizerDiscardEnable, polygonMode, cullMode,
> frontFace, depthBiasEnable, depthBiasConstantFactor, depthBiasClamp,
> depthBiasSlopeFactor, lineWidth, logicOpEnable, logicOp,
> blendEnable, srcColorBlendFactor, dstColorBlendFactor, colorBlendOp,
> srcAlphaBlendFactor, dstAlphaBlendFactor, alphaBlendOp,
> colorWriteMask, depthTestEnable, depthWriteEnable, depthCompareOp,
> depthBoundsTestEnable, stencilTestEnable, front.failOp,
> front.passOp, front.depthFailOp, front.compareOp, front.compareMask,
> front.writeMask, front.reference, back.failOp, back.passOp,
> back.depthFailOp, back.compareOp, back.compareMask, back.writeMask,
> back.reference

These properties can be set on a pipeline by specifying their name
followed by a value in the test section. This will affect subsequent
draw calls. If multiple draw calls are issued with different values
for these properties then a separate pipeline will be created for each
set of state. See the `properties.shader_test` example for details.

> _stage_ entrypoint _name_

Sets the entrypoint function to _name_ for the given stage. This will
be used for subsequent draw calls or compute dispatches.

> uniform _type_ _offset_ _values_…

This is equivalent to push _type_ _offset_ _values_. It is provided
for compatibility with Piglit.

> uniform ubo _binding_ _type_ _offset_ _values_…

This is equivalent to ubo _binding_ subdata _type_ _offset_ _values_.
It is provided for compatibility with Piglit.

Take a look in the examples directory for more examples.

## Setting buffer subdata

The commands to set push constants, ubo data and ssbo data all take
the same three arguments `type`, `offset` and `values…`. These are
used to describe a chunk of data to store at the given offset in the
corresponding buffer. The commands can be used multiple times with
different offsets to set data at different locations.

The type can be one of int, uint, int8_t, uint8_t, int16_t, uint16_t,
int64_t, uint64_t, float16_t, float, double, f16vec[234], vec[234],
dvec[234], ivec[234], uvec[234], i8vec[234], u8vec[234], i16vec[234],
u16vec[234], i64vec[234], u64vec[234], mat[234]x[234] or
dmat[234]x[234].

The values argument contains one integer or float for each component
of the given type. Multiple values can be specified in a single
command to set an array of values of the given type.

Each buffer type (push constant, UBO and SSBO) has a corresponding
current layout which is either std140 or std430. The current layout
only matters for matrix types or for specifying array values with a
single command. It is used to calculate the array stride and matrix
stride for the given type. The default layouts for each buffer type
correspond to the defaults for the corresponding buffer type in GLSL.
Note that the layout is only used as a convenience to set values in
memory. If you want to use a custom layout it is still always possible
to set all the values using multiple commands and explicit offsets.

Some examples:

    ssbo 0 subdata float 12  42.0

This will write the float value 42 twelve bytes into the buffer at
binding 0.

    ssbo layout std140
    ssbo 0 subdata float 32  1 2 3

This will write the float values 1, 2, 3 into the buffer starting at
byte 32 arranged such so that it would be suitable for an array of floats
declared as std140 such as this:

```GLSL
layout(binding = 0, std140) buffer block {
   layout(offset = 32) float one_two_three[3];
};
```

The rules of std140 force the array stride to be a multiple of a vec4
so this will effectively write the following floats starting at byte
32:

```
1 0 0 0 2 0 0 0 3
```

```
ssbo layout std430
ssbo 0 subdata mat3 12   1 2 3 4 5 6 7 8 9
```

This will write a mat3 starting at offset 12. std430 treats this like
an array of 3 vec3s. The stride for vec3s is padded up to vec4 so it
would write the floats like this:

```
1 2 3 0 4 5 6 0 7 8 9
```

```
ssbo layout std430 row_major
ssbo 0 subdata mat3 12   1 2 3 4 5 6 7 8 9
```

This will write the same matrix but laid out in a way suitable for a
uniform declared as row_major. It will look like this:

    1 4 7 0 2 5 8 0 3 6 9

## [require] section

> _feature_

The `[require]` section can contain names of members from
VkPhysicalDeviceFeatures. These will be searched for when deciding
which physical device to open. If no physical device with the
corresponding requirements can be found then it will report an error.

In addition to VkPhysicalDeviceFeatures, the name of a feature from
any feature struct from an extension that VkRunner is aware of can
also be requested. In that case VkRunner will also implicitly require
the corresponding device extension. It will also need the
`VK_KHR_get_physical_device_properties2` instance extension in order
to check for the feature. For example, specifying `shaderFloat16` in
the require section will make it also require the
`VK_KHR_shader_float16_int8` extension. VkRunner will then enable the
feature via the VkPhysicalDeviceFloat16Int8FeaturesKHR struct when
creating the device.

> _extension_

Any line that is not a feature and contains entirely alphanumeric and
underscore characters is assumed to be a device extension name. This
will be checked for when searching for a suitable device and if no
device with the extension is found then the test will report that it
was skipped. Otherwise the extension will be enabled when creating the
device.

The required Vulkan implementation version for the test can also be
set in this section. If the version is not supported by the device
driver the test will be skipped.

> framebuffer _format_

Use this to specify the format of the framebuffer using a format from
VkFormat minus the VK_FORMAT prefix.

> depthstencil _format_

If this is specified VkRunner will try to add a depth-stencil
attachment to the framebuffer with the given format. Without it no
depth-stencil buffer will be created.

> fbsize _width_ _height_

Specify the size of the framebuffer. If not specified it defaults to
250x250.

> vulkan _major_._minor_._patch_

Use this to specify the Vulkan implementation version against which
the test should run.

> subgroup_size _size_

Specify the required subgroup size for the compute shaders in the pipeline.
See Vulkan documentation for `VkPipelineShaderStageRequiredSubgroupSizeCreateInfo`
for more details.

> cooperative_matrix [params...]

Specify that Cooperative Matrix support is required. It will automatically
require VK_KHR_cooperative_matrix extension and the cooperativeMatrix feature.

Matrix configuration requirements is provided by passing the attributes
for each item, e.g. `m=16 a=float`. The items available are `m=`, `n=`
and `k=` for the matrix sizes; `a=`, `b=`, `c=` and `result=` for the
element types of each matrix; `saturating_accumulation=true|false` and
`scope=` for extra options. See Vulkan documentation for
`VkCooperativeMatrixPropertiesKHR` for more details.

If an item is not specified, it will match any value available. If
multiple different configurations are required, use multiple
`cooperative_matrix` lines.

## Shader sections

Shaders can be stored in sections like `[vertex shader]` just like in
`shader_runner`. Multiple GLSL shaders can be given for a single stage
and they will be linked together via glslangValidator.

Alternatively, the disassembly of the SPIR-V source can be provided
with a section like `[vertex shader spirv]`. This will be assembled
with `spirv-as`. If a SPIR-V section is given for a stage there can be
no other shaders for that stage.

The vertex shader can also be skipped with an empty section called
`[vertex shader passthrough]`. That will create a simple vertex shader
than just copies a vec4 for input location 0 to `gl_Position`.

## [vertex data] section

The `[vertex data]` section is used to specify vertex attributes and
data for use with the draw arrays command. It is similar to Piglit
except that integer locations are used instead of names and matrices
are specifed by using a location within the matrix rather than having
a separate field.

The format consists of a row of column headers followed by any number
of rows of data. Each column header has the form _ATTRLOC_/_FORMAT_
where _ATTRLOC_ is the location of the vertex attribute to be bound to
this column and _FORMAT_ is the name of a VkFormat minus the VK_FORMAT
prefix.

Alternatively the column header can use something closer the Piglit
format like _ATTRLOC_/_GL\_TYPE_/_GLSL\_TYPE_. _GL\_TYPE_ is the GL
type of data that follows (“half”, “float”, “double”, “byte”, “ubyte”,
“short”, “ushort”, “int” or “uint”), _GLSL\_TYPE_ is the GLSL type of
the data (“int”, “uint”, “float”, “double”, “ivec”\*, “uvec”\*,
“vec”\*, “dvec”\*).

The data follows the column headers in space-separated form. “#” can
be used for comments, as in shell scripts. See the
`vertex-data.shader_test` file as an example.

## [indices] section

The `[indices]` section just contains a list of indices to use along
with the vertices in `[vertex data]`. It will be used if the `indexed`
option is given to the `draw arrays` test command.

## Long lines

Long lines anywhere in the script can be split into multiple lines by
using a backslash to combine them. For example a line to set an array
of ints could be split up as follows:

```
ubo 0 subdata int 0 \
        1 2 3 5 8 13 21 34 55 89 144 233 377 610 \
        987 1597 2584 4181 6765 10946 17711 28657 \
        46368 75025 121393 196418 317811 514229
```

## Command line arguments

    usage: vkrunner [OPTION]... SCRIPT...
    Runs the shader test script SCRIPT

    Options:
      -h                Show this help message
      -i IMG            Write the final rendering to IMG as a PPM image
      -d                Show the SPIR-V disassembly
      -D TOK=REPL       Replace occurences of TOK with REPL in the scripts
      --device-id DEVID Select the Vulkan device

## Precompiling shaders

As an alternative to specifying the shaders in GLSL or SPIR-V
assembly, the test scripts can contain a hex dump of the SPIR-V. That
way VkRunner does not need to invoke the compiler or assembler to run
the script. This can be useful either to speed up the execution of the
tests or to run them on hardware where installing the compiler is not
practical. VkRunner also includes a Python script to precompile the
test scripts to binary. It can be run for example as below:

    ./precompile-script.py -o compiled-examples examples/*.shader_test
    ./src/vkrunner compiled-examples/*.shader_test

If glslangValidator and spirv-as are not in the path, you can indicate
where the binaries are with the following command line arguments:

    ./precompile-script.py -o compiled-examples examples/*.shader_test -g PATH_GLSLANG/glslangValidator -s PATH_SPIRV_AS/spirv-as

```

--------------------------------------------------------------------------------
/.devcontainer/docker-compose.yml:
--------------------------------------------------------------------------------

```yaml
version: '3'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/workspace:cached
    command: sleep infinity
    # Keep the container running
    tty: true
```

--------------------------------------------------------------------------------
/vkrunner/Cargo.toml:
--------------------------------------------------------------------------------

```toml
[package]
name = "vkrunner"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "A shader testing tool for Vulkan"
repository = "https://gitlab.freedesktop.org/mesa/vkrunner/"
default-run = "vkrunner"

[lib]
path = "vkrunner/lib.rs"

[build-dependencies]
bindgen = "0.66.1"

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codecs_common.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODECS_COMMON_H_
#define VULKAN_VIDEO_CODECS_COMMON_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codecs_common is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codecs_common 1
#if !defined(VK_NO_STDINT_H)
    #include <stdint.h>
#endif

#define VK_MAKE_VIDEO_STD_VERSION(major, minor, patch) \
    ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch)))


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/lib.rs:
--------------------------------------------------------------------------------

```rust
mod small_float;
mod half_float;
mod hex;
mod format;
mod tolerance;
mod util;
mod parse_num;
mod vbo;
mod vk;
mod vulkan_funcs;
mod requirements;
mod slot;
pub mod result;
mod shader_stage;
mod pipeline_key;
mod window_format;
mod source;
mod config;
mod stream;
mod script;
mod context;
mod buffer;
mod window;
mod allocate_store;
mod executor;
mod temp_file;
mod logger;
mod compiler;
mod pipeline_set;
mod flush_memory;
pub mod inspect;
mod tester;

#[cfg(test)]
mod fake_vulkan;
#[cfg(test)]
mod env_var_test;

// Re-export the public API
pub use config::Config;
pub use executor::Executor;
pub use format::Format;
pub use script::Script;
pub use shader_stage::Stage;
pub use source::Source;

```

--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------

```json
{
    "name": "shaderc-vkrunner-mcp",
    "dockerComposeFile": "docker-compose.yml",
    "service": "app",
    "workspaceFolder": "/workspace",
    "customizations": {
        "vscode": {
            "extensions": [
                "GitHub.copilot",
                "GitHub.copilot-chat",
                "charliermarsh.ruff",
                "eamodio.gitlens",
                "llvm-vs-code-extensions.vscode-clangd",
                "ms-python.python",
                "ms-vscode.cmake-tools",
                "rust-lang.rust-analyzer",
                "tamasfe.even-better-toml"
            ],
            "settings": {
                "terminal.integrated.defaultProfile.linux": "bash"
            }
        }
    },
    "remoteUser": "root"
}
```

--------------------------------------------------------------------------------
/.vscode/mcp.json:
--------------------------------------------------------------------------------

```json
{
    "servers": {
        "shaderc-vkrunner-mcp-dev": {
            "type": "stdio",
            "command": "cargo",
            "args": [
                "run",
                "--release",
                "--manifest-path",
                "${workspaceFolder}/Cargo.toml",
                "--",
                "--work-dir",
                "${workspaceFolder}"
            ]
        },
        "shaderc-vkrunner-mcp": {
            "type": "stdio",
            "command": "docker",
            "args": [
                "run",
                "--rm",
                "-i",
                "-v",
                "${workspaceFolder}:/work",
                "shaderc-vkrunner-mcp",
                "--work-dir",
                "/work"
            ]
        }
    }
}
```

--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------

```toml
[package]
name = "shaderc-vkrunner-mcp"
version = "0.1.0"
edition = "2024"

[dependencies]
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "main", features = [
    "server",
    "transport-sse-server",
    "transport-io",
] }
tokio = { version = "1", features = [
    "macros",
    "rt",
    "rt-multi-thread",
    "io-std",
    "signal",
] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = [
    "env-filter",
    "std",
    "fmt",
] }
futures = "0.3"
rand = { version = "0.9" }
axum = { version = "0.8", features = ["macros"] }
schemars = { version = "0.8", optional = true }
image = "0.25.6"
clap = { version = "4.5.36", features = ["derive"] }
shaderc = "0.9.1"
vkrunner = { path = "./vkrunner", features = [] }

[dev-dependencies]
tokio-stream = { version = "0.1" }
tokio-util = { version = "0.7", features = ["codec"] }

```

--------------------------------------------------------------------------------
/vkrunner/scripts/update-vulkan.sh:
--------------------------------------------------------------------------------

```bash
#!/usr/bin/env bash
#
# Copyright 2025 Intel Corporation
# SPDX-License-Identifier: MIT

set -e

if [ ! -f "Cargo.toml" ]; then
    echo "Run the script from the root of the repository."
    exit 1
fi

SKIP_DOWNLOAD=

for arg in "$@"; do
    case $arg in
        --skip-download)
            SKIP_DOWNLOAD=1
            shift
            ;;
        *)
            shift
            ;;
    esac
done

if [ -z "$SKIP_DOWNLOAD" ]; then
    VULKAN_HEADERS=$(mktemp -d)
    git clone https://github.com/KhronosGroup/Vulkan-Headers.git "$VULKAN_HEADERS"
    git -C "$VULKAN_HEADERS" log -1

    cp -f $VULKAN_HEADERS/include/vk_video/*.h include/vk_video/
    cp -f $VULKAN_HEADERS/include/vulkan/{vulkan.h,vulkan_core.h,vk_platform.h} include/vulkan/
fi

# TODO: Most of these scripts should be using the registry/vk.xml instead of
# parsing the C headers.

echo | gcc -include "./include/vulkan/vulkan.h" -E - | vkrunner/make-enums.py > vkrunner/enum_table.rs
vkrunner/make-features.py < include/vulkan/vulkan_core.h > vkrunner/features.rs
vkrunner/make-formats.py < include/vulkan/vulkan_core.h > vkrunner/format_table.rs
vkrunner/make-pipeline-key-data.py > vkrunner/pipeline_key_data.rs
vkrunner/make-vulkan-funcs-data.py > vkrunner/vulkan_funcs_data.rs

```

--------------------------------------------------------------------------------
/vkrunner/test-build.sh:
--------------------------------------------------------------------------------

```bash
#!/bin/bash

set -eu

src_dir="$(cd $(dirname "$0") && pwd)"
build_dir="$src_dir/tmp-build"
install_dir="$build_dir/install"
device_id=""

if [ $# -gt 0 ] && [ "$1" = "--device-id" ]; then
    if [ -z "${2:-}" ]; then
        echo "--device-id must be followed by a number"
        exit 1
    fi
    device_id="--device-id $2"
fi

rm -fr -- "$build_dir"

cargo test --target-dir "$build_dir"
cargo install --target-dir "$build_dir" --path . --root "$install_dir"

# Run the built executable with all of the examples and enable the
# validation layer. Verify that nothing was written to the output.
VKRUNNER_ALWAYS_FLUSH_MEMORY=true \
VK_LOADER_LAYERS_ENABLE="*validation" \
                  "$install_dir/bin/vkrunner" \
                  -q \
                  "$src_dir/examples"/*.shader_test \
                  2>&1 \
    | tee "$build_dir/output.txt"

if grep -q --invert-match '^/tmp' "$build_dir/output.txt"; then
    echo "FAIL VkRunner had output with quiet flag"
    exit 1;
fi

# Try again with precompiled scripts
"$src_dir"/precompile-script.py -o "$build_dir/precompiled-examples" \
          "$src_dir/examples"/*.shader_test
"$install_dir/bin/vkrunner" $device_id \
    "$build_dir/precompiled-examples/"*.shader_test

echo
echo "Test build succeeded."

```

--------------------------------------------------------------------------------
/vkrunner/include/vulkan/vulkan.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_H_
#define VULKAN_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

#include "vk_platform.h"
#include "vulkan_core.h"

#ifdef VK_USE_PLATFORM_ANDROID_KHR
#include "vulkan_android.h"
#endif

#ifdef VK_USE_PLATFORM_FUCHSIA
#include <zircon/types.h>
#include "vulkan_fuchsia.h"
#endif

#ifdef VK_USE_PLATFORM_IOS_MVK
#include "vulkan_ios.h"
#endif


#ifdef VK_USE_PLATFORM_MACOS_MVK
#include "vulkan_macos.h"
#endif

#ifdef VK_USE_PLATFORM_METAL_EXT
#include "vulkan_metal.h"
#endif

#ifdef VK_USE_PLATFORM_VI_NN
#include "vulkan_vi.h"
#endif


#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#include "vulkan_wayland.h"
#endif


#ifdef VK_USE_PLATFORM_WIN32_KHR
#include <windows.h>
#include "vulkan_win32.h"
#endif


#ifdef VK_USE_PLATFORM_XCB_KHR
#include <xcb/xcb.h>
#include "vulkan_xcb.h"
#endif


#ifdef VK_USE_PLATFORM_XLIB_KHR
#include <X11/Xlib.h>
#include "vulkan_xlib.h"
#endif


#ifdef VK_USE_PLATFORM_DIRECTFB_EXT
#include <directfb.h>
#include "vulkan_directfb.h"
#endif


#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include "vulkan_xlib_xrandr.h"
#endif


#ifdef VK_USE_PLATFORM_GGP
#include <ggp_c/vulkan_types.h>
#include "vulkan_ggp.h"
#endif


#ifdef VK_USE_PLATFORM_SCREEN_QNX
#include <screen/screen.h>
#include "vulkan_screen.h"
#endif


#ifdef VK_USE_PLATFORM_SCI
#include <nvscisync.h>
#include <nvscibuf.h>
#include "vulkan_sci.h"
#endif


#ifdef VK_ENABLE_BETA_EXTENSIONS
#include "vulkan_beta.h"
#endif

#endif // VULKAN_H_

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/window_format.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2013, 2014, 2015, 2017, 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::format::Format;
use crate::vk;

#[derive(Clone, Debug, PartialEq)]
pub struct WindowFormat {
    pub color_format: &'static Format,
    pub depth_stencil_format: Option<&'static Format>,
    pub width: usize,
    pub height: usize,
}

impl Default for WindowFormat {
    fn default() -> WindowFormat {
        let color_format =
            Format::lookup_by_vk_format(vk::VK_FORMAT_B8G8R8A8_UNORM);

        WindowFormat {
            color_format,
            depth_stencil_format: None,
            width: 250,
            height: 250,
        }
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/vk.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// on the rights to use, copy, modify, merge, publish, distribute, sub
// license, and/or sell copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
// VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]

mod bindings {
#![allow(unused_imports)]
include!(concat!(env!("OUT_DIR"), "/vulkan_bindings.rs"));
}

pub use self::bindings::*;

/// Function to return a value that can be used where the Vulkan
/// documentation specifies that `VK_NULL_HANDLE` can be used.
#[cfg(target_pointer_width = "64")]
pub fn null_handle<T>() -> *mut T {
    std::ptr::null_mut()
}

#[cfg(not(target_pointer_width = "64"))]
pub fn null_handle() -> u64 {
    // On 32-bit platforms the non-dispatchable handles are defined as
    // a 64-bit integer instead of a pointer.
    0u64
}

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_h265std_decode.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODEC_H265STD_DECODE_H_
#define VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codec_h265std_decode is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codec_h265std_decode 1
#include "vulkan_video_codec_h265std.h"

#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)

#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0
#define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_decode"
#define STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE 8
typedef struct StdVideoDecodeH265PictureInfoFlags {
    uint32_t    IrapPicFlag : 1;
    uint32_t    IdrPicFlag  : 1;
    uint32_t    IsReference : 1;
    uint32_t    short_term_ref_pic_set_sps_flag : 1;
} StdVideoDecodeH265PictureInfoFlags;

typedef struct StdVideoDecodeH265PictureInfo {
    StdVideoDecodeH265PictureInfoFlags    flags;
    uint8_t                               sps_video_parameter_set_id;
    uint8_t                               pps_seq_parameter_set_id;
    uint8_t                               pps_pic_parameter_set_id;
    uint8_t                               NumDeltaPocsOfRefRpsIdx;
    int32_t                               PicOrderCntVal;
    uint16_t                              NumBitsForSTRefPicSetInSlice;
    uint16_t                              reserved;
    uint8_t                               RefPicSetStCurrBefore[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE];
    uint8_t                               RefPicSetStCurrAfter[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE];
    uint8_t                               RefPicSetLtCurr[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE];
} StdVideoDecodeH265PictureInfo;

typedef struct StdVideoDecodeH265ReferenceInfoFlags {
    uint32_t    used_for_long_term_reference : 1;
    uint32_t    unused_for_reference : 1;
} StdVideoDecodeH265ReferenceInfoFlags;

typedef struct StdVideoDecodeH265ReferenceInfo {
    StdVideoDecodeH265ReferenceInfoFlags    flags;
    int32_t                                 PicOrderCntVal;
} StdVideoDecodeH265ReferenceInfo;


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
FROM ubuntu:25.04 AS devcontainer

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    bc \
    build-essential \
    clang \
    clang-format \
    clang-tidy \
    clang-tools \
    clangd \
    cmake \
    curl \
    ffmpeg \
    git \
    glslang-tools \
    glslc \
    jq \
    libshaderc-dev \
    libshaderc1 \
    imagemagick \
    libgl1-mesa-dri \
    libvulkan-dev \
    libvulkan1 \
    mesa-utils \
    mesa-vulkan-drivers \
    ninja-build \
    npm \
    pipx \
    python3 \
    python3-pip \
    python3-venv \
    rustup \
    sudo \
    unzip \
    vulkan-tools \
    wget \
    x11-utils \
    xvfb \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN rustup install 1.86.0 && \
    rustup default 1.86.0

RUN rustup component add rustfmt && \
    rustup component add clippy && \
    rustup component add rust-src && \
    rustup component add rust-analyzer

RUN sh -c "pipx ensurepath" && \
    bash -c "pipx ensurepath"

RUN pipx install uv \
    && pipx install ruff \
    && pipx install pre-commit

RUN echo '#!/bin/bash \n\
export VK_ICD_FILES=$(find /usr/share/vulkan/icd.d/ -name "lvp_icd*.json") \n\
export VK_ICD_FILENAMES=$VK_ICD_FILES \n\
export VK_DRIVER_FILES=$VK_ICD_FILES \n\
export LIBGL_ALWAYS_SOFTWARE=1 \n\
export GALLIUM_DRIVER=llvmpipe \n\
if ! DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then  \n\
    rm -f /tmp/.X11-unix/X99 \n\
    rm -f /tmp/.X99-lock \n\
    Xvfb :99 -screen 0 960x540x24 & \n\
fi \n\
export DISPLAY=:99 \n\
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-dir \n\
mkdir -p $XDG_RUNTIME_DIR && chmod 700 $XDG_RUNTIME_DIR \n\
' > /usr/local/bin/setup-vulkan-env.sh && chmod +x /usr/local/bin/setup-vulkan-env.sh

RUN echo '#!/bin/bash \n\
source /usr/local/bin/setup-vulkan-env.sh \n\
exec "$@"' > /entrypoint.sh && chmod +x /entrypoint.sh

RUN echo '. /usr/local/bin/setup-vulkan-env.sh' >> /etc/bash.bashrc

RUN echo '#!/bin/bash \n\
vulkaninfo --summary \n\
vkcube --width 256 --height 256 & \n\
for attempt in $(seq 1 64); do \n\
    import -window root /setup-vulkan-env.png \n\
    mean=$(identify -format "%[fx:mean]" /setup-vulkan-env.png) \n\
    if (( $(echo "$mean > 0.01" | bc -l) )); then \n\
        break \n\
    fi \n\
    sleep 0.1 \n\
done \n\
' | ./entrypoint.sh bash

COPY vkrunner /vkrunner

WORKDIR /vkrunner

RUN cargo build --release && \
    cp /vkrunner/target/release/vkrunner /usr/local/bin/ && \
    chmod +x /usr/local/bin/vkrunner

WORKDIR /

ENTRYPOINT ["/entrypoint.sh"]

CMD ["bash"]

```

--------------------------------------------------------------------------------
/vkrunner/build.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::env;
use std::path::PathBuf;

fn main() {
    let header = ["include", "vulkan", "vulkan.h"].iter().collect::<PathBuf>();

    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header(header.to_str().unwrap())
        // Only generate types and variables
        .with_codegen_config(
            bindgen::CodegenConfig::TYPES
                | bindgen::CodegenConfig::VARS
        )
        // Don’t prepend the enum name
        .prepend_enum_name(false)
        // Limit the types that we generate bindings for
        .allowlist_type(r"^(PFN|Vk).*")
        .allowlist_var(r"^VK_.*")
        // Derive the default trait
        .derive_default(true)
        // Specifiy the include path so that it can find the other headers
        .clang_arg("-Iinclude")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        // Finish the builder and generate the bindings
        .generate()
        // Unwrap the Result and panic on failure
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/vulkan_bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("vulkan_bindings.rs"))
        .expect("Couldn't write bindings!");
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/shader_stage.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018 Intel Corporation
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::vk;

/// An enum of all the possible shader stages known to VkRunner.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[repr(C)]
pub enum Stage {
    Vertex = 0,
    TessCtrl,
    TessEval,
    Geometry,
    Fragment,
    Compute
}

/// The number of shader stages known to VkRunner. This should match
/// the number of values in [Stage].
pub(crate) const N_STAGES: usize = 6;

/// All the possible stage values.
pub(crate) static ALL_STAGES: [Stage; N_STAGES] = [
    Stage::Vertex,
    Stage::TessCtrl,
    Stage::TessEval,
    Stage::Geometry,
    Stage::Fragment,
    Stage::Compute,
];

impl Stage {
    /// Get the corresponding flag for this stage. This can be used to
    /// store the stages in a bitmask.
    pub(crate) const fn flag(self) -> vk::VkShaderStageFlagBits {
        vk::VK_SHADER_STAGE_VERTEX_BIT << self as usize
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn flags() {
        assert_eq!(Stage::Vertex.flag(), vk::VK_SHADER_STAGE_VERTEX_BIT);
        assert_eq!(
            Stage::TessCtrl.flag(),
            vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
        );
        assert_eq!(
            Stage::TessEval.flag(),
            vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
        );
        assert_eq!(Stage::Geometry.flag(), vk::VK_SHADER_STAGE_GEOMETRY_BIT);
        assert_eq!(Stage::Fragment.flag(), vk::VK_SHADER_STAGE_FRAGMENT_BIT);
        assert_eq!(Stage::Compute.flag(), vk::VK_SHADER_STAGE_COMPUTE_BIT);
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/tolerance.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018 Google LLC
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#[derive(Debug, Clone, PartialEq)]
pub struct Tolerance {
    value: [f64; 4],
    is_percent: bool,
}

impl Tolerance {
    pub fn new(value: [f64; 4], is_percent: bool) -> Tolerance {
        Tolerance { value, is_percent }
    }

    pub fn equal(&self, component: usize, a: f64, b: f64) -> bool {
        if self.is_percent {
            (a - b).abs() <= (self.value[component] / 100.0 * b).abs()
        } else {
            (a - b).abs() <= self.value[component]
        }
    }
}

impl Default for Tolerance {
    fn default() -> Tolerance {
        Tolerance {
            value: [0.01; 4],
            is_percent: false,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_percentage() {
        let tolerance = Tolerance::new([25.0, 50.0, 1.0, 1.0], true);

        assert!(tolerance.equal(0, 0.76, 1.0));
        assert!(!tolerance.equal(0, 0.74, 1.0));
        assert!(tolerance.equal(1, 41.0, 80.0));
        assert!(!tolerance.equal(1, 39.0, 1.0));
        assert!(tolerance.equal(2, 100.5, 100.0));
        assert!(!tolerance.equal(2, 101.5, 100.0));
    }

    #[test]
    fn test_direct() {
        let tolerance = Tolerance::new([1.0, 2.0, 3.0, 4.0], false);

        assert!(tolerance.equal(0, 5.9, 5.0));
        assert!(!tolerance.equal(0, 6.1, 5.0));
        assert!(tolerance.equal(1, 3.1, 5.0));
        assert!(!tolerance.equal(1, 2.9, 5.0));
        assert!(tolerance.equal(3, 186.1, 190.0));
        assert!(!tolerance.equal(3, 185.9, 190.0));
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_h264std_decode.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODEC_H264STD_DECODE_H_
#define VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codec_h264std_decode is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codec_h264std_decode 1
#include "vulkan_video_codec_h264std.h"

#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)

#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0
#define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_decode"
#define STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE 2

typedef enum StdVideoDecodeH264FieldOrderCount {
    STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_TOP = 0,
    STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_BOTTOM = 1,
    STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_INVALID = 0x7FFFFFFF,
    STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_MAX_ENUM = 0x7FFFFFFF
} StdVideoDecodeH264FieldOrderCount;
typedef struct StdVideoDecodeH264PictureInfoFlags {
    uint32_t    field_pic_flag : 1;
    uint32_t    is_intra : 1;
    uint32_t    IdrPicFlag : 1;
    uint32_t    bottom_field_flag : 1;
    uint32_t    is_reference : 1;
    uint32_t    complementary_field_pair : 1;
} StdVideoDecodeH264PictureInfoFlags;

typedef struct StdVideoDecodeH264PictureInfo {
    StdVideoDecodeH264PictureInfoFlags    flags;
    uint8_t                               seq_parameter_set_id;
    uint8_t                               pic_parameter_set_id;
    uint8_t                               reserved1;
    uint8_t                               reserved2;
    uint16_t                              frame_num;
    uint16_t                              idr_pic_id;
    int32_t                               PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE];
} StdVideoDecodeH264PictureInfo;

typedef struct StdVideoDecodeH264ReferenceInfoFlags {
    uint32_t    top_field_flag : 1;
    uint32_t    bottom_field_flag : 1;
    uint32_t    used_for_long_term_reference : 1;
    uint32_t    is_non_existing : 1;
} StdVideoDecodeH264ReferenceInfoFlags;

typedef struct StdVideoDecodeH264ReferenceInfo {
    StdVideoDecodeH264ReferenceInfoFlags    flags;
    uint16_t                                FrameNum;
    uint16_t                                reserved;
    int32_t                                 PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE];
} StdVideoDecodeH264ReferenceInfo;


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
FROM ubuntu:25.04 AS builder

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    bc \
    build-essential \
    clang \
    clang-format \
    clang-tidy \
    clang-tools \
    clangd \
    cmake \
    curl \
    ffmpeg \
    git \
    glslang-tools \
    glslc \
    jq \
    libshaderc-dev \
    libshaderc1 \
    imagemagick \
    libgl1-mesa-dri \
    libvulkan-dev \
    libvulkan1 \
    mesa-utils \
    mesa-vulkan-drivers \
    ninja-build \
    npm \
    pipx \
    python3 \
    python3-pip \
    python3-venv \
    rustup \
    sudo \
    unzip \
    vulkan-tools \
    wget \
    x11-utils \
    xvfb \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN rustup install 1.86.0 && \
    rustup default 1.86.0

RUN rustup component add rustfmt && \
    rustup component add clippy && \
    rustup component add rust-src && \
    rustup component add rust-analyzer

RUN sh -c "pipx ensurepath" && \
    bash -c "pipx ensurepath"

RUN pipx install uv \
    && pipx install ruff \
    && pipx install pre-commit

WORKDIR /app
COPY . .

RUN cargo build --release

COPY vkrunner /vkrunner

WORKDIR /vkrunner

RUN cargo build --release && \
    cp /vkrunner/target/release/vkrunner /usr/local/bin/ && \
    chmod +x /usr/local/bin/vkrunner

FROM ubuntu:25.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    bc \
    glslang-tools \
    glslc \
    imagemagick \
    jq \
    libgl1-mesa-dri \
    libshaderc1 \
    libvulkan1 \
    mesa-utils \
    mesa-vulkan-drivers \
    vulkan-tools \
    x11-utils \
    xvfb \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

RUN echo '#!/bin/bash \n\
export VK_ICD_FILES=$(find /usr/share/vulkan/icd.d/ -name "lvp_icd*.json") \n\
export VK_ICD_FILENAMES=$VK_ICD_FILES \n\
export VK_DRIVER_FILES=$VK_ICD_FILES \n\
export LIBGL_ALWAYS_SOFTWARE=1 \n\
export GALLIUM_DRIVER=llvmpipe \n\
if ! ps aux | grep -v grep | grep "Xvfb :99" > /dev/null; then \n\
    rm -f /tmp/.X11-unix/X99 \n\
    rm -f /tmp/.X99-lock \n\
    Xvfb :99 -screen 0 960x540x24 > /dev/null 2>&1 & \n\
fi \n\
export DISPLAY=:99 \n\
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-dir \n\
mkdir -p $XDG_RUNTIME_DIR && chmod 700 $XDG_RUNTIME_DIR \n\
' > /usr/local/bin/setup-vulkan-env.sh && chmod +x /usr/local/bin/setup-vulkan-env.sh

RUN echo '#!/bin/bash \n\
source /usr/local/bin/setup-vulkan-env.sh \n\
if [[ "${1}" == --* ]]; then \n\
    /usr/local/bin/shaderc-vkrunner-mcp "$@" \n\
else \n\
    exec "$@" \n\
fi \n\
' > /entrypoint.sh && chmod +x /entrypoint.sh

COPY --from=builder /app/target/release/shaderc-vkrunner-mcp /usr/local/bin/
COPY --from=builder /usr/local/bin/vkrunner /usr/local/bin/

WORKDIR /work

ENTRYPOINT ["/entrypoint.sh"]

```

--------------------------------------------------------------------------------
/vkrunner/include/vulkan/vk_platform.h:
--------------------------------------------------------------------------------

```
//
// File: vk_platform.h
//
/*
** Copyright 2014-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/


#ifndef VK_PLATFORM_H_
#define VK_PLATFORM_H_

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

/*
***************************************************************************************************
*   Platform-specific directives and type declarations
***************************************************************************************************
*/

/* Platform-specific calling convention macros.
 *
 * Platforms should define these so that Vulkan clients call Vulkan commands
 * with the same calling conventions that the Vulkan implementation expects.
 *
 * VKAPI_ATTR - Placed before the return type in function declarations.
 *              Useful for C++11 and GCC/Clang-style function attribute syntax.
 * VKAPI_CALL - Placed after the return type in function declarations.
 *              Useful for MSVC-style calling convention syntax.
 * VKAPI_PTR  - Placed between the '(' and '*' in function pointer types.
 *
 * Function declaration:  VKAPI_ATTR void VKAPI_CALL vkCommand(void);
 * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
 */
#if defined(_WIN32)
    // On Windows, Vulkan commands use the stdcall convention
    #define VKAPI_ATTR
    #define VKAPI_CALL __stdcall
    #define VKAPI_PTR  VKAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
    #error "Vulkan is not supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
    // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
    // calling convention, i.e. float parameters are passed in registers. This
    // is true even if the rest of the application passes floats on the stack,
    // as it does by default when compiling for the armeabi-v7a NDK ABI.
    #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
    #define VKAPI_CALL
    #define VKAPI_PTR  VKAPI_ATTR
#else
    // On other platforms, use the default calling convention
    #define VKAPI_ATTR
    #define VKAPI_CALL
    #define VKAPI_PTR
#endif

#if !defined(VK_NO_STDDEF_H)
    #include <stddef.h>
#endif // !defined(VK_NO_STDDEF_H)

#if !defined(VK_NO_STDINT_H)
    #if defined(_MSC_VER) && (_MSC_VER < 1600)
        typedef signed   __int8  int8_t;
        typedef unsigned __int8  uint8_t;
        typedef signed   __int16 int16_t;
        typedef unsigned __int16 uint16_t;
        typedef signed   __int32 int32_t;
        typedef unsigned __int32 uint32_t;
        typedef signed   __int64 int64_t;
        typedef unsigned __int64 uint64_t;
    #else
        #include <stdint.h>
    #endif
#endif // !defined(VK_NO_STDINT_H)

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/small_float.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018, 2019 Intel Corporation
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

pub fn load_unsigned(part: u32, e_bits: u32, m_bits: u32) -> f64 {
    let e_max = u32::MAX >> (32 - e_bits);
    let mut e = ((part >> m_bits) & e_max) as i32;
    let mut m = part & (u32::MAX >> (32 - m_bits));

    if e == e_max as i32 {
        if m == 0 {
            f64::INFINITY
        } else {
            f64::NAN
        }
    } else {
        if e == 0 {
            e = 1;
        } else {
            m += 1 << m_bits;
        }

        m as f64 / (1 << m_bits) as f64
            * ((e - (e_max >> 1) as i32) as f64).exp2()
    }
}

pub fn load_signed(part: u32, e_bits: u32, m_bits: u32) -> f64 {
    let res = load_unsigned(part, e_bits, m_bits);

    if !res.is_nan() && (part & (1 << (e_bits + m_bits))) != 0 {
        -res
    } else {
        res
    }
}

#[cfg(test)]
mod test {
    use super::*;

    fn assert_float_equal(a: f64, b: f64) {
        assert!(
            (a - b).abs() < 0.001,
            "a={}, b={}",
            a,
            b
        );
    }

    #[test]
    fn test_load_unsigned() {
        assert_eq!(load_unsigned(0x30, 2, 4), f64::INFINITY);
        assert!(load_unsigned(0x3f, 2, 4).is_nan());

        assert_float_equal(load_unsigned(0, 3, 4), 0.0);
        assert_float_equal(load_unsigned(0x3555, 5, 10), 1.0 / 3.0);
    }

    #[test]
    fn test_load_signed() {
        assert_eq!(load_signed(0x70, 2, 4), -f64::INFINITY);
        assert!(load_signed(0x7f, 2, 4).is_nan());

        assert_float_equal(load_signed(0, 3, 4), 0.0);
        assert_float_equal(load_signed(0x3555, 5, 10), 1.0 / 3.0);
        assert_float_equal(load_signed(0xb555, 5, 10), -1.0 / 3.0);
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/make-enums.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python

# Copyright (C) 2018 Intel Corporation
# Copyright 2023 Neil Roberts

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from __future__ import (
    absolute_import, division, print_function, unicode_literals
)

# This script is used to generate enum_table.rs from vulkan.h. It
# is not run automatically as part of the build process but if need be
# it can be used to update the file as follows:
#
# echo | gcc -include "vulkan/vulkan.h" -E - | ./make-enums.py > enum_table.rs

import re
import sys
from mako.template import Template

ENUMS = [
    'VkPolygonMode',
    'VkCullModeFlagBits',
    'VkFrontFace',
    'VkPrimitiveTopology',
    'VkLogicOp',
    'VkBlendFactor',
    'VkBlendOp',
    'VkColorComponentFlagBits',
    'VkCompareOp',
    'VkStencilOp',
    'VkComponentTypeKHR',
    'VkScopeKHR',
]
VALUE_RE = re.compile(r'\s*\b(VK_(?:[A-Z0-9_]+))\b')
ENUM_START_RE = re.compile(r'\s*typedef\s+enum\s+(Vk[A-Za-z0-9]+)')
ENUM_END_RE = re.compile('}')
PREPROCESSOR_RE = re.compile(r' *#')

TEMPLATE="""\
// Automatically generated by make-enums.py
static ENUM_VALUES: [EnumValue; ${len(enums)}] = [
% for e in enums:
    EnumValue {
        name: "${e}",
        value: vk::${e} as i32
    },
% endfor
];"""


def get_enums(data):
    enums = set()
    in_enum = False

    for line in data:
        if PREPROCESSOR_RE.match(line):
            continue
        md = ENUM_START_RE.match(line)
        if md:
            in_enum = md.group(1) in ENUMS
        if ENUM_END_RE.match(line):
            in_enum = False
        if not in_enum:
            continue
        md = VALUE_RE.match(line)
        if md:
            enums.add(md.group(1))

    return sorted(enums)


def main():
    template = Template(TEMPLATE)
    print(template.render(enums = get_enums(sys.stdin)))


if __name__ == '__main__':
    main()

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/inspect.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018 Intel Corporation
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::format::Format;
use std::ffi::{c_int, c_void};
use std::fmt;

#[repr(C)]
pub struct Image {
    /// Width of the buffer
    pub width: c_int,
    /// Height of the buffer
    pub height: c_int,

    /// The stride in bytes from one row of the image to the next
    pub stride: usize,

    /// A description the format of each pixel in the buffer
    pub format: &'static Format,

    /// The buffer data
    pub data: *const c_void,
}

#[repr(C)]
pub struct Buffer {
    /// The binding number of the buffer
    pub binding: c_int,
    /// Size in bytes of the buffer
    pub size: usize,
    /// The buffer data
    pub data: *const c_void,
}

#[repr(C)]
pub struct Data {
    /// The color buffer
    pub color_buffer: Image,
    /// An array of buffers used as UBOs or SSBOs
    pub n_buffers: usize,
    pub buffers: *const Buffer,
}

/// A callback used to report the buffer and image data after
/// executing each test.
pub type Callback = extern "C" fn(
    data: &Data,
    user_data: *mut c_void,
);

/// A struct to combine the inspection callback with its user data pointer
#[derive(Clone)]
pub(crate) struct Inspector {
    callback: Callback,
    user_data: *mut c_void,
}

impl Inspector {
    pub fn new(callback: Callback, user_data: *mut c_void) -> Inspector {
        Inspector { callback, user_data }
    }

    pub fn inspect(&self, data: &Data) {
        (self.callback)(data, self.user_data);
    }
}

impl fmt::Debug for Inspector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Inspector")
            .field("callback", &(self.callback as usize))
            .field("user_data", &self.user_data)
            .finish()
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/util.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2013, 2014, 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::env;
use std::ffi::OsStr;

/// Align a value, only works on power-of-two alignments
#[inline]
pub const fn align(value: usize, alignment: usize) -> usize {
    debug_assert!(alignment.is_power_of_two());
    debug_assert!(alignment > 0);

    (value + alignment - 1) & !(alignment - 1)
}

/// Reads an environment variable and interprets its value as a boolean.
///
/// Recognizes 0/false/no and 1/true/yes. Other values result in the
/// default value.
pub fn env_var_as_boolean<K: AsRef<OsStr>>(
    var_name: K,
    default_value: bool,
) -> bool {
    match env::var(var_name) {
        Ok(value) => match value.as_str() {
            "1" | "true" | "yes" => true,
            "0" | "false" | "no" => false,
            _ => default_value,
        },
        Err(_) => default_value,
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::env_var_test::EnvVarLock;

    #[test]
    fn test_align() {
        assert_eq!(align(3, 4), 4);
        assert_eq!(align(4, 4), 4);
        assert_eq!(align(0, 8), 0);
        assert_eq!(align(9, 8), 16);
    }

    fn test_env_var_value<V: AsRef<OsStr>>(
        value: V,
        default_value: bool,
        expected_result: bool
    ) {
        const TEST_VAR: &'static str = "VKRUNNER_TEST_ENV_VAR";

        let _env_var_lock = EnvVarLock::new(&[
            (TEST_VAR, value)
        ]);

        assert_eq!(
            env_var_as_boolean(TEST_VAR, default_value),
            expected_result
        );
    }

    #[test]
    fn test_env_var_as_boolean() {
        test_env_var_value("1", false, true);
        test_env_var_value("true", false, true);
        test_env_var_value("yes", false, true);
        test_env_var_value("0", true, false);
        test_env_var_value("false", true, false);
        test_env_var_value("no", true, false);

        assert_eq!(
            env_var_as_boolean("ENVIRONMENT_VARIABLE_THAT_DOESNT_EXIST", true),
            true,
        );
        assert_eq!(
            env_var_as_boolean("ENVIRONMENT_VARIABLE_THAT_DOESNT_EXIST", false),
            false,
        );

        test_env_var_value("other_value", false, false);
        test_env_var_value("other_value", true, true);

        // Test using a byte sequence that isn’t valid UTF-8. I think
        // this can’t happen on Windows.
        #[cfg(unix)]
        {
            use std::os::unix::ffi::OsStrExt;

            test_env_var_value(
                OsStr::from_bytes(b"Echant\xe9 in Latin-1"),
                false,
                false,
            );
            test_env_var_value(
                OsStr::from_bytes(b"Echant\xe9 in Latin-1"),
                true,
                true,
            );
        }
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/result.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018 Intel Corporation
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::fmt;

/// Enum representing the possible results of a test.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(C)]
pub enum Result {
    Pass,
    Fail,
    Skip,
}

impl Result {
    /// Merge this result with another one. If either test is skipped
    /// then the value of the other result is returned. Otherwise if
    /// either of the tests failed then the global result is a
    /// failure. Finally if both tests passed then the global result
    /// is a pass.
    pub fn merge(self, other: Result) -> Result {
        match self {
            Result::Pass => {
                if other == Result::Skip {
                    self
                } else {
                    other
                }
            },
            Result::Fail => Result::Fail,
            Result::Skip => other,
        }
    }

    // Returns the name with a NULL terminator. This is needed because
    // there is a function in the public API which returns a static
    // string to C code.
    fn name_with_terminator(self) -> &'static str {
        match self {
            Result::Fail => "fail\0",
            Result::Skip => "skip\0",
            Result::Pass => "pass\0",
        }
    }

    /// Return either `"fail"`, `"skip"` or `"pass"` to describe the
    /// result. The result is a static string. You can also use the
    /// [to_string](ToString::to_string) method to get an owned string
    /// because [Result] implements [Display](std::fmt::Display).
    pub fn name(self) -> &'static str {
        let name = self.name_with_terminator();
        &name[0..name.len() - 1]
    }
}

impl fmt::Display for Result {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name())
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_merge() {
        assert_eq!(Result::Fail.merge(Result::Fail), Result::Fail);
        assert_eq!(Result::Fail.merge(Result::Skip), Result::Fail);
        assert_eq!(Result::Fail.merge(Result::Pass), Result::Fail);
        assert_eq!(Result::Skip.merge(Result::Fail), Result::Fail);
        assert_eq!(Result::Skip.merge(Result::Skip), Result::Skip);
        assert_eq!(Result::Skip.merge(Result::Pass), Result::Pass);
        assert_eq!(Result::Pass.merge(Result::Fail), Result::Fail);
        assert_eq!(Result::Pass.merge(Result::Skip), Result::Pass);
        assert_eq!(Result::Pass.merge(Result::Pass), Result::Pass);
    }

    #[test]
    fn test_name() {
        assert_eq!(Result::Fail.name(), "fail");
        assert_eq!(Result::Skip.name(), "skip");
        assert_eq!(Result::Pass.name(), "pass");

        for res in [Result::Fail, Result::Skip, Result::Pass] {
            assert_eq!(&res.to_string(), res.name());
        }
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/env_var_test.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Helper to serialise unit tests that set environment variables so
//! that there won’t be a race condition if the tests are run in
//! parallel.

use std::sync::{Mutex, MutexGuard};
use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};

// Mutex to make sure only one test is testing environment variables at a time
static LOCK: Mutex<()> = Mutex::new(());

/// Struct to help make unit tests that set environment variables.
/// Only one EnvValLock can exist in the process at any one time. If a
/// thread tries to construct a second one it will block until the
/// first one is dropped. The environment variables will be restored
/// when the EnvVarLock is dropped.
pub struct EnvVarLock {
    old_values: HashMap<&'static str, Option<OsString>>,
    _mutex_lock: MutexGuard<'static, ()>,
}

impl EnvVarLock {
    /// Construct a new EnvVarLock and set the environment variables
    /// from the hash table. This will block if another EnvVarLock
    /// already exists. When the object is dropped the environment
    /// variables will be restored to their original values.
    ///
    /// Note that the object has no useful methods or members but you
    /// need to keep it alive in order to hold the mutex lock. One way
    /// to do this is to put the lock in a local variable prefixed
    /// with `_`:
    ///
    /// ```
    /// let _env_var_lock = EnvVarLock::new(&[
    ///     ("MY_ENVIRONMENT_VARIABLE", "true")
    /// ]);
    /// assert_eq!(std::env::var("MY_ENVIRONMENT_VARIABLE").unwrap(), "true");
    /// ```
    pub fn new<V: AsRef<OsStr>>(
        variables: &[(&'static str, V)]
    ) -> EnvVarLock {
        let mutex_lock = LOCK.lock().unwrap();

        let old_values: HashMap<&'static str, Option<OsString>> = variables
            .iter()
            .map(|(variable, value)| {
                let old_value = env::var_os(variable);
                env::set_var(*variable, value);
                (*variable, old_value)
            })
            .collect();

        EnvVarLock { old_values, _mutex_lock: mutex_lock }
    }
}

impl Drop for EnvVarLock {
    fn drop(&mut self) {
        for (variable, value) in self.old_values.iter() {
            match value {
                Some(value) => env::set_var(variable, value),
                None => env::remove_var(variable),
            }
        }
    }
}

#[test]
fn env_var_lock_test() {
    {
        let _env_var_lock = EnvVarLock::new(&[
            ("ENV_VAR_LOCK_TEST_ENVIRONMENT_VARIABLE", "true")
        ]);
        assert_eq!(
            std::env::var("ENV_VAR_LOCK_TEST_ENVIRONMENT_VARIABLE").unwrap(),
            "true"
        );
    }

    assert!(matches!(
        std::env::var("ENV_VAR_LOCK_TEST_ENVIRONMENT_VARIABLE"),
        Err(std::env::VarError::NotPresent),
    ));
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/half_float.rs:
--------------------------------------------------------------------------------

```rust
// Copyright (c) The Piglit project 2007
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// on the rights to use, copy, modify, merge, publish, distribute, sub
// license, and/or sell copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
// VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

use crate::small_float;

// Convert a 4-byte float to a 2-byte half float.
// Based on code from:
// http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
//
// Taken over from Piglit which took it from Mesa.
pub fn from_f32(val: f32) -> u16 {
    let fi = val.to_bits();
    let flt_m = fi & 0x7fffff;
    let flt_e = (fi >> 23) & 0xff;
    // sign bit
    let flt_s = (fi >> 31) & 0x1;

    let e;
    let m;

    // handle special cases
    if flt_e == 0 && flt_m == 0 {
        // zero
        m = 0;
        e = 0;
    } else if (flt_e == 0) && (flt_m != 0) {
        // denorm -- denorm float maps to 0 half
        m = 0;
        e = 0;
    } else if (flt_e == 0xff) && (flt_m == 0) {
        // infinity
        m = 0;
        e = 31;
    } else if (flt_e == 0xff) && (flt_m != 0) {
        // NaN
        m = 1;
        e = 31;
    } else {
        // regular number
        let new_exp = flt_e as i32 - 127;
        if new_exp < -24 {
            // this maps to 0
            m = 0;
            e = 0;
        } else if new_exp < -14 {
            // this maps to a denorm
            // 2^-exp_val
            let exp_val = (-14 - new_exp) as u32;

            e = 0;

            match exp_val {
                0 => m = 0,
                1 => m = 512 + (flt_m >> 14),
                2 => m = 256 + (flt_m >> 15),
                3 => m = 128 + (flt_m >> 16),
                4 => m = 64 + (flt_m >> 17),
                5 => m = 32 + (flt_m >> 18),
                6 => m = 16 + (flt_m >> 19),
                7 => m = 8 + (flt_m >> 20),
                8 => m = 4 + (flt_m >> 21),
                9 => m = 2 + (flt_m >> 22),
                10 => m = 1,
                _ => unreachable!(),
            }
        } else if new_exp > 15 {
            // map this value to infinity
            m = 0;
            e = 31;
        } else {
            /* regular */
            e = (new_exp + 15) as u32;
            m = flt_m >> 13;
        }
    }

    ((flt_s << 15) | (e << 10) | m) as u16
}

pub fn to_f64(half: u16) -> f64 {
    small_float::load_signed(half as u32, 5, 10)
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_from_f32() {
        assert_eq!(from_f32(0.0), 0);
        assert_eq!(from_f32(1.0 / 3.0), 0x3555);
        assert_eq!(from_f32(-1.0 / 3.0), 0xb555);
        assert_eq!(from_f32(f32::INFINITY), 0x7c00);
        assert_eq!(from_f32(-f32::INFINITY), 0xfc00);
        assert_eq!(from_f32(f32::NAN), 0x7c01);
        assert_eq!(from_f32(f32::MAX), 0x7c00);
    }

    fn assert_float_equal(a: f64, b: f64) {
        assert!(
            (a - b).abs() < 0.001,
            "a={}, b={}",
            a,
            b
        );
    }

    #[test]
    fn test_to_f64() {
        assert_eq!(to_f64(0x7c00), f64::INFINITY);
        assert_eq!(to_f64(0xfc00), -f64::INFINITY);
        assert_float_equal(to_f64(0x3555), 1.0 / 3.0);
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_av1std_decode.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_
#define VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codec_av1std_decode is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codec_av1std_decode 1
#include "vulkan_video_codec_av1std.h"

#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)

#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0
#define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_decode"
typedef struct StdVideoDecodeAV1PictureInfoFlags {
    uint32_t    error_resilient_mode : 1;
    uint32_t    disable_cdf_update : 1;
    uint32_t    use_superres : 1;
    uint32_t    render_and_frame_size_different : 1;
    uint32_t    allow_screen_content_tools : 1;
    uint32_t    is_filter_switchable : 1;
    uint32_t    force_integer_mv : 1;
    uint32_t    frame_size_override_flag : 1;
    uint32_t    buffer_removal_time_present_flag : 1;
    uint32_t    allow_intrabc : 1;
    uint32_t    frame_refs_short_signaling : 1;
    uint32_t    allow_high_precision_mv : 1;
    uint32_t    is_motion_mode_switchable : 1;
    uint32_t    use_ref_frame_mvs : 1;
    uint32_t    disable_frame_end_update_cdf : 1;
    uint32_t    allow_warped_motion : 1;
    uint32_t    reduced_tx_set : 1;
    uint32_t    reference_select : 1;
    uint32_t    skip_mode_present : 1;
    uint32_t    delta_q_present : 1;
    uint32_t    delta_lf_present : 1;
    uint32_t    delta_lf_multi : 1;
    uint32_t    segmentation_enabled : 1;
    uint32_t    segmentation_update_map : 1;
    uint32_t    segmentation_temporal_update : 1;
    uint32_t    segmentation_update_data : 1;
    uint32_t    UsesLr : 1;
    uint32_t    usesChromaLr : 1;
    uint32_t    apply_grain : 1;
    uint32_t    reserved : 3;
} StdVideoDecodeAV1PictureInfoFlags;

typedef struct StdVideoDecodeAV1PictureInfo {
    StdVideoDecodeAV1PictureInfoFlags    flags;
    StdVideoAV1FrameType                 frame_type;
    uint32_t                             current_frame_id;
    uint8_t                              OrderHint;
    uint8_t                              primary_ref_frame;
    uint8_t                              refresh_frame_flags;
    uint8_t                              reserved1;
    StdVideoAV1InterpolationFilter       interpolation_filter;
    StdVideoAV1TxMode                    TxMode;
    uint8_t                              delta_q_res;
    uint8_t                              delta_lf_res;
    uint8_t                              SkipModeFrame[STD_VIDEO_AV1_SKIP_MODE_FRAMES];
    uint8_t                              coded_denom;
    uint8_t                              reserved2[3];
    uint8_t                              OrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES];
    uint32_t                             expectedFrameId[STD_VIDEO_AV1_NUM_REF_FRAMES];
    const StdVideoAV1TileInfo*           pTileInfo;
    const StdVideoAV1Quantization*       pQuantization;
    const StdVideoAV1Segmentation*       pSegmentation;
    const StdVideoAV1LoopFilter*         pLoopFilter;
    const StdVideoAV1CDEF*               pCDEF;
    const StdVideoAV1LoopRestoration*    pLoopRestoration;
    const StdVideoAV1GlobalMotion*       pGlobalMotion;
    const StdVideoAV1FilmGrain*          pFilmGrain;
} StdVideoDecodeAV1PictureInfo;

typedef struct StdVideoDecodeAV1ReferenceInfoFlags {
    uint32_t    disable_frame_end_update_cdf : 1;
    uint32_t    segmentation_enabled : 1;
    uint32_t    reserved : 30;
} StdVideoDecodeAV1ReferenceInfoFlags;

typedef struct StdVideoDecodeAV1ReferenceInfo {
    StdVideoDecodeAV1ReferenceInfoFlags    flags;
    uint8_t                                frame_type;
    uint8_t                                RefFrameSignBias;
    uint8_t                                OrderHint;
    uint8_t                                SavedOrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES];
} StdVideoDecodeAV1ReferenceInfo;


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/compiler/fake_process.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! This module is just for the unit tests. It makes an alternative
//! version of the Stdio, Command and Output structs from std::process
//! that run a fake compiler so we can get code coverage in
//! compiler.rs without depending a real GLSL compiler.

use std::process::Stdio;
use std::io::{Write, BufWriter, BufReader, BufRead};
use std::fs::File;
use std::ffi::OsStr;
use std::num::ParseIntError;

pub struct ExitStatus {
    success: bool,
}

pub struct Output {
    pub status: ExitStatus,
    pub stdout: Vec<u8>,
    pub stderr: Vec<u8>,
}

pub struct Command {
    args: Vec<String>,
}

impl Command {
    pub fn new<S: AsRef<OsStr>>(_program: S) -> Command {
        Command {
            args: Vec::new(),
        }
    }

    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
        self.args.push(arg.as_ref().to_str().unwrap().to_string());

        self
    }

    pub fn args<I, S>(&mut self, args: I) -> &mut Command
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for arg in args {
            self.arg(arg);
        }

        self
    }

    pub fn stdout<T: Into<Stdio>>(&mut self, _cfg: T) -> &mut Command {
        self
    }

    pub fn stderr<T: Into<Stdio>>(&mut self, _cfg: T) -> &mut Command {
        self
    }

    pub fn output(&mut self) -> std::io::Result<Output> {
        let mut inputs = Vec::new();
        let mut output = None;
        let mut stdout = Vec::new();
        let mut stderr = Vec::new();
        let mut success = true;

        let mut args = self.args.iter();

        while let Some(arg) = args.next() {
            match arg.as_str() {
                "--quiet" => writeln!(&mut stdout, "quiet").unwrap(),
                "-V" => writeln!(&mut stdout, "vulkan_spirv").unwrap(),
                "--target-env" => {
                    writeln!(
                        &mut stdout,
                        "target_env: {}",
                        args.next().unwrap()
                    ).unwrap();
                },
                "-S" => {
                    writeln!(&mut stdout, "stage: {}", args.next().unwrap())
                        .unwrap();
                },
                "-o" => output = Some(args.next().unwrap()),
                other_arg if other_arg.starts_with("-") => {
                    unreachable!("unexpected arg: {}", other_arg);
                },
                input_file => inputs.push(input_file.to_owned()),
            }
        }

        match output {
            None => {
                // Pretend to output the disassembly
                writeln!(&mut stdout, "disassembly").unwrap();
            },
            Some(output) => {
                if let Err(e) = copy_inputs(&inputs, &output) {
                    writeln!(&mut stderr, "{}", e).unwrap();
                    success = false;
                }
            }
        }

        Ok(Output {
            status: ExitStatus { success },
            stdout,
            stderr,
        })
    }
}

impl ExitStatus {
    pub fn success(&self) -> bool {
        self.success
    }
}

fn copy_inputs(inputs: &[String], output: &str) -> Result<(), ParseIntError> {
    let mut output = BufWriter::new(File::create(output).unwrap());

    for input in inputs {
        let input = File::open(input).unwrap();

        for line in BufReader::new(input).lines() {
            for byte in line.unwrap().split_whitespace() {
                let byte_array = [u8::from_str_radix(byte, 16)?];
                output.write_all(&byte_array).unwrap();
            }
        }
    }

    Ok(())
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/make-formats.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python

# Copyright (C) 2018 Intel Corporation
# Copyright 2023 Neil Roberts

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from __future__ import (
    absolute_import, division, print_function, unicode_literals
)

# This script is used to generate format_table.rs from vulkan.h. It is
# not run automatically as part of the build process but if need be it
# can be used to update the file as follows:
#
# ./make-formats.py < /usr/include/vulkan/vulkan.h > format_table.rs

import re
import sys
from mako.template import Template

FORMAT_RE = re.compile(r'\bVK_FORMAT_([A-Z0-9_]+)\s*=\s*((?:0x)?[a-fA-F0-9]+)')
SKIP_RE = re.compile(r'(?:_BLOCK(?:_IMG)?|_KHR|^UNDEFINED|'
                     r'^RANGE_SIZE|^MAX_ENUM|_RANGE)$')
COMPONENT_RE = re.compile('([A-Z]+)([0-9]+)')
COMPONENTS_RE = re.compile('(?:[A-Z][0-9]+)+$')
STUB_RE = re.compile('X([0-9]+)$')
PACK_RE = re.compile('PACK([0-9]+)$')
MODE_RE = re.compile('(?:[US](?:NORM|SCALED|INT|FLOAT)|SRGB)$')

TEMPLATE="""\
// Automatically generated by make-formats.py

static FORMATS: [Format; ${len(formats)}] = [
% for format in formats:
    Format {
        vk_format: vk::VK_FORMAT_${format['name']},
        name: "${format['name']}",
        % if format['packed_size'] is None:
        packed_size: None,
        % else:
        packed_size: Some(unsafe {
            NonZeroUsize::new_unchecked(${format['packed_size']})
        }),
        % endif
        n_parts: ${len(format['components'])},
        parts: [
            % for letter, size, mode in format['components']:
            Part {
                bits: ${size},
                component: Component::${letter},
                mode: Mode::${mode},
            },
            % endfor
            % for _ in range(len(format['components']), 4):
            // stub to fill the array
            Part { bits: 0, component: Component::R, mode: Mode::UNORM },
            % endfor
        ]
    },
% endfor
];"""


def get_format_names(data):
    in_enum = False

    for line in data:
        if line.startswith('typedef enum VkFormat '):
            in_enum = True
        elif line.startswith('}'):
            in_enum = False
        if not in_enum:
            continue

        md = FORMAT_RE.search(line)
        if md is None:
            continue
        name = md.group(1)
        if SKIP_RE.search(name):
            continue
        yield name, int(md.group(2), base=0)


def get_formats(data):
    for name, value in sorted(set(get_format_names(data))):
        parts = name.split('_')

        components, packed_size = get_components(parts)

        if components is None:
            continue

        yield {'name': name,
               'value': value,
               'packed_size': packed_size,
               'components': components}


def get_components(parts):
    packed_size = None
    components = []

    i = 0
    while i < len(parts):
        md = STUB_RE.match(parts[i])
        if md:
            components.append(('X', int(md.group(1)), 'UNORM'))
            i += 1
            continue

        md = COMPONENTS_RE.match(parts[i])
        if md:
            if i + 2 > len(parts):
                return None, None
            mode_md = MODE_RE.match(parts[i + 1])
            if mode_md is None:
                return None, None

            comps = [(md.group(1), int(md.group(2)), parts[i + 1])
                     for md in COMPONENT_RE.finditer(parts[i])]

            for letter, size, mode in comps:
                if letter not in "RGBADSX":
                    return None, None

            components.extend(comps)
            i += 2
            continue

        md = PACK_RE.match(parts[i])
        if md:
            packed_size = int(md.group(1))
            i += 1
            continue

        return None, None

    return components, packed_size


def main():
    template = Template(TEMPLATE)
    print(template.render(formats = list(get_formats(sys.stdin))))


if __name__ == '__main__':
    main()

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/source.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018 Intel Corporation
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::path::PathBuf;

/// Struct representing the requested source for the data of a
/// [Source]. This can either be a filename to open and read
/// or directly a string containing the source code.
#[derive(Clone, Debug)]
pub(crate) enum Data {
    File { filename: PathBuf },
    String { source: String },
}

#[derive(Clone, Debug)]
/// A token replacement that should be used for the source. The reader
/// should replace any occurences of `token` in the source with the
/// string in `replacement`.
pub(crate) struct TokenReplacement {
    pub token: String,
    pub replacement: String,
}

/// A source for a shader script. The [Source] struct just contains
/// the details of where the data is stored along with any token
/// replacements to be used while reading the data.
#[derive(Clone, Debug)]
pub struct Source {
    token_replacements: Vec<TokenReplacement>,
    data: Data,
}

type TokenReplacementIter<'a> = std::slice::Iter<'a, TokenReplacement>;

impl Source {
    fn from_data(data: Data) -> Source {
        Source {
            token_replacements: Vec::new(),
            data,
        }
    }

    /// Creates a source that will read lines from the given string.
    pub fn from_string(source: String) -> Source {
        Self::from_data(Data::String { source })
    }

    /// Creates a source that will read lines from the given file.
    pub fn from_file(filename: PathBuf) -> Source {
        Self::from_data(Data::File { filename })
    }

    /// Adds a token replacement to the source. When lines are read
    /// from the source, any mentions of the token will be replaced
    /// with the replacement. The replacement can also contain tokens
    /// which will be replaced as well. This can cause the line
    /// reading to fail and return an error if it causes an infinite
    /// loop.
    pub fn add_token_replacement(
        &mut self,
        token: String,
        replacement: String,
    ) {
        self.token_replacements.push(TokenReplacement { token, replacement });
    }

    /// Return an iterator over the token replacements that were
    /// previously set with
    /// [add_token_replacement](Source::add_token_replacement).
    pub(crate) fn token_replacements(&self) -> TokenReplacementIter {
        self.token_replacements.iter()
    }

    /// Get the data that the source points to.
    pub(crate) fn data(&self) -> &Data {
        &self.data
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_constructors() {
        let source = Source::from_string("my script".to_owned());
        assert!(matches!(
            source.data(),
            Data::String { source } if source == "my script"
        ));

        let source = Source::from_file(
            "my_script.shader_test".to_owned().into()
        );
        assert!(matches!(
            source.data(),
            Data::File { filename }
            if filename.to_str().unwrap() == "my_script.shader_test",
        ));
    }

    #[test]
    fn test_token_replacements() {
        let mut source = Source::from_string("test".to_string());

        assert_eq!(source.token_replacements.len(), 0);

        source.add_token_replacement("COLOUR".to_string(), "0xf00".to_string());

        assert_eq!(source.token_replacements.len(), 1);
        assert_eq!(source.token_replacements[0].token, "COLOUR");
        assert_eq!(source.token_replacements[0].replacement, "0xf00");

        let mut iter = source.token_replacements();
        assert_eq!(iter.next().unwrap().token, "COLOUR");
        assert!(iter.next().is_none());

        source.add_token_replacement("X".to_string(), "12".to_string());

        assert_eq!(source.token_replacements.len(), 2);
        assert_eq!(source.token_replacements[0].token, "COLOUR");
        assert_eq!(source.token_replacements[0].replacement, "0xf00");
        assert_eq!(source.token_replacements[1].token, "X");
        assert_eq!(source.token_replacements[1].replacement, "12");

        let mut iter = source.token_replacements();
        assert_eq!(iter.next().unwrap().token, "COLOUR");
        assert_eq!(iter.next().unwrap().token, "X");
        assert!(iter.next().is_none());
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/config.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2018 Intel Corporation
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::logger::{self, Logger};
use crate::inspect;
use std::ffi::c_void;
use std::ptr;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::fmt;

pub type ErrorCallback = logger::WriteCallback;

pub struct Config {
    show_disassembly: bool,
    device_id: Option<usize>,

    error_cb: Option<logger::WriteCallback>,
    inspect_cb: Option<inspect::Callback>,
    user_data: *mut c_void,

    logger: Cell<Option<Rc<RefCell<Logger>>>>,
}

impl Config {
    pub fn new() -> Config {
        Config {
            show_disassembly: false,
            device_id: None,
            error_cb: None,
            inspect_cb: None,
            user_data: ptr::null_mut(),
            logger: Cell::new(None),
        }
    }

    /// Sets whether the SPIR-V disassembly of the shaders should be
    /// shown when a script is run. The disassembly will be shown on
    /// the standard out or it will be passed to the `error_cb` if one
    /// has been set. The disassembly is generated with the
    /// `spirv-dis` program which needs to be found in the path or it
    /// can be specified with the `PIGLIT_SPIRV_DIS_BINARY`
    /// environment variable.
    pub fn set_show_disassembly(&mut self, show_disassembly: bool) {
        self.show_disassembly = show_disassembly;
    }

    /// Sets or removes a callback that will receive error messages
    /// generated during the script execution. The callback will be
    /// invoked one line at a time without the trailing newline
    /// terminator. If no callback is specified then the output will
    /// be printed on the standard output instead. The callback can
    /// later be removed by passing `None`.
    pub fn set_error_cb(&mut self, error_cb: Option<ErrorCallback>) {
        self.error_cb = error_cb;
        self.reset_logger();
    }

    /// Sets or removes an inspection callback. The callback will be
    /// invoked after executing a script so that the application can
    /// have a chance to examine the framebuffer and any storage or
    /// uniform buffers created by the script.
    pub fn set_inspect_cb(&mut self, inspect_cb: Option<inspect::Callback>) {
        self.inspect_cb = inspect_cb;
    }

    /// Sets a pointer that will be passed to the `error_cb` and the
    /// `inspect_cb`.
    pub fn set_user_data(&mut self, user_data: *mut c_void) {
        self.user_data = user_data;
        self.reset_logger();
    }

    /// Sets or removes a device number to pick out of the list of
    /// `vkPhysicalDevice`s returned by `vkEnumeratePhysicalDevices`.
    /// The device will still be checked to see if it is compatible
    /// with the script and the test will report Skip if not. If no
    /// device ID is set then VkRunner will pick the first one that is
    /// compatible with the script.
    pub fn set_device_id(&mut self, device_id: Option<usize>) {
        self.device_id = device_id;
    }

    /// Get a logger that will write to the current `error_cb` of the
    /// `Config`. The logger will be shared between calls to this
    /// until the callback is changed.
    pub(crate) fn logger(&self) -> Rc<RefCell<Logger>> {
        let logger = self.logger.take().unwrap_or_else(|| {
            Rc::new(RefCell::new(Logger::new(self.error_cb, self.user_data)))
        });

        self.logger.set(Some(Rc::clone(&logger)));

        logger
    }

    pub(crate) fn inspector(&self) -> Option<inspect::Inspector> {
        self.inspect_cb.map(|cb| inspect::Inspector::new(cb, self.user_data))
    }

    pub(crate) fn show_disassembly(&self) -> bool {
        self.show_disassembly
    }

    pub(crate) fn device_id(&self) -> Option<usize> {
        self.device_id
    }

    fn reset_logger(&self) {
        // Reset the logger back to None so that it will be
        // reconstructed the next time it is requested.
        self.logger.take();
    }
}

// Need to implement this manually because the derive macro can’t
// handle Cells
impl fmt::Debug for Config {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Config")
            .field("show_disassembly", &self.show_disassembly)
            .field("device_id", &self.device_id)
            .field("user_data", &self.user_data)
            .finish()
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/make-vulkan-funcs-data.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python

# Copyright 2023 Neil Roberts

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from __future__ import (
    absolute_import, division, print_function, unicode_literals
)

# This script is used to generate vulkan_funcs_data.rs. It is not run
# automatically as part of the build process but if need be it can be
# used to update the file as follows:
#
# ./make-vulkan-funcs-data.py > vulkan_funcs_data.rs

from mako.template import Template


CORE_FUNCS = [
    "vkGetInstanceProcAddr",
    "vkCreateInstance",
    "vkEnumerateInstanceExtensionProperties",
]


INSTANCE_FUNCS = [
    "vkCreateDevice",
    "vkDestroyInstance",
    "vkEnumerateDeviceExtensionProperties",
    "vkEnumeratePhysicalDevices",
    "vkGetDeviceProcAddr",
    "vkGetPhysicalDeviceFeatures",
    "vkGetPhysicalDeviceFeatures2KHR",
    "vkGetPhysicalDeviceFormatProperties",
    "vkGetPhysicalDeviceMemoryProperties",
    "vkGetPhysicalDeviceProperties",
    "vkGetPhysicalDeviceProperties2",
    "vkGetPhysicalDeviceQueueFamilyProperties",
    "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR",
]


DEVICE_FUNCS = [
    "vkAllocateCommandBuffers",
    "vkAllocateDescriptorSets",
    "vkAllocateMemory",
    "vkBeginCommandBuffer",
    "vkBindBufferMemory",
    "vkBindImageMemory",
    "vkCmdBeginRenderPass",
    "vkCmdBindDescriptorSets",
    "vkCmdBindIndexBuffer",
    "vkCmdBindPipeline",
    "vkCmdBindVertexBuffers",
    "vkCmdClearAttachments",
    "vkCmdCopyBufferToImage",
    "vkCmdCopyImageToBuffer",
    "vkCmdDispatch",
    "vkCmdDraw",
    "vkCmdDrawIndexed",
    "vkCmdDrawIndexedIndirect",
    "vkCmdEndRenderPass",
    "vkCmdPipelineBarrier",
    "vkCmdPushConstants",
    "vkCmdSetScissor",
    "vkCmdSetViewport",
    "vkCreateBuffer",
    "vkCreateCommandPool",
    "vkCreateComputePipelines",
    "vkCreateDescriptorPool",
    "vkCreateDescriptorSetLayout",
    "vkCreateFence",
    "vkCreateFramebuffer",
    "vkCreateGraphicsPipelines",
    "vkCreateImage",
    "vkCreateImageView",
    "vkCreatePipelineCache",
    "vkCreatePipelineLayout",
    "vkCreateRenderPass",
    "vkCreateSampler",
    "vkCreateSemaphore",
    "vkCreateShaderModule",
    "vkDestroyBuffer",
    "vkDestroyCommandPool",
    "vkDestroyDescriptorPool",
    "vkDestroyDescriptorSetLayout",
    "vkDestroyDevice",
    "vkDestroyFence",
    "vkDestroyFramebuffer",
    "vkDestroyImage",
    "vkDestroyImageView",
    "vkDestroyPipeline",
    "vkDestroyPipelineCache",
    "vkDestroyPipelineLayout",
    "vkDestroyRenderPass",
    "vkDestroySampler",
    "vkDestroySemaphore",
    "vkDestroyShaderModule",
    "vkEndCommandBuffer",
    "vkFlushMappedMemoryRanges",
    "vkFreeCommandBuffers",
    "vkFreeDescriptorSets",
    "vkFreeMemory",
    "vkGetBufferMemoryRequirements",
    "vkGetDeviceQueue",
    "vkGetImageMemoryRequirements",
    "vkGetImageSubresourceLayout",
    "vkInvalidateMappedMemoryRanges",
    "vkMapMemory",
    "vkQueueSubmit",
    "vkQueueWaitIdle",
    "vkResetFences",
    "vkUnmapMemory",
    "vkUpdateDescriptorSets",
    "vkWaitForFences",
]


TEMPLATE = """\
// Automatically generated by make-vulkan-funcs-data.py

#[derive(Debug, Clone)]
#[allow(non_snake_case)]
pub struct Library {
    lib_vulkan: *const c_void,
    lib_vulkan_is_fake: bool,

% for func in core_funcs:
    pub ${func}: vk::PFN_${func},
% endfor
}

#[derive(Debug, Clone)]
#[allow(non_snake_case)]
pub struct Instance {
% for func in instance_funcs:
    pub ${func}: vk::PFN_${func},
% endfor
}

#[derive(Debug, Clone)]
#[allow(non_snake_case)]
#[allow(dead_code)]
pub struct Device {
% for func in device_funcs:
    pub ${func}: vk::PFN_${func},
% endfor
}

impl Instance {
    pub unsafe fn new(
        get_instance_proc_cb: GetInstanceProcFunc,
        user_data: *const c_void,
    ) -> Instance {
        Instance {
% for func in instance_funcs:
            ${func}: std::mem::transmute(get_instance_proc_cb(
                "${func}\\0".as_ptr().cast(),
                user_data,
            )),
% endfor
        }
    }
}

#[allow(dead_code)]
impl Device {
    pub fn new(instance: &Instance, device: vk::VkDevice) -> Device {
        Device {
% for func in device_funcs:
            ${func}: unsafe {
                std::mem::transmute(instance.vkGetDeviceProcAddr.unwrap()(
                    device,
                    "${func}\\0".as_ptr().cast(),
                ))
            },
% endfor
        }
    }
}
"""


def main():
    template = Template(TEMPLATE)
    print(template.render(core_funcs = CORE_FUNCS,
                          instance_funcs = INSTANCE_FUNCS,
                          device_funcs = DEVICE_FUNCS),
          end="")


if __name__ == '__main__':
    main()

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_av1std_encode.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODEC_AV1STD_ENCODE_H_
#define VULKAN_VIDEO_CODEC_AV1STD_ENCODE_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codec_av1std_encode is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codec_av1std_encode 1
#include "vulkan_video_codec_av1std.h"

#define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)

#define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0
#define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_encode"
typedef struct StdVideoEncodeAV1DecoderModelInfo {
    uint8_t     buffer_delay_length_minus_1;
    uint8_t     buffer_removal_time_length_minus_1;
    uint8_t     frame_presentation_time_length_minus_1;
    uint8_t     reserved1;
    uint32_t    num_units_in_decoding_tick;
} StdVideoEncodeAV1DecoderModelInfo;

typedef struct StdVideoEncodeAV1ExtensionHeader {
    uint8_t    temporal_id;
    uint8_t    spatial_id;
} StdVideoEncodeAV1ExtensionHeader;

typedef struct StdVideoEncodeAV1OperatingPointInfoFlags {
    uint32_t    decoder_model_present_for_this_op : 1;
    uint32_t    low_delay_mode_flag : 1;
    uint32_t    initial_display_delay_present_for_this_op : 1;
    uint32_t    reserved : 29;
} StdVideoEncodeAV1OperatingPointInfoFlags;

typedef struct StdVideoEncodeAV1OperatingPointInfo {
    StdVideoEncodeAV1OperatingPointInfoFlags    flags;
    uint16_t                                    operating_point_idc;
    uint8_t                                     seq_level_idx;
    uint8_t                                     seq_tier;
    uint32_t                                    decoder_buffer_delay;
    uint32_t                                    encoder_buffer_delay;
    uint8_t                                     initial_display_delay_minus_1;
} StdVideoEncodeAV1OperatingPointInfo;

typedef struct StdVideoEncodeAV1PictureInfoFlags {
    uint32_t    error_resilient_mode : 1;
    uint32_t    disable_cdf_update : 1;
    uint32_t    use_superres : 1;
    uint32_t    render_and_frame_size_different : 1;
    uint32_t    allow_screen_content_tools : 1;
    uint32_t    is_filter_switchable : 1;
    uint32_t    force_integer_mv : 1;
    uint32_t    frame_size_override_flag : 1;
    uint32_t    buffer_removal_time_present_flag : 1;
    uint32_t    allow_intrabc : 1;
    uint32_t    frame_refs_short_signaling : 1;
    uint32_t    allow_high_precision_mv : 1;
    uint32_t    is_motion_mode_switchable : 1;
    uint32_t    use_ref_frame_mvs : 1;
    uint32_t    disable_frame_end_update_cdf : 1;
    uint32_t    allow_warped_motion : 1;
    uint32_t    reduced_tx_set : 1;
    uint32_t    skip_mode_present : 1;
    uint32_t    delta_q_present : 1;
    uint32_t    delta_lf_present : 1;
    uint32_t    delta_lf_multi : 1;
    uint32_t    segmentation_enabled : 1;
    uint32_t    segmentation_update_map : 1;
    uint32_t    segmentation_temporal_update : 1;
    uint32_t    segmentation_update_data : 1;
    uint32_t    UsesLr : 1;
    uint32_t    usesChromaLr : 1;
    uint32_t    show_frame : 1;
    uint32_t    showable_frame : 1;
    uint32_t    reserved : 3;
} StdVideoEncodeAV1PictureInfoFlags;

typedef struct StdVideoEncodeAV1PictureInfo {
    StdVideoEncodeAV1PictureInfoFlags          flags;
    StdVideoAV1FrameType                       frame_type;
    uint32_t                                   frame_presentation_time;
    uint32_t                                   current_frame_id;
    uint8_t                                    order_hint;
    uint8_t                                    primary_ref_frame;
    uint8_t                                    refresh_frame_flags;
    uint8_t                                    coded_denom;
    uint16_t                                   render_width_minus_1;
    uint16_t                                   render_height_minus_1;
    StdVideoAV1InterpolationFilter             interpolation_filter;
    StdVideoAV1TxMode                          TxMode;
    uint8_t                                    delta_q_res;
    uint8_t                                    delta_lf_res;
    uint8_t                                    ref_order_hint[STD_VIDEO_AV1_NUM_REF_FRAMES];
    int8_t                                     ref_frame_idx[STD_VIDEO_AV1_REFS_PER_FRAME];
    uint8_t                                    reserved1[3];
    uint32_t                                   delta_frame_id_minus_1[STD_VIDEO_AV1_REFS_PER_FRAME];
    const StdVideoAV1TileInfo*                 pTileInfo;
    const StdVideoAV1Quantization*             pQuantization;
    const StdVideoAV1Segmentation*             pSegmentation;
    const StdVideoAV1LoopFilter*               pLoopFilter;
    const StdVideoAV1CDEF*                     pCDEF;
    const StdVideoAV1LoopRestoration*          pLoopRestoration;
    const StdVideoAV1GlobalMotion*             pGlobalMotion;
    const StdVideoEncodeAV1ExtensionHeader*    pExtensionHeader;
    const uint32_t*                            pBufferRemovalTimes;
} StdVideoEncodeAV1PictureInfo;

typedef struct StdVideoEncodeAV1ReferenceInfoFlags {
    uint32_t    disable_frame_end_update_cdf : 1;
    uint32_t    segmentation_enabled : 1;
    uint32_t    reserved : 30;
} StdVideoEncodeAV1ReferenceInfoFlags;

typedef struct StdVideoEncodeAV1ReferenceInfo {
    StdVideoEncodeAV1ReferenceInfoFlags        flags;
    uint32_t                                   RefFrameId;
    StdVideoAV1FrameType                       frame_type;
    uint8_t                                    OrderHint;
    uint8_t                                    reserved1[3];
    const StdVideoEncodeAV1ExtensionHeader*    pExtensionHeader;
} StdVideoEncodeAV1ReferenceInfo;


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/buffer.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Module containing helper structs to automatically free vkBuffers,
//! vkDeviceMemorys and to unmap mapped memory.

use crate::vk;
use crate::context::Context;
use crate::allocate_store;
use std::ffi::c_void;
use std::rc::Rc;
use std::ptr;
use std::fmt;

#[derive(Debug)]
pub enum Error {
    MapMemoryError,
    AllocateStoreError(String),
    BufferError,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BufferError => write!(
                f,
                "Error creating vkBuffer",
            ),
            Error::MapMemoryError => write!(
                f,
                "vkMapMemory failed",
            ),
            Error::AllocateStoreError(s) => write!(f, "{}", s),
        }
    }
}

#[derive(Debug)]
pub struct MappedMemory {
    pub pointer: *mut c_void,
    memory: vk::VkDeviceMemory,
    // Needed for the destructor
    context: Rc<Context>,
}

impl Drop for MappedMemory {
    fn drop(&mut self) {
        unsafe {
            self.context.device().vkUnmapMemory.unwrap()(
                self.context.vk_device(),
                self.memory,
            );
        }
    }
}

impl MappedMemory {
    pub fn new(
        context: Rc<Context>,
        memory: vk::VkDeviceMemory,
    ) -> Result<MappedMemory, Error> {
        let mut pointer: *mut c_void = ptr::null_mut();

        let res = unsafe {
            context.device().vkMapMemory.unwrap()(
                context.vk_device(),
                memory,
                0, // offset
                vk::VK_WHOLE_SIZE as u64,
                0, // flags,
                ptr::addr_of_mut!(pointer),
            )
        };

        if res == vk::VK_SUCCESS {
            Ok(MappedMemory { pointer, memory, context })
        } else {
            Err(Error::MapMemoryError)
        }
    }
}

#[derive(Debug)]
pub struct DeviceMemory {
    pub memory: vk::VkDeviceMemory,
    pub memory_type_index: u32,
    // Needed for the destructor
    context: Rc<Context>,
}

impl Drop for DeviceMemory {
    fn drop(&mut self) {
        unsafe {
            self.context.device().vkFreeMemory.unwrap()(
                self.context.vk_device(),
                self.memory,
                ptr::null(), // allocator
            );
        }
    }
}

impl DeviceMemory {
    pub fn new_buffer(
        context: Rc<Context>,
        memory_type_flags: vk::VkMemoryPropertyFlags,
        buffer: vk::VkBuffer,
    ) -> Result<DeviceMemory, Error> {
        let res = allocate_store::allocate_buffer(
            context.as_ref(),
            memory_type_flags,
            buffer,
        );
        DeviceMemory::new_from_result(context, res)
    }

    pub fn new_image(
        context: Rc<Context>,
        memory_type_flags: vk::VkMemoryPropertyFlags,
        image: vk::VkImage,
    ) -> Result<DeviceMemory, Error> {
        let res = allocate_store::allocate_image(
            context.as_ref(),
            memory_type_flags,
            image,
        );
        DeviceMemory::new_from_result(context, res)
    }

    fn new_from_result(
        context: Rc<Context>,
        result: Result<(vk::VkDeviceMemory, u32), String>,
    ) -> Result<DeviceMemory, Error> {
        match result {
            Ok((memory, memory_type_index)) => Ok(DeviceMemory {
                memory,
                memory_type_index,
                context,
            }),
            Err(e) => Err(Error::AllocateStoreError(e)),
        }
    }
}

#[derive(Debug)]
pub struct Buffer {
    pub buffer: vk::VkBuffer,
    // Needed for the destructor
    context: Rc<Context>,
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            self.context.device().vkDestroyBuffer.unwrap()(
                self.context.vk_device(),
                self.buffer,
                ptr::null(), // allocator
            );
        }
    }
}

impl Buffer {
    pub fn new(
        context: Rc<Context>,
        size: usize,
        usage: vk::VkBufferUsageFlagBits,
    ) -> Result<Buffer, Error> {
        let buffer_create_info = vk::VkBufferCreateInfo {
            sType: vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
            pNext: ptr::null(),
            flags: 0,
            size: size as vk::VkDeviceSize,
            usage,
            sharingMode: vk::VK_SHARING_MODE_EXCLUSIVE,
            queueFamilyIndexCount: 0,
            pQueueFamilyIndices: ptr::null(),
        };

        let mut buffer: vk::VkBuffer = vk::null_handle();

        let res = unsafe {
            context.device().vkCreateBuffer.unwrap()(
                context.vk_device(),
                ptr::addr_of!(buffer_create_info),
                ptr::null(), // allocator
                ptr::addr_of_mut!(buffer),
            )
        };

        if res == vk::VK_SUCCESS {
            Ok(Buffer { buffer, context })
        } else {
            Err(Error::BufferError)
        }
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/temp_file.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::path::{Path, PathBuf};
use std::fs::File;
use std::io;
use std::fmt;
use std::fmt::Write;

/// An error that can be returned from [TempFile::new]
#[derive(Debug)]
pub enum Error {
    /// All of the possible unique names were tried and all of the
    /// files exist. This should probably not really be possible.
    NoAvailableFilename,
    /// An I/O error other than `AlreadyExists` and `Interrupted`
    /// occurred while opening the file.
    IoError(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            Error::NoAvailableFilename => {
                write!(f, "No available temporary filenames")
            },
            Error::IoError(e) => e.fmt(f),
        }
    }
}

/// Class to handle creating a tempory file and deleting it when
/// dropped.
///
/// The file will be created in the directory returned by
/// [std::env::temp_dir]. It will have a generated name beginning with
/// `vkrunner-` followed by an integer. The file will be opened in
/// write-only mode and the corresponding [File] object can be
/// accessed with [TempFile::file]. The file will be automatically
/// closed and deleted when the `TempFile` is dropped.
#[derive(Debug)]
pub struct TempFile {
    filename: PathBuf,
    file: Option<File>,
}

fn find_available_file(prefix: &str, filename: &mut PathBuf) -> Result<File, Error> {
    let mut filename_part = String::new();

    for i in 0..=u64::MAX {
        filename_part.clear();
        write!(&mut filename_part, "{}{}", prefix, i).unwrap();

        filename.push(&filename_part);

        match File::options()
            .write(true)
            .read(true)
            .create_new(true)
            .open(&filename)
        {
            Ok(file) => return Ok(file),
            Err(e) => {
                if e.kind() != io::ErrorKind::AlreadyExists
                    && e.kind() != io::ErrorKind::Interrupted
                {
                    return Err(Error::IoError(e));
                }
                // Otherwise just try again with a new name
            },
        }

        filename.pop();
    }

    Err(Error::NoAvailableFilename)
}

impl TempFile {
    /// Creates a new temporary file or returns an error.
    pub fn new() -> Result<TempFile, Error> {
        Self::new_with_prefix("vkrunner-")
    }

    /// Creates a new temporary file or returns an error.
    pub fn new_with_prefix(prefix: &str) -> Result<TempFile, Error> {
        let mut filename = std::env::temp_dir();
        let file = find_available_file(prefix, &mut filename)?;

        Ok(TempFile {
            filename,
            file: Some(file),
        })
    }

    /// Gets the [File] object. This can be `None` if
    /// [TempFile::close] has been called.
    pub fn file(&mut self) -> Option<&mut File> {
        self.file.as_mut()
    }

    /// Gets the filename of the temporary file.
    pub fn filename(&self) -> &Path {
        &self.filename
    }

    /// Closes the file. The file will still exist and won’t be
    /// deleted until the `TempFile` is dropped.
    pub fn close(&mut self) {
        self.file = None
    }
}

impl Drop for TempFile {
    fn drop(&mut self) {
        // Make sure the file is closed before trying to delete it
        self.file = None;
        // We can’t do anything if the remove fails so just ignore the error
        let _ = std::fs::remove_file(&self.filename);
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::Seek;
    use std::io::{Write, Read};

    #[test]
    fn two_files() {
        // This test checks for files being present and not present, so use
        // an unique prefix to avoid conflict with other tests running in
        // parallel.
        let prefix = "twofiles-vkrunner-";
        let mut file_a = TempFile::new_with_prefix(prefix).unwrap();

        assert!(file_a.file().is_some());
        assert!(
            file_a
                .filename()
                .display()
                .to_string()
                .find(prefix)
                .is_some()
        );
        assert!(file_a.filename().is_file());

        file_a.close();
        assert!(file_a.file().is_none());
        assert!(file_a.filename().is_file());

        let mut file_b = TempFile::new_with_prefix(prefix).unwrap();

        assert!(file_b.file().is_some());
        assert!(file_a.filename() != file_b.filename());
        assert!(file_b.filename().is_file());

        let file_a_filename = file_a.filename().to_owned();
        drop(file_a);
        assert!(!file_a_filename.is_file());

        assert!(file_b.filename.is_file());

        let file_b_filename = file_b.filename().to_owned();
        drop(file_b);
        assert!(!file_b_filename.is_file());
    }

    #[test]
    fn read() {
        let mut temp_file = TempFile::new().unwrap();

        temp_file.file().unwrap().write(b"hello").unwrap();

        temp_file.file().unwrap().rewind().unwrap();

        let mut contents = String::new();

        temp_file.file().unwrap().read_to_string(&mut contents).unwrap();

        assert_eq!(&contents, "hello");

        temp_file.close();

        let contents = std::fs::read_to_string(temp_file.filename()).unwrap();

        assert_eq!(contents, "hello");
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/make-features.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python

# Copyright (C) 2019 Intel Corporation

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from __future__ import (
    absolute_import, division, print_function, unicode_literals
)

# This script is used to generate features.rs from vulkan.h. It
# is not run automatically as part of the build process but if need be
# it can be used to update the file as follows:
#
# ./make-features.py < /usr/include/vulkan/vulkan_core.h > features.rs

import re
import sys
from mako.template import Template


EXTENSIONS = [
    "KHR_16BIT_STORAGE",
    "KHR_8BIT_STORAGE",
    {
        "name": "EXT_ASTC_DECODE_MODE",
        "struct": "VkPhysicalDeviceASTCDecodeFeaturesEXT",
        "struct_type": "ASTC_DECODE_FEATURES_EXT"
    },
    "EXT_BLEND_OPERATION_ADVANCED",
    "EXT_BUFFER_DEVICE_ADDRESS",
    "KHR_COMPUTE_SHADER_DERIVATIVES",
    "EXT_CONDITIONAL_RENDERING",
    "NV_CORNER_SAMPLED_IMAGE",
    "EXT_DESCRIPTOR_INDEXING",
    {
        "name": "NV_SCISSOR_EXCLUSIVE",
        "struct_type": "EXCLUSIVE_SCISSOR_FEATURES_NV"
    },
    "KHR_SHADER_FLOAT16_INT8",
    "EXT_FRAGMENT_DENSITY_MAP",
    "KHR_FRAGMENT_SHADER_BARYCENTRIC",
    "EXT_INLINE_UNIFORM_BLOCK",
    "EXT_MEMORY_PRIORITY",
    "NV_MESH_SHADER",
    "KHR_MULTIVIEW",
    "NV_REPRESENTATIVE_FRAGMENT_TEST",
    "KHR_SAMPLER_YCBCR_CONVERSION",
    "EXT_SCALAR_BLOCK_LAYOUT",
    "KHR_SHADER_ATOMIC_INT64",
    "NV_SHADER_IMAGE_FOOTPRINT",
    "NV_SHADING_RATE_IMAGE",
    "EXT_TRANSFORM_FEEDBACK",
    "KHR_VARIABLE_POINTERS",
    "EXT_VERTEX_ATTRIBUTE_DIVISOR",
    "KHR_VULKAN_MEMORY_MODEL",
    "KHR_COOPERATIVE_MATRIX",
    "EXT_SUBGROUP_SIZE_CONTROL",
]


TEMPLATE="""\
// Automatically generated by make-features.py

static EXTENSIONS: [Extension; ${len(extensions)}] = [
% for e in extensions:
    Extension {
        name_bytes: vk::VK_${e.name}_EXTENSION_NAME,
        struct_size: mem::size_of::<vk::${e.struct}>(),
        struct_type: vk::${e.struct_type},
        features: &[
% for f in e.features:
            "${f}",
% endfor
        ],
    },
% endfor
];

const N_BASE_FEATURES: usize = ${len(base_features)};

static BASE_FEATURES: [&'static str; N_BASE_FEATURES] = [
% for f in base_features:
    "${f}",
% endfor
];
"""


class Extension:
    def __init__(self, name, struct, struct_type, features):
        self.name = name
        self.struct = struct
        self.struct_type = struct_type
        self.features = features


def capitalize_part(part):
    md = re.match(r'([0-9]*)(.*)', part)
    return md.group(1) + md.group(2).capitalize()


def extension_to_struct_name(ext):
    parts = ext.split("_")
    vendor = parts[0]
    rest = parts[1:]

    return ("VkPhysicalDevice" +
            "".join(capitalize_part(part) for part in rest) +
            "Features" +
            vendor)


def struct_to_regexp(struct):
    # Make the vendor in the struct name optional
    md = re.match(r'(.*?)([A-Z]+)$', struct)
    return re.compile(r'^typedef\s+struct\s+' +
                      re.escape(md.group(1)) +
                      r'(?:' + re.escape(md.group(2)) + r')?\s+' +
                      r'{\s*$',
                      flags=re.MULTILINE)


def get_struct_features(header, struct):
    struct_re = struct_to_regexp(struct)
    md = struct_re.search(header)

    if md is None:
        raise Exception("Couldn't find extension {} in vulkan header".format(
            struct))

    header_tail = header[md.end() + 1 :]
    header_end = re.search(r'^}', header_tail, flags=re.MULTILINE).start()
    members = header_tail[:header_end]

    for line in members.splitlines():
        md = re.match(r'\s*VkStructureType\s+[A-Za-z]+\s*;\s*$', line)
        if md:
            continue
        md = re.match(r'\s*void\s*\*\s+pNext\s*;\s*$', line)
        if md:
            continue
        md = re.match(r'\s*VkBool32\s+([a-zA-Z][a-zA-Z0-9_]*)\s*;\s*$', line)
        if not md:
            raise Exception("Unknown member in struct: " + line)

        yield md.group(1)


def main():
    header = sys.stdin.read()

    extensions = []

    for ext in EXTENSIONS:
        if not isinstance(ext, dict):
            ext = { "name": ext }

        name = ext["name"]

        try:
            struct_type = ext["struct_type"]
        except KeyError:
            parts = name.split("_")
            struct_type = ("_".join(parts[1:]) + "_" +
                           "FEATURES_" +
                           parts[0])

        try:
            struct = ext["struct"]
        except KeyError:
            parts = struct_type.split("_")
            struct = ("VkPhysicalDevice" +
                      "".join(capitalize_part(part)
                              for part in parts[:-1]) +
                      parts[-1])

        struct_type_enum = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_" + struct_type

        features = list(get_struct_features(header, struct))
        extension = Extension(name, struct, struct_type_enum, features)
        extensions.append(extension)

    base_features = list(
        get_struct_features(header, "VkPhysicalDeviceFeaturesKHR")
    )

    # Validate that all of the feature names are unique
    all_features = [feature for extension in extensions
                    for feature in extension.features] + base_features

    feature_names = set()
    for feature in all_features:
        if feature in feature_names:
            raise Exception("Feature {} is not unique".format(feature))
        feature_names.add(feature)

    template = Template(TEMPLATE)
    print(template.render(extensions = extensions,
                          base_features = base_features))


if __name__ == '__main__':
    main()

```

--------------------------------------------------------------------------------
/vkrunner/precompile-script.py:
--------------------------------------------------------------------------------

```python
#!/usr/bin/env python

# Copyright (C) 2018 Intel Corporation

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from __future__ import (
    absolute_import, division, print_function, unicode_literals
)

import re
import tempfile
import sys
import subprocess
import argparse
import os
import struct

TARGET_ENV = "vulkan1.0"

SECTION_RE = re.compile(r'^\[([^]]+)\]\s*$')
VERSION_RE = re.compile(r'^(\s*vulkan\s*\d+\.\d+)(\.\d+\s*)$')
TRIM_RE = re.compile(r'\s+')

STAGE_MAP = {
    'vertex shader': 'vert',
    'tessellation control shader': 'tesc',
    'tessellation evaluation shader': 'tese',
    'geometry shader': 'geom',
    'fragment shader': 'frag',
    'compute shader': 'comp',
}

class Converter:
    def __init__(self, type, stage, fout, binary, version):
        self._type = type
        self._stage = stage
        self._fout = fout
        self._tempfile = tempfile.NamedTemporaryFile('w+')
        self._binary = binary
        self._version = version

    def add_line(self, line):
        self._tempfile.write(line)

    def finish(self):
        self._tempfile.flush()

        with tempfile.NamedTemporaryFile() as temp_outfile:
            if self._type == 'glsl':
                subprocess.check_call([self._binary,
                                       "--quiet",
                                       "-S", self._stage,
                                       "-G",
                                       "-V",
                                       "--target-env", self._version,
                                       "-o", temp_outfile.name,
                                       self._tempfile.name])
            else:
                subprocess.check_call([self._binary,
                                       "--target-env", self._version,
                                       "-o", temp_outfile.name,
                                       self._tempfile.name])

            data = temp_outfile.read()

        self._tempfile.close()

        if len(data) < 4 or len(data) % 4 != 0:
            print("Resulting binary SPIR-V file has an invalid size",
                  file=sys.stderr)
            sys.exit(1)

        magic_header = struct.unpack(">I", data[0:4])[0]

        if magic_header == 0x07230203:
            byte_order = ">I"
        elif magic_header == 0x03022307:
            byte_order = "<I"
        else:
            print("Resulting binary SPIR-V has an invalid magic number",
                  file=sys.stderr)
            sys.exit(1)

        line_pos = 0
        for offset in range(0, len(data), 4):
            value = struct.unpack(byte_order, data[offset:offset+4])[0]
            hex_str = "{:x}".format(value)
            if len(hex_str) + line_pos + 1 > 80:
                line_pos = 0
                print(file=self._fout)
            elif line_pos > 0:
                print(' ', file=self._fout, end='')
                line_pos += 1
            print(hex_str, file=self._fout, end='')
            line_pos += len(hex_str)

        if line_pos > 0:
            print(file=self._fout)
        print(file=self._fout)

def convert_stream(fin, fout, glslang, spirv_as):
    section_name = None
    converter = None
    version = TARGET_ENV

    for line in fin:
        md = SECTION_RE.match(line)
        if md:
            if converter:
                converter.finish()
                converter = None

            section_name = md.group(1)

            if section_name.endswith(' spirv'):
                stage_name = section_name[:-6]
                converter = Converter('spirv',
                                      STAGE_MAP[stage_name],
                                      fout,
                                      spirv_as,
                                      version)
                print("[{} binary]".format(stage_name), file=fout)
            elif section_name in STAGE_MAP:
                converter = Converter('glsl',
                                      STAGE_MAP[section_name],
                                      fout, glslang, version)
                print("[{} binary]".format(section_name), file=fout)
            else:
                fout.write(line)
        elif converter:
            converter.add_line(line)
        else:
            if section_name == 'require':
                vmd = VERSION_RE.match(line)
                if vmd:
                    version = vmd.group(1)
                    version = TRIM_RE.sub('', version)
            fout.write(line)

    if converter:
        converter.finish()


parser = argparse.ArgumentParser(description='Precompile VkRunner scripts.')
parser.add_argument('inputs', metavar='INPUT', type=str, nargs='+',
                    help='an input file process')
parser.add_argument('-o', dest='output', metavar='OUTPUT',
                    help='an output file or directory', required=True)

parser.add_argument('-g', dest='glslang', metavar='GLSLANG',
                    help='glslangValidator binary path', required=False, default="glslangValidator")

parser.add_argument('-s', dest='spirv_as', metavar='SPIRV_AS',
                    help='spirv-as binary path', required=False, default="spirv-as")

args = parser.parse_args()
output_is_directory = len(args.inputs) >= 2 or os.path.isdir(args.output)

if output_is_directory:
    try:
        os.mkdir(args.output)
    except OSError:
        pass

for input in args.inputs:
    if output_is_directory:
        output = os.path.join(args.output, os.path.basename(input))
    else:
        output = args.output

    with open(input, 'r') as fin:
        with open(output, 'w') as fout:
            convert_stream(fin, fout, args.glslang, args.spirv_as)

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_h264std_encode.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_
#define VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codec_h264std_encode is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codec_h264std_encode 1
#include "vulkan_video_codec_h264std.h"

#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)

#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0
#define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_encode"
typedef struct StdVideoEncodeH264WeightTableFlags {
    uint32_t    luma_weight_l0_flag;
    uint32_t    chroma_weight_l0_flag;
    uint32_t    luma_weight_l1_flag;
    uint32_t    chroma_weight_l1_flag;
} StdVideoEncodeH264WeightTableFlags;

typedef struct StdVideoEncodeH264WeightTable {
    StdVideoEncodeH264WeightTableFlags    flags;
    uint8_t                               luma_log2_weight_denom;
    uint8_t                               chroma_log2_weight_denom;
    int8_t                                luma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF];
    int8_t                                luma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF];
    int8_t                                chroma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES];
    int8_t                                chroma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES];
    int8_t                                luma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF];
    int8_t                                luma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF];
    int8_t                                chroma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES];
    int8_t                                chroma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES];
} StdVideoEncodeH264WeightTable;

typedef struct StdVideoEncodeH264SliceHeaderFlags {
    uint32_t    direct_spatial_mv_pred_flag : 1;
    uint32_t    num_ref_idx_active_override_flag : 1;
    uint32_t    reserved : 30;
} StdVideoEncodeH264SliceHeaderFlags;

typedef struct StdVideoEncodeH264PictureInfoFlags {
    uint32_t    IdrPicFlag : 1;
    uint32_t    is_reference : 1;
    uint32_t    no_output_of_prior_pics_flag : 1;
    uint32_t    long_term_reference_flag : 1;
    uint32_t    adaptive_ref_pic_marking_mode_flag : 1;
    uint32_t    reserved : 27;
} StdVideoEncodeH264PictureInfoFlags;

typedef struct StdVideoEncodeH264ReferenceInfoFlags {
    uint32_t    used_for_long_term_reference : 1;
    uint32_t    reserved : 31;
} StdVideoEncodeH264ReferenceInfoFlags;

typedef struct StdVideoEncodeH264ReferenceListsInfoFlags {
    uint32_t    ref_pic_list_modification_flag_l0 : 1;
    uint32_t    ref_pic_list_modification_flag_l1 : 1;
    uint32_t    reserved : 30;
} StdVideoEncodeH264ReferenceListsInfoFlags;

typedef struct StdVideoEncodeH264RefListModEntry {
    StdVideoH264ModificationOfPicNumsIdc    modification_of_pic_nums_idc;
    uint16_t                                abs_diff_pic_num_minus1;
    uint16_t                                long_term_pic_num;
} StdVideoEncodeH264RefListModEntry;

typedef struct StdVideoEncodeH264RefPicMarkingEntry {
    StdVideoH264MemMgmtControlOp    memory_management_control_operation;
    uint16_t                        difference_of_pic_nums_minus1;
    uint16_t                        long_term_pic_num;
    uint16_t                        long_term_frame_idx;
    uint16_t                        max_long_term_frame_idx_plus1;
} StdVideoEncodeH264RefPicMarkingEntry;

typedef struct StdVideoEncodeH264ReferenceListsInfo {
    StdVideoEncodeH264ReferenceListsInfoFlags      flags;
    uint8_t                                        num_ref_idx_l0_active_minus1;
    uint8_t                                        num_ref_idx_l1_active_minus1;
    uint8_t                                        RefPicList0[STD_VIDEO_H264_MAX_NUM_LIST_REF];
    uint8_t                                        RefPicList1[STD_VIDEO_H264_MAX_NUM_LIST_REF];
    uint8_t                                        refList0ModOpCount;
    uint8_t                                        refList1ModOpCount;
    uint8_t                                        refPicMarkingOpCount;
    uint8_t                                        reserved1[7];
    const StdVideoEncodeH264RefListModEntry*       pRefList0ModOperations;
    const StdVideoEncodeH264RefListModEntry*       pRefList1ModOperations;
    const StdVideoEncodeH264RefPicMarkingEntry*    pRefPicMarkingOperations;
} StdVideoEncodeH264ReferenceListsInfo;

typedef struct StdVideoEncodeH264PictureInfo {
    StdVideoEncodeH264PictureInfoFlags             flags;
    uint8_t                                        seq_parameter_set_id;
    uint8_t                                        pic_parameter_set_id;
    uint16_t                                       idr_pic_id;
    StdVideoH264PictureType                        primary_pic_type;
    uint32_t                                       frame_num;
    int32_t                                        PicOrderCnt;
    uint8_t                                        temporal_id;
    uint8_t                                        reserved1[3];
    const StdVideoEncodeH264ReferenceListsInfo*    pRefLists;
} StdVideoEncodeH264PictureInfo;

typedef struct StdVideoEncodeH264ReferenceInfo {
    StdVideoEncodeH264ReferenceInfoFlags    flags;
    StdVideoH264PictureType                 primary_pic_type;
    uint32_t                                FrameNum;
    int32_t                                 PicOrderCnt;
    uint16_t                                long_term_pic_num;
    uint16_t                                long_term_frame_idx;
    uint8_t                                 temporal_id;
} StdVideoEncodeH264ReferenceInfo;

typedef struct StdVideoEncodeH264SliceHeader {
    StdVideoEncodeH264SliceHeaderFlags        flags;
    uint32_t                                  first_mb_in_slice;
    StdVideoH264SliceType                     slice_type;
    int8_t                                    slice_alpha_c0_offset_div2;
    int8_t                                    slice_beta_offset_div2;
    int8_t                                    slice_qp_delta;
    uint8_t                                   reserved1;
    StdVideoH264CabacInitIdc                  cabac_init_idc;
    StdVideoH264DisableDeblockingFilterIdc    disable_deblocking_filter_idc;
    const StdVideoEncodeH264WeightTable*      pWeightTable;
} StdVideoEncodeH264SliceHeader;


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_h265std_encode.h:
--------------------------------------------------------------------------------

```
#ifndef VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_
#define VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_ 1

/*
** Copyright 2015-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0
*/

/*
** This header is generated from the Khronos Vulkan XML API Registry.
**
*/


#ifdef __cplusplus
extern "C" {
#endif



// vulkan_video_codec_h265std_encode is a preprocessor guard. Do not pass it to API calls.
#define vulkan_video_codec_h265std_encode 1
#include "vulkan_video_codec_h265std.h"

#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)

#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0
#define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_encode"
typedef struct StdVideoEncodeH265WeightTableFlags {
    uint16_t    luma_weight_l0_flag;
    uint16_t    chroma_weight_l0_flag;
    uint16_t    luma_weight_l1_flag;
    uint16_t    chroma_weight_l1_flag;
} StdVideoEncodeH265WeightTableFlags;

typedef struct StdVideoEncodeH265WeightTable {
    StdVideoEncodeH265WeightTableFlags    flags;
    uint8_t                               luma_log2_weight_denom;
    int8_t                                delta_chroma_log2_weight_denom;
    int8_t                                delta_luma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    int8_t                                luma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    int8_t                                delta_chroma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
    int8_t                                delta_chroma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
    int8_t                                delta_luma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    int8_t                                luma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    int8_t                                delta_chroma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
    int8_t                                delta_chroma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
} StdVideoEncodeH265WeightTable;

typedef struct StdVideoEncodeH265SliceSegmentHeaderFlags {
    uint32_t    first_slice_segment_in_pic_flag : 1;
    uint32_t    dependent_slice_segment_flag : 1;
    uint32_t    slice_sao_luma_flag : 1;
    uint32_t    slice_sao_chroma_flag : 1;
    uint32_t    num_ref_idx_active_override_flag : 1;
    uint32_t    mvd_l1_zero_flag : 1;
    uint32_t    cabac_init_flag : 1;
    uint32_t    cu_chroma_qp_offset_enabled_flag : 1;
    uint32_t    deblocking_filter_override_flag : 1;
    uint32_t    slice_deblocking_filter_disabled_flag : 1;
    uint32_t    collocated_from_l0_flag : 1;
    uint32_t    slice_loop_filter_across_slices_enabled_flag : 1;
    uint32_t    reserved : 20;
} StdVideoEncodeH265SliceSegmentHeaderFlags;

typedef struct StdVideoEncodeH265SliceSegmentHeader {
    StdVideoEncodeH265SliceSegmentHeaderFlags    flags;
    StdVideoH265SliceType                        slice_type;
    uint32_t                                     slice_segment_address;
    uint8_t                                      collocated_ref_idx;
    uint8_t                                      MaxNumMergeCand;
    int8_t                                       slice_cb_qp_offset;
    int8_t                                       slice_cr_qp_offset;
    int8_t                                       slice_beta_offset_div2;
    int8_t                                       slice_tc_offset_div2;
    int8_t                                       slice_act_y_qp_offset;
    int8_t                                       slice_act_cb_qp_offset;
    int8_t                                       slice_act_cr_qp_offset;
    int8_t                                       slice_qp_delta;
    uint16_t                                     reserved1;
    const StdVideoEncodeH265WeightTable*         pWeightTable;
} StdVideoEncodeH265SliceSegmentHeader;

typedef struct StdVideoEncodeH265ReferenceListsInfoFlags {
    uint32_t    ref_pic_list_modification_flag_l0 : 1;
    uint32_t    ref_pic_list_modification_flag_l1 : 1;
    uint32_t    reserved : 30;
} StdVideoEncodeH265ReferenceListsInfoFlags;

typedef struct StdVideoEncodeH265ReferenceListsInfo {
    StdVideoEncodeH265ReferenceListsInfoFlags    flags;
    uint8_t                                      num_ref_idx_l0_active_minus1;
    uint8_t                                      num_ref_idx_l1_active_minus1;
    uint8_t                                      RefPicList0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    uint8_t                                      RefPicList1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    uint8_t                                      list_entry_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
    uint8_t                                      list_entry_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
} StdVideoEncodeH265ReferenceListsInfo;

typedef struct StdVideoEncodeH265PictureInfoFlags {
    uint32_t    is_reference : 1;
    uint32_t    IrapPicFlag : 1;
    uint32_t    used_for_long_term_reference : 1;
    uint32_t    discardable_flag : 1;
    uint32_t    cross_layer_bla_flag : 1;
    uint32_t    pic_output_flag : 1;
    uint32_t    no_output_of_prior_pics_flag : 1;
    uint32_t    short_term_ref_pic_set_sps_flag : 1;
    uint32_t    slice_temporal_mvp_enabled_flag : 1;
    uint32_t    reserved : 23;
} StdVideoEncodeH265PictureInfoFlags;

typedef struct StdVideoEncodeH265LongTermRefPics {
    uint8_t     num_long_term_sps;
    uint8_t     num_long_term_pics;
    uint8_t     lt_idx_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS];
    uint8_t     poc_lsb_lt[STD_VIDEO_H265_MAX_LONG_TERM_PICS];
    uint16_t    used_by_curr_pic_lt_flag;
    uint8_t     delta_poc_msb_present_flag[STD_VIDEO_H265_MAX_DELTA_POC];
    uint8_t     delta_poc_msb_cycle_lt[STD_VIDEO_H265_MAX_DELTA_POC];
} StdVideoEncodeH265LongTermRefPics;

typedef struct StdVideoEncodeH265PictureInfo {
    StdVideoEncodeH265PictureInfoFlags             flags;
    StdVideoH265PictureType                        pic_type;
    uint8_t                                        sps_video_parameter_set_id;
    uint8_t                                        pps_seq_parameter_set_id;
    uint8_t                                        pps_pic_parameter_set_id;
    uint8_t                                        short_term_ref_pic_set_idx;
    int32_t                                        PicOrderCntVal;
    uint8_t                                        TemporalId;
    uint8_t                                        reserved1[7];
    const StdVideoEncodeH265ReferenceListsInfo*    pRefLists;
    const StdVideoH265ShortTermRefPicSet*          pShortTermRefPicSet;
    const StdVideoEncodeH265LongTermRefPics*       pLongTermRefPics;
} StdVideoEncodeH265PictureInfo;

typedef struct StdVideoEncodeH265ReferenceInfoFlags {
    uint32_t    used_for_long_term_reference : 1;
    uint32_t    unused_for_reference : 1;
    uint32_t    reserved : 30;
} StdVideoEncodeH265ReferenceInfoFlags;

typedef struct StdVideoEncodeH265ReferenceInfo {
    StdVideoEncodeH265ReferenceInfoFlags    flags;
    StdVideoH265PictureType                 pic_type;
    int32_t                                 PicOrderCntVal;
    uint8_t                                 TemporalId;
} StdVideoEncodeH265ReferenceInfo;


#ifdef __cplusplus
}
#endif

#endif

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/flush_memory.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2017, 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::context::Context;
use crate::vk;
use std::ptr;
use std::fmt;

#[derive(Debug)]
pub struct Error(vk::VkResult);

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "vkFlushMappedMemoryRanges failed: {:?}", self.0)
    }
}

/// Calls `vkFlushMappedMemoryRanges` with the range specified in
/// `offset` and `size` unless the specified memory type has the
/// `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` property set.
///
/// For testing, the environment variable
/// `VKRUNNER_ALWAYS_FLUSH_MEMORY` can be set to `true` to make it
/// always flush the memory regardless of memory type properties.
pub fn flush_memory(
    context: &Context,
    memory_type_index: usize,
    memory: vk::VkDeviceMemory,
    offset: vk::VkDeviceSize,
    size: vk::VkDeviceSize,
) -> Result<(), Error> {
    let memory_properties = context.memory_properties();
    let memory_type =
        &memory_properties.memoryTypes[memory_type_index as usize];

    // We don’t need to do anything if the memory is already coherent
    if !context.always_flush_memory()
        && (memory_type.propertyFlags
            & vk::VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0
    {
        return Ok(());
    }

    let mapped_memory_range = vk::VkMappedMemoryRange {
        sType: vk::VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
        pNext: ptr::null(),
        memory,
        offset,
        size,
    };

    let res = unsafe {
        context.device().vkFlushMappedMemoryRanges.unwrap()(
            context.vk_device(),
            1, // memoryRangeCount
            ptr::addr_of!(mapped_memory_range),
        )
    };

    if res == vk::VK_SUCCESS {
        Ok(())
    } else {
        Err(Error(res))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::rc::Rc;
    use crate::requirements::Requirements;
    use crate::fake_vulkan::FakeVulkan;
    use crate::env_var_test::EnvVarLock;

    struct Memory {
        handle: vk::VkDeviceMemory,
        context: Rc<Context>,
    }

    impl Memory {
        fn new(context: Rc<Context>) -> Memory {
            let mut handle = vk::null_handle();

            let allocate_info = vk::VkMemoryAllocateInfo {
                sType: vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
                pNext: ptr::null(),
                allocationSize: 1024,
                memoryTypeIndex: 0,
            };

            unsafe {
                let res = context.device().vkAllocateMemory.unwrap()(
                    context.vk_device(),
                    ptr::addr_of!(allocate_info),
                    ptr::null(), // allocator
                    ptr::addr_of_mut!(handle),
                );

                assert_eq!(res, vk::VK_SUCCESS);
            }

            Memory { handle, context }
        }
    }

    impl Drop for Memory {
        fn drop(&mut self) {
            unsafe {
                self.context.device().vkFreeMemory.unwrap()(
                    self.context.vk_device(),
                    self.handle,
                    ptr::null_mut(), // allocator
                );
            }
        }
    }

    struct TestData {
        context: Rc<Context>,
        fake_vulkan: Box<FakeVulkan>,
    }

    impl TestData {
        fn new(coherent_memory: bool) -> TestData {
            let mut fake_vulkan = FakeVulkan::new();
            fake_vulkan.physical_devices.push(Default::default());
            let memory_properties =
                &mut fake_vulkan.physical_devices[0].memory_properties;
            memory_properties.memoryTypeCount = 1;

            memory_properties.memoryTypes[0].propertyFlags =
                if coherent_memory {
                    vk::VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
                } else {
                    0
                };

            fake_vulkan.set_override();
            let context = Rc::new(
                Context::new(&Requirements::new(), None).unwrap()
            );

            TestData { context, fake_vulkan }
        }
    }

    fn test_flag_combination(
        memory_is_coherent: bool,
        always_flush: bool,
        flush_expected: bool,
    ) {
        let _env_var_lock = EnvVarLock::new(&[
            (
                "VKRUNNER_ALWAYS_FLUSH_MEMORY",
                if always_flush { "true" } else { "false" },
            )
        ]);

        let test_data = TestData::new(memory_is_coherent);

        let memory = Memory::new(Rc::clone(&test_data.context));

        flush_memory(
            &test_data.context,
            0, // memory_type_index
            memory.handle,
            16, // offset
            24, // size
        ).unwrap();

        if flush_expected {
            assert_eq!(test_data.fake_vulkan.memory_flushes.len(), 1);
            assert_eq!(
                test_data.fake_vulkan.memory_flushes[0].memory,
                memory.handle,
            );
            assert_eq!(test_data.fake_vulkan.memory_flushes[0].offset, 16);
            assert_eq!(test_data.fake_vulkan.memory_flushes[0].size, 24);
        } else {
            assert_eq!(test_data.fake_vulkan.memory_flushes.len(), 0);
        }
    }

    #[test]
    fn should_flush() {
        test_flag_combination(
            false, // memory_is_coherent
            false, // always_flush
            true, // flush_expected
        );
        test_flag_combination(
            false, // memory_is_coherent
            true, // always_flush
            true, // flush_expected
        );
        test_flag_combination(
            true, // memory_is_coherent
            false, // always_flush
            false, // flush_expected
        );
        test_flag_combination(
            true, // memory_is_coherent
            true, // always_flush
            true, // flush_expected
        );
    }

    #[test]
    fn error() {
        let _env_var_lock = EnvVarLock::new(&[
            ("VKRUNNER_ALWAYS_FLUSH_MEMORY", "false")
        ]);

        let mut test_data = TestData::new(
            false, // memory_is_coherent
        );

        let memory = Memory::new(Rc::clone(&test_data.context));

        test_data.fake_vulkan.queue_result(
            "vkFlushMappedMemoryRanges".to_string(),
            vk::VK_ERROR_UNKNOWN,
        );

        let error = flush_memory(
            &test_data.context,
            0, // memory_type_index
            memory.handle,
            16, // offset
            24, // size
        ).unwrap_err();

        assert!(error.to_string().starts_with("vkFlushMappedMemoryRanges failed"));
        assert_eq!(error.0, vk::VK_ERROR_UNKNOWN);
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/vulkan_funcs.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright (C) 2016, 2023 Neil Roberts
// Copyright (C) 2018 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use crate::vk;
use crate::util;
use std::ffi::{c_void, c_int, c_char, CString};
use std::mem;
use std::fmt;

/// Offset of the pNext member of the structs that can be chained.
/// There doesn’t seem to be a nice equivalent to offsetof in Rust so
/// this is just trying to replicate the C struct alignment rules.
pub const NEXT_PTR_OFFSET: usize = util::align(
    mem::size_of::<vk::VkStructureType>(),
    mem::align_of::<*mut std::os::raw::c_void>(),
);
/// Offset of the first VkBool32 field in the features structs.
pub const FIRST_FEATURE_OFFSET: usize = util::align(
    NEXT_PTR_OFFSET + mem::size_of::<*mut std::os::raw::c_void>(),
    mem::align_of::<vk::VkBool32>(),
);

pub type GetInstanceProcFunc = unsafe extern "C" fn(
    func_name: *const c_char,
    user_data: *const c_void,
) -> *const c_void;

#[derive(Debug)]
pub enum Error {
    OpenLibraryFailed(&'static str),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::OpenLibraryFailed(lib) => write!(f, "Error opening {}", lib)
        }
    }
}

include!{"vulkan_funcs_data.rs"}

struct LoaderFunc {
    lib_vulkan: *const c_void,
    lib_vulkan_is_fake: bool,
    get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
}

// Per-thread override for the get_instance_proc_address function.
// This is only used in unit tests to implement a fake Vulkan driver.
#[cfg(test)]
thread_local! {
    static LOADER_FUNC_OVERRIDE:
    std::cell::Cell<Option<LoaderFunc>> = std::cell::Cell::new(None);
}

impl Library {
    fn get_loader_func(
    ) -> Result<LoaderFunc, Error> {
        // Override for unit tests. If an override function is set
        // then we will return that instead. `take` is called on it so
        // that it will only be used once and subsequent calls will
        // revert back to the normal mechanism.
        #[cfg(test)]
        if let Some(loader_func) = LOADER_FUNC_OVERRIDE.with(|f| f.take()) {
            return Ok(loader_func);
        }

        #[cfg(unix)]
        {
            extern "C" {
                fn dlopen(name: *const c_char, flags: c_int) -> *const c_void;
                fn dlsym(
                    lib: *const c_void,
                    name: *const c_char
                ) -> *const c_void;
            }

            let lib_name;

            #[cfg(target_os = "android")]
            {
                lib_name = "libvulkan.so";
            }
            #[cfg(not(target_os = "android"))]
            {
                lib_name = "libvulkan.so.1";
            }

            let lib_name_c = CString::new(lib_name).unwrap();

            let lib = unsafe {
                dlopen(lib_name_c.as_ptr(), 1)
            };

            if lib.is_null() {
                return Err(Error::OpenLibraryFailed(lib_name));
            }

            let get_instance_proc_addr = unsafe {
                std::mem::transmute(dlsym(
                    lib,
                    "vkGetInstanceProcAddr\0".as_ptr().cast()
                ))
            };

            return Ok(LoaderFunc {
                lib_vulkan: lib,
                lib_vulkan_is_fake: false,
                get_instance_proc_addr
            });
        }

        #[cfg(windows)]
        {
            extern "system" {
                fn LoadLibraryA(
                    filename: *const c_char,
                ) -> *mut c_void;
                fn GetProcAddress(
                    handle: *mut c_void,
                    func_name: *const c_char,
                ) -> *const c_void;
            }

            let lib_name = "vulkan-1.dll";

            let lib = unsafe {
                let c_lib_name = CString::new(lib_name).unwrap();
                LoadLibraryA(c_lib_name.as_ptr())
            };

            if lib.is_null() {
                return Err(Error::OpenLibraryFailed(lib_name));
            }

            let get_instance_proc_addr = unsafe {
                std::mem::transmute(GetProcAddress(
                    lib,
                    "vkGetInstanceProcAddr\0".as_ptr().cast()
                ))
            };

            return Ok(LoaderFunc {
                lib_vulkan: lib,
                lib_vulkan_is_fake: false,
                get_instance_proc_addr
            });
        }

        #[cfg(not(any(unix,windows)))]
        todo!(
            "library opening on platforms other than Unix and Windows is \
             not yet implemented"
        );
    }

    pub fn new() -> Result<Library, Error> {
        let LoaderFunc {
            lib_vulkan,
            lib_vulkan_is_fake,
            get_instance_proc_addr,
        } = Library::get_loader_func()?;

        Ok(Library {
            lib_vulkan,
            lib_vulkan_is_fake,
            vkGetInstanceProcAddr: get_instance_proc_addr,
            vkCreateInstance: unsafe {
                std::mem::transmute(get_instance_proc_addr.unwrap()(
                    std::ptr::null_mut(),
                    "vkCreateInstance\0".as_ptr().cast()
                ))
            },
            vkEnumerateInstanceExtensionProperties: unsafe {
                std::mem::transmute(get_instance_proc_addr.unwrap()(
                    std::ptr::null_mut(),
                    "vkEnumerateInstanceExtensionProperties\0".as_ptr().cast()
                ))
            }
        })
    }
}

impl Drop for Library {
    fn drop(&mut self) {
        #[cfg(unix)]
        {
            extern "C" {
                fn dlclose(lib: *const c_void) -> *const c_void;
            }

            if !self.lib_vulkan_is_fake {
                unsafe { dlclose(self.lib_vulkan) };
            }
        }

        #[cfg(windows)]
        {
            extern "system" {
                fn FreeLibrary(handle: *const c_void) -> c_int;
            }

            if !self.lib_vulkan_is_fake {
                unsafe { FreeLibrary(self.lib_vulkan) };
            }
        }

        #[cfg(not(any(unix,windows)))]
        todo!(
            "library closing on platforms other than Windows and Unix is not \
             yet implemented"
        );
    }
}

/// Helper function to temporarily replace the `vkGetInstanceProcAddr`
/// function that will be used for the next call to [Library::new].
/// The override will only be used once and subsequent calls to
/// [Library::new] will revert back to trying to open the Vulkan
/// library. The override is per-thread so it is safe to use in a
/// multi-threaded testing environment. This function is only
/// available in test build configs and it is intended to help make a
/// fake Vulkan driver for unit tests.
#[cfg(test)]
pub fn override_get_instance_proc_addr(
    lib: *const c_void,
    proc: vk::PFN_vkGetInstanceProcAddr,
) {
    LOADER_FUNC_OVERRIDE.with(|f| f.replace(Some(LoaderFunc {
        lib_vulkan: lib,
        lib_vulkan_is_fake: true,
        get_instance_proc_addr: proc,
    })));
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/logger.rs:
--------------------------------------------------------------------------------

```rust
// vkrunner
//
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use std::ffi::{c_char, c_void};
use std::fmt;
use std::io;
use std::str;

/// An object that log messages can be written to. Normally this will
/// just write the messages to standard out, but an application can
/// configure a C callback to receive the messages by tweaking the
/// [Config](crate::config::Config). The struct implements `Write` so
/// it can be used with macros like [write!](std::write).
#[derive(Debug)]
pub struct Logger {
    callback: Option<WriteCallback>,
    user_data: *mut c_void,

    // The data is collected into this buffer until we have a complete
    // line to send to the callback.
    buf: Vec<u8>,

    // True if the any data was added from a u8 slice so it might not
    // be valid UTF-8.
    maybe_invalid_utf8: bool,
}

/// A callback to use to write the data to instead of writing to
/// stdout. This will be called one line at a time. Each line will be
/// terminated the C null terminator but no newlines. It will always
/// be valid UTF-8.
pub type WriteCallback = extern "C" fn(
    message: *const c_char,
    user_data: *mut c_void,
);

impl Logger {
    /// Construct a new logger that will write to the given callback.
    /// If the callback is `None` then the log will go to the stdout
    /// instead. `user_data` will be passed to the callback. You can
    /// pass [`ptr::null_mut()`](std::ptr::null_mut) if there is no
    /// callback.
    pub fn new(
        callback: Option<WriteCallback>,
        user_data: *mut c_void
    ) -> Logger {
        Logger {
            callback,
            user_data,
            maybe_invalid_utf8: false,

            buf: Vec::new(),
        }
    }

    fn send_range(&mut self, start: usize, end: usize) {
        if self.maybe_invalid_utf8 {
            let mut pos = start;

            loop {
                match str::from_utf8(&self.buf[pos..end]) {
                    Ok(_) => break,
                    Err(e) => {
                        // Replace the offending byte with a question
                        // mark. This should result in valid UTF-8
                        // without having to move the bytes around.
                        self.buf[pos + e.valid_up_to()] = b'?';
                        pos += e.valid_up_to() + 1;
                    },
                }
            }
        }

        match self.callback {
            Some(callback) => {
                // Add the C null terminator. This method should be
                // called knowing that the zero will be set at `end`
                // so it should have ensured the buffer is large
                // enough.
                self.buf[end] = 0;

                callback(
                    self.buf[start..end + 1].as_ptr().cast(),
                    self.user_data
                );
            },
            None => {
                // SAFETY: We just ensured that the range is valid
                // UTF-8 above.
                let s = unsafe {
                    str::from_utf8_unchecked(&self.buf[start..end])
                };
                println!("{}", s);
            },
        }
    }

    fn flush_lines(&mut self) {
        let mut pos = 0;

        while let Some(line_len) = self.buf[pos..]
            .into_iter()
            .position(|&c| c == b'\n')
        {
            self.send_range(pos, pos + line_len);
            pos += line_len + 1;
        }

        // Remove the lines that we successfully processed
        self.buf.drain(0..pos);

        if self.buf.is_empty() {
            self.maybe_invalid_utf8 = false;
        }
    }
}

impl io::Write for Logger {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if !buf.is_empty() {
            self.maybe_invalid_utf8 = true;
            self.buf.extend_from_slice(buf);
            self.flush_lines();
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        if !self.buf.is_empty() {
            let old_len = self.buf.len();

            // Make sure there is enough space for the null terminator
            // to be added
            self.buf.push(0);

            self.send_range(0, old_len);
            self.buf.clear();
        }

        Ok(())
    }
}

impl fmt::Write for Logger {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        self.buf.extend_from_slice(s.as_bytes());
        self.flush_lines();
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::ffi::CStr;

    struct TestLogger {
        logger: Logger,
        items: Vec<String>,
    }

    extern "C" fn log_item_cb(message: *const c_char, user_data: *mut c_void) {
        let logger = unsafe {
            &mut *(user_data as *mut TestLogger)
        };

        let message = unsafe { CStr::from_ptr(message.cast()) };
        logger.items.push(message.to_str().unwrap().to_string());
    }

    fn test_logger() -> Box<TestLogger> {
        // Need to box the logger so we can pass a pointer to it in
        // the logging callback
        let mut logger = Box::new(TestLogger {
            logger: Logger::new(None, std::ptr::null_mut()),
            items: Vec::new(),
        });

        logger.logger = Logger::new(
            Some(log_item_cb),
            logger.as_mut() as *mut TestLogger as *mut c_void,
        );

        logger
    }

    #[test]
    fn multiple_lines() {
        let mut logger = test_logger();

        use std::fmt::Write;

        writeln!(
            &mut logger.logger,
            "This is a line\n\
             This is another line.\n\
             This is followed by a number: {}",
            42,
        ).unwrap();

        assert_eq!(logger.items.len(), 3);
        assert_eq!(logger.items[0], "This is a line");
        assert_eq!(logger.items[1], "This is another line.");
        assert_eq!(logger.items[2], "This is followed by a number: 42");
    }

    #[test]
    fn split_line() {
        let mut logger = test_logger();

        use std::fmt::Write;

        write!(&mut logger.logger, "Part of first line ").unwrap();
        assert_eq!(logger.items.len(), 0);
        write!(
            &mut logger.logger,
            "next part of first line\nSecond line\n"
        ).unwrap();
        assert_eq!(logger.items.len(), 2);
        assert_eq!(
            logger.items[0],
            "Part of first line next part of first line",
        );
        assert_eq!(logger.items[1], "Second line");
    }

    #[test]
    fn bad_utf8() {
        let mut logger = test_logger();

        use std::io::Write;

        logger.logger.write(
            b"\xc4u ne mankas bajtoj \xc4\x89i tie \xe2\n"
        ).unwrap();
        assert_eq!(logger.items.len(), 1);
        assert_eq!(logger.items[0], "?u ne mankas bajtoj ĉi tie ?");
    }

    #[test]
    fn flush() {
        let mut logger = test_logger();

        use std::fmt::Write;

        write!(&mut logger.logger, "One line\nUnterminated line").unwrap();
        assert_eq!(logger.items.len(), 1);
        assert_eq!(logger.items[0], "One line");

        io::Write::flush(&mut logger.logger).unwrap();

        assert_eq!(logger.items.len(), 2);
        assert_eq!(logger.items[1], "Unterminated line");

        assert!(logger.logger.buf.is_empty());

        io::Write::flush(&mut logger.logger).unwrap();

        assert_eq!(logger.items.len(), 2);
    }
}

```

--------------------------------------------------------------------------------
/vkrunner/vkrunner/parse_num.rs:
--------------------------------------------------------------------------------

```rust
// Copyright 2023 Neil Roberts
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// on the rights to use, copy, modify, merge, publish, distribute, sub
// license, and/or sell copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next
// paragraph) shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
// VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::num::ParseIntError;
use std::fmt;

#[derive(Debug, PartialEq)]
pub enum ParseError {
    // The negative sign was used in an unsigned number type
    NegativeError,
    // A number that would be valid in an unsigned type overflows the
    // signed type
    SignedOverflow,
    // Any other error returned by the from_str_radix function
    Other(ParseIntError),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ParseError::NegativeError => write!(f, "Number can’t be negated"),
            ParseError::SignedOverflow => {
                write!(f, "Number out of range for type")
            },
            ParseError::Other(e) => e.fmt(f),
        }
    }
}

impl From<ParseIntError> for ParseError {
    fn from(e: ParseIntError) -> ParseError {
        ParseError::Other(e)
    }
}

struct NumAnalysis<'a> {
    negative: bool,
    radix: u32,
    num_part: &'a str,
    tail: &'a str,
}

fn is_octal_prefix(prefix: &str) -> bool {
    prefix.starts_with("0")
        && prefix.len() > 1
        && prefix.as_bytes()[1].is_ascii_digit()
}

fn analyse_num(mut s: &str) -> NumAnalysis {
    // skip only ASCII spaces and tabs
    while !s.is_empty() &&
        (s.as_bytes()[0] == b' ' || s.as_bytes()[0] == b'\t')
    {
        s = &s[1..];
    }

    // Optional sign
    let (prefix_start, negative) = match s.chars().next() {
        Some('-') => (1, true),
        Some('+') => (1, false),
        _ => (0, false),
    };

    let prefix = &s[prefix_start..];

    let (radix, num_start) = if prefix.starts_with("0x") {
        (16, 2)
    } else if is_octal_prefix(prefix) {
        (8, 1)
    } else {
        (10, 0)
    };

    let num_start = &prefix[num_start..];

    let split_point = num_start
        .chars()
        .take_while(|c| c.is_ascii_hexdigit())
        .count();

    NumAnalysis {
        negative,
        radix,
        num_part: &num_start[0..split_point],
        tail: &num_start[split_point..],
    }
}

// Macro to create a function to parse an unsigned int type. These are
// needed because there doesn’t seem to be an equivalent to strtoul in
// rust where the radix can be zero. The regular parse function also
// doesn’t return a tail pointer.
macro_rules! parse_unsigned {
    ($func:ident, $t:ident) => {
        pub fn $func(s: &str) -> Result<($t, &str), ParseError> {
            let analysis = analyse_num(s);

            let num = $t::from_str_radix(analysis.num_part, analysis.radix)?;

            if analysis.negative {
                Err(ParseError::NegativeError)
            } else {
                Ok((num, analysis.tail))
            }
        }
    }
}

// Macro to create a function to parse a signed int type. These are
// needed because there doesn’t seem to be an equivalent to strtol in
// rust where the radix can be zero. The regular parse function also
// doesn’t return a tail pointer.
macro_rules! parse_signed {
    ($func:ident, $st:ident, $ut:ident) => {
        pub fn $func(s: &str) -> Result<($st, &str), ParseError> {
            let analysis = analyse_num(s);

            let num = $ut::from_str_radix(analysis.num_part, analysis.radix)?;

            if analysis.negative {
                if num > $st::MAX as $ut + 1 {
                    Err(ParseError::SignedOverflow)
                } else {
                    // We have an unsigned value that we need to
                    // negate. We can’t just cast it to signed and
                    // then negate it because the MIN value is not
                    // representable as a positive value in the signed
                    // type. Instead we do the trick of !x+1 to
                    // negate while staying in the unsigned type.
                    Ok(((!num).wrapping_add(1) as $st, analysis.tail))
                }
            } else {
                if num > $st::MAX as $ut {
                    Err(ParseError::SignedOverflow)
                } else {
                    Ok((num as $st, analysis.tail))
                }
            }
        }
    }
}

parse_unsigned!(parse_u64, u64);
parse_unsigned!(parse_u32, u32);
parse_unsigned!(parse_u16, u16);
parse_unsigned!(parse_u8, u8);
parse_signed!(parse_i64, i64, u64);
parse_signed!(parse_i32, i32, u32);
parse_signed!(parse_i16, i16, u16);
parse_signed!(parse_i8, i8, u8);

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_unsigned() {
        assert_eq!(
            parse_u64(&u64::MAX.to_string()).unwrap(),
            (u64::MAX, ""),
        );
        assert_eq!(
            parse_u32(&u32::MAX.to_string()).unwrap(),
            (u32::MAX, ""),
        );
        assert_eq!(
            parse_u16(&u16::MAX.to_string()).unwrap(),
            (u16::MAX, ""),
        );
        assert_eq!(
            parse_u8(&u8::MAX.to_string()).unwrap(),
            (u8::MAX, ""),
        );

        assert!(matches!(parse_u8("-1"), Err(ParseError::NegativeError)));
        assert!(matches!(parse_u8("-0"), Err(ParseError::NegativeError)));

        assert!(matches!(
            parse_u8("256"),
            Err(ParseError::Other(ParseIntError { .. })),
        ));

        assert_eq!(
            parse_i8("  0 12"),
            Ok((0, " 12")),
        );

        assert_eq!(
            parse_u8("   0x42  after"),
            Ok((66, "  after")),
        );
        assert_eq!(
            parse_u32("   0xaBCdef01  after"),
            Ok((0xabcdef01, "  after")),
        );
        assert_eq!(
            parse_u32("   0xffgoat"),
            Ok((255, "goat")),
        );
        assert_eq!(
            parse_u32(" \t  0100  after"),
            Ok((64, "  after")),
        );
    }

    #[test]
    fn test_signed() {
        assert_eq!(
            parse_i64(&i64::MAX.to_string()).unwrap(),
            (i64::MAX, ""),
        );
        assert_eq!(
            parse_i32(&i32::MAX.to_string()).unwrap(),
            (i32::MAX, ""),
        );
        assert_eq!(
            parse_i16(&i16::MAX.to_string()).unwrap(),
            (i16::MAX, ""),
        );
        assert_eq!(
            parse_i8(&i8::MAX.to_string()).unwrap(),
            (i8::MAX, ""),
        );
        assert_eq!(
            parse_i64(&i64::MIN.to_string()).unwrap(),
            (i64::MIN, ""),
        );
        assert_eq!(
            parse_i32(&i32::MIN.to_string()).unwrap(),
            (i32::MIN, ""),
        );
        assert_eq!(
            parse_i16(&i16::MIN.to_string()).unwrap(),
            (i16::MIN, ""),
        );
        assert_eq!(
            parse_i8(&i8::MIN.to_string()).unwrap(),
            (i8::MIN, ""),
        );

        assert_eq!(
            parse_i8("-0"),
            Ok((0, "")),
        );

        assert_eq!(
            parse_i8("  -0 0"),
            Ok((0, " 0")),
        );

        assert!(matches!(
            parse_i8("128"),
            Err(ParseError::SignedOverflow),
        ));
        assert!(matches!(
            parse_i8("-129"),
            Err(ParseError::SignedOverflow),
        ));

        assert_eq!(
            parse_i8("   0x42  after"),
            Ok((66, "  after")),
        );
        assert_eq!(
            parse_i32(" \t  0100  after"),
            Ok((64, "  after")),
        );
        assert_eq!(
            parse_i8("   -0x42  after"),
            Ok((-66, "  after")),
        );
        assert_eq!(
            parse_i32(" \t  -0100  after"),
            Ok((-64, "  after")),
        );
    }
}

```

--------------------------------------------------------------------------------
/.github/workflows/build-push-image.yml:
--------------------------------------------------------------------------------

```yaml
name: Build and Push Image

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  prepare:
    name: Prepare Build Environment
    runs-on: ubuntu-latest
    outputs:
      repo_name: ${{ steps.meta.outputs.repo_name }}
      short_sha: ${{ steps.meta.outputs.short_sha }}
    steps:
      - name: Extract metadata
        id: meta
        run: |
          echo "repo_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
          echo "short_sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT

  build-amd64:
    name: Build for amd64
    needs: prepare
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push amd64 image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          platforms: linux/amd64
          tags: |
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-latest
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-${{ needs.prepare.outputs.short_sha }}
          labels: |
            org.opencontainers.image.source=https://github.com/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.description=Docker image for amd64
          cache-from: type=gha
          cache-to: type=gha,mode=max

  build-arm64:
    name: Build for arm64
    needs: prepare
    runs-on: ubuntu-24.04-arm
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push arm64 image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          platforms: linux/arm64
          tags: |
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-latest
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-${{ needs.prepare.outputs.short_sha }}
          labels: |
            org.opencontainers.image.source=https://github.com/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.description=Docker image for arm64
          cache-from: type=gha
          cache-to: type=gha,mode=max

  build-riscv64:
    if: false # Needs hosted runner
    name: Build for riscv64
    needs: prepare
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push riscv64 image
        id: build_riscv64
        continue-on-error: true
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          platforms: linux/riscv64
          tags: |
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-latest
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-${{ needs.prepare.outputs.short_sha }}
          labels: |
            org.opencontainers.image.source=https://github.com/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.description=Docker image for riscv64
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Set build status
        id: status
        run: echo "success=${{ steps.build_riscv64.outcome == 'success' }}" >> $GITHUB_OUTPUT

    outputs:
      success: ${{ steps.status.outputs.success }}

  build-ppc64le:
    if: false # Needs hosted runner
    name: Build for ppc64le
    needs: prepare
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push ppc64le image
        id: build_ppc64le
        continue-on-error: true
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          platforms: linux/ppc64le
          tags: |
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-latest
            ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-${{ needs.prepare.outputs.short_sha }}
          labels: |
            org.opencontainers.image.source=https://github.com/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}
            org.opencontainers.image.description=Docker image for ppc64le
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Set build status
        id: status
        run: echo "success=${{ steps.build_ppc64le.outcome == 'success' }}" >> $GITHUB_OUTPUT

    outputs:
      success: ${{ steps.status.outputs.success }}

  create-manifest:
    name: Create Multi-Arch Manifest
    needs: [prepare, build-amd64, build-arm64] # [build-riscv64, build-ppc64le]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    if: github.event_name != 'pull_request'
    steps:
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Create and push multi-arch manifests
        run: |

          LATEST_SOURCES="ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-latest"
          SHA_SOURCES="ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-${{ needs.prepare.outputs.short_sha }}"


          # if [ "${{ needs.build-arm64.outputs.success }}" == "true" ]; then
          #   LATEST_SOURCES="${LATEST_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-latest"
          #   SHA_SOURCES="${SHA_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-${{ needs.prepare.outputs.short_sha }}"
          # fi


          # if [ "${{ needs.build-riscv64.outputs.success }}" == "true" ]; then
          #   LATEST_SOURCES="${LATEST_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-latest"
          #   SHA_SOURCES="${SHA_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-${{ needs.prepare.outputs.short_sha }}"
          # fi

          # if [ "${{ needs.build-ppc64le.outputs.success }}" == "true" ]; then
          #   LATEST_SOURCES="${LATEST_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-latest"
          #   SHA_SOURCES="${SHA_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-${{ needs.prepare.outputs.short_sha }}"
          # fi


          echo "Creating latest manifest from: ${LATEST_SOURCES}"
          docker buildx imagetools create --tag ghcr.io/${{ needs.prepare.outputs.repo_name }}:latest ${LATEST_SOURCES}


          echo "Creating SHA manifest from: ${SHA_SOURCES}"
          docker buildx imagetools create --tag ghcr.io/${{ needs.prepare.outputs.repo_name }}:${{ needs.prepare.outputs.short_sha }} ${SHA_SOURCES}

```
Page 1/7FirstPrevNextLast