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, device: Device,
31 queue: Queue,
32 config: RwLock<SurfaceConfiguration>, surface_texture_alive: AtomicBool,
34}
35
36impl State {
37 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 let instance = Instance::new(builder.backends); let surface = unsafe { instance.create_surface(&window) };
49 let adapter = instance .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 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 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 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 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 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 self.surface.configure(&self.device, &*config);
178 true
179 } else {
180 false
181 }
182 }
183
184 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 let view = output.texture.create_view(surface_view_desc);
196
197 let encoder = self
198 .device
199 .create_command_encoder(&CommandEncoderDescriptor::default());
200 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 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 pub fn size(&self) -> (u32, u32) {
227 let config = self.config.read();
228 (config.width, config.height)
229 }
230
231 pub fn format(&self) -> TextureFormat {
233 let config = self.config.read();
234 config.format.clone()
235 }
236
237 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 pub fn update_present_mode(&self, present_mode: PresentMode) {
253 while !self.try_update_present_mode(present_mode) {
254 }
256 }
257
258 #[inline(always)]
260 pub const fn device(&self) -> &Device {
261 &self.device
262 }
263
264 #[inline(always)]
266 pub const fn queue(&self) -> &Queue {
267 &self.queue
268 }
269
270 #[inline(always)]
272 pub const fn surface(&self) -> &Surface {
273 &self.surface
274 }
275
276 #[inline(always)]
279 pub const fn adapter(&self) -> &Adapter {
280 &self.adapter
281 }
282
283 pub fn create_buffer<T: Pod>(
285 &self,
286 #[cfg(feature = "debug_labels")] label: Label,
287 content: &[T],
288 usage: BufferUsages,
289 ) -> Buffer {
290 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 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 size: texture_size,
319 mip_level_count: mip_info.mip_level_count, sample_count: builder.sample_count,
321 dimension: builder
322 .texture_dimension
323 .expect("texture dimension has to be specified before building the texture"),
324 format,
326 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 ImageCopyTexture {
336 texture: &diffuse_texture,
337 mip_level: mip_info.target_mip_level,
338 origin: mip_info.origin,
339 aspect: builder.aspect,
340 },
341 builder
343 .data
344 .expect("data has to be specified before building the texture"),
345 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 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 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 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 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 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 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 pub entry_point: &'a str,
497 pub buffers: &'a [VertexBufferLayout<'a>],
499}
500
501pub struct FragmentShaderState<'a> {
502 pub entry_point: &'a str,
505 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, aspect: TextureAspect, sample_count: u32, mip_info: MipInfo, depth_or_array_layers: u32, #[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 pub fn usages(mut self, usages: TextureUsages) -> Self {
697 self.usages = usages | TextureUsages::COPY_DST;
698 self
699 }
700
701 #[inline]
703 pub fn aspect(mut self, aspect: TextureAspect) -> Self {
704 self.aspect = aspect;
705 self
706 }
707
708 #[inline]
710 pub fn sample_count(mut self, sample_count: u32) -> Self {
711 self.sample_count = sample_count;
712 self
713 }
714
715 #[inline]
717 pub fn mip_info(mut self, mip_info: MipInfo) -> Self {
718 self.mip_info = mip_info;
719 self
720 }
721
722 #[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, present_mode: PresentMode, requirements: DeviceRequirements, backends: Backends, format: Option<TextureFormat>, }
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 #[inline]
776 pub fn power_pref(mut self, power_pref: PowerPreference) -> Self {
777 self.power_pref = power_pref;
778 self
779 }
780
781 #[inline]
783 pub fn present_mode(mut self, present_mode: PresentMode) -> Self {
784 self.present_mode = present_mode;
785 self
786 }
787
788 #[inline]
791 pub fn device_requirements(mut self, requirements: DeviceRequirements) -> Self {
792 self.requirements = requirements;
793 self
794 }
795
796 #[inline]
798 pub fn backends(mut self, backends: Backends) -> Self {
799 self.backends = backends;
800 self
801 }
802
803 #[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
881pub trait WindowSize: HasRawWindowHandle {
904 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}