This is page 2 of 7. Use http://codebase.md/mehmetoguzderin/shaderc-vkrunner-mcp?page={x} to view the full context. # Directory Structure ``` ├── .devcontainer │ ├── devcontainer.json │ ├── docker-compose.yml │ └── Dockerfile ├── .gitattributes ├── .github │ └── workflows │ └── build-push-image.yml ├── .gitignore ├── .vscode │ └── mcp.json ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.adoc ├── shaderc-vkrunner-mcp.jpg ├── src │ └── main.rs └── vkrunner ├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── build.rs ├── Cargo.toml ├── COPYING ├── examples │ ├── compute-shader.shader_test │ ├── cooperative-matrix.shader_test │ ├── depth-buffer.shader_test │ ├── desc_set_and_binding.shader_test │ ├── entrypoint.shader_test │ ├── float-framebuffer.shader_test │ ├── frexp.shader_test │ ├── geometry.shader_test │ ├── indices.shader_test │ ├── layouts.shader_test │ ├── properties.shader_test │ ├── push-constants.shader_test │ ├── require-subgroup-size.shader_test │ ├── row-major.shader_test │ ├── spirv.shader_test │ ├── ssbo.shader_test │ ├── tolerance.shader_test │ ├── tricolore.shader_test │ ├── ubo.shader_test │ ├── vertex-data-piglit.shader_test │ └── vertex-data.shader_test ├── include │ ├── vk_video │ │ ├── vulkan_video_codec_av1std_decode.h │ │ ├── vulkan_video_codec_av1std_encode.h │ │ ├── vulkan_video_codec_av1std.h │ │ ├── vulkan_video_codec_h264std_decode.h │ │ ├── vulkan_video_codec_h264std_encode.h │ │ ├── vulkan_video_codec_h264std.h │ │ ├── vulkan_video_codec_h265std_decode.h │ │ ├── vulkan_video_codec_h265std_encode.h │ │ ├── vulkan_video_codec_h265std.h │ │ └── vulkan_video_codecs_common.h │ └── vulkan │ ├── vk_platform.h │ ├── vulkan_core.h │ └── vulkan.h ├── precompile-script.py ├── README.md ├── scripts │ └── update-vulkan.sh ├── src │ └── main.rs ├── test-build.sh └── vkrunner ├── allocate_store.rs ├── buffer.rs ├── compiler │ └── fake_process.rs ├── compiler.rs ├── config.rs ├── context.rs ├── enum_table.rs ├── env_var_test.rs ├── executor.rs ├── fake_vulkan.rs ├── features.rs ├── flush_memory.rs ├── format_table.rs ├── format.rs ├── half_float.rs ├── hex.rs ├── inspect.rs ├── lib.rs ├── logger.rs ├── make-enums.py ├── make-features.py ├── make-formats.py ├── make-pipeline-key-data.py ├── make-vulkan-funcs-data.py ├── parse_num.rs ├── pipeline_key_data.rs ├── pipeline_key.rs ├── pipeline_set.rs ├── requirements.rs ├── result.rs ├── script.rs ├── shader_stage.rs ├── slot.rs ├── small_float.rs ├── source.rs ├── stream.rs ├── temp_file.rs ├── tester.rs ├── tolerance.rs ├── util.rs ├── vbo.rs ├── vk.rs ├── vulkan_funcs_data.rs ├── vulkan_funcs.rs ├── window_format.rs └── window.rs ``` # Files -------------------------------------------------------------------------------- /vkrunner/vkrunner/allocate_store.rs: -------------------------------------------------------------------------------- ```rust // vkrunner // // Copyright (C) 2016, 2017, 2023 Neil Roberts // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice (including the next // paragraph) shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. //! Helper functions for allocating Vulkan device memory for a buffer //! or an image. use crate::context::Context; use crate::vk; use std::ptr; fn find_memory_type( context: &Context, mut usable_memory_types: u32, memory_type_flags: vk::VkMemoryPropertyFlags, ) -> Result<u32, String> { let memory_properties = context.memory_properties(); while usable_memory_types != 0 { let memory_type = usable_memory_types.trailing_zeros(); if memory_properties.memoryTypes[memory_type as usize].propertyFlags & memory_type_flags == memory_type_flags { return Ok(memory_type); } usable_memory_types &= !(1 << memory_type); } Err("Couldn’t find suitable memory type to allocate buffer".to_string()) } fn allocate_memory( context: &Context, reqs: &vk::VkMemoryRequirements, memory_type_flags: vk::VkMemoryPropertyFlags, ) -> Result<(vk::VkDeviceMemory, u32), String> { let memory_type_index = find_memory_type( context, reqs.memoryTypeBits, memory_type_flags, )?; let mut memory = vk::null_handle(); let allocate_info = vk::VkMemoryAllocateInfo { sType: vk::VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, pNext: ptr::null(), allocationSize: reqs.size, memoryTypeIndex: memory_type_index, }; let res = unsafe { context.device().vkAllocateMemory.unwrap()( context.vk_device(), ptr::addr_of!(allocate_info), ptr::null(), // allocator ptr::addr_of_mut!(memory), ) }; if res == vk::VK_SUCCESS { Ok((memory, memory_type_index)) } else { Err("vkAllocateMemory failed".to_string()) } } /// Allocate Vulkan device memory for the given buffer. It will pick /// the right memory type by querying the device for the memory /// requirements of the buffer. You can also limit the memory types /// further by specifying extra flags in `memory_type_flags`. A handle /// to the newly allocate device memory will be returned along with an /// index representing the chosen memory type. /// /// If the allocation fails a `String` will be returned describing the /// error. pub fn allocate_buffer( context: &Context, memory_type_flags: vk::VkMemoryPropertyFlags, buffer: vk::VkBuffer, ) -> Result<(vk::VkDeviceMemory, u32), String> { let vkdev = context.device(); let mut reqs = vk::VkMemoryRequirements::default(); unsafe { vkdev.vkGetBufferMemoryRequirements.unwrap()( context.vk_device(), buffer, ptr::addr_of_mut!(reqs), ); } let (memory, memory_type_index) = allocate_memory(context, &reqs, memory_type_flags)?; unsafe { vkdev.vkBindBufferMemory.unwrap()( context.vk_device(), buffer, memory, 0, // memoryOffset ); } Ok((memory, memory_type_index)) } /// Allocate Vulkan device memory for the given image. It will pick /// the right memory type by querying the device for the memory /// requirements of the image. You can also limit the memory types /// further by specifying extra flags in `memory_type_flags`. A handle /// to the newly allocate device memory will be returned along with an /// index representing the chosen memory type. /// /// If the allocation fails a `String` will be returned describing the /// error. pub fn allocate_image( context: &Context, memory_type_flags: vk::VkMemoryPropertyFlags, image: vk::VkImage, ) -> Result<(vk::VkDeviceMemory, u32), String> { let vkdev = context.device(); let mut reqs = vk::VkMemoryRequirements::default(); unsafe { vkdev.vkGetImageMemoryRequirements.unwrap()( context.vk_device(), image, ptr::addr_of_mut!(reqs), ); } let (memory, memory_type_index) = allocate_memory(context, &reqs, memory_type_flags)?; unsafe { vkdev.vkBindImageMemory.unwrap()( context.vk_device(), image, memory, 0, // memoryOffset ); } Ok((memory, memory_type_index)) } #[cfg(test)] mod test { use super::*; use crate::fake_vulkan::{FakeVulkan, HandleType}; use crate::requirements::Requirements; fn call_with_temp_buffer( fake_vulkan: &mut FakeVulkan, context: &Context, memory_type_flags: vk::VkMemoryPropertyFlags, ) -> Result<(vk::VkDeviceMemory, u32), String> { let buffer = fake_vulkan.add_handle( HandleType::Buffer { create_info: Default::default(), memory: None, } ); let res = allocate_buffer(context, memory_type_flags, buffer); fake_vulkan.get_handle_mut(buffer).freed = true; res } fn call_with_temp_image( fake_vulkan: &mut FakeVulkan, context: &Context, memory_type_flags: vk::VkMemoryPropertyFlags, ) -> Result<(vk::VkDeviceMemory, u32), String> { let image = fake_vulkan.add_handle(HandleType::Image); let res = allocate_image(context, memory_type_flags, image); fake_vulkan.get_handle_mut(image).freed = true; res } fn do_allocate_buffer( memory_property_flags: &[u32], memory_type_bits: u32, memory_type_flags: vk::VkMemoryPropertyFlags, ) -> Result<(vk::VkDeviceMemory, u32, Context, Box<FakeVulkan>), String> { let mut fake_vulkan = FakeVulkan::new(); fake_vulkan.physical_devices.push(Default::default()); let memory_properties = &mut fake_vulkan.physical_devices[0].memory_properties; for (i, &flags) in memory_property_flags.iter().enumerate() { memory_properties.memoryTypes[i].propertyFlags = flags; } memory_properties.memoryTypeCount = memory_property_flags.len() as u32; fake_vulkan.memory_requirements.memoryTypeBits = memory_type_bits; fake_vulkan.set_override(); let context = Context::new(&mut Requirements::new(), None).unwrap(); call_with_temp_buffer( &mut fake_vulkan, &context, memory_type_flags, ).map(|(memory, memory_type)| ( memory, memory_type, context, fake_vulkan, )) } #[test] fn find_memory() { let (device_memory, memory_type, context, fake_vulkan) = do_allocate_buffer( // Made-up set of memory properties &[ vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | vk::VK_MEMORY_PROPERTY_PROTECTED_BIT, vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ], // Pretend that the buffer can use types 0, 1 or 3 0b1011, // Pretend we need host visible and lazily allocated. This // means either of the last two vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, ).unwrap(); // Only 2 or 3 have the properties we need, but only 3 is // allowed for the buffer requirements. assert_eq!(memory_type, 3); unsafe { context.device().vkFreeMemory.unwrap()( context.vk_device(), device_memory, ptr::null(), // allocator ); } drop(context); drop(fake_vulkan); // Try with an impossible combination let err = do_allocate_buffer( &[ vk::VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, ], 0b1, vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | vk::VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, ).unwrap_err(); assert_eq!( err, "Couldn’t find suitable memory type to allocate buffer" ); } fn make_error_context() -> (Box<FakeVulkan>, Context) { let mut fake_vulkan = FakeVulkan::new(); fake_vulkan.physical_devices.push(Default::default()); fake_vulkan.physical_devices[0].memory_properties.memoryTypeCount = 1; fake_vulkan.memory_requirements.memoryTypeBits = 1; fake_vulkan.queue_result( "vkAllocateMemory".to_string(), vk::VK_ERROR_UNKNOWN ); fake_vulkan.set_override(); let context = Context::new(&mut Requirements::new(), None).unwrap(); (fake_vulkan, context) } #[test] fn buffer_error() { let (mut fake_vulkan, context) = make_error_context(); let err = call_with_temp_buffer( &mut fake_vulkan, &context, 0, // memory_type_flags ).unwrap_err(); assert_eq!(err, "vkAllocateMemory failed"); } #[test] fn image_error() { let (mut fake_vulkan, context) = make_error_context(); let err = call_with_temp_image( &mut fake_vulkan, &context, 0, // memory_type_flags ).unwrap_err(); assert_eq!(err, "vkAllocateMemory failed"); } #[test] fn image() { let mut fake_vulkan = FakeVulkan::new(); fake_vulkan.physical_devices.push(Default::default()); fake_vulkan.physical_devices[0].memory_properties.memoryTypeCount = 1; fake_vulkan.memory_requirements.memoryTypeBits = 1; fake_vulkan.set_override(); let context = Context::new(&mut Requirements::new(), None).unwrap(); let (device_memory, memory_type) = call_with_temp_image( &mut fake_vulkan, &context, 0, // memory_type_flags ).unwrap(); assert!(device_memory != vk::null_handle()); assert_eq!(memory_type, 0); unsafe { context.device().vkFreeMemory.unwrap()( context.vk_device(), device_memory, ptr::null(), // allocator ); } } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/pipeline_key_data.rs: -------------------------------------------------------------------------------- ```rust // Automatically generated by make-pipeline-key-data.py const N_BOOL_PROPERTIES: usize = 10; const N_INT_PROPERTIES: usize = 28; const N_FLOAT_PROPERTIES: usize = 6; const TOPOLOGY_PROP_NUM: usize = 0; const PATCH_CONTROL_POINTS_PROP_NUM: usize = 1; static PROPERTIES: [Property; 44] = [ Property { prop_type: PropertyType::Int, num: 11, name: "alphaBlendOp", }, Property { prop_type: PropertyType::Int, num: 25, name: "back.compareMask", }, Property { prop_type: PropertyType::Int, num: 24, name: "back.compareOp", }, Property { prop_type: PropertyType::Int, num: 23, name: "back.depthFailOp", }, Property { prop_type: PropertyType::Int, num: 21, name: "back.failOp", }, Property { prop_type: PropertyType::Int, num: 22, name: "back.passOp", }, Property { prop_type: PropertyType::Int, num: 27, name: "back.reference", }, Property { prop_type: PropertyType::Int, num: 26, name: "back.writeMask", }, Property { prop_type: PropertyType::Bool, num: 5, name: "blendEnable", }, Property { prop_type: PropertyType::Int, num: 8, name: "colorBlendOp", }, Property { prop_type: PropertyType::Int, num: 12, name: "colorWriteMask", }, Property { prop_type: PropertyType::Int, num: 3, name: "cullMode", }, Property { prop_type: PropertyType::Float, num: 1, name: "depthBiasClamp", }, Property { prop_type: PropertyType::Float, num: 0, name: "depthBiasConstantFactor", }, Property { prop_type: PropertyType::Bool, num: 3, name: "depthBiasEnable", }, Property { prop_type: PropertyType::Float, num: 2, name: "depthBiasSlopeFactor", }, Property { prop_type: PropertyType::Bool, num: 8, name: "depthBoundsTestEnable", }, Property { prop_type: PropertyType::Bool, num: 1, name: "depthClampEnable", }, Property { prop_type: PropertyType::Int, num: 13, name: "depthCompareOp", }, Property { prop_type: PropertyType::Bool, num: 6, name: "depthTestEnable", }, Property { prop_type: PropertyType::Bool, num: 7, name: "depthWriteEnable", }, Property { prop_type: PropertyType::Int, num: 10, name: "dstAlphaBlendFactor", }, Property { prop_type: PropertyType::Int, num: 7, name: "dstColorBlendFactor", }, Property { prop_type: PropertyType::Int, num: 18, name: "front.compareMask", }, Property { prop_type: PropertyType::Int, num: 17, name: "front.compareOp", }, Property { prop_type: PropertyType::Int, num: 16, name: "front.depthFailOp", }, Property { prop_type: PropertyType::Int, num: 14, name: "front.failOp", }, Property { prop_type: PropertyType::Int, num: 15, name: "front.passOp", }, Property { prop_type: PropertyType::Int, num: 20, name: "front.reference", }, Property { prop_type: PropertyType::Int, num: 19, name: "front.writeMask", }, Property { prop_type: PropertyType::Int, num: 4, name: "frontFace", }, Property { prop_type: PropertyType::Float, num: 3, name: "lineWidth", }, Property { prop_type: PropertyType::Int, num: 5, name: "logicOp", }, Property { prop_type: PropertyType::Bool, num: 4, name: "logicOpEnable", }, Property { prop_type: PropertyType::Float, num: 5, name: "maxDepthBounds", }, Property { prop_type: PropertyType::Float, num: 4, name: "minDepthBounds", }, Property { prop_type: PropertyType::Int, num: 1, name: "patchControlPoints", }, Property { prop_type: PropertyType::Int, num: 2, name: "polygonMode", }, Property { prop_type: PropertyType::Bool, num: 0, name: "primitiveRestartEnable", }, Property { prop_type: PropertyType::Bool, num: 2, name: "rasterizerDiscardEnable", }, Property { prop_type: PropertyType::Int, num: 9, name: "srcAlphaBlendFactor", }, Property { prop_type: PropertyType::Int, num: 6, name: "srcColorBlendFactor", }, Property { prop_type: PropertyType::Bool, num: 9, name: "stencilTestEnable", }, Property { prop_type: PropertyType::Int, num: 0, name: "topology", }, ]; fn copy_properties_to_create_info( key: &Key, s: &mut vk::VkGraphicsPipelineCreateInfo ) { { let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineInputAssemblyStateCreateInfo>(s.pInputAssemblyState) }; s.topology = key.int_properties[0] as vk::VkPrimitiveTopology; s.primitiveRestartEnable = key.bool_properties[0] as vk::VkBool32; } { let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineTessellationStateCreateInfo>(s.pTessellationState) }; s.patchControlPoints = key.int_properties[1] as u32; } { let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineRasterizationStateCreateInfo>(s.pRasterizationState) }; s.depthClampEnable = key.bool_properties[1] as vk::VkBool32; s.rasterizerDiscardEnable = key.bool_properties[2] as vk::VkBool32; s.polygonMode = key.int_properties[2] as vk::VkPolygonMode; s.cullMode = key.int_properties[3] as vk::VkCullModeFlags; s.frontFace = key.int_properties[4] as vk::VkFrontFace; s.depthBiasEnable = key.bool_properties[3] as vk::VkBool32; s.depthBiasConstantFactor = key.float_properties[0] as f32; s.depthBiasClamp = key.float_properties[1] as f32; s.depthBiasSlopeFactor = key.float_properties[2] as f32; s.lineWidth = key.float_properties[3] as f32; } { let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineColorBlendStateCreateInfo>(s.pColorBlendState) }; s.logicOpEnable = key.bool_properties[4] as vk::VkBool32; s.logicOp = key.int_properties[5] as vk::VkLogicOp; { let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineColorBlendAttachmentState>(s.pAttachments) }; s.blendEnable = key.bool_properties[5] as vk::VkBool32; s.srcColorBlendFactor = key.int_properties[6] as vk::VkBlendFactor; s.dstColorBlendFactor = key.int_properties[7] as vk::VkBlendFactor; s.colorBlendOp = key.int_properties[8] as vk::VkBlendOp; s.srcAlphaBlendFactor = key.int_properties[9] as vk::VkBlendFactor; s.dstAlphaBlendFactor = key.int_properties[10] as vk::VkBlendFactor; s.alphaBlendOp = key.int_properties[11] as vk::VkBlendOp; s.colorWriteMask = key.int_properties[12] as vk::VkColorComponentFlags; } } { let s = unsafe { std::mem::transmute::<_, &mut vk::VkPipelineDepthStencilStateCreateInfo>(s.pDepthStencilState) }; s.depthTestEnable = key.bool_properties[6] as vk::VkBool32; s.depthWriteEnable = key.bool_properties[7] as vk::VkBool32; s.depthCompareOp = key.int_properties[13] as vk::VkCompareOp; s.depthBoundsTestEnable = key.bool_properties[8] as vk::VkBool32; s.stencilTestEnable = key.bool_properties[9] as vk::VkBool32; s.front.failOp = key.int_properties[14] as vk::VkStencilOp; s.front.passOp = key.int_properties[15] as vk::VkStencilOp; s.front.depthFailOp = key.int_properties[16] as vk::VkStencilOp; s.front.compareOp = key.int_properties[17] as vk::VkCompareOp; s.front.compareMask = key.int_properties[18] as u32; s.front.writeMask = key.int_properties[19] as u32; s.front.reference = key.int_properties[20] as u32; s.back.failOp = key.int_properties[21] as vk::VkStencilOp; s.back.passOp = key.int_properties[22] as vk::VkStencilOp; s.back.depthFailOp = key.int_properties[23] as vk::VkStencilOp; s.back.compareOp = key.int_properties[24] as vk::VkCompareOp; s.back.compareMask = key.int_properties[25] as u32; s.back.writeMask = key.int_properties[26] as u32; s.back.reference = key.int_properties[27] as u32; s.minDepthBounds = key.float_properties[4] as f32; s.maxDepthBounds = key.float_properties[5] as f32; } } impl Default for Key { fn default() -> Key { Key { pipeline_type: Type::Graphics, source: Source::Rectangle, entrypoints: Default::default(), bool_properties: [ false, // primitiveRestartEnable false, // depthClampEnable false, // rasterizerDiscardEnable false, // depthBiasEnable false, // logicOpEnable false, // blendEnable false, // depthTestEnable false, // depthWriteEnable false, // depthBoundsTestEnable false, // stencilTestEnable ], int_properties: [ vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP as i32, // topology 0 as i32, // patchControlPoints vk::VK_POLYGON_MODE_FILL as i32, // polygonMode vk::VK_CULL_MODE_NONE as i32, // cullMode vk::VK_FRONT_FACE_COUNTER_CLOCKWISE as i32, // frontFace vk::VK_LOGIC_OP_SET as i32, // logicOp vk::VK_BLEND_FACTOR_SRC_ALPHA as i32, // srcColorBlendFactor vk::VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA as i32, // dstColorBlendFactor vk::VK_BLEND_OP_ADD as i32, // colorBlendOp vk::VK_BLEND_FACTOR_SRC_ALPHA as i32, // srcAlphaBlendFactor vk::VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA as i32, // dstAlphaBlendFactor vk::VK_BLEND_OP_ADD as i32, // alphaBlendOp (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 vk::VK_COMPARE_OP_LESS as i32, // depthCompareOp vk::VK_STENCIL_OP_KEEP as i32, // front.failOp vk::VK_STENCIL_OP_KEEP as i32, // front.passOp vk::VK_STENCIL_OP_KEEP as i32, // front.depthFailOp vk::VK_COMPARE_OP_ALWAYS as i32, // front.compareOp u32::MAX as i32, // front.compareMask u32::MAX as i32, // front.writeMask 0 as i32, // front.reference vk::VK_STENCIL_OP_KEEP as i32, // back.failOp vk::VK_STENCIL_OP_KEEP as i32, // back.passOp vk::VK_STENCIL_OP_KEEP as i32, // back.depthFailOp vk::VK_COMPARE_OP_ALWAYS as i32, // back.compareOp u32::MAX as i32, // back.compareMask u32::MAX as i32, // back.writeMask 0 as i32, // back.reference ], float_properties: [ 0.0, // depthBiasConstantFactor 0.0, // depthBiasClamp 0.0, // depthBiasSlopeFactor 1.0, // lineWidth 0.0, // minDepthBounds 0.0, // maxDepthBounds ], } } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/hex.rs: -------------------------------------------------------------------------------- ```rust // Copyright (c) The Piglit project 2007 // Copyright 2023 Neil Roberts // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // on the rights to use, copy, modify, merge, publish, distribute, sub // license, and/or sell copies of the Software, and to permit persons to whom // the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice (including the next // paragraph) shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL // VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. use crate::half_float; use std::num::{ParseFloatError, ParseIntError}; use std::fmt; use std::convert::From; // Based on functions from piglit-util.c #[derive(Debug)] pub enum ParseError { Float(ParseFloatError), Int(ParseIntError), } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { ParseError::Float(e) => e.fmt(f), ParseError::Int(e) => e.fmt(f), } } } impl From<ParseFloatError> for ParseError { fn from(e: ParseFloatError) -> ParseError { ParseError::Float(e) } } impl From<ParseIntError> for ParseError { fn from(e: ParseIntError) -> ParseError { ParseError::Int(e) } } // Similar to haystack.starts_with(needle) but the ASCII characters of // haystack are converted to lower case before comparing. The needle // value should already be in lowercase for this to work. fn starts_with_ignore_case(haystack: &str, needle: &str) -> bool { let mut haystack_chars = haystack.chars(); for needle_c in needle.chars() { match haystack_chars.next() { None => return false, Some(haystack_c) => if haystack_c.to_ascii_lowercase() != needle_c { return false; }, } } true } // Checks whether the string slice starts with one of the special // words allowed in a float string. If so it returns the length of the // word, otherwise it returns None. fn starts_with_float_special_word(s: &str) -> Option<usize> { for word in ["infinity", "inf", "nan"] { if starts_with_ignore_case(s, word) { return Some(word.len()); } } None } // Checks whether the string starts with a valid Number part of a // float. If so it returns the byte length, otherwise it returns None. fn count_number(s: &str) -> Option<usize> { // Optional units let before_digits = count_digits(s); let num_end = &s[before_digits..]; // Optional decimal let after_digits; let n_points; if let Some('.') = num_end.chars().next() { n_points = 1; let digits = &num_end[1..]; after_digits = count_digits(digits); } else { n_points = 0; after_digits = 0; } // Either the units or the decimal must be present if before_digits > 0 || after_digits > 0 { Some(before_digits + n_points + after_digits) } else { None } } // Returns how many ASCII digits are at the start of the string fn count_digits(s: &str) -> usize { s.chars().take_while(char::is_ascii_digit).count() } // Checks whether the strings starts with a valid Exp part of a float. // If so it returns the byte length, otherwise it returns None. fn count_exp(s: &str) -> Option<usize> { if let Some('E' | 'e') = s.chars().next() { let mut count = 1; if let Some('+' | '-') = s[count..].chars().next() { count += 1; } let digits = count_digits(&s[count..]); if digits > 0 { Some(count + digits) } else { None } } else { None } } // It looks like the rust float parsing functions don’t have an // equivalent of the `endptr` argument to `strtod`. This function // tries to work around that by extracting the float part and the rest // of the string and returning the two string slices as a tuple. It also // skips leading spaces. fn split_parts(mut s: &str) -> (&str, &str) { // skip only ASCII spaces and tabs while !s.is_empty() && (s.as_bytes()[0] == b' ' || s.as_bytes()[0] == b'\t') { s = &s[1..]; } let mut split_point = 0; if s.starts_with("0x") { split_point = 2 + s[2..] .chars() .take_while(char::is_ascii_hexdigit) .count(); } else { // Optional sign if let Some('-' | '+') = s[split_point..].chars().next() { split_point += 1; } if let Some(len) = starts_with_float_special_word(&s[split_point..]) { split_point += len; } else if let Some(len) = count_number(&s[split_point..]) { split_point += len; if let Some(len) = count_exp(&s[split_point..]) { split_point += len; } } } (&s[0..split_point], &s[split_point..]) } // Wrapper for str.parse<f32> which allows using an exact hex bit // pattern to generate a float value and ignores trailing data. // // If the parsing works, it will return a tuple with the floating // point value and a string slice pointing to the rest of the string. pub fn parse_f32(s: &str) -> Result<(f32, &str), ParseError> { let (s, tail) = split_parts(s); if s.starts_with("0x") { Ok((f32::from_bits(u32::from_str_radix(&s[2..], 16)?), tail)) } else { Ok((s.parse::<f32>()?, tail)) } } // Wrapper for str.parse<f64> which allows using an exact hex bit // pattern to generate a float value and ignores trailing data. // // If the parsing works, it will return a tuple with the floating // point value and a string slice pointing to the rest of the string. pub fn parse_f64(s: &str) -> Result<(f64, &str), ParseError> { let (s, tail) = split_parts(s); if s.starts_with("0x") { Ok((f64::from_bits(u64::from_str_radix(&s[2..], 16)?), tail)) } else { Ok((s.parse::<f64>()?, tail)) } } // Wrapper for calling half_float::from_f32 on the result of parsing to the // string to a float but that also allows specifying the value exactly // as a hexadecimal number. // // If the parsing works, it will return a tuple with the half float // value and a string slice pointing to the rest of the string. pub fn parse_half_float(s: &str) -> Result<(u16, &str), ParseError> { let (s, tail) = split_parts(s); if s.starts_with("0x") { Ok((u16::from_str_radix(&s[2..], 16)?, tail)) } else { Ok((half_float::from_f32(s.parse::<f32>()?), tail)) } } #[cfg(test)] mod test { use super::*; #[test] fn test_split_parts() { // Skip spaces and tabs assert_eq!(split_parts(" 0"), ("0", "")); assert_eq!(split_parts(" \t 0"), ("0", "")); // Don’t skip other whitespace characters assert_eq!(split_parts(" \n 0"), ("", "\n 0")); // Hex digits assert_eq!(split_parts("0xCafeCafeTEA"), ("0xCafeCafe", "TEA")); // Signs assert_eq!(split_parts("+42 cupcakes"), ("+42", " cupcakes")); assert_eq!(split_parts("-42 gerbils"), ("-42", " gerbils")); // Special words assert_eq!(split_parts("+infinity forever"), ("+infinity", " forever")); assert_eq!(split_parts("INf forever"), ("INf", " forever")); assert_eq!(split_parts(" -NaN fornever"), ("-NaN", " fornever")); assert_eq!(split_parts("infin"), ("inf", "in")); assert_eq!(split_parts("NaN12"), ("NaN", "12")); // Normal numbers assert_eq!(split_parts("12.2"), ("12.2", "")); assert_eq!(split_parts("-12.2"), ("-12.2", "")); assert_eq!(split_parts("12.2e6"), ("12.2e6", "")); assert_eq!(split_parts("12.2E6"), ("12.2E6", "")); assert_eq!(split_parts("12.E6"), ("12.E6", "")); assert_eq!(split_parts("12.E-6"), ("12.E-6", "")); assert_eq!(split_parts("12.E+6"), ("12.E+6", "")); assert_eq!(split_parts(".0"), (".0", "")); assert_eq!(split_parts("5."), ("5.", "")); assert_eq!(split_parts(".5e6"), (".5e6", "")); assert_eq!(split_parts("5.e6"), ("5.e6", "")); // At least one side of the decimal point must be specified assert_eq!(split_parts("+."), ("+", ".")); // The exponent must have some digits assert_eq!(split_parts("12e"), ("12", "e")); assert_eq!(split_parts("12e-"), ("12", "e-")); // Can’t have the exponent on its own assert_eq!(split_parts("e12"), ("", "e12")); } fn float_matches<T: Into<f64>>( res: Result<(T, &str), ParseError>, expected_value: T, expected_tail: &str ) { let (value, tail) = res.unwrap(); let value = value.into(); let expected_value = expected_value.into(); assert!((value - expected_value).abs() < 0.0001, "value={}, expected_value={}", value, expected_value); assert_eq!(expected_tail, tail); } #[test] fn test_parse_f32() { float_matches(parse_f32("1.0"), 1.0, ""); float_matches(parse_f32(" \t 1.0"), 1.0, ""); float_matches(parse_f32("-1.0"), -1.0, ""); float_matches(parse_f32("+1.0"), 1.0, ""); float_matches(parse_f32("42 monkies"), 42.0, " monkies"); float_matches(parse_f32("0x0"), 0.0, ""); assert_eq!(parse_f32("0x7f800000").unwrap().0, f32::INFINITY); assert_eq!(parse_f32("-inf").unwrap(), (-f32::INFINITY, "")); assert_eq!(parse_f32("infinity 12").unwrap(), (f32::INFINITY, " 12")); assert!(parse_f32("NaN").unwrap().0.is_nan()); assert!(matches!( parse_f32(""), Err(ParseError::Float(ParseFloatError { .. })) )); assert!(matches!( parse_f32("0xaaaaaaaaa"), Err(ParseError::Int(ParseIntError { .. })) )); } #[test] fn test_parse_f64() { float_matches(parse_f64("1.0"), 1.0, ""); float_matches(parse_f64("42 monkies"), 42.0, " monkies"); float_matches(parse_f64("0x0"), 0.0, ""); assert_eq!(parse_f64("0xfff0000000000000").unwrap().0, -f64::INFINITY); assert_eq!(parse_f64("-inf").unwrap(), (-f64::INFINITY, "")); assert_eq!(parse_f64("infinity 12").unwrap(), (f64::INFINITY, " 12")); assert!(parse_f64("NaN").unwrap().0.is_nan()); assert!(matches!( parse_f64(""), Err(ParseError::Float(ParseFloatError { .. })) )); assert!(matches!( parse_f64("0xaaaaaaaaaaaaaaaaa"), Err(ParseError::Int(ParseIntError { .. })) )); } #[test] fn test_parse_half_float() { assert_eq!(parse_half_float("1.0").unwrap(), (0x3c00, "")); assert_eq!(parse_half_float("0x7bff").unwrap(), (0x7bff, "")); assert_eq!(parse_half_float("0x7c00").unwrap(), (0x7c00, "")); assert_eq!( parse_half_float("infinity 12").unwrap(), (0x7c00, " 12") ); assert!(matches!( parse_half_float(""), Err(ParseError::Float(ParseFloatError { .. })) )); assert!(matches!( parse_half_float("0xffff1"), Err(ParseError::Int(ParseIntError { .. })) )); } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/make-pipeline-key-data.py: -------------------------------------------------------------------------------- ```python #!/usr/bin/python3 # Copyright 2023 Neil Roberts # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # This script is used to generate pipeline_key_data.rs. It is not run # automatically as part of the build process but if need be it can be # used to update the file as follows: # # ./make-pipeline-key-data.py > pipeline_key_data.rs from mako.template import Template TEMPLATE="""\ // Automatically generated by make-pipeline-key-data.py const N_BOOL_PROPERTIES: usize = ${sum(1 for p in props if p.base_type == "bool")}; const N_INT_PROPERTIES: usize = ${sum(1 for p in props if p.base_type == "int")}; const N_FLOAT_PROPERTIES: usize = ${sum(1 for p in props if p.base_type == "float")}; const TOPOLOGY_PROP_NUM: usize = ${next(p for p in props if p.name == "topology").num}; const PATCH_CONTROL_POINTS_PROP_NUM: usize = ${ next(p for p in props if p.name == "patchControlPoints").num}; static PROPERTIES: [Property; ${len(props)}] = [ % for prop in sorted(props, key=lambda p: p.name): Property { prop_type: PropertyType::${prop.base_type.capitalize()}, num: ${prop.num}, name: "${prop.name}", }, % endfor ]; fn copy_properties_to_create_info( key: &Key, s: &mut vk::VkGraphicsPipelineCreateInfo ) { ${setters} } impl Default for Key { fn default() -> Key { Key { pipeline_type: Type::Graphics, source: Source::Rectangle, entrypoints: Default::default(), bool_properties: [ % for prop in sorted(props, key=lambda p: p.num): % if prop.base_type == "bool": ${prop.default}, // ${prop.name} % endif % endfor ], int_properties: [ % for prop in sorted(props, key=lambda p: p.num): % if prop.base_type == "int": ${prop.default} as i32, // ${prop.name} % endif % endfor ], float_properties: [ % for prop in sorted(props, key=lambda p: p.num): % if prop.base_type == "float": ${prop.default}, // ${prop.name} % endif % endfor ], } } } """ class Structure: def __init__(self, name, variable, children): self.name = name self.variable = variable self.children = children class Property: def __init__(self, vk_type, name, default): self.vk_type = vk_type self.base_type = vk_type_as_base_type(vk_type) self.name = name self.default = default class Properties: def __init__(self): self.values = [] self.counts = {} def add(self, prop): base_type = prop.base_type try: self.counts[base_type] += 1 except KeyError: self.counts[base_type] = 1 prop.num = self.counts[base_type] - 1 self.values.append(prop) def vk_type_as_base_type(vk_type): if vk_type == "vk::VkBool32": return "bool" elif vk_type == "f32": return "float" elif vk_type == "u32": return "int" elif vk_type.startswith("vk::Vk"): return "int" raise ValueError("Unsupported Vulkan type: {}".format(vk_type)) STRUCTURES = [ Structure("VkPipelineInputAssemblyStateCreateInfo", "pInputAssemblyState", [ Property("vk::VkPrimitiveTopology", "topology", "vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP"), Property("vk::VkBool32", "primitiveRestartEnable", "false"), ]), Structure("VkPipelineTessellationStateCreateInfo", "pTessellationState", [ Property("u32", "patchControlPoints", "0"), ]), Structure("VkPipelineRasterizationStateCreateInfo", "pRasterizationState", [ Property("vk::VkBool32", "depthClampEnable", "false"), Property("vk::VkBool32", "rasterizerDiscardEnable", "false"), Property("vk::VkPolygonMode", "polygonMode", "vk::VK_POLYGON_MODE_FILL"), Property("vk::VkCullModeFlags", "cullMode", "vk::VK_CULL_MODE_NONE"), Property("vk::VkFrontFace", "frontFace", "vk::VK_FRONT_FACE_COUNTER_CLOCKWISE"), Property("vk::VkBool32", "depthBiasEnable", "false"), Property("f32", "depthBiasConstantFactor", "0.0"), Property("f32", "depthBiasClamp", "0.0"), Property("f32", "depthBiasSlopeFactor", "0.0"), Property("f32", "lineWidth", "1.0"), ]), Structure("VkPipelineColorBlendStateCreateInfo", "pColorBlendState", [ Property("vk::VkBool32", "logicOpEnable", "false"), Property("vk::VkLogicOp", "logicOp", "vk::VK_LOGIC_OP_SET"), Structure("VkPipelineColorBlendAttachmentState", "pAttachments", [ Property("vk::VkBool32", "blendEnable", "false"), Property("vk::VkBlendFactor", "srcColorBlendFactor", "vk::VK_BLEND_FACTOR_SRC_ALPHA"), Property("vk::VkBlendFactor", "dstColorBlendFactor", "vk::VK_BLEND_FACTOR_" "ONE_MINUS_SRC_ALPHA"), Property("vk::VkBlendOp", "colorBlendOp", "vk::VK_BLEND_OP_ADD"), Property("vk::VkBlendFactor", "srcAlphaBlendFactor", "vk::VK_BLEND_FACTOR_SRC_ALPHA"), Property("vk::VkBlendFactor", "dstAlphaBlendFactor", "vk::VK_BLEND_FACTOR_" "ONE_MINUS_SRC_ALPHA"), Property("vk::VkBlendOp", "alphaBlendOp", "vk::VK_BLEND_OP_ADD"), Property("vk::VkColorComponentFlags", "colorWriteMask", "(vk::VK_COLOR_COMPONENT_R_BIT | " "vk::VK_COLOR_COMPONENT_G_BIT | " "vk::VK_COLOR_COMPONENT_B_BIT | " "vk::VK_COLOR_COMPONENT_A_BIT)"), ]), ]), Structure("VkPipelineDepthStencilStateCreateInfo", "pDepthStencilState", [ Property("vk::VkBool32", "depthTestEnable", "false"), Property("vk::VkBool32", "depthWriteEnable", "false"), Property("vk::VkCompareOp", "depthCompareOp", "vk::VK_COMPARE_OP_LESS"), Property("vk::VkBool32", "depthBoundsTestEnable", "false"), Property("vk::VkBool32", "stencilTestEnable", "false"), Property("vk::VkStencilOp", "front.failOp", "vk::VK_STENCIL_OP_KEEP"), Property("vk::VkStencilOp", "front.passOp", "vk::VK_STENCIL_OP_KEEP"), Property("vk::VkStencilOp", "front.depthFailOp", "vk::VK_STENCIL_OP_KEEP"), Property("vk::VkCompareOp", "front.compareOp", "vk::VK_COMPARE_OP_ALWAYS"), Property("u32", "front.compareMask", "u32::MAX"), Property("u32", "front.writeMask", "u32::MAX"), Property("u32", "front.reference", "0"), Property("vk::VkStencilOp", "back.failOp", "vk::VK_STENCIL_OP_KEEP"), Property("vk::VkStencilOp", "back.passOp", "vk::VK_STENCIL_OP_KEEP"), Property("vk::VkStencilOp", "back.depthFailOp", "vk::VK_STENCIL_OP_KEEP"), Property("vk::VkCompareOp", "back.compareOp", "vk::VK_COMPARE_OP_ALWAYS"), Property("u32", "back.compareMask", "u32::MAX"), Property("u32", "back.writeMask", "u32::MAX"), Property("u32", "back.reference", "0"), Property("f32", "minDepthBounds", "0.0"), Property("f32", "maxDepthBounds", "0.0"), ]) ] def get_props(structure, props): for child in structure.children: if isinstance(child, Property): props.add(child) elif isinstance(child, Structure): get_props(child, props) else: raise Exception("STRUCTURES array is broken") def make_setters(structure): parts = [] parts.append(" {") parts.append(" let s = unsafe {{ " "std::mem::transmute::<_, &mut vk::{}>(s.{}) }};".format( structure.name, structure.variable)) for child in structure.children: if isinstance(child, Structure): parts.extend(map(lambda line: " " + line, make_setters(child))) elif isinstance(child, Property): parts.append(" s.{} = key.{}_properties[{}] as {};".format( child.name, child.base_type, child.num, child.vk_type)) parts.append(" }") return parts def main(): template = Template(TEMPLATE) props = Properties() for structure in STRUCTURES: get_props(structure, props) setters = "\n".join(sum(map(make_setters, STRUCTURES), start=[])) print(template.render(props = props.values, setters = setters)) if __name__ == '__main__': main() ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/stream.rs: -------------------------------------------------------------------------------- ```rust // vkrunner // // Copyright (C) 2018 Intel Corporation // Copyright 2023 Neil Roberts // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice (including the next // paragraph) shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. use crate::source; use std::io; use std::io::BufRead; use std::fmt; use std::fs; // Encapsulates the two possible buf readers (either from a file or // from a string) that the stream will use. I don’t think we can put // this behind a boxed trait object because we can’t tell Rust that // the box won’t outlive the Stream object. #[derive(Debug)] enum Reader<'a> { File(io::BufReader<fs::File>), String(io::BufReader<&'a [u8]>), } /// A struct used to read lines from a [Source](source::Source). This /// will handle concatening lines that end with the line continuation /// character (`\`) and the token replacements. #[derive(Debug)] pub struct Stream<'a> { source: &'a source::Source, reader: Reader<'a>, line_num: usize, next_line_num: usize, reached_eof: bool, } /// An error that can be returned from [Stream::read_line] or [Stream::new]. #[derive(Debug)] pub enum StreamError { IoError(io::Error), /// A token replacement causes an infinite loop of replacements to /// occur. TokenReplacementLoop, } impl fmt::Display for StreamError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { StreamError::IoError(e) => e.fmt(f), StreamError::TokenReplacementLoop => { write!(f, "The token replacements cause an infinite loop") }, } } } impl std::convert::From<io::Error> for StreamError { fn from(value: io::Error) -> StreamError { StreamError::IoError(value) } } impl<'a> Stream<'a> { /// Constructs a new [Stream] that will read lines from the given /// [Source](source::Source). The construction can fail if the /// stream is a file source and opening the file fails. In that /// case the returned [StreamError] will contain an /// [io::Error](std::io::Error). pub fn new(source: &source::Source) -> Result<Stream, StreamError> { let reader = match source.data() { source::Data::File { filename } => { let file = fs::File::open(filename)?; Reader::File(io::BufReader::new(file)) }, source::Data::String { source } => { Reader::String(io::BufReader::new(source.as_bytes())) }, }; Ok(Stream { source, reader, line_num: 0, next_line_num: 1, reached_eof: false, }) } /// Read a line from the stream and append it to the given String. /// This will handle the line continuation characters (`\`) and /// the token replacements set on the [Source](source::Source). /// /// The length of the data appended to the string is returned. If /// the end of the source is reached then it will return 0. pub fn read_line( &mut self, line: &mut String ) -> Result<usize, StreamError> { let start_length = line.len(); self.line_num = self.next_line_num; while !self.reached_eof { let length = match &mut self.reader { Reader::File(r) => r.read_line(line)?, Reader::String(r) => r.read_line(line)?, }; if length == 0 { self.reached_eof = true; break; } self.next_line_num += 1; if length >= 2 { if line.ends_with("\\\n") { line.truncate(line.len() - 2); continue; } else if length >= 3 && line.ends_with("\\\r\n") { line.truncate(line.len() - 3); continue; } } break; } self.process_token_replacements(line, start_length)?; Ok(line.len() - start_length) } /// Returns the line number in the source data of the start of the /// last line that was returned by [read_line](Stream::read_line). /// For example, if the source file is like this: /// /// ```text /// line one \ /// continuation of line one. /// line two \ /// continuation of line two. /// ``` /// /// then the second time `read_line` is called it will append /// “line two continuation of line two” and /// [line_num](Stream::line_num) will report 3 because the line /// starts on the third line of the source data. pub fn line_num(&self) -> usize { self.line_num } fn process_token_replacements( &self, line: &mut String, start_pos: usize ) -> Result<(), StreamError> { let mut count = 0usize; // Loop through each valid position in the line string. We // can’t safely use an iterator because we’re going to modify // the string as we iterate let mut pos = start_pos; while pos < line.len() { 'token_loop: loop { for token_replacement in self.source.token_replacements() { if line[pos..].starts_with(&token_replacement.token) { count += 1; // If we’ve replaced at least 1000 tokens then // something has probably gone wrong and this // is never going to finish. if count >= 1000 { return Err(StreamError::TokenReplacementLoop); } line.replace_range( pos..pos + token_replacement.token.len(), &token_replacement.replacement, ); // Start looking for tokens from the start of // the list in case the replacement contains // one of the earlier tokens continue 'token_loop; } } break 'token_loop; } // Move to the next character. It would be nice if we // could do this by just looking at the first byte of the // UTF-8 sequence but there doesn’t seem to be a handy // Rust API for that. pos += line[pos..].chars().next().unwrap().len_utf8(); } Ok(()) } } #[cfg(test)] mod test { use super::*; #[test] fn test_line_continuation() { let source = source::Source::from_string( "line one \\\n\ more line one\n\ line three \\\n\ is really long \\\n\ \\\n\ and even has blank lines".to_string() ); let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); assert_eq!(stream.read_line(&mut line).unwrap(), 23); assert_eq!(line, "line one more line one\n"); assert_eq!(stream.line_num(), 1); assert_eq!(stream.read_line(&mut line).unwrap(), 50); assert_eq!( &line[23..], "line three is really long and even has blank lines", ); assert_eq!(stream.line_num(), 3); // The line can also be continued if it has Windows-style line endings let source = source::Source::from_string( "line one \\\r\n\ more line one\n\ line three \r what".to_string() ); let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); assert_eq!(stream.read_line(&mut line).unwrap(), 23); assert_eq!(line, "line one more line one\n"); assert_eq!(stream.line_num(), 1); line.clear(); assert_eq!(stream.read_line(&mut line).unwrap(), 17); assert_eq!(line, "line three \r what"); assert_eq!(stream.line_num(), 3); // Backslashes in the middle of the string should just be left alone let source = source::Source::from_string( "I am happy \\o//".to_string() ); let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); assert_eq!(stream.read_line(&mut line).unwrap(), 15); assert_eq!(line, "I am happy \\o//"); } #[test] fn test_missing_file() { let source = source::Source::from_file( "this-file-does-not-exist".to_string().into() ); let e = Stream::new(&source).unwrap_err(); match e { StreamError::IoError(e) => { assert_eq!(e.kind(), io::ErrorKind::NotFound); }, _ => unreachable!("expected StreamError::IoError, got: {}", e), } } fn run_test_file_source(filename: String) { fs::write(&filename, "my source code").unwrap(); let source = source::Source::from_file(filename.into()); let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); assert_eq!(stream.read_line(&mut line).unwrap(), 14); assert_eq!(line, "my source code"); // EOF should return 0 assert_eq!(stream.read_line(&mut line).unwrap(), 0); // It should also work a second time assert_eq!(stream.read_line(&mut line).unwrap(), 0); } #[test] fn test_file_source() { let mut filename = std::env::temp_dir(); filename.push("vkrunner-test-file-source"); let filename_str = filename.to_str().unwrap().to_owned(); // Catch the unwind to try to remove the file that we created // if the test fails let r = std::panic::catch_unwind( move || run_test_file_source(filename_str) ); if let Err(e) = fs::remove_file(filename) { assert_eq!(e.kind(), io::ErrorKind::NotFound); } if let Err(e) = r { std::panic::resume_unwind(e); } } macro_rules! replace_tokens { ($source:expr, $expected:expr, $($token:expr, $replacement:expr),*) => { let mut source = source::Source::from_string($source.to_owned()); $( { source.add_token_replacement( $token.to_owned(), $replacement.to_owned() ); } )*; let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); assert_eq!(stream.read_line(&mut line).unwrap(), $expected.len()); assert_eq!(line, $expected); }; } #[test] fn test_token_replacements() { // Simple replacement replace_tokens!( "one two", "1 2", "one", "1", "two", "2" ); // Line continuation within a replacement replace_tokens!( "tok\\\n\ ens are neat", "replacements are neat", "token", "replacement" ); // Chain of replacements replace_tokens!( "I like this", "I like tomatoes", "this", "thatthing", "that", "t", "thing", "omatoes" ); let mut source = source::Source::from_string( "Infinite recursion!".to_string() ); source.add_token_replacement( "recursion".to_string(), "deeper".to_string(), ); source.add_token_replacement( "deeper".to_string(), "keep-going".to_string(), ); source.add_token_replacement( "keep-going".to_string(), "recursion".to_string(), ); let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); let e = stream.read_line(&mut line).unwrap_err(); assert!(matches!(e, StreamError::TokenReplacementLoop)); assert_eq!( e.to_string(), "The token replacements cause an infinite loop" ); // Try an empty token let mut source = source::Source::from_string( "Infinite recursion!".to_string() ); source.add_token_replacement( "".to_string(), "ever longer".to_string(), ); let mut stream = Stream::new(&source).unwrap(); let mut line = String::new(); let e = stream.read_line(&mut line).unwrap_err(); assert!(matches!(e, StreamError::TokenReplacementLoop)); } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/features.rs: -------------------------------------------------------------------------------- ```rust // Automatically generated by make-features.py static EXTENSIONS: [Extension; 29] = [ Extension { name_bytes: vk::VK_KHR_16BIT_STORAGE_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDevice16BitStorageFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, features: &[ "storageBuffer16BitAccess", "uniformAndStorageBuffer16BitAccess", "storagePushConstant16", "storageInputOutput16", ], }, Extension { name_bytes: vk::VK_KHR_8BIT_STORAGE_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDevice8BitStorageFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, features: &[ "storageBuffer8BitAccess", "uniformAndStorageBuffer8BitAccess", "storagePushConstant8", ], }, Extension { name_bytes: vk::VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceASTCDecodeFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT, features: &[ "decodeModeSharedExponent", ], }, Extension { name_bytes: vk::VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT, features: &[ "advancedBlendCoherentOperations", ], }, Extension { name_bytes: vk::VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceBufferDeviceAddressFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, features: &[ "bufferDeviceAddress", "bufferDeviceAddressCaptureReplay", "bufferDeviceAddressMultiDevice", ], }, Extension { name_bytes: vk::VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR, features: &[ "computeDerivativeGroupQuads", "computeDerivativeGroupLinear", ], }, Extension { name_bytes: vk::VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceConditionalRenderingFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT, features: &[ "conditionalRendering", "inheritedConditionalRendering", ], }, Extension { name_bytes: vk::VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceCornerSampledImageFeaturesNV>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV, features: &[ "cornerSampledImage", ], }, Extension { name_bytes: vk::VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT, features: &[ "shaderInputAttachmentArrayDynamicIndexing", "shaderUniformTexelBufferArrayDynamicIndexing", "shaderStorageTexelBufferArrayDynamicIndexing", "shaderUniformBufferArrayNonUniformIndexing", "shaderSampledImageArrayNonUniformIndexing", "shaderStorageBufferArrayNonUniformIndexing", "shaderStorageImageArrayNonUniformIndexing", "shaderInputAttachmentArrayNonUniformIndexing", "shaderUniformTexelBufferArrayNonUniformIndexing", "shaderStorageTexelBufferArrayNonUniformIndexing", "descriptorBindingUniformBufferUpdateAfterBind", "descriptorBindingSampledImageUpdateAfterBind", "descriptorBindingStorageImageUpdateAfterBind", "descriptorBindingStorageBufferUpdateAfterBind", "descriptorBindingUniformTexelBufferUpdateAfterBind", "descriptorBindingStorageTexelBufferUpdateAfterBind", "descriptorBindingUpdateUnusedWhilePending", "descriptorBindingPartiallyBound", "descriptorBindingVariableDescriptorCount", "runtimeDescriptorArray", ], }, Extension { name_bytes: vk::VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceExclusiveScissorFeaturesNV>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV, features: &[ "exclusiveScissor", ], }, Extension { name_bytes: vk::VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceShaderFloat16Int8FeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, features: &[ "shaderFloat16", "shaderInt8", ], }, Extension { name_bytes: vk::VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceFragmentDensityMapFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT, features: &[ "fragmentDensityMap", "fragmentDensityMapDynamic", "fragmentDensityMapNonSubsampledImages", ], }, Extension { name_bytes: vk::VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR, features: &[ "fragmentShaderBarycentric", ], }, Extension { name_bytes: vk::VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceInlineUniformBlockFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT, features: &[ "inlineUniformBlock", "descriptorBindingInlineUniformBlockUpdateAfterBind", ], }, Extension { name_bytes: vk::VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceMemoryPriorityFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT, features: &[ "memoryPriority", ], }, Extension { name_bytes: vk::VK_NV_MESH_SHADER_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceMeshShaderFeaturesNV>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV, features: &[ "taskShader", "meshShader", ], }, Extension { name_bytes: vk::VK_KHR_MULTIVIEW_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceMultiviewFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR, features: &[ "multiview", "multiviewGeometryShader", "multiviewTessellationShader", ], }, Extension { name_bytes: vk::VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV, features: &[ "representativeFragmentTest", ], }, Extension { name_bytes: vk::VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR, features: &[ "samplerYcbcrConversion", ], }, Extension { name_bytes: vk::VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceScalarBlockLayoutFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT, features: &[ "scalarBlockLayout", ], }, Extension { name_bytes: vk::VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceShaderAtomicInt64FeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR, features: &[ "shaderBufferInt64Atomics", "shaderSharedInt64Atomics", ], }, Extension { name_bytes: vk::VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceShaderImageFootprintFeaturesNV>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV, features: &[ "imageFootprint", ], }, Extension { name_bytes: vk::VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceShadingRateImageFeaturesNV>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV, features: &[ "shadingRateImage", "shadingRateCoarseSampleOrder", ], }, Extension { name_bytes: vk::VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceTransformFeedbackFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT, features: &[ "transformFeedback", "geometryStreams", ], }, Extension { name_bytes: vk::VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceVariablePointersFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, features: &[ "variablePointersStorageBuffer", "variablePointers", ], }, Extension { name_bytes: vk::VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT, features: &[ "vertexAttributeInstanceRateDivisor", "vertexAttributeInstanceRateZeroDivisor", ], }, Extension { name_bytes: vk::VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceVulkanMemoryModelFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR, features: &[ "vulkanMemoryModel", "vulkanMemoryModelDeviceScope", "vulkanMemoryModelAvailabilityVisibilityChains", ], }, Extension { name_bytes: vk::VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceCooperativeMatrixFeaturesKHR>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, features: &[ "cooperativeMatrix", "cooperativeMatrixRobustBufferAccess", ], }, Extension { name_bytes: vk::VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, struct_size: mem::size_of::<vk::VkPhysicalDeviceSubgroupSizeControlFeaturesEXT>(), struct_type: vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT, features: &[ "subgroupSizeControl", "computeFullSubgroups", ], }, ]; const N_BASE_FEATURES: usize = 55; static BASE_FEATURES: [&'static str; N_BASE_FEATURES] = [ "robustBufferAccess", "fullDrawIndexUint32", "imageCubeArray", "independentBlend", "geometryShader", "tessellationShader", "sampleRateShading", "dualSrcBlend", "logicOp", "multiDrawIndirect", "drawIndirectFirstInstance", "depthClamp", "depthBiasClamp", "fillModeNonSolid", "depthBounds", "wideLines", "largePoints", "alphaToOne", "multiViewport", "samplerAnisotropy", "textureCompressionETC2", "textureCompressionASTC_LDR", "textureCompressionBC", "occlusionQueryPrecise", "pipelineStatisticsQuery", "vertexPipelineStoresAndAtomics", "fragmentStoresAndAtomics", "shaderTessellationAndGeometryPointSize", "shaderImageGatherExtended", "shaderStorageImageExtendedFormats", "shaderStorageImageMultisample", "shaderStorageImageReadWithoutFormat", "shaderStorageImageWriteWithoutFormat", "shaderUniformBufferArrayDynamicIndexing", "shaderSampledImageArrayDynamicIndexing", "shaderStorageBufferArrayDynamicIndexing", "shaderStorageImageArrayDynamicIndexing", "shaderClipDistance", "shaderCullDistance", "shaderFloat64", "shaderInt64", "shaderInt16", "shaderResourceResidency", "shaderResourceMinLod", "sparseBinding", "sparseResidencyBuffer", "sparseResidencyImage2D", "sparseResidencyImage3D", "sparseResidency2Samples", "sparseResidency4Samples", "sparseResidency8Samples", "sparseResidency16Samples", "sparseResidencyAliased", "variableMultisampleRate", "inheritedQueries", ]; ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_h264std.h: -------------------------------------------------------------------------------- ``` #ifndef VULKAN_VIDEO_CODEC_H264STD_H_ #define VULKAN_VIDEO_CODEC_H264STD_H_ 1 /* ** Copyright 2015-2025 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ /* ** This header is generated from the Khronos Vulkan XML API Registry. ** */ #ifdef __cplusplus extern "C" { #endif // vulkan_video_codec_h264std is a preprocessor guard. Do not pass it to API calls. #define vulkan_video_codec_h264std 1 #include "vulkan_video_codecs_common.h" #define STD_VIDEO_H264_CPB_CNT_LIST_SIZE 32 #define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS 6 #define STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS 16 #define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS 6 #define STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS 64 #define STD_VIDEO_H264_MAX_NUM_LIST_REF 32 #define STD_VIDEO_H264_MAX_CHROMA_PLANES 2 #define STD_VIDEO_H264_NO_REFERENCE_PICTURE 0xFF typedef enum StdVideoH264ChromaFormatIdc { STD_VIDEO_H264_CHROMA_FORMAT_IDC_MONOCHROME = 0, STD_VIDEO_H264_CHROMA_FORMAT_IDC_420 = 1, STD_VIDEO_H264_CHROMA_FORMAT_IDC_422 = 2, STD_VIDEO_H264_CHROMA_FORMAT_IDC_444 = 3, STD_VIDEO_H264_CHROMA_FORMAT_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_CHROMA_FORMAT_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264ChromaFormatIdc; typedef enum StdVideoH264ProfileIdc { STD_VIDEO_H264_PROFILE_IDC_BASELINE = 66, STD_VIDEO_H264_PROFILE_IDC_MAIN = 77, STD_VIDEO_H264_PROFILE_IDC_HIGH = 100, STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE = 244, STD_VIDEO_H264_PROFILE_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_PROFILE_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264ProfileIdc; typedef enum StdVideoH264LevelIdc { STD_VIDEO_H264_LEVEL_IDC_1_0 = 0, STD_VIDEO_H264_LEVEL_IDC_1_1 = 1, STD_VIDEO_H264_LEVEL_IDC_1_2 = 2, STD_VIDEO_H264_LEVEL_IDC_1_3 = 3, STD_VIDEO_H264_LEVEL_IDC_2_0 = 4, STD_VIDEO_H264_LEVEL_IDC_2_1 = 5, STD_VIDEO_H264_LEVEL_IDC_2_2 = 6, STD_VIDEO_H264_LEVEL_IDC_3_0 = 7, STD_VIDEO_H264_LEVEL_IDC_3_1 = 8, STD_VIDEO_H264_LEVEL_IDC_3_2 = 9, STD_VIDEO_H264_LEVEL_IDC_4_0 = 10, STD_VIDEO_H264_LEVEL_IDC_4_1 = 11, STD_VIDEO_H264_LEVEL_IDC_4_2 = 12, STD_VIDEO_H264_LEVEL_IDC_5_0 = 13, STD_VIDEO_H264_LEVEL_IDC_5_1 = 14, STD_VIDEO_H264_LEVEL_IDC_5_2 = 15, STD_VIDEO_H264_LEVEL_IDC_6_0 = 16, STD_VIDEO_H264_LEVEL_IDC_6_1 = 17, STD_VIDEO_H264_LEVEL_IDC_6_2 = 18, STD_VIDEO_H264_LEVEL_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_LEVEL_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264LevelIdc; typedef enum StdVideoH264PocType { STD_VIDEO_H264_POC_TYPE_0 = 0, STD_VIDEO_H264_POC_TYPE_1 = 1, STD_VIDEO_H264_POC_TYPE_2 = 2, STD_VIDEO_H264_POC_TYPE_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_POC_TYPE_MAX_ENUM = 0x7FFFFFFF } StdVideoH264PocType; typedef enum StdVideoH264AspectRatioIdc { STD_VIDEO_H264_ASPECT_RATIO_IDC_UNSPECIFIED = 0, STD_VIDEO_H264_ASPECT_RATIO_IDC_SQUARE = 1, STD_VIDEO_H264_ASPECT_RATIO_IDC_12_11 = 2, STD_VIDEO_H264_ASPECT_RATIO_IDC_10_11 = 3, STD_VIDEO_H264_ASPECT_RATIO_IDC_16_11 = 4, STD_VIDEO_H264_ASPECT_RATIO_IDC_40_33 = 5, STD_VIDEO_H264_ASPECT_RATIO_IDC_24_11 = 6, STD_VIDEO_H264_ASPECT_RATIO_IDC_20_11 = 7, STD_VIDEO_H264_ASPECT_RATIO_IDC_32_11 = 8, STD_VIDEO_H264_ASPECT_RATIO_IDC_80_33 = 9, STD_VIDEO_H264_ASPECT_RATIO_IDC_18_11 = 10, STD_VIDEO_H264_ASPECT_RATIO_IDC_15_11 = 11, STD_VIDEO_H264_ASPECT_RATIO_IDC_64_33 = 12, STD_VIDEO_H264_ASPECT_RATIO_IDC_160_99 = 13, STD_VIDEO_H264_ASPECT_RATIO_IDC_4_3 = 14, STD_VIDEO_H264_ASPECT_RATIO_IDC_3_2 = 15, STD_VIDEO_H264_ASPECT_RATIO_IDC_2_1 = 16, STD_VIDEO_H264_ASPECT_RATIO_IDC_EXTENDED_SAR = 255, STD_VIDEO_H264_ASPECT_RATIO_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_ASPECT_RATIO_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264AspectRatioIdc; typedef enum StdVideoH264WeightedBipredIdc { STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_DEFAULT = 0, STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_EXPLICIT = 1, STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_IMPLICIT = 2, STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_WEIGHTED_BIPRED_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264WeightedBipredIdc; typedef enum StdVideoH264ModificationOfPicNumsIdc { STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_SUBTRACT = 0, STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_SHORT_TERM_ADD = 1, STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_LONG_TERM = 2, STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_END = 3, STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_MODIFICATION_OF_PIC_NUMS_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264ModificationOfPicNumsIdc; typedef enum StdVideoH264MemMgmtControlOp { STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_END = 0, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_SHORT_TERM = 1, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_LONG_TERM = 2, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_LONG_TERM = 3, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_SET_MAX_LONG_TERM_INDEX = 4, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_UNMARK_ALL = 5, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MARK_CURRENT_AS_LONG_TERM = 6, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_MEM_MGMT_CONTROL_OP_MAX_ENUM = 0x7FFFFFFF } StdVideoH264MemMgmtControlOp; typedef enum StdVideoH264CabacInitIdc { STD_VIDEO_H264_CABAC_INIT_IDC_0 = 0, STD_VIDEO_H264_CABAC_INIT_IDC_1 = 1, STD_VIDEO_H264_CABAC_INIT_IDC_2 = 2, STD_VIDEO_H264_CABAC_INIT_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_CABAC_INIT_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264CabacInitIdc; typedef enum StdVideoH264DisableDeblockingFilterIdc { STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_DISABLED = 0, STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_ENABLED = 1, STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_PARTIAL = 2, STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_DISABLE_DEBLOCKING_FILTER_IDC_MAX_ENUM = 0x7FFFFFFF } StdVideoH264DisableDeblockingFilterIdc; typedef enum StdVideoH264SliceType { STD_VIDEO_H264_SLICE_TYPE_P = 0, STD_VIDEO_H264_SLICE_TYPE_B = 1, STD_VIDEO_H264_SLICE_TYPE_I = 2, STD_VIDEO_H264_SLICE_TYPE_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_SLICE_TYPE_MAX_ENUM = 0x7FFFFFFF } StdVideoH264SliceType; typedef enum StdVideoH264PictureType { STD_VIDEO_H264_PICTURE_TYPE_P = 0, STD_VIDEO_H264_PICTURE_TYPE_B = 1, STD_VIDEO_H264_PICTURE_TYPE_I = 2, STD_VIDEO_H264_PICTURE_TYPE_IDR = 5, STD_VIDEO_H264_PICTURE_TYPE_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_PICTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } StdVideoH264PictureType; typedef enum StdVideoH264NonVclNaluType { STD_VIDEO_H264_NON_VCL_NALU_TYPE_SPS = 0, STD_VIDEO_H264_NON_VCL_NALU_TYPE_PPS = 1, STD_VIDEO_H264_NON_VCL_NALU_TYPE_AUD = 2, STD_VIDEO_H264_NON_VCL_NALU_TYPE_PREFIX = 3, STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_SEQUENCE = 4, STD_VIDEO_H264_NON_VCL_NALU_TYPE_END_OF_STREAM = 5, STD_VIDEO_H264_NON_VCL_NALU_TYPE_PRECODED = 6, STD_VIDEO_H264_NON_VCL_NALU_TYPE_INVALID = 0x7FFFFFFF, STD_VIDEO_H264_NON_VCL_NALU_TYPE_MAX_ENUM = 0x7FFFFFFF } StdVideoH264NonVclNaluType; typedef struct StdVideoH264SpsVuiFlags { uint32_t aspect_ratio_info_present_flag : 1; uint32_t overscan_info_present_flag : 1; uint32_t overscan_appropriate_flag : 1; uint32_t video_signal_type_present_flag : 1; uint32_t video_full_range_flag : 1; uint32_t color_description_present_flag : 1; uint32_t chroma_loc_info_present_flag : 1; uint32_t timing_info_present_flag : 1; uint32_t fixed_frame_rate_flag : 1; uint32_t bitstream_restriction_flag : 1; uint32_t nal_hrd_parameters_present_flag : 1; uint32_t vcl_hrd_parameters_present_flag : 1; } StdVideoH264SpsVuiFlags; typedef struct StdVideoH264HrdParameters { uint8_t cpb_cnt_minus1; uint8_t bit_rate_scale; uint8_t cpb_size_scale; uint8_t reserved1; uint32_t bit_rate_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; uint32_t cpb_size_value_minus1[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; uint8_t cbr_flag[STD_VIDEO_H264_CPB_CNT_LIST_SIZE]; uint32_t initial_cpb_removal_delay_length_minus1; uint32_t cpb_removal_delay_length_minus1; uint32_t dpb_output_delay_length_minus1; uint32_t time_offset_length; } StdVideoH264HrdParameters; typedef struct StdVideoH264SequenceParameterSetVui { StdVideoH264SpsVuiFlags flags; StdVideoH264AspectRatioIdc aspect_ratio_idc; uint16_t sar_width; uint16_t sar_height; uint8_t video_format; uint8_t colour_primaries; uint8_t transfer_characteristics; uint8_t matrix_coefficients; uint32_t num_units_in_tick; uint32_t time_scale; uint8_t max_num_reorder_frames; uint8_t max_dec_frame_buffering; uint8_t chroma_sample_loc_type_top_field; uint8_t chroma_sample_loc_type_bottom_field; uint32_t reserved1; const StdVideoH264HrdParameters* pHrdParameters; } StdVideoH264SequenceParameterSetVui; typedef struct StdVideoH264SpsFlags { uint32_t constraint_set0_flag : 1; uint32_t constraint_set1_flag : 1; uint32_t constraint_set2_flag : 1; uint32_t constraint_set3_flag : 1; uint32_t constraint_set4_flag : 1; uint32_t constraint_set5_flag : 1; uint32_t direct_8x8_inference_flag : 1; uint32_t mb_adaptive_frame_field_flag : 1; uint32_t frame_mbs_only_flag : 1; uint32_t delta_pic_order_always_zero_flag : 1; uint32_t separate_colour_plane_flag : 1; uint32_t gaps_in_frame_num_value_allowed_flag : 1; uint32_t qpprime_y_zero_transform_bypass_flag : 1; uint32_t frame_cropping_flag : 1; uint32_t seq_scaling_matrix_present_flag : 1; uint32_t vui_parameters_present_flag : 1; } StdVideoH264SpsFlags; typedef struct StdVideoH264ScalingLists { uint16_t scaling_list_present_mask; uint16_t use_default_scaling_matrix_mask; uint8_t ScalingList4x4[STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS]; uint8_t ScalingList8x8[STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS][STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS]; } StdVideoH264ScalingLists; typedef struct StdVideoH264SequenceParameterSet { StdVideoH264SpsFlags flags; StdVideoH264ProfileIdc profile_idc; StdVideoH264LevelIdc level_idc; StdVideoH264ChromaFormatIdc chroma_format_idc; uint8_t seq_parameter_set_id; uint8_t bit_depth_luma_minus8; uint8_t bit_depth_chroma_minus8; uint8_t log2_max_frame_num_minus4; StdVideoH264PocType pic_order_cnt_type; int32_t offset_for_non_ref_pic; int32_t offset_for_top_to_bottom_field; uint8_t log2_max_pic_order_cnt_lsb_minus4; uint8_t num_ref_frames_in_pic_order_cnt_cycle; uint8_t max_num_ref_frames; uint8_t reserved1; uint32_t pic_width_in_mbs_minus1; uint32_t pic_height_in_map_units_minus1; uint32_t frame_crop_left_offset; uint32_t frame_crop_right_offset; uint32_t frame_crop_top_offset; uint32_t frame_crop_bottom_offset; uint32_t reserved2; const int32_t* pOffsetForRefFrame; const StdVideoH264ScalingLists* pScalingLists; const StdVideoH264SequenceParameterSetVui* pSequenceParameterSetVui; } StdVideoH264SequenceParameterSet; typedef struct StdVideoH264PpsFlags { uint32_t transform_8x8_mode_flag : 1; uint32_t redundant_pic_cnt_present_flag : 1; uint32_t constrained_intra_pred_flag : 1; uint32_t deblocking_filter_control_present_flag : 1; uint32_t weighted_pred_flag : 1; uint32_t bottom_field_pic_order_in_frame_present_flag : 1; uint32_t entropy_coding_mode_flag : 1; uint32_t pic_scaling_matrix_present_flag : 1; } StdVideoH264PpsFlags; typedef struct StdVideoH264PictureParameterSet { StdVideoH264PpsFlags flags; uint8_t seq_parameter_set_id; uint8_t pic_parameter_set_id; uint8_t num_ref_idx_l0_default_active_minus1; uint8_t num_ref_idx_l1_default_active_minus1; StdVideoH264WeightedBipredIdc weighted_bipred_idc; int8_t pic_init_qp_minus26; int8_t pic_init_qs_minus26; int8_t chroma_qp_index_offset; int8_t second_chroma_qp_index_offset; const StdVideoH264ScalingLists* pScalingLists; } StdVideoH264PictureParameterSet; #ifdef __cplusplus } #endif #endif ``` -------------------------------------------------------------------------------- /vkrunner/include/vk_video/vulkan_video_codec_av1std.h: -------------------------------------------------------------------------------- ``` #ifndef VULKAN_VIDEO_CODEC_AV1STD_H_ #define VULKAN_VIDEO_CODEC_AV1STD_H_ 1 /* ** Copyright 2015-2025 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ /* ** This header is generated from the Khronos Vulkan XML API Registry. ** */ #ifdef __cplusplus extern "C" { #endif // vulkan_video_codec_av1std is a preprocessor guard. Do not pass it to API calls. #define vulkan_video_codec_av1std 1 #include "vulkan_video_codecs_common.h" #define STD_VIDEO_AV1_NUM_REF_FRAMES 8 #define STD_VIDEO_AV1_REFS_PER_FRAME 7 #define STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME 8 #define STD_VIDEO_AV1_MAX_TILE_COLS 64 #define STD_VIDEO_AV1_MAX_TILE_ROWS 64 #define STD_VIDEO_AV1_MAX_SEGMENTS 8 #define STD_VIDEO_AV1_SEG_LVL_MAX 8 #define STD_VIDEO_AV1_PRIMARY_REF_NONE 7 #define STD_VIDEO_AV1_SELECT_INTEGER_MV 2 #define STD_VIDEO_AV1_SELECT_SCREEN_CONTENT_TOOLS 2 #define STD_VIDEO_AV1_SKIP_MODE_FRAMES 2 #define STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS 4 #define STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS 2 #define STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS 8 #define STD_VIDEO_AV1_MAX_NUM_PLANES 3 #define STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS 6 #define STD_VIDEO_AV1_MAX_NUM_Y_POINTS 14 #define STD_VIDEO_AV1_MAX_NUM_CB_POINTS 10 #define STD_VIDEO_AV1_MAX_NUM_CR_POINTS 10 #define STD_VIDEO_AV1_MAX_NUM_POS_LUMA 24 #define STD_VIDEO_AV1_MAX_NUM_POS_CHROMA 25 typedef enum StdVideoAV1Profile { STD_VIDEO_AV1_PROFILE_MAIN = 0, STD_VIDEO_AV1_PROFILE_HIGH = 1, STD_VIDEO_AV1_PROFILE_PROFESSIONAL = 2, STD_VIDEO_AV1_PROFILE_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_PROFILE_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1Profile; typedef enum StdVideoAV1Level { STD_VIDEO_AV1_LEVEL_2_0 = 0, STD_VIDEO_AV1_LEVEL_2_1 = 1, STD_VIDEO_AV1_LEVEL_2_2 = 2, STD_VIDEO_AV1_LEVEL_2_3 = 3, STD_VIDEO_AV1_LEVEL_3_0 = 4, STD_VIDEO_AV1_LEVEL_3_1 = 5, STD_VIDEO_AV1_LEVEL_3_2 = 6, STD_VIDEO_AV1_LEVEL_3_3 = 7, STD_VIDEO_AV1_LEVEL_4_0 = 8, STD_VIDEO_AV1_LEVEL_4_1 = 9, STD_VIDEO_AV1_LEVEL_4_2 = 10, STD_VIDEO_AV1_LEVEL_4_3 = 11, STD_VIDEO_AV1_LEVEL_5_0 = 12, STD_VIDEO_AV1_LEVEL_5_1 = 13, STD_VIDEO_AV1_LEVEL_5_2 = 14, STD_VIDEO_AV1_LEVEL_5_3 = 15, STD_VIDEO_AV1_LEVEL_6_0 = 16, STD_VIDEO_AV1_LEVEL_6_1 = 17, STD_VIDEO_AV1_LEVEL_6_2 = 18, STD_VIDEO_AV1_LEVEL_6_3 = 19, STD_VIDEO_AV1_LEVEL_7_0 = 20, STD_VIDEO_AV1_LEVEL_7_1 = 21, STD_VIDEO_AV1_LEVEL_7_2 = 22, STD_VIDEO_AV1_LEVEL_7_3 = 23, STD_VIDEO_AV1_LEVEL_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_LEVEL_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1Level; typedef enum StdVideoAV1FrameType { STD_VIDEO_AV1_FRAME_TYPE_KEY = 0, STD_VIDEO_AV1_FRAME_TYPE_INTER = 1, STD_VIDEO_AV1_FRAME_TYPE_INTRA_ONLY = 2, STD_VIDEO_AV1_FRAME_TYPE_SWITCH = 3, STD_VIDEO_AV1_FRAME_TYPE_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_FRAME_TYPE_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1FrameType; typedef enum StdVideoAV1ReferenceName { STD_VIDEO_AV1_REFERENCE_NAME_INTRA_FRAME = 0, STD_VIDEO_AV1_REFERENCE_NAME_LAST_FRAME = 1, STD_VIDEO_AV1_REFERENCE_NAME_LAST2_FRAME = 2, STD_VIDEO_AV1_REFERENCE_NAME_LAST3_FRAME = 3, STD_VIDEO_AV1_REFERENCE_NAME_GOLDEN_FRAME = 4, STD_VIDEO_AV1_REFERENCE_NAME_BWDREF_FRAME = 5, STD_VIDEO_AV1_REFERENCE_NAME_ALTREF2_FRAME = 6, STD_VIDEO_AV1_REFERENCE_NAME_ALTREF_FRAME = 7, STD_VIDEO_AV1_REFERENCE_NAME_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_REFERENCE_NAME_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1ReferenceName; typedef enum StdVideoAV1InterpolationFilter { STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP = 0, STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH = 1, STD_VIDEO_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP = 2, STD_VIDEO_AV1_INTERPOLATION_FILTER_BILINEAR = 3, STD_VIDEO_AV1_INTERPOLATION_FILTER_SWITCHABLE = 4, STD_VIDEO_AV1_INTERPOLATION_FILTER_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_INTERPOLATION_FILTER_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1InterpolationFilter; typedef enum StdVideoAV1TxMode { STD_VIDEO_AV1_TX_MODE_ONLY_4X4 = 0, STD_VIDEO_AV1_TX_MODE_LARGEST = 1, STD_VIDEO_AV1_TX_MODE_SELECT = 2, STD_VIDEO_AV1_TX_MODE_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_TX_MODE_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1TxMode; typedef enum StdVideoAV1FrameRestorationType { STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_NONE = 0, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_WIENER = 1, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SGRPROJ = 2, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_SWITCHABLE = 3, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_FRAME_RESTORATION_TYPE_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1FrameRestorationType; typedef enum StdVideoAV1ColorPrimaries { STD_VIDEO_AV1_COLOR_PRIMARIES_BT_709 = 1, STD_VIDEO_AV1_COLOR_PRIMARIES_UNSPECIFIED = 2, STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_M = 4, STD_VIDEO_AV1_COLOR_PRIMARIES_BT_470_B_G = 5, STD_VIDEO_AV1_COLOR_PRIMARIES_BT_601 = 6, STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_240 = 7, STD_VIDEO_AV1_COLOR_PRIMARIES_GENERIC_FILM = 8, STD_VIDEO_AV1_COLOR_PRIMARIES_BT_2020 = 9, STD_VIDEO_AV1_COLOR_PRIMARIES_XYZ = 10, STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_431 = 11, STD_VIDEO_AV1_COLOR_PRIMARIES_SMPTE_432 = 12, STD_VIDEO_AV1_COLOR_PRIMARIES_EBU_3213 = 22, STD_VIDEO_AV1_COLOR_PRIMARIES_INVALID = 0x7FFFFFFF, // STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED is a deprecated alias STD_VIDEO_AV1_COLOR_PRIMARIES_BT_UNSPECIFIED = STD_VIDEO_AV1_COLOR_PRIMARIES_UNSPECIFIED, STD_VIDEO_AV1_COLOR_PRIMARIES_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1ColorPrimaries; typedef enum StdVideoAV1TransferCharacteristics { STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_0 = 0, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_709 = 1, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_RESERVED_3 = 3, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_M = 4, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_470_B_G = 5, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_601 = 6, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_240 = 7, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LINEAR = 8, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100 = 9, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_LOG_100_SQRT10 = 10, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_IEC_61966 = 11, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_1361 = 12, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SRGB = 13, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_10_BIT = 14, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_BT_2020_12_BIT = 15, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_2084 = 16, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_SMPTE_428 = 17, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_HLG = 18, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_TRANSFER_CHARACTERISTICS_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1TransferCharacteristics; typedef enum StdVideoAV1MatrixCoefficients { STD_VIDEO_AV1_MATRIX_COEFFICIENTS_IDENTITY = 0, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_709 = 1, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_UNSPECIFIED = 2, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_RESERVED_3 = 3, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_FCC = 4, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_470_B_G = 5, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_601 = 6, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_240 = 7, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_YCGCO = 8, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_NCL = 9, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_BT_2020_CL = 10, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_SMPTE_2085 = 11, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_NCL = 12, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_CHROMAT_CL = 13, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_ICTCP = 14, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_MATRIX_COEFFICIENTS_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1MatrixCoefficients; typedef enum StdVideoAV1ChromaSamplePosition { STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_UNKNOWN = 0, STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_VERTICAL = 1, STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_COLOCATED = 2, STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_RESERVED = 3, STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_INVALID = 0x7FFFFFFF, STD_VIDEO_AV1_CHROMA_SAMPLE_POSITION_MAX_ENUM = 0x7FFFFFFF } StdVideoAV1ChromaSamplePosition; typedef struct StdVideoAV1ColorConfigFlags { uint32_t mono_chrome : 1; uint32_t color_range : 1; uint32_t separate_uv_delta_q : 1; uint32_t color_description_present_flag : 1; uint32_t reserved : 28; } StdVideoAV1ColorConfigFlags; typedef struct StdVideoAV1ColorConfig { StdVideoAV1ColorConfigFlags flags; uint8_t BitDepth; uint8_t subsampling_x; uint8_t subsampling_y; uint8_t reserved1; StdVideoAV1ColorPrimaries color_primaries; StdVideoAV1TransferCharacteristics transfer_characteristics; StdVideoAV1MatrixCoefficients matrix_coefficients; StdVideoAV1ChromaSamplePosition chroma_sample_position; } StdVideoAV1ColorConfig; typedef struct StdVideoAV1TimingInfoFlags { uint32_t equal_picture_interval : 1; uint32_t reserved : 31; } StdVideoAV1TimingInfoFlags; typedef struct StdVideoAV1TimingInfo { StdVideoAV1TimingInfoFlags flags; uint32_t num_units_in_display_tick; uint32_t time_scale; uint32_t num_ticks_per_picture_minus_1; } StdVideoAV1TimingInfo; typedef struct StdVideoAV1LoopFilterFlags { uint32_t loop_filter_delta_enabled : 1; uint32_t loop_filter_delta_update : 1; uint32_t reserved : 30; } StdVideoAV1LoopFilterFlags; typedef struct StdVideoAV1LoopFilter { StdVideoAV1LoopFilterFlags flags; uint8_t loop_filter_level[STD_VIDEO_AV1_MAX_LOOP_FILTER_STRENGTHS]; uint8_t loop_filter_sharpness; uint8_t update_ref_delta; int8_t loop_filter_ref_deltas[STD_VIDEO_AV1_TOTAL_REFS_PER_FRAME]; uint8_t update_mode_delta; int8_t loop_filter_mode_deltas[STD_VIDEO_AV1_LOOP_FILTER_ADJUSTMENTS]; } StdVideoAV1LoopFilter; typedef struct StdVideoAV1QuantizationFlags { uint32_t using_qmatrix : 1; uint32_t diff_uv_delta : 1; uint32_t reserved : 30; } StdVideoAV1QuantizationFlags; typedef struct StdVideoAV1Quantization { StdVideoAV1QuantizationFlags flags; uint8_t base_q_idx; int8_t DeltaQYDc; int8_t DeltaQUDc; int8_t DeltaQUAc; int8_t DeltaQVDc; int8_t DeltaQVAc; uint8_t qm_y; uint8_t qm_u; uint8_t qm_v; } StdVideoAV1Quantization; typedef struct StdVideoAV1Segmentation { uint8_t FeatureEnabled[STD_VIDEO_AV1_MAX_SEGMENTS]; int16_t FeatureData[STD_VIDEO_AV1_MAX_SEGMENTS][STD_VIDEO_AV1_SEG_LVL_MAX]; } StdVideoAV1Segmentation; typedef struct StdVideoAV1TileInfoFlags { uint32_t uniform_tile_spacing_flag : 1; uint32_t reserved : 31; } StdVideoAV1TileInfoFlags; typedef struct StdVideoAV1TileInfo { StdVideoAV1TileInfoFlags flags; uint8_t TileCols; uint8_t TileRows; uint16_t context_update_tile_id; uint8_t tile_size_bytes_minus_1; uint8_t reserved1[7]; const uint16_t* pMiColStarts; const uint16_t* pMiRowStarts; const uint16_t* pWidthInSbsMinus1; const uint16_t* pHeightInSbsMinus1; } StdVideoAV1TileInfo; typedef struct StdVideoAV1CDEF { uint8_t cdef_damping_minus_3; uint8_t cdef_bits; uint8_t cdef_y_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; uint8_t cdef_y_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; uint8_t cdef_uv_pri_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; uint8_t cdef_uv_sec_strength[STD_VIDEO_AV1_MAX_CDEF_FILTER_STRENGTHS]; } StdVideoAV1CDEF; typedef struct StdVideoAV1LoopRestoration { StdVideoAV1FrameRestorationType FrameRestorationType[STD_VIDEO_AV1_MAX_NUM_PLANES]; uint16_t LoopRestorationSize[STD_VIDEO_AV1_MAX_NUM_PLANES]; } StdVideoAV1LoopRestoration; typedef struct StdVideoAV1GlobalMotion { uint8_t GmType[STD_VIDEO_AV1_NUM_REF_FRAMES]; int32_t gm_params[STD_VIDEO_AV1_NUM_REF_FRAMES][STD_VIDEO_AV1_GLOBAL_MOTION_PARAMS]; } StdVideoAV1GlobalMotion; typedef struct StdVideoAV1FilmGrainFlags { uint32_t chroma_scaling_from_luma : 1; uint32_t overlap_flag : 1; uint32_t clip_to_restricted_range : 1; uint32_t update_grain : 1; uint32_t reserved : 28; } StdVideoAV1FilmGrainFlags; typedef struct StdVideoAV1FilmGrain { StdVideoAV1FilmGrainFlags flags; uint8_t grain_scaling_minus_8; uint8_t ar_coeff_lag; uint8_t ar_coeff_shift_minus_6; uint8_t grain_scale_shift; uint16_t grain_seed; uint8_t film_grain_params_ref_idx; uint8_t num_y_points; uint8_t point_y_value[STD_VIDEO_AV1_MAX_NUM_Y_POINTS]; uint8_t point_y_scaling[STD_VIDEO_AV1_MAX_NUM_Y_POINTS]; uint8_t num_cb_points; uint8_t point_cb_value[STD_VIDEO_AV1_MAX_NUM_CB_POINTS]; uint8_t point_cb_scaling[STD_VIDEO_AV1_MAX_NUM_CB_POINTS]; uint8_t num_cr_points; uint8_t point_cr_value[STD_VIDEO_AV1_MAX_NUM_CR_POINTS]; uint8_t point_cr_scaling[STD_VIDEO_AV1_MAX_NUM_CR_POINTS]; int8_t ar_coeffs_y_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_LUMA]; int8_t ar_coeffs_cb_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA]; int8_t ar_coeffs_cr_plus_128[STD_VIDEO_AV1_MAX_NUM_POS_CHROMA]; uint8_t cb_mult; uint8_t cb_luma_mult; uint16_t cb_offset; uint8_t cr_mult; uint8_t cr_luma_mult; uint16_t cr_offset; } StdVideoAV1FilmGrain; typedef struct StdVideoAV1SequenceHeaderFlags { uint32_t still_picture : 1; uint32_t reduced_still_picture_header : 1; uint32_t use_128x128_superblock : 1; uint32_t enable_filter_intra : 1; uint32_t enable_intra_edge_filter : 1; uint32_t enable_interintra_compound : 1; uint32_t enable_masked_compound : 1; uint32_t enable_warped_motion : 1; uint32_t enable_dual_filter : 1; uint32_t enable_order_hint : 1; uint32_t enable_jnt_comp : 1; uint32_t enable_ref_frame_mvs : 1; uint32_t frame_id_numbers_present_flag : 1; uint32_t enable_superres : 1; uint32_t enable_cdef : 1; uint32_t enable_restoration : 1; uint32_t film_grain_params_present : 1; uint32_t timing_info_present_flag : 1; uint32_t initial_display_delay_present_flag : 1; uint32_t reserved : 13; } StdVideoAV1SequenceHeaderFlags; typedef struct StdVideoAV1SequenceHeader { StdVideoAV1SequenceHeaderFlags flags; StdVideoAV1Profile seq_profile; uint8_t frame_width_bits_minus_1; uint8_t frame_height_bits_minus_1; uint16_t max_frame_width_minus_1; uint16_t max_frame_height_minus_1; uint8_t delta_frame_id_length_minus_2; uint8_t additional_frame_id_length_minus_1; uint8_t order_hint_bits_minus_1; uint8_t seq_force_integer_mv; uint8_t seq_force_screen_content_tools; uint8_t reserved1[5]; const StdVideoAV1ColorConfig* pColorConfig; const StdVideoAV1TimingInfo* pTimingInfo; } StdVideoAV1SequenceHeader; #ifdef __cplusplus } #endif #endif ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/executor.rs: -------------------------------------------------------------------------------- ```rust // vkrunner // // Copyright (C) 2018 Intel Corporation // Copyright 2023 Neil Roberts // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice (including the next // paragraph) shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. use crate::vulkan_funcs; use crate::context::{self, Context}; use crate::window::{Window, WindowError}; use crate::config::Config; use crate::script::Script; use crate::source::Source; use crate::result; use crate::vk; use crate::requirements::Requirements; use crate::pipeline_set::{self, PipelineSet}; use crate::tester; use crate::requirements; use std::ffi::c_void; use std::fmt; use std::rc::Rc; use std::cell::RefCell; #[derive(Debug)] pub(crate) enum Error { Context(context::Error), Window(WindowError), PipelineError(pipeline_set::Error), TestError(tester::Error), ExternalDeviceRequirementsError(requirements::Error), } impl Error { pub fn result(&self) -> result::Result { match self { Error::Context(e) => e.result(), Error::Window(e) => e.result(), Error::ExternalDeviceRequirementsError(e) => e.result(), Error::PipelineError(_) => result::Result::Fail, Error::TestError(_) => result::Result::Fail, } } } impl From<context::Error> for Error { fn from(error: context::Error) -> Error { Error::Context(error) } } impl From<WindowError> for Error { fn from(error: WindowError) -> Error { Error::Window(error) } } impl From<pipeline_set::Error> for Error { fn from(error: pipeline_set::Error) -> Error { Error::PipelineError(error) } } impl From<tester::Error> for Error { fn from(error: tester::Error) -> Error { Error::TestError(error) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Error::Context(e) => e.fmt(f), Error::Window(e) => e.fmt(f), Error::PipelineError(e) => e.fmt(f), Error::TestError(e) => e.fmt(f), Error::ExternalDeviceRequirementsError(e) => e.fmt(f), } } } #[derive(Debug)] struct ExternalData { get_instance_proc_cb: vulkan_funcs::GetInstanceProcFunc, user_data: *const c_void, physical_device: vk::VkPhysicalDevice, queue_family: u32, vk_device: vk::VkDevice, } #[derive(Debug)] pub struct Executor { config: Rc<RefCell<Config>>, window: Option<Rc<Window>>, context: Option<Rc<Context>>, // A cache of the requirements that the context was created with. // Used to detect if the requirements have changed. This won’t be // used if the context is external. requirements: Requirements, external: Option<ExternalData>, } impl Executor { fn reset_window(&mut self) { self.window = None; } fn reset_context(&mut self) { self.reset_window(); self.context = None; } fn context_is_compatible(&self, script: &Script) -> bool { // If the device is created externally then it’s up to the // caller to ensure the device has all the necessary features // enabled. if self.external.is_some() { return true; } match self.context { Some(_) => self.requirements.eq(script.requirements()), None => false, } } pub fn new(config: Rc<RefCell<Config>>) -> Executor { Executor { config, window: None, context: None, requirements: Requirements::new(), external: None, } } pub fn set_device( &mut self, get_instance_proc_cb: vulkan_funcs::GetInstanceProcFunc, user_data: *const c_void, physical_device: vk::VkPhysicalDevice, queue_family: u32, vk_device: vk::VkDevice, ) { self.reset_context(); self.external = Some(ExternalData { get_instance_proc_cb, user_data, physical_device, queue_family, vk_device, }); } fn create_context( &self, requirements: &Requirements, ) -> Result<Context, Error> { match &self.external { Some(e) => { Ok(Context::new_with_device( e.get_instance_proc_cb, e.user_data, e.physical_device, e.queue_family, e.vk_device, )?) }, None => Ok(Context::new( requirements, self.config.borrow().device_id() )?), } } fn context_for_script( &mut self, script: &Script, ) -> Result<Rc<Context>, Error> { // Recreate the context if the features or extensions have changed if !self.context_is_compatible(script) { self.reset_context(); } match &self.context { Some(c) => Ok(Rc::clone(c)), None => { self.requirements.clone_from(script.requirements()); let context = self.create_context(&self.requirements)?; Ok(Rc::clone(self.context.insert(Rc::new(context)))) } } } fn window_for_script( &mut self, script: &Script, context: Rc<Context>, ) -> Result<Rc<Window>, Error> { // Recreate the window if the framebuffer format is different if let Some(window) = &self.window { if !window.format().eq(script.window_format()) { self.reset_window(); } } match &self.window { Some(w) => Ok(Rc::clone(w)), None => Ok(Rc::clone(self.window.insert(Rc::new(Window::new( context, script.window_format(), )?)))), } } fn handle_execute_result( &self, result: Result<(), Error> ) -> result::Result { match result { Ok(()) => result::Result::Pass, Err(e) => { use std::fmt::Write; let _ = writeln!( self.config.borrow_mut().logger().borrow_mut(), "{}", e ); e.result() } } } fn execute_script_or_error( &mut self, script: &Script ) -> Result<(), Error> { let context = self.context_for_script(script)?; if self.external.is_some() { if let Err(e) = script.requirements().check( context.instance(), context.physical_device(), ) { return Err(Error::ExternalDeviceRequirementsError(e)); } } let window = self.window_for_script(script, Rc::clone(&context))?; let pipeline_set = PipelineSet::new( &mut self.config.borrow().logger().borrow_mut(), Rc::clone(&window), script, self.config.borrow().show_disassembly(), )?; tester::run( window.as_ref(), &pipeline_set, script, self.config.borrow().inspector().clone(), )?; Ok(()) } pub fn execute_script( &mut self, script: &Script ) -> result::Result { let res = self.execute_script_or_error(script); self.handle_execute_result(res) } pub fn execute( &mut self, source: &Source, ) -> result::Result { let load_res = Script::load(&self.config.borrow(), source); load_res .and_then(|script| Some(self.execute_script(&script))) .unwrap_or(result::Result::Fail) } } #[cfg(test)] mod test { use super::*; use crate::fake_vulkan::FakeVulkan; use crate::config::Config; use std::ffi::c_char; fn create_fake_vulkan() -> Box<FakeVulkan> { let mut fake_vulkan = FakeVulkan::new(); fake_vulkan.physical_devices.push(Default::default()); fake_vulkan.physical_devices[0].features.wideLines = vk::VK_TRUE; fake_vulkan.physical_devices[0].format_properties.insert( vk::VK_FORMAT_B8G8R8A8_UNORM, vk::VkFormatProperties { linearTilingFeatures: 0, optimalTilingFeatures: vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_BLIT_SRC_BIT, bufferFeatures: 0, }, ); fake_vulkan.physical_devices[0].format_properties.insert( vk::VK_FORMAT_R8_UNORM, vk::VkFormatProperties { linearTilingFeatures: 0, optimalTilingFeatures: vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_BLIT_SRC_BIT, bufferFeatures: 0, }, ); let memory_properties = &mut fake_vulkan.physical_devices[0].memory_properties; memory_properties.memoryTypes[0].propertyFlags = vk::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; memory_properties.memoryTypeCount = 1; fake_vulkan.memory_requirements.memoryTypeBits = 1; fake_vulkan } #[test] fn recreate_resources() { let fake_vulkan = create_fake_vulkan(); let config = Rc::new(RefCell::new(Config::new())); let mut executor = Executor::new(Rc::clone(&config)); fake_vulkan.set_override(); assert_eq!( executor.execute(&Source::from_string("".to_string())), result::Result::Pass, ); let context = Rc::clone(executor.context.as_ref().unwrap()); let window = Rc::clone(&executor.window.as_ref().unwrap()); // Run another script that has the same requirements assert_eq!( executor.execute(&Source::from_string( "[test]\n\ draw rect -1 -1 2 2".to_string() )), result::Result::Pass, ); // The context and window shouldn’t have changed assert!(Rc::ptr_eq(&context, executor.context.as_ref().unwrap())); assert!(Rc::ptr_eq(&window, executor.window.as_ref().unwrap())); // Run a script with different requirements fake_vulkan.set_override(); assert_eq!( executor.execute(&Source::from_string( "[require]\n\ wideLines\n\ [test]\n\ draw rect -1 -1 2 2".to_string() )), result::Result::Pass, ); // The context and window should have changed assert!(!Rc::ptr_eq(&context, executor.context.as_ref().unwrap())); assert!(!Rc::ptr_eq(&window, executor.window.as_ref().unwrap())); let context = Rc::clone(executor.context.as_ref().unwrap()); let window = Rc::clone(&executor.window.as_ref().unwrap()); // Run the same script with a different framebuffer format assert_eq!( executor.execute(&Source::from_string( "[require]\n\ wideLines\n\ framebuffer R8_UNORM\n\ [test]\n\ draw rect -1 -1 2 2".to_string() )), result::Result::Pass, ); // The context should stay the same but the framebuffer should // have changed assert!(Rc::ptr_eq(&context, executor.context.as_ref().unwrap())); assert!(!Rc::ptr_eq(&window, executor.window.as_ref().unwrap())); } extern "C" fn get_instance_proc_cb( func_name: *const c_char, user_data: *const c_void, ) -> *const c_void { unsafe { let fake_vulkan = &*(user_data as *const FakeVulkan); let func = fake_vulkan.get_function(func_name); std::mem::transmute(func) } } #[test] fn external_device() { let fake_vulkan = create_fake_vulkan(); fake_vulkan.set_override(); let context = Context::new(&Requirements::new(), None).unwrap(); let config = Rc::new(RefCell::new(Config::new())); let mut executor = Executor::new(Rc::clone(&config)); let (queue_family, _) = FakeVulkan::unmake_queue(context.queue()); executor.set_device( get_instance_proc_cb, (fake_vulkan.as_ref() as *const FakeVulkan).cast(), context.physical_device(), queue_family, context.vk_device() ); assert_eq!( executor.execute(&Source::from_string("".to_string())), result::Result::Pass, ); } #[test] fn external_requirements_error() { let fake_vulkan = create_fake_vulkan(); fake_vulkan.set_override(); let context = Context::new(&Requirements::new(), None).unwrap(); let config = Rc::new(RefCell::new(Config::new())); let mut executor = Executor::new(Rc::clone(&config)); let (queue_family, _) = FakeVulkan::unmake_queue(context.queue()); executor.set_device( get_instance_proc_cb, (fake_vulkan.as_ref() as *const FakeVulkan).cast(), context.physical_device(), queue_family, context.vk_device() ); let source = Source::from_string( "[require]\n\ logicOp".to_string() ); let script = Script::load(&executor.config.borrow(), &source).unwrap(); let error = executor.execute_script_or_error(&script).unwrap_err(); assert_eq!( &error.to_string(), "Missing required feature: logicOp", ); assert_eq!( error.result(), result::Result::Skip, ); } #[test] fn context_error() { let fake_vulkan = create_fake_vulkan(); let config = Rc::new(RefCell::new(Config::new())); config.borrow_mut().set_device_id(Some(12)); let mut executor = Executor::new(Rc::clone(&config)); let source = Source::from_string("".to_string()); let script = Script::load(&executor.config.borrow(), &source).unwrap(); fake_vulkan.set_override(); let error = executor.execute_script_or_error(&script).unwrap_err(); assert_eq!( &error.to_string(), "Device 13 was selected but the Vulkan instance only reported \ 1 device.", ); assert_eq!( error.result(), result::Result::Fail, ); } fn run_script_error(source: &str) -> Error { let fake_vulkan = create_fake_vulkan(); let config = Rc::new(RefCell::new(Config::new())); let mut executor = Executor::new(config); let source = Source::from_string(source.to_string()); let script = Script::load(&executor.config.borrow(), &source).unwrap(); fake_vulkan.set_override(); executor.execute_script_or_error(&script).unwrap_err() } #[test] fn window_error() { let error = run_script_error( "[require]\n\ depthstencil R8_UNORM" ); assert_eq!( &error.to_string(), "Format R8_UNORM is not supported as a depth/stencil attachment", ); assert_eq!( error.result(), result::Result::Skip, ); } #[test] fn pipeline_error() { let error = run_script_error( "[vertex shader]\n\ 12" ); assert_eq!( &error.to_string(), "The compiler or assembler generated an invalid SPIR-V binary", ); assert_eq!( error.result(), result::Result::Fail, ); } #[test] fn tester_error() { let error = run_script_error( "[test]\n\ probe all rgb 1 2 3" ); assert_eq!( &error.to_string(), "line 2: Probe color at (0,0)\n\ \x20 Expected: 1 2 3\n\ \x20 Observed: 0 0 0" ); assert_eq!( error.result(), result::Result::Fail, ); } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/compiler.rs: -------------------------------------------------------------------------------- ```rust // vkrunner // // Copyright (C) 2018 Intel Corporation // Copyright 2023 Neil Roberts // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice (including the next // paragraph) shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. use crate::vk; use crate::shader_stage; use crate::logger::Logger; use crate::context::Context; use crate::script::{Script, Shader}; use crate::temp_file; use crate::requirements::extract_version; use std::fmt; use std::mem; use std::ptr; use std::io::{self, Write, Read, BufWriter}; use std::fs::File; use std::path::Path; use std::env; // When testing we’ll divert to a fake command so that we don’t need // to depend on glslangValidator #[cfg(test)] mod fake_process; #[cfg(test)] use fake_process::{Command, Output}; #[cfg(not(test))] use std::process::{Command, Output}; use std::process::Stdio; /// An error that can be returned by [build_stage]. #[derive(Debug)] pub enum Error { /// There were no shaders for this stage in the script MissingStageShaders(shader_stage::Stage), /// vkCreateShaderModule returned an error CreateShaderModuleFailed, /// Error creating a temporary file TempFile(temp_file::Error), /// Other I/O error IoError(io::Error), /// A compiler or assembler command returned a non-zero status CommandFailed, /// The generated shader binary didn’t have the right SPIR-V magic /// number or wasn’t a multiple of 32-bit integers. InvalidShaderBinary, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Error::MissingStageShaders(stage) => write!( f, "No shaders for stage {:?}", stage, ), Error::CreateShaderModuleFailed => write!( f, "vkCreateShaderModule failed" ), Error::TempFile(e) => e.fmt(f), Error::IoError(e) => e.fmt(f), Error::CommandFailed => write!( f, "A subprocess failed with a non-zero exit status", ), Error::InvalidShaderBinary => write!( f, "The compiler or assembler generated an invalid SPIR-V binary", ), } } } impl From<temp_file::Error> for Error { fn from(e: temp_file::Error) -> Error { Error::TempFile(e) } } impl From<io::Error> for Error { fn from(e: io::Error) -> Error { Error::IoError(e) } } fn stage_name(stage: shader_stage::Stage) -> &'static str { match stage { shader_stage::Stage::Vertex => "vert", shader_stage::Stage::TessCtrl => "tesc", shader_stage::Stage::TessEval => "tese", shader_stage::Stage::Geometry => "geom", shader_stage::Stage::Fragment => "frag", shader_stage::Stage::Compute => "comp", } } fn handle_command_output( logger: &mut Logger, output: Output, ) -> Result<(), Error> { logger.write_all(output.stdout.as_slice())?; logger.write_all(output.stderr.as_slice())?; if output.status.success() { Ok(()) } else { Err(Error::CommandFailed) } } fn show_disassembly_from_file( logger: &mut Logger, filename: &Path, ) -> Result<(), Error> { let exe = match env::var_os("PIGLIT_SPIRV_DIS_BINARY") { Some(exe) => exe, None => "spirv-dis".into(), }; handle_command_output( logger, Command::new(exe) .arg(filename) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output()? ) } fn create_shader_from_binary( context: &Context, data: &[u32], ) -> Result<vk::VkShaderModule, Error> { let shader_module_create_info = vk::VkShaderModuleCreateInfo { sType: vk::VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, pNext: ptr::null(), flags: 0, codeSize: data.len() * mem::size_of::<u32>(), pCode: data.as_ptr(), }; let mut module: vk::VkShaderModule = vk::null_handle(); let res = unsafe { context.device().vkCreateShaderModule.unwrap()( context.vk_device(), ptr::addr_of!(shader_module_create_info), ptr::null(), // allocator ptr::addr_of_mut!(module), ) }; if res == vk::VK_SUCCESS { Ok(module) } else { Err(Error::CreateShaderModuleFailed) } } fn create_shader_from_binary_file( context: &Context, file: &mut File, ) -> Result<vk::VkShaderModule, Error> { let mut data = Vec::<u32>::new(); let mut buf = vec![0u8; 512]; let mut buf_length = 0usize; let mut big_endian = false; let mut bytes = [0u8; mem::size_of::<u32>()]; loop { let got = file.read(&mut buf[buf_length..])?; if got == 0 { break; } buf_length += got; for i in 0..buf_length / mem::size_of::<u32>() { let buf_start = i * mem::size_of::<u32>(); bytes.copy_from_slice(&buf[ buf_start..buf_start + mem::size_of::<u32>() ]); if data.len() == 0 { if bytes == [0x07, 0x23, 0x02, 0x03] { big_endian = true; } else if bytes == [0x03, 0x02, 0x23, 0x07] { big_endian = false; } else { return Err(Error::InvalidShaderBinary); } } data.push(if big_endian { u32::from_be_bytes(bytes) } else { u32::from_le_bytes(bytes) }); } let remainder = buf_length % mem::size_of::<u32>(); buf.copy_within(buf_length - remainder.., 0); buf_length = remainder; } if buf_length != 0 { Err(Error::InvalidShaderBinary) } else { create_shader_from_binary(context, &data) } } fn create_temp_file_for_source( source: &str ) -> Result<temp_file::TempFile, Error> { let mut temp_file = temp_file::TempFile::new()?; temp_file.file().unwrap().write_all(source.as_bytes())?; temp_file.file().unwrap().flush()?; temp_file.close(); Ok(temp_file) } fn version_string(version: u32) -> String { let (version_major, version_minor, _) = extract_version(version); format!("vulkan{}.{}", version_major, version_minor) } fn compile_glsl( logger: &mut Logger, context: &Context, script: &Script, stage: shader_stage::Stage, show_disassembly: bool, ) -> Result<vk::VkShaderModule, Error> { let mut shader_files = Vec::new(); for shader in script.shaders(stage) { let source = match &shader { Shader::Glsl(s) => s, _ => unreachable!("Unexpected shader type"), }; shader_files.push(create_temp_file_for_source(&source)?); } let version_str = version_string(script.requirements().version()); let mut module_file = temp_file::TempFile::new()?; let exe = match env::var_os("PIGLIT_GLSLANG_VALIDATOR_BINARY") { Some(exe) => exe, None => "glslangValidator".into(), }; handle_command_output( logger, Command::new(exe) .args([ "--quiet", "-V", "--target-env", &version_str, "-S", stage_name(stage), ]) .arg("-o").arg(module_file.filename()) .args(shader_files.iter().map(|file| file.filename())) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output()? )?; drop(shader_files); if show_disassembly { show_disassembly_from_file(logger, module_file.filename())?; } create_shader_from_binary_file(context, module_file.file().unwrap()) } fn assemble_spirv( logger: &mut Logger, context: &Context, script: &Script, source: &str, show_disassembly: bool, ) -> Result<vk::VkShaderModule, Error> { let version_str = version_string(script.requirements().version()); let mut module_file = temp_file::TempFile::new()?; let source_file = create_temp_file_for_source(source)?; let exe = match env::var_os("PIGLIT_SPIRV_AS_BINARY") { Some(exe) => exe, None => "spirv-as".into(), }; handle_command_output( logger, Command::new(exe) .args(["--target-env", &version_str]) .arg("-o").arg(module_file.filename()) .arg(source_file.filename()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output()? )?; drop(source_file); if show_disassembly { show_disassembly_from_file(logger, module_file.filename())?; } create_shader_from_binary_file(context, module_file.file().unwrap()) } fn load_binary_stage( logger: &mut Logger, context: &Context, data: &[u32], show_disassembly: bool, ) -> Result<vk::VkShaderModule, Error> { if show_disassembly { let mut temp_file = temp_file::TempFile::new()?; let mut writer = BufWriter::new(temp_file.file().unwrap()); for value in data { writer.write_all(&value.to_ne_bytes())?; } writer.flush()?; drop(writer); temp_file.close(); show_disassembly_from_file(logger, temp_file.filename())?; } create_shader_from_binary(context, data) } pub fn build_stage( logger: &mut Logger, context: &Context, script: &Script, stage: shader_stage::Stage, show_disassembly: bool, ) -> Result<vk::VkShaderModule, Error> { let shaders = script.shaders(stage); match shaders.get(0) { None => Err(Error::MissingStageShaders(stage)), Some(Shader::Glsl(_)) => compile_glsl( logger, context, script, stage, show_disassembly, ), Some(Shader::Spirv(source)) => { // The script parser should have ensured that there’s // only one shader assert_eq!(shaders.len(), 1); assemble_spirv( logger, context, script, source, show_disassembly ) }, Some(Shader::Binary(data)) => { // The script parser should have ensured that there’s // only one shader assert_eq!(shaders.len(), 1); load_binary_stage( logger, context, data, show_disassembly ) }, } } #[cfg(test)] mod test { use super::*; use crate::fake_vulkan::{FakeVulkan, HandleType}; use crate::context::Context; use crate::requirements::Requirements; use crate::source::Source; use crate::config::Config; use std::ffi::{c_char, c_void, CStr}; struct CompileOutput { log: Vec<String>, result: Result<Vec<u32>, Error>, } extern "C" fn log_cb(message: *const c_char, user_data: *mut c_void) { unsafe { let message = CStr::from_ptr(message).to_str().unwrap().to_owned(); let log = &mut *(user_data as *mut Vec<String>); log.push(message); } } fn compile_script( source: &str, stage: shader_stage::Stage, show_disassembly: bool, ) -> CompileOutput { let mut fake_vulkan = FakeVulkan::new(); fake_vulkan.physical_devices.push(Default::default()); compile_script_with_fake_vulkan( &mut fake_vulkan, source, stage, show_disassembly ) } fn compile_script_with_fake_vulkan( fake_vulkan: &mut FakeVulkan, source: &str, stage: shader_stage::Stage, show_disassembly: bool, ) -> CompileOutput { fake_vulkan.set_override(); let context = Context::new(&Requirements::new(), None).unwrap(); let source = Source::from_string(source.to_owned()); let script = Script::load(&Config::new(), &source).unwrap(); let mut log = Vec::new(); let mut logger = Logger::new( Some(log_cb), ptr::addr_of_mut!(log).cast(), ); let result = build_stage( &mut logger, &context, &script, stage, show_disassembly, ).map(|module| { let code = match &fake_vulkan.get_handle(module).data { HandleType::ShaderModule { code } => code.clone(), _ => unreachable!("Unexpected Vulkan handle type"), }; unsafe { context.device().vkDestroyShaderModule.unwrap()( context.vk_device(), module, ptr::null(), // allocator ); } code }); CompileOutput { log, result } } #[test] fn glsl_le() { let CompileOutput { log, result } = compile_script( "[fragment shader]\n\ 03 02 23 07\n\ fe ca fe ca\n", shader_stage::Stage::Fragment, false, // show_disassembly ); assert_eq!( &log, &[ "quiet", "vulkan_spirv", "target_env: vulkan1.0", "stage: frag", ], ); assert_eq!(result.unwrap(), &[0x07230203, 0xcafecafe]); } #[test] fn glsl_be() { let CompileOutput { log, result } = compile_script( "[vertex shader]\n\ 07 23 02 03\n\ ca fe ca fe\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert_eq!( &log, &[ "quiet", "vulkan_spirv", "target_env: vulkan1.0", "stage: vert", ], ); assert_eq!(result.unwrap(), &[0x07230203, 0xcafecafe]); } #[test] fn spirv() { let CompileOutput { log, result } = compile_script( "[vertex shader spirv]\n\ 07 23 02 03\n\ f0 0d fe ed\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert_eq!(&log, &["target_env: vulkan1.0"]); assert_eq!(result.unwrap(), &[0x07230203, 0xf00dfeed]); } #[test] fn binary() { let CompileOutput { log, result } = compile_script( "[vertex shader binary]\n\ 07230203\n\ f00dfeed\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert!(log.is_empty()); assert_eq!(result.unwrap(), &[0x07230203, 0xf00dfeed]); } fn test_stage( stage: shader_stage::Stage, section_name: &str, compiler_argument: &str ) { let CompileOutput { log, result } = compile_script( &format!( "[{}]\n\ 07 23 02 03\n", section_name, ), stage, false, // show_disassembly ); assert_eq!( &log, &[ "quiet", "vulkan_spirv", "target_env: vulkan1.0", &format!("stage: {}", compiler_argument) ] ); assert!(result.is_ok()); } #[test] fn all_stages() { test_stage( shader_stage::Stage::Vertex, "vertex shader", "vert" ); test_stage( shader_stage::Stage::TessCtrl, "tessellation control shader", "tesc" ); test_stage( shader_stage::Stage::TessEval, "tessellation evaluation shader", "tese" ); test_stage( shader_stage::Stage::Geometry, "geometry shader", "geom" ); test_stage( shader_stage::Stage::Fragment, "fragment shader", "frag" ); test_stage( shader_stage::Stage::Compute, "compute shader", "comp" ); } #[test] fn no_shaders() { let CompileOutput { result, .. } = compile_script( "[vertex shader]\n\ 07 23 02 03\n", shader_stage::Stage::Fragment, false, // show_disassembly ); assert_eq!( &result.unwrap_err().to_string(), "No shaders for stage Fragment", ); } #[test] fn create_shader_module_error() { let mut fake_vulkan = FakeVulkan::new(); fake_vulkan.physical_devices.push(Default::default()); fake_vulkan.queue_result( "vkCreateShaderModule".to_string(), vk::VK_ERROR_UNKNOWN ); let CompileOutput { result, .. } = compile_script_with_fake_vulkan( &mut fake_vulkan, "[vertex shader]\n\ 07 23 02 03\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert_eq!( &result.unwrap_err().to_string(), "vkCreateShaderModule failed", ); } #[test] fn invalid_magic() { let CompileOutput { result, .. } = compile_script( "[vertex shader]\n\ 12 34 56 78\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert_eq!( &result.unwrap_err().to_string(), "The compiler or assembler generated an invalid SPIR-V binary", ); } #[test] fn not_multiple_of_u32() { let CompileOutput { result, .. } = compile_script( "[vertex shader]\n\ 07 23 02 03 9a\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert_eq!( &result.unwrap_err().to_string(), "The compiler or assembler generated an invalid SPIR-V binary", ); } #[test] fn compiler_failed() { let CompileOutput { result, .. } = compile_script( "[vertex shader]\n\ invalid hex values\n", shader_stage::Stage::Vertex, false, // show_disassembly ); assert_eq!( &result.unwrap_err().to_string(), "A subprocess failed with a non-zero exit status", ); } fn test_show_disassembly(section_suffix: &str) { let CompileOutput { log, result } = compile_script( &format!( "[fragment shader{}]\n\ 03 02 23 07\n\ fe ca fe ca\n", section_suffix, ), shader_stage::Stage::Fragment, true, // show_disassembly ); assert!(log.iter().find(|&line| line == "disassembly").is_some()); assert!(result.is_ok()); } #[test] fn show_glsl_disassembly() { test_show_disassembly(""); } #[test] fn show_spirv_disassembly() { test_show_disassembly(" spirv"); } #[test] fn show_binary_disassembly() { test_show_disassembly(" binary"); } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/format.rs: -------------------------------------------------------------------------------- ```rust // vkrunner // // Copyright (C) 2018 Intel Corporation // Copyright 2023 Neil Roberts // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // on the rights to use, copy, modify, merge, publish, distribute, sub // license, and/or sell copies of the Software, and to permit persons to whom // the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice (including the next // paragraph) shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL // VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. use crate::small_float; use crate::half_float; use crate::vk; use std::convert::TryInto; use std::num::NonZeroUsize; #[derive(Debug)] pub struct Format { pub(crate) vk_format: vk::VkFormat, pub(crate) name: &'static str, pub(crate) packed_size: Option<NonZeroUsize>, n_parts: usize, parts: [Part; 4], } #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub(crate) enum Component { R, G, B, A, D, S, X, } #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub(crate) enum Mode { UNORM, SNORM, USCALED, SSCALED, UINT, SINT, UFLOAT, SFLOAT, SRGB, } #[derive(Debug, PartialEq, Eq)] pub(crate) struct Part { pub bits: usize, pub component: Component, pub mode: Mode, } include!{"format_table.rs"} impl PartialEq for Format { #[inline] fn eq(&self, other: &Format) -> bool { // If the Vulkan format enum is the same then everything else // about the format should be the same too self.vk_format == other.vk_format } } impl PartialEq<vk::VkFormat> for Format { #[inline] fn eq(&self, other: &vk::VkFormat) -> bool { self.vk_format == *other } } impl PartialEq<Format> for vk::VkFormat { #[inline] fn eq(&self, other: &Format) -> bool { *self == other.vk_format } } impl Format { pub(crate) fn lookup_by_name(name: &str) -> Option<&'static Format> { match FORMATS.binary_search_by(|format| format.name.cmp(name)) { Ok(pos) => Some(&FORMATS[pos]), Err(_) => None, } } pub(crate) fn lookup_by_vk_format( vk_format: vk::VkFormat ) -> &'static Format { for format in FORMATS.iter() { if format.vk_format == vk_format { return format; } } unreachable!("lookup failed for format {:?}", vk_format); } pub(crate) fn lookup_by_details( bit_size: usize, mode: Mode, n_components: usize ) -> Option<&'static Format> { static COMP_ORDER: [Component; 4] = [ Component::R, Component::G, Component::B, Component::A, ]; 'format_loop: for format in FORMATS.iter() { if format.n_parts != n_components { continue; } if let Some(_) = format.packed_size { continue; } for (i, part) in format.parts().iter().enumerate() { if part.bits != bit_size || part.component != COMP_ORDER[i] || part.mode != mode { continue 'format_loop; } } return Some(format); } None } pub(crate) fn parts(&self) -> &[Part] { &self.parts[0..self.n_parts] } pub fn size(&self) -> usize { match self.packed_size { Some(size) => usize::from(size) / 8, None => self.parts().iter().map(|p| p.bits).sum::<usize>() / 8, } } pub(crate) fn packed_size(&self) -> Option<usize> { self.packed_size.map(|s| usize::from(s)) } pub(crate) fn alignment(&self) -> usize { match self.packed_size { Some(size) => usize::from(size) / 8, None => self.parts().iter().map(|p| p.bits).max().unwrap() / 8, } } pub(crate) fn depth_stencil_aspect_flags(&self) -> vk::VkImageAspectFlags { self.parts().iter().map(|part| match part.component { Component::D => vk::VK_IMAGE_ASPECT_DEPTH_BIT, Component::S => vk::VK_IMAGE_ASPECT_STENCIL_BIT, _ => 0, }).fold(0, |a, b| a | b) } } impl Mode { fn load_packed_part(&self, part: u32, bits: usize) -> f64 { assert!(bits < 32); match self { Mode::SRGB | Mode::UNORM => part as f64 / ((1 << bits) - 1) as f64, Mode::SNORM => { sign_extend(part, bits) as f64 / ((1 << (bits - 1)) - 1) as f64 }, Mode::UINT | Mode::USCALED => part as f64, Mode::SSCALED | Mode::SINT => sign_extend(part, bits) as f64, Mode::UFLOAT => { match bits { 10 => small_float::load_unsigned(part, 5, 5), 11 => small_float::load_unsigned(part, 5, 6), _ => { unreachable!( "unknown bit size {} in packed UFLOAT \ format", bits ) }, } }, Mode::SFLOAT => unreachable!("Unexpected packed SFLOAT format"), } } fn load_part(&self, bits: usize, fb: &[u8]) -> f64 { match self { Mode::SRGB | Mode::UNORM => { match bits { 8 => fb[0] as f64 / u8::MAX as f64, 16 => { u16::from_ne_bytes(fb[0..2].try_into().unwrap()) as f64 / u16::MAX as f64 }, 24 => extract_u24(fb) as f64 / 16777215.0, 32 => { u32::from_ne_bytes(fb[0..4].try_into().unwrap()) as f64 / u32::MAX as f64 }, 64 => { u64::from_ne_bytes(fb[0..8].try_into().unwrap()) as f64 / u64::MAX as f64 }, _=> unreachable!("unsupported component bit size {}", bits), } }, Mode::SNORM => { match bits { 8 => fb[0] as i8 as f64 / i8::MAX as f64, 16 => { i16::from_ne_bytes(fb[0..2].try_into().unwrap()) as f64 / i16::MAX as f64 }, 32 => { i32::from_ne_bytes(fb[0..4].try_into().unwrap()) as f64 / i32::MAX as f64 }, 64 => { i64::from_ne_bytes(fb[0..8].try_into().unwrap()) as f64 / i64::MAX as f64 }, _=> unreachable!("unsupported component bit size {}", bits), } }, Mode::UINT | Mode::USCALED => { match bits { 8 => fb[0] as f64, 16 => { u16::from_ne_bytes(fb[0..2].try_into().unwrap()) as f64 }, 32 => { u32::from_ne_bytes(fb[0..4].try_into().unwrap()) as f64 }, 64 => { u64::from_ne_bytes(fb[0..8].try_into().unwrap()) as f64 }, _=> unreachable!("unsupported component bit size {}", bits), } }, Mode::SINT | Mode::SSCALED => { match bits { 8 => fb[0] as i8 as f64, 16 => { i16::from_ne_bytes(fb[0..2].try_into().unwrap()) as f64 }, 32 => { i32::from_ne_bytes(fb[0..4].try_into().unwrap()) as f64 }, 64 => { i64::from_ne_bytes(fb[0..8].try_into().unwrap()) as f64 }, _=> unreachable!("unsupported component bit size {}", bits), } }, Mode::UFLOAT => unreachable!("unexpected unpacked UFLOAT part"), Mode::SFLOAT => { match bits { 16 => { let bits = u16::from_ne_bytes(fb[0..2].try_into().unwrap()); half_float::to_f64(bits) }, 32 => { f32::from_ne_bytes(fb[0..4].try_into().unwrap()) as f64 }, 64 => f64::from_ne_bytes(fb[0..8].try_into().unwrap()), _ => { unreachable!( "unsupported unpacked SFLOAT size {}", bits ); }, } }, } } } impl Format { fn load_packed_parts(&self, source: &[u8], parts: &mut [f64]) { let mut packed_parts = match self.packed_size().unwrap() { 8 => source[0] as u32, 16 => u16::from_ne_bytes(source[0..2].try_into().unwrap()) as u32, 32 => u32::from_ne_bytes(source[0..4].try_into().unwrap()), _ => { unreachable!( "unsupported packed bit size {}", self.packed_size.unwrap() ); }, }; for (i, part) in self.parts().iter().enumerate().rev() { let part_bits = packed_parts & (u32::MAX >> (u32::BITS - part.bits as u32)); parts[i] = part.mode.load_packed_part(part_bits, part.bits); packed_parts >>= part.bits; } } pub fn load_pixel(&self, source: &[u8]) -> [f64; 4] { assert!(source.len() >= self.size()); assert!(self.n_parts <= 4); let mut parts = [0.0; 4]; match self.packed_size { Some(_) => self.load_packed_parts(source, &mut parts), None => { let mut source = source; for (i, part) in self.parts().iter().enumerate() { parts[i] = part.mode.load_part(part.bits, source); source = &source[part.bits / 8..]; } }, } // Set all the colour components to zero in case they aren’t // contained in the format. The alpha component default to 1.0 // if it’s not in the format. let mut pixel = [0.0, 0.0, 0.0, 1.0]; for (i, part) in self.parts().iter().enumerate() { match part.component { Component::R => pixel[0] = parts[i], Component::G => pixel[1] = parts[i], Component::B => pixel[2] = parts[i], Component::A => pixel[3] = parts[i], Component::D | Component::S | Component:: X => (), } } pixel } } fn sign_extend(part: u32, bits: usize) -> i32 { let uresult = if part & (1 << (bits - 1)) != 0 { ((u32::MAX) << bits) | part } else { part }; uresult as i32 } fn extract_u24(bytes: &[u8]) -> u32 { let mut value = 0; for i in 0..3 { let byte_pos; #[cfg(target_endian = "little")] { byte_pos = 2 - i; } #[cfg(not(target_endian = "little"))] { byte_pos = i; } value = ((value) << 8) | bytes[byte_pos] as u32; } value } #[cfg(test)] mod test { use super::*; #[test] fn test_lookup_by_name() { // Test that we can find every name for format in FORMATS.iter() { let other_format = match Format::lookup_by_name(format.name) { Some(f) => f, None => unreachable!("lookup for {} failed", format.name), }; // Assert that it returns a reference to the same object assert!(std::ptr::eq(format, other_format)); } // Test that a similar name fails assert!(matches!(Format::lookup_by_name("B8G8R8_SRGBC"), None)); } #[test] fn test_lookup_by_vk_format() { // Test that we can find every format for format in FORMATS.iter() { let other_format = Format::lookup_by_vk_format(format.vk_format); // Assert that it returns a reference to the same object assert!(std::ptr::eq(format, other_format)); } } #[test] fn test_lookup_by_details() { let expected_format = Format::lookup_by_vk_format(vk::VK_FORMAT_R8G8B8_UNORM); assert_eq!( Format::lookup_by_details(8, Mode::UNORM, 3), Some(expected_format), ); let expected_format = Format::lookup_by_vk_format(vk::VK_FORMAT_R64G64B64A64_SFLOAT); assert_eq!( Format::lookup_by_details(64, Mode::SFLOAT, 4), Some(expected_format), ); assert_eq!( Format::lookup_by_details(64, Mode::UFLOAT, 4), None ); } #[test] fn test_parts() { // Check that parts returns the right size slice for each type for format in FORMATS.iter() { assert_eq!(format.parts().len(), format.n_parts); } // Check some types assert_eq!( Format::lookup_by_vk_format(vk::VK_FORMAT_R8_UINT).parts(), &[Part { bits: 8, component: Component::R, mode: Mode::UINT }] ); assert_eq!( Format::lookup_by_vk_format(vk::VK_FORMAT_B5G6R5_UNORM_PACK16) .parts(), &[ Part { bits: 5, component: Component::B, mode: Mode::UNORM }, Part { bits: 6, component: Component::G, mode: Mode::UNORM }, Part { bits: 5, component: Component::R, mode: Mode::UNORM }, ] ); } #[test] fn test_size() { assert_eq!( Format::lookup_by_vk_format(vk::VK_FORMAT_B8G8R8_UINT).size(), 3 ); assert_eq!( Format::lookup_by_vk_format(vk::VK_FORMAT_R16G16_SINT).size(), 4 ); assert_eq!( Format::lookup_by_vk_format(vk::VK_FORMAT_B5G6R5_UNORM_PACK16) .size(), 2 ); } #[test] fn test_sign_extend() { assert_eq!(sign_extend(0xff, 8), -1); assert_eq!(sign_extend(1, 8), 1); } fn assert_float_equal(a: f64, b: f64) { assert!((a - b).abs() < 0.01, "a={}, b={}", a, b); } #[test] fn test_load_packed_part() { // Test that there are no formats with unsupported packed modes for format in FORMATS.iter() { if let Some(_) = format.packed_size { for part in format.parts().iter() { part.mode.load_packed_part(0, part.bits); } } } assert_float_equal(Mode::SRGB.load_packed_part(0x80, 8), 0.5); assert_float_equal(Mode::SNORM.load_packed_part(0x80, 8), -1.0); assert_float_equal(Mode::SNORM.load_packed_part(0x7f, 8), 1.0); assert_float_equal(Mode::UINT.load_packed_part(42, 8), 42.0); assert_float_equal(Mode::SINT.load_packed_part(0xff, 8), -1.0); assert_float_equal(Mode::UFLOAT.load_packed_part(0x1e0, 10), 1.0); assert_float_equal(Mode::UFLOAT.load_packed_part(0x3c0, 11), 1.0); } fn load_part(mode: Mode, bits: usize, fb_bytes: u64) -> f64 { let mut fb = Vec::new(); let n_bytes = bits / 8; for i in 0..n_bytes { let byte_pos; #[cfg(target_endian = "little")] { byte_pos = i } #[cfg(not(target_endian = "little"))] { byte_pos = n_bytes - 1 - i } fb.push(((fb_bytes >> (byte_pos * 8)) & 0xff) as u8); } mode.load_part(bits, &fb) } #[test] fn test_load_part() { let dummy_array = [0u8; 8]; // Test that there are no formats with unsupported unpacked modes for format in FORMATS.iter() { if let None = format.packed_size { for part in format.parts().iter() { assert!(part.bits <= dummy_array.len() * 8); part.mode.load_part(part.bits, &dummy_array); } } } assert_float_equal(load_part(Mode::UNORM, 8, 0x80), 0.5); assert_float_equal(load_part(Mode::UNORM, 16, 0x8000), 0.5); assert_float_equal(load_part(Mode::UNORM, 24, 0x800000), 0.5); assert_float_equal(load_part(Mode::UNORM, 32, 0x80000000), 0.5); assert_float_equal(load_part(Mode::UNORM, 64, 0x8000000000000000), 0.5); assert_float_equal(load_part(Mode::SNORM, 8, 0x81), -1.0); assert_float_equal(load_part(Mode::SNORM, 16, 0x8001), -1.0); assert_float_equal(load_part(Mode::SNORM, 32, 0x80000001), -1.0); assert_float_equal( load_part(Mode::SNORM, 64, 0x8000000000000001), -1.0 ); assert_float_equal(load_part(Mode::UINT, 8, 0x80), 128.0); assert_float_equal(load_part(Mode::UINT, 16, 0x8000), 32768.0); assert_float_equal(load_part(Mode::UINT, 32, 0x80000000), 2147483648.0); assert_float_equal( load_part(Mode::UINT, 64, 0x200000000), 8589934592.0, ); assert_float_equal(load_part(Mode::SINT, 8, 0x80), -128.0); assert_float_equal(load_part(Mode::SINT, 16, 0x8000), -32768.0); assert_float_equal( load_part(Mode::SINT, 32, 0x80000000), -2147483648.0 ); assert_float_equal( load_part(Mode::SINT, 64, u64::MAX), -1.0, ); assert_float_equal(load_part(Mode::SFLOAT, 16, 0x3c00), 1.0); assert_float_equal(load_part(Mode::SFLOAT, 32, 0x3f800000), 1.0); assert_float_equal( load_part(Mode::SFLOAT, 64, 0xbfe0000000000000), -0.5 ); } #[test] fn test_load_pixel() { let dummy_source = [0u8; 32]; // Test that the code handles every format for format in FORMATS.iter() { format.load_pixel(&dummy_source); } let source_data = [5.0f64, 4.0f64, -3.0f64, 0.5f64]; let pixel: Vec<u8> = source_data .iter() .map(|v| v.to_ne_bytes()) .flatten() .collect(); let format = Format::lookup_by_vk_format(vk::VK_FORMAT_R64G64B64A64_SFLOAT); assert_eq!(format.load_pixel(&pixel), source_data); // Try a depth-stencil format. This should just return the // default rgb values. let format = Format::lookup_by_vk_format(vk::VK_FORMAT_D24_UNORM_S8_UINT); assert_eq!(format.load_pixel(&[0xff; 4]), [0.0, 0.0, 0.0, 1.0]); // Packed format let format = Format::lookup_by_vk_format(vk::VK_FORMAT_R5G6B5_UNORM_PACK16); let pixel = format.load_pixel(&0xae27u16.to_ne_bytes()); let expected = [ 0b10101 as f64 / 0b11111 as f64, 0b110001 as f64 / 0b111111 as f64, 0b00111 as f64 / 0b11111 as f64, 1.0, ]; for (i, &pixel_comp) in pixel.iter().enumerate() { assert_float_equal(pixel_comp, expected[i]); } } #[test] fn test_alignment() { let format = Format::lookup_by_vk_format(vk::VK_FORMAT_R5G6B5_UNORM_PACK16); assert_eq!(format.alignment(), 2); let format = Format::lookup_by_vk_format(vk::VK_FORMAT_D24_UNORM_S8_UINT); assert_eq!(format.alignment(), 3); let format = Format::lookup_by_vk_format(vk::VK_FORMAT_R8G8B8_UNORM); assert_eq!(format.alignment(), 1); } } ``` -------------------------------------------------------------------------------- /vkrunner/vkrunner/enum_table.rs: -------------------------------------------------------------------------------- ```rust // Automatically generated by make-enums.py static ENUM_VALUES: [EnumValue; 174] = [ EnumValue { name: "VK_BLEND_FACTOR_CONSTANT_ALPHA", value: vk::VK_BLEND_FACTOR_CONSTANT_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_CONSTANT_COLOR", value: vk::VK_BLEND_FACTOR_CONSTANT_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_DST_ALPHA", value: vk::VK_BLEND_FACTOR_DST_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_DST_COLOR", value: vk::VK_BLEND_FACTOR_DST_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_MAX_ENUM", value: vk::VK_BLEND_FACTOR_MAX_ENUM as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE", value: vk::VK_BLEND_FACTOR_ONE as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA", value: vk::VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR", value: vk::VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA", value: vk::VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR", value: vk::VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA", value: vk::VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR", value: vk::VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA", value: vk::VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR", value: vk::VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_SRC1_ALPHA", value: vk::VK_BLEND_FACTOR_SRC1_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_SRC1_COLOR", value: vk::VK_BLEND_FACTOR_SRC1_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_SRC_ALPHA", value: vk::VK_BLEND_FACTOR_SRC_ALPHA as i32 }, EnumValue { name: "VK_BLEND_FACTOR_SRC_ALPHA_SATURATE", value: vk::VK_BLEND_FACTOR_SRC_ALPHA_SATURATE as i32 }, EnumValue { name: "VK_BLEND_FACTOR_SRC_COLOR", value: vk::VK_BLEND_FACTOR_SRC_COLOR as i32 }, EnumValue { name: "VK_BLEND_FACTOR_ZERO", value: vk::VK_BLEND_FACTOR_ZERO as i32 }, EnumValue { name: "VK_BLEND_OP_ADD", value: vk::VK_BLEND_OP_ADD as i32 }, EnumValue { name: "VK_BLEND_OP_BLUE_EXT", value: vk::VK_BLEND_OP_BLUE_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_COLORBURN_EXT", value: vk::VK_BLEND_OP_COLORBURN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_COLORDODGE_EXT", value: vk::VK_BLEND_OP_COLORDODGE_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_CONTRAST_EXT", value: vk::VK_BLEND_OP_CONTRAST_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DARKEN_EXT", value: vk::VK_BLEND_OP_DARKEN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DIFFERENCE_EXT", value: vk::VK_BLEND_OP_DIFFERENCE_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DST_ATOP_EXT", value: vk::VK_BLEND_OP_DST_ATOP_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DST_EXT", value: vk::VK_BLEND_OP_DST_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DST_IN_EXT", value: vk::VK_BLEND_OP_DST_IN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DST_OUT_EXT", value: vk::VK_BLEND_OP_DST_OUT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_DST_OVER_EXT", value: vk::VK_BLEND_OP_DST_OVER_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_EXCLUSION_EXT", value: vk::VK_BLEND_OP_EXCLUSION_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_GREEN_EXT", value: vk::VK_BLEND_OP_GREEN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_HARDLIGHT_EXT", value: vk::VK_BLEND_OP_HARDLIGHT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_HARDMIX_EXT", value: vk::VK_BLEND_OP_HARDMIX_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_HSL_COLOR_EXT", value: vk::VK_BLEND_OP_HSL_COLOR_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_HSL_HUE_EXT", value: vk::VK_BLEND_OP_HSL_HUE_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_HSL_LUMINOSITY_EXT", value: vk::VK_BLEND_OP_HSL_LUMINOSITY_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_HSL_SATURATION_EXT", value: vk::VK_BLEND_OP_HSL_SATURATION_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_INVERT_EXT", value: vk::VK_BLEND_OP_INVERT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_INVERT_OVG_EXT", value: vk::VK_BLEND_OP_INVERT_OVG_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_INVERT_RGB_EXT", value: vk::VK_BLEND_OP_INVERT_RGB_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_LIGHTEN_EXT", value: vk::VK_BLEND_OP_LIGHTEN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_LINEARBURN_EXT", value: vk::VK_BLEND_OP_LINEARBURN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_LINEARDODGE_EXT", value: vk::VK_BLEND_OP_LINEARDODGE_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_LINEARLIGHT_EXT", value: vk::VK_BLEND_OP_LINEARLIGHT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_MAX", value: vk::VK_BLEND_OP_MAX as i32 }, EnumValue { name: "VK_BLEND_OP_MAX_ENUM", value: vk::VK_BLEND_OP_MAX_ENUM as i32 }, EnumValue { name: "VK_BLEND_OP_MIN", value: vk::VK_BLEND_OP_MIN as i32 }, EnumValue { name: "VK_BLEND_OP_MINUS_CLAMPED_EXT", value: vk::VK_BLEND_OP_MINUS_CLAMPED_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_MINUS_EXT", value: vk::VK_BLEND_OP_MINUS_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_MULTIPLY_EXT", value: vk::VK_BLEND_OP_MULTIPLY_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_OVERLAY_EXT", value: vk::VK_BLEND_OP_OVERLAY_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_PINLIGHT_EXT", value: vk::VK_BLEND_OP_PINLIGHT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT", value: vk::VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_PLUS_CLAMPED_EXT", value: vk::VK_BLEND_OP_PLUS_CLAMPED_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_PLUS_DARKER_EXT", value: vk::VK_BLEND_OP_PLUS_DARKER_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_PLUS_EXT", value: vk::VK_BLEND_OP_PLUS_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_RED_EXT", value: vk::VK_BLEND_OP_RED_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_REVERSE_SUBTRACT", value: vk::VK_BLEND_OP_REVERSE_SUBTRACT as i32 }, EnumValue { name: "VK_BLEND_OP_SCREEN_EXT", value: vk::VK_BLEND_OP_SCREEN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SOFTLIGHT_EXT", value: vk::VK_BLEND_OP_SOFTLIGHT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SRC_ATOP_EXT", value: vk::VK_BLEND_OP_SRC_ATOP_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SRC_EXT", value: vk::VK_BLEND_OP_SRC_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SRC_IN_EXT", value: vk::VK_BLEND_OP_SRC_IN_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SRC_OUT_EXT", value: vk::VK_BLEND_OP_SRC_OUT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SRC_OVER_EXT", value: vk::VK_BLEND_OP_SRC_OVER_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_SUBTRACT", value: vk::VK_BLEND_OP_SUBTRACT as i32 }, EnumValue { name: "VK_BLEND_OP_VIVIDLIGHT_EXT", value: vk::VK_BLEND_OP_VIVIDLIGHT_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_XOR_EXT", value: vk::VK_BLEND_OP_XOR_EXT as i32 }, EnumValue { name: "VK_BLEND_OP_ZERO_EXT", value: vk::VK_BLEND_OP_ZERO_EXT as i32 }, EnumValue { name: "VK_COLOR_COMPONENT_A_BIT", value: vk::VK_COLOR_COMPONENT_A_BIT as i32 }, EnumValue { name: "VK_COLOR_COMPONENT_B_BIT", value: vk::VK_COLOR_COMPONENT_B_BIT as i32 }, EnumValue { name: "VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM", value: vk::VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM as i32 }, EnumValue { name: "VK_COLOR_COMPONENT_G_BIT", value: vk::VK_COLOR_COMPONENT_G_BIT as i32 }, EnumValue { name: "VK_COLOR_COMPONENT_R_BIT", value: vk::VK_COLOR_COMPONENT_R_BIT as i32 }, EnumValue { name: "VK_COMPARE_OP_ALWAYS", value: vk::VK_COMPARE_OP_ALWAYS as i32 }, EnumValue { name: "VK_COMPARE_OP_EQUAL", value: vk::VK_COMPARE_OP_EQUAL as i32 }, EnumValue { name: "VK_COMPARE_OP_GREATER", value: vk::VK_COMPARE_OP_GREATER as i32 }, EnumValue { name: "VK_COMPARE_OP_GREATER_OR_EQUAL", value: vk::VK_COMPARE_OP_GREATER_OR_EQUAL as i32 }, EnumValue { name: "VK_COMPARE_OP_LESS", value: vk::VK_COMPARE_OP_LESS as i32 }, EnumValue { name: "VK_COMPARE_OP_LESS_OR_EQUAL", value: vk::VK_COMPARE_OP_LESS_OR_EQUAL as i32 }, EnumValue { name: "VK_COMPARE_OP_MAX_ENUM", value: vk::VK_COMPARE_OP_MAX_ENUM as i32 }, EnumValue { name: "VK_COMPARE_OP_NEVER", value: vk::VK_COMPARE_OP_NEVER as i32 }, EnumValue { name: "VK_COMPARE_OP_NOT_EQUAL", value: vk::VK_COMPARE_OP_NOT_EQUAL as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_BFLOAT16_KHR", value: vk::VK_COMPONENT_TYPE_BFLOAT16_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT16_KHR", value: vk::VK_COMPONENT_TYPE_FLOAT16_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT16_NV", value: vk::VK_COMPONENT_TYPE_FLOAT16_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT32_KHR", value: vk::VK_COMPONENT_TYPE_FLOAT32_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT32_NV", value: vk::VK_COMPONENT_TYPE_FLOAT32_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT64_KHR", value: vk::VK_COMPONENT_TYPE_FLOAT64_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT64_NV", value: vk::VK_COMPONENT_TYPE_FLOAT64_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT_E4M3_NV", value: vk::VK_COMPONENT_TYPE_FLOAT_E4M3_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_FLOAT_E5M2_NV", value: vk::VK_COMPONENT_TYPE_FLOAT_E5M2_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_MAX_ENUM_KHR", value: vk::VK_COMPONENT_TYPE_MAX_ENUM_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT16_KHR", value: vk::VK_COMPONENT_TYPE_SINT16_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT16_NV", value: vk::VK_COMPONENT_TYPE_SINT16_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT32_KHR", value: vk::VK_COMPONENT_TYPE_SINT32_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT32_NV", value: vk::VK_COMPONENT_TYPE_SINT32_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT64_KHR", value: vk::VK_COMPONENT_TYPE_SINT64_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT64_NV", value: vk::VK_COMPONENT_TYPE_SINT64_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT8_KHR", value: vk::VK_COMPONENT_TYPE_SINT8_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT8_NV", value: vk::VK_COMPONENT_TYPE_SINT8_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_SINT8_PACKED_NV", value: vk::VK_COMPONENT_TYPE_SINT8_PACKED_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT16_KHR", value: vk::VK_COMPONENT_TYPE_UINT16_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT16_NV", value: vk::VK_COMPONENT_TYPE_UINT16_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT32_KHR", value: vk::VK_COMPONENT_TYPE_UINT32_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT32_NV", value: vk::VK_COMPONENT_TYPE_UINT32_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT64_KHR", value: vk::VK_COMPONENT_TYPE_UINT64_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT64_NV", value: vk::VK_COMPONENT_TYPE_UINT64_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT8_KHR", value: vk::VK_COMPONENT_TYPE_UINT8_KHR as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT8_NV", value: vk::VK_COMPONENT_TYPE_UINT8_NV as i32 }, EnumValue { name: "VK_COMPONENT_TYPE_UINT8_PACKED_NV", value: vk::VK_COMPONENT_TYPE_UINT8_PACKED_NV as i32 }, EnumValue { name: "VK_CULL_MODE_BACK_BIT", value: vk::VK_CULL_MODE_BACK_BIT as i32 }, EnumValue { name: "VK_CULL_MODE_FLAG_BITS_MAX_ENUM", value: vk::VK_CULL_MODE_FLAG_BITS_MAX_ENUM as i32 }, EnumValue { name: "VK_CULL_MODE_FRONT_AND_BACK", value: vk::VK_CULL_MODE_FRONT_AND_BACK as i32 }, EnumValue { name: "VK_CULL_MODE_FRONT_BIT", value: vk::VK_CULL_MODE_FRONT_BIT as i32 }, EnumValue { name: "VK_CULL_MODE_NONE", value: vk::VK_CULL_MODE_NONE as i32 }, EnumValue { name: "VK_FRONT_FACE_CLOCKWISE", value: vk::VK_FRONT_FACE_CLOCKWISE as i32 }, EnumValue { name: "VK_FRONT_FACE_COUNTER_CLOCKWISE", value: vk::VK_FRONT_FACE_COUNTER_CLOCKWISE as i32 }, EnumValue { name: "VK_FRONT_FACE_MAX_ENUM", value: vk::VK_FRONT_FACE_MAX_ENUM as i32 }, EnumValue { name: "VK_LOGIC_OP_AND", value: vk::VK_LOGIC_OP_AND as i32 }, EnumValue { name: "VK_LOGIC_OP_AND_INVERTED", value: vk::VK_LOGIC_OP_AND_INVERTED as i32 }, EnumValue { name: "VK_LOGIC_OP_AND_REVERSE", value: vk::VK_LOGIC_OP_AND_REVERSE as i32 }, EnumValue { name: "VK_LOGIC_OP_CLEAR", value: vk::VK_LOGIC_OP_CLEAR as i32 }, EnumValue { name: "VK_LOGIC_OP_COPY", value: vk::VK_LOGIC_OP_COPY as i32 }, EnumValue { name: "VK_LOGIC_OP_COPY_INVERTED", value: vk::VK_LOGIC_OP_COPY_INVERTED as i32 }, EnumValue { name: "VK_LOGIC_OP_EQUIVALENT", value: vk::VK_LOGIC_OP_EQUIVALENT as i32 }, EnumValue { name: "VK_LOGIC_OP_INVERT", value: vk::VK_LOGIC_OP_INVERT as i32 }, EnumValue { name: "VK_LOGIC_OP_MAX_ENUM", value: vk::VK_LOGIC_OP_MAX_ENUM as i32 }, EnumValue { name: "VK_LOGIC_OP_NAND", value: vk::VK_LOGIC_OP_NAND as i32 }, EnumValue { name: "VK_LOGIC_OP_NOR", value: vk::VK_LOGIC_OP_NOR as i32 }, EnumValue { name: "VK_LOGIC_OP_NO_OP", value: vk::VK_LOGIC_OP_NO_OP as i32 }, EnumValue { name: "VK_LOGIC_OP_OR", value: vk::VK_LOGIC_OP_OR as i32 }, EnumValue { name: "VK_LOGIC_OP_OR_INVERTED", value: vk::VK_LOGIC_OP_OR_INVERTED as i32 }, EnumValue { name: "VK_LOGIC_OP_OR_REVERSE", value: vk::VK_LOGIC_OP_OR_REVERSE as i32 }, EnumValue { name: "VK_LOGIC_OP_SET", value: vk::VK_LOGIC_OP_SET as i32 }, EnumValue { name: "VK_LOGIC_OP_XOR", value: vk::VK_LOGIC_OP_XOR as i32 }, EnumValue { name: "VK_POLYGON_MODE_FILL", value: vk::VK_POLYGON_MODE_FILL as i32 }, EnumValue { name: "VK_POLYGON_MODE_FILL_RECTANGLE_NV", value: vk::VK_POLYGON_MODE_FILL_RECTANGLE_NV as i32 }, EnumValue { name: "VK_POLYGON_MODE_LINE", value: vk::VK_POLYGON_MODE_LINE as i32 }, EnumValue { name: "VK_POLYGON_MODE_MAX_ENUM", value: vk::VK_POLYGON_MODE_MAX_ENUM as i32 }, EnumValue { name: "VK_POLYGON_MODE_POINT", value: vk::VK_POLYGON_MODE_POINT as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_LINE_LIST", value: vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY", value: vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP", value: vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY", value: vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_MAX_ENUM", value: vk::VK_PRIMITIVE_TOPOLOGY_MAX_ENUM as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST", value: vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_POINT_LIST", value: vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN", value: vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST", value: vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY", value: vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP", value: vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP as i32 }, EnumValue { name: "VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY", value: vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY as i32 }, EnumValue { name: "VK_SCOPE_DEVICE_KHR", value: vk::VK_SCOPE_DEVICE_KHR as i32 }, EnumValue { name: "VK_SCOPE_DEVICE_NV", value: vk::VK_SCOPE_DEVICE_NV as i32 }, EnumValue { name: "VK_SCOPE_MAX_ENUM_KHR", value: vk::VK_SCOPE_MAX_ENUM_KHR as i32 }, EnumValue { name: "VK_SCOPE_QUEUE_FAMILY_KHR", value: vk::VK_SCOPE_QUEUE_FAMILY_KHR as i32 }, EnumValue { name: "VK_SCOPE_QUEUE_FAMILY_NV", value: vk::VK_SCOPE_QUEUE_FAMILY_NV as i32 }, EnumValue { name: "VK_SCOPE_SUBGROUP_KHR", value: vk::VK_SCOPE_SUBGROUP_KHR as i32 }, EnumValue { name: "VK_SCOPE_SUBGROUP_NV", value: vk::VK_SCOPE_SUBGROUP_NV as i32 }, EnumValue { name: "VK_SCOPE_WORKGROUP_KHR", value: vk::VK_SCOPE_WORKGROUP_KHR as i32 }, EnumValue { name: "VK_SCOPE_WORKGROUP_NV", value: vk::VK_SCOPE_WORKGROUP_NV as i32 }, EnumValue { name: "VK_STENCIL_OP_DECREMENT_AND_CLAMP", value: vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP as i32 }, EnumValue { name: "VK_STENCIL_OP_DECREMENT_AND_WRAP", value: vk::VK_STENCIL_OP_DECREMENT_AND_WRAP as i32 }, EnumValue { name: "VK_STENCIL_OP_INCREMENT_AND_CLAMP", value: vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP as i32 }, EnumValue { name: "VK_STENCIL_OP_INCREMENT_AND_WRAP", value: vk::VK_STENCIL_OP_INCREMENT_AND_WRAP as i32 }, EnumValue { name: "VK_STENCIL_OP_INVERT", value: vk::VK_STENCIL_OP_INVERT as i32 }, EnumValue { name: "VK_STENCIL_OP_KEEP", value: vk::VK_STENCIL_OP_KEEP as i32 }, EnumValue { name: "VK_STENCIL_OP_MAX_ENUM", value: vk::VK_STENCIL_OP_MAX_ENUM as i32 }, EnumValue { name: "VK_STENCIL_OP_REPLACE", value: vk::VK_STENCIL_OP_REPLACE as i32 }, EnumValue { name: "VK_STENCIL_OP_ZERO", value: vk::VK_STENCIL_OP_ZERO as i32 }, ]; ```