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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
use super::daemon::AssetDaemonOpt;
use super::{daemon, Renderer};
use super::{RenderFeaturePlugin, RenderGraphGenerator};
use crate::renderer_thread_pool_none::RendererThreadPoolNone;
use crate::{RendererAssetPlugin, RendererThreadPool};
use fnv::FnvHashSet;
use rafx_api::{RafxApi, RafxQueueType, RafxResult};
use rafx_assets::distill_impl::AssetResource;
use rafx_assets::{AssetManager, UploadQueueConfig};
use rafx_framework::render_features::{ExtractResources, RenderRegistryBuilder};
use std::sync::Arc;

pub enum AssetSource {
    Packfile(std::path::PathBuf),
    Daemon {
        external_daemon: bool,
        daemon_args: AssetDaemonOpt,
    },
}

pub struct RendererBuilderResult {
    pub asset_resource: AssetResource,
    pub asset_manager: AssetManager,
    pub renderer: Renderer,
}

pub struct RendererBuilder {
    feature_plugins: Vec<Arc<dyn RenderFeaturePlugin>>,
    asset_plugins: Vec<Arc<dyn RendererAssetPlugin>>,
    allow_use_render_thread: bool,
}

impl Default for RendererBuilder {
    fn default() -> Self {
        RendererBuilder {
            feature_plugins: Default::default(),
            asset_plugins: Default::default(),
            allow_use_render_thread: true,
        }
    }
}

impl RendererBuilder {
    pub fn add_render_feature(
        mut self,
        plugin: Arc<dyn RenderFeaturePlugin>,
    ) -> Self {
        self.feature_plugins.push(plugin);
        self
    }

    pub fn add_asset(
        mut self,
        plugin: Arc<dyn RendererAssetPlugin>,
    ) -> Self {
        self.asset_plugins.push(plugin);
        self
    }

    pub fn allow_use_render_thread(
        mut self,
        allow_use_render_thread: bool,
    ) -> Self {
        self.allow_use_render_thread = allow_use_render_thread;
        self
    }

    pub fn build(
        self,
        extract_resources: ExtractResources,
        rafx_api: &RafxApi,
        asset_source: AssetSource,
        render_graph_generator: Box<dyn RenderGraphGenerator>,
        renderer_thread_pool: fn() -> Option<Box<dyn RendererThreadPool>>, // TODO(dvd): Change to threading type enum with options None, RenderThread, or ThreadPool.
    ) -> RafxResult<RendererBuilderResult> {
        let mut asset_resource = match asset_source {
            AssetSource::Packfile(packfile) => {
                log::info!("Reading from packfile {:?}", packfile);

                // Initialize the packfile loader with the packfile path
                daemon::init_distill_packfile(&packfile)
            }
            AssetSource::Daemon {
                external_daemon,
                daemon_args,
            } => {
                if !external_daemon {
                    log::info!("Hosting local daemon at {:?}", daemon_args.address);

                    let mut asset_dirs = FnvHashSet::default();
                    for path in daemon_args.asset_dirs {
                        log::info!("Added asset path {:?}", path);
                        asset_dirs.insert(path);
                    }

                    for plugin in &self.asset_plugins {
                        let mut paths = Default::default();
                        plugin.add_asset_paths(&mut paths);
                        for path in paths {
                            log::info!(
                                "Added asset path {:?} from asset plugin {}",
                                path,
                                plugin.plugin_name()
                            );
                            asset_dirs.insert(path);
                        }
                    }

                    for plugin in &self.feature_plugins {
                        let mut paths = Default::default();
                        plugin.add_asset_paths(&mut paths);
                        for path in paths {
                            log::info!(
                                "Added asset path {:?} from feature plugin {:?}",
                                path,
                                plugin.feature_debug_constants().feature_name
                            );
                            asset_dirs.insert(path);
                        }
                    }

                    let mut asset_daemon = rafx_assets::distill_impl::default_daemon()
                        .with_db_path(daemon_args.db_dir)
                        .with_address(daemon_args.address)
                        .with_asset_dirs(asset_dirs.into_iter().collect());

                    for plugin in &self.asset_plugins {
                        asset_daemon = plugin.configure_asset_daemon(asset_daemon);
                    }

                    // Spawn the daemon in a background thread.
                    std::thread::spawn(move || {
                        asset_daemon.run();
                    });
                } else {
                    log::info!("Connecting to daemon at {:?}", daemon_args.address);
                }

                // Connect to the daemon we just launched
                daemon::init_distill_daemon(daemon_args.address.to_string())
            }
        };

        let mut render_registry_builder = RenderRegistryBuilder::default();
        for plugin in &self.feature_plugins {
            render_registry_builder = plugin.configure_render_registry(render_registry_builder);
        }
        for plugin in &self.asset_plugins {
            render_registry_builder = plugin.configure_render_registry(render_registry_builder);
        }

        let render_registry = render_registry_builder.build();

        let device_context = rafx_api.device_context();

        let graphics_queue = device_context.create_queue(RafxQueueType::Graphics)?;
        let transfer_queue = device_context.create_queue(RafxQueueType::Transfer)?;

        let mut asset_manager = AssetManager::new(
            &device_context,
            &render_registry,
            UploadQueueConfig {
                max_concurrent_uploads: 4,
                max_new_uploads_in_single_frame: 4,
                max_bytes_per_upload: 64 * 1024 * 1024,
            },
            &graphics_queue,
            &transfer_queue,
        );

        asset_manager.register_default_asset_types(&mut asset_resource);

        for plugin in &self.asset_plugins {
            plugin.register_asset_types(&mut asset_manager, &mut asset_resource);
        }

        let renderer = Renderer::new(
            extract_resources,
            &mut asset_resource,
            &mut asset_manager,
            &graphics_queue,
            &transfer_queue,
            self.feature_plugins,
            self.asset_plugins,
            render_graph_generator,
            renderer_thread_pool()
                .or_else(|| Some(Box::new(RendererThreadPoolNone::new())))
                .unwrap(),
            self.allow_use_render_thread,
        );

        match renderer {
            Ok(renderer) => Ok(RendererBuilderResult {
                asset_resource,
                asset_manager,
                renderer,
            }),
            Err(e) => {
                std::mem::drop(asset_resource);
                std::mem::drop(asset_manager);
                Err(e)
            }
        }
    }
}