This is page 1 of 9. Use http://codebase.md/mehmetoguzderin/shaderc-vkrunner-mcp?lines=true&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: -------------------------------------------------------------------------------- ``` 1 | /target 2 | ``` -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- ``` 1 | * text=auto eol=lf 2 | ``` -------------------------------------------------------------------------------- /vkrunner/.gitignore: -------------------------------------------------------------------------------- ``` 1 | /Cargo.lock 2 | /target 3 | /tmp-build 4 | ``` -------------------------------------------------------------------------------- /vkrunner/.editorconfig: -------------------------------------------------------------------------------- ``` 1 | # To use this config on you editor, follow the instructions at: 2 | # http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | insert_final_newline = true 9 | tab_width = 8 10 | 11 | [*.{c,h,cpp,hpp,cc,hh}] 12 | indent_style = space 13 | indent_size = 8 14 | 15 | [{Makefile*,*.mk}] 16 | indent_style = tab 17 | 18 | [{*.py,SCons*}] 19 | indent_style = space 20 | indent_size = 4 21 | ``` -------------------------------------------------------------------------------- /vkrunner/.gitlab-ci.yml: -------------------------------------------------------------------------------- ```yaml 1 | include: 2 | - project: 'freedesktop/ci-templates' 3 | ref: ea3f77641d91765396beba192b8defd3085fa343 4 | file: '/templates/fedora.yml' 5 | 6 | stages: 7 | - prep 8 | - test 9 | 10 | variables: 11 | FDO_UPSTREAM_REPO: mesa/vkrunner 12 | 13 | .vkrunner.fedora:42: 14 | variables: 15 | FDO_DISTRIBUTION_VERSION: 42 16 | FDO_DISTRIBUTION_TAG: '2025-04-17.1' 17 | 18 | build-fedora-container: 19 | extends: 20 | - .fdo.container-build@fedora 21 | - .vkrunner.fedora:42 22 | stage: prep 23 | variables: 24 | FDO_DISTRIBUTION_PACKAGES: "cargo bindgen-cli glslang" 25 | 26 | cargo-test: 27 | extends: 28 | - .fdo.distribution-image@fedora 29 | - .vkrunner.fedora:42 30 | stage: test 31 | script: 32 | - cargo test 33 | ``` -------------------------------------------------------------------------------- /vkrunner/README.md: -------------------------------------------------------------------------------- ```markdown 1 | # VkRunner 2 | 3 | VkRunner is a Vulkan shader tester based on `shader_runner` in 4 | [Piglit](https://piglit.freedesktop.org/). The goal is to make it be 5 | able to test scripts as similar to Piglit’s shader_test format as 6 | possible. 7 | 8 | ## Building 9 | 10 | VkRunner requires Cargo and a rust compiler to build. 11 | 12 | To build it type: 13 | 14 | ``` 15 | cargo build 16 | ``` 17 | 18 | Can can then run VkRunner by typing: 19 | 20 | ``` 21 | cargo run 22 | ``` 23 | 24 | ## Installing 25 | 26 | The vkrunner binary can be installed like so: 27 | 28 | ``` 29 | cargo install --path . --root <install_root> 30 | ``` 31 | 32 | ## Running 33 | 34 | VkRunner requires glslangValidator to compile GLSL to SPIR-V. It is 35 | invoked on the fly while executing the test. It must either be 36 | available in your path or you can set the variable 37 | `PIGLIT_GLSLANG_VALIDATOR_BINARY` to point to it. It can be obtained 38 | from [here](https://github.com/KhronosGroup/glslang/). 39 | 40 | ## [test] section: 41 | 42 | The `[test]` section supports the following commands: 43 | 44 | > draw rect [ortho] [patch] _x_ _y_ _width_ _height_ 45 | 46 | Draws a rectangle at the given normalised coordinates. The vertices 47 | will be uploaded at vertex input location 0 as a vec3. Remember that 48 | Vulkan’s normalised coordinate system is different from OpenGL’s. If 49 | `ortho` is specified then the coordinates are scaled from the range 50 | [0,window size] to [-1,1] to make it easier to specify the positions 51 | in pixels. If `patch` is given then a patch topology will be used with 52 | a patch size of four. 53 | 54 | > draw arrays [indexed] [instanced] _topology_ _firstVertex_ _vertexCount_ [_instanceCount_] 55 | 56 | Calls `vkCmdDraw` with the given parameters. The vertex data will be 57 | sourced from the `[vertex data]` section. The _topology_ should be one 58 | of the values of VkPrimitiveTopology minus the VK\_PRIMITIVE\_TOPOLOGY 59 | prefix. Alternatively it can be a GLenum value as used in Piglit. 60 | 61 | If `indexed` is specified then `vkCmdDrawIndexed` will be use to draw 62 | the primitive instead. The indices will be sourced from the 63 | `[indices]` section. _vertexCount_ will be used as the index count, 64 | _firstVertex_ becomes the vertex offset and _firstIndex_ will always 65 | be zero. 66 | 67 | > compute _x_ _y_ _z_ 68 | 69 | Dispatch the compute shader with the given parameters. 70 | 71 | > [relative] probe [rect] (rgb|rgba) (_x_, _y_[, _width_, _height_]) (_r_, _g_, _b_[, _a_]) 72 | 73 | Verifies that a given rectangle matches the given colour. If the 74 | command begins with the keyword `relative` then the coordinates are 75 | normalised from 0.0 to 1.0, otherwise they are pixel coordinates. 76 | Either way the origin is the top-left corner of the image. If `rect` 77 | is not specified then the width and height are set to 1 pixel. The 78 | alpha component of the image can be ignored or not by specifying 79 | either `rgb` or `rgba`. 80 | 81 | > probe all (rgb|rgba) _r_ _g_ _b_ [_a_] 82 | 83 | The same as above except that it probes the entire window. 84 | 85 | > push _type_ _offset_ _values_… 86 | 87 | Sets a push constant at the given offset. Note that unlike Piglit, the 88 | offset is a byte offset into the push constant buffer rather than a 89 | uniform location. For a description of how the arguments work see 90 | “Setting buffer subdata” below. 91 | 92 | > (ubo|ssbo) _binding_ subdata _type_ _offset_ _values_… 93 | 94 | Sets a value within a uniform or storage buffer. The first time a 95 | value is set within a buffer it will be created with the minimum size 96 | needed to contain all of the values set on it via test commands. It 97 | will then be bound to the descriptor set at the given binding point. 98 | The rest of the arguments are used as described in “Setting buffer 99 | subdata” below. 100 | 101 | Note that the buffer is just updated by writing into a memory mapped 102 | view of it which means that if you do an update, draw call, update and 103 | then another draw call both draws will use the values from the second 104 | update. This is because the draws are not flushed until the next probe 105 | command or the test completes. 106 | 107 | > (ubo|ssbo) _binding_ _size_ 108 | 109 | Sets the size of a uniform or storage buffer. This is optional if 110 | there are buffer subdata commands because in that case it will just 111 | take the size of the largest offset. 112 | 113 | > probe ssbo _type_ _binding_ _offset_ _comparison_ _values_… 114 | 115 | Probes a value in the storage buffer at _binding_. The _comparison_ 116 | can be one of `==`, `!=`, `<`, `>=`, `>`, `<=` or `~=`. If the type 117 | has more than one component then they are compared individually until 118 | one of them fails the comparison. `~=` is the same with `==` but `~=` 119 | allows errors for `double` or `float` type numbers while `==` does 120 | not. Allowed errors can be set by the following `tolerance` command. 121 | See [examples/tolerance.shader_test](examples/tolerance.shader_test) 122 | for the usage of `~=`. Multiple values can be listed to compare an 123 | array of values. In that case the buffer is assumed to have the layout 124 | specified with the last `ssbo layout` command. 125 | 126 | > tolerance _tolerance0 tolerance1 tolerance2 tolerance3_ 127 | 128 | Sets four tolerances i.e., allowed errors. `vecN` type values will 129 | use first `N` tolerances among those four. Each column of `matMxN` type 130 | values will also use first `N` tolerances. `float` and `double` type 131 | values will use only the first tolerance. Each tolerance value can be 132 | an `double` type real number or percentage e.g., `0.01%`. `tolerance` 133 | command can be also used for comparisons of pixels. See 134 | [examples/tolerance.shader_test]( examples/tolerance.shader_test) for 135 | the usage of `tolerance` command. 136 | 137 | > tolerance _tolerance0_ 138 | 139 | Sets a tolerance i.e., an allowed error. If this command is set, all 140 | components of `vecN` and `matMxN` type values will use the same 141 | tolerance. Each tolerance value can be an `double` type real number or 142 | percentage e.g., `0.01%`. See [examples/tolerance.shader_test]( 143 | examples/tolerance.shader_test) for the usage of `tolerance` command. 144 | 145 | > push layout [std140|std430] [row_major|column_major] 146 | 147 | > ssbo layout [std140|std430] [row_major|column_major] 148 | 149 | > ubo layout [std140|std430] [row_major|column_major] 150 | 151 | Sets the expected layout for subsequent commands that operate on push 152 | constants, SSBOs and UBOs respectively. All layouts default to std430 153 | and column_major except the UBO layout which defaults to std140. This 154 | matches the defaults in GLSL. If row_major or column_major is not 155 | specified then it will be set back to column_major (ie, it does not 156 | leave it at as row_major if a previous layout command set it to that). 157 | Note that setting the matrix major axis only affects the layout of the 158 | data in memory. The values are still specified in test commands in 159 | column-major order. 160 | 161 | > clear color _r_ _g_ _b_ _a_ 162 | 163 | Sets the color to use for subsequent clear commands. Defaults to all 164 | zeros. 165 | 166 | > clear depth _value_ 167 | 168 | Sets the value to clear the depth buffer to in subsequent clear 169 | commands. Defaults to 1.0. 170 | 171 | > clear stencil _value_ 172 | 173 | Sets the value to clear the stencil buffer to in subsequent clear 174 | commands. Defaults to 0. 175 | 176 | > clear 177 | 178 | Clears the entire framebuffer to the previously set clear color, depth 179 | and stencil values. 180 | 181 | > patch parameter vertices _vertices_ 182 | 183 | Sets the number of control points for tessellation patches in 184 | subsequent draw calls. Defaults to 3. 185 | 186 | > topology, primitiveRestartEnable, patchControlPoints, 187 | > depthClampEnable, rasterizerDiscardEnable, polygonMode, cullMode, 188 | > frontFace, depthBiasEnable, depthBiasConstantFactor, depthBiasClamp, 189 | > depthBiasSlopeFactor, lineWidth, logicOpEnable, logicOp, 190 | > blendEnable, srcColorBlendFactor, dstColorBlendFactor, colorBlendOp, 191 | > srcAlphaBlendFactor, dstAlphaBlendFactor, alphaBlendOp, 192 | > colorWriteMask, depthTestEnable, depthWriteEnable, depthCompareOp, 193 | > depthBoundsTestEnable, stencilTestEnable, front.failOp, 194 | > front.passOp, front.depthFailOp, front.compareOp, front.compareMask, 195 | > front.writeMask, front.reference, back.failOp, back.passOp, 196 | > back.depthFailOp, back.compareOp, back.compareMask, back.writeMask, 197 | > back.reference 198 | 199 | These properties can be set on a pipeline by specifying their name 200 | followed by a value in the test section. This will affect subsequent 201 | draw calls. If multiple draw calls are issued with different values 202 | for these properties then a separate pipeline will be created for each 203 | set of state. See the `properties.shader_test` example for details. 204 | 205 | > _stage_ entrypoint _name_ 206 | 207 | Sets the entrypoint function to _name_ for the given stage. This will 208 | be used for subsequent draw calls or compute dispatches. 209 | 210 | > uniform _type_ _offset_ _values_… 211 | 212 | This is equivalent to push _type_ _offset_ _values_. It is provided 213 | for compatibility with Piglit. 214 | 215 | > uniform ubo _binding_ _type_ _offset_ _values_… 216 | 217 | This is equivalent to ubo _binding_ subdata _type_ _offset_ _values_. 218 | It is provided for compatibility with Piglit. 219 | 220 | Take a look in the examples directory for more examples. 221 | 222 | ## Setting buffer subdata 223 | 224 | The commands to set push constants, ubo data and ssbo data all take 225 | the same three arguments `type`, `offset` and `values…`. These are 226 | used to describe a chunk of data to store at the given offset in the 227 | corresponding buffer. The commands can be used multiple times with 228 | different offsets to set data at different locations. 229 | 230 | The type can be one of int, uint, int8_t, uint8_t, int16_t, uint16_t, 231 | int64_t, uint64_t, float16_t, float, double, f16vec[234], vec[234], 232 | dvec[234], ivec[234], uvec[234], i8vec[234], u8vec[234], i16vec[234], 233 | u16vec[234], i64vec[234], u64vec[234], mat[234]x[234] or 234 | dmat[234]x[234]. 235 | 236 | The values argument contains one integer or float for each component 237 | of the given type. Multiple values can be specified in a single 238 | command to set an array of values of the given type. 239 | 240 | Each buffer type (push constant, UBO and SSBO) has a corresponding 241 | current layout which is either std140 or std430. The current layout 242 | only matters for matrix types or for specifying array values with a 243 | single command. It is used to calculate the array stride and matrix 244 | stride for the given type. The default layouts for each buffer type 245 | correspond to the defaults for the corresponding buffer type in GLSL. 246 | Note that the layout is only used as a convenience to set values in 247 | memory. If you want to use a custom layout it is still always possible 248 | to set all the values using multiple commands and explicit offsets. 249 | 250 | Some examples: 251 | 252 | ssbo 0 subdata float 12 42.0 253 | 254 | This will write the float value 42 twelve bytes into the buffer at 255 | binding 0. 256 | 257 | ssbo layout std140 258 | ssbo 0 subdata float 32 1 2 3 259 | 260 | This will write the float values 1, 2, 3 into the buffer starting at 261 | byte 32 arranged such so that it would be suitable for an array of floats 262 | declared as std140 such as this: 263 | 264 | ```GLSL 265 | layout(binding = 0, std140) buffer block { 266 | layout(offset = 32) float one_two_three[3]; 267 | }; 268 | ``` 269 | 270 | The rules of std140 force the array stride to be a multiple of a vec4 271 | so this will effectively write the following floats starting at byte 272 | 32: 273 | 274 | ``` 275 | 1 0 0 0 2 0 0 0 3 276 | ``` 277 | 278 | ``` 279 | ssbo layout std430 280 | ssbo 0 subdata mat3 12 1 2 3 4 5 6 7 8 9 281 | ``` 282 | 283 | This will write a mat3 starting at offset 12. std430 treats this like 284 | an array of 3 vec3s. The stride for vec3s is padded up to vec4 so it 285 | would write the floats like this: 286 | 287 | ``` 288 | 1 2 3 0 4 5 6 0 7 8 9 289 | ``` 290 | 291 | ``` 292 | ssbo layout std430 row_major 293 | ssbo 0 subdata mat3 12 1 2 3 4 5 6 7 8 9 294 | ``` 295 | 296 | This will write the same matrix but laid out in a way suitable for a 297 | uniform declared as row_major. It will look like this: 298 | 299 | 1 4 7 0 2 5 8 0 3 6 9 300 | 301 | ## [require] section 302 | 303 | > _feature_ 304 | 305 | The `[require]` section can contain names of members from 306 | VkPhysicalDeviceFeatures. These will be searched for when deciding 307 | which physical device to open. If no physical device with the 308 | corresponding requirements can be found then it will report an error. 309 | 310 | In addition to VkPhysicalDeviceFeatures, the name of a feature from 311 | any feature struct from an extension that VkRunner is aware of can 312 | also be requested. In that case VkRunner will also implicitly require 313 | the corresponding device extension. It will also need the 314 | `VK_KHR_get_physical_device_properties2` instance extension in order 315 | to check for the feature. For example, specifying `shaderFloat16` in 316 | the require section will make it also require the 317 | `VK_KHR_shader_float16_int8` extension. VkRunner will then enable the 318 | feature via the VkPhysicalDeviceFloat16Int8FeaturesKHR struct when 319 | creating the device. 320 | 321 | > _extension_ 322 | 323 | Any line that is not a feature and contains entirely alphanumeric and 324 | underscore characters is assumed to be a device extension name. This 325 | will be checked for when searching for a suitable device and if no 326 | device with the extension is found then the test will report that it 327 | was skipped. Otherwise the extension will be enabled when creating the 328 | device. 329 | 330 | The required Vulkan implementation version for the test can also be 331 | set in this section. If the version is not supported by the device 332 | driver the test will be skipped. 333 | 334 | > framebuffer _format_ 335 | 336 | Use this to specify the format of the framebuffer using a format from 337 | VkFormat minus the VK_FORMAT prefix. 338 | 339 | > depthstencil _format_ 340 | 341 | If this is specified VkRunner will try to add a depth-stencil 342 | attachment to the framebuffer with the given format. Without it no 343 | depth-stencil buffer will be created. 344 | 345 | > fbsize _width_ _height_ 346 | 347 | Specify the size of the framebuffer. If not specified it defaults to 348 | 250x250. 349 | 350 | > vulkan _major_._minor_._patch_ 351 | 352 | Use this to specify the Vulkan implementation version against which 353 | the test should run. 354 | 355 | > subgroup_size _size_ 356 | 357 | Specify the required subgroup size for the compute shaders in the pipeline. 358 | See Vulkan documentation for `VkPipelineShaderStageRequiredSubgroupSizeCreateInfo` 359 | for more details. 360 | 361 | > cooperative_matrix [params...] 362 | 363 | Specify that Cooperative Matrix support is required. It will automatically 364 | require VK_KHR_cooperative_matrix extension and the cooperativeMatrix feature. 365 | 366 | Matrix configuration requirements is provided by passing the attributes 367 | for each item, e.g. `m=16 a=float`. The items available are `m=`, `n=` 368 | and `k=` for the matrix sizes; `a=`, `b=`, `c=` and `result=` for the 369 | element types of each matrix; `saturating_accumulation=true|false` and 370 | `scope=` for extra options. See Vulkan documentation for 371 | `VkCooperativeMatrixPropertiesKHR` for more details. 372 | 373 | If an item is not specified, it will match any value available. If 374 | multiple different configurations are required, use multiple 375 | `cooperative_matrix` lines. 376 | 377 | ## Shader sections 378 | 379 | Shaders can be stored in sections like `[vertex shader]` just like in 380 | `shader_runner`. Multiple GLSL shaders can be given for a single stage 381 | and they will be linked together via glslangValidator. 382 | 383 | Alternatively, the disassembly of the SPIR-V source can be provided 384 | with a section like `[vertex shader spirv]`. This will be assembled 385 | with `spirv-as`. If a SPIR-V section is given for a stage there can be 386 | no other shaders for that stage. 387 | 388 | The vertex shader can also be skipped with an empty section called 389 | `[vertex shader passthrough]`. That will create a simple vertex shader 390 | than just copies a vec4 for input location 0 to `gl_Position`. 391 | 392 | ## [vertex data] section 393 | 394 | The `[vertex data]` section is used to specify vertex attributes and 395 | data for use with the draw arrays command. It is similar to Piglit 396 | except that integer locations are used instead of names and matrices 397 | are specifed by using a location within the matrix rather than having 398 | a separate field. 399 | 400 | The format consists of a row of column headers followed by any number 401 | of rows of data. Each column header has the form _ATTRLOC_/_FORMAT_ 402 | where _ATTRLOC_ is the location of the vertex attribute to be bound to 403 | this column and _FORMAT_ is the name of a VkFormat minus the VK_FORMAT 404 | prefix. 405 | 406 | Alternatively the column header can use something closer the Piglit 407 | format like _ATTRLOC_/_GL\_TYPE_/_GLSL\_TYPE_. _GL\_TYPE_ is the GL 408 | type of data that follows (“half”, “float”, “double”, “byte”, “ubyte”, 409 | “short”, “ushort”, “int” or “uint”), _GLSL\_TYPE_ is the GLSL type of 410 | the data (“int”, “uint”, “float”, “double”, “ivec”\*, “uvec”\*, 411 | “vec”\*, “dvec”\*). 412 | 413 | The data follows the column headers in space-separated form. “#” can 414 | be used for comments, as in shell scripts. See the 415 | `vertex-data.shader_test` file as an example. 416 | 417 | ## [indices] section 418 | 419 | The `[indices]` section just contains a list of indices to use along 420 | with the vertices in `[vertex data]`. It will be used if the `indexed` 421 | option is given to the `draw arrays` test command. 422 | 423 | ## Long lines 424 | 425 | Long lines anywhere in the script can be split into multiple lines by 426 | using a backslash to combine them. For example a line to set an array 427 | of ints could be split up as follows: 428 | 429 | ``` 430 | ubo 0 subdata int 0 \ 431 | 1 2 3 5 8 13 21 34 55 89 144 233 377 610 \ 432 | 987 1597 2584 4181 6765 10946 17711 28657 \ 433 | 46368 75025 121393 196418 317811 514229 434 | ``` 435 | 436 | ## Command line arguments 437 | 438 | usage: vkrunner [OPTION]... SCRIPT... 439 | Runs the shader test script SCRIPT 440 | 441 | Options: 442 | -h Show this help message 443 | -i IMG Write the final rendering to IMG as a PPM image 444 | -d Show the SPIR-V disassembly 445 | -D TOK=REPL Replace occurences of TOK with REPL in the scripts 446 | --device-id DEVID Select the Vulkan device 447 | 448 | ## Precompiling shaders 449 | 450 | As an alternative to specifying the shaders in GLSL or SPIR-V 451 | assembly, the test scripts can contain a hex dump of the SPIR-V. That 452 | way VkRunner does not need to invoke the compiler or assembler to run 453 | the script. This can be useful either to speed up the execution of the 454 | tests or to run them on hardware where installing the compiler is not 455 | practical. VkRunner also includes a Python script to precompile the 456 | test scripts to binary. It can be run for example as below: 457 | 458 | ./precompile-script.py -o compiled-examples examples/*.shader_test 459 | ./src/vkrunner compiled-examples/*.shader_test 460 | 461 | If glslangValidator and spirv-as are not in the path, you can indicate 462 | where the binaries are with the following command line arguments: 463 | 464 | ./precompile-script.py -o compiled-examples examples/*.shader_test -g PATH_GLSLANG/glslangValidator -s PATH_SPIRV_AS/spirv-as 465 | ``` -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- ```yaml 1 | version: '3' 2 | 3 | services: 4 | app: 5 | build: 6 | context: .. 7 | dockerfile: .devcontainer/Dockerfile 8 | volumes: 9 | - ..:/workspace:cached 10 | command: sleep infinity 11 | # Keep the container running 12 | tty: true ``` -------------------------------------------------------------------------------- /vkrunner/Cargo.toml: -------------------------------------------------------------------------------- ```toml 1 | [package] 2 | name = "vkrunner" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | description = "A shader testing tool for Vulkan" 7 | repository = "https://gitlab.freedesktop.org/mesa/vkrunner/" 8 | default-run = "vkrunner" 9 | 10 | [lib] 11 | path = "vkrunner/lib.rs" 12 | 13 | [build-dependencies] 14 | bindgen = "0.66.1" 15 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codecs_common.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_VIDEO_CODECS_COMMON_H_ 2 | #define VULKAN_VIDEO_CODECS_COMMON_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | // vulkan_video_codecs_common is a preprocessor guard. Do not pass it to API calls. 23 | #define vulkan_video_codecs_common 1 24 | #if !defined(VK_NO_STDINT_H) 25 | #include <stdint.h> 26 | #endif 27 | 28 | #define VK_MAKE_VIDEO_STD_VERSION(major, minor, patch) \ 29 | ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) 30 | 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif 37 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/lib.rs: -------------------------------------------------------------------------------- ```rust 1 | mod small_float; 2 | mod half_float; 3 | mod hex; 4 | mod format; 5 | mod tolerance; 6 | mod util; 7 | mod parse_num; 8 | mod vbo; 9 | mod vk; 10 | mod vulkan_funcs; 11 | mod requirements; 12 | mod slot; 13 | pub mod result; 14 | mod shader_stage; 15 | mod pipeline_key; 16 | mod window_format; 17 | mod source; 18 | mod config; 19 | mod stream; 20 | mod script; 21 | mod context; 22 | mod buffer; 23 | mod window; 24 | mod allocate_store; 25 | mod executor; 26 | mod temp_file; 27 | mod logger; 28 | mod compiler; 29 | mod pipeline_set; 30 | mod flush_memory; 31 | pub mod inspect; 32 | mod tester; 33 | 34 | #[cfg(test)] 35 | mod fake_vulkan; 36 | #[cfg(test)] 37 | mod env_var_test; 38 | 39 | // Re-export the public API 40 | pub use config::Config; 41 | pub use executor::Executor; 42 | pub use format::Format; 43 | pub use script::Script; 44 | pub use shader_stage::Stage; 45 | pub use source::Source; 46 | ``` -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "shaderc-vkrunner-mcp", 3 | "dockerComposeFile": "docker-compose.yml", 4 | "service": "app", 5 | "workspaceFolder": "/workspace", 6 | "customizations": { 7 | "vscode": { 8 | "extensions": [ 9 | "GitHub.copilot", 10 | "GitHub.copilot-chat", 11 | "charliermarsh.ruff", 12 | "eamodio.gitlens", 13 | "llvm-vs-code-extensions.vscode-clangd", 14 | "ms-python.python", 15 | "ms-vscode.cmake-tools", 16 | "rust-lang.rust-analyzer", 17 | "tamasfe.even-better-toml" 18 | ], 19 | "settings": { 20 | "terminal.integrated.defaultProfile.linux": "bash" 21 | } 22 | } 23 | }, 24 | "remoteUser": "root" 25 | } ``` -------------------------------------------------------------------------------- /.vscode/mcp.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "servers": { 3 | "shaderc-vkrunner-mcp-dev": { 4 | "type": "stdio", 5 | "command": "cargo", 6 | "args": [ 7 | "run", 8 | "--release", 9 | "--manifest-path", 10 | "${workspaceFolder}/Cargo.toml", 11 | "--", 12 | "--work-dir", 13 | "${workspaceFolder}" 14 | ] 15 | }, 16 | "shaderc-vkrunner-mcp": { 17 | "type": "stdio", 18 | "command": "docker", 19 | "args": [ 20 | "run", 21 | "--rm", 22 | "-i", 23 | "-v", 24 | "${workspaceFolder}:/work", 25 | "shaderc-vkrunner-mcp", 26 | "--work-dir", 27 | "/work" 28 | ] 29 | } 30 | } 31 | } ``` -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- ```toml 1 | [package] 2 | name = "shaderc-vkrunner-mcp" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "main", features = [ 8 | "server", 9 | "transport-sse-server", 10 | "transport-io", 11 | ] } 12 | tokio = { version = "1", features = [ 13 | "macros", 14 | "rt", 15 | "rt-multi-thread", 16 | "io-std", 17 | "signal", 18 | ] } 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = "1.0" 21 | anyhow = "1.0" 22 | tracing = "0.1" 23 | tracing-subscriber = { version = "0.3", features = [ 24 | "env-filter", 25 | "std", 26 | "fmt", 27 | ] } 28 | futures = "0.3" 29 | rand = { version = "0.9" } 30 | axum = { version = "0.8", features = ["macros"] } 31 | schemars = { version = "0.8", optional = true } 32 | image = "0.25.6" 33 | clap = { version = "4.5.36", features = ["derive"] } 34 | shaderc = "0.9.1" 35 | vkrunner = { path = "./vkrunner", features = [] } 36 | 37 | [dev-dependencies] 38 | tokio-stream = { version = "0.1" } 39 | tokio-util = { version = "0.7", features = ["codec"] } 40 | ``` -------------------------------------------------------------------------------- /vkrunner/scripts/update-vulkan.sh: -------------------------------------------------------------------------------- ```bash 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright 2025 Intel Corporation 4 | # SPDX-License-Identifier: MIT 5 | 6 | set -e 7 | 8 | if [ ! -f "Cargo.toml" ]; then 9 | echo "Run the script from the root of the repository." 10 | exit 1 11 | fi 12 | 13 | SKIP_DOWNLOAD= 14 | 15 | for arg in "$@"; do 16 | case $arg in 17 | --skip-download) 18 | SKIP_DOWNLOAD=1 19 | shift 20 | ;; 21 | *) 22 | shift 23 | ;; 24 | esac 25 | done 26 | 27 | if [ -z "$SKIP_DOWNLOAD" ]; then 28 | VULKAN_HEADERS=$(mktemp -d) 29 | git clone https://github.com/KhronosGroup/Vulkan-Headers.git "$VULKAN_HEADERS" 30 | git -C "$VULKAN_HEADERS" log -1 31 | 32 | cp -f $VULKAN_HEADERS/include/vk_video/*.h include/vk_video/ 33 | cp -f $VULKAN_HEADERS/include/vulkan/{vulkan.h,vulkan_core.h,vk_platform.h} include/vulkan/ 34 | fi 35 | 36 | # TODO: Most of these scripts should be using the registry/vk.xml instead of 37 | # parsing the C headers. 38 | 39 | echo | gcc -include "./include/vulkan/vulkan.h" -E - | vkrunner/make-enums.py > vkrunner/enum_table.rs 40 | vkrunner/make-features.py < include/vulkan/vulkan_core.h > vkrunner/features.rs 41 | vkrunner/make-formats.py < include/vulkan/vulkan_core.h > vkrunner/format_table.rs 42 | vkrunner/make-pipeline-key-data.py > vkrunner/pipeline_key_data.rs 43 | vkrunner/make-vulkan-funcs-data.py > vkrunner/vulkan_funcs_data.rs 44 | ``` -------------------------------------------------------------------------------- /vkrunner/test-build.sh: -------------------------------------------------------------------------------- ```bash 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | src_dir="$(cd $(dirname "$0") && pwd)" 6 | build_dir="$src_dir/tmp-build" 7 | install_dir="$build_dir/install" 8 | device_id="" 9 | 10 | if [ $# -gt 0 ] && [ "$1" = "--device-id" ]; then 11 | if [ -z "${2:-}" ]; then 12 | echo "--device-id must be followed by a number" 13 | exit 1 14 | fi 15 | device_id="--device-id $2" 16 | fi 17 | 18 | rm -fr -- "$build_dir" 19 | 20 | cargo test --target-dir "$build_dir" 21 | cargo install --target-dir "$build_dir" --path . --root "$install_dir" 22 | 23 | # Run the built executable with all of the examples and enable the 24 | # validation layer. Verify that nothing was written to the output. 25 | VKRUNNER_ALWAYS_FLUSH_MEMORY=true \ 26 | VK_LOADER_LAYERS_ENABLE="*validation" \ 27 | "$install_dir/bin/vkrunner" \ 28 | -q \ 29 | "$src_dir/examples"/*.shader_test \ 30 | 2>&1 \ 31 | | tee "$build_dir/output.txt" 32 | 33 | if grep -q --invert-match '^/tmp' "$build_dir/output.txt"; then 34 | echo "FAIL VkRunner had output with quiet flag" 35 | exit 1; 36 | fi 37 | 38 | # Try again with precompiled scripts 39 | "$src_dir"/precompile-script.py -o "$build_dir/precompiled-examples" \ 40 | "$src_dir/examples"/*.shader_test 41 | "$install_dir/bin/vkrunner" $device_id \ 42 | "$build_dir/precompiled-examples/"*.shader_test 43 | 44 | echo 45 | echo "Test build succeeded." 46 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vulkan/vulkan.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_H_ 2 | #define VULKAN_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | #include "vk_platform.h" 11 | #include "vulkan_core.h" 12 | 13 | #ifdef VK_USE_PLATFORM_ANDROID_KHR 14 | #include "vulkan_android.h" 15 | #endif 16 | 17 | #ifdef VK_USE_PLATFORM_FUCHSIA 18 | #include <zircon/types.h> 19 | #include "vulkan_fuchsia.h" 20 | #endif 21 | 22 | #ifdef VK_USE_PLATFORM_IOS_MVK 23 | #include "vulkan_ios.h" 24 | #endif 25 | 26 | 27 | #ifdef VK_USE_PLATFORM_MACOS_MVK 28 | #include "vulkan_macos.h" 29 | #endif 30 | 31 | #ifdef VK_USE_PLATFORM_METAL_EXT 32 | #include "vulkan_metal.h" 33 | #endif 34 | 35 | #ifdef VK_USE_PLATFORM_VI_NN 36 | #include "vulkan_vi.h" 37 | #endif 38 | 39 | 40 | #ifdef VK_USE_PLATFORM_WAYLAND_KHR 41 | #include "vulkan_wayland.h" 42 | #endif 43 | 44 | 45 | #ifdef VK_USE_PLATFORM_WIN32_KHR 46 | #include <windows.h> 47 | #include "vulkan_win32.h" 48 | #endif 49 | 50 | 51 | #ifdef VK_USE_PLATFORM_XCB_KHR 52 | #include <xcb/xcb.h> 53 | #include "vulkan_xcb.h" 54 | #endif 55 | 56 | 57 | #ifdef VK_USE_PLATFORM_XLIB_KHR 58 | #include <X11/Xlib.h> 59 | #include "vulkan_xlib.h" 60 | #endif 61 | 62 | 63 | #ifdef VK_USE_PLATFORM_DIRECTFB_EXT 64 | #include <directfb.h> 65 | #include "vulkan_directfb.h" 66 | #endif 67 | 68 | 69 | #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 70 | #include <X11/Xlib.h> 71 | #include <X11/extensions/Xrandr.h> 72 | #include "vulkan_xlib_xrandr.h" 73 | #endif 74 | 75 | 76 | #ifdef VK_USE_PLATFORM_GGP 77 | #include <ggp_c/vulkan_types.h> 78 | #include "vulkan_ggp.h" 79 | #endif 80 | 81 | 82 | #ifdef VK_USE_PLATFORM_SCREEN_QNX 83 | #include <screen/screen.h> 84 | #include "vulkan_screen.h" 85 | #endif 86 | 87 | 88 | #ifdef VK_USE_PLATFORM_SCI 89 | #include <nvscisync.h> 90 | #include <nvscibuf.h> 91 | #include "vulkan_sci.h" 92 | #endif 93 | 94 | 95 | #ifdef VK_ENABLE_BETA_EXTENSIONS 96 | #include "vulkan_beta.h" 97 | #endif 98 | 99 | #endif // VULKAN_H_ 100 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/window_format.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2013, 2014, 2015, 2017, 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | use crate::format::Format; 25 | use crate::vk; 26 | 27 | #[derive(Clone, Debug, PartialEq)] 28 | pub struct WindowFormat { 29 | pub color_format: &'static Format, 30 | pub depth_stencil_format: Option<&'static Format>, 31 | pub width: usize, 32 | pub height: usize, 33 | } 34 | 35 | impl Default for WindowFormat { 36 | fn default() -> WindowFormat { 37 | let color_format = 38 | Format::lookup_by_vk_format(vk::VK_FORMAT_B8G8R8A8_UNORM); 39 | 40 | WindowFormat { 41 | color_format, 42 | depth_stencil_format: None, 43 | width: 250, 44 | height: 250, 45 | } 46 | } 47 | } 48 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/vk.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // on the rights to use, copy, modify, merge, publish, distribute, sub 9 | // license, and/or sell copies of the Software, and to permit persons to whom 10 | // the Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 | // VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | #![allow(non_camel_case_types)] 25 | #![allow(dead_code)] 26 | #![allow(non_upper_case_globals)] 27 | #![allow(non_snake_case)] 28 | 29 | mod bindings { 30 | #![allow(unused_imports)] 31 | include!(concat!(env!("OUT_DIR"), "/vulkan_bindings.rs")); 32 | } 33 | 34 | pub use self::bindings::*; 35 | 36 | /// Function to return a value that can be used where the Vulkan 37 | /// documentation specifies that `VK_NULL_HANDLE` can be used. 38 | #[cfg(target_pointer_width = "64")] 39 | pub fn null_handle<T>() -> *mut T { 40 | std::ptr::null_mut() 41 | } 42 | 43 | #[cfg(not(target_pointer_width = "64"))] 44 | pub fn null_handle() -> u64 { 45 | // On 32-bit platforms the non-dispatchable handles are defined as 46 | // a 64-bit integer instead of a pointer. 47 | 0u64 48 | } 49 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_h265std_decode.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ 2 | #define VULKAN_VIDEO_CODEC_H265STD_DECODE_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | // vulkan_video_codec_h265std_decode is a preprocessor guard. Do not pass it to API calls. 23 | #define vulkan_video_codec_h265std_decode 1 24 | #include "vulkan_video_codec_h265std.h" 25 | 26 | #define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) 27 | 28 | #define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_API_VERSION_1_0_0 29 | #define VK_STD_VULKAN_VIDEO_CODEC_H265_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_decode" 30 | #define STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE 8 31 | typedef struct StdVideoDecodeH265PictureInfoFlags { 32 | uint32_t IrapPicFlag : 1; 33 | uint32_t IdrPicFlag : 1; 34 | uint32_t IsReference : 1; 35 | uint32_t short_term_ref_pic_set_sps_flag : 1; 36 | } StdVideoDecodeH265PictureInfoFlags; 37 | 38 | typedef struct StdVideoDecodeH265PictureInfo { 39 | StdVideoDecodeH265PictureInfoFlags flags; 40 | uint8_t sps_video_parameter_set_id; 41 | uint8_t pps_seq_parameter_set_id; 42 | uint8_t pps_pic_parameter_set_id; 43 | uint8_t NumDeltaPocsOfRefRpsIdx; 44 | int32_t PicOrderCntVal; 45 | uint16_t NumBitsForSTRefPicSetInSlice; 46 | uint16_t reserved; 47 | uint8_t RefPicSetStCurrBefore[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; 48 | uint8_t RefPicSetStCurrAfter[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; 49 | uint8_t RefPicSetLtCurr[STD_VIDEO_DECODE_H265_REF_PIC_SET_LIST_SIZE]; 50 | } StdVideoDecodeH265PictureInfo; 51 | 52 | typedef struct StdVideoDecodeH265ReferenceInfoFlags { 53 | uint32_t used_for_long_term_reference : 1; 54 | uint32_t unused_for_reference : 1; 55 | } StdVideoDecodeH265ReferenceInfoFlags; 56 | 57 | typedef struct StdVideoDecodeH265ReferenceInfo { 58 | StdVideoDecodeH265ReferenceInfoFlags flags; 59 | int32_t PicOrderCntVal; 60 | } StdVideoDecodeH265ReferenceInfo; 61 | 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif 68 | ``` -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- ```dockerfile 1 | FROM ubuntu:25.04 AS devcontainer 2 | 3 | ENV DEBIAN_FRONTEND=noninteractive 4 | 5 | RUN apt-get update && apt-get install -y \ 6 | bc \ 7 | build-essential \ 8 | clang \ 9 | clang-format \ 10 | clang-tidy \ 11 | clang-tools \ 12 | clangd \ 13 | cmake \ 14 | curl \ 15 | ffmpeg \ 16 | git \ 17 | glslang-tools \ 18 | glslc \ 19 | jq \ 20 | libshaderc-dev \ 21 | libshaderc1 \ 22 | imagemagick \ 23 | libgl1-mesa-dri \ 24 | libvulkan-dev \ 25 | libvulkan1 \ 26 | mesa-utils \ 27 | mesa-vulkan-drivers \ 28 | ninja-build \ 29 | npm \ 30 | pipx \ 31 | python3 \ 32 | python3-pip \ 33 | python3-venv \ 34 | rustup \ 35 | sudo \ 36 | unzip \ 37 | vulkan-tools \ 38 | wget \ 39 | x11-utils \ 40 | xvfb \ 41 | && apt-get clean \ 42 | && rm -rf /var/lib/apt/lists/* 43 | 44 | RUN rustup install 1.86.0 && \ 45 | rustup default 1.86.0 46 | 47 | RUN rustup component add rustfmt && \ 48 | rustup component add clippy && \ 49 | rustup component add rust-src && \ 50 | rustup component add rust-analyzer 51 | 52 | RUN sh -c "pipx ensurepath" && \ 53 | bash -c "pipx ensurepath" 54 | 55 | RUN pipx install uv \ 56 | && pipx install ruff \ 57 | && pipx install pre-commit 58 | 59 | RUN echo '#!/bin/bash \n\ 60 | export VK_ICD_FILES=$(find /usr/share/vulkan/icd.d/ -name "lvp_icd*.json") \n\ 61 | export VK_ICD_FILENAMES=$VK_ICD_FILES \n\ 62 | export VK_DRIVER_FILES=$VK_ICD_FILES \n\ 63 | export LIBGL_ALWAYS_SOFTWARE=1 \n\ 64 | export GALLIUM_DRIVER=llvmpipe \n\ 65 | if ! DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then \n\ 66 | rm -f /tmp/.X11-unix/X99 \n\ 67 | rm -f /tmp/.X99-lock \n\ 68 | Xvfb :99 -screen 0 960x540x24 & \n\ 69 | fi \n\ 70 | export DISPLAY=:99 \n\ 71 | export XDG_RUNTIME_DIR=/tmp/xdg-runtime-dir \n\ 72 | mkdir -p $XDG_RUNTIME_DIR && chmod 700 $XDG_RUNTIME_DIR \n\ 73 | ' > /usr/local/bin/setup-vulkan-env.sh && chmod +x /usr/local/bin/setup-vulkan-env.sh 74 | 75 | RUN echo '#!/bin/bash \n\ 76 | source /usr/local/bin/setup-vulkan-env.sh \n\ 77 | exec "$@"' > /entrypoint.sh && chmod +x /entrypoint.sh 78 | 79 | RUN echo '. /usr/local/bin/setup-vulkan-env.sh' >> /etc/bash.bashrc 80 | 81 | RUN echo '#!/bin/bash \n\ 82 | vulkaninfo --summary \n\ 83 | vkcube --width 256 --height 256 & \n\ 84 | for attempt in $(seq 1 64); do \n\ 85 | import -window root /setup-vulkan-env.png \n\ 86 | mean=$(identify -format "%[fx:mean]" /setup-vulkan-env.png) \n\ 87 | if (( $(echo "$mean > 0.01" | bc -l) )); then \n\ 88 | break \n\ 89 | fi \n\ 90 | sleep 0.1 \n\ 91 | done \n\ 92 | ' | ./entrypoint.sh bash 93 | 94 | COPY vkrunner /vkrunner 95 | 96 | WORKDIR /vkrunner 97 | 98 | RUN cargo build --release && \ 99 | cp /vkrunner/target/release/vkrunner /usr/local/bin/ && \ 100 | chmod +x /usr/local/bin/vkrunner 101 | 102 | WORKDIR / 103 | 104 | ENTRYPOINT ["/entrypoint.sh"] 105 | 106 | CMD ["bash"] 107 | ``` -------------------------------------------------------------------------------- /vkrunner/build.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | use std::env; 25 | use std::path::PathBuf; 26 | 27 | fn main() { 28 | let header = ["include", "vulkan", "vulkan.h"].iter().collect::<PathBuf>(); 29 | 30 | let bindings = bindgen::Builder::default() 31 | // The input header we would like to generate 32 | // bindings for. 33 | .header(header.to_str().unwrap()) 34 | // Only generate types and variables 35 | .with_codegen_config( 36 | bindgen::CodegenConfig::TYPES 37 | | bindgen::CodegenConfig::VARS 38 | ) 39 | // Don’t prepend the enum name 40 | .prepend_enum_name(false) 41 | // Limit the types that we generate bindings for 42 | .allowlist_type(r"^(PFN|Vk).*") 43 | .allowlist_var(r"^VK_.*") 44 | // Derive the default trait 45 | .derive_default(true) 46 | // Specifiy the include path so that it can find the other headers 47 | .clang_arg("-Iinclude") 48 | // Tell cargo to invalidate the built crate whenever any of the 49 | // included header files changed. 50 | .parse_callbacks(Box::new(bindgen::CargoCallbacks)) 51 | // Finish the builder and generate the bindings 52 | .generate() 53 | // Unwrap the Result and panic on failure 54 | .expect("Unable to generate bindings"); 55 | 56 | // Write the bindings to the $OUT_DIR/vulkan_bindings.rs file. 57 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 58 | bindings 59 | .write_to_file(out_path.join("vulkan_bindings.rs")) 60 | .expect("Couldn't write bindings!"); 61 | } 62 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/shader_stage.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018 Intel Corporation 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | use crate::vk; 26 | 27 | /// An enum of all the possible shader stages known to VkRunner. 28 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 29 | #[repr(C)] 30 | pub enum Stage { 31 | Vertex = 0, 32 | TessCtrl, 33 | TessEval, 34 | Geometry, 35 | Fragment, 36 | Compute 37 | } 38 | 39 | /// The number of shader stages known to VkRunner. This should match 40 | /// the number of values in [Stage]. 41 | pub(crate) const N_STAGES: usize = 6; 42 | 43 | /// All the possible stage values. 44 | pub(crate) static ALL_STAGES: [Stage; N_STAGES] = [ 45 | Stage::Vertex, 46 | Stage::TessCtrl, 47 | Stage::TessEval, 48 | Stage::Geometry, 49 | Stage::Fragment, 50 | Stage::Compute, 51 | ]; 52 | 53 | impl Stage { 54 | /// Get the corresponding flag for this stage. This can be used to 55 | /// store the stages in a bitmask. 56 | pub(crate) const fn flag(self) -> vk::VkShaderStageFlagBits { 57 | vk::VK_SHADER_STAGE_VERTEX_BIT << self as usize 58 | } 59 | } 60 | 61 | #[cfg(test)] 62 | mod test { 63 | use super::*; 64 | 65 | #[test] 66 | fn flags() { 67 | assert_eq!(Stage::Vertex.flag(), vk::VK_SHADER_STAGE_VERTEX_BIT); 68 | assert_eq!( 69 | Stage::TessCtrl.flag(), 70 | vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 71 | ); 72 | assert_eq!( 73 | Stage::TessEval.flag(), 74 | vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 75 | ); 76 | assert_eq!(Stage::Geometry.flag(), vk::VK_SHADER_STAGE_GEOMETRY_BIT); 77 | assert_eq!(Stage::Fragment.flag(), vk::VK_SHADER_STAGE_FRAGMENT_BIT); 78 | assert_eq!(Stage::Compute.flag(), vk::VK_SHADER_STAGE_COMPUTE_BIT); 79 | } 80 | } 81 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/tolerance.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018 Google LLC 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | #[derive(Debug, Clone, PartialEq)] 26 | pub struct Tolerance { 27 | value: [f64; 4], 28 | is_percent: bool, 29 | } 30 | 31 | impl Tolerance { 32 | pub fn new(value: [f64; 4], is_percent: bool) -> Tolerance { 33 | Tolerance { value, is_percent } 34 | } 35 | 36 | pub fn equal(&self, component: usize, a: f64, b: f64) -> bool { 37 | if self.is_percent { 38 | (a - b).abs() <= (self.value[component] / 100.0 * b).abs() 39 | } else { 40 | (a - b).abs() <= self.value[component] 41 | } 42 | } 43 | } 44 | 45 | impl Default for Tolerance { 46 | fn default() -> Tolerance { 47 | Tolerance { 48 | value: [0.01; 4], 49 | is_percent: false, 50 | } 51 | } 52 | } 53 | 54 | #[cfg(test)] 55 | mod test { 56 | use super::*; 57 | 58 | #[test] 59 | fn test_percentage() { 60 | let tolerance = Tolerance::new([25.0, 50.0, 1.0, 1.0], true); 61 | 62 | assert!(tolerance.equal(0, 0.76, 1.0)); 63 | assert!(!tolerance.equal(0, 0.74, 1.0)); 64 | assert!(tolerance.equal(1, 41.0, 80.0)); 65 | assert!(!tolerance.equal(1, 39.0, 1.0)); 66 | assert!(tolerance.equal(2, 100.5, 100.0)); 67 | assert!(!tolerance.equal(2, 101.5, 100.0)); 68 | } 69 | 70 | #[test] 71 | fn test_direct() { 72 | let tolerance = Tolerance::new([1.0, 2.0, 3.0, 4.0], false); 73 | 74 | assert!(tolerance.equal(0, 5.9, 5.0)); 75 | assert!(!tolerance.equal(0, 6.1, 5.0)); 76 | assert!(tolerance.equal(1, 3.1, 5.0)); 77 | assert!(!tolerance.equal(1, 2.9, 5.0)); 78 | assert!(tolerance.equal(3, 186.1, 190.0)); 79 | assert!(!tolerance.equal(3, 185.9, 190.0)); 80 | } 81 | } 82 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_h264std_decode.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ 2 | #define VULKAN_VIDEO_CODEC_H264STD_DECODE_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | // vulkan_video_codec_h264std_decode is a preprocessor guard. Do not pass it to API calls. 23 | #define vulkan_video_codec_h264std_decode 1 24 | #include "vulkan_video_codec_h264std.h" 25 | 26 | #define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) 27 | 28 | #define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_API_VERSION_1_0_0 29 | #define VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_decode" 30 | #define STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE 2 31 | 32 | typedef enum StdVideoDecodeH264FieldOrderCount { 33 | STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_TOP = 0, 34 | STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_BOTTOM = 1, 35 | STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_INVALID = 0x7FFFFFFF, 36 | STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_MAX_ENUM = 0x7FFFFFFF 37 | } StdVideoDecodeH264FieldOrderCount; 38 | typedef struct StdVideoDecodeH264PictureInfoFlags { 39 | uint32_t field_pic_flag : 1; 40 | uint32_t is_intra : 1; 41 | uint32_t IdrPicFlag : 1; 42 | uint32_t bottom_field_flag : 1; 43 | uint32_t is_reference : 1; 44 | uint32_t complementary_field_pair : 1; 45 | } StdVideoDecodeH264PictureInfoFlags; 46 | 47 | typedef struct StdVideoDecodeH264PictureInfo { 48 | StdVideoDecodeH264PictureInfoFlags flags; 49 | uint8_t seq_parameter_set_id; 50 | uint8_t pic_parameter_set_id; 51 | uint8_t reserved1; 52 | uint8_t reserved2; 53 | uint16_t frame_num; 54 | uint16_t idr_pic_id; 55 | int32_t PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE]; 56 | } StdVideoDecodeH264PictureInfo; 57 | 58 | typedef struct StdVideoDecodeH264ReferenceInfoFlags { 59 | uint32_t top_field_flag : 1; 60 | uint32_t bottom_field_flag : 1; 61 | uint32_t used_for_long_term_reference : 1; 62 | uint32_t is_non_existing : 1; 63 | } StdVideoDecodeH264ReferenceInfoFlags; 64 | 65 | typedef struct StdVideoDecodeH264ReferenceInfo { 66 | StdVideoDecodeH264ReferenceInfoFlags flags; 67 | uint16_t FrameNum; 68 | uint16_t reserved; 69 | int32_t PicOrderCnt[STD_VIDEO_DECODE_H264_FIELD_ORDER_COUNT_LIST_SIZE]; 70 | } StdVideoDecodeH264ReferenceInfo; 71 | 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | ``` -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- ```dockerfile 1 | FROM ubuntu:25.04 AS builder 2 | 3 | ENV DEBIAN_FRONTEND=noninteractive 4 | 5 | RUN apt-get update && apt-get install -y \ 6 | bc \ 7 | build-essential \ 8 | clang \ 9 | clang-format \ 10 | clang-tidy \ 11 | clang-tools \ 12 | clangd \ 13 | cmake \ 14 | curl \ 15 | ffmpeg \ 16 | git \ 17 | glslang-tools \ 18 | glslc \ 19 | jq \ 20 | libshaderc-dev \ 21 | libshaderc1 \ 22 | imagemagick \ 23 | libgl1-mesa-dri \ 24 | libvulkan-dev \ 25 | libvulkan1 \ 26 | mesa-utils \ 27 | mesa-vulkan-drivers \ 28 | ninja-build \ 29 | npm \ 30 | pipx \ 31 | python3 \ 32 | python3-pip \ 33 | python3-venv \ 34 | rustup \ 35 | sudo \ 36 | unzip \ 37 | vulkan-tools \ 38 | wget \ 39 | x11-utils \ 40 | xvfb \ 41 | && apt-get clean \ 42 | && rm -rf /var/lib/apt/lists/* 43 | 44 | RUN rustup install 1.86.0 && \ 45 | rustup default 1.86.0 46 | 47 | RUN rustup component add rustfmt && \ 48 | rustup component add clippy && \ 49 | rustup component add rust-src && \ 50 | rustup component add rust-analyzer 51 | 52 | RUN sh -c "pipx ensurepath" && \ 53 | bash -c "pipx ensurepath" 54 | 55 | RUN pipx install uv \ 56 | && pipx install ruff \ 57 | && pipx install pre-commit 58 | 59 | WORKDIR /app 60 | COPY . . 61 | 62 | RUN cargo build --release 63 | 64 | COPY vkrunner /vkrunner 65 | 66 | WORKDIR /vkrunner 67 | 68 | RUN cargo build --release && \ 69 | cp /vkrunner/target/release/vkrunner /usr/local/bin/ && \ 70 | chmod +x /usr/local/bin/vkrunner 71 | 72 | FROM ubuntu:25.04 73 | 74 | ENV DEBIAN_FRONTEND=noninteractive 75 | 76 | RUN apt-get update && apt-get install -y \ 77 | bc \ 78 | glslang-tools \ 79 | glslc \ 80 | imagemagick \ 81 | jq \ 82 | libgl1-mesa-dri \ 83 | libshaderc1 \ 84 | libvulkan1 \ 85 | mesa-utils \ 86 | mesa-vulkan-drivers \ 87 | vulkan-tools \ 88 | x11-utils \ 89 | xvfb \ 90 | && apt-get clean \ 91 | && rm -rf /var/lib/apt/lists/* 92 | 93 | RUN echo '#!/bin/bash \n\ 94 | export VK_ICD_FILES=$(find /usr/share/vulkan/icd.d/ -name "lvp_icd*.json") \n\ 95 | export VK_ICD_FILENAMES=$VK_ICD_FILES \n\ 96 | export VK_DRIVER_FILES=$VK_ICD_FILES \n\ 97 | export LIBGL_ALWAYS_SOFTWARE=1 \n\ 98 | export GALLIUM_DRIVER=llvmpipe \n\ 99 | if ! ps aux | grep -v grep | grep "Xvfb :99" > /dev/null; then \n\ 100 | rm -f /tmp/.X11-unix/X99 \n\ 101 | rm -f /tmp/.X99-lock \n\ 102 | Xvfb :99 -screen 0 960x540x24 > /dev/null 2>&1 & \n\ 103 | fi \n\ 104 | export DISPLAY=:99 \n\ 105 | export XDG_RUNTIME_DIR=/tmp/xdg-runtime-dir \n\ 106 | mkdir -p $XDG_RUNTIME_DIR && chmod 700 $XDG_RUNTIME_DIR \n\ 107 | ' > /usr/local/bin/setup-vulkan-env.sh && chmod +x /usr/local/bin/setup-vulkan-env.sh 108 | 109 | RUN echo '#!/bin/bash \n\ 110 | source /usr/local/bin/setup-vulkan-env.sh \n\ 111 | if [[ "${1}" == --* ]]; then \n\ 112 | /usr/local/bin/shaderc-vkrunner-mcp "$@" \n\ 113 | else \n\ 114 | exec "$@" \n\ 115 | fi \n\ 116 | ' > /entrypoint.sh && chmod +x /entrypoint.sh 117 | 118 | COPY --from=builder /app/target/release/shaderc-vkrunner-mcp /usr/local/bin/ 119 | COPY --from=builder /usr/local/bin/vkrunner /usr/local/bin/ 120 | 121 | WORKDIR /work 122 | 123 | ENTRYPOINT ["/entrypoint.sh"] 124 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vulkan/vk_platform.h: -------------------------------------------------------------------------------- ``` 1 | // 2 | // File: vk_platform.h 3 | // 4 | /* 5 | ** Copyright 2014-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | 11 | #ifndef VK_PLATFORM_H_ 12 | #define VK_PLATFORM_H_ 13 | 14 | #ifdef __cplusplus 15 | extern "C" 16 | { 17 | #endif // __cplusplus 18 | 19 | /* 20 | *************************************************************************************************** 21 | * Platform-specific directives and type declarations 22 | *************************************************************************************************** 23 | */ 24 | 25 | /* Platform-specific calling convention macros. 26 | * 27 | * Platforms should define these so that Vulkan clients call Vulkan commands 28 | * with the same calling conventions that the Vulkan implementation expects. 29 | * 30 | * VKAPI_ATTR - Placed before the return type in function declarations. 31 | * Useful for C++11 and GCC/Clang-style function attribute syntax. 32 | * VKAPI_CALL - Placed after the return type in function declarations. 33 | * Useful for MSVC-style calling convention syntax. 34 | * VKAPI_PTR - Placed between the '(' and '*' in function pointer types. 35 | * 36 | * Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); 37 | * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); 38 | */ 39 | #if defined(_WIN32) 40 | // On Windows, Vulkan commands use the stdcall convention 41 | #define VKAPI_ATTR 42 | #define VKAPI_CALL __stdcall 43 | #define VKAPI_PTR VKAPI_CALL 44 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 45 | #error "Vulkan is not supported for the 'armeabi' NDK ABI" 46 | #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) 47 | // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" 48 | // calling convention, i.e. float parameters are passed in registers. This 49 | // is true even if the rest of the application passes floats on the stack, 50 | // as it does by default when compiling for the armeabi-v7a NDK ABI. 51 | #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) 52 | #define VKAPI_CALL 53 | #define VKAPI_PTR VKAPI_ATTR 54 | #else 55 | // On other platforms, use the default calling convention 56 | #define VKAPI_ATTR 57 | #define VKAPI_CALL 58 | #define VKAPI_PTR 59 | #endif 60 | 61 | #if !defined(VK_NO_STDDEF_H) 62 | #include <stddef.h> 63 | #endif // !defined(VK_NO_STDDEF_H) 64 | 65 | #if !defined(VK_NO_STDINT_H) 66 | #if defined(_MSC_VER) && (_MSC_VER < 1600) 67 | typedef signed __int8 int8_t; 68 | typedef unsigned __int8 uint8_t; 69 | typedef signed __int16 int16_t; 70 | typedef unsigned __int16 uint16_t; 71 | typedef signed __int32 int32_t; 72 | typedef unsigned __int32 uint32_t; 73 | typedef signed __int64 int64_t; 74 | typedef unsigned __int64 uint64_t; 75 | #else 76 | #include <stdint.h> 77 | #endif 78 | #endif // !defined(VK_NO_STDINT_H) 79 | 80 | #ifdef __cplusplus 81 | } // extern "C" 82 | #endif // __cplusplus 83 | 84 | #endif 85 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/small_float.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018, 2019 Intel Corporation 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | pub fn load_unsigned(part: u32, e_bits: u32, m_bits: u32) -> f64 { 26 | let e_max = u32::MAX >> (32 - e_bits); 27 | let mut e = ((part >> m_bits) & e_max) as i32; 28 | let mut m = part & (u32::MAX >> (32 - m_bits)); 29 | 30 | if e == e_max as i32 { 31 | if m == 0 { 32 | f64::INFINITY 33 | } else { 34 | f64::NAN 35 | } 36 | } else { 37 | if e == 0 { 38 | e = 1; 39 | } else { 40 | m += 1 << m_bits; 41 | } 42 | 43 | m as f64 / (1 << m_bits) as f64 44 | * ((e - (e_max >> 1) as i32) as f64).exp2() 45 | } 46 | } 47 | 48 | pub fn load_signed(part: u32, e_bits: u32, m_bits: u32) -> f64 { 49 | let res = load_unsigned(part, e_bits, m_bits); 50 | 51 | if !res.is_nan() && (part & (1 << (e_bits + m_bits))) != 0 { 52 | -res 53 | } else { 54 | res 55 | } 56 | } 57 | 58 | #[cfg(test)] 59 | mod test { 60 | use super::*; 61 | 62 | fn assert_float_equal(a: f64, b: f64) { 63 | assert!( 64 | (a - b).abs() < 0.001, 65 | "a={}, b={}", 66 | a, 67 | b 68 | ); 69 | } 70 | 71 | #[test] 72 | fn test_load_unsigned() { 73 | assert_eq!(load_unsigned(0x30, 2, 4), f64::INFINITY); 74 | assert!(load_unsigned(0x3f, 2, 4).is_nan()); 75 | 76 | assert_float_equal(load_unsigned(0, 3, 4), 0.0); 77 | assert_float_equal(load_unsigned(0x3555, 5, 10), 1.0 / 3.0); 78 | } 79 | 80 | #[test] 81 | fn test_load_signed() { 82 | assert_eq!(load_signed(0x70, 2, 4), -f64::INFINITY); 83 | assert!(load_signed(0x7f, 2, 4).is_nan()); 84 | 85 | assert_float_equal(load_signed(0, 3, 4), 0.0); 86 | assert_float_equal(load_signed(0x3555, 5, 10), 1.0 / 3.0); 87 | assert_float_equal(load_signed(0xb555, 5, 10), -1.0 / 3.0); 88 | } 89 | } 90 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/make-enums.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2018 Intel Corporation 4 | # Copyright 2023 Neil Roberts 5 | 6 | # Permission is hereby granted, free of charge, to any person obtaining a 7 | # copy of this software and associated documentation files (the "Software"), 8 | # to deal in the Software without restriction, including without limitation 9 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | # and/or sell copies of the Software, and to permit persons to whom the 11 | # Software is furnished to do so, subject to the following conditions: 12 | 13 | # The above copyright notice and this permission notice (including the next 14 | # paragraph) shall be included in all copies or substantial portions of the 15 | # Software. 16 | 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | # DEALINGS IN THE SOFTWARE. 24 | 25 | from __future__ import ( 26 | absolute_import, division, print_function, unicode_literals 27 | ) 28 | 29 | # This script is used to generate enum_table.rs from vulkan.h. It 30 | # is not run automatically as part of the build process but if need be 31 | # it can be used to update the file as follows: 32 | # 33 | # echo | gcc -include "vulkan/vulkan.h" -E - | ./make-enums.py > enum_table.rs 34 | 35 | import re 36 | import sys 37 | from mako.template import Template 38 | 39 | ENUMS = [ 40 | 'VkPolygonMode', 41 | 'VkCullModeFlagBits', 42 | 'VkFrontFace', 43 | 'VkPrimitiveTopology', 44 | 'VkLogicOp', 45 | 'VkBlendFactor', 46 | 'VkBlendOp', 47 | 'VkColorComponentFlagBits', 48 | 'VkCompareOp', 49 | 'VkStencilOp', 50 | 'VkComponentTypeKHR', 51 | 'VkScopeKHR', 52 | ] 53 | VALUE_RE = re.compile(r'\s*\b(VK_(?:[A-Z0-9_]+))\b') 54 | ENUM_START_RE = re.compile(r'\s*typedef\s+enum\s+(Vk[A-Za-z0-9]+)') 55 | ENUM_END_RE = re.compile('}') 56 | PREPROCESSOR_RE = re.compile(r' *#') 57 | 58 | TEMPLATE="""\ 59 | // Automatically generated by make-enums.py 60 | static ENUM_VALUES: [EnumValue; ${len(enums)}] = [ 61 | % for e in enums: 62 | EnumValue { 63 | name: "${e}", 64 | value: vk::${e} as i32 65 | }, 66 | % endfor 67 | ];""" 68 | 69 | 70 | def get_enums(data): 71 | enums = set() 72 | in_enum = False 73 | 74 | for line in data: 75 | if PREPROCESSOR_RE.match(line): 76 | continue 77 | md = ENUM_START_RE.match(line) 78 | if md: 79 | in_enum = md.group(1) in ENUMS 80 | if ENUM_END_RE.match(line): 81 | in_enum = False 82 | if not in_enum: 83 | continue 84 | md = VALUE_RE.match(line) 85 | if md: 86 | enums.add(md.group(1)) 87 | 88 | return sorted(enums) 89 | 90 | 91 | def main(): 92 | template = Template(TEMPLATE) 93 | print(template.render(enums = get_enums(sys.stdin))) 94 | 95 | 96 | if __name__ == '__main__': 97 | main() 98 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/inspect.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018 Intel Corporation 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | use crate::format::Format; 26 | use std::ffi::{c_int, c_void}; 27 | use std::fmt; 28 | 29 | #[repr(C)] 30 | pub struct Image { 31 | /// Width of the buffer 32 | pub width: c_int, 33 | /// Height of the buffer 34 | pub height: c_int, 35 | 36 | /// The stride in bytes from one row of the image to the next 37 | pub stride: usize, 38 | 39 | /// A description the format of each pixel in the buffer 40 | pub format: &'static Format, 41 | 42 | /// The buffer data 43 | pub data: *const c_void, 44 | } 45 | 46 | #[repr(C)] 47 | pub struct Buffer { 48 | /// The binding number of the buffer 49 | pub binding: c_int, 50 | /// Size in bytes of the buffer 51 | pub size: usize, 52 | /// The buffer data 53 | pub data: *const c_void, 54 | } 55 | 56 | #[repr(C)] 57 | pub struct Data { 58 | /// The color buffer 59 | pub color_buffer: Image, 60 | /// An array of buffers used as UBOs or SSBOs 61 | pub n_buffers: usize, 62 | pub buffers: *const Buffer, 63 | } 64 | 65 | /// A callback used to report the buffer and image data after 66 | /// executing each test. 67 | pub type Callback = extern "C" fn( 68 | data: &Data, 69 | user_data: *mut c_void, 70 | ); 71 | 72 | /// A struct to combine the inspection callback with its user data pointer 73 | #[derive(Clone)] 74 | pub(crate) struct Inspector { 75 | callback: Callback, 76 | user_data: *mut c_void, 77 | } 78 | 79 | impl Inspector { 80 | pub fn new(callback: Callback, user_data: *mut c_void) -> Inspector { 81 | Inspector { callback, user_data } 82 | } 83 | 84 | pub fn inspect(&self, data: &Data) { 85 | (self.callback)(data, self.user_data); 86 | } 87 | } 88 | 89 | impl fmt::Debug for Inspector { 90 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 91 | f.debug_struct("Inspector") 92 | .field("callback", &(self.callback as usize)) 93 | .field("user_data", &self.user_data) 94 | .finish() 95 | } 96 | } 97 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/util.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2013, 2014, 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | use std::env; 25 | use std::ffi::OsStr; 26 | 27 | /// Align a value, only works on power-of-two alignments 28 | #[inline] 29 | pub const fn align(value: usize, alignment: usize) -> usize { 30 | debug_assert!(alignment.is_power_of_two()); 31 | debug_assert!(alignment > 0); 32 | 33 | (value + alignment - 1) & !(alignment - 1) 34 | } 35 | 36 | /// Reads an environment variable and interprets its value as a boolean. 37 | /// 38 | /// Recognizes 0/false/no and 1/true/yes. Other values result in the 39 | /// default value. 40 | pub fn env_var_as_boolean<K: AsRef<OsStr>>( 41 | var_name: K, 42 | default_value: bool, 43 | ) -> bool { 44 | match env::var(var_name) { 45 | Ok(value) => match value.as_str() { 46 | "1" | "true" | "yes" => true, 47 | "0" | "false" | "no" => false, 48 | _ => default_value, 49 | }, 50 | Err(_) => default_value, 51 | } 52 | } 53 | 54 | #[cfg(test)] 55 | mod test { 56 | use super::*; 57 | use crate::env_var_test::EnvVarLock; 58 | 59 | #[test] 60 | fn test_align() { 61 | assert_eq!(align(3, 4), 4); 62 | assert_eq!(align(4, 4), 4); 63 | assert_eq!(align(0, 8), 0); 64 | assert_eq!(align(9, 8), 16); 65 | } 66 | 67 | fn test_env_var_value<V: AsRef<OsStr>>( 68 | value: V, 69 | default_value: bool, 70 | expected_result: bool 71 | ) { 72 | const TEST_VAR: &'static str = "VKRUNNER_TEST_ENV_VAR"; 73 | 74 | let _env_var_lock = EnvVarLock::new(&[ 75 | (TEST_VAR, value) 76 | ]); 77 | 78 | assert_eq!( 79 | env_var_as_boolean(TEST_VAR, default_value), 80 | expected_result 81 | ); 82 | } 83 | 84 | #[test] 85 | fn test_env_var_as_boolean() { 86 | test_env_var_value("1", false, true); 87 | test_env_var_value("true", false, true); 88 | test_env_var_value("yes", false, true); 89 | test_env_var_value("0", true, false); 90 | test_env_var_value("false", true, false); 91 | test_env_var_value("no", true, false); 92 | 93 | assert_eq!( 94 | env_var_as_boolean("ENVIRONMENT_VARIABLE_THAT_DOESNT_EXIST", true), 95 | true, 96 | ); 97 | assert_eq!( 98 | env_var_as_boolean("ENVIRONMENT_VARIABLE_THAT_DOESNT_EXIST", false), 99 | false, 100 | ); 101 | 102 | test_env_var_value("other_value", false, false); 103 | test_env_var_value("other_value", true, true); 104 | 105 | // Test using a byte sequence that isn’t valid UTF-8. I think 106 | // this can’t happen on Windows. 107 | #[cfg(unix)] 108 | { 109 | use std::os::unix::ffi::OsStrExt; 110 | 111 | test_env_var_value( 112 | OsStr::from_bytes(b"Echant\xe9 in Latin-1"), 113 | false, 114 | false, 115 | ); 116 | test_env_var_value( 117 | OsStr::from_bytes(b"Echant\xe9 in Latin-1"), 118 | true, 119 | true, 120 | ); 121 | } 122 | } 123 | } 124 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/result.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018 Intel Corporation 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | use std::fmt; 26 | 27 | /// Enum representing the possible results of a test. 28 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 29 | #[repr(C)] 30 | pub enum Result { 31 | Pass, 32 | Fail, 33 | Skip, 34 | } 35 | 36 | impl Result { 37 | /// Merge this result with another one. If either test is skipped 38 | /// then the value of the other result is returned. Otherwise if 39 | /// either of the tests failed then the global result is a 40 | /// failure. Finally if both tests passed then the global result 41 | /// is a pass. 42 | pub fn merge(self, other: Result) -> Result { 43 | match self { 44 | Result::Pass => { 45 | if other == Result::Skip { 46 | self 47 | } else { 48 | other 49 | } 50 | }, 51 | Result::Fail => Result::Fail, 52 | Result::Skip => other, 53 | } 54 | } 55 | 56 | // Returns the name with a NULL terminator. This is needed because 57 | // there is a function in the public API which returns a static 58 | // string to C code. 59 | fn name_with_terminator(self) -> &'static str { 60 | match self { 61 | Result::Fail => "fail\0", 62 | Result::Skip => "skip\0", 63 | Result::Pass => "pass\0", 64 | } 65 | } 66 | 67 | /// Return either `"fail"`, `"skip"` or `"pass"` to describe the 68 | /// result. The result is a static string. You can also use the 69 | /// [to_string](ToString::to_string) method to get an owned string 70 | /// because [Result] implements [Display](std::fmt::Display). 71 | pub fn name(self) -> &'static str { 72 | let name = self.name_with_terminator(); 73 | &name[0..name.len() - 1] 74 | } 75 | } 76 | 77 | impl fmt::Display for Result { 78 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 79 | write!(f, "{}", self.name()) 80 | } 81 | } 82 | 83 | #[cfg(test)] 84 | mod test { 85 | use super::*; 86 | 87 | #[test] 88 | fn test_merge() { 89 | assert_eq!(Result::Fail.merge(Result::Fail), Result::Fail); 90 | assert_eq!(Result::Fail.merge(Result::Skip), Result::Fail); 91 | assert_eq!(Result::Fail.merge(Result::Pass), Result::Fail); 92 | assert_eq!(Result::Skip.merge(Result::Fail), Result::Fail); 93 | assert_eq!(Result::Skip.merge(Result::Skip), Result::Skip); 94 | assert_eq!(Result::Skip.merge(Result::Pass), Result::Pass); 95 | assert_eq!(Result::Pass.merge(Result::Fail), Result::Fail); 96 | assert_eq!(Result::Pass.merge(Result::Skip), Result::Pass); 97 | assert_eq!(Result::Pass.merge(Result::Pass), Result::Pass); 98 | } 99 | 100 | #[test] 101 | fn test_name() { 102 | assert_eq!(Result::Fail.name(), "fail"); 103 | assert_eq!(Result::Skip.name(), "skip"); 104 | assert_eq!(Result::Pass.name(), "pass"); 105 | 106 | for res in [Result::Fail, Result::Skip, Result::Pass] { 107 | assert_eq!(&res.to_string(), res.name()); 108 | } 109 | } 110 | } 111 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/env_var_test.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | //! Helper to serialise unit tests that set environment variables so 25 | //! that there won’t be a race condition if the tests are run in 26 | //! parallel. 27 | 28 | use std::sync::{Mutex, MutexGuard}; 29 | use std::collections::HashMap; 30 | use std::env; 31 | use std::ffi::{OsString, OsStr}; 32 | 33 | // Mutex to make sure only one test is testing environment variables at a time 34 | static LOCK: Mutex<()> = Mutex::new(()); 35 | 36 | /// Struct to help make unit tests that set environment variables. 37 | /// Only one EnvValLock can exist in the process at any one time. If a 38 | /// thread tries to construct a second one it will block until the 39 | /// first one is dropped. The environment variables will be restored 40 | /// when the EnvVarLock is dropped. 41 | pub struct EnvVarLock { 42 | old_values: HashMap<&'static str, Option<OsString>>, 43 | _mutex_lock: MutexGuard<'static, ()>, 44 | } 45 | 46 | impl EnvVarLock { 47 | /// Construct a new EnvVarLock and set the environment variables 48 | /// from the hash table. This will block if another EnvVarLock 49 | /// already exists. When the object is dropped the environment 50 | /// variables will be restored to their original values. 51 | /// 52 | /// Note that the object has no useful methods or members but you 53 | /// need to keep it alive in order to hold the mutex lock. One way 54 | /// to do this is to put the lock in a local variable prefixed 55 | /// with `_`: 56 | /// 57 | /// ``` 58 | /// let _env_var_lock = EnvVarLock::new(&[ 59 | /// ("MY_ENVIRONMENT_VARIABLE", "true") 60 | /// ]); 61 | /// assert_eq!(std::env::var("MY_ENVIRONMENT_VARIABLE").unwrap(), "true"); 62 | /// ``` 63 | pub fn new<V: AsRef<OsStr>>( 64 | variables: &[(&'static str, V)] 65 | ) -> EnvVarLock { 66 | let mutex_lock = LOCK.lock().unwrap(); 67 | 68 | let old_values: HashMap<&'static str, Option<OsString>> = variables 69 | .iter() 70 | .map(|(variable, value)| { 71 | let old_value = env::var_os(variable); 72 | env::set_var(*variable, value); 73 | (*variable, old_value) 74 | }) 75 | .collect(); 76 | 77 | EnvVarLock { old_values, _mutex_lock: mutex_lock } 78 | } 79 | } 80 | 81 | impl Drop for EnvVarLock { 82 | fn drop(&mut self) { 83 | for (variable, value) in self.old_values.iter() { 84 | match value { 85 | Some(value) => env::set_var(variable, value), 86 | None => env::remove_var(variable), 87 | } 88 | } 89 | } 90 | } 91 | 92 | #[test] 93 | fn env_var_lock_test() { 94 | { 95 | let _env_var_lock = EnvVarLock::new(&[ 96 | ("ENV_VAR_LOCK_TEST_ENVIRONMENT_VARIABLE", "true") 97 | ]); 98 | assert_eq!( 99 | std::env::var("ENV_VAR_LOCK_TEST_ENVIRONMENT_VARIABLE").unwrap(), 100 | "true" 101 | ); 102 | } 103 | 104 | assert!(matches!( 105 | std::env::var("ENV_VAR_LOCK_TEST_ENVIRONMENT_VARIABLE"), 106 | Err(std::env::VarError::NotPresent), 107 | )); 108 | } 109 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/half_float.rs: -------------------------------------------------------------------------------- ```rust 1 | // Copyright (c) The Piglit project 2007 2 | // Copyright 2023 Neil Roberts 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the "Software"), 6 | // to deal in the Software without restriction, including without limitation 7 | // on the rights to use, copy, modify, merge, publish, distribute, sub 8 | // license, and/or sell copies of the Software, and to permit persons to whom 9 | // the Software is furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice (including the next 12 | // paragraph) shall be included in all copies or substantial portions of the 13 | // Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 | // VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | use crate::small_float; 24 | 25 | // Convert a 4-byte float to a 2-byte half float. 26 | // Based on code from: 27 | // http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html 28 | // 29 | // Taken over from Piglit which took it from Mesa. 30 | pub fn from_f32(val: f32) -> u16 { 31 | let fi = val.to_bits(); 32 | let flt_m = fi & 0x7fffff; 33 | let flt_e = (fi >> 23) & 0xff; 34 | // sign bit 35 | let flt_s = (fi >> 31) & 0x1; 36 | 37 | let e; 38 | let m; 39 | 40 | // handle special cases 41 | if flt_e == 0 && flt_m == 0 { 42 | // zero 43 | m = 0; 44 | e = 0; 45 | } else if (flt_e == 0) && (flt_m != 0) { 46 | // denorm -- denorm float maps to 0 half 47 | m = 0; 48 | e = 0; 49 | } else if (flt_e == 0xff) && (flt_m == 0) { 50 | // infinity 51 | m = 0; 52 | e = 31; 53 | } else if (flt_e == 0xff) && (flt_m != 0) { 54 | // NaN 55 | m = 1; 56 | e = 31; 57 | } else { 58 | // regular number 59 | let new_exp = flt_e as i32 - 127; 60 | if new_exp < -24 { 61 | // this maps to 0 62 | m = 0; 63 | e = 0; 64 | } else if new_exp < -14 { 65 | // this maps to a denorm 66 | // 2^-exp_val 67 | let exp_val = (-14 - new_exp) as u32; 68 | 69 | e = 0; 70 | 71 | match exp_val { 72 | 0 => m = 0, 73 | 1 => m = 512 + (flt_m >> 14), 74 | 2 => m = 256 + (flt_m >> 15), 75 | 3 => m = 128 + (flt_m >> 16), 76 | 4 => m = 64 + (flt_m >> 17), 77 | 5 => m = 32 + (flt_m >> 18), 78 | 6 => m = 16 + (flt_m >> 19), 79 | 7 => m = 8 + (flt_m >> 20), 80 | 8 => m = 4 + (flt_m >> 21), 81 | 9 => m = 2 + (flt_m >> 22), 82 | 10 => m = 1, 83 | _ => unreachable!(), 84 | } 85 | } else if new_exp > 15 { 86 | // map this value to infinity 87 | m = 0; 88 | e = 31; 89 | } else { 90 | /* regular */ 91 | e = (new_exp + 15) as u32; 92 | m = flt_m >> 13; 93 | } 94 | } 95 | 96 | ((flt_s << 15) | (e << 10) | m) as u16 97 | } 98 | 99 | pub fn to_f64(half: u16) -> f64 { 100 | small_float::load_signed(half as u32, 5, 10) 101 | } 102 | 103 | #[cfg(test)] 104 | mod test { 105 | use super::*; 106 | 107 | #[test] 108 | fn test_from_f32() { 109 | assert_eq!(from_f32(0.0), 0); 110 | assert_eq!(from_f32(1.0 / 3.0), 0x3555); 111 | assert_eq!(from_f32(-1.0 / 3.0), 0xb555); 112 | assert_eq!(from_f32(f32::INFINITY), 0x7c00); 113 | assert_eq!(from_f32(-f32::INFINITY), 0xfc00); 114 | assert_eq!(from_f32(f32::NAN), 0x7c01); 115 | assert_eq!(from_f32(f32::MAX), 0x7c00); 116 | } 117 | 118 | fn assert_float_equal(a: f64, b: f64) { 119 | assert!( 120 | (a - b).abs() < 0.001, 121 | "a={}, b={}", 122 | a, 123 | b 124 | ); 125 | } 126 | 127 | #[test] 128 | fn test_to_f64() { 129 | assert_eq!(to_f64(0x7c00), f64::INFINITY); 130 | assert_eq!(to_f64(0xfc00), -f64::INFINITY); 131 | assert_float_equal(to_f64(0x3555), 1.0 / 3.0); 132 | } 133 | } 134 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_av1std_decode.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ 2 | #define VULKAN_VIDEO_CODEC_AV1STD_DECODE_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | // vulkan_video_codec_av1std_decode is a preprocessor guard. Do not pass it to API calls. 23 | #define vulkan_video_codec_av1std_decode 1 24 | #include "vulkan_video_codec_av1std.h" 25 | 26 | #define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) 27 | 28 | #define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_API_VERSION_1_0_0 29 | #define VK_STD_VULKAN_VIDEO_CODEC_AV1_DECODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_decode" 30 | typedef struct StdVideoDecodeAV1PictureInfoFlags { 31 | uint32_t error_resilient_mode : 1; 32 | uint32_t disable_cdf_update : 1; 33 | uint32_t use_superres : 1; 34 | uint32_t render_and_frame_size_different : 1; 35 | uint32_t allow_screen_content_tools : 1; 36 | uint32_t is_filter_switchable : 1; 37 | uint32_t force_integer_mv : 1; 38 | uint32_t frame_size_override_flag : 1; 39 | uint32_t buffer_removal_time_present_flag : 1; 40 | uint32_t allow_intrabc : 1; 41 | uint32_t frame_refs_short_signaling : 1; 42 | uint32_t allow_high_precision_mv : 1; 43 | uint32_t is_motion_mode_switchable : 1; 44 | uint32_t use_ref_frame_mvs : 1; 45 | uint32_t disable_frame_end_update_cdf : 1; 46 | uint32_t allow_warped_motion : 1; 47 | uint32_t reduced_tx_set : 1; 48 | uint32_t reference_select : 1; 49 | uint32_t skip_mode_present : 1; 50 | uint32_t delta_q_present : 1; 51 | uint32_t delta_lf_present : 1; 52 | uint32_t delta_lf_multi : 1; 53 | uint32_t segmentation_enabled : 1; 54 | uint32_t segmentation_update_map : 1; 55 | uint32_t segmentation_temporal_update : 1; 56 | uint32_t segmentation_update_data : 1; 57 | uint32_t UsesLr : 1; 58 | uint32_t usesChromaLr : 1; 59 | uint32_t apply_grain : 1; 60 | uint32_t reserved : 3; 61 | } StdVideoDecodeAV1PictureInfoFlags; 62 | 63 | typedef struct StdVideoDecodeAV1PictureInfo { 64 | StdVideoDecodeAV1PictureInfoFlags flags; 65 | StdVideoAV1FrameType frame_type; 66 | uint32_t current_frame_id; 67 | uint8_t OrderHint; 68 | uint8_t primary_ref_frame; 69 | uint8_t refresh_frame_flags; 70 | uint8_t reserved1; 71 | StdVideoAV1InterpolationFilter interpolation_filter; 72 | StdVideoAV1TxMode TxMode; 73 | uint8_t delta_q_res; 74 | uint8_t delta_lf_res; 75 | uint8_t SkipModeFrame[STD_VIDEO_AV1_SKIP_MODE_FRAMES]; 76 | uint8_t coded_denom; 77 | uint8_t reserved2[3]; 78 | uint8_t OrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES]; 79 | uint32_t expectedFrameId[STD_VIDEO_AV1_NUM_REF_FRAMES]; 80 | const StdVideoAV1TileInfo* pTileInfo; 81 | const StdVideoAV1Quantization* pQuantization; 82 | const StdVideoAV1Segmentation* pSegmentation; 83 | const StdVideoAV1LoopFilter* pLoopFilter; 84 | const StdVideoAV1CDEF* pCDEF; 85 | const StdVideoAV1LoopRestoration* pLoopRestoration; 86 | const StdVideoAV1GlobalMotion* pGlobalMotion; 87 | const StdVideoAV1FilmGrain* pFilmGrain; 88 | } StdVideoDecodeAV1PictureInfo; 89 | 90 | typedef struct StdVideoDecodeAV1ReferenceInfoFlags { 91 | uint32_t disable_frame_end_update_cdf : 1; 92 | uint32_t segmentation_enabled : 1; 93 | uint32_t reserved : 30; 94 | } StdVideoDecodeAV1ReferenceInfoFlags; 95 | 96 | typedef struct StdVideoDecodeAV1ReferenceInfo { 97 | StdVideoDecodeAV1ReferenceInfoFlags flags; 98 | uint8_t frame_type; 99 | uint8_t RefFrameSignBias; 100 | uint8_t OrderHint; 101 | uint8_t SavedOrderHints[STD_VIDEO_AV1_NUM_REF_FRAMES]; 102 | } StdVideoDecodeAV1ReferenceInfo; 103 | 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif 110 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/compiler/fake_process.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | //! This module is just for the unit tests. It makes an alternative 25 | //! version of the Stdio, Command and Output structs from std::process 26 | //! that run a fake compiler so we can get code coverage in 27 | //! compiler.rs without depending a real GLSL compiler. 28 | 29 | use std::process::Stdio; 30 | use std::io::{Write, BufWriter, BufReader, BufRead}; 31 | use std::fs::File; 32 | use std::ffi::OsStr; 33 | use std::num::ParseIntError; 34 | 35 | pub struct ExitStatus { 36 | success: bool, 37 | } 38 | 39 | pub struct Output { 40 | pub status: ExitStatus, 41 | pub stdout: Vec<u8>, 42 | pub stderr: Vec<u8>, 43 | } 44 | 45 | pub struct Command { 46 | args: Vec<String>, 47 | } 48 | 49 | impl Command { 50 | pub fn new<S: AsRef<OsStr>>(_program: S) -> Command { 51 | Command { 52 | args: Vec::new(), 53 | } 54 | } 55 | 56 | pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command { 57 | self.args.push(arg.as_ref().to_str().unwrap().to_string()); 58 | 59 | self 60 | } 61 | 62 | pub fn args<I, S>(&mut self, args: I) -> &mut Command 63 | where 64 | I: IntoIterator<Item = S>, 65 | S: AsRef<OsStr>, 66 | { 67 | for arg in args { 68 | self.arg(arg); 69 | } 70 | 71 | self 72 | } 73 | 74 | pub fn stdout<T: Into<Stdio>>(&mut self, _cfg: T) -> &mut Command { 75 | self 76 | } 77 | 78 | pub fn stderr<T: Into<Stdio>>(&mut self, _cfg: T) -> &mut Command { 79 | self 80 | } 81 | 82 | pub fn output(&mut self) -> std::io::Result<Output> { 83 | let mut inputs = Vec::new(); 84 | let mut output = None; 85 | let mut stdout = Vec::new(); 86 | let mut stderr = Vec::new(); 87 | let mut success = true; 88 | 89 | let mut args = self.args.iter(); 90 | 91 | while let Some(arg) = args.next() { 92 | match arg.as_str() { 93 | "--quiet" => writeln!(&mut stdout, "quiet").unwrap(), 94 | "-V" => writeln!(&mut stdout, "vulkan_spirv").unwrap(), 95 | "--target-env" => { 96 | writeln!( 97 | &mut stdout, 98 | "target_env: {}", 99 | args.next().unwrap() 100 | ).unwrap(); 101 | }, 102 | "-S" => { 103 | writeln!(&mut stdout, "stage: {}", args.next().unwrap()) 104 | .unwrap(); 105 | }, 106 | "-o" => output = Some(args.next().unwrap()), 107 | other_arg if other_arg.starts_with("-") => { 108 | unreachable!("unexpected arg: {}", other_arg); 109 | }, 110 | input_file => inputs.push(input_file.to_owned()), 111 | } 112 | } 113 | 114 | match output { 115 | None => { 116 | // Pretend to output the disassembly 117 | writeln!(&mut stdout, "disassembly").unwrap(); 118 | }, 119 | Some(output) => { 120 | if let Err(e) = copy_inputs(&inputs, &output) { 121 | writeln!(&mut stderr, "{}", e).unwrap(); 122 | success = false; 123 | } 124 | } 125 | } 126 | 127 | Ok(Output { 128 | status: ExitStatus { success }, 129 | stdout, 130 | stderr, 131 | }) 132 | } 133 | } 134 | 135 | impl ExitStatus { 136 | pub fn success(&self) -> bool { 137 | self.success 138 | } 139 | } 140 | 141 | fn copy_inputs(inputs: &[String], output: &str) -> Result<(), ParseIntError> { 142 | let mut output = BufWriter::new(File::create(output).unwrap()); 143 | 144 | for input in inputs { 145 | let input = File::open(input).unwrap(); 146 | 147 | for line in BufReader::new(input).lines() { 148 | for byte in line.unwrap().split_whitespace() { 149 | let byte_array = [u8::from_str_radix(byte, 16)?]; 150 | output.write_all(&byte_array).unwrap(); 151 | } 152 | } 153 | } 154 | 155 | Ok(()) 156 | } 157 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/make-formats.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2018 Intel Corporation 4 | # Copyright 2023 Neil Roberts 5 | 6 | # Permission is hereby granted, free of charge, to any person obtaining a 7 | # copy of this software and associated documentation files (the "Software"), 8 | # to deal in the Software without restriction, including without limitation 9 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | # and/or sell copies of the Software, and to permit persons to whom the 11 | # Software is furnished to do so, subject to the following conditions: 12 | 13 | # The above copyright notice and this permission notice (including the next 14 | # paragraph) shall be included in all copies or substantial portions of the 15 | # Software. 16 | 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | # DEALINGS IN THE SOFTWARE. 24 | 25 | from __future__ import ( 26 | absolute_import, division, print_function, unicode_literals 27 | ) 28 | 29 | # This script is used to generate format_table.rs from vulkan.h. It is 30 | # not run automatically as part of the build process but if need be it 31 | # can be used to update the file as follows: 32 | # 33 | # ./make-formats.py < /usr/include/vulkan/vulkan.h > format_table.rs 34 | 35 | import re 36 | import sys 37 | from mako.template import Template 38 | 39 | FORMAT_RE = re.compile(r'\bVK_FORMAT_([A-Z0-9_]+)\s*=\s*((?:0x)?[a-fA-F0-9]+)') 40 | SKIP_RE = re.compile(r'(?:_BLOCK(?:_IMG)?|_KHR|^UNDEFINED|' 41 | r'^RANGE_SIZE|^MAX_ENUM|_RANGE)$') 42 | COMPONENT_RE = re.compile('([A-Z]+)([0-9]+)') 43 | COMPONENTS_RE = re.compile('(?:[A-Z][0-9]+)+$') 44 | STUB_RE = re.compile('X([0-9]+)$') 45 | PACK_RE = re.compile('PACK([0-9]+)$') 46 | MODE_RE = re.compile('(?:[US](?:NORM|SCALED|INT|FLOAT)|SRGB)$') 47 | 48 | TEMPLATE="""\ 49 | // Automatically generated by make-formats.py 50 | 51 | static FORMATS: [Format; ${len(formats)}] = [ 52 | % for format in formats: 53 | Format { 54 | vk_format: vk::VK_FORMAT_${format['name']}, 55 | name: "${format['name']}", 56 | % if format['packed_size'] is None: 57 | packed_size: None, 58 | % else: 59 | packed_size: Some(unsafe { 60 | NonZeroUsize::new_unchecked(${format['packed_size']}) 61 | }), 62 | % endif 63 | n_parts: ${len(format['components'])}, 64 | parts: [ 65 | % for letter, size, mode in format['components']: 66 | Part { 67 | bits: ${size}, 68 | component: Component::${letter}, 69 | mode: Mode::${mode}, 70 | }, 71 | % endfor 72 | % for _ in range(len(format['components']), 4): 73 | // stub to fill the array 74 | Part { bits: 0, component: Component::R, mode: Mode::UNORM }, 75 | % endfor 76 | ] 77 | }, 78 | % endfor 79 | ];""" 80 | 81 | 82 | def get_format_names(data): 83 | in_enum = False 84 | 85 | for line in data: 86 | if line.startswith('typedef enum VkFormat '): 87 | in_enum = True 88 | elif line.startswith('}'): 89 | in_enum = False 90 | if not in_enum: 91 | continue 92 | 93 | md = FORMAT_RE.search(line) 94 | if md is None: 95 | continue 96 | name = md.group(1) 97 | if SKIP_RE.search(name): 98 | continue 99 | yield name, int(md.group(2), base=0) 100 | 101 | 102 | def get_formats(data): 103 | for name, value in sorted(set(get_format_names(data))): 104 | parts = name.split('_') 105 | 106 | components, packed_size = get_components(parts) 107 | 108 | if components is None: 109 | continue 110 | 111 | yield {'name': name, 112 | 'value': value, 113 | 'packed_size': packed_size, 114 | 'components': components} 115 | 116 | 117 | def get_components(parts): 118 | packed_size = None 119 | components = [] 120 | 121 | i = 0 122 | while i < len(parts): 123 | md = STUB_RE.match(parts[i]) 124 | if md: 125 | components.append(('X', int(md.group(1)), 'UNORM')) 126 | i += 1 127 | continue 128 | 129 | md = COMPONENTS_RE.match(parts[i]) 130 | if md: 131 | if i + 2 > len(parts): 132 | return None, None 133 | mode_md = MODE_RE.match(parts[i + 1]) 134 | if mode_md is None: 135 | return None, None 136 | 137 | comps = [(md.group(1), int(md.group(2)), parts[i + 1]) 138 | for md in COMPONENT_RE.finditer(parts[i])] 139 | 140 | for letter, size, mode in comps: 141 | if letter not in "RGBADSX": 142 | return None, None 143 | 144 | components.extend(comps) 145 | i += 2 146 | continue 147 | 148 | md = PACK_RE.match(parts[i]) 149 | if md: 150 | packed_size = int(md.group(1)) 151 | i += 1 152 | continue 153 | 154 | return None, None 155 | 156 | return components, packed_size 157 | 158 | 159 | def main(): 160 | template = Template(TEMPLATE) 161 | print(template.render(formats = list(get_formats(sys.stdin)))) 162 | 163 | 164 | if __name__ == '__main__': 165 | main() 166 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/source.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018 Intel Corporation 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | use std::path::PathBuf; 26 | 27 | /// Struct representing the requested source for the data of a 28 | /// [Source]. This can either be a filename to open and read 29 | /// or directly a string containing the source code. 30 | #[derive(Clone, Debug)] 31 | pub(crate) enum Data { 32 | File { filename: PathBuf }, 33 | String { source: String }, 34 | } 35 | 36 | #[derive(Clone, Debug)] 37 | /// A token replacement that should be used for the source. The reader 38 | /// should replace any occurences of `token` in the source with the 39 | /// string in `replacement`. 40 | pub(crate) struct TokenReplacement { 41 | pub token: String, 42 | pub replacement: String, 43 | } 44 | 45 | /// A source for a shader script. The [Source] struct just contains 46 | /// the details of where the data is stored along with any token 47 | /// replacements to be used while reading the data. 48 | #[derive(Clone, Debug)] 49 | pub struct Source { 50 | token_replacements: Vec<TokenReplacement>, 51 | data: Data, 52 | } 53 | 54 | type TokenReplacementIter<'a> = std::slice::Iter<'a, TokenReplacement>; 55 | 56 | impl Source { 57 | fn from_data(data: Data) -> Source { 58 | Source { 59 | token_replacements: Vec::new(), 60 | data, 61 | } 62 | } 63 | 64 | /// Creates a source that will read lines from the given string. 65 | pub fn from_string(source: String) -> Source { 66 | Self::from_data(Data::String { source }) 67 | } 68 | 69 | /// Creates a source that will read lines from the given file. 70 | pub fn from_file(filename: PathBuf) -> Source { 71 | Self::from_data(Data::File { filename }) 72 | } 73 | 74 | /// Adds a token replacement to the source. When lines are read 75 | /// from the source, any mentions of the token will be replaced 76 | /// with the replacement. The replacement can also contain tokens 77 | /// which will be replaced as well. This can cause the line 78 | /// reading to fail and return an error if it causes an infinite 79 | /// loop. 80 | pub fn add_token_replacement( 81 | &mut self, 82 | token: String, 83 | replacement: String, 84 | ) { 85 | self.token_replacements.push(TokenReplacement { token, replacement }); 86 | } 87 | 88 | /// Return an iterator over the token replacements that were 89 | /// previously set with 90 | /// [add_token_replacement](Source::add_token_replacement). 91 | pub(crate) fn token_replacements(&self) -> TokenReplacementIter { 92 | self.token_replacements.iter() 93 | } 94 | 95 | /// Get the data that the source points to. 96 | pub(crate) fn data(&self) -> &Data { 97 | &self.data 98 | } 99 | } 100 | 101 | #[cfg(test)] 102 | mod test { 103 | use super::*; 104 | 105 | #[test] 106 | fn test_constructors() { 107 | let source = Source::from_string("my script".to_owned()); 108 | assert!(matches!( 109 | source.data(), 110 | Data::String { source } if source == "my script" 111 | )); 112 | 113 | let source = Source::from_file( 114 | "my_script.shader_test".to_owned().into() 115 | ); 116 | assert!(matches!( 117 | source.data(), 118 | Data::File { filename } 119 | if filename.to_str().unwrap() == "my_script.shader_test", 120 | )); 121 | } 122 | 123 | #[test] 124 | fn test_token_replacements() { 125 | let mut source = Source::from_string("test".to_string()); 126 | 127 | assert_eq!(source.token_replacements.len(), 0); 128 | 129 | source.add_token_replacement("COLOUR".to_string(), "0xf00".to_string()); 130 | 131 | assert_eq!(source.token_replacements.len(), 1); 132 | assert_eq!(source.token_replacements[0].token, "COLOUR"); 133 | assert_eq!(source.token_replacements[0].replacement, "0xf00"); 134 | 135 | let mut iter = source.token_replacements(); 136 | assert_eq!(iter.next().unwrap().token, "COLOUR"); 137 | assert!(iter.next().is_none()); 138 | 139 | source.add_token_replacement("X".to_string(), "12".to_string()); 140 | 141 | assert_eq!(source.token_replacements.len(), 2); 142 | assert_eq!(source.token_replacements[0].token, "COLOUR"); 143 | assert_eq!(source.token_replacements[0].replacement, "0xf00"); 144 | assert_eq!(source.token_replacements[1].token, "X"); 145 | assert_eq!(source.token_replacements[1].replacement, "12"); 146 | 147 | let mut iter = source.token_replacements(); 148 | assert_eq!(iter.next().unwrap().token, "COLOUR"); 149 | assert_eq!(iter.next().unwrap().token, "X"); 150 | assert!(iter.next().is_none()); 151 | } 152 | } 153 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/config.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright (C) 2018 Intel Corporation 4 | // Copyright 2023 Neil Roberts 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a 7 | // copy of this software and associated documentation files (the "Software"), 8 | // to deal in the Software without restriction, including without limitation 9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | // and/or sell copies of the Software, and to permit persons to whom the 11 | // Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice (including the next 14 | // paragraph) shall be included in all copies or substantial portions of the 15 | // Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | // DEALINGS IN THE SOFTWARE. 24 | 25 | use crate::logger::{self, Logger}; 26 | use crate::inspect; 27 | use std::ffi::c_void; 28 | use std::ptr; 29 | use std::cell::{Cell, RefCell}; 30 | use std::rc::Rc; 31 | use std::fmt; 32 | 33 | pub type ErrorCallback = logger::WriteCallback; 34 | 35 | pub struct Config { 36 | show_disassembly: bool, 37 | device_id: Option<usize>, 38 | 39 | error_cb: Option<logger::WriteCallback>, 40 | inspect_cb: Option<inspect::Callback>, 41 | user_data: *mut c_void, 42 | 43 | logger: Cell<Option<Rc<RefCell<Logger>>>>, 44 | } 45 | 46 | impl Config { 47 | pub fn new() -> Config { 48 | Config { 49 | show_disassembly: false, 50 | device_id: None, 51 | error_cb: None, 52 | inspect_cb: None, 53 | user_data: ptr::null_mut(), 54 | logger: Cell::new(None), 55 | } 56 | } 57 | 58 | /// Sets whether the SPIR-V disassembly of the shaders should be 59 | /// shown when a script is run. The disassembly will be shown on 60 | /// the standard out or it will be passed to the `error_cb` if one 61 | /// has been set. The disassembly is generated with the 62 | /// `spirv-dis` program which needs to be found in the path or it 63 | /// can be specified with the `PIGLIT_SPIRV_DIS_BINARY` 64 | /// environment variable. 65 | pub fn set_show_disassembly(&mut self, show_disassembly: bool) { 66 | self.show_disassembly = show_disassembly; 67 | } 68 | 69 | /// Sets or removes a callback that will receive error messages 70 | /// generated during the script execution. The callback will be 71 | /// invoked one line at a time without the trailing newline 72 | /// terminator. If no callback is specified then the output will 73 | /// be printed on the standard output instead. The callback can 74 | /// later be removed by passing `None`. 75 | pub fn set_error_cb(&mut self, error_cb: Option<ErrorCallback>) { 76 | self.error_cb = error_cb; 77 | self.reset_logger(); 78 | } 79 | 80 | /// Sets or removes an inspection callback. The callback will be 81 | /// invoked after executing a script so that the application can 82 | /// have a chance to examine the framebuffer and any storage or 83 | /// uniform buffers created by the script. 84 | pub fn set_inspect_cb(&mut self, inspect_cb: Option<inspect::Callback>) { 85 | self.inspect_cb = inspect_cb; 86 | } 87 | 88 | /// Sets a pointer that will be passed to the `error_cb` and the 89 | /// `inspect_cb`. 90 | pub fn set_user_data(&mut self, user_data: *mut c_void) { 91 | self.user_data = user_data; 92 | self.reset_logger(); 93 | } 94 | 95 | /// Sets or removes a device number to pick out of the list of 96 | /// `vkPhysicalDevice`s returned by `vkEnumeratePhysicalDevices`. 97 | /// The device will still be checked to see if it is compatible 98 | /// with the script and the test will report Skip if not. If no 99 | /// device ID is set then VkRunner will pick the first one that is 100 | /// compatible with the script. 101 | pub fn set_device_id(&mut self, device_id: Option<usize>) { 102 | self.device_id = device_id; 103 | } 104 | 105 | /// Get a logger that will write to the current `error_cb` of the 106 | /// `Config`. The logger will be shared between calls to this 107 | /// until the callback is changed. 108 | pub(crate) fn logger(&self) -> Rc<RefCell<Logger>> { 109 | let logger = self.logger.take().unwrap_or_else(|| { 110 | Rc::new(RefCell::new(Logger::new(self.error_cb, self.user_data))) 111 | }); 112 | 113 | self.logger.set(Some(Rc::clone(&logger))); 114 | 115 | logger 116 | } 117 | 118 | pub(crate) fn inspector(&self) -> Option<inspect::Inspector> { 119 | self.inspect_cb.map(|cb| inspect::Inspector::new(cb, self.user_data)) 120 | } 121 | 122 | pub(crate) fn show_disassembly(&self) -> bool { 123 | self.show_disassembly 124 | } 125 | 126 | pub(crate) fn device_id(&self) -> Option<usize> { 127 | self.device_id 128 | } 129 | 130 | fn reset_logger(&self) { 131 | // Reset the logger back to None so that it will be 132 | // reconstructed the next time it is requested. 133 | self.logger.take(); 134 | } 135 | } 136 | 137 | // Need to implement this manually because the derive macro can’t 138 | // handle Cells 139 | impl fmt::Debug for Config { 140 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 141 | f.debug_struct("Config") 142 | .field("show_disassembly", &self.show_disassembly) 143 | .field("device_id", &self.device_id) 144 | .field("user_data", &self.user_data) 145 | .finish() 146 | } 147 | } 148 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/make-vulkan-funcs-data.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/env python 2 | 3 | # Copyright 2023 Neil Roberts 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom the 10 | # Software is furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice (including the next 13 | # paragraph) shall be included in all copies or substantial portions of the 14 | # Software. 15 | 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | # DEALINGS IN THE SOFTWARE. 23 | 24 | from __future__ import ( 25 | absolute_import, division, print_function, unicode_literals 26 | ) 27 | 28 | # This script is used to generate vulkan_funcs_data.rs. It is not run 29 | # automatically as part of the build process but if need be it can be 30 | # used to update the file as follows: 31 | # 32 | # ./make-vulkan-funcs-data.py > vulkan_funcs_data.rs 33 | 34 | from mako.template import Template 35 | 36 | 37 | CORE_FUNCS = [ 38 | "vkGetInstanceProcAddr", 39 | "vkCreateInstance", 40 | "vkEnumerateInstanceExtensionProperties", 41 | ] 42 | 43 | 44 | INSTANCE_FUNCS = [ 45 | "vkCreateDevice", 46 | "vkDestroyInstance", 47 | "vkEnumerateDeviceExtensionProperties", 48 | "vkEnumeratePhysicalDevices", 49 | "vkGetDeviceProcAddr", 50 | "vkGetPhysicalDeviceFeatures", 51 | "vkGetPhysicalDeviceFeatures2KHR", 52 | "vkGetPhysicalDeviceFormatProperties", 53 | "vkGetPhysicalDeviceMemoryProperties", 54 | "vkGetPhysicalDeviceProperties", 55 | "vkGetPhysicalDeviceProperties2", 56 | "vkGetPhysicalDeviceQueueFamilyProperties", 57 | "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR", 58 | ] 59 | 60 | 61 | DEVICE_FUNCS = [ 62 | "vkAllocateCommandBuffers", 63 | "vkAllocateDescriptorSets", 64 | "vkAllocateMemory", 65 | "vkBeginCommandBuffer", 66 | "vkBindBufferMemory", 67 | "vkBindImageMemory", 68 | "vkCmdBeginRenderPass", 69 | "vkCmdBindDescriptorSets", 70 | "vkCmdBindIndexBuffer", 71 | "vkCmdBindPipeline", 72 | "vkCmdBindVertexBuffers", 73 | "vkCmdClearAttachments", 74 | "vkCmdCopyBufferToImage", 75 | "vkCmdCopyImageToBuffer", 76 | "vkCmdDispatch", 77 | "vkCmdDraw", 78 | "vkCmdDrawIndexed", 79 | "vkCmdDrawIndexedIndirect", 80 | "vkCmdEndRenderPass", 81 | "vkCmdPipelineBarrier", 82 | "vkCmdPushConstants", 83 | "vkCmdSetScissor", 84 | "vkCmdSetViewport", 85 | "vkCreateBuffer", 86 | "vkCreateCommandPool", 87 | "vkCreateComputePipelines", 88 | "vkCreateDescriptorPool", 89 | "vkCreateDescriptorSetLayout", 90 | "vkCreateFence", 91 | "vkCreateFramebuffer", 92 | "vkCreateGraphicsPipelines", 93 | "vkCreateImage", 94 | "vkCreateImageView", 95 | "vkCreatePipelineCache", 96 | "vkCreatePipelineLayout", 97 | "vkCreateRenderPass", 98 | "vkCreateSampler", 99 | "vkCreateSemaphore", 100 | "vkCreateShaderModule", 101 | "vkDestroyBuffer", 102 | "vkDestroyCommandPool", 103 | "vkDestroyDescriptorPool", 104 | "vkDestroyDescriptorSetLayout", 105 | "vkDestroyDevice", 106 | "vkDestroyFence", 107 | "vkDestroyFramebuffer", 108 | "vkDestroyImage", 109 | "vkDestroyImageView", 110 | "vkDestroyPipeline", 111 | "vkDestroyPipelineCache", 112 | "vkDestroyPipelineLayout", 113 | "vkDestroyRenderPass", 114 | "vkDestroySampler", 115 | "vkDestroySemaphore", 116 | "vkDestroyShaderModule", 117 | "vkEndCommandBuffer", 118 | "vkFlushMappedMemoryRanges", 119 | "vkFreeCommandBuffers", 120 | "vkFreeDescriptorSets", 121 | "vkFreeMemory", 122 | "vkGetBufferMemoryRequirements", 123 | "vkGetDeviceQueue", 124 | "vkGetImageMemoryRequirements", 125 | "vkGetImageSubresourceLayout", 126 | "vkInvalidateMappedMemoryRanges", 127 | "vkMapMemory", 128 | "vkQueueSubmit", 129 | "vkQueueWaitIdle", 130 | "vkResetFences", 131 | "vkUnmapMemory", 132 | "vkUpdateDescriptorSets", 133 | "vkWaitForFences", 134 | ] 135 | 136 | 137 | TEMPLATE = """\ 138 | // Automatically generated by make-vulkan-funcs-data.py 139 | 140 | #[derive(Debug, Clone)] 141 | #[allow(non_snake_case)] 142 | pub struct Library { 143 | lib_vulkan: *const c_void, 144 | lib_vulkan_is_fake: bool, 145 | 146 | % for func in core_funcs: 147 | pub ${func}: vk::PFN_${func}, 148 | % endfor 149 | } 150 | 151 | #[derive(Debug, Clone)] 152 | #[allow(non_snake_case)] 153 | pub struct Instance { 154 | % for func in instance_funcs: 155 | pub ${func}: vk::PFN_${func}, 156 | % endfor 157 | } 158 | 159 | #[derive(Debug, Clone)] 160 | #[allow(non_snake_case)] 161 | #[allow(dead_code)] 162 | pub struct Device { 163 | % for func in device_funcs: 164 | pub ${func}: vk::PFN_${func}, 165 | % endfor 166 | } 167 | 168 | impl Instance { 169 | pub unsafe fn new( 170 | get_instance_proc_cb: GetInstanceProcFunc, 171 | user_data: *const c_void, 172 | ) -> Instance { 173 | Instance { 174 | % for func in instance_funcs: 175 | ${func}: std::mem::transmute(get_instance_proc_cb( 176 | "${func}\\0".as_ptr().cast(), 177 | user_data, 178 | )), 179 | % endfor 180 | } 181 | } 182 | } 183 | 184 | #[allow(dead_code)] 185 | impl Device { 186 | pub fn new(instance: &Instance, device: vk::VkDevice) -> Device { 187 | Device { 188 | % for func in device_funcs: 189 | ${func}: unsafe { 190 | std::mem::transmute(instance.vkGetDeviceProcAddr.unwrap()( 191 | device, 192 | "${func}\\0".as_ptr().cast(), 193 | )) 194 | }, 195 | % endfor 196 | } 197 | } 198 | } 199 | """ 200 | 201 | 202 | def main(): 203 | template = Template(TEMPLATE) 204 | print(template.render(core_funcs = CORE_FUNCS, 205 | instance_funcs = INSTANCE_FUNCS, 206 | device_funcs = DEVICE_FUNCS), 207 | end="") 208 | 209 | 210 | if __name__ == '__main__': 211 | main() 212 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_av1std_encode.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_VIDEO_CODEC_AV1STD_ENCODE_H_ 2 | #define VULKAN_VIDEO_CODEC_AV1STD_ENCODE_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | // vulkan_video_codec_av1std_encode is a preprocessor guard. Do not pass it to API calls. 23 | #define vulkan_video_codec_av1std_encode 1 24 | #include "vulkan_video_codec_av1std.h" 25 | 26 | #define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) 27 | 28 | #define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_API_VERSION_1_0_0 29 | #define VK_STD_VULKAN_VIDEO_CODEC_AV1_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_av1_encode" 30 | typedef struct StdVideoEncodeAV1DecoderModelInfo { 31 | uint8_t buffer_delay_length_minus_1; 32 | uint8_t buffer_removal_time_length_minus_1; 33 | uint8_t frame_presentation_time_length_minus_1; 34 | uint8_t reserved1; 35 | uint32_t num_units_in_decoding_tick; 36 | } StdVideoEncodeAV1DecoderModelInfo; 37 | 38 | typedef struct StdVideoEncodeAV1ExtensionHeader { 39 | uint8_t temporal_id; 40 | uint8_t spatial_id; 41 | } StdVideoEncodeAV1ExtensionHeader; 42 | 43 | typedef struct StdVideoEncodeAV1OperatingPointInfoFlags { 44 | uint32_t decoder_model_present_for_this_op : 1; 45 | uint32_t low_delay_mode_flag : 1; 46 | uint32_t initial_display_delay_present_for_this_op : 1; 47 | uint32_t reserved : 29; 48 | } StdVideoEncodeAV1OperatingPointInfoFlags; 49 | 50 | typedef struct StdVideoEncodeAV1OperatingPointInfo { 51 | StdVideoEncodeAV1OperatingPointInfoFlags flags; 52 | uint16_t operating_point_idc; 53 | uint8_t seq_level_idx; 54 | uint8_t seq_tier; 55 | uint32_t decoder_buffer_delay; 56 | uint32_t encoder_buffer_delay; 57 | uint8_t initial_display_delay_minus_1; 58 | } StdVideoEncodeAV1OperatingPointInfo; 59 | 60 | typedef struct StdVideoEncodeAV1PictureInfoFlags { 61 | uint32_t error_resilient_mode : 1; 62 | uint32_t disable_cdf_update : 1; 63 | uint32_t use_superres : 1; 64 | uint32_t render_and_frame_size_different : 1; 65 | uint32_t allow_screen_content_tools : 1; 66 | uint32_t is_filter_switchable : 1; 67 | uint32_t force_integer_mv : 1; 68 | uint32_t frame_size_override_flag : 1; 69 | uint32_t buffer_removal_time_present_flag : 1; 70 | uint32_t allow_intrabc : 1; 71 | uint32_t frame_refs_short_signaling : 1; 72 | uint32_t allow_high_precision_mv : 1; 73 | uint32_t is_motion_mode_switchable : 1; 74 | uint32_t use_ref_frame_mvs : 1; 75 | uint32_t disable_frame_end_update_cdf : 1; 76 | uint32_t allow_warped_motion : 1; 77 | uint32_t reduced_tx_set : 1; 78 | uint32_t skip_mode_present : 1; 79 | uint32_t delta_q_present : 1; 80 | uint32_t delta_lf_present : 1; 81 | uint32_t delta_lf_multi : 1; 82 | uint32_t segmentation_enabled : 1; 83 | uint32_t segmentation_update_map : 1; 84 | uint32_t segmentation_temporal_update : 1; 85 | uint32_t segmentation_update_data : 1; 86 | uint32_t UsesLr : 1; 87 | uint32_t usesChromaLr : 1; 88 | uint32_t show_frame : 1; 89 | uint32_t showable_frame : 1; 90 | uint32_t reserved : 3; 91 | } StdVideoEncodeAV1PictureInfoFlags; 92 | 93 | typedef struct StdVideoEncodeAV1PictureInfo { 94 | StdVideoEncodeAV1PictureInfoFlags flags; 95 | StdVideoAV1FrameType frame_type; 96 | uint32_t frame_presentation_time; 97 | uint32_t current_frame_id; 98 | uint8_t order_hint; 99 | uint8_t primary_ref_frame; 100 | uint8_t refresh_frame_flags; 101 | uint8_t coded_denom; 102 | uint16_t render_width_minus_1; 103 | uint16_t render_height_minus_1; 104 | StdVideoAV1InterpolationFilter interpolation_filter; 105 | StdVideoAV1TxMode TxMode; 106 | uint8_t delta_q_res; 107 | uint8_t delta_lf_res; 108 | uint8_t ref_order_hint[STD_VIDEO_AV1_NUM_REF_FRAMES]; 109 | int8_t ref_frame_idx[STD_VIDEO_AV1_REFS_PER_FRAME]; 110 | uint8_t reserved1[3]; 111 | uint32_t delta_frame_id_minus_1[STD_VIDEO_AV1_REFS_PER_FRAME]; 112 | const StdVideoAV1TileInfo* pTileInfo; 113 | const StdVideoAV1Quantization* pQuantization; 114 | const StdVideoAV1Segmentation* pSegmentation; 115 | const StdVideoAV1LoopFilter* pLoopFilter; 116 | const StdVideoAV1CDEF* pCDEF; 117 | const StdVideoAV1LoopRestoration* pLoopRestoration; 118 | const StdVideoAV1GlobalMotion* pGlobalMotion; 119 | const StdVideoEncodeAV1ExtensionHeader* pExtensionHeader; 120 | const uint32_t* pBufferRemovalTimes; 121 | } StdVideoEncodeAV1PictureInfo; 122 | 123 | typedef struct StdVideoEncodeAV1ReferenceInfoFlags { 124 | uint32_t disable_frame_end_update_cdf : 1; 125 | uint32_t segmentation_enabled : 1; 126 | uint32_t reserved : 30; 127 | } StdVideoEncodeAV1ReferenceInfoFlags; 128 | 129 | typedef struct StdVideoEncodeAV1ReferenceInfo { 130 | StdVideoEncodeAV1ReferenceInfoFlags flags; 131 | uint32_t RefFrameId; 132 | StdVideoAV1FrameType frame_type; 133 | uint8_t OrderHint; 134 | uint8_t reserved1[3]; 135 | const StdVideoEncodeAV1ExtensionHeader* pExtensionHeader; 136 | } StdVideoEncodeAV1ReferenceInfo; 137 | 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif 144 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/buffer.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | //! Module containing helper structs to automatically free vkBuffers, 25 | //! vkDeviceMemorys and to unmap mapped memory. 26 | 27 | use crate::vk; 28 | use crate::context::Context; 29 | use crate::allocate_store; 30 | use std::ffi::c_void; 31 | use std::rc::Rc; 32 | use std::ptr; 33 | use std::fmt; 34 | 35 | #[derive(Debug)] 36 | pub enum Error { 37 | MapMemoryError, 38 | AllocateStoreError(String), 39 | BufferError, 40 | } 41 | 42 | impl fmt::Display for Error { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 | match self { 45 | Error::BufferError => write!( 46 | f, 47 | "Error creating vkBuffer", 48 | ), 49 | Error::MapMemoryError => write!( 50 | f, 51 | "vkMapMemory failed", 52 | ), 53 | Error::AllocateStoreError(s) => write!(f, "{}", s), 54 | } 55 | } 56 | } 57 | 58 | #[derive(Debug)] 59 | pub struct MappedMemory { 60 | pub pointer: *mut c_void, 61 | memory: vk::VkDeviceMemory, 62 | // Needed for the destructor 63 | context: Rc<Context>, 64 | } 65 | 66 | impl Drop for MappedMemory { 67 | fn drop(&mut self) { 68 | unsafe { 69 | self.context.device().vkUnmapMemory.unwrap()( 70 | self.context.vk_device(), 71 | self.memory, 72 | ); 73 | } 74 | } 75 | } 76 | 77 | impl MappedMemory { 78 | pub fn new( 79 | context: Rc<Context>, 80 | memory: vk::VkDeviceMemory, 81 | ) -> Result<MappedMemory, Error> { 82 | let mut pointer: *mut c_void = ptr::null_mut(); 83 | 84 | let res = unsafe { 85 | context.device().vkMapMemory.unwrap()( 86 | context.vk_device(), 87 | memory, 88 | 0, // offset 89 | vk::VK_WHOLE_SIZE as u64, 90 | 0, // flags, 91 | ptr::addr_of_mut!(pointer), 92 | ) 93 | }; 94 | 95 | if res == vk::VK_SUCCESS { 96 | Ok(MappedMemory { pointer, memory, context }) 97 | } else { 98 | Err(Error::MapMemoryError) 99 | } 100 | } 101 | } 102 | 103 | #[derive(Debug)] 104 | pub struct DeviceMemory { 105 | pub memory: vk::VkDeviceMemory, 106 | pub memory_type_index: u32, 107 | // Needed for the destructor 108 | context: Rc<Context>, 109 | } 110 | 111 | impl Drop for DeviceMemory { 112 | fn drop(&mut self) { 113 | unsafe { 114 | self.context.device().vkFreeMemory.unwrap()( 115 | self.context.vk_device(), 116 | self.memory, 117 | ptr::null(), // allocator 118 | ); 119 | } 120 | } 121 | } 122 | 123 | impl DeviceMemory { 124 | pub fn new_buffer( 125 | context: Rc<Context>, 126 | memory_type_flags: vk::VkMemoryPropertyFlags, 127 | buffer: vk::VkBuffer, 128 | ) -> Result<DeviceMemory, Error> { 129 | let res = allocate_store::allocate_buffer( 130 | context.as_ref(), 131 | memory_type_flags, 132 | buffer, 133 | ); 134 | DeviceMemory::new_from_result(context, res) 135 | } 136 | 137 | pub fn new_image( 138 | context: Rc<Context>, 139 | memory_type_flags: vk::VkMemoryPropertyFlags, 140 | image: vk::VkImage, 141 | ) -> Result<DeviceMemory, Error> { 142 | let res = allocate_store::allocate_image( 143 | context.as_ref(), 144 | memory_type_flags, 145 | image, 146 | ); 147 | DeviceMemory::new_from_result(context, res) 148 | } 149 | 150 | fn new_from_result( 151 | context: Rc<Context>, 152 | result: Result<(vk::VkDeviceMemory, u32), String>, 153 | ) -> Result<DeviceMemory, Error> { 154 | match result { 155 | Ok((memory, memory_type_index)) => Ok(DeviceMemory { 156 | memory, 157 | memory_type_index, 158 | context, 159 | }), 160 | Err(e) => Err(Error::AllocateStoreError(e)), 161 | } 162 | } 163 | } 164 | 165 | #[derive(Debug)] 166 | pub struct Buffer { 167 | pub buffer: vk::VkBuffer, 168 | // Needed for the destructor 169 | context: Rc<Context>, 170 | } 171 | 172 | impl Drop for Buffer { 173 | fn drop(&mut self) { 174 | unsafe { 175 | self.context.device().vkDestroyBuffer.unwrap()( 176 | self.context.vk_device(), 177 | self.buffer, 178 | ptr::null(), // allocator 179 | ); 180 | } 181 | } 182 | } 183 | 184 | impl Buffer { 185 | pub fn new( 186 | context: Rc<Context>, 187 | size: usize, 188 | usage: vk::VkBufferUsageFlagBits, 189 | ) -> Result<Buffer, Error> { 190 | let buffer_create_info = vk::VkBufferCreateInfo { 191 | sType: vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 192 | pNext: ptr::null(), 193 | flags: 0, 194 | size: size as vk::VkDeviceSize, 195 | usage, 196 | sharingMode: vk::VK_SHARING_MODE_EXCLUSIVE, 197 | queueFamilyIndexCount: 0, 198 | pQueueFamilyIndices: ptr::null(), 199 | }; 200 | 201 | let mut buffer: vk::VkBuffer = vk::null_handle(); 202 | 203 | let res = unsafe { 204 | context.device().vkCreateBuffer.unwrap()( 205 | context.vk_device(), 206 | ptr::addr_of!(buffer_create_info), 207 | ptr::null(), // allocator 208 | ptr::addr_of_mut!(buffer), 209 | ) 210 | }; 211 | 212 | if res == vk::VK_SUCCESS { 213 | Ok(Buffer { buffer, context }) 214 | } else { 215 | Err(Error::BufferError) 216 | } 217 | } 218 | } 219 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/temp_file.rs: -------------------------------------------------------------------------------- ```rust 1 | // vkrunner 2 | // 3 | // Copyright 2023 Neil Roberts 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a 6 | // copy of this software and associated documentation files (the "Software"), 7 | // to deal in the Software without restriction, including without limitation 8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | // and/or sell copies of the Software, and to permit persons to whom the 10 | // Software is furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice (including the next 13 | // paragraph) shall be included in all copies or substantial portions of the 14 | // Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | // DEALINGS IN THE SOFTWARE. 23 | 24 | use std::path::{Path, PathBuf}; 25 | use std::fs::File; 26 | use std::io; 27 | use std::fmt; 28 | use std::fmt::Write; 29 | 30 | /// An error that can be returned from [TempFile::new] 31 | #[derive(Debug)] 32 | pub enum Error { 33 | /// All of the possible unique names were tried and all of the 34 | /// files exist. This should probably not really be possible. 35 | NoAvailableFilename, 36 | /// An I/O error other than `AlreadyExists` and `Interrupted` 37 | /// occurred while opening the file. 38 | IoError(io::Error), 39 | } 40 | 41 | impl fmt::Display for Error { 42 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 43 | match self { 44 | Error::NoAvailableFilename => { 45 | write!(f, "No available temporary filenames") 46 | }, 47 | Error::IoError(e) => e.fmt(f), 48 | } 49 | } 50 | } 51 | 52 | /// Class to handle creating a tempory file and deleting it when 53 | /// dropped. 54 | /// 55 | /// The file will be created in the directory returned by 56 | /// [std::env::temp_dir]. It will have a generated name beginning with 57 | /// `vkrunner-` followed by an integer. The file will be opened in 58 | /// write-only mode and the corresponding [File] object can be 59 | /// accessed with [TempFile::file]. The file will be automatically 60 | /// closed and deleted when the `TempFile` is dropped. 61 | #[derive(Debug)] 62 | pub struct TempFile { 63 | filename: PathBuf, 64 | file: Option<File>, 65 | } 66 | 67 | fn find_available_file(prefix: &str, filename: &mut PathBuf) -> Result<File, Error> { 68 | let mut filename_part = String::new(); 69 | 70 | for i in 0..=u64::MAX { 71 | filename_part.clear(); 72 | write!(&mut filename_part, "{}{}", prefix, i).unwrap(); 73 | 74 | filename.push(&filename_part); 75 | 76 | match File::options() 77 | .write(true) 78 | .read(true) 79 | .create_new(true) 80 | .open(&filename) 81 | { 82 | Ok(file) => return Ok(file), 83 | Err(e) => { 84 | if e.kind() != io::ErrorKind::AlreadyExists 85 | && e.kind() != io::ErrorKind::Interrupted 86 | { 87 | return Err(Error::IoError(e)); 88 | } 89 | // Otherwise just try again with a new name 90 | }, 91 | } 92 | 93 | filename.pop(); 94 | } 95 | 96 | Err(Error::NoAvailableFilename) 97 | } 98 | 99 | impl TempFile { 100 | /// Creates a new temporary file or returns an error. 101 | pub fn new() -> Result<TempFile, Error> { 102 | Self::new_with_prefix("vkrunner-") 103 | } 104 | 105 | /// Creates a new temporary file or returns an error. 106 | pub fn new_with_prefix(prefix: &str) -> Result<TempFile, Error> { 107 | let mut filename = std::env::temp_dir(); 108 | let file = find_available_file(prefix, &mut filename)?; 109 | 110 | Ok(TempFile { 111 | filename, 112 | file: Some(file), 113 | }) 114 | } 115 | 116 | /// Gets the [File] object. This can be `None` if 117 | /// [TempFile::close] has been called. 118 | pub fn file(&mut self) -> Option<&mut File> { 119 | self.file.as_mut() 120 | } 121 | 122 | /// Gets the filename of the temporary file. 123 | pub fn filename(&self) -> &Path { 124 | &self.filename 125 | } 126 | 127 | /// Closes the file. The file will still exist and won’t be 128 | /// deleted until the `TempFile` is dropped. 129 | pub fn close(&mut self) { 130 | self.file = None 131 | } 132 | } 133 | 134 | impl Drop for TempFile { 135 | fn drop(&mut self) { 136 | // Make sure the file is closed before trying to delete it 137 | self.file = None; 138 | // We can’t do anything if the remove fails so just ignore the error 139 | let _ = std::fs::remove_file(&self.filename); 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod test { 145 | use super::*; 146 | use std::io::Seek; 147 | use std::io::{Write, Read}; 148 | 149 | #[test] 150 | fn two_files() { 151 | // This test checks for files being present and not present, so use 152 | // an unique prefix to avoid conflict with other tests running in 153 | // parallel. 154 | let prefix = "twofiles-vkrunner-"; 155 | let mut file_a = TempFile::new_with_prefix(prefix).unwrap(); 156 | 157 | assert!(file_a.file().is_some()); 158 | assert!( 159 | file_a 160 | .filename() 161 | .display() 162 | .to_string() 163 | .find(prefix) 164 | .is_some() 165 | ); 166 | assert!(file_a.filename().is_file()); 167 | 168 | file_a.close(); 169 | assert!(file_a.file().is_none()); 170 | assert!(file_a.filename().is_file()); 171 | 172 | let mut file_b = TempFile::new_with_prefix(prefix).unwrap(); 173 | 174 | assert!(file_b.file().is_some()); 175 | assert!(file_a.filename() != file_b.filename()); 176 | assert!(file_b.filename().is_file()); 177 | 178 | let file_a_filename = file_a.filename().to_owned(); 179 | drop(file_a); 180 | assert!(!file_a_filename.is_file()); 181 | 182 | assert!(file_b.filename.is_file()); 183 | 184 | let file_b_filename = file_b.filename().to_owned(); 185 | drop(file_b); 186 | assert!(!file_b_filename.is_file()); 187 | } 188 | 189 | #[test] 190 | fn read() { 191 | let mut temp_file = TempFile::new().unwrap(); 192 | 193 | temp_file.file().unwrap().write(b"hello").unwrap(); 194 | 195 | temp_file.file().unwrap().rewind().unwrap(); 196 | 197 | let mut contents = String::new(); 198 | 199 | temp_file.file().unwrap().read_to_string(&mut contents).unwrap(); 200 | 201 | assert_eq!(&contents, "hello"); 202 | 203 | temp_file.close(); 204 | 205 | let contents = std::fs::read_to_string(temp_file.filename()).unwrap(); 206 | 207 | assert_eq!(contents, "hello"); 208 | } 209 | } 210 | ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/make-features.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2019 Intel Corporation 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom the 10 | # Software is furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice (including the next 13 | # paragraph) shall be included in all copies or substantial portions of the 14 | # Software. 15 | 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | # DEALINGS IN THE SOFTWARE. 23 | 24 | from __future__ import ( 25 | absolute_import, division, print_function, unicode_literals 26 | ) 27 | 28 | # This script is used to generate features.rs from vulkan.h. It 29 | # is not run automatically as part of the build process but if need be 30 | # it can be used to update the file as follows: 31 | # 32 | # ./make-features.py < /usr/include/vulkan/vulkan_core.h > features.rs 33 | 34 | import re 35 | import sys 36 | from mako.template import Template 37 | 38 | 39 | EXTENSIONS = [ 40 | "KHR_16BIT_STORAGE", 41 | "KHR_8BIT_STORAGE", 42 | { 43 | "name": "EXT_ASTC_DECODE_MODE", 44 | "struct": "VkPhysicalDeviceASTCDecodeFeaturesEXT", 45 | "struct_type": "ASTC_DECODE_FEATURES_EXT" 46 | }, 47 | "EXT_BLEND_OPERATION_ADVANCED", 48 | "EXT_BUFFER_DEVICE_ADDRESS", 49 | "KHR_COMPUTE_SHADER_DERIVATIVES", 50 | "EXT_CONDITIONAL_RENDERING", 51 | "NV_CORNER_SAMPLED_IMAGE", 52 | "EXT_DESCRIPTOR_INDEXING", 53 | { 54 | "name": "NV_SCISSOR_EXCLUSIVE", 55 | "struct_type": "EXCLUSIVE_SCISSOR_FEATURES_NV" 56 | }, 57 | "KHR_SHADER_FLOAT16_INT8", 58 | "EXT_FRAGMENT_DENSITY_MAP", 59 | "KHR_FRAGMENT_SHADER_BARYCENTRIC", 60 | "EXT_INLINE_UNIFORM_BLOCK", 61 | "EXT_MEMORY_PRIORITY", 62 | "NV_MESH_SHADER", 63 | "KHR_MULTIVIEW", 64 | "NV_REPRESENTATIVE_FRAGMENT_TEST", 65 | "KHR_SAMPLER_YCBCR_CONVERSION", 66 | "EXT_SCALAR_BLOCK_LAYOUT", 67 | "KHR_SHADER_ATOMIC_INT64", 68 | "NV_SHADER_IMAGE_FOOTPRINT", 69 | "NV_SHADING_RATE_IMAGE", 70 | "EXT_TRANSFORM_FEEDBACK", 71 | "KHR_VARIABLE_POINTERS", 72 | "EXT_VERTEX_ATTRIBUTE_DIVISOR", 73 | "KHR_VULKAN_MEMORY_MODEL", 74 | "KHR_COOPERATIVE_MATRIX", 75 | "EXT_SUBGROUP_SIZE_CONTROL", 76 | ] 77 | 78 | 79 | TEMPLATE="""\ 80 | // Automatically generated by make-features.py 81 | 82 | static EXTENSIONS: [Extension; ${len(extensions)}] = [ 83 | % for e in extensions: 84 | Extension { 85 | name_bytes: vk::VK_${e.name}_EXTENSION_NAME, 86 | struct_size: mem::size_of::<vk::${e.struct}>(), 87 | struct_type: vk::${e.struct_type}, 88 | features: &[ 89 | % for f in e.features: 90 | "${f}", 91 | % endfor 92 | ], 93 | }, 94 | % endfor 95 | ]; 96 | 97 | const N_BASE_FEATURES: usize = ${len(base_features)}; 98 | 99 | static BASE_FEATURES: [&'static str; N_BASE_FEATURES] = [ 100 | % for f in base_features: 101 | "${f}", 102 | % endfor 103 | ]; 104 | """ 105 | 106 | 107 | class Extension: 108 | def __init__(self, name, struct, struct_type, features): 109 | self.name = name 110 | self.struct = struct 111 | self.struct_type = struct_type 112 | self.features = features 113 | 114 | 115 | def capitalize_part(part): 116 | md = re.match(r'([0-9]*)(.*)', part) 117 | return md.group(1) + md.group(2).capitalize() 118 | 119 | 120 | def extension_to_struct_name(ext): 121 | parts = ext.split("_") 122 | vendor = parts[0] 123 | rest = parts[1:] 124 | 125 | return ("VkPhysicalDevice" + 126 | "".join(capitalize_part(part) for part in rest) + 127 | "Features" + 128 | vendor) 129 | 130 | 131 | def struct_to_regexp(struct): 132 | # Make the vendor in the struct name optional 133 | md = re.match(r'(.*?)([A-Z]+)$', struct) 134 | return re.compile(r'^typedef\s+struct\s+' + 135 | re.escape(md.group(1)) + 136 | r'(?:' + re.escape(md.group(2)) + r')?\s+' + 137 | r'{\s*$', 138 | flags=re.MULTILINE) 139 | 140 | 141 | def get_struct_features(header, struct): 142 | struct_re = struct_to_regexp(struct) 143 | md = struct_re.search(header) 144 | 145 | if md is None: 146 | raise Exception("Couldn't find extension {} in vulkan header".format( 147 | struct)) 148 | 149 | header_tail = header[md.end() + 1 :] 150 | header_end = re.search(r'^}', header_tail, flags=re.MULTILINE).start() 151 | members = header_tail[:header_end] 152 | 153 | for line in members.splitlines(): 154 | md = re.match(r'\s*VkStructureType\s+[A-Za-z]+\s*;\s*$', line) 155 | if md: 156 | continue 157 | md = re.match(r'\s*void\s*\*\s+pNext\s*;\s*$', line) 158 | if md: 159 | continue 160 | md = re.match(r'\s*VkBool32\s+([a-zA-Z][a-zA-Z0-9_]*)\s*;\s*$', line) 161 | if not md: 162 | raise Exception("Unknown member in struct: " + line) 163 | 164 | yield md.group(1) 165 | 166 | 167 | def main(): 168 | header = sys.stdin.read() 169 | 170 | extensions = [] 171 | 172 | for ext in EXTENSIONS: 173 | if not isinstance(ext, dict): 174 | ext = { "name": ext } 175 | 176 | name = ext["name"] 177 | 178 | try: 179 | struct_type = ext["struct_type"] 180 | except KeyError: 181 | parts = name.split("_") 182 | struct_type = ("_".join(parts[1:]) + "_" + 183 | "FEATURES_" + 184 | parts[0]) 185 | 186 | try: 187 | struct = ext["struct"] 188 | except KeyError: 189 | parts = struct_type.split("_") 190 | struct = ("VkPhysicalDevice" + 191 | "".join(capitalize_part(part) 192 | for part in parts[:-1]) + 193 | parts[-1]) 194 | 195 | struct_type_enum = "VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_" + struct_type 196 | 197 | features = list(get_struct_features(header, struct)) 198 | extension = Extension(name, struct, struct_type_enum, features) 199 | extensions.append(extension) 200 | 201 | base_features = list( 202 | get_struct_features(header, "VkPhysicalDeviceFeaturesKHR") 203 | ) 204 | 205 | # Validate that all of the feature names are unique 206 | all_features = [feature for extension in extensions 207 | for feature in extension.features] + base_features 208 | 209 | feature_names = set() 210 | for feature in all_features: 211 | if feature in feature_names: 212 | raise Exception("Feature {} is not unique".format(feature)) 213 | feature_names.add(feature) 214 | 215 | template = Template(TEMPLATE) 216 | print(template.render(extensions = extensions, 217 | base_features = base_features)) 218 | 219 | 220 | if __name__ == '__main__': 221 | main() 222 | ``` -------------------------------------------------------------------------------- /vkrunner/precompile-script.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/env python 2 | 3 | # Copyright (C) 2018 Intel Corporation 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom the 10 | # Software is furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice (including the next 13 | # paragraph) shall be included in all copies or substantial portions of the 14 | # Software. 15 | 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | # DEALINGS IN THE SOFTWARE. 23 | 24 | from __future__ import ( 25 | absolute_import, division, print_function, unicode_literals 26 | ) 27 | 28 | import re 29 | import tempfile 30 | import sys 31 | import subprocess 32 | import argparse 33 | import os 34 | import struct 35 | 36 | TARGET_ENV = "vulkan1.0" 37 | 38 | SECTION_RE = re.compile(r'^\[([^]]+)\]\s*$') 39 | VERSION_RE = re.compile(r'^(\s*vulkan\s*\d+\.\d+)(\.\d+\s*)$') 40 | TRIM_RE = re.compile(r'\s+') 41 | 42 | STAGE_MAP = { 43 | 'vertex shader': 'vert', 44 | 'tessellation control shader': 'tesc', 45 | 'tessellation evaluation shader': 'tese', 46 | 'geometry shader': 'geom', 47 | 'fragment shader': 'frag', 48 | 'compute shader': 'comp', 49 | } 50 | 51 | class Converter: 52 | def __init__(self, type, stage, fout, binary, version): 53 | self._type = type 54 | self._stage = stage 55 | self._fout = fout 56 | self._tempfile = tempfile.NamedTemporaryFile('w+') 57 | self._binary = binary 58 | self._version = version 59 | 60 | def add_line(self, line): 61 | self._tempfile.write(line) 62 | 63 | def finish(self): 64 | self._tempfile.flush() 65 | 66 | with tempfile.NamedTemporaryFile() as temp_outfile: 67 | if self._type == 'glsl': 68 | subprocess.check_call([self._binary, 69 | "--quiet", 70 | "-S", self._stage, 71 | "-G", 72 | "-V", 73 | "--target-env", self._version, 74 | "-o", temp_outfile.name, 75 | self._tempfile.name]) 76 | else: 77 | subprocess.check_call([self._binary, 78 | "--target-env", self._version, 79 | "-o", temp_outfile.name, 80 | self._tempfile.name]) 81 | 82 | data = temp_outfile.read() 83 | 84 | self._tempfile.close() 85 | 86 | if len(data) < 4 or len(data) % 4 != 0: 87 | print("Resulting binary SPIR-V file has an invalid size", 88 | file=sys.stderr) 89 | sys.exit(1) 90 | 91 | magic_header = struct.unpack(">I", data[0:4])[0] 92 | 93 | if magic_header == 0x07230203: 94 | byte_order = ">I" 95 | elif magic_header == 0x03022307: 96 | byte_order = "<I" 97 | else: 98 | print("Resulting binary SPIR-V has an invalid magic number", 99 | file=sys.stderr) 100 | sys.exit(1) 101 | 102 | line_pos = 0 103 | for offset in range(0, len(data), 4): 104 | value = struct.unpack(byte_order, data[offset:offset+4])[0] 105 | hex_str = "{:x}".format(value) 106 | if len(hex_str) + line_pos + 1 > 80: 107 | line_pos = 0 108 | print(file=self._fout) 109 | elif line_pos > 0: 110 | print(' ', file=self._fout, end='') 111 | line_pos += 1 112 | print(hex_str, file=self._fout, end='') 113 | line_pos += len(hex_str) 114 | 115 | if line_pos > 0: 116 | print(file=self._fout) 117 | print(file=self._fout) 118 | 119 | def convert_stream(fin, fout, glslang, spirv_as): 120 | section_name = None 121 | converter = None 122 | version = TARGET_ENV 123 | 124 | for line in fin: 125 | md = SECTION_RE.match(line) 126 | if md: 127 | if converter: 128 | converter.finish() 129 | converter = None 130 | 131 | section_name = md.group(1) 132 | 133 | if section_name.endswith(' spirv'): 134 | stage_name = section_name[:-6] 135 | converter = Converter('spirv', 136 | STAGE_MAP[stage_name], 137 | fout, 138 | spirv_as, 139 | version) 140 | print("[{} binary]".format(stage_name), file=fout) 141 | elif section_name in STAGE_MAP: 142 | converter = Converter('glsl', 143 | STAGE_MAP[section_name], 144 | fout, glslang, version) 145 | print("[{} binary]".format(section_name), file=fout) 146 | else: 147 | fout.write(line) 148 | elif converter: 149 | converter.add_line(line) 150 | else: 151 | if section_name == 'require': 152 | vmd = VERSION_RE.match(line) 153 | if vmd: 154 | version = vmd.group(1) 155 | version = TRIM_RE.sub('', version) 156 | fout.write(line) 157 | 158 | if converter: 159 | converter.finish() 160 | 161 | 162 | parser = argparse.ArgumentParser(description='Precompile VkRunner scripts.') 163 | parser.add_argument('inputs', metavar='INPUT', type=str, nargs='+', 164 | help='an input file process') 165 | parser.add_argument('-o', dest='output', metavar='OUTPUT', 166 | help='an output file or directory', required=True) 167 | 168 | parser.add_argument('-g', dest='glslang', metavar='GLSLANG', 169 | help='glslangValidator binary path', required=False, default="glslangValidator") 170 | 171 | parser.add_argument('-s', dest='spirv_as', metavar='SPIRV_AS', 172 | help='spirv-as binary path', required=False, default="spirv-as") 173 | 174 | args = parser.parse_args() 175 | output_is_directory = len(args.inputs) >= 2 or os.path.isdir(args.output) 176 | 177 | if output_is_directory: 178 | try: 179 | os.mkdir(args.output) 180 | except OSError: 181 | pass 182 | 183 | for input in args.inputs: 184 | if output_is_directory: 185 | output = os.path.join(args.output, os.path.basename(input)) 186 | else: 187 | output = args.output 188 | 189 | with open(input, 'r') as fin: 190 | with open(output, 'w') as fout: 191 | convert_stream(fin, fout, args.glslang, args.spirv_as) 192 | ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_h264std_encode.h: -------------------------------------------------------------------------------- ``` 1 | #ifndef VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ 2 | #define VULKAN_VIDEO_CODEC_H264STD_ENCODE_H_ 1 3 | 4 | /* 5 | ** Copyright 2015-2025 The Khronos Group Inc. 6 | ** 7 | ** SPDX-License-Identifier: Apache-2.0 8 | */ 9 | 10 | /* 11 | ** This header is generated from the Khronos Vulkan XML API Registry. 12 | ** 13 | */ 14 | 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | 22 | // vulkan_video_codec_h264std_encode is a preprocessor guard. Do not pass it to API calls. 23 | #define vulkan_video_codec_h264std_encode 1 24 | #include "vulkan_video_codec_h264std.h" 25 | 26 | #define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0) 27 | 28 | #define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_API_VERSION_1_0_0 29 | #define VK_STD_VULKAN_VIDEO_CODEC_H264_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h264_encode" 30 | typedef struct StdVideoEncodeH264WeightTableFlags { 31 | uint32_t luma_weight_l0_flag; 32 | uint32_t chroma_weight_l0_flag; 33 | uint32_t luma_weight_l1_flag; 34 | uint32_t chroma_weight_l1_flag; 35 | } StdVideoEncodeH264WeightTableFlags; 36 | 37 | typedef struct StdVideoEncodeH264WeightTable { 38 | StdVideoEncodeH264WeightTableFlags flags; 39 | uint8_t luma_log2_weight_denom; 40 | uint8_t chroma_log2_weight_denom; 41 | int8_t luma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; 42 | int8_t luma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; 43 | int8_t chroma_weight_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; 44 | int8_t chroma_offset_l0[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; 45 | int8_t luma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; 46 | int8_t luma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; 47 | int8_t chroma_weight_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; 48 | int8_t chroma_offset_l1[STD_VIDEO_H264_MAX_NUM_LIST_REF][STD_VIDEO_H264_MAX_CHROMA_PLANES]; 49 | } StdVideoEncodeH264WeightTable; 50 | 51 | typedef struct StdVideoEncodeH264SliceHeaderFlags { 52 | uint32_t direct_spatial_mv_pred_flag : 1; 53 | uint32_t num_ref_idx_active_override_flag : 1; 54 | uint32_t reserved : 30; 55 | } StdVideoEncodeH264SliceHeaderFlags; 56 | 57 | typedef struct StdVideoEncodeH264PictureInfoFlags { 58 | uint32_t IdrPicFlag : 1; 59 | uint32_t is_reference : 1; 60 | uint32_t no_output_of_prior_pics_flag : 1; 61 | uint32_t long_term_reference_flag : 1; 62 | uint32_t adaptive_ref_pic_marking_mode_flag : 1; 63 | uint32_t reserved : 27; 64 | } StdVideoEncodeH264PictureInfoFlags; 65 | 66 | typedef struct StdVideoEncodeH264ReferenceInfoFlags { 67 | uint32_t used_for_long_term_reference : 1; 68 | uint32_t reserved : 31; 69 | } StdVideoEncodeH264ReferenceInfoFlags; 70 | 71 | typedef struct StdVideoEncodeH264ReferenceListsInfoFlags { 72 | uint32_t ref_pic_list_modification_flag_l0 : 1; 73 | uint32_t ref_pic_list_modification_flag_l1 : 1; 74 | uint32_t reserved : 30; 75 | } StdVideoEncodeH264ReferenceListsInfoFlags; 76 | 77 | typedef struct StdVideoEncodeH264RefListModEntry { 78 | StdVideoH264ModificationOfPicNumsIdc modification_of_pic_nums_idc; 79 | uint16_t abs_diff_pic_num_minus1; 80 | uint16_t long_term_pic_num; 81 | } StdVideoEncodeH264RefListModEntry; 82 | 83 | typedef struct StdVideoEncodeH264RefPicMarkingEntry { 84 | StdVideoH264MemMgmtControlOp memory_management_control_operation; 85 | uint16_t difference_of_pic_nums_minus1; 86 | uint16_t long_term_pic_num; 87 | uint16_t long_term_frame_idx; 88 | uint16_t max_long_term_frame_idx_plus1; 89 | } StdVideoEncodeH264RefPicMarkingEntry; 90 | 91 | typedef struct StdVideoEncodeH264ReferenceListsInfo { 92 | StdVideoEncodeH264ReferenceListsInfoFlags flags; 93 | uint8_t num_ref_idx_l0_active_minus1; 94 | uint8_t num_ref_idx_l1_active_minus1; 95 | uint8_t RefPicList0[STD_VIDEO_H264_MAX_NUM_LIST_REF]; 96 | uint8_t RefPicList1[STD_VIDEO_H264_MAX_NUM_LIST_REF]; 97 | uint8_t refList0ModOpCount; 98 | uint8_t refList1ModOpCount; 99 | uint8_t refPicMarkingOpCount; 100 | uint8_t reserved1[7]; 101 | const StdVideoEncodeH264RefListModEntry* pRefList0ModOperations; 102 | const StdVideoEncodeH264RefListModEntry* pRefList1ModOperations; 103 | const StdVideoEncodeH264RefPicMarkingEntry* pRefPicMarkingOperations; 104 | } StdVideoEncodeH264ReferenceListsInfo; 105 | 106 | typedef struct StdVideoEncodeH264PictureInfo { 107 | StdVideoEncodeH264PictureInfoFlags flags; 108 | uint8_t seq_parameter_set_id; 109 | uint8_t pic_parameter_set_id; 110 | uint16_t idr_pic_id; 111 | StdVideoH264PictureType primary_pic_type; 112 | uint32_t frame_num; 113 | int32_t PicOrderCnt; 114 | uint8_t temporal_id; 115 | uint8_t reserved1[3]; 116 | const StdVideoEncodeH264ReferenceListsInfo* pRefLists; 117 | } StdVideoEncodeH264PictureInfo; 118 | 119 | typedef struct StdVideoEncodeH264ReferenceInfo { 120 | StdVideoEncodeH264ReferenceInfoFlags flags; 121 | StdVideoH264PictureType primary_pic_type; 122 | uint32_t FrameNum; 123 | int32_t PicOrderCnt; 124 | uint16_t long_term_pic_num; 125 | uint16_t long_term_frame_idx; 126 | uint8_t temporal_id; 127 | } StdVideoEncodeH264ReferenceInfo; 128 | 129 | typedef struct StdVideoEncodeH264SliceHeader { 130 | StdVideoEncodeH264SliceHeaderFlags flags; 131 | uint32_t first_mb_in_slice; 132 | StdVideoH264SliceType slice_type; 133 | int8_t slice_alpha_c0_offset_div2; 134 | int8_t slice_beta_offset_div2; 135 | int8_t slice_qp_delta; 136 | uint8_t reserved1; 137 | StdVideoH264CabacInitIdc cabac_init_idc; 138 | StdVideoH264DisableDeblockingFilterIdc disable_deblocking_filter_idc; 139 | const StdVideoEncodeH264WeightTable* pWeightTable; 140 | } StdVideoEncodeH264SliceHeader; 141 | 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif 148 | ```