wgpu_biolerless/
lib.rs

1use anyhow::Error as AnyError;
2use bytemuck::Pod;
3use parking_lot::RwLock;
4use raw_window_handle::HasRawWindowHandle;
5use std::error::Error;
6use std::fmt::{Debug, Display, Formatter};
7use std::iter::once;
8use std::num::NonZeroU32;
9use std::sync::atomic::{AtomicBool, Ordering};
10use wgpu::util::{BufferInitDescriptor, DeviceExt};
11#[cfg(feature = "debug_labels")]
12use wgpu::Label;
13use wgpu::{
14    Adapter, Backends, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout,
15    BindGroupLayoutDescriptor, BindGroupLayoutEntry, Buffer, BufferAddress, BufferUsages,
16    ColorTargetState, CommandEncoder, CommandEncoderDescriptor, DepthStencilState, Device,
17    DeviceDescriptor, Extent3d, Features, FragmentState, ImageCopyTexture, ImageDataLayout,
18    Instance, Limits, MultisampleState, Origin3d, PipelineLayout, PipelineLayoutDescriptor,
19    PowerPreference, PresentMode, PrimitiveState, PushConstantRange, Queue, RenderPass,
20    RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
21    RenderPipeline, RenderPipelineDescriptor, RequestAdapterOptions, ShaderModule,
22    ShaderModuleDescriptor, ShaderSource, Surface, SurfaceConfiguration, SurfaceError, Texture,
23    TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureView,
24    TextureViewDescriptor, VertexAttribute, VertexBufferLayout, VertexFormat, VertexState,
25};
26
27pub struct State {
28    surface: Surface,
29    adapter: Adapter, // can be used by api users to acquire information
30    device: Device,
31    queue: Queue,
32    config: RwLock<SurfaceConfiguration>, // FIXME: should we use a Mutex instead?
33    surface_texture_alive: AtomicBool,
34}
35
36impl State {
37    /// Tries to create a new `State` from a `StateBuilder`
38    ///
39    /// returns either the newly created state or an error if
40    /// requesting an adapter or device fails.
41    pub async fn new<T: WindowSize>(builder: StateBuilder<T>) -> anyhow::Result<Self> {
42        let window = builder
43            .window
44            .expect("window has to be specified before building the state");
45        let size = window.window_size();
46        // The instance is a handle to our GPU
47        let instance = Instance::new(builder.backends); // used to create adapters and surfaces
48        let surface = unsafe { instance.create_surface(&window) };
49        let adapter = instance // adapter is a handle to our graphics card
50            .request_adapter(&RequestAdapterOptions {
51                power_preference: builder.power_pref,
52                force_fallback_adapter: false,
53                compatible_surface: Some(&surface),
54            })
55            .await;
56        if let Some(adapter) = adapter {
57            let (device, queue) = adapter
58                .request_device(
59                    &DeviceDescriptor {
60                        label: None,
61                        features: builder.requirements.features,
62                        limits: builder.requirements.limits,
63                    },
64                    None,
65                )
66                .await?;
67
68            // use the specified format, if none is provided, fallback to the preferred format
69            let format = builder
70                .format
71                .unwrap_or_else(|| surface.get_supported_formats(&adapter)[0]);
72            let config = SurfaceConfiguration {
73                usage: TextureUsages::RENDER_ATTACHMENT,
74                format,
75                width: size.0,
76                height: size.0,
77                present_mode: builder.present_mode,
78            };
79            surface.configure(&device, &config);
80
81            return Ok(Self {
82                surface,
83                adapter,
84                device,
85                queue,
86                config: RwLock::new(config),
87                surface_texture_alive: Default::default(),
88            });
89        }
90        Err(AnyError::from(NoSuitableAdapterFoundError))
91    }
92
93    /// Creates a new pipeline layout from its bind group layouts and
94    /// its push constant ranges
95    pub fn create_pipeline_layout(
96        &self,
97        #[cfg(feature = "debug_labels")] label: Label,
98        bind_group_layouts: &[&BindGroupLayout],
99        push_constant_ranges: &[PushConstantRange],
100    ) -> PipelineLayout {
101        self.device
102            .create_pipeline_layout(&PipelineLayoutDescriptor {
103                #[cfg(feature = "debug_labels")]
104                label,
105                #[cfg(not(feature = "debug_labels"))]
106                label: None,
107                bind_group_layouts,
108                push_constant_ranges,
109            })
110    }
111
112    /// Helper method to create a pipeline from its builder
113    pub fn create_pipeline(&self, builder: PipelineBuilder) -> RenderPipeline {
114        let shaders = builder
115            .shader_sources
116            .expect("shader sources have to be specified before building the pipeline")
117            .to_modules(self);
118        let vertex_shader = builder
119            .vertex_shader
120            .expect("vertex shader has to be specified before building the pipeline");
121
122        self.device
123            .create_render_pipeline(&RenderPipelineDescriptor {
124                #[cfg(feature = "debug_labels")]
125                label: builder.label,
126                #[cfg(not(feature = "debug_labels"))]
127                label: None,
128                layout: Some(
129                    builder
130                        .layout
131                        .expect("layout has to be specified before building the pipeline"),
132                ),
133                vertex: VertexState {
134                    module: shaders.vertex_module(),
135                    entry_point: vertex_shader.entry_point,
136                    buffers: vertex_shader.buffers,
137                },
138                fragment: builder
139                    .fragment_shader
140                    .map(|fragment_shader| FragmentState {
141                        module: shaders.fragment_module(),
142                        entry_point: fragment_shader.entry_point,
143                        targets: fragment_shader.targets,
144                    }),
145                primitive: builder
146                    .primitive
147                    .expect("primitive has to be specified before building the pipeline"),
148                depth_stencil: builder.depth_stencil,
149                multisample: builder.multisample,
150                multiview: builder.multiview,
151            })
152    }
153
154    /// Creates a shader module from its src
155    pub fn create_shader(
156        &self,
157        #[cfg(feature = "debug_labels")] label: Label,
158        src: ShaderSource,
159    ) -> ShaderModule {
160        self.device.create_shader_module(ShaderModuleDescriptor {
161            #[cfg(feature = "debug_labels")]
162            label,
163            #[cfg(not(feature = "debug_labels"))]
164            label: None,
165            source: src,
166        })
167    }
168
169    /// Returns whether the resizing succeeded or not
170    pub fn resize(&self, size: impl Into<(u32, u32)>) -> bool {
171        let size = size.into();
172        if size.0 > 0 && size.1 > 0 {
173            let mut config = self.config.write();
174            config.width = size.0;
175            config.height = size.1;
176            // FIXME: should we verify that there exist no old textures?
177            self.surface.configure(&self.device, &*config);
178            true
179        } else {
180            false
181        }
182    }
183
184    /// Initiates the rendering process, the passed callback gets
185    /// called once all the required state is set up and
186    /// once it ran, all the required steps to proceed get executed.
187    pub fn render<F: FnOnce(&TextureView, CommandEncoder, &State) -> CommandEncoder>(
188        &self,
189        callback: F,
190        surface_view_desc: &TextureViewDescriptor,
191    ) -> Result<(), SurfaceError> {
192        self.surface_texture_alive.store(true, Ordering::Release);
193        let output = self.surface.get_current_texture()?;
194        // get a view of the current texture in order to render on it
195        let view = output.texture.create_view(surface_view_desc);
196
197        let encoder = self
198            .device
199            .create_command_encoder(&CommandEncoderDescriptor::default());
200        // let the user do stuff with the encoder
201        let encoder = callback(&view, encoder, self);
202
203        self.queue.submit(once(encoder.finish()));
204
205        output.present();
206        self.surface_texture_alive.store(false, Ordering::Release);
207
208        Ok(())
209    }
210
211    /// Helper method to create a render pass in the encoder
212    pub fn create_render_pass<'a>(
213        &self,
214        encoder: &'a mut CommandEncoder,
215        color_attachments: &'a [Option<RenderPassColorAttachment<'a>>],
216        depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'a>>,
217    ) -> RenderPass<'a> {
218        encoder.begin_render_pass(&RenderPassDescriptor {
219            label: None,
220            color_attachments,
221            depth_stencil_attachment,
222        })
223    }
224
225    /// Returns the size defined in the config
226    pub fn size(&self) -> (u32, u32) {
227        let config = self.config.read();
228        (config.width, config.height)
229    }
230
231    /// Returns the format defined in the config
232    pub fn format(&self) -> TextureFormat {
233        let config = self.config.read();
234        config.format.clone()
235    }
236
237    /// Tries to update the present mode of the surface.
238    /// Returns whether update succeeded or not
239    pub fn try_update_present_mode(&self, present_mode: PresentMode) -> bool {
240        if !self.surface_texture_alive.load(Ordering::Acquire) {
241            let mut config = self.config.write();
242            config.present_mode = present_mode;
243            self.surface.configure(&self.device, &*config);
244            true
245        } else {
246            false
247        }
248    }
249
250    /// Updates the present mode of the surface
251    /// *Note*: this function will wait until the render call has finished
252    pub fn update_present_mode(&self, present_mode: PresentMode) {
253        while !self.try_update_present_mode(present_mode) {
254            // do nothing, as we just want to update the present mode
255        }
256    }
257
258    /// Returns a reference to the device
259    #[inline(always)]
260    pub const fn device(&self) -> &Device {
261        &self.device
262    }
263
264    /// Returns a reference to the queue
265    #[inline(always)]
266    pub const fn queue(&self) -> &Queue {
267        &self.queue
268    }
269
270    /// Returns a reference to the surface
271    #[inline(always)]
272    pub const fn surface(&self) -> &Surface {
273        &self.surface
274    }
275
276    /// Returns a reference to the adapter which can be used to
277    /// acquire information
278    #[inline(always)]
279    pub const fn adapter(&self) -> &Adapter {
280        &self.adapter
281    }
282
283    /// Helper method to create a buffer from its content and usage
284    pub fn create_buffer<T: Pod>(
285        &self,
286        #[cfg(feature = "debug_labels")] label: Label,
287        content: &[T],
288        usage: BufferUsages,
289    ) -> Buffer {
290        // FIXME: should we switch from Pod to NoUninit?
291        self.device.create_buffer_init(&BufferInitDescriptor {
292            #[cfg(feature = "debug_labels")]
293            label,
294            #[cfg(not(feature = "debug_labels"))]
295            label: None,
296            contents: bytemuck::cast_slice(content),
297            usage,
298        })
299    }
300
301    /// Helper method to create a texture from its builder
302    pub fn create_texture(&self, builder: TextureBuilder) -> Texture {
303        let mip_info = builder.mip_info;
304        let dimensions = builder
305            .dimensions
306            .expect("dimensions have to be specified before building the texture");
307        let texture_size = Extent3d {
308            width: dimensions.0,
309            height: dimensions.1,
310            depth_or_array_layers: builder.depth_or_array_layers,
311        };
312        let format = builder
313            .format
314            .expect("format has to be specified before building the texture");
315        let diffuse_texture = self.device.create_texture(&TextureDescriptor {
316            // All textures are stored as 3D, we represent our 2D texture
317            // by setting depth to 1.
318            size: texture_size,
319            mip_level_count: mip_info.mip_level_count, // We'll talk about this a little later
320            sample_count: builder.sample_count,
321            dimension: builder
322                .texture_dimension
323                .expect("texture dimension has to be specified before building the texture"),
324            // Most images are stored using sRGB so we need to reflect that here.
325            format,
326            // COPY_DST means that we want to copy data to this texture
327            usage: builder.usages,
328            #[cfg(feature = "debug_labels")]
329            label: builder.label,
330            #[cfg(not(feature = "debug_labels"))]
331            label: None,
332        });
333        self.queue.write_texture(
334            // Tells wgpu where to copy the pixel data
335            ImageCopyTexture {
336                texture: &diffuse_texture,
337                mip_level: mip_info.target_mip_level,
338                origin: mip_info.origin,
339                aspect: builder.aspect,
340            },
341            // The actual pixel data
342            builder
343                .data
344                .expect("data has to be specified before building the texture"),
345            // The layout of the texture
346            ImageDataLayout {
347                offset: 0,
348                bytes_per_row: NonZeroU32::new(format.describe().block_size as u32 * dimensions.0),
349                rows_per_image: NonZeroU32::new(dimensions.1),
350            },
351            texture_size,
352        );
353
354        diffuse_texture
355    }
356
357    /// Helper method to create a `BindGroupLayoutEntry` from its entries
358    pub fn create_bind_group_layout(
359        &self,
360        #[cfg(feature = "debug_labels")] label: Label,
361        entries: &[BindGroupLayoutEntry],
362    ) -> BindGroupLayout {
363        self.device
364            .create_bind_group_layout(&BindGroupLayoutDescriptor {
365                #[cfg(feature = "debug_labels")]
366                label,
367                #[cfg(not(feature = "debug_labels"))]
368                label: None,
369                entries,
370            })
371    }
372
373    /// Helper method to create a `BindGroup` from its layout and entries
374    pub fn create_bind_group(
375        &self,
376        #[cfg(feature = "debug_labels")] label: Label,
377        layout: &BindGroupLayout,
378        entries: &[BindGroupEntry],
379    ) -> BindGroup {
380        self.device.create_bind_group(&BindGroupDescriptor {
381            #[cfg(feature = "debug_labels")]
382            label,
383            #[cfg(not(feature = "debug_labels"))]
384            label: None,
385            layout,
386            entries,
387        })
388    }
389
390    /// Helper method to write data to a buffer at a specific offset
391    pub fn write_buffer<T: Pod>(&self, buffer: &Buffer, offset: BufferAddress, data: &[T]) {
392        self.queue
393            .write_buffer(buffer, offset, bytemuck::cast_slice(data));
394    }
395
396    /// Helper method to create a depth texture from its format
397    pub fn create_depth_texture(&self, format: TextureFormat) -> Texture {
398        let (width, height) = self.size();
399        let size = Extent3d {
400            width,
401            height,
402            depth_or_array_layers: 1,
403        };
404        let texture_desc = TextureDescriptor {
405            label: None,
406            size,
407            mip_level_count: 1,
408            sample_count: 1,
409            dimension: TextureDimension::D2,
410            format,
411            usage: TextureUsages::TEXTURE_BINDING | TextureUsages::RENDER_ATTACHMENT,
412        };
413        self.device.create_texture(&texture_desc)
414    }
415}
416
417#[derive(Default)]
418pub struct PipelineBuilder<'a> {
419    layout: Option<&'a PipelineLayout>,
420    vertex_shader: Option<VertexShaderState<'a>>,
421    fragment_shader: Option<FragmentShaderState<'a>>,
422    primitive: Option<PrimitiveState>,
423    depth_stencil: Option<DepthStencilState>,
424    multisample: MultisampleState,
425    multiview: Option<NonZeroU32>,
426    shader_sources: Option<ShaderModuleSources<'a>>,
427    #[cfg(feature = "debug_labels")]
428    label: Label<'a>,
429}
430
431impl<'a> PipelineBuilder<'a> {
432    #[inline]
433    pub fn new() -> Self {
434        Self::default()
435    }
436
437    pub fn layout(mut self, layout: &'a PipelineLayout) -> Self {
438        self.layout = Some(layout);
439        self
440    }
441
442    pub fn vertex(mut self, vertex_shader: VertexShaderState<'a>) -> Self {
443        self.vertex_shader = Some(vertex_shader);
444        self
445    }
446
447    pub fn fragment(mut self, fragment_shader: FragmentShaderState<'a>) -> Self {
448        self.fragment_shader = Some(fragment_shader);
449        self
450    }
451
452    pub fn primitive(mut self, primitive: PrimitiveState) -> Self {
453        self.primitive = Some(primitive);
454        self
455    }
456
457    pub fn depth_stencil(mut self, depth_stencil: DepthStencilState) -> Self {
458        self.depth_stencil = Some(depth_stencil);
459        self
460    }
461
462    /// The default value is `MultisampleState::default()`
463    pub fn multisample(mut self, multisample: MultisampleState) -> Self {
464        self.multisample = multisample;
465        self
466    }
467
468    pub fn multiview(mut self, multiview: NonZeroU32) -> Self {
469        self.multiview = Some(multiview);
470        self
471    }
472
473    pub fn shader_src(mut self, shader_sources: ShaderModuleSources<'a>) -> Self {
474        // FIXME: do we even need ShaderModuleSources, wouldn't it be cleaner to let the user
475        // FIXME: pass in either a Ref to a ShaderModule or a ShaderSource themselves?
476        // FIXME: tho this could also make it less nice to use.
477        self.shader_sources = Some(shader_sources);
478        self
479    }
480
481    #[cfg(feature = "debug_labels")]
482    pub fn label(mut self, label: &'a str) -> Self {
483        self.label = Some(label);
484        self
485    }
486
487    #[inline]
488    pub fn build(self, state: &State) -> RenderPipeline {
489        state.create_pipeline(self)
490    }
491}
492
493pub struct VertexShaderState<'a> {
494    /// The name of the entry point in the compiled shader. There must be a function that returns
495    /// void with this name in the shader.
496    pub entry_point: &'a str,
497    /// The format of any vertex buffers used with this pipeline.
498    pub buffers: &'a [VertexBufferLayout<'a>],
499}
500
501pub struct FragmentShaderState<'a> {
502    /// The name of the entry point in the compiled shader. There must be a function that returns
503    /// void with this name in the shader.
504    pub entry_point: &'a str,
505    /// The color state of the render targets.
506    pub targets: &'a [Option<ColorTargetState>],
507}
508
509pub enum ShaderModuleSources<'a> {
510    Single(ModuleSrc<'a>),
511    Multi(ModuleSrc<'a>, ModuleSrc<'a>),
512}
513
514impl<'a> ShaderModuleSources<'a> {
515    fn to_modules(self, state: &'a State) -> ShaderModules {
516        match self {
517            ShaderModuleSources::Single(src) => ShaderModules::Single(src.to_module(state)),
518            ShaderModuleSources::Multi(vertex_src, fragment_src) => {
519                ShaderModules::Multi(vertex_src.to_module(state), fragment_src.to_module(state))
520            }
521        }
522    }
523}
524
525pub enum ModuleSrc<'a> {
526    Source(ShaderSource<'a>, #[cfg(feature = "debug_labels")] Label<'a>),
527    Ref(&'a ShaderModule),
528}
529
530impl<'a> ModuleSrc<'a> {
531    #[cfg(feature = "debug_labels")]
532    fn to_module(self, state: &'a State) -> MaybeOwnedModule<'a> {
533        match self {
534            ModuleSrc::Source(src, label) => {
535                MaybeOwnedModule::Owned(state.create_shader(src, label))
536            }
537            ModuleSrc::Ref(reference) => MaybeOwnedModule::Ref(reference),
538        }
539    }
540
541    #[cfg(not(feature = "debug_labels"))]
542    fn to_module(self, state: &'a State) -> MaybeOwnedModule<'a> {
543        match self {
544            ModuleSrc::Source(src) => MaybeOwnedModule::Owned(state.create_shader(src)),
545            ModuleSrc::Ref(reference) => MaybeOwnedModule::Ref(reference),
546        }
547    }
548}
549
550#[cfg(feature = "debug_labels")]
551impl<'a> From<ShaderSource<'a>> for ModuleSrc<'a> {
552    #[inline]
553    fn from(src: ShaderSource<'a>) -> Self {
554        Self::Source(src, None)
555    }
556}
557
558#[cfg(not(feature = "debug_labels"))]
559impl<'a> From<ShaderSource<'a>> for ModuleSrc<'a> {
560    #[inline]
561    fn from(src: ShaderSource<'a>) -> Self {
562        Self::Source(src)
563    }
564}
565
566impl<'a> From<&'a ShaderModule> for ModuleSrc<'a> {
567    #[inline]
568    fn from(src: &'a ShaderModule) -> Self {
569        Self::Ref(src)
570    }
571}
572
573enum ShaderModules<'a> {
574    Single(MaybeOwnedModule<'a>),
575    Multi(MaybeOwnedModule<'a>, MaybeOwnedModule<'a>),
576}
577
578impl ShaderModules<'_> {
579    fn vertex_module(&self) -> &ShaderModule {
580        match self {
581            ShaderModules::Single(module) => module.shader_ref(),
582            ShaderModules::Multi(vertex_module, _) => vertex_module.shader_ref(),
583        }
584    }
585
586    fn fragment_module(&self) -> &ShaderModule {
587        match self {
588            ShaderModules::Single(module) => module.shader_ref(),
589            ShaderModules::Multi(_, fragment_module) => fragment_module.shader_ref(),
590        }
591    }
592}
593
594enum MaybeOwnedModule<'a> {
595    Owned(ShaderModule),
596    Ref(&'a ShaderModule),
597}
598
599impl MaybeOwnedModule<'_> {
600    fn shader_ref(&self) -> &ShaderModule {
601        match self {
602            MaybeOwnedModule::Owned(owned) => owned,
603            MaybeOwnedModule::Ref(reference) => *reference,
604        }
605    }
606}
607
608impl<'a> From<ShaderSource<'a>> for ShaderModuleSources<'a> {
609    #[inline]
610    fn from(src: ShaderSource<'a>) -> Self {
611        Self::Single(ModuleSrc::from(src))
612    }
613}
614
615impl<'a> From<(ShaderSource<'a>, ShaderSource<'a>)> for ShaderModuleSources<'a> {
616    #[inline]
617    fn from(src: (ShaderSource<'a>, ShaderSource<'a>)) -> Self {
618        Self::Multi(ModuleSrc::from(src.0), ModuleSrc::from(src.1))
619    }
620}
621
622impl<'a> From<&'a ShaderModule> for ShaderModuleSources<'a> {
623    #[inline]
624    fn from(src: &'a ShaderModule) -> Self {
625        Self::Single(ModuleSrc::from(src))
626    }
627}
628
629impl<'a> From<(&'a ShaderModule, &'a ShaderModule)> for ShaderModuleSources<'a> {
630    #[inline]
631    fn from(src: (&'a ShaderModule, &'a ShaderModule)) -> Self {
632        Self::Multi(ModuleSrc::from(src.0), ModuleSrc::from(src.1))
633    }
634}
635
636pub struct TextureBuilder<'a> {
637    data: Option<&'a [u8]>,
638    dimensions: Option<(u32, u32)>,
639    format: Option<TextureFormat>,
640    texture_dimension: Option<TextureDimension>,
641    usages: TextureUsages,      // MAYBE(currently): we have a default
642    aspect: TextureAspect,      // we have a default
643    sample_count: u32,          // we have a default
644    mip_info: MipInfo,          // we have a default
645    depth_or_array_layers: u32, // we have a default
646    #[cfg(feature = "debug_labels")]
647    label: Label<'a>,
648}
649
650impl Default for TextureBuilder<'_> {
651    fn default() -> Self {
652        Self {
653            data: None,
654            dimensions: None,
655            format: None,
656            texture_dimension: None,
657            usages: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
658            aspect: TextureAspect::All,
659            sample_count: 1,
660            mip_info: MipInfo::default(),
661            depth_or_array_layers: 1,
662            #[cfg(feature = "debug_labels")]
663            label: None,
664        }
665    }
666}
667
668impl<'a> TextureBuilder<'a> {
669    #[inline]
670    pub fn new() -> Self {
671        Self::default()
672    }
673
674    pub fn data(mut self, data: &'a [u8]) -> Self {
675        self.data = Some(data);
676        self
677    }
678
679    pub fn dimensions(mut self, dimensions: (u32, u32)) -> Self {
680        self.dimensions = Some(dimensions);
681        self
682    }
683
684    pub fn format(mut self, format: TextureFormat) -> Self {
685        self.format = Some(format);
686        self
687    }
688
689    pub fn texture_dimension(mut self, texture_dimension: TextureDimension) -> Self {
690        self.texture_dimension = Some(texture_dimension);
691        self
692    }
693
694    /// The default value is TextureUsages::TEXTURE_BINDING
695    /// *Note*: TextureUsages::COPY_DST gets appended to the usages
696    pub fn usages(mut self, usages: TextureUsages) -> Self {
697        self.usages = usages | TextureUsages::COPY_DST;
698        self
699    }
700
701    /// The default value is `TextureAspect::All`
702    #[inline]
703    pub fn aspect(mut self, aspect: TextureAspect) -> Self {
704        self.aspect = aspect;
705        self
706    }
707
708    /// The default value is 1
709    #[inline]
710    pub fn sample_count(mut self, sample_count: u32) -> Self {
711        self.sample_count = sample_count;
712        self
713    }
714
715    /// The default value is `MipInfo::default()`
716    #[inline]
717    pub fn mip_info(mut self, mip_info: MipInfo) -> Self {
718        self.mip_info = mip_info;
719        self
720    }
721
722    /// The default value is 1
723    #[inline]
724    pub fn depth_or_array_layers(mut self, depth_or_array_layers: u32) -> Self {
725        self.depth_or_array_layers = depth_or_array_layers;
726        self
727    }
728
729    #[cfg(feature = "debug_labels")]
730    pub fn label(mut self, label: &'a str) -> Self {
731        self.label = Some(label);
732        self
733    }
734
735    #[inline]
736    pub fn build(self, state: &State) -> Texture {
737        state.create_texture(self)
738    }
739}
740
741pub struct StateBuilder<T: WindowSize> {
742    window: Option<T>,
743    power_pref: PowerPreference,      // we have a default
744    present_mode: PresentMode,        // we have a default
745    requirements: DeviceRequirements, // we have a default
746    backends: Backends,               // we have a default
747    format: Option<TextureFormat>,    // we have a default
748}
749
750impl<T: WindowSize> Default for StateBuilder<T> {
751    fn default() -> Self {
752        Self {
753            backends: Backends::all(),
754            window: None,
755            power_pref: Default::default(),
756            present_mode: Default::default(),
757            requirements: Default::default(),
758            format: None,
759        }
760    }
761}
762
763impl<T: WindowSize> StateBuilder<T> {
764    #[inline]
765    pub fn new() -> Self {
766        Self::default()
767    }
768
769    pub fn window(mut self, window: T) -> Self {
770        self.window = Some(window);
771        self
772    }
773
774    /// The default value is `PowerPreference::LowPower`
775    #[inline]
776    pub fn power_pref(mut self, power_pref: PowerPreference) -> Self {
777        self.power_pref = power_pref;
778        self
779    }
780
781    /// The default value is `PresentMode::Fifo`
782    #[inline]
783    pub fn present_mode(mut self, present_mode: PresentMode) -> Self {
784        self.present_mode = present_mode;
785        self
786    }
787
788    // FIXME: should we rename this to `requirements`?
789    /// The default value is `DeviceRequirements::default()`
790    #[inline]
791    pub fn device_requirements(mut self, requirements: DeviceRequirements) -> Self {
792        self.requirements = requirements;
793        self
794    }
795
796    /// The default value is `Backends::all()`
797    #[inline]
798    pub fn backends(mut self, backends: Backends) -> Self {
799        self.backends = backends;
800        self
801    }
802
803    /// The default is to use the preferred format
804    /// *Note*: This might be useful when you don't have control over the
805    /// pipelines provided to you but you can specify a default.
806    /// This method may be deprecated in the future.
807    #[inline]
808    pub fn format(mut self, format: TextureFormat) -> Self {
809        self.format = Some(format);
810        self
811    }
812
813    #[inline]
814    pub async fn build(self) -> anyhow::Result<State> {
815        State::new(self).await
816    }
817}
818
819pub struct MipInfo {
820    pub origin: Origin3d,
821    pub target_mip_level: u32,
822    pub mip_level_count: u32,
823}
824
825impl Default for MipInfo {
826    fn default() -> Self {
827        Self {
828            origin: Origin3d::ZERO,
829            target_mip_level: 0,
830            mip_level_count: 1,
831        }
832    }
833}
834
835#[derive(Default)]
836pub struct DeviceRequirements {
837    pub features: Features,
838    pub limits: Limits,
839}
840
841pub struct NoSuitableAdapterFoundError;
842
843impl Debug for NoSuitableAdapterFoundError {
844    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
845        f.write_str("couldn't create state because no suitable adapter was found")
846    }
847}
848
849impl Display for NoSuitableAdapterFoundError {
850    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
851        f.write_str("couldn't create state because no suitable adapter was found")
852    }
853}
854
855impl Error for NoSuitableAdapterFoundError {}
856
857pub const fn matrix<const COLUMNS: usize>(
858    offset: u64,
859    location: u32,
860    format: VertexFormat,
861) -> [VertexAttribute; COLUMNS] {
862    let mut ret = [VertexAttribute {
863        format,
864        offset: 0,
865        shader_location: 0,
866    }; COLUMNS];
867
868    let mut x = 0;
869    while COLUMNS > x {
870        ret[x] = VertexAttribute {
871            format,
872            offset: (offset + format.size() * x as u64) as BufferAddress,
873            shader_location: location + x as u32,
874        };
875        x += 1;
876    }
877
878    ret
879}
880
881/// This trait is required in order to abstract over the windowing library
882///
883/// an implementation of this trait could look like this:
884/// pub struct WinitWindowWrapper<'a>(&'a Window);
885///
886/// impl WindowSize for WinitWindowWrapper<'_> {
887///
888///     fn window_size<T: Into<(u32, u32)>>(&self) -> T {
889///         let size = self.0.inner_size();
890///         (size.width, size.height)
891///     }
892///
893/// }
894///
895/// unsafe impl HasRawWindowHandle for WinitWindowWrapper<'_> {
896///
897///     fn raw_window_handle(&self) -> RawWindowHandle {
898///         self.0.raw_window_handle()
899///     }
900///
901/// }
902///
903pub trait WindowSize: HasRawWindowHandle {
904    /// Returns the size of the window in the format (width, height)
905    fn window_size(&self) -> (u32, u32);
906}
907
908#[cfg(feature = "winit")]
909impl WindowSize for winit::window::Window {
910    fn window_size(&self) -> (u32, u32) {
911        let size = self.inner_size();
912        (size.width, size.height)
913    }
914}