1use std::marker::PhantomData;
2use std::num::NonZeroU32;
3use std::num::NonZeroU64;
4
5use bitvec::vec::BitVec;
6use ratatui_core::style::Color;
7use rustybuzz::UnicodeBuffer;
8use web_time::Duration;
9use web_time::Instant;
10use wgpu::include_wgsl;
11use wgpu::util::BufferInitDescriptor;
12use wgpu::util::DeviceExt;
13use wgpu::vertex_attr_array;
14use wgpu::AddressMode;
15use wgpu::Backends;
16use wgpu::BindGroupDescriptor;
17use wgpu::BindGroupEntry;
18use wgpu::BindGroupLayoutDescriptor;
19use wgpu::BindGroupLayoutEntry;
20use wgpu::BindingResource;
21use wgpu::BindingType;
22use wgpu::BlendState;
23use wgpu::Buffer;
24use wgpu::BufferBindingType;
25use wgpu::BufferDescriptor;
26use wgpu::BufferUsages;
27use wgpu::ColorTargetState;
28use wgpu::ColorWrites;
29use wgpu::Device;
30use wgpu::Extent3d;
31use wgpu::FilterMode;
32use wgpu::FragmentState;
33use wgpu::Instance;
34use wgpu::InstanceDescriptor;
35use wgpu::InstanceFlags;
36use wgpu::Limits;
37use wgpu::MipmapFilterMode;
38use wgpu::MultisampleState;
39use wgpu::PipelineCompilationOptions;
40use wgpu::PipelineLayoutDescriptor;
41use wgpu::PresentMode;
42use wgpu::PrimitiveState;
43use wgpu::PrimitiveTopology;
44use wgpu::RenderPipelineDescriptor;
45use wgpu::Sampler;
46use wgpu::SamplerBindingType;
47use wgpu::SamplerDescriptor;
48use wgpu::ShaderStages;
49use wgpu::Surface;
50use wgpu::SurfaceTarget;
51use wgpu::TextureDescriptor;
52use wgpu::TextureDimension;
53use wgpu::TextureFormat;
54use wgpu::TextureSampleType;
55use wgpu::TextureUsages;
56use wgpu::TextureView;
57use wgpu::TextureViewDescriptor;
58use wgpu::TextureViewDimension;
59use wgpu::VertexBufferLayout;
60use wgpu::VertexState;
61use wgpu::VertexStepMode;
62
63use crate::backend::build_wgpu_state;
64use crate::backend::private::Token;
65use crate::backend::wgpu_backend::WgpuBackend;
66use crate::backend::Dimensions;
67use crate::backend::PostProcessor;
68use crate::backend::RenderSurface;
69use crate::backend::TextBgVertexMember;
70use crate::backend::TextCacheBgPipeline;
71use crate::backend::TextCacheFgPipeline;
72use crate::backend::TextVertexMember;
73use crate::backend::Viewport;
74use crate::colors::named;
75use crate::colors::ColorTable;
76use crate::fonts::Font;
77use crate::fonts::Fonts;
78use crate::shaders::DefaultPostProcessor;
79use crate::utils::plan_cache::PlanCache;
80use crate::utils::text_atlas::Atlas;
81use crate::Error;
82use crate::Result;
83
84const CACHE_WIDTH: u32 = 1800;
85const CACHE_HEIGHT: u32 = 1200;
86
87pub struct Builder<'a, P: PostProcessor = DefaultPostProcessor> {
93 user_data: P::UserData,
94 fonts: Fonts<'a>,
95 instance: Option<Instance>,
96 limits: Option<Limits>,
97 present_mode: Option<PresentMode>,
98 width: NonZeroU32,
99 height: NonZeroU32,
100 viewport: Viewport,
101 colors: ColorTable,
102 reset_fg: Color,
103 reset_bg: Color,
104 fast_blink: Duration,
105 slow_blink: Duration,
106}
107
108impl<'a, P: PostProcessor> Builder<'a, P>
109where
110 P::UserData: Default,
111{
112 pub fn from_font(font: Font<'a>) -> Self {
115 Self {
116 user_data: Default::default(),
117 instance: None,
118 fonts: Fonts::new(font, 24),
119 limits: None,
120 present_mode: None,
121 width: NonZeroU32::new(1).unwrap(),
122 height: NonZeroU32::new(1).unwrap(),
123 viewport: Viewport::Full,
124 colors: named::DEFAULT_COLORS,
125 reset_fg: Color::Black,
126 reset_bg: Color::White,
127 fast_blink: Duration::from_millis(200),
128 slow_blink: Duration::from_millis(1000),
129 }
130 }
131}
132
133impl<'a, P: PostProcessor> Builder<'a, P> {
134 pub fn from_font_and_user_data(
137 font: Font<'a>,
138 user_data: P::UserData,
139 ) -> Self {
140 Self {
141 user_data,
142 instance: None,
143 fonts: Fonts::new(font, 24),
144 limits: None,
145 present_mode: None,
146 width: NonZeroU32::new(1).unwrap(),
147 height: NonZeroU32::new(1).unwrap(),
148 viewport: Viewport::Full,
149 colors: named::DEFAULT_COLORS,
150 reset_fg: Color::Black,
151 reset_bg: Color::White,
152 fast_blink: Duration::from_millis(200),
153 slow_blink: Duration::from_millis(1000),
154 }
155 }
156
157 #[must_use]
159 pub fn with_instance(
160 mut self,
161 instance: Instance,
162 ) -> Self {
163 self.instance = Some(instance);
164 self
165 }
166
167 #[must_use]
170 pub fn with_viewport(
171 mut self,
172 viewport: Viewport,
173 ) -> Self {
174 self.viewport = viewport;
175 self
176 }
177
178 #[must_use]
180 pub fn with_font_size_px(
181 mut self,
182 size: u32,
183 ) -> Self {
184 self.fonts.set_size_px(size);
185 self
186 }
187
188 pub fn with_fonts<I: IntoIterator<Item = Font<'a>>>(
196 mut self,
197 fonts: I,
198 ) -> Self {
199 self.fonts.add_fonts(fonts);
200 self
201 }
202
203 #[must_use]
208 pub fn with_regular_fonts<I: IntoIterator<Item = Font<'a>>>(
209 mut self,
210 fonts: I,
211 ) -> Self {
212 self.fonts.add_regular_fonts(fonts);
213 self
214 }
215
216 #[must_use]
221 pub fn with_bold_fonts<I: IntoIterator<Item = Font<'a>>>(
222 mut self,
223 fonts: I,
224 ) -> Self {
225 self.fonts.add_bold_fonts(fonts);
226 self
227 }
228
229 #[must_use]
234 pub fn with_italic_fonts<I: IntoIterator<Item = Font<'a>>>(
235 mut self,
236 fonts: I,
237 ) -> Self {
238 self.fonts.add_italic_fonts(fonts);
239 self
240 }
241
242 #[must_use]
247 pub fn with_bold_italic_fonts<I: IntoIterator<Item = Font<'a>>>(
248 mut self,
249 fonts: I,
250 ) -> Self {
251 self.fonts.add_bold_italic_fonts(fonts);
252 self
253 }
254
255 #[must_use]
258 pub fn with_limits(
259 mut self,
260 limits: Limits,
261 ) -> Self {
262 self.limits = Some(limits);
263 self
264 }
265
266 #[must_use]
268 pub fn with_present_mode(
269 mut self,
270 mode: PresentMode,
271 ) -> Self {
272 self.present_mode = Some(mode);
273 self
274 }
275
276 #[must_use]
279 pub fn with_dimensions(
280 mut self,
281 dimensions: Dimensions,
282 ) -> Self {
283 self.width = dimensions.width;
284 self.height = dimensions.height;
285 self
286 }
287
288 #[must_use]
291 pub fn with_width_and_height(
292 mut self,
293 dimensions: Dimensions,
294 ) -> Self {
295 self.width = dimensions.width;
296 self.height = dimensions.height;
297 self
298 }
299
300 pub fn with_color_table(
303 mut self,
304 colors: ColorTable,
305 ) -> Self {
306 self.colors = colors;
307 self
308 }
309
310 #[must_use]
313 pub fn with_fg_color(
314 mut self,
315 fg: Color,
316 ) -> Self {
317 self.reset_fg = fg;
318 self
319 }
320
321 #[must_use]
324 pub fn with_bg_color(
325 mut self,
326 bg: Color,
327 ) -> Self {
328 self.reset_bg = bg;
329 self
330 }
331
332 #[must_use]
337 pub fn with_rapid_blink_millis(
338 mut self,
339 millis: u64,
340 ) -> Self {
341 self.fast_blink = Duration::from_millis(millis);
342 self
343 }
344
345 #[must_use]
350 pub fn with_slow_blink_millis(
351 mut self,
352 millis: u64,
353 ) -> Self {
354 self.slow_blink = Duration::from_millis(millis);
355 self
356 }
357}
358
359impl<'a, P: PostProcessor> Builder<'a, P> {
360 pub async fn build_with_target<'s>(
363 mut self,
364 target: impl Into<SurfaceTarget<'s>>,
365 ) -> Result<WgpuBackend<'a, 's, P>> {
366 let instance = self.instance.get_or_insert_with(|| {
367 wgpu::Instance::new(&InstanceDescriptor {
368 backends: Backends::default(),
369 flags: InstanceFlags::default(),
370 ..Default::default()
371 })
372 });
373 let surface = instance
374 .create_surface(target)
375 .map_err(Error::SurfaceCreationFailed)?;
376
377 self.build_with_surface(surface).await
378 }
379
380 pub async fn build_with_surface<'s>(
385 self,
386 surface: Surface<'s>,
387 ) -> Result<WgpuBackend<'a, 's, P>> {
388 self.build_with_render_surface(surface).await
389 }
390
391 #[cfg(test)]
392 pub(crate) async fn build_headless(
393 self
394 ) -> Result<WgpuBackend<'a, 'static, P, super::HeadlessSurface>> {
395 self.build_with_render_surface(super::HeadlessSurface::default())
396 .await
397 }
398
399 #[cfg(test)]
400 pub(crate) async fn build_headless_with_format(
401 self,
402 format: TextureFormat,
403 ) -> Result<WgpuBackend<'a, 'static, P, super::HeadlessSurface>> {
404 self.build_with_render_surface(super::HeadlessSurface::new(format))
405 .await
406 }
407
408 async fn build_with_render_surface<'s, S: RenderSurface<'s> + 's>(
409 mut self,
410 mut surface: S,
411 ) -> Result<WgpuBackend<'a, 's, P, S>> {
412 let instance = self.instance.get_or_insert_with(|| {
413 wgpu::Instance::new(&InstanceDescriptor {
414 backends: Backends::default(),
415 flags: InstanceFlags::default(),
416 ..Default::default()
417 })
418 });
419
420 let adapter = instance
421 .request_adapter(&wgpu::RequestAdapterOptions {
422 compatible_surface: surface.wgpu_surface(Token),
423 ..Default::default()
424 })
425 .await
426 .map_err(Error::AdapterRequestFailed)?;
427
428 let limits = if let Some(limits) = self.limits {
429 min_limits(&adapter, limits)
430 } else {
431 adapter.limits()
432 };
433
434 let (device, queue) = adapter
435 .request_device(&wgpu::DeviceDescriptor {
436 required_limits: limits.clone(),
437 ..Default::default()
438 })
439 .await
440 .map_err(Error::DeviceRequestFailed)?;
441
442 let mut surface_config = surface
443 .get_default_config(
444 &adapter,
445 self.width.get().min(limits.max_texture_dimension_2d),
446 self.height.get().min(limits.max_texture_dimension_2d),
447 Token,
448 )
449 .ok_or(Error::SurfaceConfigurationRequestFailed)?;
450
451 if let Some(mode) = self.present_mode {
452 surface_config.present_mode = mode;
453 }
454
455 surface.configure(&device, &surface_config, Token);
456
457 let (inset_width, inset_height) = match self.viewport {
458 Viewport::Full => (0, 0),
459 Viewport::Shrink { width, height } => (width, height),
460 };
461
462 let drawable_width = surface_config.width - inset_width;
463 let drawable_height = surface_config.height - inset_height;
464
465 info!(
466 "char width x height: {}x{}",
467 self.fonts.min_width_px(),
468 self.fonts.height_px()
469 );
470
471 let text_cache = device.create_texture(&TextureDescriptor {
472 label: Some("Text Atlas"),
473 size: Extent3d {
474 width: CACHE_WIDTH,
475 height: CACHE_HEIGHT,
476 depth_or_array_layers: 1,
477 },
478 mip_level_count: 1,
479 sample_count: 1,
480 dimension: TextureDimension::D2,
481 format: TextureFormat::Rgba8Unorm,
482 usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
483 view_formats: &[],
484 });
485
486 let text_cache_view = text_cache.create_view(&TextureViewDescriptor::default());
487
488 let text_mask = device.create_texture(&TextureDescriptor {
489 label: Some("Text Mask"),
490 size: Extent3d {
491 width: CACHE_WIDTH,
492 height: CACHE_HEIGHT,
493 depth_or_array_layers: 1,
494 },
495 mip_level_count: 1,
496 sample_count: 1,
497 dimension: TextureDimension::D2,
498 format: TextureFormat::R8Unorm,
499 usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
500 view_formats: &[],
501 });
502
503 let text_mask_view = text_mask.create_view(&TextureViewDescriptor::default());
504
505 let sampler = device.create_sampler(&SamplerDescriptor {
506 address_mode_u: AddressMode::ClampToEdge,
507 address_mode_v: AddressMode::ClampToEdge,
508 address_mode_w: AddressMode::ClampToEdge,
509 mag_filter: FilterMode::Nearest,
510 min_filter: FilterMode::Nearest,
511 mipmap_filter: MipmapFilterMode::Nearest,
512 ..Default::default()
513 });
514
515 let text_screen_size_buffer = device.create_buffer(&BufferDescriptor {
516 label: Some("Text Uniforms Buffer"),
517 size: size_of::<[f32; 4]>() as u64,
518 mapped_at_creation: false,
519 usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
520 });
521
522 let atlas_size_buffer = device.create_buffer_init(&BufferInitDescriptor {
523 label: Some("Atlas Size buffer"),
524 contents: bytemuck::cast_slice(&[CACHE_WIDTH as f32, CACHE_HEIGHT as f32, 0.0, 0.0]),
525 usage: BufferUsages::UNIFORM,
526 });
527
528 let text_bg_compositor = build_text_bg_compositor(&device, &text_screen_size_buffer);
529
530 let text_fg_compositor = build_text_fg_compositor(
531 &device,
532 &text_screen_size_buffer,
533 &atlas_size_buffer,
534 &text_cache_view,
535 &text_mask_view,
536 &sampler,
537 );
538
539 let wgpu_state = build_wgpu_state(
540 &device,
541 (drawable_width / self.fonts.min_width_px()) * self.fonts.min_width_px(),
542 (drawable_height / self.fonts.height_px()) * self.fonts.height_px(),
543 );
544
545 let reset_fg = self.colors.c2c(self.reset_fg, [0, 0, 0]);
546 let reset_bg = self.colors.c2c(self.reset_bg, [255, 255, 255]);
547
548 Ok(WgpuBackend {
549 post_process: P::compile(
550 &device,
551 &wgpu_state.text_dest_view,
552 &surface_config,
553 self.user_data,
554 ),
555 cells: vec![],
556 dirty_rows: vec![],
557 dirty_cells: BitVec::new(),
558 rendered: vec![],
559 sourced: vec![],
560 fast_blinking: BitVec::new(),
561 slow_blinking: BitVec::new(),
562 cursor: (0, 0),
563 surface,
564 _surface: PhantomData,
565 surface_config,
566 device,
567 queue,
568 plan_cache: PlanCache::new(self.fonts.count().max(2)),
569 buffer: UnicodeBuffer::new(),
570 row: String::new(),
571 rowmap: vec![],
572 viewport: self.viewport,
573 cached: Atlas::new(&self.fonts, CACHE_WIDTH, CACHE_HEIGHT),
574 text_cache,
575 text_mask,
576 bg_vertices: vec![],
577 text_indices: vec![],
578 text_vertices: vec![],
579 text_screen_size_buffer,
580 text_bg_compositor,
581 text_fg_compositor,
582 wgpu_state,
583 fonts: self.fonts,
584 colors: self.colors,
585 reset_fg,
586 reset_bg,
587 fast_duration: self.fast_blink,
588 last_fast_toggle: Instant::now(),
589 show_fast: true,
590 slow_duration: self.slow_blink,
591 last_slow_toggle: Instant::now(),
592 show_slow: true,
593 })
594 }
595}
596
597fn build_text_bg_compositor(
598 device: &Device,
599 screen_size: &Buffer,
600) -> TextCacheBgPipeline {
601 let shader = device.create_shader_module(include_wgsl!("shaders/composite_bg.wgsl"));
602
603 let vertex_shader_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
604 label: Some("Text Bg Compositor Uniforms Binding Layout"),
605 entries: &[BindGroupLayoutEntry {
606 binding: 0,
607 visibility: ShaderStages::VERTEX,
608 ty: BindingType::Buffer {
609 ty: BufferBindingType::Uniform,
610 has_dynamic_offset: false,
611 min_binding_size: Some(NonZeroU64::new(size_of::<[f32; 4]>() as u64).unwrap()),
612 },
613 count: None,
614 }],
615 });
616
617 let fs_uniforms = device.create_bind_group(&BindGroupDescriptor {
618 label: Some("Text Bg Compositor Uniforms Binding"),
619 layout: &vertex_shader_layout,
620 entries: &[BindGroupEntry {
621 binding: 0,
622 resource: screen_size.as_entire_binding(),
623 }],
624 });
625
626 let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
627 label: Some("Text Bg Compositor Layout"),
628 bind_group_layouts: &[&vertex_shader_layout],
629 immediate_size: 0,
630 });
631
632 let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
633 label: Some("Text Bg Compositor Pipeline"),
634 layout: Some(&pipeline_layout),
635 vertex: VertexState {
636 module: &shader,
637 entry_point: Some("vs_main"),
638 compilation_options: PipelineCompilationOptions::default(),
639 buffers: &[VertexBufferLayout {
640 array_stride: size_of::<TextBgVertexMember>() as u64,
641 step_mode: VertexStepMode::Vertex,
642 attributes: &vertex_attr_array![0 => Float32x2, 1 => Uint32],
643 }],
644 },
645 primitive: PrimitiveState {
646 topology: PrimitiveTopology::TriangleList,
647 ..Default::default()
648 },
649 depth_stencil: None,
650 multisample: MultisampleState::default(),
651 fragment: Some(FragmentState {
652 module: &shader,
653 entry_point: Some("fs_main"),
654 compilation_options: PipelineCompilationOptions::default(),
655 targets: &[Some(ColorTargetState {
656 format: TextureFormat::Rgba8Unorm,
657 blend: None,
658 write_mask: ColorWrites::ALL,
659 })],
660 }),
661 multiview_mask: None,
662 cache: None,
663 });
664
665 TextCacheBgPipeline {
666 pipeline,
667 fs_uniforms,
668 }
669}
670
671fn build_text_fg_compositor(
672 device: &Device,
673 screen_size: &Buffer,
674 atlas_size: &Buffer,
675 cache_view: &TextureView,
676 mask_view: &TextureView,
677 sampler: &Sampler,
678) -> TextCacheFgPipeline {
679 let shader = device.create_shader_module(include_wgsl!("shaders/composite_fg.wgsl"));
680
681 let vertex_shader_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
682 label: Some("Text Compositor Uniforms Binding Layout"),
683 entries: &[BindGroupLayoutEntry {
684 binding: 0,
685 visibility: ShaderStages::VERTEX,
686 ty: BindingType::Buffer {
687 ty: BufferBindingType::Uniform,
688 has_dynamic_offset: false,
689 min_binding_size: Some(NonZeroU64::new(size_of::<[f32; 4]>() as u64).unwrap()),
690 },
691 count: None,
692 }],
693 });
694
695 let fragment_shader_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
696 label: Some("Text Compositor Fragment Binding Layout"),
697 entries: &[
698 BindGroupLayoutEntry {
699 binding: 0,
700 visibility: ShaderStages::FRAGMENT,
701 ty: BindingType::Texture {
702 sample_type: TextureSampleType::Float { filterable: true },
703 view_dimension: TextureViewDimension::D2,
704 multisampled: false,
705 },
706 count: None,
707 },
708 BindGroupLayoutEntry {
709 binding: 1,
710 visibility: ShaderStages::FRAGMENT,
711 ty: BindingType::Texture {
712 sample_type: TextureSampleType::Float { filterable: true },
713 view_dimension: TextureViewDimension::D2,
714 multisampled: false,
715 },
716 count: None,
717 },
718 BindGroupLayoutEntry {
719 binding: 2,
720 visibility: ShaderStages::FRAGMENT,
721 ty: BindingType::Sampler(SamplerBindingType::Filtering),
722 count: None,
723 },
724 BindGroupLayoutEntry {
725 binding: 3,
726 visibility: ShaderStages::FRAGMENT,
727 ty: BindingType::Buffer {
728 ty: BufferBindingType::Uniform,
729 has_dynamic_offset: false,
730 min_binding_size: Some(NonZeroU64::new(size_of::<[f32; 4]>() as u64).unwrap()),
731 },
732 count: None,
733 },
734 ],
735 });
736
737 let fs_uniforms = device.create_bind_group(&BindGroupDescriptor {
738 label: Some("Text Compositor Uniforms Binding"),
739 layout: &vertex_shader_layout,
740 entries: &[BindGroupEntry {
741 binding: 0,
742 resource: screen_size.as_entire_binding(),
743 }],
744 });
745
746 let atlas_bindings = device.create_bind_group(&BindGroupDescriptor {
747 label: Some("Text Compositor Fragment Binding"),
748 layout: &fragment_shader_layout,
749 entries: &[
750 BindGroupEntry {
751 binding: 0,
752 resource: BindingResource::TextureView(cache_view),
753 },
754 BindGroupEntry {
755 binding: 1,
756 resource: BindingResource::TextureView(mask_view),
757 },
758 BindGroupEntry {
759 binding: 2,
760 resource: BindingResource::Sampler(sampler),
761 },
762 BindGroupEntry {
763 binding: 3,
764 resource: atlas_size.as_entire_binding(),
765 },
766 ],
767 });
768
769 let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
770 label: Some("Text Compositor Layout"),
771 bind_group_layouts: &[&vertex_shader_layout, &fragment_shader_layout],
772 immediate_size: 0,
773 });
774
775 let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
776 label: Some("Text Compositor Pipeline"),
777 layout: Some(&pipeline_layout),
778 vertex: VertexState {
779 module: &shader,
780 entry_point: Some("vs_main"),
781 compilation_options: PipelineCompilationOptions::default(),
782 buffers: &[VertexBufferLayout {
783 array_stride: size_of::<TextVertexMember>() as u64,
784 step_mode: VertexStepMode::Vertex,
785 attributes: &vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Uint32, 3 => Uint32, 4 => Uint32, 5 => Uint32, 6 => Uint32],
786 }],
787 },
788 primitive: PrimitiveState {
789 topology: PrimitiveTopology::TriangleList,
790 ..Default::default()
791 },
792 depth_stencil: None,
793 multisample: MultisampleState::default(),
794 fragment: Some(FragmentState {
795 module: &shader,
796 entry_point: Some("fs_main"),
797 compilation_options: PipelineCompilationOptions::default(),
798 targets: &[Some(ColorTargetState {
799 format: TextureFormat::Rgba8Unorm,
800 blend: Some(BlendState::ALPHA_BLENDING),
801 write_mask: ColorWrites::ALL,
802 })],
803 }),
804 multiview_mask: None,
805 cache: None,
806 });
807
808 TextCacheFgPipeline {
809 pipeline,
810 fs_uniforms,
811 atlas_bindings,
812 }
813}
814
815fn min_limits(
816 adapter: &wgpu::Adapter,
817 limits: Limits,
818) -> Limits {
819 let Limits {
820 max_texture_dimension_1d: max_texture_dimension_1d_wl,
821 max_texture_dimension_2d: max_texture_dimension_2d_wl,
822 max_texture_dimension_3d: max_texture_dimension_3d_wl,
823 max_texture_array_layers: max_texture_array_layers_wl,
824 max_bind_groups: max_bind_groups_wl,
825 max_bindings_per_bind_group: max_bindings_per_bind_group_wl,
826 max_dynamic_uniform_buffers_per_pipeline_layout:
827 max_dynamic_uniform_buffers_per_pipeline_layout_wl,
828 max_dynamic_storage_buffers_per_pipeline_layout:
829 max_dynamic_storage_buffers_per_pipeline_layout_wl,
830 max_sampled_textures_per_shader_stage: max_sampled_textures_per_shader_stage_wl,
831 max_samplers_per_shader_stage: max_samplers_per_shader_stage_wl,
832 max_storage_buffers_per_shader_stage: max_storage_buffers_per_shader_stage_wl,
833 max_storage_textures_per_shader_stage: max_storage_textures_per_shader_stage_wl,
834 max_uniform_buffers_per_shader_stage: max_uniform_buffers_per_shader_stage_wl,
835 max_uniform_buffer_binding_size: max_uniform_buffer_binding_size_wl,
836 max_storage_buffer_binding_size: max_storage_buffer_binding_size_wl,
837 max_vertex_buffers: max_vertex_buffers_wl,
838 max_buffer_size: max_buffer_size_wl,
839 max_vertex_attributes: max_vertex_attributes_wl,
840 max_vertex_buffer_array_stride: max_vertex_buffer_array_stride_wl,
841 min_uniform_buffer_offset_alignment: min_uniform_buffer_offset_alignment_wl,
842 min_storage_buffer_offset_alignment: min_storage_buffer_offset_alignment_wl,
843 max_inter_stage_shader_components: max_inter_stage_shader_components_wl,
844 max_color_attachments: max_color_attachments_wl,
845 max_color_attachment_bytes_per_sample: max_color_attachment_bytes_per_sample_wl,
846 max_compute_workgroup_storage_size: max_compute_workgroup_storage_size_wl,
847 max_compute_invocations_per_workgroup: max_compute_invocations_per_workgroup_wl,
848 max_compute_workgroup_size_x: max_compute_workgroup_size_x_wl,
849 max_compute_workgroup_size_y: max_compute_workgroup_size_y_wl,
850 max_compute_workgroup_size_z: max_compute_workgroup_size_z_wl,
851 max_compute_workgroups_per_dimension: max_compute_workgroups_per_dimension_wl,
852 max_non_sampler_bindings: max_non_sampler_bindings_wl,
853 max_binding_array_elements_per_shader_stage: max_binding_array_elements_per_shader_stage_wl,
854 max_binding_array_sampler_elements_per_shader_stage:
855 max_binding_array_sampler_elements_per_shader_stage_wl,
856 max_blas_primitive_count: max_blas_primitive_count_wl,
857 max_blas_geometry_count: max_blas_geometry_count_wl,
858 max_tlas_instance_count: max_tlas_instance_count_wl,
859 max_acceleration_structures_per_shader_stage:
860 max_acceleration_structures_per_shader_stage_wl,
861 max_immediate_size: max_immediate_size_wl,
862 max_task_mesh_workgroup_total_count: max_task_mesh_workgroup_total_count_wl,
863 max_task_mesh_workgroups_per_dimension: max_task_mesh_workgroups_per_dimension_wl,
864 max_task_invocations_per_workgroup: max_task_invocations_per_workgroup_wl,
865 max_task_invocations_per_dimension: max_task_invocations_per_dimension_wl,
866 max_mesh_invocations_per_workgroup: max_mesh_invocations_per_workgroup_wl,
867 max_mesh_invocations_per_dimension: max_mesh_invocations_per_dimension_wl,
868 max_task_payload_size: max_task_payload_size_wl,
869 max_mesh_output_vertices: max_mesh_output_vertices_wl,
870 max_mesh_output_primitives: max_mesh_output_primitives_wl,
871 max_mesh_output_layers: max_mesh_output_layers_wl,
872 max_mesh_multiview_view_count: max_mesh_multiview_view_count_wl,
873 max_multiview_view_count: max_multiview_view_count_wl,
874 } = limits;
875 let Limits {
876 max_texture_dimension_1d: max_texture_dimension_1d_al,
877 max_texture_dimension_2d: max_texture_dimension_2d_al,
878 max_texture_dimension_3d: max_texture_dimension_3d_al,
879 max_texture_array_layers: max_texture_array_layers_al,
880 max_bind_groups: max_bind_groups_al,
881 max_bindings_per_bind_group: max_bindings_per_bind_group_al,
882 max_dynamic_uniform_buffers_per_pipeline_layout:
883 max_dynamic_uniform_buffers_per_pipeline_layout_al,
884 max_dynamic_storage_buffers_per_pipeline_layout:
885 max_dynamic_storage_buffers_per_pipeline_layout_al,
886 max_sampled_textures_per_shader_stage: max_sampled_textures_per_shader_stage_al,
887 max_samplers_per_shader_stage: max_samplers_per_shader_stage_al,
888 max_storage_buffers_per_shader_stage: max_storage_buffers_per_shader_stage_al,
889 max_storage_textures_per_shader_stage: max_storage_textures_per_shader_stage_al,
890 max_uniform_buffers_per_shader_stage: max_uniform_buffers_per_shader_stage_al,
891 max_uniform_buffer_binding_size: max_uniform_buffer_binding_size_al,
892 max_storage_buffer_binding_size: max_storage_buffer_binding_size_al,
893 max_vertex_buffers: max_vertex_buffers_al,
894 max_buffer_size: max_buffer_size_al,
895 max_vertex_attributes: max_vertex_attributes_al,
896 max_vertex_buffer_array_stride: max_vertex_buffer_array_stride_al,
897 min_uniform_buffer_offset_alignment: min_uniform_buffer_offset_alignment_al,
898 min_storage_buffer_offset_alignment: min_storage_buffer_offset_alignment_al,
899 max_inter_stage_shader_components: max_inter_stage_shader_components_al,
900 max_color_attachments: max_color_attachments_al,
901 max_color_attachment_bytes_per_sample: max_color_attachment_bytes_per_sample_al,
902 max_compute_workgroup_storage_size: max_compute_workgroup_storage_size_al,
903 max_compute_invocations_per_workgroup: max_compute_invocations_per_workgroup_al,
904 max_compute_workgroup_size_x: max_compute_workgroup_size_x_al,
905 max_compute_workgroup_size_y: max_compute_workgroup_size_y_al,
906 max_compute_workgroup_size_z: max_compute_workgroup_size_z_al,
907 max_compute_workgroups_per_dimension: max_compute_workgroups_per_dimension_al,
908 max_non_sampler_bindings: max_non_sampler_bindings_al,
909 max_binding_array_elements_per_shader_stage: max_binding_array_elements_per_shader_stage_al,
910 max_binding_array_sampler_elements_per_shader_stage:
911 max_binding_array_sampler_elements_per_shader_stage_al,
912 max_blas_primitive_count: max_blas_primitive_count_al,
913 max_blas_geometry_count: max_blas_geometry_count_al,
914 max_tlas_instance_count: max_tlas_instance_count_al,
915 max_acceleration_structures_per_shader_stage:
916 max_acceleration_structures_per_shader_stage_al,
917 max_immediate_size: max_immediate_size_al,
918 max_task_mesh_workgroup_total_count: max_task_mesh_workgroup_total_count_al,
919 max_task_mesh_workgroups_per_dimension: max_task_mesh_workgroups_per_dimension_al,
920 max_task_invocations_per_workgroup: max_task_invocations_per_workgroup_al,
921 max_task_invocations_per_dimension: max_task_invocations_per_dimension_al,
922 max_mesh_invocations_per_workgroup: max_mesh_invocations_per_workgroup_al,
923 max_mesh_invocations_per_dimension: max_mesh_invocations_per_dimension_al,
924 max_task_payload_size: max_task_payload_size_al,
925 max_mesh_output_vertices: max_mesh_output_vertices_al,
926 max_mesh_output_primitives: max_mesh_output_primitives_al,
927 max_mesh_output_layers: max_mesh_output_layers_al,
928 max_mesh_multiview_view_count: max_mesh_multiview_view_count_al,
929 max_multiview_view_count: max_multiview_view_count_al,
930 } = adapter.limits();
931
932 Limits {
933 max_texture_dimension_1d: if max_texture_dimension_1d_wl <= max_texture_dimension_1d_al {
934 max_texture_dimension_1d_wl
935 } else {
936 max_texture_dimension_1d_al
937 },
938 max_texture_dimension_2d: if max_texture_dimension_2d_wl <= max_texture_dimension_2d_al {
939 max_texture_dimension_2d_wl
940 } else {
941 max_texture_dimension_2d_al
942 },
943 max_texture_dimension_3d: if max_texture_dimension_3d_wl <= max_texture_dimension_3d_al {
944 max_texture_dimension_3d_wl
945 } else {
946 max_texture_dimension_3d_al
947 },
948 max_texture_array_layers: if max_texture_array_layers_wl <= max_texture_array_layers_al {
949 max_texture_array_layers_wl
950 } else {
951 max_texture_array_layers_al
952 },
953 max_bind_groups: if max_bind_groups_wl <= max_bind_groups_al {
954 max_bind_groups_wl
955 } else {
956 max_bind_groups_al
957 },
958 max_bindings_per_bind_group: if max_bindings_per_bind_group_wl
959 <= max_bindings_per_bind_group_al
960 {
961 max_bindings_per_bind_group_wl
962 } else {
963 max_bindings_per_bind_group_al
964 },
965 max_dynamic_uniform_buffers_per_pipeline_layout:
966 if max_dynamic_uniform_buffers_per_pipeline_layout_wl
967 <= max_dynamic_uniform_buffers_per_pipeline_layout_al
968 {
969 max_dynamic_uniform_buffers_per_pipeline_layout_wl
970 } else {
971 max_dynamic_uniform_buffers_per_pipeline_layout_al
972 },
973 max_dynamic_storage_buffers_per_pipeline_layout:
974 if max_dynamic_storage_buffers_per_pipeline_layout_wl
975 <= max_dynamic_storage_buffers_per_pipeline_layout_al
976 {
977 max_dynamic_storage_buffers_per_pipeline_layout_wl
978 } else {
979 max_dynamic_storage_buffers_per_pipeline_layout_al
980 },
981 max_sampled_textures_per_shader_stage: if max_sampled_textures_per_shader_stage_wl
982 <= max_sampled_textures_per_shader_stage_al
983 {
984 max_sampled_textures_per_shader_stage_wl
985 } else {
986 max_sampled_textures_per_shader_stage_al
987 },
988 max_samplers_per_shader_stage: if max_samplers_per_shader_stage_wl
989 <= max_samplers_per_shader_stage_al
990 {
991 max_samplers_per_shader_stage_wl
992 } else {
993 max_samplers_per_shader_stage_al
994 },
995 max_storage_buffers_per_shader_stage: if max_storage_buffers_per_shader_stage_wl
996 <= max_storage_buffers_per_shader_stage_al
997 {
998 max_storage_buffers_per_shader_stage_wl
999 } else {
1000 max_storage_buffers_per_shader_stage_al
1001 },
1002 max_storage_textures_per_shader_stage: if max_storage_textures_per_shader_stage_wl
1003 <= max_storage_textures_per_shader_stage_al
1004 {
1005 max_storage_textures_per_shader_stage_wl
1006 } else {
1007 max_storage_textures_per_shader_stage_al
1008 },
1009 max_uniform_buffers_per_shader_stage: if max_uniform_buffers_per_shader_stage_wl
1010 <= max_uniform_buffers_per_shader_stage_al
1011 {
1012 max_uniform_buffers_per_shader_stage_wl
1013 } else {
1014 max_uniform_buffers_per_shader_stage_al
1015 },
1016 max_uniform_buffer_binding_size: if max_uniform_buffer_binding_size_wl
1017 <= max_uniform_buffer_binding_size_al
1018 {
1019 max_uniform_buffer_binding_size_wl
1020 } else {
1021 max_uniform_buffer_binding_size_al
1022 },
1023 max_storage_buffer_binding_size: if max_storage_buffer_binding_size_wl
1024 <= max_storage_buffer_binding_size_al
1025 {
1026 max_storage_buffer_binding_size_wl
1027 } else {
1028 max_storage_buffer_binding_size_al
1029 },
1030 max_vertex_buffers: if max_vertex_buffers_wl <= max_vertex_buffers_al {
1031 max_vertex_buffers_wl
1032 } else {
1033 max_vertex_buffers_al
1034 },
1035 max_buffer_size: if max_buffer_size_wl <= max_buffer_size_al {
1036 max_buffer_size_wl
1037 } else {
1038 max_buffer_size_al
1039 },
1040 max_vertex_attributes: if max_vertex_attributes_wl <= max_vertex_attributes_al {
1041 max_vertex_attributes_wl
1042 } else {
1043 max_vertex_attributes_al
1044 },
1045 max_vertex_buffer_array_stride: if max_vertex_buffer_array_stride_wl
1046 <= max_vertex_buffer_array_stride_al
1047 {
1048 max_vertex_buffer_array_stride_wl
1049 } else {
1050 max_vertex_buffer_array_stride_al
1051 },
1052 min_uniform_buffer_offset_alignment: if min_uniform_buffer_offset_alignment_wl
1053 <= min_uniform_buffer_offset_alignment_al
1054 {
1055 min_uniform_buffer_offset_alignment_wl
1056 } else {
1057 min_uniform_buffer_offset_alignment_al
1058 },
1059 min_storage_buffer_offset_alignment: if min_storage_buffer_offset_alignment_wl
1060 <= min_storage_buffer_offset_alignment_al
1061 {
1062 min_storage_buffer_offset_alignment_wl
1063 } else {
1064 min_storage_buffer_offset_alignment_al
1065 },
1066 max_inter_stage_shader_components: if max_inter_stage_shader_components_wl
1067 <= max_inter_stage_shader_components_al
1068 {
1069 max_inter_stage_shader_components_wl
1070 } else {
1071 max_inter_stage_shader_components_al
1072 },
1073 max_color_attachments: if max_color_attachments_wl <= max_color_attachments_al {
1074 max_color_attachments_wl
1075 } else {
1076 max_color_attachments_al
1077 },
1078 max_color_attachment_bytes_per_sample: if max_color_attachment_bytes_per_sample_wl
1079 <= max_color_attachment_bytes_per_sample_al
1080 {
1081 max_color_attachment_bytes_per_sample_wl
1082 } else {
1083 max_color_attachment_bytes_per_sample_al
1084 },
1085 max_compute_workgroup_storage_size: if max_compute_workgroup_storage_size_wl
1086 <= max_compute_workgroup_storage_size_al
1087 {
1088 max_compute_workgroup_storage_size_wl
1089 } else {
1090 max_compute_workgroup_storage_size_al
1091 },
1092 max_compute_invocations_per_workgroup: if max_compute_invocations_per_workgroup_wl
1093 <= max_compute_invocations_per_workgroup_al
1094 {
1095 max_compute_invocations_per_workgroup_wl
1096 } else {
1097 max_compute_invocations_per_workgroup_al
1098 },
1099 max_compute_workgroup_size_x: if max_compute_workgroup_size_x_wl
1100 <= max_compute_workgroup_size_x_al
1101 {
1102 max_compute_workgroup_size_x_wl
1103 } else {
1104 max_compute_workgroup_size_x_al
1105 },
1106 max_compute_workgroup_size_y: if max_compute_workgroup_size_y_wl
1107 <= max_compute_workgroup_size_y_al
1108 {
1109 max_compute_workgroup_size_y_wl
1110 } else {
1111 max_compute_workgroup_size_y_al
1112 },
1113 max_compute_workgroup_size_z: if max_compute_workgroup_size_z_wl
1114 <= max_compute_workgroup_size_z_al
1115 {
1116 max_compute_workgroup_size_z_wl
1117 } else {
1118 max_compute_workgroup_size_z_al
1119 },
1120 max_compute_workgroups_per_dimension: if max_compute_workgroups_per_dimension_wl
1121 <= max_compute_workgroups_per_dimension_al
1122 {
1123 max_compute_workgroups_per_dimension_wl
1124 } else {
1125 max_compute_workgroups_per_dimension_al
1126 },
1127 max_non_sampler_bindings: if max_non_sampler_bindings_wl <= max_non_sampler_bindings_al {
1128 max_non_sampler_bindings_wl
1129 } else {
1130 max_non_sampler_bindings_al
1131 },
1132 max_binding_array_elements_per_shader_stage:
1133 if max_binding_array_elements_per_shader_stage_wl
1134 <= max_binding_array_elements_per_shader_stage_al
1135 {
1136 max_binding_array_elements_per_shader_stage_wl
1137 } else {
1138 max_binding_array_elements_per_shader_stage_al
1139 },
1140 max_binding_array_sampler_elements_per_shader_stage:
1141 if max_binding_array_sampler_elements_per_shader_stage_wl
1142 <= max_binding_array_sampler_elements_per_shader_stage_al
1143 {
1144 max_binding_array_sampler_elements_per_shader_stage_wl
1145 } else {
1146 max_binding_array_sampler_elements_per_shader_stage_al
1147 },
1148 max_blas_primitive_count: if max_blas_primitive_count_wl <= max_blas_primitive_count_al {
1149 max_blas_primitive_count_wl
1150 } else {
1151 max_blas_primitive_count_al
1152 },
1153 max_blas_geometry_count: if max_blas_geometry_count_wl <= max_blas_geometry_count_al {
1154 max_blas_geometry_count_wl
1155 } else {
1156 max_blas_geometry_count_al
1157 },
1158 max_tlas_instance_count: if max_tlas_instance_count_wl <= max_tlas_instance_count_al {
1159 max_tlas_instance_count_wl
1160 } else {
1161 max_tlas_instance_count_al
1162 },
1163 max_acceleration_structures_per_shader_stage:
1164 if max_acceleration_structures_per_shader_stage_wl
1165 <= max_acceleration_structures_per_shader_stage_al
1166 {
1167 max_acceleration_structures_per_shader_stage_wl
1168 } else {
1169 max_acceleration_structures_per_shader_stage_al
1170 },
1171 max_immediate_size: if max_immediate_size_wl <= max_immediate_size_al {
1172 max_immediate_size_wl
1173 } else {
1174 max_immediate_size_al
1175 },
1176 max_task_mesh_workgroup_total_count: if max_task_mesh_workgroup_total_count_wl
1177 <= max_task_mesh_workgroup_total_count_al
1178 {
1179 max_task_mesh_workgroup_total_count_wl
1180 } else {
1181 max_task_mesh_workgroup_total_count_al
1182 },
1183 max_task_mesh_workgroups_per_dimension: if max_task_mesh_workgroups_per_dimension_wl
1184 <= max_task_mesh_workgroups_per_dimension_al
1185 {
1186 max_task_mesh_workgroups_per_dimension_wl
1187 } else {
1188 max_task_mesh_workgroups_per_dimension_al
1189 },
1190 max_task_invocations_per_workgroup: if max_task_invocations_per_workgroup_wl
1191 <= max_task_invocations_per_workgroup_al
1192 {
1193 max_task_invocations_per_workgroup_wl
1194 } else {
1195 max_task_invocations_per_workgroup_al
1196 },
1197 max_task_invocations_per_dimension: if max_task_invocations_per_dimension_wl
1198 <= max_task_invocations_per_dimension_al
1199 {
1200 max_task_invocations_per_dimension_wl
1201 } else {
1202 max_task_invocations_per_dimension_al
1203 },
1204 max_mesh_invocations_per_workgroup: if max_mesh_invocations_per_workgroup_wl
1205 <= max_mesh_invocations_per_workgroup_al
1206 {
1207 max_mesh_invocations_per_workgroup_wl
1208 } else {
1209 max_mesh_invocations_per_workgroup_al
1210 },
1211 max_mesh_invocations_per_dimension: if max_mesh_invocations_per_dimension_wl
1212 <= max_mesh_invocations_per_dimension_al
1213 {
1214 max_mesh_invocations_per_dimension_wl
1215 } else {
1216 max_mesh_invocations_per_dimension_al
1217 },
1218 max_task_payload_size: if max_task_payload_size_wl <= max_task_payload_size_al {
1219 max_task_payload_size_wl
1220 } else {
1221 max_task_payload_size_al
1222 },
1223 max_mesh_output_vertices: if max_mesh_output_vertices_wl <= max_mesh_output_vertices_al {
1224 max_mesh_output_vertices_wl
1225 } else {
1226 max_mesh_output_vertices_al
1227 },
1228 max_mesh_output_primitives: if max_mesh_output_primitives_wl
1229 <= max_mesh_output_primitives_al
1230 {
1231 max_mesh_output_primitives_wl
1232 } else {
1233 max_mesh_output_primitives_al
1234 },
1235 max_mesh_output_layers: if max_mesh_output_layers_wl <= max_mesh_output_layers_al {
1236 max_mesh_output_layers_wl
1237 } else {
1238 max_mesh_output_layers_al
1239 },
1240 max_mesh_multiview_view_count: if max_mesh_multiview_view_count_wl
1241 <= max_mesh_multiview_view_count_al
1242 {
1243 max_mesh_multiview_view_count_wl
1244 } else {
1245 max_mesh_multiview_view_count_al
1246 },
1247 max_multiview_view_count: if max_multiview_view_count_wl <= max_multiview_view_count_al {
1248 max_multiview_view_count_wl
1249 } else {
1250 max_multiview_view_count_al
1251 },
1252 }
1253}