1use ash::vk;
2use naga::back::spv;
3use std::{ffi, mem, str};
4
5const DUMP_PREFIX: Option<&str> = None;
6
7struct CompiledShader<'a> {
8 vk_module: vk::ShaderModule,
9 _entry_point: ffi::CString,
10 create_info: vk::PipelineShaderStageCreateInfo<'a>,
11 attribute_mappings: Vec<crate::VertexAttributeMapping>,
12 wg_size: [u32; 3],
13}
14
15impl super::Context {
16 fn make_spv_options(&self, data_layouts: &[&crate::ShaderDataLayout]) -> spv::Options<'_> {
17 let mut binding_map = spv::BindingMap::default();
19 for (group_index, layout) in data_layouts.iter().enumerate() {
20 for (binding_index, &(_, binding)) in layout.bindings.iter().enumerate() {
21 let binding_array_size = match binding {
22 crate::ShaderBinding::TextureArray { count }
23 | crate::ShaderBinding::BufferArray { count }
24 | crate::ShaderBinding::AccelerationStructureArray { count } => Some(count),
25 _ => None,
26 };
27 let rb = naga::ResourceBinding {
28 group: group_index as u32,
29 binding: binding_index as u32,
30 };
31 binding_map.insert(
32 rb,
33 spv::BindingInfo {
34 descriptor_set: group_index as u32,
35 binding: binding_index as u32,
36 binding_array_size,
37 },
38 );
39 }
40 }
41
42 spv::Options {
43 lang_version: match self.device.ray_tracing {
44 Some(_) => (1, 4),
46 None => (1, 3),
47 },
48 flags: self.naga_flags,
49 fake_missing_bindings: false,
50 binding_map,
51 capabilities: None,
52 bounds_check_policies: naga::proc::BoundsCheckPolicies::default(),
53 zero_initialize_workgroup_memory: spv::ZeroInitializeWorkgroupMemoryMode::None,
54 force_loop_bounding: false,
55 ray_query_initialization_tracking: true,
56 use_storage_input_output_16: false,
57 debug_info: None,
58 task_dispatch_limits: None,
59 mesh_shader_primitive_indices_clamp: true,
60 }
61 }
62
63 fn load_shader(
64 &self,
65 sf: crate::ShaderFunction,
66 naga_options_base: &spv::Options,
67 group_layouts: &[&crate::ShaderDataLayout],
68 group_infos: &mut [crate::ShaderDataInfo],
69 vertex_fetch_states: &[crate::VertexFetchState],
70 ) -> CompiledShader<'_> {
71 let ep_index = sf.entry_point_index();
72 let ep = &sf.shader.module.entry_points[ep_index];
73 let ep_info = sf.shader.info.get_entry_point(ep_index);
74
75 let (mut module, module_info) = sf.shader.resolve_constants(sf.constants);
76 crate::Shader::fill_resource_bindings(
77 &mut module,
78 group_infos,
79 ep.stage,
80 ep_info,
81 group_layouts,
82 );
83 let attribute_mappings =
84 crate::Shader::fill_vertex_locations(&mut module, ep_index, vertex_fetch_states);
85
86 let pipeline_options = spv::PipelineOptions {
87 shader_stage: ep.stage,
88 entry_point: sf.entry_point.to_string(),
89 };
90 let file_path;
91 let file_name_str;
92 let mut naga_options_debug;
93 let naga_options = if let Some(ref temp_dir) = self.shader_debug_path {
94 use std::{
95 fs,
96 hash::{DefaultHasher, Hash as _, Hasher as _},
97 };
98 let mut hasher = DefaultHasher::new();
99 sf.shader.source.hash(&mut hasher);
100 file_path = temp_dir.join(format!("{}-{:x}.wgsl", sf.entry_point, hasher.finish()));
101 let _ = fs::write(&file_path, &sf.shader.source);
102
103 naga_options_debug = naga_options_base.clone();
104 file_name_str = file_path.to_string_lossy().into_owned();
105 naga_options_debug.debug_info = Some(naga::back::spv::DebugInfo {
106 source_code: &sf.shader.source,
107 file_name: &file_name_str,
108 language: naga::back::spv::SourceLanguage::GLSL,
110 });
111 &naga_options_debug
112 } else {
113 naga_options_base
114 };
115
116 let spv =
117 spv::write_vec(&module, &module_info, naga_options, Some(&pipeline_options)).unwrap();
118
119 if let Some(dump_prefix) = DUMP_PREFIX {
120 let mut file_name = String::new();
121 for i in 1.. {
122 file_name = format!("{}{}_{:?}{}.spv", dump_prefix, sf.entry_point, ep.stage, i);
123 if !std::path::Path::new(&file_name).exists() {
124 break;
125 }
126 }
127 let spv_bytes =
128 unsafe { std::slice::from_raw_parts(spv.as_ptr() as *const u8, spv.len() * 4) };
129 println!("Dumping {}", file_name);
130 std::fs::write(file_name, spv_bytes).unwrap();
131 }
132
133 let vk_info = vk::ShaderModuleCreateInfo::default().code(&spv);
134
135 let vk_module = unsafe {
136 self.device
137 .core
138 .create_shader_module(&vk_info, None)
139 .unwrap()
140 };
141
142 let vk_stage = match ep.stage {
143 naga::ShaderStage::Compute => vk::ShaderStageFlags::COMPUTE,
144 naga::ShaderStage::Vertex => vk::ShaderStageFlags::VERTEX,
145 naga::ShaderStage::Fragment => vk::ShaderStageFlags::FRAGMENT,
146 _ => panic!("Unsupported shader stage: {:?}", ep.stage),
147 };
148
149 let entry_point = ffi::CString::new(sf.entry_point).unwrap();
150 let create_info = vk::PipelineShaderStageCreateInfo {
151 stage: vk_stage,
152 module: vk_module,
153 p_name: entry_point.as_ptr(),
154 ..Default::default()
155 };
156
157 CompiledShader {
158 vk_module,
159 _entry_point: entry_point,
160 create_info,
161 attribute_mappings,
162 wg_size: ep.workgroup_size,
163 }
164 }
165
166 fn create_descriptor_set_layout(
167 &self,
168 layout: &crate::ShaderDataLayout,
169 info: &crate::ShaderDataInfo,
170 ) -> super::DescriptorSetLayout {
171 if info.visibility.is_empty() {
172 return super::DescriptorSetLayout {
174 raw: unsafe {
175 self.device
176 .core
177 .create_descriptor_set_layout(&Default::default(), None)
178 .unwrap()
179 },
180 ..Default::default()
181 };
182 }
183
184 let stage_flags = map_shader_visibility(info.visibility);
185 let mut vk_bindings = Vec::with_capacity(layout.bindings.len());
186 let mut template_entries = Vec::with_capacity(layout.bindings.len());
187 let mut template_offsets = Vec::with_capacity(layout.bindings.len());
188 let mut binding_flags = Vec::with_capacity(layout.bindings.len());
189 let mut inline_uniform_mask = 0u64;
190 let mut update_offset = 0;
191 for (binding_index, (&(_, binding), &access)) in layout
192 .bindings
193 .iter()
194 .zip(info.binding_access.iter())
195 .enumerate()
196 {
197 let (descriptor_type, descriptor_size, descriptor_count, flag) = match binding {
198 crate::ShaderBinding::Texture => (
199 if access.is_empty() {
200 vk::DescriptorType::SAMPLED_IMAGE
201 } else {
202 vk::DescriptorType::STORAGE_IMAGE
203 },
204 mem::size_of::<vk::DescriptorImageInfo>(),
205 1u32,
206 vk::DescriptorBindingFlags::empty(),
207 ),
208 crate::ShaderBinding::TextureArray { count } => (
209 if access.is_empty() {
210 vk::DescriptorType::SAMPLED_IMAGE
211 } else {
212 vk::DescriptorType::STORAGE_IMAGE
213 },
214 mem::size_of::<vk::DescriptorImageInfo>(),
215 count,
216 vk::DescriptorBindingFlags::PARTIALLY_BOUND,
217 ),
218 crate::ShaderBinding::Sampler => (
219 vk::DescriptorType::SAMPLER,
220 mem::size_of::<vk::DescriptorImageInfo>(),
221 1u32,
222 vk::DescriptorBindingFlags::empty(),
223 ),
224 crate::ShaderBinding::Buffer => (
225 vk::DescriptorType::STORAGE_BUFFER,
226 mem::size_of::<vk::DescriptorBufferInfo>(),
227 1u32,
228 vk::DescriptorBindingFlags::empty(),
229 ),
230 crate::ShaderBinding::BufferArray { count } => (
231 vk::DescriptorType::STORAGE_BUFFER,
232 mem::size_of::<vk::DescriptorBufferInfo>(),
233 count,
234 vk::DescriptorBindingFlags::PARTIALLY_BOUND,
235 ),
236 crate::ShaderBinding::AccelerationStructure => (
237 vk::DescriptorType::ACCELERATION_STRUCTURE_KHR,
238 mem::size_of::<vk::AccelerationStructureKHR>(),
239 1u32,
240 vk::DescriptorBindingFlags::empty(),
241 ),
242 crate::ShaderBinding::AccelerationStructureArray { count } => (
243 vk::DescriptorType::ACCELERATION_STRUCTURE_KHR,
244 mem::size_of::<vk::AccelerationStructureKHR>(),
245 count,
246 vk::DescriptorBindingFlags::PARTIALLY_BOUND,
247 ),
248 crate::ShaderBinding::Plain { size } => {
249 if size <= self.device.max_inline_uniform_block_size {
250 (
251 vk::DescriptorType::INLINE_UNIFORM_BLOCK_EXT,
252 1,
253 size,
254 vk::DescriptorBindingFlags::empty(),
255 )
256 } else {
257 (
258 vk::DescriptorType::UNIFORM_BUFFER,
259 mem::size_of::<vk::DescriptorBufferInfo>(),
260 1u32,
261 vk::DescriptorBindingFlags::empty(),
262 )
263 }
264 }
265 };
266 if descriptor_type == vk::DescriptorType::INLINE_UNIFORM_BLOCK_EXT {
267 assert_eq!(
268 descriptor_count % 4,
269 0,
270 "Inline uniform block binding {} size must be 4-byte aligned, got {}",
271 binding_index,
272 descriptor_count
273 );
274 inline_uniform_mask |= 1 << binding_index;
275 }
276
277 vk_bindings.push(vk::DescriptorSetLayoutBinding {
278 binding: binding_index as u32,
279 descriptor_type,
280 descriptor_count,
281 stage_flags,
282 ..Default::default()
283 });
284 template_entries.push(vk::DescriptorUpdateTemplateEntryKHR {
285 dst_binding: binding_index as u32,
286 dst_array_element: 0,
287 descriptor_count,
288 descriptor_type,
289 offset: update_offset,
290 stride: descriptor_size,
291 });
292 binding_flags.push(flag);
293 template_offsets.push(update_offset as u32);
294 update_offset += descriptor_size * descriptor_count as usize;
295 }
296
297 let mut binding_flags_info =
298 vk::DescriptorSetLayoutBindingFlagsCreateInfo::default().binding_flags(&binding_flags);
299 let set_layout_info = vk::DescriptorSetLayoutCreateInfo::default()
300 .bindings(&vk_bindings)
301 .push_next(&mut binding_flags_info);
302 let raw = unsafe {
303 self.device
304 .core
305 .create_descriptor_set_layout(&set_layout_info, None)
306 .unwrap()
307 };
308
309 let template_create_info = vk::DescriptorUpdateTemplateCreateInfo::default()
310 .descriptor_update_entries(&template_entries)
311 .template_type(vk::DescriptorUpdateTemplateTypeKHR::DESCRIPTOR_SET)
312 .descriptor_set_layout(raw);
313 let update_template = unsafe {
314 self.device
315 .core
316 .create_descriptor_update_template(&template_create_info, None)
317 .unwrap()
318 };
319
320 super::DescriptorSetLayout {
321 raw,
322 update_template,
323 template_size: update_offset as u32,
324 template_offsets: template_offsets.into_boxed_slice(),
325 inline_uniform_mask,
326 }
327 }
328
329 fn create_pipeline_layout(
330 &self,
331 group_layouts: &[&crate::ShaderDataLayout],
332 group_infos: &[crate::ShaderDataInfo],
333 ) -> super::PipelineLayout {
334 let mut descriptor_set_layouts = Vec::with_capacity(group_layouts.len());
335 let mut vk_set_layouts = Vec::with_capacity(group_layouts.len());
336 for (&layout, info) in group_layouts.iter().zip(group_infos) {
337 let dsl = self.create_descriptor_set_layout(layout, info);
338 vk_set_layouts.push(dsl.raw);
339 descriptor_set_layouts.push(dsl);
340 }
341
342 let vk_info = vk::PipelineLayoutCreateInfo::default().set_layouts(&vk_set_layouts);
343 let raw = unsafe {
344 self.device
345 .core
346 .create_pipeline_layout(&vk_info, None)
347 .unwrap()
348 };
349
350 super::PipelineLayout {
351 raw,
352 descriptor_set_layouts,
353 }
354 }
355
356 fn destroy_pipeline_layout(&self, layout: &mut super::PipelineLayout) {
357 unsafe {
358 self.device
359 .core
360 .destroy_pipeline_layout(mem::take(&mut layout.raw), None);
361 }
362 for dsl in layout.descriptor_set_layouts.drain(..) {
363 unsafe {
364 self.device
365 .core
366 .destroy_descriptor_set_layout(dsl.raw, None);
367 }
368 if !dsl.is_empty() {
369 unsafe {
370 self.device
371 .core
372 .destroy_descriptor_update_template(dsl.update_template, None);
373 }
374 }
375 }
376 }
377}
378
379#[hidden_trait::expose]
380impl crate::traits::ShaderDevice for super::Context {
381 type ComputePipeline = super::ComputePipeline;
382 type RenderPipeline = super::RenderPipeline;
383
384 fn create_compute_pipeline(&self, desc: crate::ComputePipelineDesc) -> super::ComputePipeline {
385 let mut group_infos = desc
386 .data_layouts
387 .iter()
388 .map(|layout| layout.to_info())
389 .collect::<Vec<_>>();
390
391 let options = self.make_spv_options(desc.data_layouts);
392 let cs = self.load_shader(
393 desc.compute,
394 &options,
395 desc.data_layouts,
396 &mut group_infos,
397 &[],
398 );
399
400 let layout = self.create_pipeline_layout(desc.data_layouts, &group_infos);
401
402 let create_info = vk::ComputePipelineCreateInfo::default()
403 .layout(layout.raw)
404 .stage(cs.create_info);
405
406 let mut raw_vec = unsafe {
407 self.device
408 .core
409 .create_compute_pipelines(vk::PipelineCache::null(), &[create_info], None)
410 .unwrap_or_else(|(_, err)| {
411 panic!("Failed to create compute pipeline '{}': {err:?}", desc.name)
412 })
413 };
414 let raw = raw_vec.pop().unwrap();
415
416 unsafe { self.device.core.destroy_shader_module(cs.vk_module, None) };
417
418 if let Some(ref ext) = self.device.shader_info
419 && let Ok(statistics) =
420 unsafe { ext.get_shader_info_statistics(raw, vk::ShaderStageFlags::COMPUTE) }
421 {
422 let ru = &statistics.resource_usage;
423 log::info!(
424 "Compute pipeline '{}' uses: {} VGPRs, {} SGPRs",
425 desc.name,
426 ru.num_used_vgprs,
427 ru.num_used_sgprs,
428 );
429 }
430
431 if !desc.name.is_empty() {
432 self.set_object_name(raw, desc.name);
433 }
434 super::ComputePipeline {
435 raw,
436 layout,
437 wg_size: cs.wg_size,
438 }
439 }
440
441 fn destroy_compute_pipeline(&self, pipeline: &mut super::ComputePipeline) {
442 self.destroy_pipeline_layout(&mut pipeline.layout);
443 unsafe {
444 self.device.core.destroy_pipeline(pipeline.raw, None);
445 }
446 }
447
448 fn create_render_pipeline(&self, desc: crate::RenderPipelineDesc) -> super::RenderPipeline {
449 let mut group_infos = desc
450 .data_layouts
451 .iter()
452 .map(|layout| layout.to_info())
453 .collect::<Vec<_>>();
454
455 let options = self.make_spv_options(desc.data_layouts);
456 let vs = self.load_shader(
457 desc.vertex,
458 &options,
459 desc.data_layouts,
460 &mut group_infos,
461 desc.vertex_fetches,
462 );
463 let fs = desc.fragment.map(|desc_fragment| {
464 self.load_shader(
465 desc_fragment,
466 &options,
467 desc.data_layouts,
468 &mut group_infos,
469 &[],
470 )
471 });
472
473 let mut stages = [vs.create_info, vk::PipelineShaderStageCreateInfo::default()];
474 let mut stage_count = 1;
475 if let Some(ref fs) = fs {
476 stages[1] = fs.create_info;
477 stage_count += 1;
478 }
479 let stages = &stages[..stage_count]; let layout = self.create_pipeline_layout(desc.data_layouts, &group_infos);
482
483 let vertex_buffers = desc
484 .vertex_fetches
485 .iter()
486 .enumerate()
487 .map(|(i, vf)| vk::VertexInputBindingDescription {
488 binding: i as u32,
489 stride: vf.layout.stride,
490 input_rate: if vf.instanced {
491 vk::VertexInputRate::INSTANCE
492 } else {
493 vk::VertexInputRate::VERTEX
494 },
495 })
496 .collect::<Vec<_>>();
497 let vertex_attributes = vs
498 .attribute_mappings
499 .into_iter()
500 .enumerate()
501 .map(|(index, mapping)| {
502 let (_, ref at) = desc.vertex_fetches[mapping.buffer_index].layout.attributes
503 [mapping.attribute_index];
504 vk::VertexInputAttributeDescription {
505 location: index as u32,
506 binding: mapping.buffer_index as u32,
507 format: super::map_vertex_format(at.format),
508 offset: at.offset,
509 }
510 })
511 .collect::<Vec<_>>();
512
513 let vk_vertex_input = vk::PipelineVertexInputStateCreateInfo::default()
514 .vertex_binding_descriptions(&vertex_buffers)
515 .vertex_attribute_descriptions(&vertex_attributes);
516 let (raw_topology, supports_restart) = map_primitive_topology(desc.primitive.topology);
517 let vk_input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
518 .topology(raw_topology)
519 .primitive_restart_enable(supports_restart);
520
521 let mut vk_rasterization = vk::PipelineRasterizationStateCreateInfo::default()
522 .polygon_mode(if desc.primitive.wireframe {
523 vk::PolygonMode::LINE
524 } else {
525 vk::PolygonMode::FILL
526 })
527 .front_face(map_front_face(desc.primitive.front_face))
528 .line_width(1.0);
529 if let Some(face) = desc.primitive.cull_mode {
530 vk_rasterization = vk_rasterization.cull_mode(map_cull_face(face));
531 }
532
533 let mut vk_depth_clip_state =
534 vk::PipelineRasterizationDepthClipStateCreateInfoEXT::default()
535 .depth_clip_enable(false);
536 if desc.primitive.unclipped_depth {
537 vk_rasterization = vk_rasterization.push_next(&mut vk_depth_clip_state);
538 }
539
540 let dynamic_states = [
541 vk::DynamicState::VIEWPORT,
542 vk::DynamicState::SCISSOR,
543 vk::DynamicState::BLEND_CONSTANTS,
544 vk::DynamicState::STENCIL_REFERENCE,
545 ];
546 let vk_dynamic_state =
547 vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
548
549 let vk_viewport = vk::PipelineViewportStateCreateInfo::default()
550 .flags(vk::PipelineViewportStateCreateFlags::empty())
551 .scissor_count(1)
552 .viewport_count(1);
553
554 let vk_sample_mask = [
555 desc.multisample_state.sample_mask as u32,
556 (desc.multisample_state.sample_mask >> 32) as u32,
557 ];
558
559 let vk_multisample = vk::PipelineMultisampleStateCreateInfo::default()
560 .rasterization_samples(vk::SampleCountFlags::from_raw(
561 desc.multisample_state.sample_count,
562 ))
563 .alpha_to_coverage_enable(desc.multisample_state.alpha_to_coverage)
564 .sample_mask(&vk_sample_mask);
565
566 let mut d_format = vk::Format::UNDEFINED;
567 let mut s_format = vk::Format::UNDEFINED;
568 let mut vk_depth_stencil = vk::PipelineDepthStencilStateCreateInfo::default();
569 if let Some(ref ds) = desc.depth_stencil {
570 let ds_format = super::map_texture_format(ds.format);
571 if ds.format.aspects().contains(crate::TexelAspects::DEPTH) {
572 d_format = ds_format;
573 }
574 if ds.format.aspects().contains(crate::TexelAspects::STENCIL) {
575 s_format = ds_format;
576 }
577
578 if ds.depth_write_enabled || ds.depth_compare != crate::CompareFunction::Always {
579 vk_depth_stencil = vk_depth_stencil
580 .depth_test_enable(true)
581 .depth_write_enable(ds.depth_write_enabled)
582 .depth_compare_op(map_comparison(ds.depth_compare));
583 }
584 if ds.stencil != crate::StencilState::default() {
585 let s = &ds.stencil;
586 let front = map_stencil_face_state(&s.front, s.read_mask, s.write_mask);
587 let back = map_stencil_face_state(&s.back, s.read_mask, s.write_mask);
588 vk_depth_stencil = vk_depth_stencil
589 .stencil_test_enable(true)
590 .front(front)
591 .back(back);
592 }
593
594 if ds.bias != crate::DepthBiasState::default() {
595 vk_rasterization = vk_rasterization
596 .depth_bias_enable(true)
597 .depth_bias_constant_factor(ds.bias.constant as f32)
598 .depth_bias_clamp(ds.bias.clamp)
599 .depth_bias_slope_factor(ds.bias.slope_scale);
600 }
601 }
602
603 let mut color_formats = Vec::with_capacity(desc.color_targets.len());
604 let mut vk_attachments = Vec::with_capacity(desc.color_targets.len());
605 for ct in desc.color_targets {
606 let mut vk_attachment = vk::PipelineColorBlendAttachmentState::default()
607 .color_write_mask(vk::ColorComponentFlags::from_raw(ct.write_mask.bits()));
608 if let Some(ref blend) = ct.blend {
609 assert!(
610 !blend.uses_dual_source() || self.dual_source_blending,
611 "Dual-source blending is not supported by this Vulkan device"
612 );
613
614 let (color_op, color_src, color_dst) = map_blend_component(&blend.color);
615 let (alpha_op, alpha_src, alpha_dst) = map_blend_component(&blend.alpha);
616 vk_attachment = vk_attachment
617 .blend_enable(true)
618 .color_blend_op(color_op)
619 .src_color_blend_factor(color_src)
620 .dst_color_blend_factor(color_dst)
621 .alpha_blend_op(alpha_op)
622 .src_alpha_blend_factor(alpha_src)
623 .dst_alpha_blend_factor(alpha_dst);
624 }
625
626 color_formats.push(super::map_texture_format(ct.format));
627 vk_attachments.push(vk_attachment);
628 }
629 let vk_color_blend =
630 vk::PipelineColorBlendStateCreateInfo::default().attachments(&vk_attachments);
631
632 let mut rendering_info = vk::PipelineRenderingCreateInfo::default()
633 .color_attachment_formats(&color_formats)
634 .depth_attachment_format(d_format)
635 .stencil_attachment_format(s_format);
636
637 let create_info = vk::GraphicsPipelineCreateInfo::default()
638 .layout(layout.raw)
639 .stages(stages)
640 .vertex_input_state(&vk_vertex_input)
641 .input_assembly_state(&vk_input_assembly)
642 .rasterization_state(&vk_rasterization)
643 .viewport_state(&vk_viewport)
644 .multisample_state(&vk_multisample)
645 .depth_stencil_state(&vk_depth_stencil)
646 .color_blend_state(&vk_color_blend)
647 .dynamic_state(&vk_dynamic_state)
648 .push_next(&mut rendering_info);
649
650 let mut raw_vec = unsafe {
651 self.device
652 .core
653 .create_graphics_pipelines(vk::PipelineCache::null(), &[create_info], None)
654 .unwrap_or_else(|(_, err)| {
655 panic!("Failed to create render pipeline '{}': {err:?}", desc.name)
656 })
657 };
658 let raw = raw_vec.pop().unwrap();
659
660 unsafe { self.device.core.destroy_shader_module(vs.vk_module, None) };
661 if let Some(fs) = fs {
662 unsafe { self.device.core.destroy_shader_module(fs.vk_module, None) };
663 }
664
665 if !desc.name.is_empty() {
666 self.set_object_name(raw, desc.name);
667 }
668 super::RenderPipeline { raw, layout }
669 }
670
671 fn destroy_render_pipeline(&self, pipeline: &mut super::RenderPipeline) {
672 self.destroy_pipeline_layout(&mut pipeline.layout);
673 unsafe {
674 self.device.core.destroy_pipeline(pipeline.raw, None);
675 }
676 }
677}
678
679fn map_shader_visibility(visibility: crate::ShaderVisibility) -> vk::ShaderStageFlags {
680 use crate::ShaderVisibility as Sv;
681 use vk::ShaderStageFlags as Flags;
682
683 let mut flags = Flags::empty();
684 if visibility.contains(Sv::COMPUTE) {
685 flags |= Flags::COMPUTE;
686 }
687 if visibility.contains(Sv::VERTEX) {
688 flags |= Flags::VERTEX;
689 }
690 if visibility.contains(Sv::FRAGMENT) {
691 flags |= Flags::FRAGMENT;
692 }
693
694 flags
695}
696
697fn map_primitive_topology(topology: crate::PrimitiveTopology) -> (vk::PrimitiveTopology, bool) {
698 use crate::PrimitiveTopology as Pt;
699 match topology {
700 Pt::PointList => (vk::PrimitiveTopology::POINT_LIST, false),
701 Pt::LineList => (vk::PrimitiveTopology::LINE_LIST, false),
702 Pt::LineStrip => (vk::PrimitiveTopology::LINE_STRIP, true),
703 Pt::TriangleList => (vk::PrimitiveTopology::TRIANGLE_LIST, false),
704 Pt::TriangleStrip => (vk::PrimitiveTopology::TRIANGLE_STRIP, true),
705 }
706}
707
708fn map_front_face(front_face: crate::FrontFace) -> vk::FrontFace {
709 match front_face {
710 crate::FrontFace::Cw => vk::FrontFace::CLOCKWISE,
711 crate::FrontFace::Ccw => vk::FrontFace::COUNTER_CLOCKWISE,
712 }
713}
714
715fn map_cull_face(face: crate::Face) -> vk::CullModeFlags {
716 match face {
717 crate::Face::Front => vk::CullModeFlags::FRONT,
718 crate::Face::Back => vk::CullModeFlags::BACK,
719 }
720}
721
722fn map_comparison(fun: crate::CompareFunction) -> vk::CompareOp {
723 use crate::CompareFunction as Cf;
724 match fun {
725 Cf::Never => vk::CompareOp::NEVER,
726 Cf::Less => vk::CompareOp::LESS,
727 Cf::LessEqual => vk::CompareOp::LESS_OR_EQUAL,
728 Cf::Equal => vk::CompareOp::EQUAL,
729 Cf::GreaterEqual => vk::CompareOp::GREATER_OR_EQUAL,
730 Cf::Greater => vk::CompareOp::GREATER,
731 Cf::NotEqual => vk::CompareOp::NOT_EQUAL,
732 Cf::Always => vk::CompareOp::ALWAYS,
733 }
734}
735
736fn map_stencil_op(op: crate::StencilOperation) -> vk::StencilOp {
737 use crate::StencilOperation as So;
738 match op {
739 So::Keep => vk::StencilOp::KEEP,
740 So::Zero => vk::StencilOp::ZERO,
741 So::Replace => vk::StencilOp::REPLACE,
742 So::Invert => vk::StencilOp::INVERT,
743 So::IncrementClamp => vk::StencilOp::INCREMENT_AND_CLAMP,
744 So::IncrementWrap => vk::StencilOp::INCREMENT_AND_WRAP,
745 So::DecrementClamp => vk::StencilOp::DECREMENT_AND_CLAMP,
746 So::DecrementWrap => vk::StencilOp::DECREMENT_AND_WRAP,
747 }
748}
749
750fn map_stencil_face_state(
751 face: &crate::StencilFaceState,
752 compare_mask: u32,
753 write_mask: u32,
754) -> vk::StencilOpState {
755 vk::StencilOpState {
756 fail_op: map_stencil_op(face.fail_op),
757 pass_op: map_stencil_op(face.pass_op),
758 depth_fail_op: map_stencil_op(face.depth_fail_op),
759 compare_op: map_comparison(face.compare),
760 compare_mask,
761 write_mask,
762 reference: 0,
763 }
764}
765
766fn map_blend_factor(factor: crate::BlendFactor) -> vk::BlendFactor {
767 use crate::BlendFactor as Bf;
768 match factor {
769 Bf::Zero => vk::BlendFactor::ZERO,
770 Bf::One => vk::BlendFactor::ONE,
771 Bf::Src => vk::BlendFactor::SRC_COLOR,
772 Bf::OneMinusSrc => vk::BlendFactor::ONE_MINUS_SRC_COLOR,
773 Bf::SrcAlpha => vk::BlendFactor::SRC_ALPHA,
774 Bf::OneMinusSrcAlpha => vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
775 Bf::Dst => vk::BlendFactor::DST_COLOR,
776 Bf::OneMinusDst => vk::BlendFactor::ONE_MINUS_DST_COLOR,
777 Bf::DstAlpha => vk::BlendFactor::DST_ALPHA,
778 Bf::OneMinusDstAlpha => vk::BlendFactor::ONE_MINUS_DST_ALPHA,
779 Bf::SrcAlphaSaturated => vk::BlendFactor::SRC_ALPHA_SATURATE,
780 Bf::Constant => vk::BlendFactor::CONSTANT_COLOR,
781 Bf::OneMinusConstant => vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR,
782 Bf::Src1 => vk::BlendFactor::SRC1_COLOR,
783 Bf::OneMinusSrc1 => vk::BlendFactor::ONE_MINUS_SRC1_COLOR,
784 Bf::Src1Alpha => vk::BlendFactor::SRC1_ALPHA,
785 Bf::OneMinusSrc1Alpha => vk::BlendFactor::ONE_MINUS_SRC1_ALPHA,
786 }
787}
788
789fn map_blend_op(operation: crate::BlendOperation) -> vk::BlendOp {
790 use crate::BlendOperation as Bo;
791 match operation {
792 Bo::Add => vk::BlendOp::ADD,
793 Bo::Subtract => vk::BlendOp::SUBTRACT,
794 Bo::ReverseSubtract => vk::BlendOp::REVERSE_SUBTRACT,
795 Bo::Min => vk::BlendOp::MIN,
796 Bo::Max => vk::BlendOp::MAX,
797 }
798}
799
800fn map_blend_component(
801 component: &crate::BlendComponent,
802) -> (vk::BlendOp, vk::BlendFactor, vk::BlendFactor) {
803 let op = map_blend_op(component.operation);
804 let src = map_blend_factor(component.src_factor);
805 let dst = map_blend_factor(component.dst_factor);
806 (op, src, dst)
807}