wgpu_hal/vulkan/
conv.rs

1use alloc::vec::Vec;
2
3use ash::vk;
4
5impl super::PrivateCapabilities {
6    pub fn map_texture_format(&self, format: wgt::TextureFormat) -> vk::Format {
7        use ash::vk::Format as F;
8        use wgt::TextureFormat as Tf;
9        use wgt::{AstcBlock, AstcChannel};
10        match format {
11            Tf::R8Unorm => F::R8_UNORM,
12            Tf::R8Snorm => F::R8_SNORM,
13            Tf::R8Uint => F::R8_UINT,
14            Tf::R8Sint => F::R8_SINT,
15            Tf::R16Uint => F::R16_UINT,
16            Tf::R16Sint => F::R16_SINT,
17            Tf::R16Unorm => F::R16_UNORM,
18            Tf::R16Snorm => F::R16_SNORM,
19            Tf::R16Float => F::R16_SFLOAT,
20            Tf::Rg8Unorm => F::R8G8_UNORM,
21            Tf::Rg8Snorm => F::R8G8_SNORM,
22            Tf::Rg8Uint => F::R8G8_UINT,
23            Tf::Rg8Sint => F::R8G8_SINT,
24            Tf::Rg16Unorm => F::R16G16_UNORM,
25            Tf::Rg16Snorm => F::R16G16_SNORM,
26            Tf::R32Uint => F::R32_UINT,
27            Tf::R32Sint => F::R32_SINT,
28            Tf::R32Float => F::R32_SFLOAT,
29            Tf::Rg16Uint => F::R16G16_UINT,
30            Tf::Rg16Sint => F::R16G16_SINT,
31            Tf::Rg16Float => F::R16G16_SFLOAT,
32            Tf::Rgba8Unorm => F::R8G8B8A8_UNORM,
33            Tf::Rgba8UnormSrgb => F::R8G8B8A8_SRGB,
34            Tf::Bgra8UnormSrgb => F::B8G8R8A8_SRGB,
35            Tf::Rgba8Snorm => F::R8G8B8A8_SNORM,
36            Tf::Bgra8Unorm => F::B8G8R8A8_UNORM,
37            Tf::Rgba8Uint => F::R8G8B8A8_UINT,
38            Tf::Rgba8Sint => F::R8G8B8A8_SINT,
39            Tf::Rgb10a2Uint => F::A2B10G10R10_UINT_PACK32,
40            Tf::Rgb10a2Unorm => F::A2B10G10R10_UNORM_PACK32,
41            Tf::Rg11b10Ufloat => F::B10G11R11_UFLOAT_PACK32,
42            Tf::R64Uint => F::R64_UINT,
43            Tf::Rg32Uint => F::R32G32_UINT,
44            Tf::Rg32Sint => F::R32G32_SINT,
45            Tf::Rg32Float => F::R32G32_SFLOAT,
46            Tf::Rgba16Uint => F::R16G16B16A16_UINT,
47            Tf::Rgba16Sint => F::R16G16B16A16_SINT,
48            Tf::Rgba16Unorm => F::R16G16B16A16_UNORM,
49            Tf::Rgba16Snorm => F::R16G16B16A16_SNORM,
50            Tf::Rgba16Float => F::R16G16B16A16_SFLOAT,
51            Tf::Rgba32Uint => F::R32G32B32A32_UINT,
52            Tf::Rgba32Sint => F::R32G32B32A32_SINT,
53            Tf::Rgba32Float => F::R32G32B32A32_SFLOAT,
54            Tf::Depth32Float => F::D32_SFLOAT,
55            Tf::Depth32FloatStencil8 => F::D32_SFLOAT_S8_UINT,
56            Tf::Depth24Plus => {
57                if self.texture_d24 {
58                    F::X8_D24_UNORM_PACK32
59                } else {
60                    F::D32_SFLOAT
61                }
62            }
63            Tf::Depth24PlusStencil8 => {
64                if self.texture_d24_s8 {
65                    F::D24_UNORM_S8_UINT
66                } else {
67                    F::D32_SFLOAT_S8_UINT
68                }
69            }
70            Tf::Stencil8 => {
71                if self.texture_s8 {
72                    F::S8_UINT
73                } else if self.texture_d24_s8 {
74                    F::D24_UNORM_S8_UINT
75                } else {
76                    F::D32_SFLOAT_S8_UINT
77                }
78            }
79            Tf::Depth16Unorm => F::D16_UNORM,
80            Tf::NV12 => F::G8_B8R8_2PLANE_420_UNORM,
81            Tf::P010 => F::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
82            Tf::Rgb9e5Ufloat => F::E5B9G9R9_UFLOAT_PACK32,
83            Tf::Bc1RgbaUnorm => F::BC1_RGBA_UNORM_BLOCK,
84            Tf::Bc1RgbaUnormSrgb => F::BC1_RGBA_SRGB_BLOCK,
85            Tf::Bc2RgbaUnorm => F::BC2_UNORM_BLOCK,
86            Tf::Bc2RgbaUnormSrgb => F::BC2_SRGB_BLOCK,
87            Tf::Bc3RgbaUnorm => F::BC3_UNORM_BLOCK,
88            Tf::Bc3RgbaUnormSrgb => F::BC3_SRGB_BLOCK,
89            Tf::Bc4RUnorm => F::BC4_UNORM_BLOCK,
90            Tf::Bc4RSnorm => F::BC4_SNORM_BLOCK,
91            Tf::Bc5RgUnorm => F::BC5_UNORM_BLOCK,
92            Tf::Bc5RgSnorm => F::BC5_SNORM_BLOCK,
93            Tf::Bc6hRgbUfloat => F::BC6H_UFLOAT_BLOCK,
94            Tf::Bc6hRgbFloat => F::BC6H_SFLOAT_BLOCK,
95            Tf::Bc7RgbaUnorm => F::BC7_UNORM_BLOCK,
96            Tf::Bc7RgbaUnormSrgb => F::BC7_SRGB_BLOCK,
97            Tf::Etc2Rgb8Unorm => F::ETC2_R8G8B8_UNORM_BLOCK,
98            Tf::Etc2Rgb8UnormSrgb => F::ETC2_R8G8B8_SRGB_BLOCK,
99            Tf::Etc2Rgb8A1Unorm => F::ETC2_R8G8B8A1_UNORM_BLOCK,
100            Tf::Etc2Rgb8A1UnormSrgb => F::ETC2_R8G8B8A1_SRGB_BLOCK,
101            Tf::Etc2Rgba8Unorm => F::ETC2_R8G8B8A8_UNORM_BLOCK,
102            Tf::Etc2Rgba8UnormSrgb => F::ETC2_R8G8B8A8_SRGB_BLOCK,
103            Tf::EacR11Unorm => F::EAC_R11_UNORM_BLOCK,
104            Tf::EacR11Snorm => F::EAC_R11_SNORM_BLOCK,
105            Tf::EacRg11Unorm => F::EAC_R11G11_UNORM_BLOCK,
106            Tf::EacRg11Snorm => F::EAC_R11G11_SNORM_BLOCK,
107            Tf::Astc { block, channel } => match channel {
108                AstcChannel::Unorm => match block {
109                    AstcBlock::B4x4 => F::ASTC_4X4_UNORM_BLOCK,
110                    AstcBlock::B5x4 => F::ASTC_5X4_UNORM_BLOCK,
111                    AstcBlock::B5x5 => F::ASTC_5X5_UNORM_BLOCK,
112                    AstcBlock::B6x5 => F::ASTC_6X5_UNORM_BLOCK,
113                    AstcBlock::B6x6 => F::ASTC_6X6_UNORM_BLOCK,
114                    AstcBlock::B8x5 => F::ASTC_8X5_UNORM_BLOCK,
115                    AstcBlock::B8x6 => F::ASTC_8X6_UNORM_BLOCK,
116                    AstcBlock::B8x8 => F::ASTC_8X8_UNORM_BLOCK,
117                    AstcBlock::B10x5 => F::ASTC_10X5_UNORM_BLOCK,
118                    AstcBlock::B10x6 => F::ASTC_10X6_UNORM_BLOCK,
119                    AstcBlock::B10x8 => F::ASTC_10X8_UNORM_BLOCK,
120                    AstcBlock::B10x10 => F::ASTC_10X10_UNORM_BLOCK,
121                    AstcBlock::B12x10 => F::ASTC_12X10_UNORM_BLOCK,
122                    AstcBlock::B12x12 => F::ASTC_12X12_UNORM_BLOCK,
123                },
124                AstcChannel::UnormSrgb => match block {
125                    AstcBlock::B4x4 => F::ASTC_4X4_SRGB_BLOCK,
126                    AstcBlock::B5x4 => F::ASTC_5X4_SRGB_BLOCK,
127                    AstcBlock::B5x5 => F::ASTC_5X5_SRGB_BLOCK,
128                    AstcBlock::B6x5 => F::ASTC_6X5_SRGB_BLOCK,
129                    AstcBlock::B6x6 => F::ASTC_6X6_SRGB_BLOCK,
130                    AstcBlock::B8x5 => F::ASTC_8X5_SRGB_BLOCK,
131                    AstcBlock::B8x6 => F::ASTC_8X6_SRGB_BLOCK,
132                    AstcBlock::B8x8 => F::ASTC_8X8_SRGB_BLOCK,
133                    AstcBlock::B10x5 => F::ASTC_10X5_SRGB_BLOCK,
134                    AstcBlock::B10x6 => F::ASTC_10X6_SRGB_BLOCK,
135                    AstcBlock::B10x8 => F::ASTC_10X8_SRGB_BLOCK,
136                    AstcBlock::B10x10 => F::ASTC_10X10_SRGB_BLOCK,
137                    AstcBlock::B12x10 => F::ASTC_12X10_SRGB_BLOCK,
138                    AstcBlock::B12x12 => F::ASTC_12X12_SRGB_BLOCK,
139                },
140                AstcChannel::Hdr => match block {
141                    AstcBlock::B4x4 => F::ASTC_4X4_SFLOAT_BLOCK_EXT,
142                    AstcBlock::B5x4 => F::ASTC_5X4_SFLOAT_BLOCK_EXT,
143                    AstcBlock::B5x5 => F::ASTC_5X5_SFLOAT_BLOCK_EXT,
144                    AstcBlock::B6x5 => F::ASTC_6X5_SFLOAT_BLOCK_EXT,
145                    AstcBlock::B6x6 => F::ASTC_6X6_SFLOAT_BLOCK_EXT,
146                    AstcBlock::B8x5 => F::ASTC_8X5_SFLOAT_BLOCK_EXT,
147                    AstcBlock::B8x6 => F::ASTC_8X6_SFLOAT_BLOCK_EXT,
148                    AstcBlock::B8x8 => F::ASTC_8X8_SFLOAT_BLOCK_EXT,
149                    AstcBlock::B10x5 => F::ASTC_10X5_SFLOAT_BLOCK_EXT,
150                    AstcBlock::B10x6 => F::ASTC_10X6_SFLOAT_BLOCK_EXT,
151                    AstcBlock::B10x8 => F::ASTC_10X8_SFLOAT_BLOCK_EXT,
152                    AstcBlock::B10x10 => F::ASTC_10X10_SFLOAT_BLOCK_EXT,
153                    AstcBlock::B12x10 => F::ASTC_12X10_SFLOAT_BLOCK_EXT,
154                    AstcBlock::B12x12 => F::ASTC_12X12_SFLOAT_BLOCK_EXT,
155                },
156            },
157        }
158    }
159}
160
161pub fn map_vk_surface_formats(sf: vk::SurfaceFormatKHR) -> Option<wgt::TextureFormat> {
162    use ash::vk::Format as F;
163    use wgt::TextureFormat as Tf;
164    // List we care about pulled from https://vulkan.gpuinfo.org/listsurfaceformats.php.
165    // Device::create_swapchain() hardcodes linear scRGB for fp16, non-linear sRGB otherwise.
166    Some(match sf.color_space {
167        vk::ColorSpaceKHR::SRGB_NONLINEAR => match sf.format {
168            F::B8G8R8A8_UNORM => Tf::Bgra8Unorm,
169            F::B8G8R8A8_SRGB => Tf::Bgra8UnormSrgb,
170            F::R8G8B8A8_SNORM => Tf::Rgba8Snorm,
171            F::R8G8B8A8_UNORM => Tf::Rgba8Unorm,
172            F::R8G8B8A8_SRGB => Tf::Rgba8UnormSrgb,
173            F::R16G16B16A16_SNORM => Tf::Rgba16Snorm,
174            F::R16G16B16A16_UNORM => Tf::Rgba16Unorm,
175            F::A2B10G10R10_UNORM_PACK32 => Tf::Rgb10a2Unorm,
176            _ => return None,
177        },
178        vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT => match sf.format {
179            F::R16G16B16A16_SFLOAT => Tf::Rgba16Float,
180            _ => return None,
181        },
182        _ => return None,
183    })
184}
185
186impl crate::Attachment<'_, super::TextureView> {
187    pub(super) fn make_attachment_key(&self, ops: crate::AttachmentOps) -> super::AttachmentKey {
188        super::AttachmentKey {
189            format: self.view.raw_format,
190            layout: derive_image_layout(self.usage, self.view.format),
191            ops,
192        }
193    }
194}
195
196impl crate::ColorAttachment<'_, super::TextureView> {
197    pub(super) unsafe fn make_vk_clear_color(&self) -> vk::ClearColorValue {
198        let cv = &self.clear_value;
199        match self.target.view.format.sample_type(None, None).unwrap() {
200            wgt::TextureSampleType::Float { .. } => vk::ClearColorValue {
201                float32: [cv.r as f32, cv.g as f32, cv.b as f32, cv.a as f32],
202            },
203            wgt::TextureSampleType::Sint => vk::ClearColorValue {
204                int32: [cv.r as i32, cv.g as i32, cv.b as i32, cv.a as i32],
205            },
206            wgt::TextureSampleType::Uint => vk::ClearColorValue {
207                uint32: [cv.r as u32, cv.g as u32, cv.b as u32, cv.a as u32],
208            },
209            wgt::TextureSampleType::Depth => unreachable!(),
210        }
211    }
212}
213
214pub fn derive_image_layout(usage: wgt::TextureUses, format: wgt::TextureFormat) -> vk::ImageLayout {
215    // Note: depth textures are always sampled with RODS layout
216    let is_color = !format.is_depth_stencil_format();
217    match usage {
218        wgt::TextureUses::UNINITIALIZED => vk::ImageLayout::UNDEFINED,
219        wgt::TextureUses::COPY_SRC => vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
220        wgt::TextureUses::COPY_DST => vk::ImageLayout::TRANSFER_DST_OPTIMAL,
221        wgt::TextureUses::RESOURCE if is_color => vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
222        wgt::TextureUses::COLOR_TARGET => vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
223        wgt::TextureUses::DEPTH_STENCIL_WRITE => vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
224        _ => {
225            if usage == wgt::TextureUses::PRESENT {
226                vk::ImageLayout::PRESENT_SRC_KHR
227            } else if is_color {
228                vk::ImageLayout::GENERAL
229            } else {
230                vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL
231            }
232        }
233    }
234}
235
236pub fn map_texture_usage(usage: wgt::TextureUses) -> vk::ImageUsageFlags {
237    let mut flags = vk::ImageUsageFlags::empty();
238    if usage.contains(wgt::TextureUses::COPY_SRC) {
239        flags |= vk::ImageUsageFlags::TRANSFER_SRC;
240    }
241    if usage.contains(wgt::TextureUses::COPY_DST) {
242        flags |= vk::ImageUsageFlags::TRANSFER_DST;
243    }
244    if usage.contains(wgt::TextureUses::RESOURCE) {
245        flags |= vk::ImageUsageFlags::SAMPLED;
246    }
247    if usage.contains(wgt::TextureUses::COLOR_TARGET) {
248        flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
249    }
250    if usage
251        .intersects(wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::DEPTH_STENCIL_WRITE)
252    {
253        flags |= vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT;
254    }
255    if usage.intersects(
256        wgt::TextureUses::STORAGE_READ_ONLY
257            | wgt::TextureUses::STORAGE_WRITE_ONLY
258            | wgt::TextureUses::STORAGE_READ_WRITE
259            | wgt::TextureUses::STORAGE_ATOMIC,
260    ) {
261        flags |= vk::ImageUsageFlags::STORAGE;
262    }
263    if usage.contains(wgt::TextureUses::TRANSIENT) {
264        flags |= vk::ImageUsageFlags::TRANSIENT_ATTACHMENT;
265    }
266    flags
267}
268
269pub fn map_texture_usage_to_barrier(
270    usage: wgt::TextureUses,
271) -> (vk::PipelineStageFlags, vk::AccessFlags) {
272    let mut stages = vk::PipelineStageFlags::empty();
273    let mut access = vk::AccessFlags::empty();
274    let shader_stages = vk::PipelineStageFlags::VERTEX_SHADER
275        | vk::PipelineStageFlags::FRAGMENT_SHADER
276        | vk::PipelineStageFlags::COMPUTE_SHADER;
277
278    if usage.contains(wgt::TextureUses::COPY_SRC) {
279        stages |= vk::PipelineStageFlags::TRANSFER;
280        access |= vk::AccessFlags::TRANSFER_READ;
281    }
282    if usage.contains(wgt::TextureUses::COPY_DST) {
283        stages |= vk::PipelineStageFlags::TRANSFER;
284        access |= vk::AccessFlags::TRANSFER_WRITE;
285    }
286    if usage.contains(wgt::TextureUses::RESOURCE) {
287        stages |= shader_stages;
288        access |= vk::AccessFlags::SHADER_READ;
289    }
290    if usage.contains(wgt::TextureUses::COLOR_TARGET) {
291        stages |= vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT;
292        access |= vk::AccessFlags::COLOR_ATTACHMENT_READ | vk::AccessFlags::COLOR_ATTACHMENT_WRITE;
293    }
294    if usage.intersects(wgt::TextureUses::DEPTH_STENCIL_READ) {
295        stages |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
296            | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
297        access |= vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ;
298    }
299    if usage.intersects(wgt::TextureUses::DEPTH_STENCIL_WRITE) {
300        stages |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
301            | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
302        access |= vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
303            | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE;
304    }
305    if usage.intersects(
306        wgt::TextureUses::STORAGE_READ_ONLY
307            | wgt::TextureUses::STORAGE_READ_WRITE
308            | wgt::TextureUses::STORAGE_ATOMIC,
309    ) {
310        stages |= shader_stages;
311        access |= vk::AccessFlags::SHADER_READ;
312    }
313    if usage.intersects(
314        wgt::TextureUses::STORAGE_WRITE_ONLY
315            | wgt::TextureUses::STORAGE_READ_WRITE
316            | wgt::TextureUses::STORAGE_ATOMIC,
317    ) {
318        stages |= shader_stages;
319        access |= vk::AccessFlags::SHADER_WRITE;
320    }
321
322    if usage == wgt::TextureUses::UNINITIALIZED || usage == wgt::TextureUses::PRESENT {
323        (
324            vk::PipelineStageFlags::TOP_OF_PIPE,
325            vk::AccessFlags::empty(),
326        )
327    } else {
328        (stages, access)
329    }
330}
331
332pub fn map_vk_image_usage(usage: vk::ImageUsageFlags) -> wgt::TextureUses {
333    let mut bits = wgt::TextureUses::empty();
334    if usage.contains(vk::ImageUsageFlags::TRANSFER_SRC) {
335        bits |= wgt::TextureUses::COPY_SRC;
336    }
337    if usage.contains(vk::ImageUsageFlags::TRANSFER_DST) {
338        bits |= wgt::TextureUses::COPY_DST;
339    }
340    if usage.contains(vk::ImageUsageFlags::SAMPLED) {
341        bits |= wgt::TextureUses::RESOURCE;
342    }
343    if usage.contains(vk::ImageUsageFlags::COLOR_ATTACHMENT) {
344        bits |= wgt::TextureUses::COLOR_TARGET;
345    }
346    if usage.contains(vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT) {
347        bits |= wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::DEPTH_STENCIL_WRITE;
348    }
349    if usage.contains(vk::ImageUsageFlags::STORAGE) {
350        bits |= wgt::TextureUses::STORAGE_READ_ONLY
351            | wgt::TextureUses::STORAGE_WRITE_ONLY
352            | wgt::TextureUses::STORAGE_READ_WRITE
353            | wgt::TextureUses::STORAGE_ATOMIC;
354    }
355    if usage.contains(vk::ImageUsageFlags::TRANSIENT_ATTACHMENT) {
356        bits |= wgt::TextureUses::TRANSIENT;
357    }
358    bits
359}
360
361pub fn map_texture_dimension(dim: wgt::TextureDimension) -> vk::ImageType {
362    match dim {
363        wgt::TextureDimension::D1 => vk::ImageType::TYPE_1D,
364        wgt::TextureDimension::D2 => vk::ImageType::TYPE_2D,
365        wgt::TextureDimension::D3 => vk::ImageType::TYPE_3D,
366    }
367}
368
369pub fn map_index_format(index_format: wgt::IndexFormat) -> vk::IndexType {
370    match index_format {
371        wgt::IndexFormat::Uint16 => vk::IndexType::UINT16,
372        wgt::IndexFormat::Uint32 => vk::IndexType::UINT32,
373    }
374}
375
376pub fn map_vertex_format(vertex_format: wgt::VertexFormat) -> vk::Format {
377    use wgt::VertexFormat as Vf;
378    match vertex_format {
379        Vf::Uint8 => vk::Format::R8_UINT,
380        Vf::Uint8x2 => vk::Format::R8G8_UINT,
381        Vf::Uint8x4 => vk::Format::R8G8B8A8_UINT,
382        Vf::Sint8 => vk::Format::R8_SINT,
383        Vf::Sint8x2 => vk::Format::R8G8_SINT,
384        Vf::Sint8x4 => vk::Format::R8G8B8A8_SINT,
385        Vf::Unorm8 => vk::Format::R8_UNORM,
386        Vf::Unorm8x2 => vk::Format::R8G8_UNORM,
387        Vf::Unorm8x4 => vk::Format::R8G8B8A8_UNORM,
388        Vf::Snorm8 => vk::Format::R8_SNORM,
389        Vf::Snorm8x2 => vk::Format::R8G8_SNORM,
390        Vf::Snorm8x4 => vk::Format::R8G8B8A8_SNORM,
391        Vf::Uint16 => vk::Format::R16_UINT,
392        Vf::Uint16x2 => vk::Format::R16G16_UINT,
393        Vf::Uint16x4 => vk::Format::R16G16B16A16_UINT,
394        Vf::Sint16 => vk::Format::R16_SINT,
395        Vf::Sint16x2 => vk::Format::R16G16_SINT,
396        Vf::Sint16x4 => vk::Format::R16G16B16A16_SINT,
397        Vf::Unorm16 => vk::Format::R16_UNORM,
398        Vf::Unorm16x2 => vk::Format::R16G16_UNORM,
399        Vf::Unorm16x4 => vk::Format::R16G16B16A16_UNORM,
400        Vf::Snorm16 => vk::Format::R16_SNORM,
401        Vf::Snorm16x2 => vk::Format::R16G16_SNORM,
402        Vf::Snorm16x4 => vk::Format::R16G16B16A16_SNORM,
403        Vf::Float16 => vk::Format::R16_SFLOAT,
404        Vf::Float16x2 => vk::Format::R16G16_SFLOAT,
405        Vf::Float16x4 => vk::Format::R16G16B16A16_SFLOAT,
406        Vf::Float32 => vk::Format::R32_SFLOAT,
407        Vf::Float32x2 => vk::Format::R32G32_SFLOAT,
408        Vf::Float32x3 => vk::Format::R32G32B32_SFLOAT,
409        Vf::Float32x4 => vk::Format::R32G32B32A32_SFLOAT,
410        Vf::Uint32 => vk::Format::R32_UINT,
411        Vf::Uint32x2 => vk::Format::R32G32_UINT,
412        Vf::Uint32x3 => vk::Format::R32G32B32_UINT,
413        Vf::Uint32x4 => vk::Format::R32G32B32A32_UINT,
414        Vf::Sint32 => vk::Format::R32_SINT,
415        Vf::Sint32x2 => vk::Format::R32G32_SINT,
416        Vf::Sint32x3 => vk::Format::R32G32B32_SINT,
417        Vf::Sint32x4 => vk::Format::R32G32B32A32_SINT,
418        Vf::Float64 => vk::Format::R64_SFLOAT,
419        Vf::Float64x2 => vk::Format::R64G64_SFLOAT,
420        Vf::Float64x3 => vk::Format::R64G64B64_SFLOAT,
421        Vf::Float64x4 => vk::Format::R64G64B64A64_SFLOAT,
422        Vf::Unorm10_10_10_2 => vk::Format::A2B10G10R10_UNORM_PACK32,
423        Vf::Unorm8x4Bgra => vk::Format::B8G8R8A8_UNORM,
424    }
425}
426
427pub fn map_aspects(aspects: crate::FormatAspects) -> vk::ImageAspectFlags {
428    let mut flags = vk::ImageAspectFlags::empty();
429    if aspects.contains(crate::FormatAspects::COLOR) {
430        flags |= vk::ImageAspectFlags::COLOR;
431    }
432    if aspects.contains(crate::FormatAspects::DEPTH) {
433        flags |= vk::ImageAspectFlags::DEPTH;
434    }
435    if aspects.contains(crate::FormatAspects::STENCIL) {
436        flags |= vk::ImageAspectFlags::STENCIL;
437    }
438    if aspects.contains(crate::FormatAspects::PLANE_0) {
439        flags |= vk::ImageAspectFlags::PLANE_0;
440    }
441    if aspects.contains(crate::FormatAspects::PLANE_1) {
442        flags |= vk::ImageAspectFlags::PLANE_1;
443    }
444    if aspects.contains(crate::FormatAspects::PLANE_2) {
445        flags |= vk::ImageAspectFlags::PLANE_2;
446    }
447    flags
448}
449
450pub fn map_attachment_ops(
451    op: crate::AttachmentOps,
452) -> (vk::AttachmentLoadOp, vk::AttachmentStoreOp) {
453    let load_op = if op.contains(crate::AttachmentOps::LOAD) {
454        vk::AttachmentLoadOp::LOAD
455    } else if op.contains(crate::AttachmentOps::LOAD_DONT_CARE) {
456        vk::AttachmentLoadOp::DONT_CARE
457    } else if op.contains(crate::AttachmentOps::LOAD_CLEAR) {
458        vk::AttachmentLoadOp::CLEAR
459    } else {
460        unreachable!()
461    };
462    let store_op = if op.contains(crate::AttachmentOps::STORE) {
463        vk::AttachmentStoreOp::STORE
464    } else if op.contains(crate::AttachmentOps::STORE_DISCARD) {
465        vk::AttachmentStoreOp::DONT_CARE
466    } else {
467        unreachable!()
468    };
469    (load_op, store_op)
470}
471
472pub fn map_present_mode(mode: wgt::PresentMode) -> vk::PresentModeKHR {
473    match mode {
474        wgt::PresentMode::Immediate => vk::PresentModeKHR::IMMEDIATE,
475        wgt::PresentMode::Mailbox => vk::PresentModeKHR::MAILBOX,
476        wgt::PresentMode::Fifo => vk::PresentModeKHR::FIFO,
477        wgt::PresentMode::FifoRelaxed => vk::PresentModeKHR::FIFO_RELAXED,
478        wgt::PresentMode::AutoNoVsync | wgt::PresentMode::AutoVsync => {
479            unreachable!("Cannot create swapchain with Auto PresentationMode")
480        }
481    }
482}
483
484pub fn map_vk_present_mode(mode: vk::PresentModeKHR) -> Option<wgt::PresentMode> {
485    // Not exposed in Ash yet.
486    const FIFO_LATEST_READY: vk::PresentModeKHR = vk::PresentModeKHR::from_raw(1_000_361_000);
487
488    // See https://registry.khronos.org/vulkan/specs/latest/man/html/VkPresentModeKHR.html
489    match mode {
490        vk::PresentModeKHR::IMMEDIATE => Some(wgt::PresentMode::Immediate),
491        vk::PresentModeKHR::MAILBOX => Some(wgt::PresentMode::Mailbox),
492        vk::PresentModeKHR::FIFO => Some(wgt::PresentMode::Fifo),
493        vk::PresentModeKHR::FIFO_RELAXED => Some(wgt::PresentMode::FifoRelaxed),
494
495        // Modes that aren't exposed yet.
496        vk::PresentModeKHR::SHARED_DEMAND_REFRESH => None,
497        vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH => None,
498        FIFO_LATEST_READY => None,
499
500        _ => {
501            log::debug!("Unrecognized present mode {mode:?}");
502            None
503        }
504    }
505}
506
507pub fn map_composite_alpha_mode(mode: wgt::CompositeAlphaMode) -> vk::CompositeAlphaFlagsKHR {
508    match mode {
509        wgt::CompositeAlphaMode::Opaque => vk::CompositeAlphaFlagsKHR::OPAQUE,
510        wgt::CompositeAlphaMode::PreMultiplied => vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED,
511        wgt::CompositeAlphaMode::PostMultiplied => vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED,
512        wgt::CompositeAlphaMode::Inherit => vk::CompositeAlphaFlagsKHR::INHERIT,
513        wgt::CompositeAlphaMode::Auto => unreachable!(),
514    }
515}
516
517pub fn map_vk_composite_alpha(flags: vk::CompositeAlphaFlagsKHR) -> Vec<wgt::CompositeAlphaMode> {
518    let mut modes = Vec::new();
519    if flags.contains(vk::CompositeAlphaFlagsKHR::OPAQUE) {
520        modes.push(wgt::CompositeAlphaMode::Opaque);
521    }
522    if flags.contains(vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED) {
523        modes.push(wgt::CompositeAlphaMode::PreMultiplied);
524    }
525    if flags.contains(vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED) {
526        modes.push(wgt::CompositeAlphaMode::PostMultiplied);
527    }
528    if flags.contains(vk::CompositeAlphaFlagsKHR::INHERIT) {
529        modes.push(wgt::CompositeAlphaMode::Inherit);
530    }
531    modes
532}
533
534pub fn map_buffer_usage(usage: wgt::BufferUses) -> vk::BufferUsageFlags {
535    let mut flags = vk::BufferUsageFlags::empty();
536    if usage.contains(wgt::BufferUses::COPY_SRC) {
537        flags |= vk::BufferUsageFlags::TRANSFER_SRC;
538    }
539    if usage.contains(wgt::BufferUses::COPY_DST) {
540        flags |= vk::BufferUsageFlags::TRANSFER_DST;
541    }
542    if usage.contains(wgt::BufferUses::UNIFORM) {
543        flags |= vk::BufferUsageFlags::UNIFORM_BUFFER;
544    }
545    if usage.intersects(wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE) {
546        flags |= vk::BufferUsageFlags::STORAGE_BUFFER;
547    }
548    if usage.contains(wgt::BufferUses::INDEX) {
549        flags |= vk::BufferUsageFlags::INDEX_BUFFER;
550    }
551    if usage.contains(wgt::BufferUses::VERTEX) {
552        flags |= vk::BufferUsageFlags::VERTEX_BUFFER;
553    }
554    if usage.contains(wgt::BufferUses::INDIRECT) {
555        flags |= vk::BufferUsageFlags::INDIRECT_BUFFER;
556    }
557    if usage.contains(wgt::BufferUses::ACCELERATION_STRUCTURE_SCRATCH) {
558        flags |= vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
559    }
560    if usage.intersects(
561        wgt::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT
562            | wgt::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT,
563    ) {
564        flags |= vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR
565            | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
566    }
567    if usage.intersects(wgt::BufferUses::ACCELERATION_STRUCTURE_QUERY) {
568        flags |= vk::BufferUsageFlags::TRANSFER_DST;
569    }
570    flags
571}
572
573pub fn map_buffer_usage_to_barrier(
574    usage: wgt::BufferUses,
575) -> (vk::PipelineStageFlags, vk::AccessFlags) {
576    let mut stages = vk::PipelineStageFlags::empty();
577    let mut access = vk::AccessFlags::empty();
578    let shader_stages = vk::PipelineStageFlags::VERTEX_SHADER
579        | vk::PipelineStageFlags::FRAGMENT_SHADER
580        | vk::PipelineStageFlags::COMPUTE_SHADER;
581
582    if usage.contains(wgt::BufferUses::MAP_READ) {
583        stages |= vk::PipelineStageFlags::HOST;
584        access |= vk::AccessFlags::HOST_READ;
585    }
586    if usage.contains(wgt::BufferUses::MAP_WRITE) {
587        stages |= vk::PipelineStageFlags::HOST;
588        access |= vk::AccessFlags::HOST_WRITE;
589    }
590    if usage.contains(wgt::BufferUses::COPY_SRC) {
591        stages |= vk::PipelineStageFlags::TRANSFER;
592        access |= vk::AccessFlags::TRANSFER_READ;
593    }
594    if usage.contains(wgt::BufferUses::COPY_DST) {
595        stages |= vk::PipelineStageFlags::TRANSFER;
596        access |= vk::AccessFlags::TRANSFER_WRITE;
597    }
598    if usage.contains(wgt::BufferUses::UNIFORM) {
599        stages |= shader_stages;
600        access |= vk::AccessFlags::UNIFORM_READ;
601    }
602    if usage.intersects(wgt::BufferUses::STORAGE_READ_ONLY) {
603        stages |= shader_stages;
604        access |= vk::AccessFlags::SHADER_READ;
605    }
606    if usage.intersects(wgt::BufferUses::STORAGE_READ_WRITE) {
607        stages |= shader_stages;
608        access |= vk::AccessFlags::SHADER_READ | vk::AccessFlags::SHADER_WRITE;
609    }
610    if usage.contains(wgt::BufferUses::INDEX) {
611        stages |= vk::PipelineStageFlags::VERTEX_INPUT;
612        access |= vk::AccessFlags::INDEX_READ;
613    }
614    if usage.contains(wgt::BufferUses::VERTEX) {
615        stages |= vk::PipelineStageFlags::VERTEX_INPUT;
616        access |= vk::AccessFlags::VERTEX_ATTRIBUTE_READ;
617    }
618    if usage.contains(wgt::BufferUses::INDIRECT) {
619        stages |= vk::PipelineStageFlags::DRAW_INDIRECT;
620        access |= vk::AccessFlags::INDIRECT_COMMAND_READ;
621    }
622    if usage.intersects(
623        wgt::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT
624            | wgt::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT
625            | wgt::BufferUses::ACCELERATION_STRUCTURE_SCRATCH,
626    ) {
627        stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
628        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR
629            | vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR
630            | vk::AccessFlags::SHADER_READ;
631    }
632    if usage.contains(wgt::BufferUses::ACCELERATION_STRUCTURE_QUERY) {
633        stages |= vk::PipelineStageFlags::TRANSFER;
634        access |= vk::AccessFlags::TRANSFER_WRITE;
635    }
636
637    (stages, access)
638}
639
640pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> vk::ImageViewType {
641    match dim {
642        wgt::TextureViewDimension::D1 => vk::ImageViewType::TYPE_1D,
643        wgt::TextureViewDimension::D2 => vk::ImageViewType::TYPE_2D,
644        wgt::TextureViewDimension::D2Array => vk::ImageViewType::TYPE_2D_ARRAY,
645        wgt::TextureViewDimension::Cube => vk::ImageViewType::CUBE,
646        wgt::TextureViewDimension::CubeArray => vk::ImageViewType::CUBE_ARRAY,
647        wgt::TextureViewDimension::D3 => vk::ImageViewType::TYPE_3D,
648    }
649}
650
651pub fn map_copy_extent(extent: &crate::CopyExtent) -> vk::Extent3D {
652    vk::Extent3D {
653        width: extent.width,
654        height: extent.height,
655        depth: extent.depth,
656    }
657}
658
659pub fn map_subresource_range(
660    range: &wgt::ImageSubresourceRange,
661    format: wgt::TextureFormat,
662) -> vk::ImageSubresourceRange {
663    vk::ImageSubresourceRange {
664        aspect_mask: map_aspects(crate::FormatAspects::new(format, range.aspect)),
665        base_mip_level: range.base_mip_level,
666        level_count: range.mip_level_count.unwrap_or(vk::REMAINING_MIP_LEVELS),
667        base_array_layer: range.base_array_layer,
668        layer_count: range
669            .array_layer_count
670            .unwrap_or(vk::REMAINING_ARRAY_LAYERS),
671    }
672}
673
674// Special subresource range mapping for dealing with barriers
675// so that we account for the "hidden" depth aspect in emulated Stencil8.
676pub(super) fn map_subresource_range_combined_aspect(
677    range: &wgt::ImageSubresourceRange,
678    format: wgt::TextureFormat,
679    private_caps: &super::PrivateCapabilities,
680) -> vk::ImageSubresourceRange {
681    let mut range = map_subresource_range(range, format);
682    if !private_caps.texture_s8 && format == wgt::TextureFormat::Stencil8 {
683        range.aspect_mask |= vk::ImageAspectFlags::DEPTH;
684    }
685    range
686}
687
688pub fn map_subresource_layers(
689    base: &crate::TextureCopyBase,
690) -> (vk::ImageSubresourceLayers, vk::Offset3D) {
691    let offset = vk::Offset3D {
692        x: base.origin.x as i32,
693        y: base.origin.y as i32,
694        z: base.origin.z as i32,
695    };
696    let subresource = vk::ImageSubresourceLayers {
697        aspect_mask: map_aspects(base.aspect),
698        mip_level: base.mip_level,
699        base_array_layer: base.array_layer,
700        layer_count: 1,
701    };
702    (subresource, offset)
703}
704
705pub fn map_filter_mode(mode: wgt::FilterMode) -> vk::Filter {
706    match mode {
707        wgt::FilterMode::Nearest => vk::Filter::NEAREST,
708        wgt::FilterMode::Linear => vk::Filter::LINEAR,
709    }
710}
711
712pub fn map_mip_filter_mode(mode: wgt::MipmapFilterMode) -> vk::SamplerMipmapMode {
713    match mode {
714        wgt::MipmapFilterMode::Nearest => vk::SamplerMipmapMode::NEAREST,
715        wgt::MipmapFilterMode::Linear => vk::SamplerMipmapMode::LINEAR,
716    }
717}
718
719pub fn map_address_mode(mode: wgt::AddressMode) -> vk::SamplerAddressMode {
720    match mode {
721        wgt::AddressMode::ClampToEdge => vk::SamplerAddressMode::CLAMP_TO_EDGE,
722        wgt::AddressMode::Repeat => vk::SamplerAddressMode::REPEAT,
723        wgt::AddressMode::MirrorRepeat => vk::SamplerAddressMode::MIRRORED_REPEAT,
724        wgt::AddressMode::ClampToBorder => vk::SamplerAddressMode::CLAMP_TO_BORDER,
725        // wgt::AddressMode::MirrorClamp => vk::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE,
726    }
727}
728
729pub fn map_border_color(border_color: wgt::SamplerBorderColor) -> vk::BorderColor {
730    match border_color {
731        wgt::SamplerBorderColor::TransparentBlack | wgt::SamplerBorderColor::Zero => {
732            vk::BorderColor::FLOAT_TRANSPARENT_BLACK
733        }
734        wgt::SamplerBorderColor::OpaqueBlack => vk::BorderColor::FLOAT_OPAQUE_BLACK,
735        wgt::SamplerBorderColor::OpaqueWhite => vk::BorderColor::FLOAT_OPAQUE_WHITE,
736    }
737}
738
739pub fn map_comparison(fun: wgt::CompareFunction) -> vk::CompareOp {
740    use wgt::CompareFunction as Cf;
741    match fun {
742        Cf::Never => vk::CompareOp::NEVER,
743        Cf::Less => vk::CompareOp::LESS,
744        Cf::LessEqual => vk::CompareOp::LESS_OR_EQUAL,
745        Cf::Equal => vk::CompareOp::EQUAL,
746        Cf::GreaterEqual => vk::CompareOp::GREATER_OR_EQUAL,
747        Cf::Greater => vk::CompareOp::GREATER,
748        Cf::NotEqual => vk::CompareOp::NOT_EQUAL,
749        Cf::Always => vk::CompareOp::ALWAYS,
750    }
751}
752
753pub fn map_shader_stage(stage: wgt::ShaderStages) -> vk::ShaderStageFlags {
754    let mut flags = vk::ShaderStageFlags::empty();
755    if stage.contains(wgt::ShaderStages::VERTEX) {
756        flags |= vk::ShaderStageFlags::VERTEX;
757    }
758    if stage.contains(wgt::ShaderStages::FRAGMENT) {
759        flags |= vk::ShaderStageFlags::FRAGMENT;
760    }
761    if stage.contains(wgt::ShaderStages::COMPUTE) {
762        flags |= vk::ShaderStageFlags::COMPUTE;
763    }
764    if stage.contains(wgt::ShaderStages::TASK) {
765        flags |= vk::ShaderStageFlags::TASK_EXT;
766    }
767    if stage.contains(wgt::ShaderStages::MESH) {
768        flags |= vk::ShaderStageFlags::MESH_EXT;
769    }
770    flags
771}
772
773pub fn map_binding_type(ty: wgt::BindingType) -> vk::DescriptorType {
774    match ty {
775        wgt::BindingType::Buffer {
776            ty,
777            has_dynamic_offset,
778            ..
779        } => match ty {
780            wgt::BufferBindingType::Storage { .. } => match has_dynamic_offset {
781                true => vk::DescriptorType::STORAGE_BUFFER_DYNAMIC,
782                false => vk::DescriptorType::STORAGE_BUFFER,
783            },
784            wgt::BufferBindingType::Uniform => match has_dynamic_offset {
785                true => vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC,
786                false => vk::DescriptorType::UNIFORM_BUFFER,
787            },
788        },
789        wgt::BindingType::Sampler { .. } => vk::DescriptorType::SAMPLER,
790        wgt::BindingType::Texture { .. } => vk::DescriptorType::SAMPLED_IMAGE,
791        wgt::BindingType::StorageTexture { .. } => vk::DescriptorType::STORAGE_IMAGE,
792        wgt::BindingType::AccelerationStructure { .. } => {
793            vk::DescriptorType::ACCELERATION_STRUCTURE_KHR
794        }
795        wgt::BindingType::ExternalTexture => unimplemented!(),
796    }
797}
798
799pub fn map_topology(topology: wgt::PrimitiveTopology) -> vk::PrimitiveTopology {
800    use wgt::PrimitiveTopology as Pt;
801    match topology {
802        Pt::PointList => vk::PrimitiveTopology::POINT_LIST,
803        Pt::LineList => vk::PrimitiveTopology::LINE_LIST,
804        Pt::LineStrip => vk::PrimitiveTopology::LINE_STRIP,
805        Pt::TriangleList => vk::PrimitiveTopology::TRIANGLE_LIST,
806        Pt::TriangleStrip => vk::PrimitiveTopology::TRIANGLE_STRIP,
807    }
808}
809
810pub fn map_polygon_mode(mode: wgt::PolygonMode) -> vk::PolygonMode {
811    match mode {
812        wgt::PolygonMode::Fill => vk::PolygonMode::FILL,
813        wgt::PolygonMode::Line => vk::PolygonMode::LINE,
814        wgt::PolygonMode::Point => vk::PolygonMode::POINT,
815    }
816}
817
818pub fn map_front_face(front_face: wgt::FrontFace) -> vk::FrontFace {
819    match front_face {
820        wgt::FrontFace::Cw => vk::FrontFace::CLOCKWISE,
821        wgt::FrontFace::Ccw => vk::FrontFace::COUNTER_CLOCKWISE,
822    }
823}
824
825pub fn map_cull_face(face: wgt::Face) -> vk::CullModeFlags {
826    match face {
827        wgt::Face::Front => vk::CullModeFlags::FRONT,
828        wgt::Face::Back => vk::CullModeFlags::BACK,
829    }
830}
831
832pub fn map_stencil_op(op: wgt::StencilOperation) -> vk::StencilOp {
833    use wgt::StencilOperation as So;
834    match op {
835        So::Keep => vk::StencilOp::KEEP,
836        So::Zero => vk::StencilOp::ZERO,
837        So::Replace => vk::StencilOp::REPLACE,
838        So::Invert => vk::StencilOp::INVERT,
839        So::IncrementClamp => vk::StencilOp::INCREMENT_AND_CLAMP,
840        So::IncrementWrap => vk::StencilOp::INCREMENT_AND_WRAP,
841        So::DecrementClamp => vk::StencilOp::DECREMENT_AND_CLAMP,
842        So::DecrementWrap => vk::StencilOp::DECREMENT_AND_WRAP,
843    }
844}
845
846pub fn map_stencil_face(
847    face: &wgt::StencilFaceState,
848    compare_mask: u32,
849    write_mask: u32,
850) -> vk::StencilOpState {
851    vk::StencilOpState {
852        fail_op: map_stencil_op(face.fail_op),
853        pass_op: map_stencil_op(face.pass_op),
854        depth_fail_op: map_stencil_op(face.depth_fail_op),
855        compare_op: map_comparison(face.compare),
856        compare_mask,
857        write_mask,
858        reference: 0,
859    }
860}
861
862fn map_blend_factor(factor: wgt::BlendFactor) -> vk::BlendFactor {
863    use wgt::BlendFactor as Bf;
864    match factor {
865        Bf::Zero => vk::BlendFactor::ZERO,
866        Bf::One => vk::BlendFactor::ONE,
867        Bf::Src => vk::BlendFactor::SRC_COLOR,
868        Bf::OneMinusSrc => vk::BlendFactor::ONE_MINUS_SRC_COLOR,
869        Bf::SrcAlpha => vk::BlendFactor::SRC_ALPHA,
870        Bf::OneMinusSrcAlpha => vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
871        Bf::Dst => vk::BlendFactor::DST_COLOR,
872        Bf::OneMinusDst => vk::BlendFactor::ONE_MINUS_DST_COLOR,
873        Bf::DstAlpha => vk::BlendFactor::DST_ALPHA,
874        Bf::OneMinusDstAlpha => vk::BlendFactor::ONE_MINUS_DST_ALPHA,
875        Bf::SrcAlphaSaturated => vk::BlendFactor::SRC_ALPHA_SATURATE,
876        Bf::Constant => vk::BlendFactor::CONSTANT_COLOR,
877        Bf::OneMinusConstant => vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR,
878        Bf::Src1 => vk::BlendFactor::SRC1_COLOR,
879        Bf::OneMinusSrc1 => vk::BlendFactor::ONE_MINUS_SRC1_COLOR,
880        Bf::Src1Alpha => vk::BlendFactor::SRC1_ALPHA,
881        Bf::OneMinusSrc1Alpha => vk::BlendFactor::ONE_MINUS_SRC1_ALPHA,
882    }
883}
884
885fn map_blend_op(operation: wgt::BlendOperation) -> vk::BlendOp {
886    use wgt::BlendOperation as Bo;
887    match operation {
888        Bo::Add => vk::BlendOp::ADD,
889        Bo::Subtract => vk::BlendOp::SUBTRACT,
890        Bo::ReverseSubtract => vk::BlendOp::REVERSE_SUBTRACT,
891        Bo::Min => vk::BlendOp::MIN,
892        Bo::Max => vk::BlendOp::MAX,
893    }
894}
895
896pub fn map_blend_component(
897    component: &wgt::BlendComponent,
898) -> (vk::BlendOp, vk::BlendFactor, vk::BlendFactor) {
899    let op = map_blend_op(component.operation);
900    let src = map_blend_factor(component.src_factor);
901    let dst = map_blend_factor(component.dst_factor);
902    (op, src, dst)
903}
904
905pub fn map_pipeline_statistics(
906    types: wgt::PipelineStatisticsTypes,
907) -> vk::QueryPipelineStatisticFlags {
908    use wgt::PipelineStatisticsTypes as Pst;
909    let mut flags = vk::QueryPipelineStatisticFlags::empty();
910    if types.contains(Pst::VERTEX_SHADER_INVOCATIONS) {
911        flags |= vk::QueryPipelineStatisticFlags::VERTEX_SHADER_INVOCATIONS;
912    }
913    if types.contains(Pst::CLIPPER_INVOCATIONS) {
914        flags |= vk::QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS;
915    }
916    if types.contains(Pst::CLIPPER_PRIMITIVES_OUT) {
917        flags |= vk::QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES;
918    }
919    if types.contains(Pst::FRAGMENT_SHADER_INVOCATIONS) {
920        flags |= vk::QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS;
921    }
922    if types.contains(Pst::COMPUTE_SHADER_INVOCATIONS) {
923        flags |= vk::QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS;
924    }
925    flags
926}
927
928pub fn map_acceleration_structure_format(
929    format: crate::AccelerationStructureFormat,
930) -> vk::AccelerationStructureTypeKHR {
931    match format {
932        crate::AccelerationStructureFormat::TopLevel => vk::AccelerationStructureTypeKHR::TOP_LEVEL,
933        crate::AccelerationStructureFormat::BottomLevel => {
934            vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL
935        }
936    }
937}
938
939pub fn map_acceleration_structure_build_mode(
940    format: crate::AccelerationStructureBuildMode,
941) -> vk::BuildAccelerationStructureModeKHR {
942    match format {
943        crate::AccelerationStructureBuildMode::Build => {
944            vk::BuildAccelerationStructureModeKHR::BUILD
945        }
946        crate::AccelerationStructureBuildMode::Update => {
947            vk::BuildAccelerationStructureModeKHR::UPDATE
948        }
949    }
950}
951
952pub fn map_acceleration_structure_flags(
953    flags: crate::AccelerationStructureBuildFlags,
954) -> vk::BuildAccelerationStructureFlagsKHR {
955    let mut vk_flags = vk::BuildAccelerationStructureFlagsKHR::empty();
956
957    if flags.contains(crate::AccelerationStructureBuildFlags::PREFER_FAST_TRACE) {
958        vk_flags |= vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE;
959    }
960
961    if flags.contains(crate::AccelerationStructureBuildFlags::PREFER_FAST_BUILD) {
962        vk_flags |= vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_BUILD;
963    }
964
965    if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_UPDATE) {
966        vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_UPDATE;
967    }
968
969    if flags.contains(crate::AccelerationStructureBuildFlags::LOW_MEMORY) {
970        vk_flags |= vk::BuildAccelerationStructureFlagsKHR::LOW_MEMORY;
971    }
972
973    if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_COMPACTION) {
974        vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_COMPACTION
975    }
976
977    if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_RAY_HIT_VERTEX_RETURN) {
978        vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_DATA_ACCESS
979    }
980
981    vk_flags
982}
983
984pub fn map_acceleration_structure_geometry_flags(
985    flags: crate::AccelerationStructureGeometryFlags,
986) -> vk::GeometryFlagsKHR {
987    let mut vk_flags = vk::GeometryFlagsKHR::empty();
988
989    if flags.contains(crate::AccelerationStructureGeometryFlags::OPAQUE) {
990        vk_flags |= vk::GeometryFlagsKHR::OPAQUE;
991    }
992
993    if flags.contains(crate::AccelerationStructureGeometryFlags::NO_DUPLICATE_ANY_HIT_INVOCATION) {
994        vk_flags |= vk::GeometryFlagsKHR::NO_DUPLICATE_ANY_HIT_INVOCATION;
995    }
996
997    vk_flags
998}
999
1000pub fn map_acceleration_structure_usage_to_barrier(
1001    usage: crate::AccelerationStructureUses,
1002    features: wgt::Features,
1003) -> (vk::PipelineStageFlags, vk::AccessFlags) {
1004    let mut stages = vk::PipelineStageFlags::empty();
1005    let mut access = vk::AccessFlags::empty();
1006
1007    if usage.contains(crate::AccelerationStructureUses::BUILD_INPUT) {
1008        stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1009        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1010    }
1011    if usage.contains(crate::AccelerationStructureUses::QUERY_INPUT) {
1012        stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1013        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1014    }
1015    if usage.contains(crate::AccelerationStructureUses::BUILD_OUTPUT) {
1016        stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1017        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR;
1018    }
1019    if usage.contains(crate::AccelerationStructureUses::SHADER_INPUT)
1020        && features.contains(wgt::Features::EXPERIMENTAL_RAY_QUERY)
1021    {
1022        stages |= vk::PipelineStageFlags::VERTEX_SHADER
1023            | vk::PipelineStageFlags::FRAGMENT_SHADER
1024            | vk::PipelineStageFlags::COMPUTE_SHADER;
1025        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1026    }
1027    if usage.contains(crate::AccelerationStructureUses::COPY_SRC) {
1028        stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1029        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1030    }
1031    if usage.contains(crate::AccelerationStructureUses::COPY_DST) {
1032        stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1033        access |= vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR;
1034    }
1035
1036    (stages, access)
1037}