This is page 2 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
--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_h265std_encode.h:
--------------------------------------------------------------------------------
```
1 | #ifndef VULKAN_VIDEO_CODEC_H265STD_ENCODE_H_
2 | #define VULKAN_VIDEO_CODEC_H265STD_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_h265std_encode is a preprocessor guard. Do not pass it to API calls.
23 | #define vulkan_video_codec_h265std_encode 1
24 | #include "vulkan_video_codec_h265std.h"
25 |
26 | #define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0 VK_MAKE_VIDEO_STD_VERSION(1, 0, 0)
27 |
28 | #define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_SPEC_VERSION VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_API_VERSION_1_0_0
29 | #define VK_STD_VULKAN_VIDEO_CODEC_H265_ENCODE_EXTENSION_NAME "VK_STD_vulkan_video_codec_h265_encode"
30 | typedef struct StdVideoEncodeH265WeightTableFlags {
31 | uint16_t luma_weight_l0_flag;
32 | uint16_t chroma_weight_l0_flag;
33 | uint16_t luma_weight_l1_flag;
34 | uint16_t chroma_weight_l1_flag;
35 | } StdVideoEncodeH265WeightTableFlags;
36 |
37 | typedef struct StdVideoEncodeH265WeightTable {
38 | StdVideoEncodeH265WeightTableFlags flags;
39 | uint8_t luma_log2_weight_denom;
40 | int8_t delta_chroma_log2_weight_denom;
41 | int8_t delta_luma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
42 | int8_t luma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
43 | int8_t delta_chroma_weight_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
44 | int8_t delta_chroma_offset_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
45 | int8_t delta_luma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
46 | int8_t luma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
47 | int8_t delta_chroma_weight_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
48 | int8_t delta_chroma_offset_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF][STD_VIDEO_H265_MAX_CHROMA_PLANES];
49 | } StdVideoEncodeH265WeightTable;
50 |
51 | typedef struct StdVideoEncodeH265SliceSegmentHeaderFlags {
52 | uint32_t first_slice_segment_in_pic_flag : 1;
53 | uint32_t dependent_slice_segment_flag : 1;
54 | uint32_t slice_sao_luma_flag : 1;
55 | uint32_t slice_sao_chroma_flag : 1;
56 | uint32_t num_ref_idx_active_override_flag : 1;
57 | uint32_t mvd_l1_zero_flag : 1;
58 | uint32_t cabac_init_flag : 1;
59 | uint32_t cu_chroma_qp_offset_enabled_flag : 1;
60 | uint32_t deblocking_filter_override_flag : 1;
61 | uint32_t slice_deblocking_filter_disabled_flag : 1;
62 | uint32_t collocated_from_l0_flag : 1;
63 | uint32_t slice_loop_filter_across_slices_enabled_flag : 1;
64 | uint32_t reserved : 20;
65 | } StdVideoEncodeH265SliceSegmentHeaderFlags;
66 |
67 | typedef struct StdVideoEncodeH265SliceSegmentHeader {
68 | StdVideoEncodeH265SliceSegmentHeaderFlags flags;
69 | StdVideoH265SliceType slice_type;
70 | uint32_t slice_segment_address;
71 | uint8_t collocated_ref_idx;
72 | uint8_t MaxNumMergeCand;
73 | int8_t slice_cb_qp_offset;
74 | int8_t slice_cr_qp_offset;
75 | int8_t slice_beta_offset_div2;
76 | int8_t slice_tc_offset_div2;
77 | int8_t slice_act_y_qp_offset;
78 | int8_t slice_act_cb_qp_offset;
79 | int8_t slice_act_cr_qp_offset;
80 | int8_t slice_qp_delta;
81 | uint16_t reserved1;
82 | const StdVideoEncodeH265WeightTable* pWeightTable;
83 | } StdVideoEncodeH265SliceSegmentHeader;
84 |
85 | typedef struct StdVideoEncodeH265ReferenceListsInfoFlags {
86 | uint32_t ref_pic_list_modification_flag_l0 : 1;
87 | uint32_t ref_pic_list_modification_flag_l1 : 1;
88 | uint32_t reserved : 30;
89 | } StdVideoEncodeH265ReferenceListsInfoFlags;
90 |
91 | typedef struct StdVideoEncodeH265ReferenceListsInfo {
92 | StdVideoEncodeH265ReferenceListsInfoFlags 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_H265_MAX_NUM_LIST_REF];
96 | uint8_t RefPicList1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
97 | uint8_t list_entry_l0[STD_VIDEO_H265_MAX_NUM_LIST_REF];
98 | uint8_t list_entry_l1[STD_VIDEO_H265_MAX_NUM_LIST_REF];
99 | } StdVideoEncodeH265ReferenceListsInfo;
100 |
101 | typedef struct StdVideoEncodeH265PictureInfoFlags {
102 | uint32_t is_reference : 1;
103 | uint32_t IrapPicFlag : 1;
104 | uint32_t used_for_long_term_reference : 1;
105 | uint32_t discardable_flag : 1;
106 | uint32_t cross_layer_bla_flag : 1;
107 | uint32_t pic_output_flag : 1;
108 | uint32_t no_output_of_prior_pics_flag : 1;
109 | uint32_t short_term_ref_pic_set_sps_flag : 1;
110 | uint32_t slice_temporal_mvp_enabled_flag : 1;
111 | uint32_t reserved : 23;
112 | } StdVideoEncodeH265PictureInfoFlags;
113 |
114 | typedef struct StdVideoEncodeH265LongTermRefPics {
115 | uint8_t num_long_term_sps;
116 | uint8_t num_long_term_pics;
117 | uint8_t lt_idx_sps[STD_VIDEO_H265_MAX_LONG_TERM_REF_PICS_SPS];
118 | uint8_t poc_lsb_lt[STD_VIDEO_H265_MAX_LONG_TERM_PICS];
119 | uint16_t used_by_curr_pic_lt_flag;
120 | uint8_t delta_poc_msb_present_flag[STD_VIDEO_H265_MAX_DELTA_POC];
121 | uint8_t delta_poc_msb_cycle_lt[STD_VIDEO_H265_MAX_DELTA_POC];
122 | } StdVideoEncodeH265LongTermRefPics;
123 |
124 | typedef struct StdVideoEncodeH265PictureInfo {
125 | StdVideoEncodeH265PictureInfoFlags flags;
126 | StdVideoH265PictureType pic_type;
127 | uint8_t sps_video_parameter_set_id;
128 | uint8_t pps_seq_parameter_set_id;
129 | uint8_t pps_pic_parameter_set_id;
130 | uint8_t short_term_ref_pic_set_idx;
131 | int32_t PicOrderCntVal;
132 | uint8_t TemporalId;
133 | uint8_t reserved1[7];
134 | const StdVideoEncodeH265ReferenceListsInfo* pRefLists;
135 | const StdVideoH265ShortTermRefPicSet* pShortTermRefPicSet;
136 | const StdVideoEncodeH265LongTermRefPics* pLongTermRefPics;
137 | } StdVideoEncodeH265PictureInfo;
138 |
139 | typedef struct StdVideoEncodeH265ReferenceInfoFlags {
140 | uint32_t used_for_long_term_reference : 1;
141 | uint32_t unused_for_reference : 1;
142 | uint32_t reserved : 30;
143 | } StdVideoEncodeH265ReferenceInfoFlags;
144 |
145 | typedef struct StdVideoEncodeH265ReferenceInfo {
146 | StdVideoEncodeH265ReferenceInfoFlags flags;
147 | StdVideoH265PictureType pic_type;
148 | int32_t PicOrderCntVal;
149 | uint8_t TemporalId;
150 | } StdVideoEncodeH265ReferenceInfo;
151 |
152 |
153 | #ifdef __cplusplus
154 | }
155 | #endif
156 |
157 | #endif
158 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/flush_memory.rs:
--------------------------------------------------------------------------------
```rust
1 | // vkrunner
2 | //
3 | // Copyright (C) 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::context::Context;
25 | use crate::vk;
26 | use std::ptr;
27 | use std::fmt;
28 |
29 | #[derive(Debug)]
30 | pub struct Error(vk::VkResult);
31 |
32 | impl fmt::Display for Error {
33 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 | write!(f, "vkFlushMappedMemoryRanges failed: {:?}", self.0)
35 | }
36 | }
37 |
38 | /// Calls `vkFlushMappedMemoryRanges` with the range specified in
39 | /// `offset` and `size` unless the specified memory type has the
40 | /// `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` property set.
41 | ///
42 | /// For testing, the environment variable
43 | /// `VKRUNNER_ALWAYS_FLUSH_MEMORY` can be set to `true` to make it
44 | /// always flush the memory regardless of memory type properties.
45 | pub fn flush_memory(
46 | context: &Context,
47 | memory_type_index: usize,
48 | memory: vk::VkDeviceMemory,
49 | offset: vk::VkDeviceSize,
50 | size: vk::VkDeviceSize,
51 | ) -> Result<(), Error> {
52 | let memory_properties = context.memory_properties();
53 | let memory_type =
54 | &memory_properties.memoryTypes[memory_type_index as usize];
55 |
56 | // We don’t need to do anything if the memory is already coherent
57 | if !context.always_flush_memory()
58 | && (memory_type.propertyFlags
59 | & vk::VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0
60 | {
61 | return Ok(());
62 | }
63 |
64 | let mapped_memory_range = vk::VkMappedMemoryRange {
65 | sType: vk::VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
66 | pNext: ptr::null(),
67 | memory,
68 | offset,
69 | size,
70 | };
71 |
72 | let res = unsafe {
73 | context.device().vkFlushMappedMemoryRanges.unwrap()(
74 | context.vk_device(),
75 | 1, // memoryRangeCount
76 | ptr::addr_of!(mapped_memory_range),
77 | )
78 | };
79 |
80 | if res == vk::VK_SUCCESS {
81 | Ok(())
82 | } else {
83 | Err(Error(res))
84 | }
85 | }
86 |
87 | #[cfg(test)]
88 | mod test {
89 | use super::*;
90 | use std::rc::Rc;
91 | use crate::requirements::Requirements;
92 | use crate::fake_vulkan::FakeVulkan;
93 | use crate::env_var_test::EnvVarLock;
94 |
95 | struct Memory {
96 | handle: vk::VkDeviceMemory,
97 | context: Rc<Context>,
98 | }
99 |
100 | impl Memory {
101 | fn new(context: Rc<Context>) -> Memory {
102 | let mut handle = vk::null_handle();
103 |
104 | let allocate_info = vk::VkMemoryAllocateInfo {
105 | sType: vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
106 | pNext: ptr::null(),
107 | allocationSize: 1024,
108 | memoryTypeIndex: 0,
109 | };
110 |
111 | unsafe {
112 | let res = context.device().vkAllocateMemory.unwrap()(
113 | context.vk_device(),
114 | ptr::addr_of!(allocate_info),
115 | ptr::null(), // allocator
116 | ptr::addr_of_mut!(handle),
117 | );
118 |
119 | assert_eq!(res, vk::VK_SUCCESS);
120 | }
121 |
122 | Memory { handle, context }
123 | }
124 | }
125 |
126 | impl Drop for Memory {
127 | fn drop(&mut self) {
128 | unsafe {
129 | self.context.device().vkFreeMemory.unwrap()(
130 | self.context.vk_device(),
131 | self.handle,
132 | ptr::null_mut(), // allocator
133 | );
134 | }
135 | }
136 | }
137 |
138 | struct TestData {
139 | context: Rc<Context>,
140 | fake_vulkan: Box<FakeVulkan>,
141 | }
142 |
143 | impl TestData {
144 | fn new(coherent_memory: bool) -> TestData {
145 | let mut fake_vulkan = FakeVulkan::new();
146 | fake_vulkan.physical_devices.push(Default::default());
147 | let memory_properties =
148 | &mut fake_vulkan.physical_devices[0].memory_properties;
149 | memory_properties.memoryTypeCount = 1;
150 |
151 | memory_properties.memoryTypes[0].propertyFlags =
152 | if coherent_memory {
153 | vk::VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
154 | } else {
155 | 0
156 | };
157 |
158 | fake_vulkan.set_override();
159 | let context = Rc::new(
160 | Context::new(&Requirements::new(), None).unwrap()
161 | );
162 |
163 | TestData { context, fake_vulkan }
164 | }
165 | }
166 |
167 | fn test_flag_combination(
168 | memory_is_coherent: bool,
169 | always_flush: bool,
170 | flush_expected: bool,
171 | ) {
172 | let _env_var_lock = EnvVarLock::new(&[
173 | (
174 | "VKRUNNER_ALWAYS_FLUSH_MEMORY",
175 | if always_flush { "true" } else { "false" },
176 | )
177 | ]);
178 |
179 | let test_data = TestData::new(memory_is_coherent);
180 |
181 | let memory = Memory::new(Rc::clone(&test_data.context));
182 |
183 | flush_memory(
184 | &test_data.context,
185 | 0, // memory_type_index
186 | memory.handle,
187 | 16, // offset
188 | 24, // size
189 | ).unwrap();
190 |
191 | if flush_expected {
192 | assert_eq!(test_data.fake_vulkan.memory_flushes.len(), 1);
193 | assert_eq!(
194 | test_data.fake_vulkan.memory_flushes[0].memory,
195 | memory.handle,
196 | );
197 | assert_eq!(test_data.fake_vulkan.memory_flushes[0].offset, 16);
198 | assert_eq!(test_data.fake_vulkan.memory_flushes[0].size, 24);
199 | } else {
200 | assert_eq!(test_data.fake_vulkan.memory_flushes.len(), 0);
201 | }
202 | }
203 |
204 | #[test]
205 | fn should_flush() {
206 | test_flag_combination(
207 | false, // memory_is_coherent
208 | false, // always_flush
209 | true, // flush_expected
210 | );
211 | test_flag_combination(
212 | false, // memory_is_coherent
213 | true, // always_flush
214 | true, // flush_expected
215 | );
216 | test_flag_combination(
217 | true, // memory_is_coherent
218 | false, // always_flush
219 | false, // flush_expected
220 | );
221 | test_flag_combination(
222 | true, // memory_is_coherent
223 | true, // always_flush
224 | true, // flush_expected
225 | );
226 | }
227 |
228 | #[test]
229 | fn error() {
230 | let _env_var_lock = EnvVarLock::new(&[
231 | ("VKRUNNER_ALWAYS_FLUSH_MEMORY", "false")
232 | ]);
233 |
234 | let mut test_data = TestData::new(
235 | false, // memory_is_coherent
236 | );
237 |
238 | let memory = Memory::new(Rc::clone(&test_data.context));
239 |
240 | test_data.fake_vulkan.queue_result(
241 | "vkFlushMappedMemoryRanges".to_string(),
242 | vk::VK_ERROR_UNKNOWN,
243 | );
244 |
245 | let error = flush_memory(
246 | &test_data.context,
247 | 0, // memory_type_index
248 | memory.handle,
249 | 16, // offset
250 | 24, // size
251 | ).unwrap_err();
252 |
253 | assert!(error.to_string().starts_with("vkFlushMappedMemoryRanges failed"));
254 | assert_eq!(error.0, vk::VK_ERROR_UNKNOWN);
255 | }
256 | }
257 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/vulkan_funcs.rs:
--------------------------------------------------------------------------------
```rust
1 | // vkrunner
2 | //
3 | // Copyright (C) 2016, 2023 Neil Roberts
4 | // Copyright (C) 2018 Intel Corporation
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 | use crate::util;
27 | use std::ffi::{c_void, c_int, c_char, CString};
28 | use std::mem;
29 | use std::fmt;
30 |
31 | /// Offset of the pNext member of the structs that can be chained.
32 | /// There doesn’t seem to be a nice equivalent to offsetof in Rust so
33 | /// this is just trying to replicate the C struct alignment rules.
34 | pub const NEXT_PTR_OFFSET: usize = util::align(
35 | mem::size_of::<vk::VkStructureType>(),
36 | mem::align_of::<*mut std::os::raw::c_void>(),
37 | );
38 | /// Offset of the first VkBool32 field in the features structs.
39 | pub const FIRST_FEATURE_OFFSET: usize = util::align(
40 | NEXT_PTR_OFFSET + mem::size_of::<*mut std::os::raw::c_void>(),
41 | mem::align_of::<vk::VkBool32>(),
42 | );
43 |
44 | pub type GetInstanceProcFunc = unsafe extern "C" fn(
45 | func_name: *const c_char,
46 | user_data: *const c_void,
47 | ) -> *const c_void;
48 |
49 | #[derive(Debug)]
50 | pub enum Error {
51 | OpenLibraryFailed(&'static str),
52 | }
53 |
54 | impl fmt::Display for Error {
55 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 | match self {
57 | Error::OpenLibraryFailed(lib) => write!(f, "Error opening {}", lib)
58 | }
59 | }
60 | }
61 |
62 | include!{"vulkan_funcs_data.rs"}
63 |
64 | struct LoaderFunc {
65 | lib_vulkan: *const c_void,
66 | lib_vulkan_is_fake: bool,
67 | get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
68 | }
69 |
70 | // Per-thread override for the get_instance_proc_address function.
71 | // This is only used in unit tests to implement a fake Vulkan driver.
72 | #[cfg(test)]
73 | thread_local! {
74 | static LOADER_FUNC_OVERRIDE:
75 | std::cell::Cell<Option<LoaderFunc>> = std::cell::Cell::new(None);
76 | }
77 |
78 | impl Library {
79 | fn get_loader_func(
80 | ) -> Result<LoaderFunc, Error> {
81 | // Override for unit tests. If an override function is set
82 | // then we will return that instead. `take` is called on it so
83 | // that it will only be used once and subsequent calls will
84 | // revert back to the normal mechanism.
85 | #[cfg(test)]
86 | if let Some(loader_func) = LOADER_FUNC_OVERRIDE.with(|f| f.take()) {
87 | return Ok(loader_func);
88 | }
89 |
90 | #[cfg(unix)]
91 | {
92 | extern "C" {
93 | fn dlopen(name: *const c_char, flags: c_int) -> *const c_void;
94 | fn dlsym(
95 | lib: *const c_void,
96 | name: *const c_char
97 | ) -> *const c_void;
98 | }
99 |
100 | let lib_name;
101 |
102 | #[cfg(target_os = "android")]
103 | {
104 | lib_name = "libvulkan.so";
105 | }
106 | #[cfg(not(target_os = "android"))]
107 | {
108 | lib_name = "libvulkan.so.1";
109 | }
110 |
111 | let lib_name_c = CString::new(lib_name).unwrap();
112 |
113 | let lib = unsafe {
114 | dlopen(lib_name_c.as_ptr(), 1)
115 | };
116 |
117 | if lib.is_null() {
118 | return Err(Error::OpenLibraryFailed(lib_name));
119 | }
120 |
121 | let get_instance_proc_addr = unsafe {
122 | std::mem::transmute(dlsym(
123 | lib,
124 | "vkGetInstanceProcAddr\0".as_ptr().cast()
125 | ))
126 | };
127 |
128 | return Ok(LoaderFunc {
129 | lib_vulkan: lib,
130 | lib_vulkan_is_fake: false,
131 | get_instance_proc_addr
132 | });
133 | }
134 |
135 | #[cfg(windows)]
136 | {
137 | extern "system" {
138 | fn LoadLibraryA(
139 | filename: *const c_char,
140 | ) -> *mut c_void;
141 | fn GetProcAddress(
142 | handle: *mut c_void,
143 | func_name: *const c_char,
144 | ) -> *const c_void;
145 | }
146 |
147 | let lib_name = "vulkan-1.dll";
148 |
149 | let lib = unsafe {
150 | let c_lib_name = CString::new(lib_name).unwrap();
151 | LoadLibraryA(c_lib_name.as_ptr())
152 | };
153 |
154 | if lib.is_null() {
155 | return Err(Error::OpenLibraryFailed(lib_name));
156 | }
157 |
158 | let get_instance_proc_addr = unsafe {
159 | std::mem::transmute(GetProcAddress(
160 | lib,
161 | "vkGetInstanceProcAddr\0".as_ptr().cast()
162 | ))
163 | };
164 |
165 | return Ok(LoaderFunc {
166 | lib_vulkan: lib,
167 | lib_vulkan_is_fake: false,
168 | get_instance_proc_addr
169 | });
170 | }
171 |
172 | #[cfg(not(any(unix,windows)))]
173 | todo!(
174 | "library opening on platforms other than Unix and Windows is \
175 | not yet implemented"
176 | );
177 | }
178 |
179 | pub fn new() -> Result<Library, Error> {
180 | let LoaderFunc {
181 | lib_vulkan,
182 | lib_vulkan_is_fake,
183 | get_instance_proc_addr,
184 | } = Library::get_loader_func()?;
185 |
186 | Ok(Library {
187 | lib_vulkan,
188 | lib_vulkan_is_fake,
189 | vkGetInstanceProcAddr: get_instance_proc_addr,
190 | vkCreateInstance: unsafe {
191 | std::mem::transmute(get_instance_proc_addr.unwrap()(
192 | std::ptr::null_mut(),
193 | "vkCreateInstance\0".as_ptr().cast()
194 | ))
195 | },
196 | vkEnumerateInstanceExtensionProperties: unsafe {
197 | std::mem::transmute(get_instance_proc_addr.unwrap()(
198 | std::ptr::null_mut(),
199 | "vkEnumerateInstanceExtensionProperties\0".as_ptr().cast()
200 | ))
201 | }
202 | })
203 | }
204 | }
205 |
206 | impl Drop for Library {
207 | fn drop(&mut self) {
208 | #[cfg(unix)]
209 | {
210 | extern "C" {
211 | fn dlclose(lib: *const c_void) -> *const c_void;
212 | }
213 |
214 | if !self.lib_vulkan_is_fake {
215 | unsafe { dlclose(self.lib_vulkan) };
216 | }
217 | }
218 |
219 | #[cfg(windows)]
220 | {
221 | extern "system" {
222 | fn FreeLibrary(handle: *const c_void) -> c_int;
223 | }
224 |
225 | if !self.lib_vulkan_is_fake {
226 | unsafe { FreeLibrary(self.lib_vulkan) };
227 | }
228 | }
229 |
230 | #[cfg(not(any(unix,windows)))]
231 | todo!(
232 | "library closing on platforms other than Windows and Unix is not \
233 | yet implemented"
234 | );
235 | }
236 | }
237 |
238 | /// Helper function to temporarily replace the `vkGetInstanceProcAddr`
239 | /// function that will be used for the next call to [Library::new].
240 | /// The override will only be used once and subsequent calls to
241 | /// [Library::new] will revert back to trying to open the Vulkan
242 | /// library. The override is per-thread so it is safe to use in a
243 | /// multi-threaded testing environment. This function is only
244 | /// available in test build configs and it is intended to help make a
245 | /// fake Vulkan driver for unit tests.
246 | #[cfg(test)]
247 | pub fn override_get_instance_proc_addr(
248 | lib: *const c_void,
249 | proc: vk::PFN_vkGetInstanceProcAddr,
250 | ) {
251 | LOADER_FUNC_OVERRIDE.with(|f| f.replace(Some(LoaderFunc {
252 | lib_vulkan: lib,
253 | lib_vulkan_is_fake: true,
254 | get_instance_proc_addr: proc,
255 | })));
256 | }
257 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/logger.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::ffi::{c_char, c_void};
25 | use std::fmt;
26 | use std::io;
27 | use std::str;
28 |
29 | /// An object that log messages can be written to. Normally this will
30 | /// just write the messages to standard out, but an application can
31 | /// configure a C callback to receive the messages by tweaking the
32 | /// [Config](crate::config::Config). The struct implements `Write` so
33 | /// it can be used with macros like [write!](std::write).
34 | #[derive(Debug)]
35 | pub struct Logger {
36 | callback: Option<WriteCallback>,
37 | user_data: *mut c_void,
38 |
39 | // The data is collected into this buffer until we have a complete
40 | // line to send to the callback.
41 | buf: Vec<u8>,
42 |
43 | // True if the any data was added from a u8 slice so it might not
44 | // be valid UTF-8.
45 | maybe_invalid_utf8: bool,
46 | }
47 |
48 | /// A callback to use to write the data to instead of writing to
49 | /// stdout. This will be called one line at a time. Each line will be
50 | /// terminated the C null terminator but no newlines. It will always
51 | /// be valid UTF-8.
52 | pub type WriteCallback = extern "C" fn(
53 | message: *const c_char,
54 | user_data: *mut c_void,
55 | );
56 |
57 | impl Logger {
58 | /// Construct a new logger that will write to the given callback.
59 | /// If the callback is `None` then the log will go to the stdout
60 | /// instead. `user_data` will be passed to the callback. You can
61 | /// pass [`ptr::null_mut()`](std::ptr::null_mut) if there is no
62 | /// callback.
63 | pub fn new(
64 | callback: Option<WriteCallback>,
65 | user_data: *mut c_void
66 | ) -> Logger {
67 | Logger {
68 | callback,
69 | user_data,
70 | maybe_invalid_utf8: false,
71 |
72 | buf: Vec::new(),
73 | }
74 | }
75 |
76 | fn send_range(&mut self, start: usize, end: usize) {
77 | if self.maybe_invalid_utf8 {
78 | let mut pos = start;
79 |
80 | loop {
81 | match str::from_utf8(&self.buf[pos..end]) {
82 | Ok(_) => break,
83 | Err(e) => {
84 | // Replace the offending byte with a question
85 | // mark. This should result in valid UTF-8
86 | // without having to move the bytes around.
87 | self.buf[pos + e.valid_up_to()] = b'?';
88 | pos += e.valid_up_to() + 1;
89 | },
90 | }
91 | }
92 | }
93 |
94 | match self.callback {
95 | Some(callback) => {
96 | // Add the C null terminator. This method should be
97 | // called knowing that the zero will be set at `end`
98 | // so it should have ensured the buffer is large
99 | // enough.
100 | self.buf[end] = 0;
101 |
102 | callback(
103 | self.buf[start..end + 1].as_ptr().cast(),
104 | self.user_data
105 | );
106 | },
107 | None => {
108 | // SAFETY: We just ensured that the range is valid
109 | // UTF-8 above.
110 | let s = unsafe {
111 | str::from_utf8_unchecked(&self.buf[start..end])
112 | };
113 | println!("{}", s);
114 | },
115 | }
116 | }
117 |
118 | fn flush_lines(&mut self) {
119 | let mut pos = 0;
120 |
121 | while let Some(line_len) = self.buf[pos..]
122 | .into_iter()
123 | .position(|&c| c == b'\n')
124 | {
125 | self.send_range(pos, pos + line_len);
126 | pos += line_len + 1;
127 | }
128 |
129 | // Remove the lines that we successfully processed
130 | self.buf.drain(0..pos);
131 |
132 | if self.buf.is_empty() {
133 | self.maybe_invalid_utf8 = false;
134 | }
135 | }
136 | }
137 |
138 | impl io::Write for Logger {
139 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
140 | if !buf.is_empty() {
141 | self.maybe_invalid_utf8 = true;
142 | self.buf.extend_from_slice(buf);
143 | self.flush_lines();
144 | }
145 |
146 | Ok(buf.len())
147 | }
148 |
149 | fn flush(&mut self) -> io::Result<()> {
150 | if !self.buf.is_empty() {
151 | let old_len = self.buf.len();
152 |
153 | // Make sure there is enough space for the null terminator
154 | // to be added
155 | self.buf.push(0);
156 |
157 | self.send_range(0, old_len);
158 | self.buf.clear();
159 | }
160 |
161 | Ok(())
162 | }
163 | }
164 |
165 | impl fmt::Write for Logger {
166 | fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
167 | self.buf.extend_from_slice(s.as_bytes());
168 | self.flush_lines();
169 | Ok(())
170 | }
171 | }
172 |
173 | #[cfg(test)]
174 | mod test {
175 | use super::*;
176 | use std::ffi::CStr;
177 |
178 | struct TestLogger {
179 | logger: Logger,
180 | items: Vec<String>,
181 | }
182 |
183 | extern "C" fn log_item_cb(message: *const c_char, user_data: *mut c_void) {
184 | let logger = unsafe {
185 | &mut *(user_data as *mut TestLogger)
186 | };
187 |
188 | let message = unsafe { CStr::from_ptr(message.cast()) };
189 | logger.items.push(message.to_str().unwrap().to_string());
190 | }
191 |
192 | fn test_logger() -> Box<TestLogger> {
193 | // Need to box the logger so we can pass a pointer to it in
194 | // the logging callback
195 | let mut logger = Box::new(TestLogger {
196 | logger: Logger::new(None, std::ptr::null_mut()),
197 | items: Vec::new(),
198 | });
199 |
200 | logger.logger = Logger::new(
201 | Some(log_item_cb),
202 | logger.as_mut() as *mut TestLogger as *mut c_void,
203 | );
204 |
205 | logger
206 | }
207 |
208 | #[test]
209 | fn multiple_lines() {
210 | let mut logger = test_logger();
211 |
212 | use std::fmt::Write;
213 |
214 | writeln!(
215 | &mut logger.logger,
216 | "This is a line\n\
217 | This is another line.\n\
218 | This is followed by a number: {}",
219 | 42,
220 | ).unwrap();
221 |
222 | assert_eq!(logger.items.len(), 3);
223 | assert_eq!(logger.items[0], "This is a line");
224 | assert_eq!(logger.items[1], "This is another line.");
225 | assert_eq!(logger.items[2], "This is followed by a number: 42");
226 | }
227 |
228 | #[test]
229 | fn split_line() {
230 | let mut logger = test_logger();
231 |
232 | use std::fmt::Write;
233 |
234 | write!(&mut logger.logger, "Part of first line ").unwrap();
235 | assert_eq!(logger.items.len(), 0);
236 | write!(
237 | &mut logger.logger,
238 | "next part of first line\nSecond line\n"
239 | ).unwrap();
240 | assert_eq!(logger.items.len(), 2);
241 | assert_eq!(
242 | logger.items[0],
243 | "Part of first line next part of first line",
244 | );
245 | assert_eq!(logger.items[1], "Second line");
246 | }
247 |
248 | #[test]
249 | fn bad_utf8() {
250 | let mut logger = test_logger();
251 |
252 | use std::io::Write;
253 |
254 | logger.logger.write(
255 | b"\xc4u ne mankas bajtoj \xc4\x89i tie \xe2\n"
256 | ).unwrap();
257 | assert_eq!(logger.items.len(), 1);
258 | assert_eq!(logger.items[0], "?u ne mankas bajtoj ĉi tie ?");
259 | }
260 |
261 | #[test]
262 | fn flush() {
263 | let mut logger = test_logger();
264 |
265 | use std::fmt::Write;
266 |
267 | write!(&mut logger.logger, "One line\nUnterminated line").unwrap();
268 | assert_eq!(logger.items.len(), 1);
269 | assert_eq!(logger.items[0], "One line");
270 |
271 | io::Write::flush(&mut logger.logger).unwrap();
272 |
273 | assert_eq!(logger.items.len(), 2);
274 | assert_eq!(logger.items[1], "Unterminated line");
275 |
276 | assert!(logger.logger.buf.is_empty());
277 |
278 | io::Write::flush(&mut logger.logger).unwrap();
279 |
280 | assert_eq!(logger.items.len(), 2);
281 | }
282 | }
283 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/parse_num.rs:
--------------------------------------------------------------------------------
```rust
1 | // Copyright 2023 Neil Roberts
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a
4 | // copy of this software and associated documentation files (the "Software"),
5 | // to deal in the Software without restriction, including without limitation
6 | // on the rights to use, copy, modify, merge, publish, distribute, sub
7 | // license, and/or sell copies of the Software, and to permit persons to whom
8 | // the Software is furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice (including the next
11 | // paragraph) shall be included in all copies or substantial portions of the
12 | // Software.
13 | //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 | // VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 | // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 | use std::num::ParseIntError;
23 | use std::fmt;
24 |
25 | #[derive(Debug, PartialEq)]
26 | pub enum ParseError {
27 | // The negative sign was used in an unsigned number type
28 | NegativeError,
29 | // A number that would be valid in an unsigned type overflows the
30 | // signed type
31 | SignedOverflow,
32 | // Any other error returned by the from_str_radix function
33 | Other(ParseIntError),
34 | }
35 |
36 | impl fmt::Display for ParseError {
37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 | match self {
39 | ParseError::NegativeError => write!(f, "Number can’t be negated"),
40 | ParseError::SignedOverflow => {
41 | write!(f, "Number out of range for type")
42 | },
43 | ParseError::Other(e) => e.fmt(f),
44 | }
45 | }
46 | }
47 |
48 | impl From<ParseIntError> for ParseError {
49 | fn from(e: ParseIntError) -> ParseError {
50 | ParseError::Other(e)
51 | }
52 | }
53 |
54 | struct NumAnalysis<'a> {
55 | negative: bool,
56 | radix: u32,
57 | num_part: &'a str,
58 | tail: &'a str,
59 | }
60 |
61 | fn is_octal_prefix(prefix: &str) -> bool {
62 | prefix.starts_with("0")
63 | && prefix.len() > 1
64 | && prefix.as_bytes()[1].is_ascii_digit()
65 | }
66 |
67 | fn analyse_num(mut s: &str) -> NumAnalysis {
68 | // skip only ASCII spaces and tabs
69 | while !s.is_empty() &&
70 | (s.as_bytes()[0] == b' ' || s.as_bytes()[0] == b'\t')
71 | {
72 | s = &s[1..];
73 | }
74 |
75 | // Optional sign
76 | let (prefix_start, negative) = match s.chars().next() {
77 | Some('-') => (1, true),
78 | Some('+') => (1, false),
79 | _ => (0, false),
80 | };
81 |
82 | let prefix = &s[prefix_start..];
83 |
84 | let (radix, num_start) = if prefix.starts_with("0x") {
85 | (16, 2)
86 | } else if is_octal_prefix(prefix) {
87 | (8, 1)
88 | } else {
89 | (10, 0)
90 | };
91 |
92 | let num_start = &prefix[num_start..];
93 |
94 | let split_point = num_start
95 | .chars()
96 | .take_while(|c| c.is_ascii_hexdigit())
97 | .count();
98 |
99 | NumAnalysis {
100 | negative,
101 | radix,
102 | num_part: &num_start[0..split_point],
103 | tail: &num_start[split_point..],
104 | }
105 | }
106 |
107 | // Macro to create a function to parse an unsigned int type. These are
108 | // needed because there doesn’t seem to be an equivalent to strtoul in
109 | // rust where the radix can be zero. The regular parse function also
110 | // doesn’t return a tail pointer.
111 | macro_rules! parse_unsigned {
112 | ($func:ident, $t:ident) => {
113 | pub fn $func(s: &str) -> Result<($t, &str), ParseError> {
114 | let analysis = analyse_num(s);
115 |
116 | let num = $t::from_str_radix(analysis.num_part, analysis.radix)?;
117 |
118 | if analysis.negative {
119 | Err(ParseError::NegativeError)
120 | } else {
121 | Ok((num, analysis.tail))
122 | }
123 | }
124 | }
125 | }
126 |
127 | // Macro to create a function to parse a signed int type. These are
128 | // needed because there doesn’t seem to be an equivalent to strtol in
129 | // rust where the radix can be zero. The regular parse function also
130 | // doesn’t return a tail pointer.
131 | macro_rules! parse_signed {
132 | ($func:ident, $st:ident, $ut:ident) => {
133 | pub fn $func(s: &str) -> Result<($st, &str), ParseError> {
134 | let analysis = analyse_num(s);
135 |
136 | let num = $ut::from_str_radix(analysis.num_part, analysis.radix)?;
137 |
138 | if analysis.negative {
139 | if num > $st::MAX as $ut + 1 {
140 | Err(ParseError::SignedOverflow)
141 | } else {
142 | // We have an unsigned value that we need to
143 | // negate. We can’t just cast it to signed and
144 | // then negate it because the MIN value is not
145 | // representable as a positive value in the signed
146 | // type. Instead we do the trick of !x+1 to
147 | // negate while staying in the unsigned type.
148 | Ok(((!num).wrapping_add(1) as $st, analysis.tail))
149 | }
150 | } else {
151 | if num > $st::MAX as $ut {
152 | Err(ParseError::SignedOverflow)
153 | } else {
154 | Ok((num as $st, analysis.tail))
155 | }
156 | }
157 | }
158 | }
159 | }
160 |
161 | parse_unsigned!(parse_u64, u64);
162 | parse_unsigned!(parse_u32, u32);
163 | parse_unsigned!(parse_u16, u16);
164 | parse_unsigned!(parse_u8, u8);
165 | parse_signed!(parse_i64, i64, u64);
166 | parse_signed!(parse_i32, i32, u32);
167 | parse_signed!(parse_i16, i16, u16);
168 | parse_signed!(parse_i8, i8, u8);
169 |
170 | #[cfg(test)]
171 | mod test {
172 | use super::*;
173 |
174 | #[test]
175 | fn test_unsigned() {
176 | assert_eq!(
177 | parse_u64(&u64::MAX.to_string()).unwrap(),
178 | (u64::MAX, ""),
179 | );
180 | assert_eq!(
181 | parse_u32(&u32::MAX.to_string()).unwrap(),
182 | (u32::MAX, ""),
183 | );
184 | assert_eq!(
185 | parse_u16(&u16::MAX.to_string()).unwrap(),
186 | (u16::MAX, ""),
187 | );
188 | assert_eq!(
189 | parse_u8(&u8::MAX.to_string()).unwrap(),
190 | (u8::MAX, ""),
191 | );
192 |
193 | assert!(matches!(parse_u8("-1"), Err(ParseError::NegativeError)));
194 | assert!(matches!(parse_u8("-0"), Err(ParseError::NegativeError)));
195 |
196 | assert!(matches!(
197 | parse_u8("256"),
198 | Err(ParseError::Other(ParseIntError { .. })),
199 | ));
200 |
201 | assert_eq!(
202 | parse_i8(" 0 12"),
203 | Ok((0, " 12")),
204 | );
205 |
206 | assert_eq!(
207 | parse_u8(" 0x42 after"),
208 | Ok((66, " after")),
209 | );
210 | assert_eq!(
211 | parse_u32(" 0xaBCdef01 after"),
212 | Ok((0xabcdef01, " after")),
213 | );
214 | assert_eq!(
215 | parse_u32(" 0xffgoat"),
216 | Ok((255, "goat")),
217 | );
218 | assert_eq!(
219 | parse_u32(" \t 0100 after"),
220 | Ok((64, " after")),
221 | );
222 | }
223 |
224 | #[test]
225 | fn test_signed() {
226 | assert_eq!(
227 | parse_i64(&i64::MAX.to_string()).unwrap(),
228 | (i64::MAX, ""),
229 | );
230 | assert_eq!(
231 | parse_i32(&i32::MAX.to_string()).unwrap(),
232 | (i32::MAX, ""),
233 | );
234 | assert_eq!(
235 | parse_i16(&i16::MAX.to_string()).unwrap(),
236 | (i16::MAX, ""),
237 | );
238 | assert_eq!(
239 | parse_i8(&i8::MAX.to_string()).unwrap(),
240 | (i8::MAX, ""),
241 | );
242 | assert_eq!(
243 | parse_i64(&i64::MIN.to_string()).unwrap(),
244 | (i64::MIN, ""),
245 | );
246 | assert_eq!(
247 | parse_i32(&i32::MIN.to_string()).unwrap(),
248 | (i32::MIN, ""),
249 | );
250 | assert_eq!(
251 | parse_i16(&i16::MIN.to_string()).unwrap(),
252 | (i16::MIN, ""),
253 | );
254 | assert_eq!(
255 | parse_i8(&i8::MIN.to_string()).unwrap(),
256 | (i8::MIN, ""),
257 | );
258 |
259 | assert_eq!(
260 | parse_i8("-0"),
261 | Ok((0, "")),
262 | );
263 |
264 | assert_eq!(
265 | parse_i8(" -0 0"),
266 | Ok((0, " 0")),
267 | );
268 |
269 | assert!(matches!(
270 | parse_i8("128"),
271 | Err(ParseError::SignedOverflow),
272 | ));
273 | assert!(matches!(
274 | parse_i8("-129"),
275 | Err(ParseError::SignedOverflow),
276 | ));
277 |
278 | assert_eq!(
279 | parse_i8(" 0x42 after"),
280 | Ok((66, " after")),
281 | );
282 | assert_eq!(
283 | parse_i32(" \t 0100 after"),
284 | Ok((64, " after")),
285 | );
286 | assert_eq!(
287 | parse_i8(" -0x42 after"),
288 | Ok((-66, " after")),
289 | );
290 | assert_eq!(
291 | parse_i32(" \t -0100 after"),
292 | Ok((-64, " after")),
293 | );
294 | }
295 | }
296 |
```
--------------------------------------------------------------------------------
/.github/workflows/build-push-image.yml:
--------------------------------------------------------------------------------
```yaml
1 | name: Build and Push Image
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | workflow_dispatch:
7 |
8 | jobs:
9 | prepare:
10 | name: Prepare Build Environment
11 | runs-on: ubuntu-latest
12 | outputs:
13 | repo_name: ${{ steps.meta.outputs.repo_name }}
14 | short_sha: ${{ steps.meta.outputs.short_sha }}
15 | steps:
16 | - name: Extract metadata
17 | id: meta
18 | run: |
19 | echo "repo_name=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
20 | echo "short_sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
21 |
22 | build-amd64:
23 | name: Build for amd64
24 | needs: prepare
25 | runs-on: ubuntu-24.04
26 | permissions:
27 | contents: read
28 | packages: write
29 | steps:
30 | - name: Checkout repository
31 | uses: actions/checkout@v4
32 |
33 | - name: Set up Docker Buildx
34 | uses: docker/setup-buildx-action@v3
35 |
36 | - name: Login to GitHub Container Registry
37 | if: github.event_name != 'pull_request'
38 | uses: docker/login-action@v3
39 | with:
40 | registry: ghcr.io
41 | username: ${{ github.actor }}
42 | password: ${{ secrets.GITHUB_TOKEN }}
43 |
44 | - name: Build and push amd64 image
45 | uses: docker/build-push-action@v5
46 | with:
47 | context: .
48 | push: ${{ github.event_name != 'pull_request' }}
49 | platforms: linux/amd64
50 | tags: |
51 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-latest
52 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-${{ needs.prepare.outputs.short_sha }}
53 | labels: |
54 | org.opencontainers.image.source=https://github.com/${{ github.repository }}
55 | org.opencontainers.image.revision=${{ github.sha }}
56 | org.opencontainers.image.description=Docker image for amd64
57 | cache-from: type=gha
58 | cache-to: type=gha,mode=max
59 |
60 | build-arm64:
61 | name: Build for arm64
62 | needs: prepare
63 | runs-on: ubuntu-24.04-arm
64 | permissions:
65 | contents: read
66 | packages: write
67 | steps:
68 | - name: Checkout repository
69 | uses: actions/checkout@v4
70 |
71 | - name: Set up Docker Buildx
72 | uses: docker/setup-buildx-action@v3
73 |
74 | - name: Login to GitHub Container Registry
75 | if: github.event_name != 'pull_request'
76 | uses: docker/login-action@v3
77 | with:
78 | registry: ghcr.io
79 | username: ${{ github.actor }}
80 | password: ${{ secrets.GITHUB_TOKEN }}
81 |
82 | - name: Build and push arm64 image
83 | uses: docker/build-push-action@v5
84 | with:
85 | context: .
86 | push: ${{ github.event_name != 'pull_request' }}
87 | platforms: linux/arm64
88 | tags: |
89 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-latest
90 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-${{ needs.prepare.outputs.short_sha }}
91 | labels: |
92 | org.opencontainers.image.source=https://github.com/${{ github.repository }}
93 | org.opencontainers.image.revision=${{ github.sha }}
94 | org.opencontainers.image.description=Docker image for arm64
95 | cache-from: type=gha
96 | cache-to: type=gha,mode=max
97 |
98 | build-riscv64:
99 | if: false # Needs hosted runner
100 | name: Build for riscv64
101 | needs: prepare
102 | runs-on: ubuntu-latest
103 | permissions:
104 | contents: read
105 | packages: write
106 | steps:
107 | - name: Checkout repository
108 | uses: actions/checkout@v4
109 |
110 | - name: Set up QEMU
111 | uses: docker/setup-qemu-action@v3
112 |
113 | - name: Set up Docker Buildx
114 | uses: docker/setup-buildx-action@v3
115 |
116 | - name: Login to GitHub Container Registry
117 | if: github.event_name != 'pull_request'
118 | uses: docker/login-action@v3
119 | with:
120 | registry: ghcr.io
121 | username: ${{ github.actor }}
122 | password: ${{ secrets.GITHUB_TOKEN }}
123 |
124 | - name: Build and push riscv64 image
125 | id: build_riscv64
126 | continue-on-error: true
127 | uses: docker/build-push-action@v5
128 | with:
129 | context: .
130 | push: ${{ github.event_name != 'pull_request' }}
131 | platforms: linux/riscv64
132 | tags: |
133 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-latest
134 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-${{ needs.prepare.outputs.short_sha }}
135 | labels: |
136 | org.opencontainers.image.source=https://github.com/${{ github.repository }}
137 | org.opencontainers.image.revision=${{ github.sha }}
138 | org.opencontainers.image.description=Docker image for riscv64
139 | cache-from: type=gha
140 | cache-to: type=gha,mode=max
141 |
142 | - name: Set build status
143 | id: status
144 | run: echo "success=${{ steps.build_riscv64.outcome == 'success' }}" >> $GITHUB_OUTPUT
145 |
146 | outputs:
147 | success: ${{ steps.status.outputs.success }}
148 |
149 | build-ppc64le:
150 | if: false # Needs hosted runner
151 | name: Build for ppc64le
152 | needs: prepare
153 | runs-on: ubuntu-latest
154 | permissions:
155 | contents: read
156 | packages: write
157 | steps:
158 | - name: Checkout repository
159 | uses: actions/checkout@v4
160 |
161 | - name: Set up QEMU
162 | uses: docker/setup-qemu-action@v3
163 |
164 | - name: Set up Docker Buildx
165 | uses: docker/setup-buildx-action@v3
166 |
167 | - name: Login to GitHub Container Registry
168 | if: github.event_name != 'pull_request'
169 | uses: docker/login-action@v3
170 | with:
171 | registry: ghcr.io
172 | username: ${{ github.actor }}
173 | password: ${{ secrets.GITHUB_TOKEN }}
174 |
175 | - name: Build and push ppc64le image
176 | id: build_ppc64le
177 | continue-on-error: true
178 | uses: docker/build-push-action@v5
179 | with:
180 | context: .
181 | push: ${{ github.event_name != 'pull_request' }}
182 | platforms: linux/ppc64le
183 | tags: |
184 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-latest
185 | ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-${{ needs.prepare.outputs.short_sha }}
186 | labels: |
187 | org.opencontainers.image.source=https://github.com/${{ github.repository }}
188 | org.opencontainers.image.revision=${{ github.sha }}
189 | org.opencontainers.image.description=Docker image for ppc64le
190 | cache-from: type=gha
191 | cache-to: type=gha,mode=max
192 |
193 | - name: Set build status
194 | id: status
195 | run: echo "success=${{ steps.build_ppc64le.outcome == 'success' }}" >> $GITHUB_OUTPUT
196 |
197 | outputs:
198 | success: ${{ steps.status.outputs.success }}
199 |
200 | create-manifest:
201 | name: Create Multi-Arch Manifest
202 | needs: [prepare, build-amd64, build-arm64] # [build-riscv64, build-ppc64le]
203 | runs-on: ubuntu-latest
204 | permissions:
205 | contents: read
206 | packages: write
207 | if: github.event_name != 'pull_request'
208 | steps:
209 | - name: Login to GitHub Container Registry
210 | uses: docker/login-action@v3
211 | with:
212 | registry: ghcr.io
213 | username: ${{ github.actor }}
214 | password: ${{ secrets.GITHUB_TOKEN }}
215 |
216 | - name: Set up Docker Buildx
217 | uses: docker/setup-buildx-action@v3
218 |
219 | - name: Create and push multi-arch manifests
220 | run: |
221 |
222 | LATEST_SOURCES="ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-latest"
223 | SHA_SOURCES="ghcr.io/${{ needs.prepare.outputs.repo_name }}:amd64-${{ needs.prepare.outputs.short_sha }}"
224 |
225 |
226 | # if [ "${{ needs.build-arm64.outputs.success }}" == "true" ]; then
227 | # LATEST_SOURCES="${LATEST_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-latest"
228 | # SHA_SOURCES="${SHA_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:arm64-${{ needs.prepare.outputs.short_sha }}"
229 | # fi
230 |
231 |
232 | # if [ "${{ needs.build-riscv64.outputs.success }}" == "true" ]; then
233 | # LATEST_SOURCES="${LATEST_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-latest"
234 | # SHA_SOURCES="${SHA_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:riscv64-${{ needs.prepare.outputs.short_sha }}"
235 | # fi
236 |
237 | # if [ "${{ needs.build-ppc64le.outputs.success }}" == "true" ]; then
238 | # LATEST_SOURCES="${LATEST_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-latest"
239 | # SHA_SOURCES="${SHA_SOURCES} ghcr.io/${{ needs.prepare.outputs.repo_name }}:ppc64le-${{ needs.prepare.outputs.short_sha }}"
240 | # fi
241 |
242 |
243 | echo "Creating latest manifest from: ${LATEST_SOURCES}"
244 | docker buildx imagetools create --tag ghcr.io/${{ needs.prepare.outputs.repo_name }}:latest ${LATEST_SOURCES}
245 |
246 |
247 | echo "Creating SHA manifest from: ${SHA_SOURCES}"
248 | docker buildx imagetools create --tag ghcr.io/${{ needs.prepare.outputs.repo_name }}:${{ needs.prepare.outputs.short_sha }} ${SHA_SOURCES}
249 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/allocate_store.rs:
--------------------------------------------------------------------------------
```rust
1 | // vkrunner
2 | //
3 | // Copyright (C) 2016, 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 | //! Helper functions for allocating Vulkan device memory for a buffer
25 | //! or an image.
26 |
27 | use crate::context::Context;
28 | use crate::vk;
29 | use std::ptr;
30 |
31 | fn find_memory_type(
32 | context: &Context,
33 | mut usable_memory_types: u32,
34 | memory_type_flags: vk::VkMemoryPropertyFlags,
35 | ) -> Result<u32, String> {
36 | let memory_properties = context.memory_properties();
37 |
38 | while usable_memory_types != 0 {
39 | let memory_type = usable_memory_types.trailing_zeros();
40 |
41 | if memory_properties.memoryTypes[memory_type as usize].propertyFlags
42 | & memory_type_flags
43 | == memory_type_flags
44 | {
45 | return Ok(memory_type);
46 | }
47 |
48 | usable_memory_types &= !(1 << memory_type);
49 | }
50 |
51 | Err("Couldn’t find suitable memory type to allocate buffer".to_string())
52 | }
53 |
54 | fn allocate_memory(
55 | context: &Context,
56 | reqs: &vk::VkMemoryRequirements,
57 | memory_type_flags: vk::VkMemoryPropertyFlags,
58 | ) -> Result<(vk::VkDeviceMemory, u32), String> {
59 | let memory_type_index = find_memory_type(
60 | context,
61 | reqs.memoryTypeBits,
62 | memory_type_flags,
63 | )?;
64 |
65 | let mut memory = vk::null_handle();
66 |
67 | let allocate_info = vk::VkMemoryAllocateInfo {
68 | sType: vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
69 | pNext: ptr::null(),
70 | allocationSize: reqs.size,
71 | memoryTypeIndex: memory_type_index,
72 | };
73 | let res = unsafe {
74 | context.device().vkAllocateMemory.unwrap()(
75 | context.vk_device(),
76 | ptr::addr_of!(allocate_info),
77 | ptr::null(), // allocator
78 | ptr::addr_of_mut!(memory),
79 | )
80 | };
81 | if res == vk::VK_SUCCESS {
82 | Ok((memory, memory_type_index))
83 | } else {
84 | Err("vkAllocateMemory failed".to_string())
85 | }
86 | }
87 |
88 | /// Allocate Vulkan device memory for the given buffer. It will pick
89 | /// the right memory type by querying the device for the memory
90 | /// requirements of the buffer. You can also limit the memory types
91 | /// further by specifying extra flags in `memory_type_flags`. A handle
92 | /// to the newly allocate device memory will be returned along with an
93 | /// index representing the chosen memory type.
94 | ///
95 | /// If the allocation fails a `String` will be returned describing the
96 | /// error.
97 | pub fn allocate_buffer(
98 | context: &Context,
99 | memory_type_flags: vk::VkMemoryPropertyFlags,
100 | buffer: vk::VkBuffer,
101 | ) -> Result<(vk::VkDeviceMemory, u32), String> {
102 | let vkdev = context.device();
103 |
104 | let mut reqs = vk::VkMemoryRequirements::default();
105 |
106 | unsafe {
107 | vkdev.vkGetBufferMemoryRequirements.unwrap()(
108 | context.vk_device(),
109 | buffer,
110 | ptr::addr_of_mut!(reqs),
111 | );
112 | }
113 |
114 | let (memory, memory_type_index) =
115 | allocate_memory(context, &reqs, memory_type_flags)?;
116 |
117 | unsafe {
118 | vkdev.vkBindBufferMemory.unwrap()(
119 | context.vk_device(),
120 | buffer,
121 | memory,
122 | 0, // memoryOffset
123 | );
124 | }
125 |
126 | Ok((memory, memory_type_index))
127 | }
128 |
129 | /// Allocate Vulkan device memory for the given image. It will pick
130 | /// the right memory type by querying the device for the memory
131 | /// requirements of the image. You can also limit the memory types
132 | /// further by specifying extra flags in `memory_type_flags`. A handle
133 | /// to the newly allocate device memory will be returned along with an
134 | /// index representing the chosen memory type.
135 | ///
136 | /// If the allocation fails a `String` will be returned describing the
137 | /// error.
138 | pub fn allocate_image(
139 | context: &Context,
140 | memory_type_flags: vk::VkMemoryPropertyFlags,
141 | image: vk::VkImage,
142 | ) -> Result<(vk::VkDeviceMemory, u32), String> {
143 | let vkdev = context.device();
144 |
145 | let mut reqs = vk::VkMemoryRequirements::default();
146 |
147 | unsafe {
148 | vkdev.vkGetImageMemoryRequirements.unwrap()(
149 | context.vk_device(),
150 | image,
151 | ptr::addr_of_mut!(reqs),
152 | );
153 | }
154 |
155 | let (memory, memory_type_index) =
156 | allocate_memory(context, &reqs, memory_type_flags)?;
157 |
158 | unsafe {
159 | vkdev.vkBindImageMemory.unwrap()(
160 | context.vk_device(),
161 | image,
162 | memory,
163 | 0, // memoryOffset
164 | );
165 | }
166 |
167 | Ok((memory, memory_type_index))
168 | }
169 |
170 | #[cfg(test)]
171 | mod test {
172 | use super::*;
173 | use crate::fake_vulkan::{FakeVulkan, HandleType};
174 | use crate::requirements::Requirements;
175 |
176 | fn call_with_temp_buffer(
177 | fake_vulkan: &mut FakeVulkan,
178 | context: &Context,
179 | memory_type_flags: vk::VkMemoryPropertyFlags,
180 | ) -> Result<(vk::VkDeviceMemory, u32), String> {
181 | let buffer = fake_vulkan.add_handle(
182 | HandleType::Buffer {
183 | create_info: Default::default(),
184 | memory: None,
185 | }
186 | );
187 |
188 | let res = allocate_buffer(context, memory_type_flags, buffer);
189 |
190 | fake_vulkan.get_handle_mut(buffer).freed = true;
191 |
192 | res
193 | }
194 |
195 | fn call_with_temp_image(
196 | fake_vulkan: &mut FakeVulkan,
197 | context: &Context,
198 | memory_type_flags: vk::VkMemoryPropertyFlags,
199 | ) -> Result<(vk::VkDeviceMemory, u32), String> {
200 | let image = fake_vulkan.add_handle(HandleType::Image);
201 |
202 | let res = allocate_image(context, memory_type_flags, image);
203 |
204 | fake_vulkan.get_handle_mut(image).freed = true;
205 |
206 | res
207 | }
208 |
209 | fn do_allocate_buffer(
210 | memory_property_flags: &[u32],
211 | memory_type_bits: u32,
212 | memory_type_flags: vk::VkMemoryPropertyFlags,
213 | ) -> Result<(vk::VkDeviceMemory, u32, Context, Box<FakeVulkan>), String> {
214 | let mut fake_vulkan = FakeVulkan::new();
215 | fake_vulkan.physical_devices.push(Default::default());
216 |
217 | let memory_properties =
218 | &mut fake_vulkan.physical_devices[0].memory_properties;
219 |
220 | for (i, &flags) in memory_property_flags.iter().enumerate() {
221 | memory_properties.memoryTypes[i].propertyFlags = flags;
222 | }
223 | memory_properties.memoryTypeCount = memory_property_flags.len() as u32;
224 |
225 | fake_vulkan.memory_requirements.memoryTypeBits = memory_type_bits;
226 |
227 | fake_vulkan.set_override();
228 | let context = Context::new(&mut Requirements::new(), None).unwrap();
229 | call_with_temp_buffer(
230 | &mut fake_vulkan,
231 | &context,
232 | memory_type_flags,
233 | ).map(|(memory, memory_type)| (
234 | memory,
235 | memory_type,
236 | context,
237 | fake_vulkan,
238 | ))
239 | }
240 |
241 | #[test]
242 | fn find_memory() {
243 | let (device_memory, memory_type, context, fake_vulkan) =
244 | do_allocate_buffer(
245 | // Made-up set of memory properties
246 | &[
247 | vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
248 | | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
249 | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
250 | | vk::VK_MEMORY_PROPERTY_PROTECTED_BIT,
251 | vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
252 | | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
253 | | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,
254 | vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
255 | | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
256 | | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
257 | ],
258 | // Pretend that the buffer can use types 0, 1 or 3
259 | 0b1011,
260 | // Pretend we need host visible and lazily allocated. This
261 | // means either of the last two
262 | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
263 | | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,
264 | ).unwrap();
265 |
266 | // Only 2 or 3 have the properties we need, but only 3 is
267 | // allowed for the buffer requirements.
268 | assert_eq!(memory_type, 3);
269 |
270 | unsafe {
271 | context.device().vkFreeMemory.unwrap()(
272 | context.vk_device(),
273 | device_memory,
274 | ptr::null(), // allocator
275 | );
276 | }
277 |
278 | drop(context);
279 | drop(fake_vulkan);
280 |
281 | // Try with an impossible combination
282 | let err = do_allocate_buffer(
283 | &[
284 | vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
285 | | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
286 | ],
287 | 0b1,
288 | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
289 | | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,
290 | ).unwrap_err();
291 |
292 | assert_eq!(
293 | err,
294 | "Couldn’t find suitable memory type to allocate buffer"
295 | );
296 | }
297 |
298 | fn make_error_context() -> (Box<FakeVulkan>, Context) {
299 | let mut fake_vulkan = FakeVulkan::new();
300 | fake_vulkan.physical_devices.push(Default::default());
301 |
302 | fake_vulkan.physical_devices[0].memory_properties.memoryTypeCount = 1;
303 | fake_vulkan.memory_requirements.memoryTypeBits = 1;
304 |
305 | fake_vulkan.queue_result(
306 | "vkAllocateMemory".to_string(),
307 | vk::VK_ERROR_UNKNOWN
308 | );
309 |
310 | fake_vulkan.set_override();
311 | let context = Context::new(&mut Requirements::new(), None).unwrap();
312 |
313 | (fake_vulkan, context)
314 | }
315 |
316 | #[test]
317 | fn buffer_error() {
318 | let (mut fake_vulkan, context) = make_error_context();
319 |
320 | let err = call_with_temp_buffer(
321 | &mut fake_vulkan,
322 | &context,
323 | 0, // memory_type_flags
324 | ).unwrap_err();
325 |
326 | assert_eq!(err, "vkAllocateMemory failed");
327 | }
328 |
329 | #[test]
330 | fn image_error() {
331 | let (mut fake_vulkan, context) = make_error_context();
332 |
333 | let err = call_with_temp_image(
334 | &mut fake_vulkan,
335 | &context,
336 | 0, // memory_type_flags
337 | ).unwrap_err();
338 |
339 | assert_eq!(err, "vkAllocateMemory failed");
340 | }
341 |
342 | #[test]
343 | fn image() {
344 | let mut fake_vulkan = FakeVulkan::new();
345 | fake_vulkan.physical_devices.push(Default::default());
346 |
347 | fake_vulkan.physical_devices[0].memory_properties.memoryTypeCount = 1;
348 | fake_vulkan.memory_requirements.memoryTypeBits = 1;
349 |
350 | fake_vulkan.set_override();
351 | let context = Context::new(&mut Requirements::new(), None).unwrap();
352 |
353 | let (device_memory, memory_type) = call_with_temp_image(
354 | &mut fake_vulkan,
355 | &context,
356 | 0, // memory_type_flags
357 | ).unwrap();
358 |
359 | assert!(device_memory != vk::null_handle());
360 | assert_eq!(memory_type, 0);
361 |
362 | unsafe {
363 | context.device().vkFreeMemory.unwrap()(
364 | context.vk_device(),
365 | device_memory,
366 | ptr::null(), // allocator
367 | );
368 | }
369 | }
370 | }
371 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/pipeline_key_data.rs:
--------------------------------------------------------------------------------
```rust
1 | // Automatically generated by make-pipeline-key-data.py
2 |
3 | const N_BOOL_PROPERTIES: usize = 10;
4 | const N_INT_PROPERTIES: usize = 28;
5 | const N_FLOAT_PROPERTIES: usize = 6;
6 |
7 | const TOPOLOGY_PROP_NUM: usize = 0;
8 | const PATCH_CONTROL_POINTS_PROP_NUM: usize = 1;
9 |
10 | static PROPERTIES: [Property; 44] = [
11 | Property {
12 | prop_type: PropertyType::Int,
13 | num: 11,
14 | name: "alphaBlendOp",
15 | },
16 | Property {
17 | prop_type: PropertyType::Int,
18 | num: 25,
19 | name: "back.compareMask",
20 | },
21 | Property {
22 | prop_type: PropertyType::Int,
23 | num: 24,
24 | name: "back.compareOp",
25 | },
26 | Property {
27 | prop_type: PropertyType::Int,
28 | num: 23,
29 | name: "back.depthFailOp",
30 | },
31 | Property {
32 | prop_type: PropertyType::Int,
33 | num: 21,
34 | name: "back.failOp",
35 | },
36 | Property {
37 | prop_type: PropertyType::Int,
38 | num: 22,
39 | name: "back.passOp",
40 | },
41 | Property {
42 | prop_type: PropertyType::Int,
43 | num: 27,
44 | name: "back.reference",
45 | },
46 | Property {
47 | prop_type: PropertyType::Int,
48 | num: 26,
49 | name: "back.writeMask",
50 | },
51 | Property {
52 | prop_type: PropertyType::Bool,
53 | num: 5,
54 | name: "blendEnable",
55 | },
56 | Property {
57 | prop_type: PropertyType::Int,
58 | num: 8,
59 | name: "colorBlendOp",
60 | },
61 | Property {
62 | prop_type: PropertyType::Int,
63 | num: 12,
64 | name: "colorWriteMask",
65 | },
66 | Property {
67 | prop_type: PropertyType::Int,
68 | num: 3,
69 | name: "cullMode",
70 | },
71 | Property {
72 | prop_type: PropertyType::Float,
73 | num: 1,
74 | name: "depthBiasClamp",
75 | },
76 | Property {
77 | prop_type: PropertyType::Float,
78 | num: 0,
79 | name: "depthBiasConstantFactor",
80 | },
81 | Property {
82 | prop_type: PropertyType::Bool,
83 | num: 3,
84 | name: "depthBiasEnable",
85 | },
86 | Property {
87 | prop_type: PropertyType::Float,
88 | num: 2,
89 | name: "depthBiasSlopeFactor",
90 | },
91 | Property {
92 | prop_type: PropertyType::Bool,
93 | num: 8,
94 | name: "depthBoundsTestEnable",
95 | },
96 | Property {
97 | prop_type: PropertyType::Bool,
98 | num: 1,
99 | name: "depthClampEnable",
100 | },
101 | Property {
102 | prop_type: PropertyType::Int,
103 | num: 13,
104 | name: "depthCompareOp",
105 | },
106 | Property {
107 | prop_type: PropertyType::Bool,
108 | num: 6,
109 | name: "depthTestEnable",
110 | },
111 | Property {
112 | prop_type: PropertyType::Bool,
113 | num: 7,
114 | name: "depthWriteEnable",
115 | },
116 | Property {
117 | prop_type: PropertyType::Int,
118 | num: 10,
119 | name: "dstAlphaBlendFactor",
120 | },
121 | Property {
122 | prop_type: PropertyType::Int,
123 | num: 7,
124 | name: "dstColorBlendFactor",
125 | },
126 | Property {
127 | prop_type: PropertyType::Int,
128 | num: 18,
129 | name: "front.compareMask",
130 | },
131 | Property {
132 | prop_type: PropertyType::Int,
133 | num: 17,
134 | name: "front.compareOp",
135 | },
136 | Property {
137 | prop_type: PropertyType::Int,
138 | num: 16,
139 | name: "front.depthFailOp",
140 | },
141 | Property {
142 | prop_type: PropertyType::Int,
143 | num: 14,
144 | name: "front.failOp",
145 | },
146 | Property {
147 | prop_type: PropertyType::Int,
148 | num: 15,
149 | name: "front.passOp",
150 | },
151 | Property {
152 | prop_type: PropertyType::Int,
153 | num: 20,
154 | name: "front.reference",
155 | },
156 | Property {
157 | prop_type: PropertyType::Int,
158 | num: 19,
159 | name: "front.writeMask",
160 | },
161 | Property {
162 | prop_type: PropertyType::Int,
163 | num: 4,
164 | name: "frontFace",
165 | },
166 | Property {
167 | prop_type: PropertyType::Float,
168 | num: 3,
169 | name: "lineWidth",
170 | },
171 | Property {
172 | prop_type: PropertyType::Int,
173 | num: 5,
174 | name: "logicOp",
175 | },
176 | Property {
177 | prop_type: PropertyType::Bool,
178 | num: 4,
179 | name: "logicOpEnable",
180 | },
181 | Property {
182 | prop_type: PropertyType::Float,
183 | num: 5,
184 | name: "maxDepthBounds",
185 | },
186 | Property {
187 | prop_type: PropertyType::Float,
188 | num: 4,
189 | name: "minDepthBounds",
190 | },
191 | Property {
192 | prop_type: PropertyType::Int,
193 | num: 1,
194 | name: "patchControlPoints",
195 | },
196 | Property {
197 | prop_type: PropertyType::Int,
198 | num: 2,
199 | name: "polygonMode",
200 | },
201 | Property {
202 | prop_type: PropertyType::Bool,
203 | num: 0,
204 | name: "primitiveRestartEnable",
205 | },
206 | Property {
207 | prop_type: PropertyType::Bool,
208 | num: 2,
209 | name: "rasterizerDiscardEnable",
210 | },
211 | Property {
212 | prop_type: PropertyType::Int,
213 | num: 9,
214 | name: "srcAlphaBlendFactor",
215 | },
216 | Property {
217 | prop_type: PropertyType::Int,
218 | num: 6,
219 | name: "srcColorBlendFactor",
220 | },
221 | Property {
222 | prop_type: PropertyType::Bool,
223 | num: 9,
224 | name: "stencilTestEnable",
225 | },
226 | Property {
227 | prop_type: PropertyType::Int,
228 | num: 0,
229 | name: "topology",
230 | },
231 | ];
232 |
233 | fn copy_properties_to_create_info(
234 | key: &Key,
235 | s: &mut vk::VkGraphicsPipelineCreateInfo
236 | ) {
237 | {
238 | let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineInputAssemblyStateCreateInfo>(s.pInputAssemblyState) };
239 | s.topology = key.int_properties[0] as vk::VkPrimitiveTopology;
240 | s.primitiveRestartEnable = key.bool_properties[0] as vk::VkBool32;
241 | }
242 | {
243 | let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineTessellationStateCreateInfo>(s.pTessellationState) };
244 | s.patchControlPoints = key.int_properties[1] as u32;
245 | }
246 | {
247 | let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineRasterizationStateCreateInfo>(s.pRasterizationState) };
248 | s.depthClampEnable = key.bool_properties[1] as vk::VkBool32;
249 | s.rasterizerDiscardEnable = key.bool_properties[2] as vk::VkBool32;
250 | s.polygonMode = key.int_properties[2] as vk::VkPolygonMode;
251 | s.cullMode = key.int_properties[3] as vk::VkCullModeFlags;
252 | s.frontFace = key.int_properties[4] as vk::VkFrontFace;
253 | s.depthBiasEnable = key.bool_properties[3] as vk::VkBool32;
254 | s.depthBiasConstantFactor = key.float_properties[0] as f32;
255 | s.depthBiasClamp = key.float_properties[1] as f32;
256 | s.depthBiasSlopeFactor = key.float_properties[2] as f32;
257 | s.lineWidth = key.float_properties[3] as f32;
258 | }
259 | {
260 | let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineColorBlendStateCreateInfo>(s.pColorBlendState) };
261 | s.logicOpEnable = key.bool_properties[4] as vk::VkBool32;
262 | s.logicOp = key.int_properties[5] as vk::VkLogicOp;
263 | {
264 | let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineColorBlendAttachmentState>(s.pAttachments) };
265 | s.blendEnable = key.bool_properties[5] as vk::VkBool32;
266 | s.srcColorBlendFactor = key.int_properties[6] as vk::VkBlendFactor;
267 | s.dstColorBlendFactor = key.int_properties[7] as vk::VkBlendFactor;
268 | s.colorBlendOp = key.int_properties[8] as vk::VkBlendOp;
269 | s.srcAlphaBlendFactor = key.int_properties[9] as vk::VkBlendFactor;
270 | s.dstAlphaBlendFactor = key.int_properties[10] as vk::VkBlendFactor;
271 | s.alphaBlendOp = key.int_properties[11] as vk::VkBlendOp;
272 | s.colorWriteMask = key.int_properties[12] as vk::VkColorComponentFlags;
273 | }
274 | }
275 | {
276 | let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineDepthStencilStateCreateInfo>(s.pDepthStencilState) };
277 | s.depthTestEnable = key.bool_properties[6] as vk::VkBool32;
278 | s.depthWriteEnable = key.bool_properties[7] as vk::VkBool32;
279 | s.depthCompareOp = key.int_properties[13] as vk::VkCompareOp;
280 | s.depthBoundsTestEnable = key.bool_properties[8] as vk::VkBool32;
281 | s.stencilTestEnable = key.bool_properties[9] as vk::VkBool32;
282 | s.front.failOp = key.int_properties[14] as vk::VkStencilOp;
283 | s.front.passOp = key.int_properties[15] as vk::VkStencilOp;
284 | s.front.depthFailOp = key.int_properties[16] as vk::VkStencilOp;
285 | s.front.compareOp = key.int_properties[17] as vk::VkCompareOp;
286 | s.front.compareMask = key.int_properties[18] as u32;
287 | s.front.writeMask = key.int_properties[19] as u32;
288 | s.front.reference = key.int_properties[20] as u32;
289 | s.back.failOp = key.int_properties[21] as vk::VkStencilOp;
290 | s.back.passOp = key.int_properties[22] as vk::VkStencilOp;
291 | s.back.depthFailOp = key.int_properties[23] as vk::VkStencilOp;
292 | s.back.compareOp = key.int_properties[24] as vk::VkCompareOp;
293 | s.back.compareMask = key.int_properties[25] as u32;
294 | s.back.writeMask = key.int_properties[26] as u32;
295 | s.back.reference = key.int_properties[27] as u32;
296 | s.minDepthBounds = key.float_properties[4] as f32;
297 | s.maxDepthBounds = key.float_properties[5] as f32;
298 | }
299 | }
300 |
301 | impl Default for Key {
302 | fn default() -> Key {
303 | Key {
304 | pipeline_type: Type::Graphics,
305 | source: Source::Rectangle,
306 | entrypoints: Default::default(),
307 |
308 | bool_properties: [
309 | false, // primitiveRestartEnable
310 | false, // depthClampEnable
311 | false, // rasterizerDiscardEnable
312 | false, // depthBiasEnable
313 | false, // logicOpEnable
314 | false, // blendEnable
315 | false, // depthTestEnable
316 | false, // depthWriteEnable
317 | false, // depthBoundsTestEnable
318 | false, // stencilTestEnable
319 | ],
320 | int_properties: [
321 | vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP as i32, // topology
322 | 0 as i32, // patchControlPoints
323 | vk::VK_POLYGON_MODE_FILL as i32, // polygonMode
324 | vk::VK_CULL_MODE_NONE as i32, // cullMode
325 | vk::VK_FRONT_FACE_COUNTER_CLOCKWISE as i32, // frontFace
326 | vk::VK_LOGIC_OP_SET as i32, // logicOp
327 | vk::VK_BLEND_FACTOR_SRC_ALPHA as i32, // srcColorBlendFactor
328 | vk::VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA as i32, // dstColorBlendFactor
329 | vk::VK_BLEND_OP_ADD as i32, // colorBlendOp
330 | vk::VK_BLEND_FACTOR_SRC_ALPHA as i32, // srcAlphaBlendFactor
331 | vk::VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA as i32, // dstAlphaBlendFactor
332 | vk::VK_BLEND_OP_ADD as i32, // alphaBlendOp
333 | (vk::VK_COLOR_COMPONENT_R_BIT | vk::VK_COLOR_COMPONENT_G_BIT | vk::VK_COLOR_COMPONENT_B_BIT | vk::VK_COLOR_COMPONENT_A_BIT) as i32, // colorWriteMask
334 | vk::VK_COMPARE_OP_LESS as i32, // depthCompareOp
335 | vk::VK_STENCIL_OP_KEEP as i32, // front.failOp
336 | vk::VK_STENCIL_OP_KEEP as i32, // front.passOp
337 | vk::VK_STENCIL_OP_KEEP as i32, // front.depthFailOp
338 | vk::VK_COMPARE_OP_ALWAYS as i32, // front.compareOp
339 | u32::MAX as i32, // front.compareMask
340 | u32::MAX as i32, // front.writeMask
341 | 0 as i32, // front.reference
342 | vk::VK_STENCIL_OP_KEEP as i32, // back.failOp
343 | vk::VK_STENCIL_OP_KEEP as i32, // back.passOp
344 | vk::VK_STENCIL_OP_KEEP as i32, // back.depthFailOp
345 | vk::VK_COMPARE_OP_ALWAYS as i32, // back.compareOp
346 | u32::MAX as i32, // back.compareMask
347 | u32::MAX as i32, // back.writeMask
348 | 0 as i32, // back.reference
349 | ],
350 | float_properties: [
351 | 0.0, // depthBiasConstantFactor
352 | 0.0, // depthBiasClamp
353 | 0.0, // depthBiasSlopeFactor
354 | 1.0, // lineWidth
355 | 0.0, // minDepthBounds
356 | 0.0, // maxDepthBounds
357 | ],
358 | }
359 | }
360 | }
361 |
362 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/hex.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::half_float;
24 | use std::num::{ParseFloatError, ParseIntError};
25 | use std::fmt;
26 | use std::convert::From;
27 |
28 | // Based on functions from piglit-util.c
29 |
30 | #[derive(Debug)]
31 | pub enum ParseError {
32 | Float(ParseFloatError),
33 | Int(ParseIntError),
34 | }
35 |
36 | impl fmt::Display for ParseError {
37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 | match self {
39 | ParseError::Float(e) => e.fmt(f),
40 | ParseError::Int(e) => e.fmt(f),
41 | }
42 | }
43 | }
44 |
45 | impl From<ParseFloatError> for ParseError {
46 | fn from(e: ParseFloatError) -> ParseError {
47 | ParseError::Float(e)
48 | }
49 | }
50 |
51 | impl From<ParseIntError> for ParseError {
52 | fn from(e: ParseIntError) -> ParseError {
53 | ParseError::Int(e)
54 | }
55 | }
56 |
57 | // Similar to haystack.starts_with(needle) but the ASCII characters of
58 | // haystack are converted to lower case before comparing. The needle
59 | // value should already be in lowercase for this to work.
60 | fn starts_with_ignore_case(haystack: &str, needle: &str) -> bool {
61 | let mut haystack_chars = haystack.chars();
62 |
63 | for needle_c in needle.chars() {
64 | match haystack_chars.next() {
65 | None => return false,
66 | Some(haystack_c) => if haystack_c.to_ascii_lowercase() != needle_c {
67 | return false;
68 | },
69 | }
70 | }
71 |
72 | true
73 | }
74 |
75 | // Checks whether the string slice starts with one of the special
76 | // words allowed in a float string. If so it returns the length of the
77 | // word, otherwise it returns None.
78 | fn starts_with_float_special_word(s: &str) -> Option<usize> {
79 | for word in ["infinity", "inf", "nan"] {
80 | if starts_with_ignore_case(s, word) {
81 | return Some(word.len());
82 | }
83 | }
84 |
85 | None
86 | }
87 |
88 | // Checks whether the string starts with a valid Number part of a
89 | // float. If so it returns the byte length, otherwise it returns None.
90 | fn count_number(s: &str) -> Option<usize> {
91 | // Optional units
92 | let before_digits = count_digits(s);
93 |
94 | let num_end = &s[before_digits..];
95 |
96 | // Optional decimal
97 | let after_digits;
98 | let n_points;
99 |
100 | if let Some('.') = num_end.chars().next() {
101 | n_points = 1;
102 | let digits = &num_end[1..];
103 | after_digits = count_digits(digits);
104 | } else {
105 | n_points = 0;
106 | after_digits = 0;
107 | }
108 |
109 | // Either the units or the decimal must be present
110 | if before_digits > 0 || after_digits > 0 {
111 | Some(before_digits + n_points + after_digits)
112 | } else {
113 | None
114 | }
115 | }
116 |
117 | // Returns how many ASCII digits are at the start of the string
118 | fn count_digits(s: &str) -> usize {
119 | s.chars().take_while(char::is_ascii_digit).count()
120 | }
121 |
122 | // Checks whether the strings starts with a valid Exp part of a float.
123 | // If so it returns the byte length, otherwise it returns None.
124 | fn count_exp(s: &str) -> Option<usize> {
125 | if let Some('E' | 'e') = s.chars().next() {
126 | let mut count = 1;
127 |
128 | if let Some('+' | '-') = s[count..].chars().next() {
129 | count += 1;
130 | }
131 |
132 | let digits = count_digits(&s[count..]);
133 |
134 | if digits > 0 {
135 | Some(count + digits)
136 | } else {
137 | None
138 | }
139 | } else {
140 | None
141 | }
142 | }
143 |
144 | // It looks like the rust float parsing functions don’t have an
145 | // equivalent of the `endptr` argument to `strtod`. This function
146 | // tries to work around that by extracting the float part and the rest
147 | // of the string and returning the two string slices as a tuple. It also
148 | // skips leading spaces.
149 | fn split_parts(mut s: &str) -> (&str, &str) {
150 | // skip only ASCII spaces and tabs
151 | while !s.is_empty() &&
152 | (s.as_bytes()[0] == b' ' || s.as_bytes()[0] == b'\t')
153 | {
154 | s = &s[1..];
155 | }
156 |
157 | let mut split_point = 0;
158 |
159 | if s.starts_with("0x") {
160 | split_point =
161 | 2
162 | + s[2..]
163 | .chars()
164 | .take_while(char::is_ascii_hexdigit)
165 | .count();
166 | } else {
167 | // Optional sign
168 | if let Some('-' | '+') = s[split_point..].chars().next() {
169 | split_point += 1;
170 | }
171 |
172 | if let Some(len) = starts_with_float_special_word(&s[split_point..]) {
173 | split_point += len;
174 | } else if let Some(len) = count_number(&s[split_point..]) {
175 | split_point += len;
176 |
177 | if let Some(len) = count_exp(&s[split_point..]) {
178 | split_point += len;
179 | }
180 | }
181 | }
182 |
183 | (&s[0..split_point], &s[split_point..])
184 | }
185 |
186 | // Wrapper for str.parse<f32> which allows using an exact hex bit
187 | // pattern to generate a float value and ignores trailing data.
188 | //
189 | // If the parsing works, it will return a tuple with the floating
190 | // point value and a string slice pointing to the rest of the string.
191 | pub fn parse_f32(s: &str) -> Result<(f32, &str), ParseError> {
192 | let (s, tail) = split_parts(s);
193 |
194 | if s.starts_with("0x") {
195 | Ok((f32::from_bits(u32::from_str_radix(&s[2..], 16)?), tail))
196 | } else {
197 | Ok((s.parse::<f32>()?, tail))
198 | }
199 | }
200 |
201 | // Wrapper for str.parse<f64> which allows using an exact hex bit
202 | // pattern to generate a float value and ignores trailing data.
203 | //
204 | // If the parsing works, it will return a tuple with the floating
205 | // point value and a string slice pointing to the rest of the string.
206 | pub fn parse_f64(s: &str) -> Result<(f64, &str), ParseError> {
207 | let (s, tail) = split_parts(s);
208 |
209 | if s.starts_with("0x") {
210 | Ok((f64::from_bits(u64::from_str_radix(&s[2..], 16)?), tail))
211 | } else {
212 | Ok((s.parse::<f64>()?, tail))
213 | }
214 | }
215 |
216 | // Wrapper for calling half_float::from_f32 on the result of parsing to the
217 | // string to a float but that also allows specifying the value exactly
218 | // as a hexadecimal number.
219 | //
220 | // If the parsing works, it will return a tuple with the half float
221 | // value and a string slice pointing to the rest of the string.
222 | pub fn parse_half_float(s: &str) -> Result<(u16, &str), ParseError> {
223 | let (s, tail) = split_parts(s);
224 |
225 | if s.starts_with("0x") {
226 | Ok((u16::from_str_radix(&s[2..], 16)?, tail))
227 | } else {
228 | Ok((half_float::from_f32(s.parse::<f32>()?), tail))
229 | }
230 | }
231 |
232 | #[cfg(test)]
233 | mod test {
234 | use super::*;
235 |
236 | #[test]
237 | fn test_split_parts() {
238 | // Skip spaces and tabs
239 | assert_eq!(split_parts(" 0"), ("0", ""));
240 | assert_eq!(split_parts(" \t 0"), ("0", ""));
241 | // Don’t skip other whitespace characters
242 | assert_eq!(split_parts(" \n 0"), ("", "\n 0"));
243 |
244 | // Hex digits
245 | assert_eq!(split_parts("0xCafeCafeTEA"), ("0xCafeCafe", "TEA"));
246 |
247 | // Signs
248 | assert_eq!(split_parts("+42 cupcakes"), ("+42", " cupcakes"));
249 | assert_eq!(split_parts("-42 gerbils"), ("-42", " gerbils"));
250 |
251 | // Special words
252 | assert_eq!(split_parts("+infinity forever"), ("+infinity", " forever"));
253 | assert_eq!(split_parts("INf forever"), ("INf", " forever"));
254 | assert_eq!(split_parts(" -NaN fornever"), ("-NaN", " fornever"));
255 | assert_eq!(split_parts("infin"), ("inf", "in"));
256 | assert_eq!(split_parts("NaN12"), ("NaN", "12"));
257 |
258 | // Normal numbers
259 | assert_eq!(split_parts("12.2"), ("12.2", ""));
260 | assert_eq!(split_parts("-12.2"), ("-12.2", ""));
261 | assert_eq!(split_parts("12.2e6"), ("12.2e6", ""));
262 | assert_eq!(split_parts("12.2E6"), ("12.2E6", ""));
263 | assert_eq!(split_parts("12.E6"), ("12.E6", ""));
264 | assert_eq!(split_parts("12.E-6"), ("12.E-6", ""));
265 | assert_eq!(split_parts("12.E+6"), ("12.E+6", ""));
266 | assert_eq!(split_parts(".0"), (".0", ""));
267 | assert_eq!(split_parts("5."), ("5.", ""));
268 | assert_eq!(split_parts(".5e6"), (".5e6", ""));
269 | assert_eq!(split_parts("5.e6"), ("5.e6", ""));
270 |
271 | // At least one side of the decimal point must be specified
272 | assert_eq!(split_parts("+."), ("+", "."));
273 |
274 | // The exponent must have some digits
275 | assert_eq!(split_parts("12e"), ("12", "e"));
276 | assert_eq!(split_parts("12e-"), ("12", "e-"));
277 |
278 | // Can’t have the exponent on its own
279 | assert_eq!(split_parts("e12"), ("", "e12"));
280 | }
281 |
282 | fn float_matches<T: Into<f64>>(
283 | res: Result<(T, &str), ParseError>,
284 | expected_value: T,
285 | expected_tail: &str
286 | ) {
287 | let (value, tail) = res.unwrap();
288 | let value = value.into();
289 | let expected_value = expected_value.into();
290 |
291 | assert!((value - expected_value).abs() < 0.0001,
292 | "value={}, expected_value={}",
293 | value,
294 | expected_value);
295 | assert_eq!(expected_tail, tail);
296 | }
297 |
298 | #[test]
299 | fn test_parse_f32() {
300 | float_matches(parse_f32("1.0"), 1.0, "");
301 | float_matches(parse_f32(" \t 1.0"), 1.0, "");
302 | float_matches(parse_f32("-1.0"), -1.0, "");
303 | float_matches(parse_f32("+1.0"), 1.0, "");
304 | float_matches(parse_f32("42 monkies"), 42.0, " monkies");
305 |
306 | float_matches(parse_f32("0x0"), 0.0, "");
307 | assert_eq!(parse_f32("0x7f800000").unwrap().0, f32::INFINITY);
308 |
309 | assert_eq!(parse_f32("-inf").unwrap(), (-f32::INFINITY, ""));
310 | assert_eq!(parse_f32("infinity 12").unwrap(), (f32::INFINITY, " 12"));
311 | assert!(parse_f32("NaN").unwrap().0.is_nan());
312 |
313 | assert!(matches!(
314 | parse_f32(""),
315 | Err(ParseError::Float(ParseFloatError { .. }))
316 | ));
317 |
318 | assert!(matches!(
319 | parse_f32("0xaaaaaaaaa"),
320 | Err(ParseError::Int(ParseIntError { .. }))
321 | ));
322 | }
323 |
324 | #[test]
325 | fn test_parse_f64() {
326 | float_matches(parse_f64("1.0"), 1.0, "");
327 | float_matches(parse_f64("42 monkies"), 42.0, " monkies");
328 |
329 | float_matches(parse_f64("0x0"), 0.0, "");
330 | assert_eq!(parse_f64("0xfff0000000000000").unwrap().0, -f64::INFINITY);
331 |
332 | assert_eq!(parse_f64("-inf").unwrap(), (-f64::INFINITY, ""));
333 | assert_eq!(parse_f64("infinity 12").unwrap(), (f64::INFINITY, " 12"));
334 | assert!(parse_f64("NaN").unwrap().0.is_nan());
335 |
336 | assert!(matches!(
337 | parse_f64(""),
338 | Err(ParseError::Float(ParseFloatError { .. }))
339 | ));
340 |
341 | assert!(matches!(
342 | parse_f64("0xaaaaaaaaaaaaaaaaa"),
343 | Err(ParseError::Int(ParseIntError { .. }))
344 | ));
345 | }
346 |
347 | #[test]
348 | fn test_parse_half_float() {
349 | assert_eq!(parse_half_float("1.0").unwrap(), (0x3c00, ""));
350 |
351 | assert_eq!(parse_half_float("0x7bff").unwrap(), (0x7bff, ""));
352 | assert_eq!(parse_half_float("0x7c00").unwrap(), (0x7c00, ""));
353 |
354 | assert_eq!(
355 | parse_half_float("infinity 12").unwrap(),
356 | (0x7c00, " 12")
357 | );
358 |
359 | assert!(matches!(
360 | parse_half_float(""),
361 | Err(ParseError::Float(ParseFloatError { .. }))
362 | ));
363 |
364 | assert!(matches!(
365 | parse_half_float("0xffff1"),
366 | Err(ParseError::Int(ParseIntError { .. }))
367 | ));
368 | }
369 | }
370 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/make-pipeline-key-data.py:
--------------------------------------------------------------------------------
```python
1 | #!/usr/bin/python3
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 script is used to generate pipeline_key_data.rs. It is not run
25 | # automatically as part of the build process but if need be it can be
26 | # used to update the file as follows:
27 | #
28 | # ./make-pipeline-key-data.py > pipeline_key_data.rs
29 |
30 | from mako.template import Template
31 |
32 | TEMPLATE="""\
33 | // Automatically generated by make-pipeline-key-data.py
34 |
35 | const N_BOOL_PROPERTIES: usize = ${sum(1 for p in props
36 | if p.base_type == "bool")};
37 | const N_INT_PROPERTIES: usize = ${sum(1 for p in props
38 | if p.base_type == "int")};
39 | const N_FLOAT_PROPERTIES: usize = ${sum(1 for p in props
40 | if p.base_type == "float")};
41 |
42 | const TOPOLOGY_PROP_NUM: usize = ${next(p for p in props
43 | if p.name == "topology").num};
44 | const PATCH_CONTROL_POINTS_PROP_NUM: usize = ${
45 | next(p for p in props if p.name == "patchControlPoints").num};
46 |
47 | static PROPERTIES: [Property; ${len(props)}] = [
48 | % for prop in sorted(props, key=lambda p: p.name):
49 | Property {
50 | prop_type: PropertyType::${prop.base_type.capitalize()},
51 | num: ${prop.num},
52 | name: "${prop.name}",
53 | },
54 | % endfor
55 | ];
56 |
57 | fn copy_properties_to_create_info(
58 | key: &Key,
59 | s: &mut vk::VkGraphicsPipelineCreateInfo
60 | ) {
61 | ${setters}
62 | }
63 |
64 | impl Default for Key {
65 | fn default() -> Key {
66 | Key {
67 | pipeline_type: Type::Graphics,
68 | source: Source::Rectangle,
69 | entrypoints: Default::default(),
70 |
71 | bool_properties: [
72 | % for prop in sorted(props, key=lambda p: p.num):
73 | % if prop.base_type == "bool":
74 | ${prop.default}, // ${prop.name}
75 | % endif
76 | % endfor
77 | ],
78 | int_properties: [
79 | % for prop in sorted(props, key=lambda p: p.num):
80 | % if prop.base_type == "int":
81 | ${prop.default} as i32, // ${prop.name}
82 | % endif
83 | % endfor
84 | ],
85 | float_properties: [
86 | % for prop in sorted(props, key=lambda p: p.num):
87 | % if prop.base_type == "float":
88 | ${prop.default}, // ${prop.name}
89 | % endif
90 | % endfor
91 | ],
92 | }
93 | }
94 | }
95 | """
96 |
97 |
98 | class Structure:
99 | def __init__(self, name, variable, children):
100 | self.name = name
101 | self.variable = variable
102 | self.children = children
103 |
104 |
105 | class Property:
106 | def __init__(self, vk_type, name, default):
107 | self.vk_type = vk_type
108 | self.base_type = vk_type_as_base_type(vk_type)
109 | self.name = name
110 | self.default = default
111 |
112 |
113 | class Properties:
114 | def __init__(self):
115 | self.values = []
116 | self.counts = {}
117 |
118 | def add(self, prop):
119 | base_type = prop.base_type
120 | try:
121 | self.counts[base_type] += 1
122 | except KeyError:
123 | self.counts[base_type] = 1
124 |
125 | prop.num = self.counts[base_type] - 1
126 |
127 | self.values.append(prop)
128 |
129 |
130 | def vk_type_as_base_type(vk_type):
131 | if vk_type == "vk::VkBool32":
132 | return "bool"
133 | elif vk_type == "f32":
134 | return "float"
135 | elif vk_type == "u32":
136 | return "int"
137 | elif vk_type.startswith("vk::Vk"):
138 | return "int"
139 |
140 | raise ValueError("Unsupported Vulkan type: {}".format(vk_type))
141 |
142 |
143 | STRUCTURES = [
144 | Structure("VkPipelineInputAssemblyStateCreateInfo",
145 | "pInputAssemblyState",
146 | [
147 | Property("vk::VkPrimitiveTopology",
148 | "topology",
149 | "vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP"),
150 | Property("vk::VkBool32",
151 | "primitiveRestartEnable",
152 | "false"),
153 | ]),
154 |
155 | Structure("VkPipelineTessellationStateCreateInfo",
156 | "pTessellationState",
157 | [
158 | Property("u32", "patchControlPoints", "0"),
159 | ]),
160 |
161 | Structure("VkPipelineRasterizationStateCreateInfo",
162 | "pRasterizationState",
163 | [
164 | Property("vk::VkBool32", "depthClampEnable", "false"),
165 | Property("vk::VkBool32", "rasterizerDiscardEnable", "false"),
166 | Property("vk::VkPolygonMode",
167 | "polygonMode",
168 | "vk::VK_POLYGON_MODE_FILL"),
169 | Property("vk::VkCullModeFlags",
170 | "cullMode",
171 | "vk::VK_CULL_MODE_NONE"),
172 | Property("vk::VkFrontFace",
173 | "frontFace",
174 | "vk::VK_FRONT_FACE_COUNTER_CLOCKWISE"),
175 | Property("vk::VkBool32", "depthBiasEnable", "false"),
176 | Property("f32", "depthBiasConstantFactor", "0.0"),
177 | Property("f32", "depthBiasClamp", "0.0"),
178 | Property("f32", "depthBiasSlopeFactor", "0.0"),
179 | Property("f32", "lineWidth", "1.0"),
180 | ]),
181 |
182 | Structure("VkPipelineColorBlendStateCreateInfo",
183 | "pColorBlendState",
184 | [
185 | Property("vk::VkBool32", "logicOpEnable", "false"),
186 | Property("vk::VkLogicOp", "logicOp", "vk::VK_LOGIC_OP_SET"),
187 |
188 | Structure("VkPipelineColorBlendAttachmentState",
189 | "pAttachments",
190 | [
191 | Property("vk::VkBool32",
192 | "blendEnable",
193 | "false"),
194 | Property("vk::VkBlendFactor",
195 | "srcColorBlendFactor",
196 | "vk::VK_BLEND_FACTOR_SRC_ALPHA"),
197 | Property("vk::VkBlendFactor",
198 | "dstColorBlendFactor",
199 | "vk::VK_BLEND_FACTOR_"
200 | "ONE_MINUS_SRC_ALPHA"),
201 | Property("vk::VkBlendOp",
202 | "colorBlendOp",
203 | "vk::VK_BLEND_OP_ADD"),
204 | Property("vk::VkBlendFactor",
205 | "srcAlphaBlendFactor",
206 | "vk::VK_BLEND_FACTOR_SRC_ALPHA"),
207 | Property("vk::VkBlendFactor",
208 | "dstAlphaBlendFactor",
209 | "vk::VK_BLEND_FACTOR_"
210 | "ONE_MINUS_SRC_ALPHA"),
211 | Property("vk::VkBlendOp",
212 | "alphaBlendOp",
213 | "vk::VK_BLEND_OP_ADD"),
214 | Property("vk::VkColorComponentFlags",
215 | "colorWriteMask",
216 | "(vk::VK_COLOR_COMPONENT_R_BIT | "
217 | "vk::VK_COLOR_COMPONENT_G_BIT | "
218 | "vk::VK_COLOR_COMPONENT_B_BIT | "
219 | "vk::VK_COLOR_COMPONENT_A_BIT)"),
220 | ]),
221 | ]),
222 |
223 | Structure("VkPipelineDepthStencilStateCreateInfo",
224 | "pDepthStencilState",
225 | [
226 | Property("vk::VkBool32", "depthTestEnable", "false"),
227 | Property("vk::VkBool32", "depthWriteEnable", "false"),
228 | Property("vk::VkCompareOp",
229 | "depthCompareOp",
230 | "vk::VK_COMPARE_OP_LESS"),
231 | Property("vk::VkBool32",
232 | "depthBoundsTestEnable",
233 | "false"),
234 | Property("vk::VkBool32",
235 | "stencilTestEnable",
236 | "false"),
237 | Property("vk::VkStencilOp",
238 | "front.failOp",
239 | "vk::VK_STENCIL_OP_KEEP"),
240 | Property("vk::VkStencilOp",
241 | "front.passOp",
242 | "vk::VK_STENCIL_OP_KEEP"),
243 | Property("vk::VkStencilOp",
244 | "front.depthFailOp",
245 | "vk::VK_STENCIL_OP_KEEP"),
246 | Property("vk::VkCompareOp",
247 | "front.compareOp",
248 | "vk::VK_COMPARE_OP_ALWAYS"),
249 | Property("u32",
250 | "front.compareMask",
251 | "u32::MAX"),
252 | Property("u32",
253 | "front.writeMask",
254 | "u32::MAX"),
255 | Property("u32",
256 | "front.reference",
257 | "0"),
258 | Property("vk::VkStencilOp",
259 | "back.failOp",
260 | "vk::VK_STENCIL_OP_KEEP"),
261 | Property("vk::VkStencilOp",
262 | "back.passOp",
263 | "vk::VK_STENCIL_OP_KEEP"),
264 | Property("vk::VkStencilOp",
265 | "back.depthFailOp",
266 | "vk::VK_STENCIL_OP_KEEP"),
267 | Property("vk::VkCompareOp",
268 | "back.compareOp",
269 | "vk::VK_COMPARE_OP_ALWAYS"),
270 | Property("u32",
271 | "back.compareMask",
272 | "u32::MAX"),
273 | Property("u32",
274 | "back.writeMask",
275 | "u32::MAX"),
276 | Property("u32",
277 | "back.reference",
278 | "0"),
279 | Property("f32", "minDepthBounds", "0.0"),
280 | Property("f32", "maxDepthBounds", "0.0"),
281 | ])
282 | ]
283 |
284 |
285 | def get_props(structure, props):
286 | for child in structure.children:
287 | if isinstance(child, Property):
288 | props.add(child)
289 | elif isinstance(child, Structure):
290 | get_props(child, props)
291 | else:
292 | raise Exception("STRUCTURES array is broken")
293 |
294 |
295 | def make_setters(structure):
296 | parts = []
297 |
298 | parts.append(" {")
299 | parts.append(" let s = unsafe {{ "
300 | "std::mem::transmute::<_, &mut vk::{}>(s.{}) }};".format(
301 | structure.name,
302 | structure.variable))
303 |
304 | for child in structure.children:
305 | if isinstance(child, Structure):
306 | parts.extend(map(lambda line: " " + line,
307 | make_setters(child)))
308 | elif isinstance(child, Property):
309 | parts.append(" s.{} = key.{}_properties[{}] as {};".format(
310 | child.name,
311 | child.base_type,
312 | child.num,
313 | child.vk_type))
314 |
315 | parts.append(" }")
316 |
317 | return parts
318 |
319 |
320 | def main():
321 | template = Template(TEMPLATE)
322 |
323 | props = Properties()
324 | for structure in STRUCTURES:
325 | get_props(structure, props)
326 |
327 | setters = "\n".join(sum(map(make_setters, STRUCTURES), start=[]))
328 |
329 | print(template.render(props = props.values, setters = setters))
330 |
331 |
332 | if __name__ == '__main__':
333 | main()
334 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/stream.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::source;
26 | use std::io;
27 | use std::io::BufRead;
28 | use std::fmt;
29 | use std::fs;
30 |
31 | // Encapsulates the two possible buf readers (either from a file or
32 | // from a string) that the stream will use. I don’t think we can put
33 | // this behind a boxed trait object because we can’t tell Rust that
34 | // the box won’t outlive the Stream object.
35 | #[derive(Debug)]
36 | enum Reader<'a> {
37 | File(io::BufReader<fs::File>),
38 | String(io::BufReader<&'a [u8]>),
39 | }
40 |
41 | /// A struct used to read lines from a [Source](source::Source). This
42 | /// will handle concatening lines that end with the line continuation
43 | /// character (`\`) and the token replacements.
44 | #[derive(Debug)]
45 | pub struct Stream<'a> {
46 | source: &'a source::Source,
47 | reader: Reader<'a>,
48 |
49 | line_num: usize,
50 | next_line_num: usize,
51 | reached_eof: bool,
52 | }
53 |
54 | /// An error that can be returned from [Stream::read_line] or [Stream::new].
55 | #[derive(Debug)]
56 | pub enum StreamError {
57 | IoError(io::Error),
58 | /// A token replacement causes an infinite loop of replacements to
59 | /// occur.
60 | TokenReplacementLoop,
61 | }
62 |
63 | impl fmt::Display for StreamError {
64 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 | match self {
66 | StreamError::IoError(e) => e.fmt(f),
67 | StreamError::TokenReplacementLoop => {
68 | write!(f, "The token replacements cause an infinite loop")
69 | },
70 | }
71 | }
72 | }
73 |
74 | impl std::convert::From<io::Error> for StreamError {
75 | fn from(value: io::Error) -> StreamError {
76 | StreamError::IoError(value)
77 | }
78 | }
79 |
80 | impl<'a> Stream<'a> {
81 | /// Constructs a new [Stream] that will read lines from the given
82 | /// [Source](source::Source). The construction can fail if the
83 | /// stream is a file source and opening the file fails. In that
84 | /// case the returned [StreamError] will contain an
85 | /// [io::Error](std::io::Error).
86 | pub fn new(source: &source::Source) -> Result<Stream, StreamError> {
87 | let reader = match source.data() {
88 | source::Data::File { filename } => {
89 | let file = fs::File::open(filename)?;
90 | Reader::File(io::BufReader::new(file))
91 | },
92 | source::Data::String { source } => {
93 | Reader::String(io::BufReader::new(source.as_bytes()))
94 | },
95 | };
96 |
97 | Ok(Stream {
98 | source,
99 | reader,
100 | line_num: 0,
101 | next_line_num: 1,
102 | reached_eof: false,
103 | })
104 | }
105 |
106 | /// Read a line from the stream and append it to the given String.
107 | /// This will handle the line continuation characters (`\`) and
108 | /// the token replacements set on the [Source](source::Source).
109 | ///
110 | /// The length of the data appended to the string is returned. If
111 | /// the end of the source is reached then it will return 0.
112 | pub fn read_line(
113 | &mut self,
114 | line: &mut String
115 | ) -> Result<usize, StreamError> {
116 | let start_length = line.len();
117 |
118 | self.line_num = self.next_line_num;
119 |
120 | while !self.reached_eof {
121 | let length = match &mut self.reader {
122 | Reader::File(r) => r.read_line(line)?,
123 | Reader::String(r) => r.read_line(line)?,
124 | };
125 |
126 | if length == 0 {
127 | self.reached_eof = true;
128 | break;
129 | }
130 |
131 | self.next_line_num += 1;
132 |
133 | if length >= 2 {
134 | if line.ends_with("\\\n") {
135 | line.truncate(line.len() - 2);
136 | continue;
137 | } else if length >= 3 && line.ends_with("\\\r\n") {
138 | line.truncate(line.len() - 3);
139 | continue;
140 | }
141 | }
142 |
143 | break;
144 | }
145 |
146 | self.process_token_replacements(line, start_length)?;
147 |
148 | Ok(line.len() - start_length)
149 | }
150 |
151 | /// Returns the line number in the source data of the start of the
152 | /// last line that was returned by [read_line](Stream::read_line).
153 | /// For example, if the source file is like this:
154 | ///
155 | /// ```text
156 | /// line one \
157 | /// continuation of line one.
158 | /// line two \
159 | /// continuation of line two.
160 | /// ```
161 | ///
162 | /// then the second time `read_line` is called it will append
163 | /// “line two continuation of line two” and
164 | /// [line_num](Stream::line_num) will report 3 because the line
165 | /// starts on the third line of the source data.
166 | pub fn line_num(&self) -> usize {
167 | self.line_num
168 | }
169 |
170 | fn process_token_replacements(
171 | &self,
172 | line: &mut String,
173 | start_pos: usize
174 | ) -> Result<(), StreamError> {
175 | let mut count = 0usize;
176 |
177 | // Loop through each valid position in the line string. We
178 | // can’t safely use an iterator because we’re going to modify
179 | // the string as we iterate
180 | let mut pos = start_pos;
181 |
182 | while pos < line.len() {
183 | 'token_loop: loop {
184 | for token_replacement in self.source.token_replacements() {
185 | if line[pos..].starts_with(&token_replacement.token) {
186 | count += 1;
187 |
188 | // If we’ve replaced at least 1000 tokens then
189 | // something has probably gone wrong and this
190 | // is never going to finish.
191 | if count >= 1000 {
192 | return Err(StreamError::TokenReplacementLoop);
193 | }
194 |
195 | line.replace_range(
196 | pos..pos + token_replacement.token.len(),
197 | &token_replacement.replacement,
198 | );
199 |
200 | // Start looking for tokens from the start of
201 | // the list in case the replacement contains
202 | // one of the earlier tokens
203 | continue 'token_loop;
204 | }
205 | }
206 |
207 | break 'token_loop;
208 | }
209 |
210 | // Move to the next character. It would be nice if we
211 | // could do this by just looking at the first byte of the
212 | // UTF-8 sequence but there doesn’t seem to be a handy
213 | // Rust API for that.
214 | pos += line[pos..].chars().next().unwrap().len_utf8();
215 | }
216 |
217 | Ok(())
218 | }
219 | }
220 |
221 | #[cfg(test)]
222 | mod test {
223 | use super::*;
224 |
225 | #[test]
226 | fn test_line_continuation() {
227 | let source = source::Source::from_string(
228 | "line one \\\n\
229 | more line one\n\
230 | line three \\\n\
231 | is really long \\\n\
232 | \\\n\
233 | and even has blank lines".to_string()
234 | );
235 | let mut stream = Stream::new(&source).unwrap();
236 |
237 | let mut line = String::new();
238 | assert_eq!(stream.read_line(&mut line).unwrap(), 23);
239 | assert_eq!(line, "line one more line one\n");
240 | assert_eq!(stream.line_num(), 1);
241 |
242 | assert_eq!(stream.read_line(&mut line).unwrap(), 50);
243 | assert_eq!(
244 | &line[23..],
245 | "line three is really long and even has blank lines",
246 | );
247 | assert_eq!(stream.line_num(), 3);
248 |
249 | // The line can also be continued if it has Windows-style line endings
250 | let source = source::Source::from_string(
251 | "line one \\\r\n\
252 | more line one\n\
253 | line three \r what".to_string()
254 | );
255 | let mut stream = Stream::new(&source).unwrap();
256 | let mut line = String::new();
257 |
258 | assert_eq!(stream.read_line(&mut line).unwrap(), 23);
259 | assert_eq!(line, "line one more line one\n");
260 | assert_eq!(stream.line_num(), 1);
261 |
262 | line.clear();
263 | assert_eq!(stream.read_line(&mut line).unwrap(), 17);
264 | assert_eq!(line, "line three \r what");
265 | assert_eq!(stream.line_num(), 3);
266 |
267 | // Backslashes in the middle of the string should just be left alone
268 | let source = source::Source::from_string(
269 | "I am happy \\o//".to_string()
270 | );
271 | let mut stream = Stream::new(&source).unwrap();
272 | let mut line = String::new();
273 | assert_eq!(stream.read_line(&mut line).unwrap(), 15);
274 | assert_eq!(line, "I am happy \\o//");
275 | }
276 |
277 | #[test]
278 | fn test_missing_file() {
279 | let source = source::Source::from_file(
280 | "this-file-does-not-exist".to_string().into()
281 | );
282 | let e = Stream::new(&source).unwrap_err();
283 | match e {
284 | StreamError::IoError(e) => {
285 | assert_eq!(e.kind(), io::ErrorKind::NotFound);
286 | },
287 | _ => unreachable!("expected StreamError::IoError, got: {}", e),
288 | }
289 | }
290 |
291 | fn run_test_file_source(filename: String) {
292 | fs::write(&filename, "my source code").unwrap();
293 |
294 | let source = source::Source::from_file(filename.into());
295 | let mut stream = Stream::new(&source).unwrap();
296 | let mut line = String::new();
297 | assert_eq!(stream.read_line(&mut line).unwrap(), 14);
298 | assert_eq!(line, "my source code");
299 |
300 | // EOF should return 0
301 | assert_eq!(stream.read_line(&mut line).unwrap(), 0);
302 | // It should also work a second time
303 | assert_eq!(stream.read_line(&mut line).unwrap(), 0);
304 | }
305 |
306 | #[test]
307 | fn test_file_source() {
308 | let mut filename = std::env::temp_dir();
309 | filename.push("vkrunner-test-file-source");
310 | let filename_str = filename.to_str().unwrap().to_owned();
311 |
312 | // Catch the unwind to try to remove the file that we created
313 | // if the test fails
314 | let r = std::panic::catch_unwind(
315 | move || run_test_file_source(filename_str)
316 | );
317 |
318 | if let Err(e) = fs::remove_file(filename) {
319 | assert_eq!(e.kind(), io::ErrorKind::NotFound);
320 | }
321 |
322 | if let Err(e) = r {
323 | std::panic::resume_unwind(e);
324 | }
325 | }
326 |
327 | macro_rules! replace_tokens {
328 | ($source:expr, $expected:expr, $($token:expr, $replacement:expr),*) => {
329 | let mut source = source::Source::from_string($source.to_owned());
330 |
331 | $(
332 | {
333 | source.add_token_replacement(
334 | $token.to_owned(),
335 | $replacement.to_owned()
336 | );
337 | }
338 | )*;
339 |
340 | let mut stream = Stream::new(&source).unwrap();
341 | let mut line = String::new();
342 |
343 | assert_eq!(stream.read_line(&mut line).unwrap(), $expected.len());
344 | assert_eq!(line, $expected);
345 | };
346 | }
347 |
348 | #[test]
349 | fn test_token_replacements() {
350 | // Simple replacement
351 | replace_tokens!(
352 | "one two",
353 | "1 2",
354 | "one", "1",
355 | "two", "2"
356 | );
357 | // Line continuation within a replacement
358 | replace_tokens!(
359 | "tok\\\n\
360 | ens are neat",
361 | "replacements are neat",
362 | "token",
363 | "replacement"
364 | );
365 | // Chain of replacements
366 | replace_tokens!(
367 | "I like this",
368 | "I like tomatoes",
369 | "this", "thatthing",
370 | "that", "t",
371 | "thing", "omatoes"
372 | );
373 |
374 | let mut source = source::Source::from_string(
375 | "Infinite recursion!".to_string()
376 | );
377 | source.add_token_replacement(
378 | "recursion".to_string(),
379 | "deeper".to_string(),
380 | );
381 | source.add_token_replacement(
382 | "deeper".to_string(),
383 | "keep-going".to_string(),
384 | );
385 | source.add_token_replacement(
386 | "keep-going".to_string(),
387 | "recursion".to_string(),
388 | );
389 | let mut stream = Stream::new(&source).unwrap();
390 | let mut line = String::new();
391 | let e = stream.read_line(&mut line).unwrap_err();
392 | assert!(matches!(e, StreamError::TokenReplacementLoop));
393 | assert_eq!(
394 | e.to_string(),
395 | "The token replacements cause an infinite loop"
396 | );
397 |
398 | // Try an empty token
399 | let mut source = source::Source::from_string(
400 | "Infinite recursion!".to_string()
401 | );
402 | source.add_token_replacement(
403 | "".to_string(),
404 | "ever longer".to_string(),
405 | );
406 | let mut stream = Stream::new(&source).unwrap();
407 | let mut line = String::new();
408 | let e = stream.read_line(&mut line).unwrap_err();
409 | assert!(matches!(e, StreamError::TokenReplacementLoop));
410 | }
411 | }
412 |
```
--------------------------------------------------------------------------------
/vkrunner/vkrunner/features.rs:
--------------------------------------------------------------------------------
```rust
1 | // Automatically generated by make-features.py
2 |
3 | static EXTENSIONS: [Extension; 29] = [
4 | Extension {
5 | name_bytes: vk::VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
6 | struct_size: mem::size_of::<vk::VkPhysicalDevice16BitStorageFeaturesKHR>(),
7 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
8 | features: &[
9 | "storageBuffer16BitAccess",
10 | "uniformAndStorageBuffer16BitAccess",
11 | "storagePushConstant16",
12 | "storageInputOutput16",
13 | ],
14 | },
15 | Extension {
16 | name_bytes: vk::VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
17 | struct_size: mem::size_of::<vk::VkPhysicalDevice8BitStorageFeaturesKHR>(),
18 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR,
19 | features: &[
20 | "storageBuffer8BitAccess",
21 | "uniformAndStorageBuffer8BitAccess",
22 | "storagePushConstant8",
23 | ],
24 | },
25 | Extension {
26 | name_bytes: vk::VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME,
27 | struct_size: mem::size_of::<vk::VkPhysicalDeviceASTCDecodeFeaturesEXT>(),
28 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT,
29 | features: &[
30 | "decodeModeSharedExponent",
31 | ],
32 | },
33 | Extension {
34 | name_bytes: vk::VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME,
35 | struct_size: mem::size_of::<vk::VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT>(),
36 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT,
37 | features: &[
38 | "advancedBlendCoherentOperations",
39 | ],
40 | },
41 | Extension {
42 | name_bytes: vk::VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
43 | struct_size: mem::size_of::<vk::VkPhysicalDeviceBufferDeviceAddressFeaturesEXT>(),
44 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT,
45 | features: &[
46 | "bufferDeviceAddress",
47 | "bufferDeviceAddressCaptureReplay",
48 | "bufferDeviceAddressMultiDevice",
49 | ],
50 | },
51 | Extension {
52 | name_bytes: vk::VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME,
53 | struct_size: mem::size_of::<vk::VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR>(),
54 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR,
55 | features: &[
56 | "computeDerivativeGroupQuads",
57 | "computeDerivativeGroupLinear",
58 | ],
59 | },
60 | Extension {
61 | name_bytes: vk::VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME,
62 | struct_size: mem::size_of::<vk::VkPhysicalDeviceConditionalRenderingFeaturesEXT>(),
63 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT,
64 | features: &[
65 | "conditionalRendering",
66 | "inheritedConditionalRendering",
67 | ],
68 | },
69 | Extension {
70 | name_bytes: vk::VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME,
71 | struct_size: mem::size_of::<vk::VkPhysicalDeviceCornerSampledImageFeaturesNV>(),
72 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV,
73 | features: &[
74 | "cornerSampledImage",
75 | ],
76 | },
77 | Extension {
78 | name_bytes: vk::VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
79 | struct_size: mem::size_of::<vk::VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(),
80 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT,
81 | features: &[
82 | "shaderInputAttachmentArrayDynamicIndexing",
83 | "shaderUniformTexelBufferArrayDynamicIndexing",
84 | "shaderStorageTexelBufferArrayDynamicIndexing",
85 | "shaderUniformBufferArrayNonUniformIndexing",
86 | "shaderSampledImageArrayNonUniformIndexing",
87 | "shaderStorageBufferArrayNonUniformIndexing",
88 | "shaderStorageImageArrayNonUniformIndexing",
89 | "shaderInputAttachmentArrayNonUniformIndexing",
90 | "shaderUniformTexelBufferArrayNonUniformIndexing",
91 | "shaderStorageTexelBufferArrayNonUniformIndexing",
92 | "descriptorBindingUniformBufferUpdateAfterBind",
93 | "descriptorBindingSampledImageUpdateAfterBind",
94 | "descriptorBindingStorageImageUpdateAfterBind",
95 | "descriptorBindingStorageBufferUpdateAfterBind",
96 | "descriptorBindingUniformTexelBufferUpdateAfterBind",
97 | "descriptorBindingStorageTexelBufferUpdateAfterBind",
98 | "descriptorBindingUpdateUnusedWhilePending",
99 | "descriptorBindingPartiallyBound",
100 | "descriptorBindingVariableDescriptorCount",
101 | "runtimeDescriptorArray",
102 | ],
103 | },
104 | Extension {
105 | name_bytes: vk::VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME,
106 | struct_size: mem::size_of::<vk::VkPhysicalDeviceExclusiveScissorFeaturesNV>(),
107 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV,
108 | features: &[
109 | "exclusiveScissor",
110 | ],
111 | },
112 | Extension {
113 | name_bytes: vk::VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME,
114 | struct_size: mem::size_of::<vk::VkPhysicalDeviceShaderFloat16Int8FeaturesKHR>(),
115 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR,
116 | features: &[
117 | "shaderFloat16",
118 | "shaderInt8",
119 | ],
120 | },
121 | Extension {
122 | name_bytes: vk::VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME,
123 | struct_size: mem::size_of::<vk::VkPhysicalDeviceFragmentDensityMapFeaturesEXT>(),
124 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT,
125 | features: &[
126 | "fragmentDensityMap",
127 | "fragmentDensityMapDynamic",
128 | "fragmentDensityMapNonSubsampledImages",
129 | ],
130 | },
131 | Extension {
132 | name_bytes: vk::VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME,
133 | struct_size: mem::size_of::<vk::VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR>(),
134 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR,
135 | features: &[
136 | "fragmentShaderBarycentric",
137 | ],
138 | },
139 | Extension {
140 | name_bytes: vk::VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME,
141 | struct_size: mem::size_of::<vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT>(),
142 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
143 | features: &[
144 | "inlineUniformBlock",
145 | "descriptorBindingInlineUniformBlockUpdateAfterBind",
146 | ],
147 | },
148 | Extension {
149 | name_bytes: vk::VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME,
150 | struct_size: mem::size_of::<vk::VkPhysicalDeviceMemoryPriorityFeaturesEXT>(),
151 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT,
152 | features: &[
153 | "memoryPriority",
154 | ],
155 | },
156 | Extension {
157 | name_bytes: vk::VK_NV_MESH_SHADER_EXTENSION_NAME,
158 | struct_size: mem::size_of::<vk::VkPhysicalDeviceMeshShaderFeaturesNV>(),
159 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV,
160 | features: &[
161 | "taskShader",
162 | "meshShader",
163 | ],
164 | },
165 | Extension {
166 | name_bytes: vk::VK_KHR_MULTIVIEW_EXTENSION_NAME,
167 | struct_size: mem::size_of::<vk::VkPhysicalDeviceMultiviewFeaturesKHR>(),
168 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
169 | features: &[
170 | "multiview",
171 | "multiviewGeometryShader",
172 | "multiviewTessellationShader",
173 | ],
174 | },
175 | Extension {
176 | name_bytes: vk::VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME,
177 | struct_size: mem::size_of::<vk::VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV>(),
178 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV,
179 | features: &[
180 | "representativeFragmentTest",
181 | ],
182 | },
183 | Extension {
184 | name_bytes: vk::VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
185 | struct_size: mem::size_of::<vk::VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR>(),
186 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR,
187 | features: &[
188 | "samplerYcbcrConversion",
189 | ],
190 | },
191 | Extension {
192 | name_bytes: vk::VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME,
193 | struct_size: mem::size_of::<vk::VkPhysicalDeviceScalarBlockLayoutFeaturesEXT>(),
194 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT,
195 | features: &[
196 | "scalarBlockLayout",
197 | ],
198 | },
199 | Extension {
200 | name_bytes: vk::VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME,
201 | struct_size: mem::size_of::<vk::VkPhysicalDeviceShaderAtomicInt64FeaturesKHR>(),
202 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR,
203 | features: &[
204 | "shaderBufferInt64Atomics",
205 | "shaderSharedInt64Atomics",
206 | ],
207 | },
208 | Extension {
209 | name_bytes: vk::VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME,
210 | struct_size: mem::size_of::<vk::VkPhysicalDeviceShaderImageFootprintFeaturesNV>(),
211 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV,
212 | features: &[
213 | "imageFootprint",
214 | ],
215 | },
216 | Extension {
217 | name_bytes: vk::VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME,
218 | struct_size: mem::size_of::<vk::VkPhysicalDeviceShadingRateImageFeaturesNV>(),
219 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV,
220 | features: &[
221 | "shadingRateImage",
222 | "shadingRateCoarseSampleOrder",
223 | ],
224 | },
225 | Extension {
226 | name_bytes: vk::VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME,
227 | struct_size: mem::size_of::<vk::VkPhysicalDeviceTransformFeedbackFeaturesEXT>(),
228 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
229 | features: &[
230 | "transformFeedback",
231 | "geometryStreams",
232 | ],
233 | },
234 | Extension {
235 | name_bytes: vk::VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
236 | struct_size: mem::size_of::<vk::VkPhysicalDeviceVariablePointersFeaturesKHR>(),
237 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR,
238 | features: &[
239 | "variablePointersStorageBuffer",
240 | "variablePointers",
241 | ],
242 | },
243 | Extension {
244 | name_bytes: vk::VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
245 | struct_size: mem::size_of::<vk::VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT>(),
246 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT,
247 | features: &[
248 | "vertexAttributeInstanceRateDivisor",
249 | "vertexAttributeInstanceRateZeroDivisor",
250 | ],
251 | },
252 | Extension {
253 | name_bytes: vk::VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME,
254 | struct_size: mem::size_of::<vk::VkPhysicalDeviceVulkanMemoryModelFeaturesKHR>(),
255 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR,
256 | features: &[
257 | "vulkanMemoryModel",
258 | "vulkanMemoryModelDeviceScope",
259 | "vulkanMemoryModelAvailabilityVisibilityChains",
260 | ],
261 | },
262 | Extension {
263 | name_bytes: vk::VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME,
264 | struct_size: mem::size_of::<vk::VkPhysicalDeviceCooperativeMatrixFeaturesKHR>(),
265 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR,
266 | features: &[
267 | "cooperativeMatrix",
268 | "cooperativeMatrixRobustBufferAccess",
269 | ],
270 | },
271 | Extension {
272 | name_bytes: vk::VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME,
273 | struct_size: mem::size_of::<vk::VkPhysicalDeviceSubgroupSizeControlFeaturesEXT>(),
274 | struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT,
275 | features: &[
276 | "subgroupSizeControl",
277 | "computeFullSubgroups",
278 | ],
279 | },
280 | ];
281 |
282 | const N_BASE_FEATURES: usize = 55;
283 |
284 | static BASE_FEATURES: [&'static str; N_BASE_FEATURES] = [
285 | "robustBufferAccess",
286 | "fullDrawIndexUint32",
287 | "imageCubeArray",
288 | "independentBlend",
289 | "geometryShader",
290 | "tessellationShader",
291 | "sampleRateShading",
292 | "dualSrcBlend",
293 | "logicOp",
294 | "multiDrawIndirect",
295 | "drawIndirectFirstInstance",
296 | "depthClamp",
297 | "depthBiasClamp",
298 | "fillModeNonSolid",
299 | "depthBounds",
300 | "wideLines",
301 | "largePoints",
302 | "alphaToOne",
303 | "multiViewport",
304 | "samplerAnisotropy",
305 | "textureCompressionETC2",
306 | "textureCompressionASTC_LDR",
307 | "textureCompressionBC",
308 | "occlusionQueryPrecise",
309 | "pipelineStatisticsQuery",
310 | "vertexPipelineStoresAndAtomics",
311 | "fragmentStoresAndAtomics",
312 | "shaderTessellationAndGeometryPointSize",
313 | "shaderImageGatherExtended",
314 | "shaderStorageImageExtendedFormats",
315 | "shaderStorageImageMultisample",
316 | "shaderStorageImageReadWithoutFormat",
317 | "shaderStorageImageWriteWithoutFormat",
318 | "shaderUniformBufferArrayDynamicIndexing",
319 | "shaderSampledImageArrayDynamicIndexing",
320 | "shaderStorageBufferArrayDynamicIndexing",
321 | "shaderStorageImageArrayDynamicIndexing",
322 | "shaderClipDistance",
323 | "shaderCullDistance",
324 | "shaderFloat64",
325 | "shaderInt64",
326 | "shaderInt16",
327 | "shaderResourceResidency",
328 | "shaderResourceMinLod",
329 | "sparseBinding",
330 | "sparseResidencyBuffer",
331 | "sparseResidencyImage2D",
332 | "sparseResidencyImage3D",
333 | "sparseResidency2Samples",
334 | "sparseResidency4Samples",
335 | "sparseResidency8Samples",
336 | "sparseResidency16Samples",
337 | "sparseResidencyAliased",
338 | "variableMultisampleRate",
339 | "inheritedQueries",
340 | ];
341 |
342 |
```
--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_h264std.h:
--------------------------------------------------------------------------------
```
1 | #ifndef VULKAN_VIDEO_CODEC_H264STD_H_
2 | #define VULKAN_VIDEO_CODEC_H264STD_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 is a preprocessor guard. Do not pass it to API calls.
23 | #define vulkan_video_codec_h264std 1
24 | #include "vulkan_video_codecs_common.h"
25 | #define STD_VIDEO_H264_CPB_CNT_LIST_SIZE 32
26 | #define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS 6
27 | #define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS 16
28 | #define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS 6
29 | #define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS 64
30 | #define STD_VIDEO_H264_MAX_NUM_LIST_REF 32
31 | #define STD_VIDEO_H264_MAX_CHROMA_PLANES 2
32 | #define STD_VIDEO_H264_NO_REFERENCE_PICTURE 0xFF
33 |
34 | typedef enum StdVideoH264ChromaFormatIdc {
35 | STD_VIDEO_H264_CHROMA_FORMAT_IDC_MONOCHROME = 0,
36 | STD_VIDEO_H264_CHROMA_FORMAT_IDC_420 = 1,
37 | STD_VIDEO_H264_CHROMA_FORMAT_IDC_422 = 2,
38 | STD_VIDEO_H264_CHROMA_FORMAT_IDC_444 = 3,
39 | STD_VIDEO_H264_CHROMA_FORMAT_IDC_INVALID = 0x7FFFFFFF,
40 | STD_VIDEO_H264_CHROMA_FORMAT_IDC_MAX_ENUM = 0x7FFFFFFF
41 | } StdVideoH264ChromaFormatIdc;
42 |
43 | typedef enum StdVideoH264ProfileIdc {
44 | STD_VIDEO_H264_PROFILE_IDC_BASELINE = 66,
45 | STD_VIDEO_H264_PROFILE_IDC_MAIN = 77,
46 | STD_VIDEO_H264_PROFILE_IDC_HIGH = 100,
47 | STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE = 244,
48 | STD_VIDEO_H264_PROFILE_IDC_INVALID = 0x7FFFFFFF,
49 | STD_VIDEO_H264_PROFILE_IDC_MAX_ENUM = 0x7FFFFFFF
50 | } StdVideoH264ProfileIdc;
51 |
52 | typedef enum StdVideoH264LevelIdc {
53 | STD_VIDEO_H264_LEVEL_IDC_1_0 = 0,
54 | STD_VIDEO_H264_LEVEL_IDC_1_1 = 1,
55 | STD_VIDEO_H264_LEVEL_IDC_1_2 = 2,
56 | STD_VIDEO_H264_LEVEL_IDC_1_3 = 3,
57 | STD_VIDEO_H264_LEVEL_IDC_2_0 = 4,
58 | STD_VIDEO_H264_LEVEL_IDC_2_1 = 5,
59 | STD_VIDEO_H264_LEVEL_IDC_2_2 = 6,
60 | STD_VIDEO_H264_LEVEL_IDC_3_0 = 7,
61 | STD_VIDEO_H264_LEVEL_IDC_3_1 = 8,
62 | STD_VIDEO_H264_LEVEL_IDC_3_2 = 9,
63 | STD_VIDEO_H264_LEVEL_IDC_4_0 = 10,
64 | STD_VIDEO_H264_LEVEL_IDC_4_1 = 11,
65 | STD_VIDEO_H264_LEVEL_IDC_4_2 = 12,
66 | STD_VIDEO_H264_LEVEL_IDC_5_0 = 13,
67 | STD_VIDEO_H264_LEVEL_IDC_5_1 = 14,
68 | STD_VIDEO_H264_LEVEL_IDC_5_2 = 15,
69 | STD_VIDEO_H264_LEVEL_IDC_6_0 = 16,
70 | STD_VIDEO_H264_LEVEL_IDC_6_1 = 17,
71 | STD_VIDEO_H264_LEVEL_IDC_6_2 = 18,
72 | STD_VIDEO_H264_LEVEL_IDC_INVALID = 0x7FFFFFFF,
73 | STD_VIDEO_H264_LEVEL_IDC_MAX_ENUM = 0x7FFFFFFF
74 | } StdVideoH264LevelIdc;
75 |
76 | typedef enum StdVideoH264PocType {
77 | STD_VIDEO_H264_POC_TYPE_0 = 0,
78 | STD_VIDEO_H264_POC_TYPE_1 = 1,
79 | STD_VIDEO_H264_POC_TYPE_2 = 2,
80 | STD_VIDEO_H264_POC_TYPE_INVALID = 0x7FFFFFFF,
81 | STD_VIDEO_H264_POC_TYPE_MAX_ENUM = 0x7FFFFFFF
82 | } StdVideoH264PocType;
83 |
84 | typedef enum StdVideoH264AspectRatioIdc {
85 | STD_VIDEO_H264_ASPECT_RATIO_IDC_UNSPECIFIED = 0,
86 | STD_VIDEO_H264_ASPECT_RATIO_IDC_SQUARE = 1,
87 | STD_VIDEO_H264_ASPECT_RATIO_IDC_12_11 = 2,
88 | STD_VIDEO_H264_ASPECT_RATIO_IDC_10_11 = 3,
89 | STD_VIDEO_H264_ASPECT_RATIO_IDC_16_11 = 4,
90 | STD_VIDEO_H264_ASPECT_RATIO_IDC_40_33 = 5,
91 | STD_VIDEO_H264_ASPECT_RATIO_IDC_24_11 = 6,
92 | STD_VIDEO_H264_ASPECT_RATIO_IDC_20_11 = 7,
93 | STD_VIDEO_H264_ASPECT_RATIO_IDC_32_11 = 8,
94 | STD_VIDEO_H264_ASPECT_RATIO_IDC_80_33 = 9,
95 | STD_VIDEO_H264_ASPECT_RATIO_IDC_18_11 = 10,
96 | STD_VIDEO_H264_ASPECT_RATIO_IDC_15_11 = 11,
97 | STD_VIDEO_H264_ASPECT_RATIO_IDC_64_33 = 12,
98 | STD_VIDEO_H264_ASPECT_RATIO_IDC_160_99 = 13,
99 | STD_VIDEO_H264_ASPECT_RATIO_IDC_4_3 = 14,
100 | STD_VIDEO_H264_ASPECT_RATIO_IDC_3_2 = 15,
101 | STD_VIDEO_H264_ASPECT_RATIO_IDC_2_1 = 16,
102 | STD_VIDEO_H264_ASPECT_RATIO_IDC_EXTENDED_SAR = 255,
103 | STD_VIDEO_H264_ASPECT_RATIO_IDC_INVALID = 0x7FFFFFFF,
104 | STD_VIDEO_H264_ASPECT_RATIO_IDC_MAX_ENUM = 0x7FFFFFFF
105 | } StdVideoH264AspectRatioIdc;
106 |
107 | typedef enum StdVideoH264WeightedBipredIdc {
108 | STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_DEFAULT = 0,
109 | STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_EXPLICIT = 1,
110 | STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_IMPLICIT = 2,
111 | STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_INVALID = 0x7FFFFFFF,
112 | STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_MAX_ENUM = 0x7FFFFFFF
113 | } StdVideoH264WeightedBipredIdc;
114 |
115 | typedef enum StdVideoH264ModificationOfPicNumsIdc {
116 | STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT = 0,
117 | STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD = 1,
118 | STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM = 2,
119 | STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_END = 3,
120 | STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_INVALID = 0x7FFFFFFF,
121 | STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_MAX_ENUM = 0x7FFFFFFF
122 | } StdVideoH264ModificationOfPicNumsIdc;
123 |
124 | typedef enum StdVideoH264MemMgmtControlOp {
125 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_END = 0,
126 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_SHORT_TERM = 1,
127 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_LONG_TERM = 2,
128 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM = 3,
129 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_SET_MAX_LONG_TERM_INDEX = 4,
130 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_ALL = 5,
131 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_CURRENT_AS_LONG_TERM = 6,
132 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_INVALID = 0x7FFFFFFF,
133 | STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MAX_ENUM = 0x7FFFFFFF
134 | } StdVideoH264MemMgmtControlOp;
135 |
136 | typedef enum StdVideoH264CabacInitIdc {
137 | STD_VIDEO_H264_CABAC_INIT_IDC_0 = 0,
138 | STD_VIDEO_H264_CABAC_INIT_IDC_1 = 1,
139 | STD_VIDEO_H264_CABAC_INIT_IDC_2 = 2,
140 | STD_VIDEO_H264_CABAC_INIT_IDC_INVALID = 0x7FFFFFFF,
141 | STD_VIDEO_H264_CABAC_INIT_IDC_MAX_ENUM = 0x7FFFFFFF
142 | } StdVideoH264CabacInitIdc;
143 |
144 | typedef enum StdVideoH264DisableDeblockingFilterIdc {
145 | STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_DISABLED = 0,
146 | STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_ENABLED = 1,
147 | STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_PARTIAL = 2,
148 | STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_INVALID = 0x7FFFFFFF,
149 | STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_MAX_ENUM = 0x7FFFFFFF
150 | } StdVideoH264DisableDeblockingFilterIdc;
151 |
152 | typedef enum StdVideoH264SliceType {
153 | STD_VIDEO_H264_SLICE_TYPE_P = 0,
154 | STD_VIDEO_H264_SLICE_TYPE_B = 1,
155 | STD_VIDEO_H264_SLICE_TYPE_I = 2,
156 | STD_VIDEO_H264_SLICE_TYPE_INVALID = 0x7FFFFFFF,
157 | STD_VIDEO_H264_SLICE_TYPE_MAX_ENUM = 0x7FFFFFFF
158 | } StdVideoH264SliceType;
159 |
160 | typedef enum StdVideoH264PictureType {
161 | STD_VIDEO_H264_PICTURE_TYPE_P = 0,
162 | STD_VIDEO_H264_PICTURE_TYPE_B = 1,
163 | STD_VIDEO_H264_PICTURE_TYPE_I = 2,
164 | STD_VIDEO_H264_PICTURE_TYPE_IDR = 5,
165 | STD_VIDEO_H264_PICTURE_TYPE_INVALID = 0x7FFFFFFF,
166 | STD_VIDEO_H264_PICTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
167 | } StdVideoH264PictureType;
168 |
169 | typedef enum StdVideoH264NonVclNaluType {
170 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_SPS = 0,
171 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_PPS = 1,
172 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_AUD = 2,
173 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_PREFIX = 3,
174 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_SEQUENCE = 4,
175 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_STREAM = 5,
176 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_PRECODED = 6,
177 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_INVALID = 0x7FFFFFFF,
178 | STD_VIDEO_H264_NON_VCL_NALU_TYPE_MAX_ENUM = 0x7FFFFFFF
179 | } StdVideoH264NonVclNaluType;
180 | typedef struct StdVideoH264SpsVuiFlags {
181 | uint32_t aspect_ratio_info_present_flag : 1;
182 | uint32_t overscan_info_present_flag : 1;
183 | uint32_t overscan_appropriate_flag : 1;
184 | uint32_t video_signal_type_present_flag : 1;
185 | uint32_t video_full_range_flag : 1;
186 | uint32_t color_description_present_flag : 1;
187 | uint32_t chroma_loc_info_present_flag : 1;
188 | uint32_t timing_info_present_flag : 1;
189 | uint32_t fixed_frame_rate_flag : 1;
190 | uint32_t bitstream_restriction_flag : 1;
191 | uint32_t nal_hrd_parameters_present_flag : 1;
192 | uint32_t vcl_hrd_parameters_present_flag : 1;
193 | } StdVideoH264SpsVuiFlags;
194 |
195 | typedef struct StdVideoH264HrdParameters {
196 | uint8_t cpb_cnt_minus1;
197 | uint8_t bit_rate_scale;
198 | uint8_t cpb_size_scale;
199 | uint8_t reserved1;
200 | uint32_t bit_rate_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE];
201 | uint32_t cpb_size_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE];
202 | uint8_t cbr_flag[STD_VIDEO_H264_CPB_CNT_LIST_SIZE];
203 | uint32_t initial_cpb_removal_delay_length_minus1;
204 | uint32_t cpb_removal_delay_length_minus1;
205 | uint32_t dpb_output_delay_length_minus1;
206 | uint32_t time_offset_length;
207 | } StdVideoH264HrdParameters;
208 |
209 | typedef struct StdVideoH264SequenceParameterSetVui {
210 | StdVideoH264SpsVuiFlags flags;
211 | StdVideoH264AspectRatioIdc aspect_ratio_idc;
212 | uint16_t sar_width;
213 | uint16_t sar_height;
214 | uint8_t video_format;
215 | uint8_t colour_primaries;
216 | uint8_t transfer_characteristics;
217 | uint8_t matrix_coefficients;
218 | uint32_t num_units_in_tick;
219 | uint32_t time_scale;
220 | uint8_t max_num_reorder_frames;
221 | uint8_t max_dec_frame_buffering;
222 | uint8_t chroma_sample_loc_type_top_field;
223 | uint8_t chroma_sample_loc_type_bottom_field;
224 | uint32_t reserved1;
225 | const StdVideoH264HrdParameters* pHrdParameters;
226 | } StdVideoH264SequenceParameterSetVui;
227 |
228 | typedef struct StdVideoH264SpsFlags {
229 | uint32_t constraint_set0_flag : 1;
230 | uint32_t constraint_set1_flag : 1;
231 | uint32_t constraint_set2_flag : 1;
232 | uint32_t constraint_set3_flag : 1;
233 | uint32_t constraint_set4_flag : 1;
234 | uint32_t constraint_set5_flag : 1;
235 | uint32_t direct_8x8_inference_flag : 1;
236 | uint32_t mb_adaptive_frame_field_flag : 1;
237 | uint32_t frame_mbs_only_flag : 1;
238 | uint32_t delta_pic_order_always_zero_flag : 1;
239 | uint32_t separate_colour_plane_flag : 1;
240 | uint32_t gaps_in_frame_num_value_allowed_flag : 1;
241 | uint32_t qpprime_y_zero_transform_bypass_flag : 1;
242 | uint32_t frame_cropping_flag : 1;
243 | uint32_t seq_scaling_matrix_present_flag : 1;
244 | uint32_t vui_parameters_present_flag : 1;
245 | } StdVideoH264SpsFlags;
246 |
247 | typedef struct StdVideoH264ScalingLists {
248 | uint16_t scaling_list_present_mask;
249 | uint16_t use_default_scaling_matrix_mask;
250 | uint8_t ScalingList4x4[STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS];
251 | uint8_t ScalingList8x8[STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS];
252 | } StdVideoH264ScalingLists;
253 |
254 | typedef struct StdVideoH264SequenceParameterSet {
255 | StdVideoH264SpsFlags flags;
256 | StdVideoH264ProfileIdc profile_idc;
257 | StdVideoH264LevelIdc level_idc;
258 | StdVideoH264ChromaFormatIdc chroma_format_idc;
259 | uint8_t seq_parameter_set_id;
260 | uint8_t bit_depth_luma_minus8;
261 | uint8_t bit_depth_chroma_minus8;
262 | uint8_t log2_max_frame_num_minus4;
263 | StdVideoH264PocType pic_order_cnt_type;
264 | int32_t offset_for_non_ref_pic;
265 | int32_t offset_for_top_to_bottom_field;
266 | uint8_t log2_max_pic_order_cnt_lsb_minus4;
267 | uint8_t num_ref_frames_in_pic_order_cnt_cycle;
268 | uint8_t max_num_ref_frames;
269 | uint8_t reserved1;
270 | uint32_t pic_width_in_mbs_minus1;
271 | uint32_t pic_height_in_map_units_minus1;
272 | uint32_t frame_crop_left_offset;
273 | uint32_t frame_crop_right_offset;
274 | uint32_t frame_crop_top_offset;
275 | uint32_t frame_crop_bottom_offset;
276 | uint32_t reserved2;
277 | const int32_t* pOffsetForRefFrame;
278 | const StdVideoH264ScalingLists* pScalingLists;
279 | const StdVideoH264SequenceParameterSetVui* pSequenceParameterSetVui;
280 | } StdVideoH264SequenceParameterSet;
281 |
282 | typedef struct StdVideoH264PpsFlags {
283 | uint32_t transform_8x8_mode_flag : 1;
284 | uint32_t redundant_pic_cnt_present_flag : 1;
285 | uint32_t constrained_intra_pred_flag : 1;
286 | uint32_t deblocking_filter_control_present_flag : 1;
287 | uint32_t weighted_pred_flag : 1;
288 | uint32_t bottom_field_pic_order_in_frame_present_flag : 1;
289 | uint32_t entropy_coding_mode_flag : 1;
290 | uint32_t pic_scaling_matrix_present_flag : 1;
291 | } StdVideoH264PpsFlags;
292 |
293 | typedef struct StdVideoH264PictureParameterSet {
294 | StdVideoH264PpsFlags flags;
295 | uint8_t seq_parameter_set_id;
296 | uint8_t pic_parameter_set_id;
297 | uint8_t num_ref_idx_l0_default_active_minus1;
298 | uint8_t num_ref_idx_l1_default_active_minus1;
299 | StdVideoH264WeightedBipredIdc weighted_bipred_idc;
300 | int8_t pic_init_qp_minus26;
301 | int8_t pic_init_qs_minus26;
302 | int8_t chroma_qp_index_offset;
303 | int8_t second_chroma_qp_index_offset;
304 | const StdVideoH264ScalingLists* pScalingLists;
305 | } StdVideoH264PictureParameterSet;
306 |
307 |
308 | #ifdef __cplusplus
309 | }
310 | #endif
311 |
312 | #endif
313 |
```
--------------------------------------------------------------------------------
/vkrunner/include/vk_video/vulkan_video_codec_av1std.h:
--------------------------------------------------------------------------------
```
1 | #ifndef VULKAN_VIDEO_CODEC_AV1STD_H_
2 | #define VULKAN_VIDEO_CODEC_AV1STD_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 is a preprocessor guard. Do not pass it to API calls.
23 | #define vulkan_video_codec_av1std 1
24 | #include "vulkan_video_codecs_common.h"
25 | #define STD_VIDEO_AV1_NUM_REF_FRAMES 8
26 | #define STD_VIDEO_AV1_REFS_PER_FRAME 7
27 | #define STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME 8
28 | #define STD_VIDEO_AV1_MAX_TILE_COLS 64
29 | #define STD_VIDEO_AV1_MAX_TILE_ROWS 64
30 | #define STD_VIDEO_AV1_MAX_SEGMENTS 8
31 | #define STD_VIDEO_AV1_SEG_LVL_MAX 8
32 | #define STD_VIDEO_AV1_PRIMARY_REF_NONE 7
33 | #define STD_VIDEO_AV1_SELECT_INTEGER_MV 2
34 | #define STD_VIDEO_AV1_SELECT_SCREEN_CONTENT_TOOLS 2
35 | #define STD_VIDEO_AV1_SKIP_MODE_FRAMES 2
36 | #define STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS 4
37 | #define STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS 2
38 | #define STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS 8
39 | #define STD_VIDEO_AV1_MAX_NUM_PLANES 3
40 | #define STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS 6
41 | #define STD_VIDEO_AV1_MAX_NUM_Y_POINTS 14
42 | #define STD_VIDEO_AV1_MAX_NUM_CB_POINTS 10
43 | #define STD_VIDEO_AV1_MAX_NUM_CR_POINTS 10
44 | #define STD_VIDEO_AV1_MAX_NUM_POS_LUMA 24
45 | #define STD_VIDEO_AV1_MAX_NUM_POS_CHROMA 25
46 |
47 | typedef enum StdVideoAV1Profile {
48 | STD_VIDEO_AV1_PROFILE_MAIN = 0,
49 | STD_VIDEO_AV1_PROFILE_HIGH = 1,
50 | STD_VIDEO_AV1_PROFILE_PROFESSIONAL = 2,
51 | STD_VIDEO_AV1_PROFILE_INVALID = 0x7FFFFFFF,
52 | STD_VIDEO_AV1_PROFILE_MAX_ENUM = 0x7FFFFFFF
53 | } StdVideoAV1Profile;
54 |
55 | typedef enum StdVideoAV1Level {
56 | STD_VIDEO_AV1_LEVEL_2_0 = 0,
57 | STD_VIDEO_AV1_LEVEL_2_1 = 1,
58 | STD_VIDEO_AV1_LEVEL_2_2 = 2,
59 | STD_VIDEO_AV1_LEVEL_2_3 = 3,
60 | STD_VIDEO_AV1_LEVEL_3_0 = 4,
61 | STD_VIDEO_AV1_LEVEL_3_1 = 5,
62 | STD_VIDEO_AV1_LEVEL_3_2 = 6,
63 | STD_VIDEO_AV1_LEVEL_3_3 = 7,
64 | STD_VIDEO_AV1_LEVEL_4_0 = 8,
65 | STD_VIDEO_AV1_LEVEL_4_1 = 9,
66 | STD_VIDEO_AV1_LEVEL_4_2 = 10,
67 | STD_VIDEO_AV1_LEVEL_4_3 = 11,
68 | STD_VIDEO_AV1_LEVEL_5_0 = 12,
69 | STD_VIDEO_AV1_LEVEL_5_1 = 13,
70 | STD_VIDEO_AV1_LEVEL_5_2 = 14,
71 | STD_VIDEO_AV1_LEVEL_5_3 = 15,
72 | STD_VIDEO_AV1_LEVEL_6_0 = 16,
73 | STD_VIDEO_AV1_LEVEL_6_1 = 17,
74 | STD_VIDEO_AV1_LEVEL_6_2 = 18,
75 | STD_VIDEO_AV1_LEVEL_6_3 = 19,
76 | STD_VIDEO_AV1_LEVEL_7_0 = 20,
77 | STD_VIDEO_AV1_LEVEL_7_1 = 21,
78 | STD_VIDEO_AV1_LEVEL_7_2 = 22,
79 | STD_VIDEO_AV1_LEVEL_7_3 = 23,
80 | STD_VIDEO_AV1_LEVEL_INVALID = 0x7FFFFFFF,
81 | STD_VIDEO_AV1_LEVEL_MAX_ENUM = 0x7FFFFFFF
82 | } StdVideoAV1Level;
83 |
84 | typedef enum StdVideoAV1FrameType {
85 | STD_VIDEO_AV1_FRAME_TYPE_KEY = 0,
86 | STD_VIDEO_AV1_FRAME_TYPE_INTER = 1,
87 | STD_VIDEO_AV1_FRAME_TYPE_INTRA_ONLY = 2,
88 | STD_VIDEO_AV1_FRAME_TYPE_SWITCH = 3,
89 | STD_VIDEO_AV1_FRAME_TYPE_INVALID = 0x7FFFFFFF,
90 | STD_VIDEO_AV1_FRAME_TYPE_MAX_ENUM = 0x7FFFFFFF
91 | } StdVideoAV1FrameType;
92 |
93 | typedef enum StdVideoAV1ReferenceName {
94 | STD_VIDEO_AV1_REFERENCE_NAME_INTRA_FRAME = 0,
95 | STD_VIDEO_AV1_REFERENCE_NAME_LAST_FRAME = 1,
96 | STD_VIDEO_AV1_REFERENCE_NAME_LAST2_FRAME = 2,
97 | STD_VIDEO_AV1_REFERENCE_NAME_LAST3_FRAME = 3,
98 | STD_VIDEO_AV1_REFERENCE_NAME_GOLDEN_FRAME = 4,
99 | STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME = 5,
100 | STD_VIDEO_AV1_REFERENCE_NAME_ALTREF2_FRAME = 6,
101 | STD_VIDEO_AV1_REFERENCE_NAME_ALTREF_FRAME = 7,
102 | STD_VIDEO_AV1_REFERENCE_NAME_INVALID = 0x7FFFFFFF,
103 | STD_VIDEO_AV1_REFERENCE_NAME_MAX_ENUM = 0x7FFFFFFF
104 | } StdVideoAV1ReferenceName;
105 |
106 | typedef enum StdVideoAV1InterpolationFilter {
107 | STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP = 0,
108 | STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH = 1,
109 | STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP = 2,
110 | STD_VIDEO_AV1_INTERPOLATION_FILTER_BILINEAR = 3,
111 | STD_VIDEO_AV1_INTERPOLATION_FILTER_SWITCHABLE = 4,
112 | STD_VIDEO_AV1_INTERPOLATION_FILTER_INVALID = 0x7FFFFFFF,
113 | STD_VIDEO_AV1_INTERPOLATION_FILTER_MAX_ENUM = 0x7FFFFFFF
114 | } StdVideoAV1InterpolationFilter;
115 |
116 | typedef enum StdVideoAV1TxMode {
117 | STD_VIDEO_AV1_TX_MODE_ONLY_4X4 = 0,
118 | STD_VIDEO_AV1_TX_MODE_LARGEST = 1,
119 | STD_VIDEO_AV1_TX_MODE_SELECT = 2,
120 | STD_VIDEO_AV1_TX_MODE_INVALID = 0x7FFFFFFF,
121 | STD_VIDEO_AV1_TX_MODE_MAX_ENUM = 0x7FFFFFFF
122 | } StdVideoAV1TxMode;
123 |
124 | typedef enum StdVideoAV1FrameRestorationType {
125 | STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE = 0,
126 | STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER = 1,
127 | STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ = 2,
128 | STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SWITCHABLE = 3,
129 | STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_INVALID = 0x7FFFFFFF,
130 | STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_MAX_ENUM = 0x7FFFFFFF
131 | } StdVideoAV1FrameRestorationType;
132 |
133 | typedef enum StdVideoAV1ColorPrimaries {
134 | STD_VIDEO_AV1_COLOR_PRIMARIES_BT_709 = 1,
135 | STD_VIDEO_AV1_COLOR_PRIMARIES_UNSPECIFIED = 2,
136 | STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_M = 4,
137 | STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_B_G = 5,
138 | STD_VIDEO_AV1_COLOR_PRIMARIES_BT_601 = 6,
139 | STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_240 = 7,
140 | STD_VIDEO_AV1_COLOR_PRIMARIES_GENERIC_FILM = 8,
141 | STD_VIDEO_AV1_COLOR_PRIMARIES_BT_2020 = 9,
142 | STD_VIDEO_AV1_COLOR_PRIMARIES_XYZ = 10,
143 | STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_431 = 11,
144 | STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_432 = 12,
145 | STD_VIDEO_AV1_COLOR_PRIMARIES_EBU_3213 = 22,
146 | STD_VIDEO_AV1_COLOR_PRIMARIES_INVALID = 0x7FFFFFFF,
147 | // STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED is a deprecated alias
148 | STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED = STD_VIDEO_AV1_COLOR_PRIMARIES_UNSPECIFIED,
149 | STD_VIDEO_AV1_COLOR_PRIMARIES_MAX_ENUM = 0x7FFFFFFF
150 | } StdVideoAV1ColorPrimaries;
151 |
152 | typedef enum StdVideoAV1TransferCharacteristics {
153 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_0 = 0,
154 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_709 = 1,
155 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2,
156 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_3 = 3,
157 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_M = 4,
158 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_B_G = 5,
159 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_601 = 6,
160 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_240 = 7,
161 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LINEAR = 8,
162 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100 = 9,
163 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100_SQRT10 = 10,
164 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_IEC_61966 = 11,
165 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_1361 = 12,
166 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SRGB = 13,
167 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_10_BIT = 14,
168 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_12_BIT = 15,
169 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_2084 = 16,
170 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_428 = 17,
171 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_HLG = 18,
172 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_INVALID = 0x7FFFFFFF,
173 | STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_MAX_ENUM = 0x7FFFFFFF
174 | } StdVideoAV1TransferCharacteristics;
175 |
176 | typedef enum StdVideoAV1MatrixCoefficients {
177 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_IDENTITY = 0,
178 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_709 = 1,
179 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_UNSPECIFIED = 2,
180 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_RESERVED_3 = 3,
181 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_FCC = 4,
182 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_470_B_G = 5,
183 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_601 = 6,
184 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_240 = 7,
185 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_YCGCO = 8,
186 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_NCL = 9,
187 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_CL = 10,
188 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_2085 = 11,
189 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_NCL = 12,
190 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_CL = 13,
191 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_ICTCP = 14,
192 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_INVALID = 0x7FFFFFFF,
193 | STD_VIDEO_AV1_MATRIX_COEFFICIENTS_MAX_ENUM = 0x7FFFFFFF
194 | } StdVideoAV1MatrixCoefficients;
195 |
196 | typedef enum StdVideoAV1ChromaSamplePosition {
197 | STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_UNKNOWN = 0,
198 | STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_VERTICAL = 1,
199 | STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_COLOCATED = 2,
200 | STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_RESERVED = 3,
201 | STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_INVALID = 0x7FFFFFFF,
202 | STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_MAX_ENUM = 0x7FFFFFFF
203 | } StdVideoAV1ChromaSamplePosition;
204 | typedef struct StdVideoAV1ColorConfigFlags {
205 | uint32_t mono_chrome : 1;
206 | uint32_t color_range : 1;
207 | uint32_t separate_uv_delta_q : 1;
208 | uint32_t color_description_present_flag : 1;
209 | uint32_t reserved : 28;
210 | } StdVideoAV1ColorConfigFlags;
211 |
212 | typedef struct StdVideoAV1ColorConfig {
213 | StdVideoAV1ColorConfigFlags flags;
214 | uint8_t BitDepth;
215 | uint8_t subsampling_x;
216 | uint8_t subsampling_y;
217 | uint8_t reserved1;
218 | StdVideoAV1ColorPrimaries color_primaries;
219 | StdVideoAV1TransferCharacteristics transfer_characteristics;
220 | StdVideoAV1MatrixCoefficients matrix_coefficients;
221 | StdVideoAV1ChromaSamplePosition chroma_sample_position;
222 | } StdVideoAV1ColorConfig;
223 |
224 | typedef struct StdVideoAV1TimingInfoFlags {
225 | uint32_t equal_picture_interval : 1;
226 | uint32_t reserved : 31;
227 | } StdVideoAV1TimingInfoFlags;
228 |
229 | typedef struct StdVideoAV1TimingInfo {
230 | StdVideoAV1TimingInfoFlags flags;
231 | uint32_t num_units_in_display_tick;
232 | uint32_t time_scale;
233 | uint32_t num_ticks_per_picture_minus_1;
234 | } StdVideoAV1TimingInfo;
235 |
236 | typedef struct StdVideoAV1LoopFilterFlags {
237 | uint32_t loop_filter_delta_enabled : 1;
238 | uint32_t loop_filter_delta_update : 1;
239 | uint32_t reserved : 30;
240 | } StdVideoAV1LoopFilterFlags;
241 |
242 | typedef struct StdVideoAV1LoopFilter {
243 | StdVideoAV1LoopFilterFlags flags;
244 | uint8_t loop_filter_level[STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS];
245 | uint8_t loop_filter_sharpness;
246 | uint8_t update_ref_delta;
247 | int8_t loop_filter_ref_deltas[STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME];
248 | uint8_t update_mode_delta;
249 | int8_t loop_filter_mode_deltas[STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS];
250 | } StdVideoAV1LoopFilter;
251 |
252 | typedef struct StdVideoAV1QuantizationFlags {
253 | uint32_t using_qmatrix : 1;
254 | uint32_t diff_uv_delta : 1;
255 | uint32_t reserved : 30;
256 | } StdVideoAV1QuantizationFlags;
257 |
258 | typedef struct StdVideoAV1Quantization {
259 | StdVideoAV1QuantizationFlags flags;
260 | uint8_t base_q_idx;
261 | int8_t DeltaQYDc;
262 | int8_t DeltaQUDc;
263 | int8_t DeltaQUAc;
264 | int8_t DeltaQVDc;
265 | int8_t DeltaQVAc;
266 | uint8_t qm_y;
267 | uint8_t qm_u;
268 | uint8_t qm_v;
269 | } StdVideoAV1Quantization;
270 |
271 | typedef struct StdVideoAV1Segmentation {
272 | uint8_t FeatureEnabled[STD_VIDEO_AV1_MAX_SEGMENTS];
273 | int16_t FeatureData[STD_VIDEO_AV1_MAX_SEGMENTS][STD_VIDEO_AV1_SEG_LVL_MAX];
274 | } StdVideoAV1Segmentation;
275 |
276 | typedef struct StdVideoAV1TileInfoFlags {
277 | uint32_t uniform_tile_spacing_flag : 1;
278 | uint32_t reserved : 31;
279 | } StdVideoAV1TileInfoFlags;
280 |
281 | typedef struct StdVideoAV1TileInfo {
282 | StdVideoAV1TileInfoFlags flags;
283 | uint8_t TileCols;
284 | uint8_t TileRows;
285 | uint16_t context_update_tile_id;
286 | uint8_t tile_size_bytes_minus_1;
287 | uint8_t reserved1[7];
288 | const uint16_t* pMiColStarts;
289 | const uint16_t* pMiRowStarts;
290 | const uint16_t* pWidthInSbsMinus1;
291 | const uint16_t* pHeightInSbsMinus1;
292 | } StdVideoAV1TileInfo;
293 |
294 | typedef struct StdVideoAV1CDEF {
295 | uint8_t cdef_damping_minus_3;
296 | uint8_t cdef_bits;
297 | uint8_t cdef_y_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS];
298 | uint8_t cdef_y_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS];
299 | uint8_t cdef_uv_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS];
300 | uint8_t cdef_uv_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS];
301 | } StdVideoAV1CDEF;
302 |
303 | typedef struct StdVideoAV1LoopRestoration {
304 | StdVideoAV1FrameRestorationType FrameRestorationType[STD_VIDEO_AV1_MAX_NUM_PLANES];
305 | uint16_t LoopRestorationSize[STD_VIDEO_AV1_MAX_NUM_PLANES];
306 | } StdVideoAV1LoopRestoration;
307 |
308 | typedef struct StdVideoAV1GlobalMotion {
309 | uint8_t GmType[STD_VIDEO_AV1_NUM_REF_FRAMES];
310 | int32_t gm_params[STD_VIDEO_AV1_NUM_REF_FRAMES][STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS];
311 | } StdVideoAV1GlobalMotion;
312 |
313 | typedef struct StdVideoAV1FilmGrainFlags {
314 | uint32_t chroma_scaling_from_luma : 1;
315 | uint32_t overlap_flag : 1;
316 | uint32_t clip_to_restricted_range : 1;
317 | uint32_t update_grain : 1;
318 | uint32_t reserved : 28;
319 | } StdVideoAV1FilmGrainFlags;
320 |
321 | typedef struct StdVideoAV1FilmGrain {
322 | StdVideoAV1FilmGrainFlags flags;
323 | uint8_t grain_scaling_minus_8;
324 | uint8_t ar_coeff_lag;
325 | uint8_t ar_coeff_shift_minus_6;
326 | uint8_t grain_scale_shift;
327 | uint16_t grain_seed;
328 | uint8_t film_grain_params_ref_idx;
329 | uint8_t num_y_points;
330 | uint8_t point_y_value[STD_VIDEO_AV1_MAX_NUM_Y_POINTS];
331 | uint8_t point_y_scaling[STD_VIDEO_AV1_MAX_NUM_Y_POINTS];
332 | uint8_t num_cb_points;
333 | uint8_t point_cb_value[STD_VIDEO_AV1_MAX_NUM_CB_POINTS];
334 | uint8_t point_cb_scaling[STD_VIDEO_AV1_MAX_NUM_CB_POINTS];
335 | uint8_t num_cr_points;
336 | uint8_t point_cr_value[STD_VIDEO_AV1_MAX_NUM_CR_POINTS];
337 | uint8_t point_cr_scaling[STD_VIDEO_AV1_MAX_NUM_CR_POINTS];
338 | int8_t ar_coeffs_y_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_LUMA];
339 | int8_t ar_coeffs_cb_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA];
340 | int8_t ar_coeffs_cr_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA];
341 | uint8_t cb_mult;
342 | uint8_t cb_luma_mult;
343 | uint16_t cb_offset;
344 | uint8_t cr_mult;
345 | uint8_t cr_luma_mult;
346 | uint16_t cr_offset;
347 | } StdVideoAV1FilmGrain;
348 |
349 | typedef struct StdVideoAV1SequenceHeaderFlags {
350 | uint32_t still_picture : 1;
351 | uint32_t reduced_still_picture_header : 1;
352 | uint32_t use_128x128_superblock : 1;
353 | uint32_t enable_filter_intra : 1;
354 | uint32_t enable_intra_edge_filter : 1;
355 | uint32_t enable_interintra_compound : 1;
356 | uint32_t enable_masked_compound : 1;
357 | uint32_t enable_warped_motion : 1;
358 | uint32_t enable_dual_filter : 1;
359 | uint32_t enable_order_hint : 1;
360 | uint32_t enable_jnt_comp : 1;
361 | uint32_t enable_ref_frame_mvs : 1;
362 | uint32_t frame_id_numbers_present_flag : 1;
363 | uint32_t enable_superres : 1;
364 | uint32_t enable_cdef : 1;
365 | uint32_t enable_restoration : 1;
366 | uint32_t film_grain_params_present : 1;
367 | uint32_t timing_info_present_flag : 1;
368 | uint32_t initial_display_delay_present_flag : 1;
369 | uint32_t reserved : 13;
370 | } StdVideoAV1SequenceHeaderFlags;
371 |
372 | typedef struct StdVideoAV1SequenceHeader {
373 | StdVideoAV1SequenceHeaderFlags flags;
374 | StdVideoAV1Profile seq_profile;
375 | uint8_t frame_width_bits_minus_1;
376 | uint8_t frame_height_bits_minus_1;
377 | uint16_t max_frame_width_minus_1;
378 | uint16_t max_frame_height_minus_1;
379 | uint8_t delta_frame_id_length_minus_2;
380 | uint8_t additional_frame_id_length_minus_1;
381 | uint8_t order_hint_bits_minus_1;
382 | uint8_t seq_force_integer_mv;
383 | uint8_t seq_force_screen_content_tools;
384 | uint8_t reserved1[5];
385 | const StdVideoAV1ColorConfig* pColorConfig;
386 | const StdVideoAV1TimingInfo* pTimingInfo;
387 | } StdVideoAV1SequenceHeader;
388 |
389 |
390 | #ifdef __cplusplus
391 | }
392 | #endif
393 |
394 | #endif
395 |
```