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(
162 sf: vk::SurfaceFormatKHR,
163) -> Option<(wgt::TextureFormat, wgt::SurfaceColorSpace)> {
164 use ash::vk::Format as F;
165 use wgt::TextureFormat as Tf;
166 let format = 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::R16G16B16A16_SFLOAT => Tf::Rgba16Float,
176 F::A2B10G10R10_UNORM_PACK32 => Tf::Rgb10a2Unorm,
177 _ => return None,
178 };
179 let color_space = map_vk_color_space(sf.color_space)?;
180 Some((format, color_space))
181}
182
183pub fn map_vk_color_space(color_space: vk::ColorSpaceKHR) -> Option<wgt::SurfaceColorSpace> {
184 use wgt::SurfaceColorSpace as Scs;
185 Some(match color_space {
186 vk::ColorSpaceKHR::SRGB_NONLINEAR => Scs::Srgb,
187 vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT => Scs::ExtendedSrgbLinear,
188 vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT => Scs::ExtendedSrgb,
189 vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT => Scs::DisplayP3,
190 vk::ColorSpaceKHR::HDR10_ST2084_EXT => Scs::Bt2100Pq,
191 vk::ColorSpaceKHR::HDR10_HLG_EXT => Scs::Bt2100Hlg,
192 _ => return None,
193 })
194}
195
196pub fn map_surface_color_space(color_space: wgt::SurfaceColorSpace) -> vk::ColorSpaceKHR {
197 use wgt::SurfaceColorSpace as Scs;
198 match color_space {
199 Scs::Auto => unreachable!("wgpu-core resolves `Auto` before configuring the surface"),
200 Scs::Srgb => vk::ColorSpaceKHR::SRGB_NONLINEAR,
201 Scs::ExtendedSrgbLinear => vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT,
202 Scs::ExtendedSrgb => vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT,
203 Scs::DisplayP3 => vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT,
204 Scs::Bt2100Pq => vk::ColorSpaceKHR::HDR10_ST2084_EXT,
205 Scs::Bt2100Hlg => vk::ColorSpaceKHR::HDR10_HLG_EXT,
206 Scs::ExtendedDisplayP3 => {
207 unreachable!("`ExtendedDisplayP3` is never reported in the Vulkan surface capabilities")
208 }
209 }
210}
211
212impl crate::Attachment<'_, super::TextureView> {
213 pub(super) fn make_attachment_key(&self, ops: crate::AttachmentOps) -> super::AttachmentKey {
214 super::AttachmentKey {
215 format: self.view.raw_format,
216 layout: derive_image_layout(self.usage, self.view.format),
217 ops,
218 }
219 }
220}
221
222impl crate::ColorAttachment<'_, super::TextureView> {
223 pub(super) unsafe fn make_vk_clear_color(&self) -> vk::ClearColorValue {
224 let cv = &self.clear_value;
225 match self.target.view.format.sample_type(None, None).unwrap() {
226 wgt::TextureSampleType::Float { .. } => vk::ClearColorValue {
227 float32: [cv.r as f32, cv.g as f32, cv.b as f32, cv.a as f32],
228 },
229 wgt::TextureSampleType::Sint => vk::ClearColorValue {
230 int32: [cv.r as i32, cv.g as i32, cv.b as i32, cv.a as i32],
231 },
232 wgt::TextureSampleType::Uint => vk::ClearColorValue {
233 uint32: [cv.r as u32, cv.g as u32, cv.b as u32, cv.a as u32],
234 },
235 wgt::TextureSampleType::Depth => unreachable!(),
236 }
237 }
238}
239
240pub fn derive_image_layout(usage: wgt::TextureUses, format: wgt::TextureFormat) -> vk::ImageLayout {
241 let is_color = !format.is_depth_stencil_format();
242 match usage {
243 wgt::TextureUses::UNINITIALIZED => vk::ImageLayout::UNDEFINED,
244 wgt::TextureUses::COPY_SRC => vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
245 wgt::TextureUses::COPY_DST => vk::ImageLayout::TRANSFER_DST_OPTIMAL,
246 wgt::TextureUses::RESOURCE if is_color => vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
247 wgt::TextureUses::COLOR_TARGET => vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
248 _ => {
249 if usage == wgt::TextureUses::PRESENT {
250 vk::ImageLayout::PRESENT_SRC_KHR
251 } else if is_color {
252 vk::ImageLayout::GENERAL
253 } else {
254 match (
255 usage.contains(wgt::TextureUses::DEPTH_WRITE),
256 usage.contains(wgt::TextureUses::STENCIL_WRITE),
257 ) {
258 (true, true) => vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
259 (false, true) => vk::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
260 (true, false) => vk::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
261 (false, false) => vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL,
262 }
263 }
264 }
265 }
266}
267
268pub fn map_queue_family(family: crate::QueueFamily) -> u32 {
269 match family {
270 crate::QueueFamily::Explicit(index) => index,
271 crate::QueueFamily::External => vk::QUEUE_FAMILY_EXTERNAL,
272 crate::QueueFamily::Foreign => vk::QUEUE_FAMILY_FOREIGN_EXT,
273 }
274}
275
276pub const VIEWABLE_IMAGE_USAGES: vk::ImageUsageFlags = vk::ImageUsageFlags::from_raw(
279 vk::ImageUsageFlags::SAMPLED.as_raw()
280 | vk::ImageUsageFlags::STORAGE.as_raw()
281 | vk::ImageUsageFlags::COLOR_ATTACHMENT.as_raw()
282 | vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT.as_raw()
283 | vk::ImageUsageFlags::INPUT_ATTACHMENT.as_raw()
284 | vk::ImageUsageFlags::TRANSIENT_ATTACHMENT.as_raw(),
285);
286
287pub fn map_texture_usage(usage: wgt::TextureUses) -> vk::ImageUsageFlags {
288 let mut flags = vk::ImageUsageFlags::empty();
289 if usage.contains(wgt::TextureUses::COPY_SRC) {
290 flags |= vk::ImageUsageFlags::TRANSFER_SRC;
291 }
292 if usage.contains(wgt::TextureUses::COPY_DST) {
293 flags |= vk::ImageUsageFlags::TRANSFER_DST;
294 }
295 if usage.contains(wgt::TextureUses::RESOURCE) {
296 flags |= vk::ImageUsageFlags::SAMPLED;
297 }
298 if usage.contains(wgt::TextureUses::COLOR_TARGET) {
299 flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT;
300 }
301 if usage.intersects(
302 wgt::TextureUses::DEPTH_READ
303 | wgt::TextureUses::DEPTH_WRITE
304 | wgt::TextureUses::STENCIL_READ
305 | wgt::TextureUses::STENCIL_WRITE,
306 ) {
307 flags |= vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT;
308 }
309 if usage.intersects(
310 wgt::TextureUses::STORAGE_READ_ONLY
311 | wgt::TextureUses::STORAGE_WRITE_ONLY
312 | wgt::TextureUses::STORAGE_READ_WRITE
313 | wgt::TextureUses::STORAGE_ATOMIC,
314 ) {
315 flags |= vk::ImageUsageFlags::STORAGE;
316 }
317 if usage.contains(wgt::TextureUses::TRANSIENT) {
318 flags |= vk::ImageUsageFlags::TRANSIENT_ATTACHMENT;
319 }
320 flags
321}
322
323pub fn map_texture_usage_to_barrier(
324 usage: wgt::TextureUses,
325 queue_flags: vk::QueueFlags,
326 support_store_op_none: bool,
327 features: wgt::Features,
328) -> (vk::PipelineStageFlags, vk::AccessFlags) {
329 let mut stages = vk::PipelineStageFlags::empty();
330 let mut access = vk::AccessFlags::empty();
331 let shader_stages = shader_stages(queue_flags, features);
332
333 if usage.contains(wgt::TextureUses::COPY_SRC) {
334 stages |= vk::PipelineStageFlags::TRANSFER;
335 access |= vk::AccessFlags::TRANSFER_READ;
336 }
337 if usage.contains(wgt::TextureUses::COPY_DST) {
338 stages |= vk::PipelineStageFlags::TRANSFER;
339 access |= vk::AccessFlags::TRANSFER_WRITE;
340 }
341 if usage.contains(wgt::TextureUses::RESOURCE) {
342 stages |= shader_stages;
343 access |= vk::AccessFlags::SHADER_READ;
344 }
345 if usage.contains(wgt::TextureUses::COLOR_TARGET) {
346 stages |= vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT;
347 access |= vk::AccessFlags::COLOR_ATTACHMENT_READ | vk::AccessFlags::COLOR_ATTACHMENT_WRITE;
348 }
349 if usage.intersects(wgt::TextureUses::DEPTH_READ | wgt::TextureUses::STENCIL_READ) {
350 stages |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
351 | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
352 access |= if !support_store_op_none {
353 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
356 | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE
357 } else {
358 vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
359 }
360 }
361 if usage.intersects(wgt::TextureUses::DEPTH_WRITE | wgt::TextureUses::STENCIL_WRITE) {
362 stages |= vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS
363 | vk::PipelineStageFlags::LATE_FRAGMENT_TESTS;
364 access |= vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
365 | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE;
366 }
367 if usage.intersects(
368 wgt::TextureUses::STORAGE_READ_ONLY
369 | wgt::TextureUses::STORAGE_READ_WRITE
370 | wgt::TextureUses::STORAGE_ATOMIC,
371 ) {
372 stages |= shader_stages;
373 access |= vk::AccessFlags::SHADER_READ;
374 }
375 if usage.intersects(
376 wgt::TextureUses::STORAGE_WRITE_ONLY
377 | wgt::TextureUses::STORAGE_READ_WRITE
378 | wgt::TextureUses::STORAGE_ATOMIC,
379 ) {
380 stages |= shader_stages;
381 access |= vk::AccessFlags::SHADER_WRITE;
382 }
383
384 if usage == wgt::TextureUses::UNINITIALIZED || usage == wgt::TextureUses::PRESENT {
385 (
386 vk::PipelineStageFlags::TOP_OF_PIPE,
387 vk::AccessFlags::empty(),
388 )
389 } else {
390 (stages, access)
391 }
392}
393
394pub fn map_vk_image_usage(usage: vk::ImageUsageFlags) -> wgt::TextureUses {
395 let mut bits = wgt::TextureUses::empty();
396 if usage.contains(vk::ImageUsageFlags::TRANSFER_SRC) {
397 bits |= wgt::TextureUses::COPY_SRC;
398 }
399 if usage.contains(vk::ImageUsageFlags::TRANSFER_DST) {
400 bits |= wgt::TextureUses::COPY_DST;
401 }
402 if usage.contains(vk::ImageUsageFlags::SAMPLED) {
403 bits |= wgt::TextureUses::RESOURCE;
404 }
405 if usage.contains(vk::ImageUsageFlags::COLOR_ATTACHMENT) {
406 bits |= wgt::TextureUses::COLOR_TARGET;
407 }
408 if usage.contains(vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT) {
409 bits |= wgt::TextureUses::DEPTH_READ
410 | wgt::TextureUses::DEPTH_WRITE
411 | wgt::TextureUses::STENCIL_READ
412 | wgt::TextureUses::STENCIL_WRITE;
413 }
414 if usage.contains(vk::ImageUsageFlags::STORAGE) {
415 bits |= wgt::TextureUses::STORAGE_READ_ONLY
416 | wgt::TextureUses::STORAGE_WRITE_ONLY
417 | wgt::TextureUses::STORAGE_READ_WRITE
418 | wgt::TextureUses::STORAGE_ATOMIC;
419 }
420 if usage.contains(vk::ImageUsageFlags::TRANSIENT_ATTACHMENT) {
421 bits |= wgt::TextureUses::TRANSIENT;
422 }
423 bits
424}
425
426pub fn map_texture_dimension(dim: wgt::TextureDimension) -> vk::ImageType {
427 match dim {
428 wgt::TextureDimension::D1 => vk::ImageType::TYPE_1D,
429 wgt::TextureDimension::D2 => vk::ImageType::TYPE_2D,
430 wgt::TextureDimension::D3 => vk::ImageType::TYPE_3D,
431 }
432}
433
434pub fn map_index_format(index_format: wgt::IndexFormat) -> vk::IndexType {
435 match index_format {
436 wgt::IndexFormat::Uint16 => vk::IndexType::UINT16,
437 wgt::IndexFormat::Uint32 => vk::IndexType::UINT32,
438 }
439}
440
441pub fn map_vertex_format(vertex_format: wgt::VertexFormat) -> vk::Format {
442 use wgt::VertexFormat as Vf;
443 match vertex_format {
444 Vf::Uint8 => vk::Format::R8_UINT,
445 Vf::Uint8x2 => vk::Format::R8G8_UINT,
446 Vf::Uint8x4 => vk::Format::R8G8B8A8_UINT,
447 Vf::Sint8 => vk::Format::R8_SINT,
448 Vf::Sint8x2 => vk::Format::R8G8_SINT,
449 Vf::Sint8x4 => vk::Format::R8G8B8A8_SINT,
450 Vf::Unorm8 => vk::Format::R8_UNORM,
451 Vf::Unorm8x2 => vk::Format::R8G8_UNORM,
452 Vf::Unorm8x4 => vk::Format::R8G8B8A8_UNORM,
453 Vf::Snorm8 => vk::Format::R8_SNORM,
454 Vf::Snorm8x2 => vk::Format::R8G8_SNORM,
455 Vf::Snorm8x4 => vk::Format::R8G8B8A8_SNORM,
456 Vf::Uint16 => vk::Format::R16_UINT,
457 Vf::Uint16x2 => vk::Format::R16G16_UINT,
458 Vf::Uint16x4 => vk::Format::R16G16B16A16_UINT,
459 Vf::Sint16 => vk::Format::R16_SINT,
460 Vf::Sint16x2 => vk::Format::R16G16_SINT,
461 Vf::Sint16x4 => vk::Format::R16G16B16A16_SINT,
462 Vf::Unorm16 => vk::Format::R16_UNORM,
463 Vf::Unorm16x2 => vk::Format::R16G16_UNORM,
464 Vf::Unorm16x4 => vk::Format::R16G16B16A16_UNORM,
465 Vf::Snorm16 => vk::Format::R16_SNORM,
466 Vf::Snorm16x2 => vk::Format::R16G16_SNORM,
467 Vf::Snorm16x4 => vk::Format::R16G16B16A16_SNORM,
468 Vf::Float16 => vk::Format::R16_SFLOAT,
469 Vf::Float16x2 => vk::Format::R16G16_SFLOAT,
470 Vf::Float16x4 => vk::Format::R16G16B16A16_SFLOAT,
471 Vf::Float32 => vk::Format::R32_SFLOAT,
472 Vf::Float32x2 => vk::Format::R32G32_SFLOAT,
473 Vf::Float32x3 => vk::Format::R32G32B32_SFLOAT,
474 Vf::Float32x4 => vk::Format::R32G32B32A32_SFLOAT,
475 Vf::Uint32 => vk::Format::R32_UINT,
476 Vf::Uint32x2 => vk::Format::R32G32_UINT,
477 Vf::Uint32x3 => vk::Format::R32G32B32_UINT,
478 Vf::Uint32x4 => vk::Format::R32G32B32A32_UINT,
479 Vf::Sint32 => vk::Format::R32_SINT,
480 Vf::Sint32x2 => vk::Format::R32G32_SINT,
481 Vf::Sint32x3 => vk::Format::R32G32B32_SINT,
482 Vf::Sint32x4 => vk::Format::R32G32B32A32_SINT,
483 Vf::Float64 => vk::Format::R64_SFLOAT,
484 Vf::Float64x2 => vk::Format::R64G64_SFLOAT,
485 Vf::Float64x3 => vk::Format::R64G64B64_SFLOAT,
486 Vf::Float64x4 => vk::Format::R64G64B64A64_SFLOAT,
487 Vf::Unorm10_10_10_2 => vk::Format::A2B10G10R10_UNORM_PACK32,
488 Vf::Snorm10_10_10_2 => vk::Format::A2B10G10R10_SNORM_PACK32,
491 Vf::Unorm8x4Bgra => vk::Format::B8G8R8A8_UNORM,
492 }
493}
494
495pub fn map_aspects(aspects: crate::FormatAspects) -> vk::ImageAspectFlags {
496 let mut flags = vk::ImageAspectFlags::empty();
497 if aspects.contains(crate::FormatAspects::COLOR) {
498 flags |= vk::ImageAspectFlags::COLOR;
499 }
500 if aspects.contains(crate::FormatAspects::DEPTH) {
501 flags |= vk::ImageAspectFlags::DEPTH;
502 }
503 if aspects.contains(crate::FormatAspects::STENCIL) {
504 flags |= vk::ImageAspectFlags::STENCIL;
505 }
506 if aspects.contains(crate::FormatAspects::PLANE_0) {
507 flags |= vk::ImageAspectFlags::PLANE_0;
508 }
509 if aspects.contains(crate::FormatAspects::PLANE_1) {
510 flags |= vk::ImageAspectFlags::PLANE_1;
511 }
512 if aspects.contains(crate::FormatAspects::PLANE_2) {
513 flags |= vk::ImageAspectFlags::PLANE_2;
514 }
515 flags
516}
517
518pub fn map_attachment_ops(
519 op: crate::AttachmentOps,
520) -> (vk::AttachmentLoadOp, vk::AttachmentStoreOp) {
521 let load_op = if op.contains(crate::AttachmentOps::LOAD) {
522 vk::AttachmentLoadOp::LOAD
523 } else if op.contains(crate::AttachmentOps::LOAD_DONT_CARE) {
524 vk::AttachmentLoadOp::DONT_CARE
525 } else if op.contains(crate::AttachmentOps::LOAD_CLEAR) {
526 vk::AttachmentLoadOp::CLEAR
527 } else {
528 unreachable!()
529 };
530 let store_op = if op.contains(crate::AttachmentOps::STORE) {
531 vk::AttachmentStoreOp::STORE
532 } else if op.contains(crate::AttachmentOps::STORE_DISCARD) {
533 vk::AttachmentStoreOp::DONT_CARE
534 } else {
535 unreachable!()
536 };
537 (load_op, store_op)
538}
539
540pub fn map_present_mode(mode: wgt::PresentMode) -> vk::PresentModeKHR {
541 match mode {
542 wgt::PresentMode::Immediate => vk::PresentModeKHR::IMMEDIATE,
543 wgt::PresentMode::Mailbox => vk::PresentModeKHR::MAILBOX,
544 wgt::PresentMode::Fifo => vk::PresentModeKHR::FIFO,
545 wgt::PresentMode::FifoRelaxed => vk::PresentModeKHR::FIFO_RELAXED,
546 wgt::PresentMode::AutoNoVsync | wgt::PresentMode::AutoVsync => {
547 unreachable!("Cannot create swapchain with Auto PresentationMode")
548 }
549 }
550}
551
552pub fn map_vk_present_mode(mode: vk::PresentModeKHR) -> Option<wgt::PresentMode> {
553 const FIFO_LATEST_READY: vk::PresentModeKHR = vk::PresentModeKHR::from_raw(1_000_361_000);
555
556 match mode {
558 vk::PresentModeKHR::IMMEDIATE => Some(wgt::PresentMode::Immediate),
559 vk::PresentModeKHR::MAILBOX => Some(wgt::PresentMode::Mailbox),
560 vk::PresentModeKHR::FIFO => Some(wgt::PresentMode::Fifo),
561 vk::PresentModeKHR::FIFO_RELAXED => Some(wgt::PresentMode::FifoRelaxed),
562
563 vk::PresentModeKHR::SHARED_DEMAND_REFRESH => None,
565 vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH => None,
566 FIFO_LATEST_READY => None,
567
568 _ => {
569 log::debug!("Unrecognized present mode {mode:?}");
570 None
571 }
572 }
573}
574
575pub fn map_composite_alpha_mode(mode: wgt::CompositeAlphaMode) -> vk::CompositeAlphaFlagsKHR {
576 match mode {
577 wgt::CompositeAlphaMode::Opaque => vk::CompositeAlphaFlagsKHR::OPAQUE,
578 wgt::CompositeAlphaMode::PreMultiplied => vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED,
579 wgt::CompositeAlphaMode::PostMultiplied => vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED,
580 wgt::CompositeAlphaMode::Inherit => vk::CompositeAlphaFlagsKHR::INHERIT,
581 wgt::CompositeAlphaMode::Auto => unreachable!(),
582 }
583}
584
585pub fn map_vk_composite_alpha(flags: vk::CompositeAlphaFlagsKHR) -> Vec<wgt::CompositeAlphaMode> {
586 let mut modes = Vec::new();
587 if flags.contains(vk::CompositeAlphaFlagsKHR::OPAQUE) {
588 modes.push(wgt::CompositeAlphaMode::Opaque);
589 }
590 if flags.contains(vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED) {
591 modes.push(wgt::CompositeAlphaMode::PreMultiplied);
592 }
593 if flags.contains(vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED) {
594 modes.push(wgt::CompositeAlphaMode::PostMultiplied);
595 }
596 if flags.contains(vk::CompositeAlphaFlagsKHR::INHERIT) {
597 modes.push(wgt::CompositeAlphaMode::Inherit);
598 }
599 modes
600}
601
602pub fn map_buffer_usage(usage: wgt::BufferUses) -> vk::BufferUsageFlags {
603 let mut flags = vk::BufferUsageFlags::empty();
604 if usage.contains(wgt::BufferUses::COPY_SRC) {
605 flags |= vk::BufferUsageFlags::TRANSFER_SRC;
606 }
607 if usage.contains(wgt::BufferUses::COPY_DST) {
608 flags |= vk::BufferUsageFlags::TRANSFER_DST;
609 }
610 if usage.contains(wgt::BufferUses::UNIFORM) {
611 flags |= vk::BufferUsageFlags::UNIFORM_BUFFER;
612 }
613 if usage.intersects(wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE) {
614 flags |= vk::BufferUsageFlags::STORAGE_BUFFER;
615 }
616 if usage.contains(wgt::BufferUses::INDEX) {
617 flags |= vk::BufferUsageFlags::INDEX_BUFFER;
618 }
619 if usage.contains(wgt::BufferUses::VERTEX) {
620 flags |= vk::BufferUsageFlags::VERTEX_BUFFER;
621 }
622 if usage.contains(wgt::BufferUses::INDIRECT) {
623 flags |= vk::BufferUsageFlags::INDIRECT_BUFFER;
624 }
625 if usage.contains(wgt::BufferUses::ACCELERATION_STRUCTURE_SCRATCH) {
626 flags |= vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
627 }
628 if usage.intersects(
629 wgt::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT
630 | wgt::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT,
631 ) {
632 flags |= vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR
633 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
634 }
635 if usage.intersects(wgt::BufferUses::ACCELERATION_STRUCTURE_QUERY) {
636 flags |= vk::BufferUsageFlags::TRANSFER_DST;
637 }
638 if usage.intersects(wgt::BufferUses::RAY_TRACING_PIPELINE_SHADER_DATA) {
639 flags |= vk::BufferUsageFlags::SHADER_BINDING_TABLE_KHR
640 | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
641 }
642 flags
643}
644
645pub fn map_buffer_usage_to_barrier(
646 usage: wgt::BufferUses,
647 queue_flags: vk::QueueFlags,
648 features: wgt::Features,
649) -> (vk::PipelineStageFlags, vk::AccessFlags) {
650 let mut stages = vk::PipelineStageFlags::empty();
651 let mut access = vk::AccessFlags::empty();
652 let shader_stages = shader_stages(queue_flags, features);
653
654 if usage.contains(wgt::BufferUses::MAP_READ) {
655 stages |= vk::PipelineStageFlags::HOST;
656 access |= vk::AccessFlags::HOST_READ;
657 }
658 if usage.contains(wgt::BufferUses::MAP_WRITE) {
659 stages |= vk::PipelineStageFlags::HOST;
660 access |= vk::AccessFlags::HOST_WRITE;
661 }
662 if usage.contains(wgt::BufferUses::COPY_SRC) {
663 stages |= vk::PipelineStageFlags::TRANSFER;
664 access |= vk::AccessFlags::TRANSFER_READ;
665 }
666 if usage.contains(wgt::BufferUses::COPY_DST) {
667 stages |= vk::PipelineStageFlags::TRANSFER;
668 access |= vk::AccessFlags::TRANSFER_WRITE;
669 }
670 if usage.contains(wgt::BufferUses::UNIFORM) {
671 stages |= shader_stages;
672 access |= vk::AccessFlags::UNIFORM_READ;
673 }
674 if usage.intersects(wgt::BufferUses::STORAGE_READ_ONLY) {
675 stages |= shader_stages;
676 access |= vk::AccessFlags::SHADER_READ;
677 }
678 if usage.intersects(wgt::BufferUses::STORAGE_READ_WRITE) {
679 stages |= shader_stages;
680 access |= vk::AccessFlags::SHADER_READ | vk::AccessFlags::SHADER_WRITE;
681 }
682 if usage.contains(wgt::BufferUses::INDEX) {
683 stages |= vk::PipelineStageFlags::VERTEX_INPUT;
684 access |= vk::AccessFlags::INDEX_READ;
685 }
686 if usage.contains(wgt::BufferUses::VERTEX) {
687 stages |= vk::PipelineStageFlags::VERTEX_INPUT;
688 access |= vk::AccessFlags::VERTEX_ATTRIBUTE_READ;
689 }
690 if usage.contains(wgt::BufferUses::INDIRECT) {
691 stages |= vk::PipelineStageFlags::DRAW_INDIRECT;
692 access |= vk::AccessFlags::INDIRECT_COMMAND_READ;
693 }
694 if usage.intersects(
695 wgt::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT
696 | wgt::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT
697 | wgt::BufferUses::ACCELERATION_STRUCTURE_SCRATCH,
698 ) {
699 stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
700 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR
701 | vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR
702 | vk::AccessFlags::SHADER_READ;
703 }
704 if usage.contains(wgt::BufferUses::ACCELERATION_STRUCTURE_QUERY) {
705 stages |= vk::PipelineStageFlags::TRANSFER;
706 access |= vk::AccessFlags::TRANSFER_WRITE;
707 }
708
709 (stages, access)
710}
711
712fn shader_stages(queue_flags: vk::QueueFlags, features: wgt::Features) -> vk::PipelineStageFlags {
713 let mut stages = vk::PipelineStageFlags::empty();
714
715 if queue_flags.contains(vk::QueueFlags::GRAPHICS) {
716 stages |= vk::PipelineStageFlags::VERTEX_SHADER | vk::PipelineStageFlags::FRAGMENT_SHADER;
717 }
718 if queue_flags.contains(vk::QueueFlags::COMPUTE) {
719 stages |= vk::PipelineStageFlags::COMPUTE_SHADER;
720 if features.contains(wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES) {
723 stages |= vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR;
724 }
725 }
726
727 stages
728}
729
730pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> vk::ImageViewType {
731 match dim {
732 wgt::TextureViewDimension::D1 => vk::ImageViewType::TYPE_1D,
733 wgt::TextureViewDimension::D2 => vk::ImageViewType::TYPE_2D,
734 wgt::TextureViewDimension::D2Array => vk::ImageViewType::TYPE_2D_ARRAY,
735 wgt::TextureViewDimension::Cube => vk::ImageViewType::CUBE,
736 wgt::TextureViewDimension::CubeArray => vk::ImageViewType::CUBE_ARRAY,
737 wgt::TextureViewDimension::D3 => vk::ImageViewType::TYPE_3D,
738 }
739}
740
741pub fn map_copy_extent(extent: &crate::CopyExtent) -> vk::Extent3D {
742 vk::Extent3D {
743 width: extent.width,
744 height: extent.height,
745 depth: extent.depth,
746 }
747}
748
749pub fn map_subresource_range(
750 range: &wgt::ImageSubresourceRange,
751 format: wgt::TextureFormat,
752) -> vk::ImageSubresourceRange {
753 vk::ImageSubresourceRange {
754 aspect_mask: map_aspects(crate::FormatAspects::new(format, range.aspect)),
755 base_mip_level: range.base_mip_level,
756 level_count: range.mip_level_count.unwrap_or(vk::REMAINING_MIP_LEVELS),
757 base_array_layer: range.base_array_layer,
758 layer_count: range
759 .array_layer_count
760 .unwrap_or(vk::REMAINING_ARRAY_LAYERS),
761 }
762}
763
764pub(super) fn map_subresource_range_combined_aspect(
767 range: &wgt::ImageSubresourceRange,
768 format: wgt::TextureFormat,
769 private_caps: &super::PrivateCapabilities,
770) -> vk::ImageSubresourceRange {
771 let mut range = map_subresource_range(range, format);
772 if !private_caps.texture_s8 && format == wgt::TextureFormat::Stencil8 {
773 range.aspect_mask |= vk::ImageAspectFlags::DEPTH;
774 }
775 range
776}
777
778pub fn map_subresource_layers(
779 base: &crate::TextureCopyBase,
780) -> (vk::ImageSubresourceLayers, vk::Offset3D) {
781 let offset = vk::Offset3D {
782 x: base.origin.x as i32,
783 y: base.origin.y as i32,
784 z: base.origin.z as i32,
785 };
786 let subresource = vk::ImageSubresourceLayers {
787 aspect_mask: map_aspects(base.aspect),
788 mip_level: base.mip_level,
789 base_array_layer: base.array_layer,
790 layer_count: 1,
791 };
792 (subresource, offset)
793}
794
795pub fn map_filter_mode(mode: wgt::FilterMode) -> vk::Filter {
796 match mode {
797 wgt::FilterMode::Nearest => vk::Filter::NEAREST,
798 wgt::FilterMode::Linear => vk::Filter::LINEAR,
799 }
800}
801
802pub fn map_mip_filter_mode(mode: wgt::MipmapFilterMode) -> vk::SamplerMipmapMode {
803 match mode {
804 wgt::MipmapFilterMode::Nearest => vk::SamplerMipmapMode::NEAREST,
805 wgt::MipmapFilterMode::Linear => vk::SamplerMipmapMode::LINEAR,
806 }
807}
808
809pub fn map_address_mode(mode: wgt::AddressMode) -> vk::SamplerAddressMode {
810 match mode {
811 wgt::AddressMode::ClampToEdge => vk::SamplerAddressMode::CLAMP_TO_EDGE,
812 wgt::AddressMode::Repeat => vk::SamplerAddressMode::REPEAT,
813 wgt::AddressMode::MirrorRepeat => vk::SamplerAddressMode::MIRRORED_REPEAT,
814 wgt::AddressMode::ClampToBorder => vk::SamplerAddressMode::CLAMP_TO_BORDER,
815 }
817}
818
819pub fn map_border_color(border_color: wgt::SamplerBorderColor) -> vk::BorderColor {
820 match border_color {
821 wgt::SamplerBorderColor::TransparentBlack | wgt::SamplerBorderColor::Zero => {
822 vk::BorderColor::FLOAT_TRANSPARENT_BLACK
823 }
824 wgt::SamplerBorderColor::OpaqueBlack => vk::BorderColor::FLOAT_OPAQUE_BLACK,
825 wgt::SamplerBorderColor::OpaqueWhite => vk::BorderColor::FLOAT_OPAQUE_WHITE,
826 }
827}
828
829pub fn map_comparison(fun: wgt::CompareFunction) -> vk::CompareOp {
830 use wgt::CompareFunction as Cf;
831 match fun {
832 Cf::Never => vk::CompareOp::NEVER,
833 Cf::Less => vk::CompareOp::LESS,
834 Cf::LessEqual => vk::CompareOp::LESS_OR_EQUAL,
835 Cf::Equal => vk::CompareOp::EQUAL,
836 Cf::GreaterEqual => vk::CompareOp::GREATER_OR_EQUAL,
837 Cf::Greater => vk::CompareOp::GREATER,
838 Cf::NotEqual => vk::CompareOp::NOT_EQUAL,
839 Cf::Always => vk::CompareOp::ALWAYS,
840 }
841}
842
843pub fn map_shader_stage(stage: wgt::ShaderStages) -> vk::ShaderStageFlags {
844 let mut flags = vk::ShaderStageFlags::empty();
845 if stage.contains(wgt::ShaderStages::VERTEX) {
846 flags |= vk::ShaderStageFlags::VERTEX;
847 }
848 if stage.contains(wgt::ShaderStages::FRAGMENT) {
849 flags |= vk::ShaderStageFlags::FRAGMENT;
850 }
851 if stage.contains(wgt::ShaderStages::COMPUTE) {
852 flags |= vk::ShaderStageFlags::COMPUTE;
853 }
854 if stage.contains(wgt::ShaderStages::TASK) {
855 flags |= vk::ShaderStageFlags::TASK_EXT;
856 }
857 if stage.contains(wgt::ShaderStages::MESH) {
858 flags |= vk::ShaderStageFlags::MESH_EXT;
859 }
860 if stage.contains(wgt::ShaderStages::RAY_GENERATION) {
861 flags |= vk::ShaderStageFlags::RAYGEN_KHR;
862 }
863 if stage.contains(wgt::ShaderStages::MISS) {
864 flags |= vk::ShaderStageFlags::MISS_KHR;
865 }
866 if stage.contains(wgt::ShaderStages::ANY_HIT) {
867 flags |= vk::ShaderStageFlags::ANY_HIT_KHR;
868 }
869 if stage.contains(wgt::ShaderStages::CLOSEST_HIT) {
870 flags |= vk::ShaderStageFlags::CLOSEST_HIT_KHR;
871 }
872 flags
873}
874
875pub fn map_binding_type(ty: wgt::BindingType) -> vk::DescriptorType {
876 match ty {
877 wgt::BindingType::Buffer {
878 ty,
879 has_dynamic_offset,
880 ..
881 } => match ty {
882 wgt::BufferBindingType::Storage { .. } => match has_dynamic_offset {
883 true => vk::DescriptorType::STORAGE_BUFFER_DYNAMIC,
884 false => vk::DescriptorType::STORAGE_BUFFER,
885 },
886 wgt::BufferBindingType::Uniform => match has_dynamic_offset {
887 true => vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC,
888 false => vk::DescriptorType::UNIFORM_BUFFER,
889 },
890 },
891 wgt::BindingType::Sampler { .. } => vk::DescriptorType::SAMPLER,
892 wgt::BindingType::Texture { .. } => vk::DescriptorType::SAMPLED_IMAGE,
893 wgt::BindingType::StorageTexture { .. } => vk::DescriptorType::STORAGE_IMAGE,
894 wgt::BindingType::AccelerationStructure { .. } => {
895 vk::DescriptorType::ACCELERATION_STRUCTURE_KHR
896 }
897 wgt::BindingType::ExternalTexture => unimplemented!(),
898 }
899}
900
901pub fn map_topology(topology: wgt::PrimitiveTopology) -> vk::PrimitiveTopology {
902 use wgt::PrimitiveTopology as Pt;
903 match topology {
904 Pt::PointList => vk::PrimitiveTopology::POINT_LIST,
905 Pt::LineList => vk::PrimitiveTopology::LINE_LIST,
906 Pt::LineStrip => vk::PrimitiveTopology::LINE_STRIP,
907 Pt::TriangleList => vk::PrimitiveTopology::TRIANGLE_LIST,
908 Pt::TriangleStrip => vk::PrimitiveTopology::TRIANGLE_STRIP,
909 }
910}
911
912pub fn map_polygon_mode(mode: wgt::PolygonMode) -> vk::PolygonMode {
913 match mode {
914 wgt::PolygonMode::Fill => vk::PolygonMode::FILL,
915 wgt::PolygonMode::Line => vk::PolygonMode::LINE,
916 wgt::PolygonMode::Point => vk::PolygonMode::POINT,
917 }
918}
919
920pub fn map_front_face(front_face: wgt::FrontFace) -> vk::FrontFace {
921 match front_face {
922 wgt::FrontFace::Cw => vk::FrontFace::CLOCKWISE,
923 wgt::FrontFace::Ccw => vk::FrontFace::COUNTER_CLOCKWISE,
924 }
925}
926
927pub fn map_cull_face(face: wgt::Face) -> vk::CullModeFlags {
928 match face {
929 wgt::Face::Front => vk::CullModeFlags::FRONT,
930 wgt::Face::Back => vk::CullModeFlags::BACK,
931 }
932}
933
934pub fn map_stencil_op(op: wgt::StencilOperation) -> vk::StencilOp {
935 use wgt::StencilOperation as So;
936 match op {
937 So::Keep => vk::StencilOp::KEEP,
938 So::Zero => vk::StencilOp::ZERO,
939 So::Replace => vk::StencilOp::REPLACE,
940 So::Invert => vk::StencilOp::INVERT,
941 So::IncrementClamp => vk::StencilOp::INCREMENT_AND_CLAMP,
942 So::IncrementWrap => vk::StencilOp::INCREMENT_AND_WRAP,
943 So::DecrementClamp => vk::StencilOp::DECREMENT_AND_CLAMP,
944 So::DecrementWrap => vk::StencilOp::DECREMENT_AND_WRAP,
945 }
946}
947
948pub fn map_stencil_face(
949 face: &wgt::StencilFaceState,
950 compare_mask: u32,
951 write_mask: u32,
952) -> vk::StencilOpState {
953 vk::StencilOpState {
954 fail_op: map_stencil_op(face.fail_op),
955 pass_op: map_stencil_op(face.pass_op),
956 depth_fail_op: map_stencil_op(face.depth_fail_op),
957 compare_op: map_comparison(face.compare),
958 compare_mask,
959 write_mask,
960 reference: 0,
961 }
962}
963
964fn map_blend_factor(factor: wgt::BlendFactor) -> vk::BlendFactor {
965 use wgt::BlendFactor as Bf;
966 match factor {
967 Bf::Zero => vk::BlendFactor::ZERO,
968 Bf::One => vk::BlendFactor::ONE,
969 Bf::Src => vk::BlendFactor::SRC_COLOR,
970 Bf::OneMinusSrc => vk::BlendFactor::ONE_MINUS_SRC_COLOR,
971 Bf::SrcAlpha => vk::BlendFactor::SRC_ALPHA,
972 Bf::OneMinusSrcAlpha => vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
973 Bf::Dst => vk::BlendFactor::DST_COLOR,
974 Bf::OneMinusDst => vk::BlendFactor::ONE_MINUS_DST_COLOR,
975 Bf::DstAlpha => vk::BlendFactor::DST_ALPHA,
976 Bf::OneMinusDstAlpha => vk::BlendFactor::ONE_MINUS_DST_ALPHA,
977 Bf::SrcAlphaSaturated => vk::BlendFactor::SRC_ALPHA_SATURATE,
978 Bf::Constant => vk::BlendFactor::CONSTANT_COLOR,
979 Bf::OneMinusConstant => vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR,
980 Bf::Src1 => vk::BlendFactor::SRC1_COLOR,
981 Bf::OneMinusSrc1 => vk::BlendFactor::ONE_MINUS_SRC1_COLOR,
982 Bf::Src1Alpha => vk::BlendFactor::SRC1_ALPHA,
983 Bf::OneMinusSrc1Alpha => vk::BlendFactor::ONE_MINUS_SRC1_ALPHA,
984 }
985}
986
987fn map_blend_op(operation: wgt::BlendOperation) -> vk::BlendOp {
988 use wgt::BlendOperation as Bo;
989 match operation {
990 Bo::Add => vk::BlendOp::ADD,
991 Bo::Subtract => vk::BlendOp::SUBTRACT,
992 Bo::ReverseSubtract => vk::BlendOp::REVERSE_SUBTRACT,
993 Bo::Min => vk::BlendOp::MIN,
994 Bo::Max => vk::BlendOp::MAX,
995 }
996}
997
998pub fn map_blend_component(
999 component: &wgt::BlendComponent,
1000) -> (vk::BlendOp, vk::BlendFactor, vk::BlendFactor) {
1001 let op = map_blend_op(component.operation);
1002 let src = map_blend_factor(component.src_factor);
1003 let dst = map_blend_factor(component.dst_factor);
1004 (op, src, dst)
1005}
1006
1007pub fn map_pipeline_statistics(
1008 types: wgt::PipelineStatisticsTypes,
1009) -> vk::QueryPipelineStatisticFlags {
1010 use wgt::PipelineStatisticsTypes as Pst;
1011 let mut flags = vk::QueryPipelineStatisticFlags::empty();
1012 if types.contains(Pst::VERTEX_SHADER_INVOCATIONS) {
1013 flags |= vk::QueryPipelineStatisticFlags::VERTEX_SHADER_INVOCATIONS;
1014 }
1015 if types.contains(Pst::CLIPPER_INVOCATIONS) {
1016 flags |= vk::QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS;
1017 }
1018 if types.contains(Pst::CLIPPER_PRIMITIVES_OUT) {
1019 flags |= vk::QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES;
1020 }
1021 if types.contains(Pst::FRAGMENT_SHADER_INVOCATIONS) {
1022 flags |= vk::QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS;
1023 }
1024 if types.contains(Pst::COMPUTE_SHADER_INVOCATIONS) {
1025 flags |= vk::QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS;
1026 }
1027 flags
1028}
1029
1030pub fn map_acceleration_structure_format(
1031 format: crate::AccelerationStructureFormat,
1032) -> vk::AccelerationStructureTypeKHR {
1033 match format {
1034 crate::AccelerationStructureFormat::TopLevel => vk::AccelerationStructureTypeKHR::TOP_LEVEL,
1035 crate::AccelerationStructureFormat::BottomLevel => {
1036 vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL
1037 }
1038 }
1039}
1040
1041pub fn map_acceleration_structure_build_mode(
1042 format: crate::AccelerationStructureBuildMode,
1043) -> vk::BuildAccelerationStructureModeKHR {
1044 match format {
1045 crate::AccelerationStructureBuildMode::Build => {
1046 vk::BuildAccelerationStructureModeKHR::BUILD
1047 }
1048 crate::AccelerationStructureBuildMode::Update => {
1049 vk::BuildAccelerationStructureModeKHR::UPDATE
1050 }
1051 }
1052}
1053
1054pub fn map_acceleration_structure_flags(
1055 flags: crate::AccelerationStructureBuildFlags,
1056) -> vk::BuildAccelerationStructureFlagsKHR {
1057 let mut vk_flags = vk::BuildAccelerationStructureFlagsKHR::empty();
1058
1059 if flags.contains(crate::AccelerationStructureBuildFlags::PREFER_FAST_TRACE) {
1060 vk_flags |= vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE;
1061 }
1062
1063 if flags.contains(crate::AccelerationStructureBuildFlags::PREFER_FAST_BUILD) {
1064 vk_flags |= vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_BUILD;
1065 }
1066
1067 if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_UPDATE) {
1068 vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_UPDATE;
1069 }
1070
1071 if flags.contains(crate::AccelerationStructureBuildFlags::LOW_MEMORY) {
1072 vk_flags |= vk::BuildAccelerationStructureFlagsKHR::LOW_MEMORY;
1073 }
1074
1075 if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_COMPACTION) {
1076 vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_COMPACTION
1077 }
1078
1079 if flags.contains(crate::AccelerationStructureBuildFlags::ALLOW_RAY_HIT_VERTEX_RETURN) {
1080 vk_flags |= vk::BuildAccelerationStructureFlagsKHR::ALLOW_DATA_ACCESS
1081 }
1082
1083 vk_flags
1084}
1085
1086pub fn map_acceleration_structure_geometry_flags(
1087 flags: crate::AccelerationStructureGeometryFlags,
1088) -> vk::GeometryFlagsKHR {
1089 let mut vk_flags = vk::GeometryFlagsKHR::empty();
1090
1091 if flags.contains(crate::AccelerationStructureGeometryFlags::OPAQUE) {
1092 vk_flags |= vk::GeometryFlagsKHR::OPAQUE;
1093 }
1094
1095 if flags.contains(crate::AccelerationStructureGeometryFlags::NO_DUPLICATE_ANY_HIT_INVOCATION) {
1096 vk_flags |= vk::GeometryFlagsKHR::NO_DUPLICATE_ANY_HIT_INVOCATION;
1097 }
1098
1099 vk_flags
1100}
1101
1102pub fn map_acceleration_structure_usage_to_barrier(
1103 usage: crate::AccelerationStructureUses,
1104 features: wgt::Features,
1105 queue_flags: vk::QueueFlags,
1106) -> (vk::PipelineStageFlags, vk::AccessFlags) {
1107 let mut stages = vk::PipelineStageFlags::empty();
1108 let mut access = vk::AccessFlags::empty();
1109
1110 if usage.contains(crate::AccelerationStructureUses::BUILD_INPUT) {
1111 stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1112 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1113 }
1114 if usage.contains(crate::AccelerationStructureUses::QUERY_INPUT) {
1115 stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1116 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1117 }
1118 if usage.contains(crate::AccelerationStructureUses::BUILD_OUTPUT) {
1119 stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1120 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR;
1121 }
1122 if usage.contains(crate::AccelerationStructureUses::SHADER_INPUT)
1123 && features.contains(wgt::Features::EXPERIMENTAL_RAY_QUERY)
1124 {
1125 stages |= shader_stages(queue_flags, features);
1126 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1127 }
1128 if usage.contains(crate::AccelerationStructureUses::SHADER_INPUT)
1129 && features.contains(wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES)
1130 {
1131 stages |= vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR;
1132 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1133 }
1134 if usage.contains(crate::AccelerationStructureUses::COPY_SRC) {
1135 stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1136 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR;
1137 }
1138 if usage.contains(crate::AccelerationStructureUses::COPY_DST) {
1139 stages |= vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR;
1140 access |= vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR;
1141 }
1142
1143 (stages, access)
1144}
1145
1146pub fn map_component_swizzle(swizzle: wgt::ComponentSwizzle) -> vk::ComponentSwizzle {
1147 match swizzle {
1148 wgt::ComponentSwizzle::Zero => vk::ComponentSwizzle::ZERO,
1149 wgt::ComponentSwizzle::One => vk::ComponentSwizzle::ONE,
1150 wgt::ComponentSwizzle::R => vk::ComponentSwizzle::R,
1151 wgt::ComponentSwizzle::G => vk::ComponentSwizzle::G,
1152 wgt::ComponentSwizzle::B => vk::ComponentSwizzle::B,
1153 wgt::ComponentSwizzle::A => vk::ComponentSwizzle::A,
1154 }
1155}
1156
1157pub fn map_texture_component_swizzle(
1158 swizzle: wgt::TextureComponentSwizzle,
1159) -> vk::ComponentMapping {
1160 vk::ComponentMapping {
1161 r: map_component_swizzle(swizzle.r),
1162 g: map_component_swizzle(swizzle.g),
1163 b: map_component_swizzle(swizzle.b),
1164 a: map_component_swizzle(swizzle.a),
1165 }
1166}
1167
1168#[cfg(test)]
1169mod tests {
1170 use super::*;
1171
1172 #[test]
1176 fn color_space_round_trip() {
1177 for vk_color_space in [
1178 vk::ColorSpaceKHR::SRGB_NONLINEAR,
1179 vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT,
1180 vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT,
1181 vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT,
1182 vk::ColorSpaceKHR::HDR10_ST2084_EXT,
1183 vk::ColorSpaceKHR::HDR10_HLG_EXT,
1184 ] {
1185 let mapped = map_vk_color_space(vk_color_space).unwrap();
1186 assert_eq!(map_surface_color_space(mapped), vk_color_space);
1187 }
1188 }
1189
1190 #[test]
1191 fn unknown_color_spaces_are_dropped() {
1192 for vk_color_space in [
1193 vk::ColorSpaceKHR::BT2020_LINEAR_EXT,
1194 vk::ColorSpaceKHR::DOLBYVISION_EXT,
1195 vk::ColorSpaceKHR::PASS_THROUGH_EXT,
1196 vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT,
1197 ] {
1198 assert!(map_vk_color_space(vk_color_space).is_none());
1199 assert!(map_vk_surface_formats(vk::SurfaceFormatKHR {
1200 format: vk::Format::B8G8R8A8_UNORM,
1201 color_space: vk_color_space,
1202 })
1203 .is_none());
1204 }
1205 }
1206
1207 #[test]
1208 fn hdr10_surface_format_maps() {
1209 let (format, color_space) = map_vk_surface_formats(vk::SurfaceFormatKHR {
1210 format: vk::Format::A2B10G10R10_UNORM_PACK32,
1211 color_space: vk::ColorSpaceKHR::HDR10_ST2084_EXT,
1212 })
1213 .unwrap();
1214 assert_eq!(format, wgt::TextureFormat::Rgb10a2Unorm);
1215 assert_eq!(color_space, wgt::SurfaceColorSpace::Bt2100Pq);
1216 }
1217
1218 #[test]
1219 fn buffer_shader_stages_follow_queue_flags() {
1220 let usage = wgt::BufferUses::UNIFORM;
1221
1222 let (stages, access) =
1223 map_buffer_usage_to_barrier(usage, vk::QueueFlags::GRAPHICS, wgt::Features::empty());
1224 assert_eq!(
1225 stages,
1226 vk::PipelineStageFlags::VERTEX_SHADER | vk::PipelineStageFlags::FRAGMENT_SHADER
1227 );
1228 assert_eq!(access, vk::AccessFlags::UNIFORM_READ);
1229
1230 let (stages, access) =
1231 map_buffer_usage_to_barrier(usage, vk::QueueFlags::COMPUTE, wgt::Features::empty());
1232 assert_eq!(stages, vk::PipelineStageFlags::COMPUTE_SHADER);
1233 assert_eq!(access, vk::AccessFlags::UNIFORM_READ);
1234
1235 let (stages, access) = map_buffer_usage_to_barrier(
1236 usage,
1237 vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE,
1238 wgt::Features::empty(),
1239 );
1240 assert_eq!(
1241 stages,
1242 vk::PipelineStageFlags::VERTEX_SHADER
1243 | vk::PipelineStageFlags::FRAGMENT_SHADER
1244 | vk::PipelineStageFlags::COMPUTE_SHADER
1245 );
1246 assert_eq!(access, vk::AccessFlags::UNIFORM_READ);
1247 }
1248
1249 #[test]
1250 fn non_shader_buffer_usage_is_unchanged() {
1251 let (stages, access) = map_buffer_usage_to_barrier(
1252 wgt::BufferUses::COPY_SRC | wgt::BufferUses::VERTEX,
1253 vk::QueueFlags::empty(),
1254 wgt::Features::empty(),
1255 );
1256
1257 assert_eq!(
1258 stages,
1259 vk::PipelineStageFlags::TRANSFER | vk::PipelineStageFlags::VERTEX_INPUT
1260 );
1261 assert_eq!(
1262 access,
1263 vk::AccessFlags::TRANSFER_READ | vk::AccessFlags::VERTEX_ATTRIBUTE_READ
1264 );
1265 }
1266
1267 #[test]
1268 fn texture_shader_stages_follow_queue_flags() {
1269 let usage = wgt::TextureUses::RESOURCE;
1270
1271 let (stages, access) = map_texture_usage_to_barrier(
1272 usage,
1273 vk::QueueFlags::GRAPHICS,
1274 false,
1275 wgt::Features::empty(),
1276 );
1277 assert_eq!(
1278 stages,
1279 vk::PipelineStageFlags::VERTEX_SHADER | vk::PipelineStageFlags::FRAGMENT_SHADER
1280 );
1281 assert_eq!(access, vk::AccessFlags::SHADER_READ);
1282
1283 let (stages, access) = map_texture_usage_to_barrier(
1284 usage,
1285 vk::QueueFlags::COMPUTE,
1286 false,
1287 wgt::Features::empty(),
1288 );
1289 assert_eq!(stages, vk::PipelineStageFlags::COMPUTE_SHADER);
1290 assert_eq!(access, vk::AccessFlags::SHADER_READ);
1291
1292 let (stages, access) = map_texture_usage_to_barrier(
1293 usage,
1294 vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE,
1295 false,
1296 wgt::Features::empty(),
1297 );
1298 assert_eq!(
1299 stages,
1300 vk::PipelineStageFlags::VERTEX_SHADER
1301 | vk::PipelineStageFlags::FRAGMENT_SHADER
1302 | vk::PipelineStageFlags::COMPUTE_SHADER
1303 );
1304 assert_eq!(access, vk::AccessFlags::SHADER_READ);
1305 }
1306
1307 #[test]
1308 fn non_shader_texture_usage_is_unchanged() {
1309 let (stages, access) = map_texture_usage_to_barrier(
1310 wgt::TextureUses::COPY_SRC | wgt::TextureUses::COLOR_TARGET,
1311 vk::QueueFlags::empty(),
1312 false,
1313 wgt::Features::empty(),
1314 );
1315
1316 assert_eq!(
1317 stages,
1318 vk::PipelineStageFlags::TRANSFER | vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT
1319 );
1320 assert_eq!(
1321 access,
1322 vk::AccessFlags::TRANSFER_READ
1323 | vk::AccessFlags::COLOR_ATTACHMENT_READ
1324 | vk::AccessFlags::COLOR_ATTACHMENT_WRITE
1325 );
1326 }
1327
1328 #[test]
1329 fn acceleration_structure_shader_stages_follow_queue_flags() {
1330 let usage = crate::AccelerationStructureUses::SHADER_INPUT;
1331 let features = wgt::Features::EXPERIMENTAL_RAY_QUERY;
1332
1333 let (stages, access) =
1334 map_acceleration_structure_usage_to_barrier(usage, features, vk::QueueFlags::GRAPHICS);
1335 assert_eq!(
1336 stages,
1337 vk::PipelineStageFlags::VERTEX_SHADER | vk::PipelineStageFlags::FRAGMENT_SHADER
1338 );
1339 assert_eq!(access, vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR);
1340
1341 let (stages, access) =
1342 map_acceleration_structure_usage_to_barrier(usage, features, vk::QueueFlags::COMPUTE);
1343 assert_eq!(stages, vk::PipelineStageFlags::COMPUTE_SHADER);
1344 assert_eq!(access, vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR);
1345
1346 let (stages, access) = map_acceleration_structure_usage_to_barrier(
1347 usage,
1348 features | wgt::Features::EXPERIMENTAL_RAY_TRACING_PIPELINES,
1349 vk::QueueFlags::COMPUTE,
1350 );
1351 assert_eq!(
1352 stages,
1353 vk::PipelineStageFlags::COMPUTE_SHADER | vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR
1354 );
1355 assert_eq!(access, vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR);
1356
1357 let (stages, access) = map_acceleration_structure_usage_to_barrier(
1358 usage,
1359 features,
1360 vk::QueueFlags::GRAPHICS | vk::QueueFlags::COMPUTE,
1361 );
1362 assert_eq!(
1363 stages,
1364 vk::PipelineStageFlags::VERTEX_SHADER
1365 | vk::PipelineStageFlags::FRAGMENT_SHADER
1366 | vk::PipelineStageFlags::COMPUTE_SHADER
1367 );
1368 assert_eq!(access, vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR);
1369 }
1370
1371 #[test]
1372 fn non_shader_acceleration_structure_usage_is_unchanged() {
1373 let (stages, access) = map_acceleration_structure_usage_to_barrier(
1374 crate::AccelerationStructureUses::BUILD_INPUT
1375 | crate::AccelerationStructureUses::BUILD_OUTPUT,
1376 wgt::Features::empty(),
1377 vk::QueueFlags::empty(),
1378 );
1379
1380 assert_eq!(
1381 stages,
1382 vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR
1383 );
1384 assert_eq!(
1385 access,
1386 vk::AccessFlags::ACCELERATION_STRUCTURE_READ_KHR
1387 | vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR
1388 );
1389 }
1390}