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
use crate::{AssetManager, DefaultAssetTypeHandler, DefaultAssetTypeLoadHandler};
use fnv::FnvHashMap;
use hydrate_base::LoadHandle;
use rafx_api::{
    RafxApiType, RafxHashedShaderPackage, RafxReflectedEntryPoint, RafxResult, RafxShaderPackage,
    RAFX_VALID_API_TYPES,
};
use rafx_framework::{ResourceArc, ShaderModuleResource};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use type_uuid::*;

#[derive(TypeUuid, Serialize, Deserialize, Debug, Clone, PartialEq)]
#[uuid = "e0ae2222-1a44-4022-af95-03c9101ac89e"]
pub struct ShaderAssetData {
    pub shader_package: RafxHashedShaderPackage,
}

//
// The "loaded" state of assets. Assets may have dependencies. Arcs to those dependencies ensure
// they do not get destroyed. All of the raw resources are hashed to avoid duplicating anything that
// is functionally identical. So for example if you have two windows with identical swapchain
// surfaces, they could share the same renderpass/pipeline resources
//
#[derive(TypeUuid, Clone)]
#[uuid = "b6958faa-5769-4048-a507-f91a07f49af4"]
pub struct ShaderAsset {
    pub shader_module: ResourceArc<ShaderModuleResource>,
    // Indexed by RafxApiType
    pub reflection_data: Arc<Vec<FnvHashMap<String, RafxReflectedEntryPoint>>>,
}

impl ShaderAsset {
    pub fn find_reflection_data(
        &self,
        entry_point_name: &str,
        api_type: RafxApiType,
    ) -> Option<&RafxReflectedEntryPoint> {
        self.reflection_data[api_type as usize].get(entry_point_name)
    }
}

pub struct ShaderLoadHandler;

// we get a warning from this when building without any backends, which occurs when recompiling
// shaders and regenerating corresponding rust code
#[allow(dead_code)]
fn build_reflection_data_map(
    reflection_data_lookup: &mut Vec<FnvHashMap<String, RafxReflectedEntryPoint>>,
    shader_package: &RafxShaderPackage,
    api_type: RafxApiType,
) {
    if let Some(reflection_data) = shader_package.reflection(api_type) {
        for entry_point in reflection_data {
            let old = reflection_data_lookup[api_type as usize].insert(
                entry_point.rafx_api_reflection.entry_point_name.clone(),
                entry_point.clone(),
            );
            assert!(old.is_none());
        }
    }
}

impl DefaultAssetTypeLoadHandler<ShaderAssetData, ShaderAsset> for ShaderLoadHandler {
    #[profiling::function]
    fn load(
        asset_manager: &mut AssetManager,
        asset_data: ShaderAssetData,
        _load_handle: LoadHandle,
    ) -> RafxResult<ShaderAsset> {
        let mut reflection_data_lookup = Vec::with_capacity(RAFX_VALID_API_TYPES.len());
        reflection_data_lookup.resize_with(RAFX_VALID_API_TYPES.len(), Default::default);

        #[cfg(feature = "rafx-vulkan")]
        build_reflection_data_map(
            &mut reflection_data_lookup,
            asset_data.shader_package.shader_package(),
            RafxApiType::Vk,
        );
        #[cfg(feature = "rafx-dx12")]
        build_reflection_data_map(
            &mut reflection_data_lookup,
            asset_data.shader_package.shader_package(),
            RafxApiType::Dx12,
        );
        #[cfg(feature = "rafx-metal")]
        build_reflection_data_map(
            &mut reflection_data_lookup,
            asset_data.shader_package.shader_package(),
            RafxApiType::Metal,
        );
        #[cfg(feature = "rafx-gles2")]
        build_reflection_data_map(
            &mut reflection_data_lookup,
            asset_data.shader_package.shader_package(),
            RafxApiType::Gles2,
        );
        #[cfg(feature = "rafx-gles3")]
        build_reflection_data_map(
            &mut reflection_data_lookup,
            asset_data.shader_package.shader_package(),
            RafxApiType::Gles3,
        );

        let shader_module = asset_manager
            .resources()
            .get_or_create_shader_module_from_hashed_package(&asset_data.shader_package)?;

        Ok(ShaderAsset {
            shader_module,
            reflection_data: Arc::new(reflection_data_lookup),
        })
    }
}

pub type ShaderAssetTypeHandler =
    DefaultAssetTypeHandler<ShaderAssetData, ShaderAsset, ShaderLoadHandler>;