      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123

    use std::collections::HashSet;
    use std::path::PathBuf;
    use vulkano::pipeline::GraphicsPipelineAbstract;
    use vulkano::framebuffer::RenderPassAbstract;
    use std::sync::Arc;
    use vulkano::pipeline::shader::{ShaderModule, GraphicsShaderType, GeometryShaderExecutionMode};
    use vulkano::device::Device;
    use shade_runner::Entry;
    use shaderc::ShaderKind;
    use crate::canvas::CompiledGraphicsPipelineHandle;

    /*

    Realistically, what should the API for this thing look like...

    It's going to just generate a pipeline. But that consists of loading and compiling various shaders,
        and generating a pipeline for those shaders and other customer behaviour.

    This best works I think if I allow users to
        A.) impl from a base trait which allows resource lookup
        B.) Generate 1 of each of the types of shaders
        C.) Modify specilization constants, whatever that might mean
        D.) impl from a base trait which defines it's interface

    */

    /// Inheriting this gives private functions to grab resources
    pub(super) trait CompiledGraphicsPipelineResources {

        fn get_path(filename: String, shader_type: ShaderType) -> PathBuf {
            let project_root =
                std::env::current_dir()
                    .expect("failed to get root directory");

            let mut shader_path = project_root.clone();
            shader_path.push(PathBuf::from("resources/shaders/"));

            let mut shader_path = shader_path.clone();

            match shader_type {
                ShaderType::VERTEX => {
                    shader_path.push(PathBuf::from(filename.clone() + ".vert"));
                }
                ShaderType::FRAGMENT => {
                    shader_path.push(PathBuf::from(filename.clone() + ".frag"));
                }
                ShaderType::GEOMETRY => {
                    shader_path.push(PathBuf::from(filename.clone() + ".geom"));
                }
                ShaderType::TESSELLATION_CONTROL => {
                    shader_path.push(PathBuf::from(filename.clone() + ".tesscont"));
                }
                ShaderType::TESSELLATION_EVALUATION => {
                    shader_path.push(PathBuf::from(filename.clone() + ".tesseval"));
                }
            }

            shader_path
        }

        fn compile(filepath: PathBuf, device: Arc<Device>, shader_type: ShaderType) -> (Entry, Arc<ShaderModule>) {
            let compiled_shader = shade_runner::load(filepath, Self::convert_sr(shader_type))
                .expect("Shader didn't compile");

            let vulkano_entry =
                shade_runner::parse(&compiled_shader)
                    .expect("failed to parse");

            (vulkano_entry, unsafe {
                ShaderModule::from_words(device.clone(), &compiled_shader.spriv.clone())
            }.unwrap())
        }

        fn convert_vk(shader_type: ShaderType) -> GraphicsShaderType {
            match shader_type {
                ShaderType::VERTEX => { GraphicsShaderType::Vertex }
                ShaderType::FRAGMENT => { GraphicsShaderType::Fragment }
                ShaderType::GEOMETRY => { GraphicsShaderType::Geometry(GeometryShaderExecutionMode::Triangles) }
                ShaderType::TESSELLATION_CONTROL => { GraphicsShaderType::TessellationControl }
                ShaderType::TESSELLATION_EVALUATION => { GraphicsShaderType::TessellationEvaluation }
            }
        }

        fn convert_sr(shader_type: ShaderType) -> ShaderKind {
            match shader_type {
                ShaderType::VERTEX => { ShaderKind::Vertex }
                ShaderType::FRAGMENT => { ShaderKind::Fragment }
                ShaderType::GEOMETRY => { ShaderKind::Geometry }
                ShaderType::TESSELLATION_CONTROL => { ShaderKind::TessControl }
                ShaderType::TESSELLATION_EVALUATION => { ShaderKind::TessEvaluation }
            }
        }
    }

    pub trait CompiledGraphicsPipeline {
        fn new(filename: String,
               device: Arc<Device>,
               handle: Arc<CompiledGraphicsPipelineHandle>,
               render_pass: Arc<dyn RenderPassAbstract + Send + Sync>) -> Self where Self: Sized;
        fn get_name(&self) -> String;
        fn get_handle(&self) -> Arc<CompiledGraphicsPipelineHandle>;
        fn get_pipeline(&self) -> Arc<dyn GraphicsPipelineAbstract + Sync + Send>;
        fn get_renderpass(&self) -> Arc<dyn RenderPassAbstract + Send + Sync>;
        fn recompile(self, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>)
                     -> Self where Self: Sized;
    }

    /// Legacy ShaderType enum for single type shaders.
    #[derive(PartialEq, Eq, Hash, Clone)]
    pub enum ShaderType {
        VERTEX = 0,
        FRAGMENT = 1,
        GEOMETRY = 2,
        TESSELLATION_CONTROL = 3,
        TESSELLATION_EVALUATION = 4,
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g., `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g., `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g., `str,u8` or `String,struct:Vec,test`)