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