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