rendy_factory/
config.rs

1use std::cmp::min;
2
3use crate::{
4    command::FamilyId,
5    core::DeviceId,
6    memory::{DynamicConfig, HeapsConfig, LinearConfig},
7};
8
9/// Factory initialization config.
10///
11/// `devices` - [`DeviceConfigure`] implementation instance to pick physical device.
12/// [`BasicDevicesConfigure`] can be used as sane default.
13/// `heaps` - [`HeapsConfigure`] implementation instance to cofigure memory allocators.
14/// [`BasicHeapsConfigure`] can be used as sane default.
15/// `queues` - [`QueuesConfigure`] implementation to configure device queues creation.
16/// [`OneGraphicsQueue`] can be used if only one graphics queue will satisfy requirements.
17///
18/// [`DeviceConfigure`]: trait.DevicesConfigure.html
19/// [`BasicDevicesConfigure`]: struct.BasicDevicesConfigure.html
20/// [`HeapsConfigure`]: trait.HeapsConfigure.html
21/// [`BasicHeapsConfigure`]: struct.BasicHeapsConfigure.html
22/// [`QueuesConfigure`]: trait.QueuesConfigure.html
23/// [`OneGraphicsQueue`]: struct.OneGraphicsQueue.html
24#[derive(Clone, Debug, Default)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct Config<D = BasicDevicesConfigure, H = BasicHeapsConfigure, Q = OneGraphicsQueue> {
27    /// Config to choose adapter.
28    pub devices: D,
29
30    /// Config for memory::Heaps.
31    pub heaps: H,
32
33    /// Config for queue families.
34    pub queues: Q,
35}
36
37/// Queues configuration.
38///
39/// Method [`configure`] receives collection of queue families and
40/// returns an iterator over family ids and number of queues.
41///
42/// [`configure`]: trait.QueuesConfigure.html#tymethod.configure
43pub unsafe trait QueuesConfigure {
44    /// Slice of priorities.
45    type Priorities: AsRef<[f32]>;
46
47    /// Iterator over families to create.
48    type Families: IntoIterator<Item = (FamilyId, Self::Priorities)>;
49
50    /// Configure.
51    fn configure(
52        &self,
53        device: DeviceId,
54        families: &[impl rendy_core::hal::queue::QueueFamily],
55    ) -> Self::Families;
56}
57
58/// QueuePicker that picks first graphics queue family.
59///
60/// TODO: Try to pick family that is capable of presenting
61/// This is possible in platform-dependent way for some platforms.
62///
63/// To pick multiple families with require number of queues
64/// a custom [`QueuesConfigure`] implementation can be used instead.
65///
66/// [`QueuesConfigure`]: trait.QueuesConfigure.html
67#[derive(Clone, Copy, Debug, Default)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69pub struct OneGraphicsQueue;
70
71unsafe impl QueuesConfigure for OneGraphicsQueue {
72    type Priorities = [f32; 1];
73    type Families = Option<(FamilyId, [f32; 1])>;
74    fn configure(
75        &self,
76        device: DeviceId,
77        families: &[impl rendy_core::hal::queue::QueueFamily],
78    ) -> Option<(FamilyId, [f32; 1])> {
79        families
80            .iter()
81            .find(|f| f.queue_type().supports_graphics() && f.max_queues() > 0)
82            .map(|f| {
83                (
84                    FamilyId {
85                        device,
86                        index: f.id().0,
87                    },
88                    [1.0],
89                )
90            })
91    }
92}
93
94/// Saved config for queues.
95/// This config can be loaded from config files
96/// in any format supported by serde ecosystem.
97#[derive(Clone, Debug)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99pub struct SavedQueueConfig(Vec<(usize, Vec<f32>)>);
100
101unsafe impl QueuesConfigure for SavedQueueConfig {
102    type Priorities = Vec<f32>;
103    type Families = Vec<(FamilyId, Vec<f32>)>;
104    fn configure(
105        &self,
106        device: DeviceId,
107        _: &[impl rendy_core::hal::queue::QueueFamily],
108    ) -> Vec<(FamilyId, Vec<f32>)> {
109        // TODO: FamilyId should be stored directly once it become serializable.
110        self.0
111            .iter()
112            .map(|(id, vec)| (FamilyId { device, index: *id }, vec.clone()))
113            .collect()
114    }
115}
116
117/// Heaps configuration.
118///
119/// Method [`configure`] receives memory properties and
120/// emits iterator memory types together with configurations for allocators and
121/// iterator over heaps sizes.
122///
123/// [`configure`]: trait.HeapsConfigure.html#tymethod.configure
124pub unsafe trait HeapsConfigure {
125    /// Iterator over memory types.
126    type Types: IntoIterator<Item = (rendy_core::hal::memory::Properties, u32, HeapsConfig)>;
127
128    /// Iterator over heaps.
129    type Heaps: IntoIterator<Item = u64>;
130
131    /// Configure.
132    fn configure(
133        &self,
134        properties: &rendy_core::hal::adapter::MemoryProperties,
135    ) -> (Self::Types, Self::Heaps);
136}
137
138/// Basic heaps config.
139/// It uses some arbitrary values that can be considered sane default
140/// for today (year 2019) hardware and software.
141///
142/// If default allocators configuration is suboptimal for the particular use case
143/// a custom [`HeapsConfigure`] implementation can be used instead.
144///
145/// [`HeapsConfigure`]: trait.HeapsConfigure.html
146#[derive(Clone, Copy, Debug, Default)]
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148pub struct BasicHeapsConfigure;
149
150unsafe impl HeapsConfigure for BasicHeapsConfigure {
151    type Types = Vec<(rendy_core::hal::memory::Properties, u32, HeapsConfig)>;
152    type Heaps = Vec<u64>;
153
154    fn configure(
155        &self,
156        properties: &rendy_core::hal::adapter::MemoryProperties,
157    ) -> (Self::Types, Self::Heaps) {
158        let _1mb = 1024 * 1024;
159        let _32mb = 32 * _1mb;
160        let _128mb = 128 * _1mb;
161
162        let types = properties
163            .memory_types
164            .iter()
165            .map(|mt| {
166                let config = HeapsConfig {
167                    linear: if mt
168                        .properties
169                        .contains(rendy_core::hal::memory::Properties::CPU_VISIBLE)
170                    {
171                        Some(LinearConfig {
172                            linear_size: min(_128mb, properties.memory_heaps[mt.heap_index] / 16),
173                        })
174                    } else {
175                        None
176                    },
177                    dynamic: Some(DynamicConfig {
178                        block_size_granularity: 256.min(
179                            (properties.memory_heaps[mt.heap_index] / 4096).next_power_of_two(),
180                        ),
181                        min_device_allocation: _1mb
182                            .min(properties.memory_heaps[mt.heap_index] / 1048)
183                            .next_power_of_two(),
184                        max_chunk_size: _32mb.min(
185                            (properties.memory_heaps[mt.heap_index] / 128).next_power_of_two(),
186                        ),
187                    }),
188                };
189
190                (mt.properties, mt.heap_index as u32, config)
191            })
192            .collect();
193
194        let heaps = properties.memory_heaps.iter().cloned().collect();
195
196        (types, heaps)
197    }
198}
199
200/// Saved config for allocators.
201/// This config can be loaded from config files
202/// in any format supported by serde ecosystem.
203#[derive(Clone, Debug)]
204#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
205pub struct SavedHeapsConfig {
206    types: Vec<(rendy_core::hal::memory::Properties, u32, HeapsConfig)>,
207    heaps: Vec<u64>,
208}
209
210unsafe impl HeapsConfigure for SavedHeapsConfig {
211    type Types = Vec<(rendy_core::hal::memory::Properties, u32, HeapsConfig)>;
212    type Heaps = Vec<u64>;
213
214    fn configure(
215        &self,
216        _properties: &rendy_core::hal::adapter::MemoryProperties,
217    ) -> (Self::Types, Self::Heaps) {
218        (self.types.clone(), self.heaps.clone())
219    }
220}
221
222/// Devices configuration.
223/// Picks physical device to use.
224pub trait DevicesConfigure {
225    /// Pick adapter from the slice.
226    ///
227    /// # Panics
228    ///
229    /// This function may panic if empty slice is provided.
230    ///
231    fn pick<B>(&self, adapters: &[rendy_core::hal::adapter::Adapter<B>]) -> usize
232    where
233        B: rendy_core::hal::Backend;
234}
235
236/// Basics adapters config.
237///
238/// It picks first device with highest priority.
239/// From highest - discrete GPU, to lowest - CPU.
240///
241/// To pick among presented discret GPUs,
242/// or to intentionally pick integrated GPU when discrete GPU is available
243/// a custom [`DeviceConfigure`] implementationcan be used instead.
244///
245/// [`DeviceConfigure`]: trait.DevicesConfigure.html
246#[derive(Clone, Copy, Debug, Default)]
247#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
248pub struct BasicDevicesConfigure;
249
250impl DevicesConfigure for BasicDevicesConfigure {
251    fn pick<B>(&self, adapters: &[rendy_core::hal::adapter::Adapter<B>]) -> usize
252    where
253        B: rendy_core::hal::Backend,
254    {
255        adapters
256            .iter()
257            .enumerate()
258            .min_by_key(|(_, adapter)| match adapter.info.device_type {
259                rendy_core::hal::adapter::DeviceType::DiscreteGpu => 0,
260                rendy_core::hal::adapter::DeviceType::IntegratedGpu => 1,
261                rendy_core::hal::adapter::DeviceType::VirtualGpu => 2,
262                rendy_core::hal::adapter::DeviceType::Cpu => 3,
263                _ => 4,
264            })
265            .expect("No adapters present")
266            .0
267    }
268}