hac/
context.rs

1use std::sync::Arc;
2
3use bytemuck::Pod;
4use pollster::FutureExt as _;
5pub use wgpu::{Backends, Features, Limits};
6
7use crate::{
8    BindGroupDescriptor, Buffer, CommandQueue, Image, ImageInfo, Kernel, KernelInfo, Program,
9    Sampler, SamplerInfo,
10};
11
12/// Information to create a context.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct ContextInfo {
15    pub backends: Backends,
16    pub features: Features,
17    pub limits: Limits,
18}
19
20impl Default for ContextInfo {
21    fn default() -> Self {
22        Self {
23            backends: Backends::all(),
24            features: Features::empty(),
25            limits: Limits::default(),
26        }
27    }
28}
29
30/// Manager used to create resources
31#[derive(Debug)]
32pub struct Context {
33    pub(crate) device: Arc<crate::Device>,
34}
35
36impl Context {
37    /// Creates a context.
38    pub fn new(info: &ContextInfo) -> Self {
39        let instance = wgpu::Instance::new(info.backends);
40
41        let adapter = instance
42            .request_adapter(&wgpu::RequestAdapterOptions::default())
43            .block_on()
44            .unwrap();
45
46        Self::from_wgpu_adapter(
47            &adapter,
48            &wgpu::DeviceDescriptor {
49                label: Some("Device"),
50                features: info.features,
51                limits: info.limits.clone(),
52            },
53        )
54    }
55
56    /// Creates a context from a wgpu Adapter.
57    ///
58    /// Useful when wanting to use a specific adapter i.e. one that supports presenting
59    /// th the screen, if that's not the case consider `Context::new()`.
60    ///
61    /// The context will acquire it's own `wgpu::Device` and `wgpu::Queue`.
62    pub fn from_wgpu_adapter(
63        adapter: &wgpu::Adapter,
64        device_descriptor: &wgpu::DeviceDescriptor,
65    ) -> Self {
66        let (device, queue) = adapter
67            .request_device(&device_descriptor, None)
68            .block_on()
69            .unwrap();
70
71        Self {
72            device: Arc::new(crate::Device {
73                handle: device,
74                queue,
75            }),
76        }
77    }
78
79    /// Creates an empty buffer capable of holding `capacity` **elements of T**.
80    ///
81    /// # Panics
82    ///
83    /// - if `capacity * std::mem::size_of::<T>()` exceeds the `max_buffer_size` limit
84    /// set in [`ContextInfo`] (with a default of 2^30).
85    pub fn buffer<T: Pod>(&self, capacity: wgpu::BufferAddress) -> Buffer<T> {
86        Buffer::new(self, capacity)
87    }
88
89    /// Creates an buffer initialized from a slice.
90    ///
91    /// # Panics
92    ///
93    /// - if `std::mem::size_of_val(data)` exceeds the `max_buffer_size` limit
94    /// set in [`ContextInfo`] (with a default of 2^30).
95    pub fn buffer_from_slice<T: Pod>(&self, data: &[T]) -> Buffer<T> {
96        Buffer::from_slice(self, data)
97    }
98
99    /// Creates an [`Image`] with info.
100    pub fn image(&self, info: &ImageInfo) -> Image {
101        Image::new(self, info)
102    }
103
104    /// Creates a [`Sampler`] with info.
105    pub fn sampler(&self, info: &SamplerInfo) -> Sampler {
106        Sampler::new(self, info)
107    }
108
109    /// Creates a [`BindGroupDescriptor`] (a.k.a. descriptor set) to bind resources
110    /// such as buffers, samplers and images.
111    pub fn bind_group_descriptor(&self) -> BindGroupDescriptor {
112        BindGroupDescriptor::new(self)
113    }
114
115    /// Creates a [`Program`] from a `wgpu::ShaderSource`.
116    pub fn program_from_shader_source(&self, source: wgpu::ShaderSource) -> Program {
117        Program::from_source(self, source)
118    }
119
120    /// Creates a [`Program`] from wgsl source code.
121    pub fn program_from_wgsl(&self, source: &str) -> Program {
122        let shader_source = wgpu::ShaderSource::Wgsl(source.into());
123        self.program_from_shader_source(shader_source)
124    }
125
126    /// Creates a [`Kernel`] with info.
127    pub fn kernel(&self, info: &KernelInfo) -> Kernel {
128        Kernel::new(self, info)
129    }
130
131    /// Creates a [`CommandQueue`].
132    pub fn command_queue(&self) -> CommandQueue {
133        CommandQueue::new(self)
134    }
135
136    #[cfg(feature = "from_image")]
137    /// Creates an image from an RgbaImage of the image crate.
138    pub fn image_from_rgba8_img(
139        &self,
140        image: &image::RgbaImage,
141        sample_type: crate::ImageSampleType,
142    ) -> Image {
143        Image::from_rgba8_image(self, image, sample_type)
144    }
145}