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 | ```