1use std::borrow::Cow;
8use std::slice;
9use std::sync::{Arc, Mutex};
10
11use log::{info, warn};
12use paint_api::{CrossProcessPaintApi, WebRenderExternalImageIdManager, WebRenderImageHandlerType};
13use rustc_hash::FxHashMap;
14use servo_base::generic_channel::{GenericReceiver, GenericSender, GenericSharedMemory};
15use servo_base::id::PipelineId;
16use servo_config::pref;
17use webgpu_traits::id::DeviceId;
18use webgpu_traits::{
19 Adapter, BufferAddress, ComputePassDescriptor, DeviceDescriptor, DeviceLostReason, Error,
20 ErrorScope, ExperimentalFeatures, Extent3d, Mapping, MemoryHints, Origin3d, Pipeline, PopError,
21 RenderPassDescriptor, ShaderCompilationInfo, ShaderModuleDescriptor, TexelCopyBufferLayout,
22 TexelCopyTextureInfo, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat,
23 TextureUsages, TextureViewDescriptor, WebGPU, WebGPUAdapter, WebGPUContextId, WebGPUDevice,
24 WebGPUMsg, WebGPUQueue, WebGPURequest, id,
25};
26use webrender_api::ExternalImageId;
27use wgpu_core::resource::{BufferAccessResult, BufferMapOperation};
28use wgpu_types::error::WebGpuError;
29use wgpu_types::{
30 ExternalTextureDescriptor, ExternalTextureFormat, ExternalTextureTransferFunction,
31 InstanceDescriptor,
32};
33
34use crate::canvas_context::WebGpuExternalImageMap;
35use crate::encoders::{
36 handle_command_encoder_command, handle_compute_pass_command, handle_render_bundle_command,
37 handle_render_pass_command,
38};
39use crate::poll_thread::Poller;
40
41#[derive(Eq, Hash, PartialEq)]
42pub(crate) struct DeviceScope {
43 pub device_id: DeviceId,
44 pub pipeline_id: PipelineId,
45 pub error_scope_stack: Option<Vec<ErrorScope>>,
49 }
55
56impl DeviceScope {
57 pub fn new(device_id: DeviceId, pipeline_id: PipelineId) -> Self {
58 Self {
59 device_id,
60 pipeline_id,
61 error_scope_stack: Some(Vec::new()),
62 }
63 }
64}
65
66#[expect(clippy::upper_case_acronyms)] pub(crate) struct WGPU {
68 receiver: GenericReceiver<WebGPURequest>,
69 sender: GenericSender<WebGPURequest>,
70 pub(crate) script_sender: GenericSender<WebGPUMsg>,
71 pub(crate) global: Arc<wgpu_core::global::Global>,
72 devices: Arc<Mutex<FxHashMap<DeviceId, DeviceScope>>>,
73 pub(crate) paint_api: CrossProcessPaintApi,
74 pub(crate) webrender_external_image_id_manager: WebRenderExternalImageIdManager,
75 pub(crate) wgpu_image_map: WebGpuExternalImageMap,
76 pub(crate) poller: Poller,
78}
79
80impl WGPU {
81 pub(crate) fn new(
82 receiver: GenericReceiver<WebGPURequest>,
83 sender: GenericSender<WebGPURequest>,
84 script_sender: GenericSender<WebGPUMsg>,
85 paint_api: CrossProcessPaintApi,
86 webrender_external_image_id_manager: WebRenderExternalImageIdManager,
87 wgpu_image_map: WebGpuExternalImageMap,
88 ) -> Self {
89 let backend_pref = pref!(dom_webgpu_wgpu_backend);
90 let backends = if backend_pref.is_empty() {
91 wgpu_types::Backends::PRIMARY
92 } else {
93 info!(
94 "Selecting backends based on dom.webgpu.wgpu_backend pref: {:?}",
95 backend_pref
96 );
97 wgpu_types::Backends::from_comma_list(&backend_pref)
98 };
99 let global = Arc::new(wgpu_core::global::Global::new(
100 "wgpu-core",
101 InstanceDescriptor {
102 backends,
103 backend_options: wgpu_types::BackendOptions {
104 gl: wgpu_types::GlBackendOptions {
105 gles_minor_version: wgpu_types::Gles3MinorVersion::Automatic,
106 fence_behavior: wgpu_types::GlFenceBehavior::Normal,
107 debug_fns: wgpu_types::GlDebugFns::Auto,
108 },
109 dx12: wgpu_types::Dx12BackendOptions {
110 ..Default::default()
111 },
112 noop: wgpu_types::NoopBackendOptions::default(),
113 },
114
115 flags: wgpu_types::InstanceFlags::from_build_config() |
116 wgpu_types::InstanceFlags::AUTOMATIC_TIMESTAMP_NORMALIZATION |
117 wgpu_types::InstanceFlags::STRICT_WEBGPU_COMPLIANCE,
118 memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds {
121 for_resource_creation: Some(95),
122 for_device_loss: Some(99),
123 },
124 display: None,
125 },
126 None,
127 ));
128 WGPU {
129 poller: Poller::new(Arc::clone(&global)),
130 receiver,
131 sender,
132 script_sender,
133 global,
134 devices: Arc::new(Mutex::new(FxHashMap::default())),
135 paint_api,
136 webrender_external_image_id_manager,
137 wgpu_image_map,
138 }
139 }
140
141 pub(crate) fn run(&mut self) {
142 loop {
143 if let Ok(msg) = self.receiver.recv() {
144 log::trace!("recv: {msg:?}");
145 match msg {
146 WebGPURequest::SetImageKey {
147 context_id,
148 image_key,
149 } => self.set_image_key(context_id, image_key),
150 WebGPURequest::BufferMapAsync {
151 callback: sender,
152 buffer_id,
153 device_id,
154 host_map,
155 offset,
156 size,
157 } => {
158 let glob = Arc::clone(&self.global);
159 let resp_sender = sender.clone();
160 let token = self.poller.token();
161 let callback = Box::from(move |result: BufferAccessResult| {
162 drop(token);
163 let response = result.and_then(|_| {
164 let global = &glob;
165 let (slice_pointer, range_size) =
166 global.buffer_get_mapped_range(buffer_id, offset, size)?;
167 let data = unsafe {
169 slice::from_raw_parts(
170 slice_pointer.as_ptr(),
171 range_size as usize,
172 )
173 };
174
175 Ok(Mapping {
176 data: GenericSharedMemory::from_bytes(data),
177 range: offset..offset + range_size,
178 mode: host_map,
179 })
180 });
181 if let Err(e) = resp_sender.send(response) {
182 warn!("Could not send BufferMapAsync Response ({})", e);
183 }
184 });
185
186 let operation = BufferMapOperation {
187 host: host_map,
188 callback: Some(callback),
189 };
190 let global = &self.global;
191 let result = global.buffer_map_async(buffer_id, offset, size, operation);
192 self.poller.wake();
193 self.maybe_dispatch_wgpu_error(device_id, result.err());
195 },
196 WebGPURequest::CommandEncoderFinish {
197 command_encoder_id,
198 device_id,
199 desc,
200 command_buffer_id,
201 } => {
202 let global = &self.global;
203 let (_, error) = global.command_encoder_finish(
204 command_encoder_id,
205 &desc,
206 Some(command_buffer_id),
207 );
208 self.maybe_dispatch_wgpu_error(device_id, error.map(|(_, e)| e));
209 },
210 WebGPURequest::CommandEncoderCommand {
211 command_encoder_id,
212 command,
213 device_id,
214 } => {
215 let global = &self.global;
216 let result =
217 handle_command_encoder_command(global, command_encoder_id, command);
218 self.maybe_dispatch_wgpu_error(device_id, result.err());
219 },
220 WebGPURequest::CreateBindGroup {
221 device_id,
222 bind_group_id,
223 descriptor,
224 } => {
225 let global = &self.global;
226 let (_, error) = global.device_create_bind_group(
227 device_id,
228 &descriptor,
229 Some(bind_group_id),
230 );
231 self.maybe_dispatch_wgpu_error(device_id, error);
232 },
233 WebGPURequest::CreateBindGroupLayout {
234 device_id,
235 bind_group_layout_id,
236 descriptor,
237 } => {
238 let global = &self.global;
239 if let Some(desc) = descriptor {
240 let (_, error) = global.device_create_bind_group_layout(
241 device_id,
242 &desc,
243 Some(bind_group_layout_id),
244 );
245
246 self.maybe_dispatch_wgpu_error(device_id, error);
247 }
248 },
249 WebGPURequest::CreateBuffer {
250 device_id,
251 buffer_id,
252 descriptor,
253 } => {
254 let global = &self.global;
255 let (_, error) =
256 global.device_create_buffer(device_id, &descriptor, Some(buffer_id));
257
258 self.maybe_dispatch_wgpu_error(device_id, error);
259 },
260 WebGPURequest::CreateCommandEncoder {
261 device_id,
262 command_encoder_id,
263 desc,
264 } => {
265 let global = &self.global;
266 let (_, error) = global.device_create_command_encoder(
267 device_id,
268 &desc,
269 Some(command_encoder_id),
270 );
271
272 self.maybe_dispatch_wgpu_error(device_id, error);
273 },
274 WebGPURequest::CreateComputePipeline {
275 device_id,
276 compute_pipeline_id,
277 descriptor,
278 async_sender: sender,
279 } => {
280 let global = &self.global;
281 let (_, error) = global.device_create_compute_pipeline(
282 device_id,
283 &descriptor,
284 Some(compute_pipeline_id),
285 );
286 if let Some(sender) = sender {
287 let res = match error.and_then(Error::from_wgpu_error) {
288 None => Ok(Pipeline {
290 id: compute_pipeline_id,
291 label: descriptor.label.unwrap_or_default().to_string(),
292 }),
293 Some(e) => Err(e),
294 };
295 if let Err(e) = sender.send(res) {
296 warn!("Failed sending WebGPUComputePipelineResponse {e:?}");
297 }
298 } else {
299 self.maybe_dispatch_wgpu_error(device_id, error);
300 }
301 },
302 WebGPURequest::CreatePipelineLayout {
303 device_id,
304 pipeline_layout_id,
305 descriptor,
306 } => {
307 let global = &self.global;
308 let (_, error) = global.device_create_pipeline_layout(
309 device_id,
310 &descriptor,
311 Some(pipeline_layout_id),
312 );
313 self.maybe_dispatch_wgpu_error(device_id, error);
314 },
315 WebGPURequest::CreateRenderPipeline {
316 device_id,
317 render_pipeline_id,
318 descriptor,
319 async_sender: sender,
320 } => {
321 let global = &self.global;
322 let (_, error) = global.device_create_render_pipeline(
323 device_id,
324 &descriptor,
325 Some(render_pipeline_id),
326 );
327
328 if let Some(sender) = sender {
329 let res = match error.and_then(Error::from_wgpu_error) {
330 None => Ok(Pipeline {
332 id: render_pipeline_id,
333 label: descriptor.label.unwrap_or_default().to_string(),
334 }),
335 Some(e) => Err(e),
336 };
337 if let Err(e) = sender.send(res) {
338 warn!("Failed sending WebGPURenderPipelineResponse {e:?}");
339 }
340 } else {
341 self.maybe_dispatch_wgpu_error(device_id, error);
342 }
343 },
344 WebGPURequest::CreateSampler {
345 device_id,
346 sampler_id,
347 descriptor,
348 } => {
349 let global = &self.global;
350 let (_, error) =
351 global.device_create_sampler(device_id, &descriptor, Some(sampler_id));
352 self.maybe_dispatch_wgpu_error(device_id, error);
353 },
354 WebGPURequest::CreateShaderModule {
355 device_id,
356 program_id,
357 program,
358 label,
359 callback: sender,
360 } => {
361 let global = &self.global;
362 let source =
363 wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::Borrowed(&program));
364 let desc = ShaderModuleDescriptor {
365 label: label.map(|s| s.into()),
366 runtime_checks: wgpu_types::ShaderRuntimeChecks::checked(),
367 };
368 let (_, error) = global.device_create_shader_module(
369 device_id,
370 &desc,
371 source,
372 Some(program_id),
373 );
374 if let Err(e) = sender.send(
375 error
376 .as_ref()
377 .map(|e| ShaderCompilationInfo::from(e, &program)),
378 ) {
379 warn!("Failed to send CompilationInfo {e:?}");
380 }
381 self.maybe_dispatch_wgpu_error(device_id, error);
382 },
383 WebGPURequest::CreateContext {
384 buffer_ids,
385 size,
386 sender,
387 } => {
388 let id = self
389 .webrender_external_image_id_manager
390 .next_id(WebRenderImageHandlerType::WebGpu);
391 let context_id = WebGPUContextId(id.0);
392
393 if let Err(error) = sender.send(context_id) {
394 warn!("Failed to send ContextId to new context ({error})");
395 };
396
397 self.create_context(context_id, size, buffer_ids);
398 },
399 WebGPURequest::Present {
400 context_id,
401 pending_texture,
402 size,
403 canvas_epoch,
404 } => {
405 self.present(context_id, pending_texture, size, canvas_epoch);
406 },
407 WebGPURequest::GetImage {
408 context_id,
409 pending_texture,
410 sender,
411 } => self.get_image(context_id, pending_texture, sender),
412 WebGPURequest::ValidateTextureDescriptor {
413 device_id,
414 texture_id,
415 descriptor,
416 } => {
417 let global = &self.global;
420 let (_, error) =
421 global.device_create_texture(device_id, &descriptor, Some(texture_id));
422 global.texture_drop(texture_id);
423 self.poller.wake();
424 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(texture_id))
425 {
426 warn!("Unable to send FreeTexture({:?}) ({:?})", texture_id, e);
427 };
428 self.maybe_dispatch_wgpu_error(device_id, error);
429 },
430 WebGPURequest::DestroyContext { context_id } => {
431 self.destroy_context(context_id);
432 self.webrender_external_image_id_manager
433 .remove(&ExternalImageId(context_id.0));
434 },
435 WebGPURequest::CreateTexture {
436 device_id,
437 texture_id,
438 descriptor,
439 } => {
440 let global = &self.global;
441 let (_, error) =
442 global.device_create_texture(device_id, &descriptor, Some(texture_id));
443 self.maybe_dispatch_wgpu_error(device_id, error);
444 },
445 WebGPURequest::CreateTextureView {
446 texture_id,
447 texture_view_id,
448 device_id,
449 descriptor,
450 } => {
451 let global = &self.global;
452 if let Some(desc) = descriptor {
453 let (_, error) = global.texture_create_view(
454 texture_id,
455 &desc,
456 Some(texture_view_id),
457 );
458
459 self.maybe_dispatch_wgpu_error(device_id, error);
460 }
461 },
462 WebGPURequest::DestroyBuffer(buffer) => {
463 let global = &self.global;
464 global.buffer_destroy(buffer);
465 },
466 WebGPURequest::DestroyDevice(device) => {
467 let global = &self.global;
468 global.device_destroy(device);
469 self.poller.wake();
471 },
472 WebGPURequest::DestroyTexture(texture_id) => {
473 let global = &self.global;
474 global.texture_destroy(texture_id);
475 },
476 WebGPURequest::Exit(sender) => {
477 if let Err(e) = sender.send(()) {
478 warn!("Failed to send response to WebGPURequest::Exit ({})", e)
479 }
480 break;
481 },
482 WebGPURequest::DropCommandEncoder(id) => {
483 let global = &self.global;
484 global.command_encoder_drop(id);
485 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeCommandEncoder(id)) {
486 warn!("Unable to send FreeCommandEncoder({:?}) ({:?})", id, e);
487 };
488 },
489 WebGPURequest::DropCommandBuffer(id) => {
490 let global = &self.global;
491 global.command_buffer_drop(id);
492 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeCommandBuffer(id)) {
493 warn!("Unable to send FreeCommandBuffer({:?}) ({:?})", id, e);
494 };
495 },
496 WebGPURequest::DropDevice(device_id) => {
497 let global = &self.global;
498 global.device_drop(device_id);
499 let device_scope = self
500 .devices
501 .lock()
502 .unwrap()
503 .remove(&device_id)
504 .expect("Device should not be dropped by this point");
505 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeDevice {
506 device_id,
507 pipeline_id: device_scope.pipeline_id,
508 }) {
509 warn!("Unable to send FreeDevice({:?}) ({:?})", device_id, e);
510 };
511 },
512 WebGPURequest::RequestAdapter {
513 sender,
514 options,
515 adapter_id,
516 } => {
517 let global = &self.global;
518 let response = self
519 .global
520 .request_adapter(
521 &options,
522 wgpu_types::Backends::all(),
523 Some(adapter_id),
524 )
525 .map(|adapter_id| {
526 let adapter_info = global.adapter_get_info(adapter_id);
528 let limits = global.adapter_limits(adapter_id);
529 let features = global.adapter_features(adapter_id);
530 Adapter {
531 adapter_info,
532 adapter_id: WebGPUAdapter(adapter_id),
533 features,
534 limits,
535 channel: WebGPU(self.sender.clone()),
536 }
537 })
538 .map_err(|err| err.to_string());
539
540 if let Err(e) = sender.send(Some(response)) {
541 warn!(
542 "Failed to send response to WebGPURequest::RequestAdapter ({})",
543 e
544 )
545 }
546 },
547 WebGPURequest::RequestDevice {
548 sender,
549 adapter_id,
550 descriptor,
551 device_id,
552 queue_id,
553 pipeline_id,
554 } => {
555 let mut desc = DeviceDescriptor {
556 label: descriptor.label.as_ref().map(crate::Cow::from),
557 required_features: descriptor.required_features,
558 required_limits: descriptor.required_limits.clone(),
559 memory_hints: MemoryHints::MemoryUsage,
560 trace: wgpu_types::Trace::Off,
561 experimental_features: ExperimentalFeatures::disabled(),
562 };
563 let global = &self.global;
564 let features = global.adapter_features(adapter_id.0);
566 if features.contains(wgpu_types::Features::EXTERNAL_TEXTURE) {
567 desc.required_features |= wgpu_types::Features::EXTERNAL_TEXTURE;
568 }
569 let device = WebGPUDevice(device_id);
570 let queue = WebGPUQueue(queue_id);
571 let result = global
572 .adapter_request_device(
573 adapter_id.0,
574 &desc,
575 Some(device_id),
576 Some(queue_id),
577 )
578 .map(|_| {
579 {
580 self.devices.lock().unwrap().insert(
581 device_id,
582 DeviceScope::new(device_id, pipeline_id),
583 );
584 }
585 let script_sender = self.script_sender.clone();
586 let devices = Arc::clone(&self.devices);
587 let callback = Box::from(move |reason, msg| {
588 let reason = match reason {
589 wgpu_types::DeviceLostReason::Unknown => {
590 DeviceLostReason::Unknown
591 },
592 wgpu_types::DeviceLostReason::Destroyed => {
593 DeviceLostReason::Destroyed
594 },
595 };
596 let _ = devices
598 .lock()
599 .unwrap()
600 .get_mut(&device_id)
601 .expect("Device should not be dropped by this point")
602 .error_scope_stack
603 .take();
604 if let Err(e) = script_sender.send(WebGPUMsg::DeviceLost {
605 device,
606 pipeline_id,
607 reason,
608 msg,
609 }) {
610 warn!("Failed to send WebGPUMsg::DeviceLost: {e}");
611 }
612 });
613 global.device_set_device_lost_closure(device_id, callback);
614 let mut descriptor = descriptor;
615 descriptor.required_limits = global.device_limits(device_id);
616 descriptor.required_features = global.device_features(device_id);
617 descriptor
618 })
619 .map_err(Into::into);
620
621 if let Err(e) = sender.send((device, queue, result)) {
622 warn!(
623 "Failed to send response to WebGPURequest::RequestDevice ({})",
624 e
625 )
626 }
627 },
628 WebGPURequest::BeginComputePass {
629 command_encoder_id,
630 compute_pass_id,
631 label,
632 timestamp_writes,
633 device_id,
634 } => {
635 let global = &self.global;
636 let (_, error) = global.command_encoder_begin_compute_pass_with_id(
637 command_encoder_id,
638 &ComputePassDescriptor {
639 label,
640 timestamp_writes,
641 },
642 Some(compute_pass_id),
643 );
644 self.maybe_dispatch_wgpu_error(device_id, error);
645 },
646 WebGPURequest::ComputePassCommand {
647 compute_pass_id,
648 compute_command,
649 device_id,
650 } => {
651 let result = handle_compute_pass_command(
652 &self.global,
653 compute_pass_id,
654 compute_command,
655 );
656 self.maybe_dispatch_wgpu_error(device_id, result.err());
657 },
658 WebGPURequest::EndComputePass {
659 compute_pass_id,
660 device_id,
661 } => {
662 let result = self.global.compute_pass_end_with_id(compute_pass_id);
664 self.maybe_dispatch_wgpu_error(device_id, result.err());
665 },
666 WebGPURequest::BeginRenderPass {
667 command_encoder_id,
668 render_pass_id,
669 label,
670 color_attachments,
671 depth_stencil_attachment,
672 timestamp_writes,
673 device_id,
674 } => {
675 let global = &self.global;
676 let desc = &RenderPassDescriptor {
677 label,
678 color_attachments: color_attachments.into(),
679 depth_stencil_attachment,
680 timestamp_writes,
681 occlusion_query_set: None,
682 multiview_mask: None,
683 };
684 let (_, error) = global.command_encoder_begin_render_pass_with_id(
685 command_encoder_id,
686 desc,
687 Some(render_pass_id),
688 );
689 self.maybe_dispatch_wgpu_error(device_id, error);
690 },
691 WebGPURequest::RenderPassCommand {
692 render_pass_id,
693 render_command,
694 device_id,
695 } => {
696 let result = handle_render_pass_command(
697 &self.global,
698 render_pass_id,
699 render_command,
700 );
701 self.maybe_dispatch_wgpu_error(device_id, result.err());
702 },
703 WebGPURequest::EndRenderPass {
704 render_pass_id,
705 device_id,
706 } => {
707 let result = self.global.render_pass_end_with_id(render_pass_id);
709 self.maybe_dispatch_wgpu_error(device_id, result.err());
710 },
711 WebGPURequest::Submit {
712 device_id,
713 queue_id,
714 command_buffers,
715 } => {
716 let global = &self.global;
717 let result = {
718 let _guard = self.poller.lock();
719 global.queue_submit(queue_id, &command_buffers)
720 };
721 self.maybe_dispatch_wgpu_error(device_id, result.err().map(|(_, x)| x));
722 },
723 WebGPURequest::UnmapBuffer { buffer_id, mapping } => {
724 let global = &self.global;
725 if let Some(mapping) = mapping &&
726 let Ok((slice_pointer, range_size)) = global.buffer_get_mapped_range(
727 buffer_id,
728 mapping.range.start,
729 Some(mapping.range.end - mapping.range.start),
730 )
731 {
732 unsafe {
733 slice::from_raw_parts_mut(
734 slice_pointer.as_ptr(),
735 range_size as usize,
736 )
737 }
738 .copy_from_slice(&mapping.data);
739 }
740 let _result = global.buffer_unmap(buffer_id);
742 },
743 WebGPURequest::WriteBuffer {
744 device_id,
745 queue_id,
746 buffer_id,
747 buffer_offset,
748 data,
749 } => {
750 let global = &self.global;
751 let result = global.queue_write_buffer(
752 queue_id,
753 buffer_id,
754 buffer_offset as BufferAddress,
755 &data,
756 );
757 self.maybe_dispatch_wgpu_error(device_id, result.err());
758 },
759 WebGPURequest::WriteTexture {
760 device_id,
761 queue_id,
762 texture_cv,
763 data_layout,
764 size,
765 data,
766 } => {
767 let global = &self.global;
768 let _guard = self.poller.lock();
769 let result = global.queue_write_texture(
771 queue_id,
772 &texture_cv,
773 &data,
774 &data_layout,
775 &size,
776 );
777 drop(_guard);
778 self.maybe_dispatch_wgpu_error(device_id, result.err());
779 },
780 WebGPURequest::CopyExternalImageToTexture {
781 device_id,
782 queue_id,
783 usable_source,
784 destination,
785 dest_tex_descriptor,
786 copy_size,
787 } => {
788 let global = &self.global;
790 let Some(source) = usable_source else {
793 self.maybe_dispatch_error(
794 device_id,
795 Some(Error::Validation("Source is not usable".to_string())),
796 );
797 continue;
798 };
799 if !dest_tex_descriptor
801 .usage
802 .contains(TextureUsages::RENDER_ATTACHMENT)
803 {
804 self.maybe_dispatch_error(
805 device_id,
806 Some(Error::Validation(
807 "Texture usage must include RENDER_ATTACHMENT".to_string(),
808 )),
809 );
810 continue;
811 }
812 if dest_tex_descriptor.dimension != TextureDimension::D2 {
814 self.maybe_dispatch_error(
815 device_id,
816 Some(Error::Validation(
817 "Texture dimension must be 2d".to_string(),
818 )),
819 );
820 continue;
821 }
822 let _guard = self.poller.lock();
826 let result = global.queue_write_texture(
827 queue_id,
828 &destination,
829 source.data(),
830 &TexelCopyBufferLayout {
831 offset: 0,
832 bytes_per_row: Some(source.size().width * 4),
833 rows_per_image: None,
834 },
835 ©_size,
836 );
837 drop(_guard);
838 self.maybe_dispatch_wgpu_error(device_id, result.err());
839 },
840 WebGPURequest::QueueOnSubmittedWorkDone { sender, queue_id } => {
841 let global = &self.global;
842 let token = self.poller.token();
843 let callback = Box::from(move || {
844 drop(token);
845 if let Err(e) = sender.send(()) {
846 warn!("Could not send SubmittedWorkDone Response ({})", e);
847 }
848 });
849 global.queue_on_submitted_work_done(queue_id, callback);
850 self.poller.wake();
851 },
852 WebGPURequest::DropTexture(id) => {
853 let global = &self.global;
854 global.texture_drop(id);
855 self.poller.wake();
856 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(id)) {
857 warn!("Unable to send FreeTexture({:?}) ({:?})", id, e);
858 };
859 },
860 WebGPURequest::DropAdapter(id) => {
861 let global = &self.global;
862 global.adapter_drop(id);
863 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeAdapter(id)) {
864 warn!("Unable to send FreeAdapter({:?}) ({:?})", id, e);
865 };
866 },
867 WebGPURequest::DropBuffer(id) => {
868 let global = &self.global;
869 global.buffer_drop(id);
870 self.poller.wake();
871 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(id)) {
872 warn!("Unable to send FreeBuffer({:?}) ({:?})", id, e);
873 };
874 },
875 WebGPURequest::DropPipelineLayout(id) => {
876 let global = &self.global;
877 global.pipeline_layout_drop(id);
878 if let Err(e) = self.script_sender.send(WebGPUMsg::FreePipelineLayout(id)) {
879 warn!("Unable to send FreePipelineLayout({:?}) ({:?})", id, e);
880 };
881 },
882 WebGPURequest::DropComputePipeline(id) => {
883 let global = &self.global;
884 global.compute_pipeline_drop(id);
885 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeComputePipeline(id))
886 {
887 warn!("Unable to send FreeComputePipeline({:?}) ({:?})", id, e);
888 };
889 },
890 WebGPURequest::DropComputePass(id) => {
891 self.global.compute_pass_drop(id);
892 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeComputePass(id)) {
893 warn!("Unable to send FreeComputePass({:?}) ({:?})", id, e);
894 };
895 },
896 WebGPURequest::DropRenderPass(id) => {
897 self.global.render_pass_drop(id);
898 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderPass(id)) {
899 warn!("Unable to send FreeRenderPass({:?}) ({:?})", id, e);
900 };
901 },
902 WebGPURequest::DropRenderPipeline(id) => {
903 let global = &self.global;
904 global.render_pipeline_drop(id);
905 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderPipeline(id)) {
906 warn!("Unable to send FreeRenderPipeline({:?}) ({:?})", id, e);
907 };
908 },
909 WebGPURequest::DropBindGroup(id) => {
910 let global = &self.global;
911 global.bind_group_drop(id);
912 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBindGroup(id)) {
913 warn!("Unable to send FreeBindGroup({:?}) ({:?})", id, e);
914 };
915 },
916 WebGPURequest::DropBindGroupLayout(id) => {
917 let global = &self.global;
918 global.bind_group_layout_drop(id);
919 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBindGroupLayout(id))
920 {
921 warn!("Unable to send FreeBindGroupLayout({:?}) ({:?})", id, e);
922 };
923 },
924 WebGPURequest::DropTextureView(id) => {
925 let global = &self.global;
926 global.texture_view_drop(id);
927 self.poller.wake();
928 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTextureView(id)) {
929 warn!("Unable to send FreeTextureView({:?}) ({:?})", id, e);
930 };
931 },
932 WebGPURequest::DropSampler(id) => {
933 let global = &self.global;
934 global.sampler_drop(id);
935 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeSampler(id)) {
936 warn!("Unable to send FreeSampler({:?}) ({:?})", id, e);
937 };
938 },
939 WebGPURequest::DropShaderModule(id) => {
940 let global = &self.global;
941 global.shader_module_drop(id);
942 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeShaderModule(id)) {
943 warn!("Unable to send FreeShaderModule({:?}) ({:?})", id, e);
944 };
945 },
946 WebGPURequest::DropRenderBundleEncoder(id) => {
947 let global = &self.global;
948 global.render_bundle_encoder_drop(id);
949 if let Err(e) = self
950 .script_sender
951 .send(WebGPUMsg::FreeRenderBundleEncoder(id))
952 {
953 warn!("Unable to send FreeRenderBundleEncoder({:?}) ({:?})", id, e);
954 };
955 },
956 WebGPURequest::DropRenderBundle(id) => {
957 let global = &self.global;
958 global.render_bundle_drop(id);
959 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderBundle(id)) {
960 warn!("Unable to send FreeRenderBundle({:?}) ({:?})", id, e);
961 };
962 },
963 WebGPURequest::DropQuerySet(id) => {
964 let global = &self.global;
965 global.query_set_drop(id);
966 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeQuerySet(id)) {
967 warn!("Unable to send FreeQuerySet({:?}) ({:?})", id, e);
968 };
969 },
970 WebGPURequest::PushErrorScope { device_id, filter } => {
971 let mut devices = self.devices.lock().unwrap();
973 let device_scope = devices
974 .get_mut(&device_id)
975 .expect("Device should not be dropped by this point");
976 if let Some(error_scope_stack) = &mut device_scope.error_scope_stack {
977 error_scope_stack.push(ErrorScope::new(filter));
978 } },
980 WebGPURequest::DispatchError { device_id, error } => {
981 self.dispatch_error(device_id, error);
982 },
983 WebGPURequest::PopErrorScope {
984 device_id,
985 callback: sender,
986 } => {
987 let mut devices = self.devices.lock().unwrap();
989 let device_scope = devices
990 .get_mut(&device_id)
991 .expect("Device should not be dropped by this point");
992 let result =
993 if let Some(error_scope_stack) = &mut device_scope.error_scope_stack {
994 if let Some(error_scope) = error_scope_stack.pop() {
995 Ok(
996 error_scope.errors.first().cloned(),
998 )
999 } else {
1000 Err(PopError::Empty)
1001 }
1002 } else {
1003 Err(PopError::Lost)
1005 };
1006 if let Err(error) = sender.send(result) {
1007 warn!("Error while sending PopErrorScope result: {error}");
1008 }
1009 },
1010 WebGPURequest::ComputeGetBindGroupLayout {
1011 device_id,
1012 pipeline_id,
1013 index,
1014 id,
1015 } => {
1016 let global = &self.global;
1017 let (_, error) = global.compute_pipeline_get_bind_group_layout(
1018 pipeline_id,
1019 index,
1020 Some(id),
1021 );
1022 self.maybe_dispatch_wgpu_error(device_id, error);
1023 },
1024 WebGPURequest::RenderGetBindGroupLayout {
1025 device_id,
1026 pipeline_id,
1027 index,
1028 id,
1029 } => {
1030 let global = &self.global;
1031 let (_, error) = global.render_pipeline_get_bind_group_layout(
1032 pipeline_id,
1033 index,
1034 Some(id),
1035 );
1036 self.maybe_dispatch_wgpu_error(device_id, error);
1037 },
1038 WebGPURequest::CreateQuerySet {
1039 device_id,
1040 query_set_id,
1041 descriptor,
1042 } => {
1043 let global = &self.global;
1044 let (_, error) = global.device_create_query_set(
1045 device_id,
1046 &descriptor,
1047 Some(query_set_id),
1048 );
1049 self.maybe_dispatch_wgpu_error(device_id, error);
1050 },
1051 WebGPURequest::CreatePlanarTexture {
1052 device_id,
1053 size,
1054 format,
1055 texture_id,
1056 texture_view_id,
1057 } => {
1058 let (_, maybe_error) = self.global.device_create_texture(
1059 device_id,
1060 &TextureDescriptor {
1061 label: None,
1062 size: Extent3d {
1063 width: size.width,
1064 height: size.height,
1065 depth_or_array_layers: 1,
1066 },
1067 mip_level_count: 1,
1068 sample_count: 1,
1069 dimension: TextureDimension::D2,
1070 format: match format {
1071 pixels::SnapshotPixelFormat::RGBA => TextureFormat::Rgba8Unorm,
1072 pixels::SnapshotPixelFormat::BGRA => TextureFormat::Bgra8Unorm,
1073 },
1074 usage: TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING,
1075 view_formats: Vec::new(),
1076 },
1077 Some(texture_id),
1078 );
1079 self.maybe_dispatch_error(
1080 device_id,
1081 maybe_error.map(|error| {
1082 Error::Internal(format!(
1083 "Failed to create planar texture: {error:?}"
1084 ))
1085 }),
1086 );
1087 let (_, maybe_error) = self.global.texture_create_view(
1088 texture_id,
1089 &TextureViewDescriptor {
1090 ..Default::default()
1091 },
1092 Some(texture_view_id),
1093 );
1094 self.maybe_dispatch_error(
1095 device_id,
1096 maybe_error.map(|error| {
1097 Error::Internal(format!(
1098 "Failed to create planar texture view: {error:?}"
1099 ))
1100 }),
1101 );
1102 },
1103 WebGPURequest::UpdatePlanarTexture {
1104 device_id,
1105 queue_id,
1106 texture_id,
1107 snapshot,
1108 } => {
1109 let result = self.global.queue_write_texture(
1110 queue_id,
1111 &TexelCopyTextureInfo {
1112 texture: texture_id,
1113 mip_level: 0,
1114 origin: Origin3d::ZERO,
1115 aspect: TextureAspect::All,
1116 },
1117 snapshot.data(),
1118 &TexelCopyBufferLayout {
1119 offset: 0,
1120 bytes_per_row: Some(snapshot.size().width * 4),
1121 rows_per_image: None,
1122 },
1123 &Extent3d {
1124 width: snapshot.size().width,
1125 height: snapshot.size().height,
1126 depth_or_array_layers: 1,
1127 },
1128 );
1129 self.maybe_dispatch_error(
1130 device_id,
1131 result.err().map(|error| {
1132 Error::Internal(format!(
1133 "Failed to write planar texture: {error:?}"
1134 ))
1135 }),
1136 );
1137 },
1138 WebGPURequest::DropPlanarTexture(id, view_id) => {
1139 self.global.texture_view_drop(view_id);
1140 self.global.texture_drop(id);
1141 self.poller.wake();
1142 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTextureView(view_id))
1143 {
1144 warn!("Unable to send FreeTextureView({:?}) ({:?})", view_id, e);
1145 };
1146 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(id)) {
1147 warn!("Unable to send FreeTexture({:?}) ({:?})", id, e);
1148 };
1149 },
1150 WebGPURequest::ImportExternalTexture {
1151 device_id,
1152 external_texture_id,
1153 size,
1154 label,
1155 plane0,
1156 } => {
1157 let desc = ExternalTextureDescriptor {
1158 label: Some(label.into()),
1159 width: size.width,
1160 height: size.height,
1161 format: ExternalTextureFormat::Rgba,
1162 yuv_conversion_matrix: [0.; 16],
1163 gamut_conversion_matrix: [
1164 1., 0., 0., 0., 1., 0., 0., 0., 1., ],
1168 src_transfer_function: ExternalTextureTransferFunction::default(),
1169 dst_transfer_function: ExternalTextureTransferFunction::default(),
1170 sample_transform: [
1171 1., 0., 0., 1., 0., 0., ],
1175 load_transform: [
1176 1., 0., 0., 1., 0., 0., ],
1180 };
1181 if let Some(plane0) = plane0 {
1182 let (_, maybe_error) = self.global.device_create_external_texture(
1183 device_id,
1184 &desc,
1185 &[plane0],
1186 Some(external_texture_id),
1187 );
1188 self.maybe_dispatch_error(
1189 device_id,
1190 maybe_error.map(|error| {
1191 Error::Internal(format!(
1192 "Failed to import external texture: {error:?}"
1193 ))
1194 }),
1195 );
1196 } else {
1197 self.global
1198 .create_external_texture_error(Some(external_texture_id), &desc);
1199 self.maybe_dispatch_error(
1200 device_id,
1201 Some(Error::Validation("Usability is not good".to_string())),
1202 );
1203 }
1204 },
1205 WebGPURequest::DestroyExternalTexture(id) => {
1206 self.global.external_texture_destroy(id);
1207 },
1208 WebGPURequest::DropExternalTexture(id) => {
1209 self.global.external_texture_drop(id);
1210 if let Err(e) = self.script_sender.send(WebGPUMsg::FreeExternalTexture(id))
1211 {
1212 warn!("Unable to send FreeExternalTexture({:?}) ({:?})", id, e);
1213 };
1214 },
1215 WebGPURequest::DestroyQuerySet(query_set_id) => {
1216 self.global.query_set_destroy(query_set_id);
1217 },
1218 WebGPURequest::RenderBundleEncoderFinish {
1219 render_bundle_encoder_id,
1220 descriptor,
1221 render_bundle_id,
1222 device_id,
1223 } => {
1224 let global = &self.global;
1225 let (_, error) = global.render_bundle_encoder_finish_with_id(
1226 render_bundle_encoder_id,
1227 &descriptor,
1228 Some(render_bundle_id),
1229 );
1230
1231 self.maybe_dispatch_wgpu_error(device_id, error);
1232 },
1233 WebGPURequest::CreateRenderBundleEncoder {
1234 device_id,
1235 render_bundle_encoder_id,
1236 desc,
1237 } => {
1238 let (_, error) = self.global.device_create_render_bundle_encoder_with_id(
1239 device_id,
1240 &desc,
1241 Some(render_bundle_encoder_id),
1242 );
1243 self.maybe_dispatch_wgpu_error(device_id, error);
1244 },
1245 WebGPURequest::RenderBundleEncoderCommand {
1246 render_bundle_encoder_id,
1247 render_command,
1248 device_id,
1249 } => {
1250 let result = handle_render_bundle_command(
1251 &self.global,
1252 render_bundle_encoder_id,
1253 render_command,
1254 );
1255 self.maybe_dispatch_wgpu_error(device_id, result.err());
1256 },
1257 }
1258 }
1259 }
1260 if let Err(e) = self.script_sender.send(WebGPUMsg::Exit) {
1261 warn!("Failed to send WebGPUMsg::Exit to script ({})", e);
1262 }
1263 }
1264
1265 #[inline]
1266 fn maybe_dispatch_wgpu_error<E: WebGpuError>(
1267 &mut self,
1268 device_id: id::DeviceId,
1269 error: Option<E>,
1270 ) {
1271 self.maybe_dispatch_error(device_id, error.and_then(Error::from_wgpu_error))
1272 }
1273
1274 fn maybe_dispatch_error(&mut self, device_id: id::DeviceId, error: Option<Error>) {
1276 if let Some(error) = error {
1277 self.dispatch_error(device_id, error);
1278 }
1279 }
1280
1281 fn dispatch_error(&mut self, device_id: id::DeviceId, error: Error) {
1283 log::trace!("Dispatching error for device {:?}: {:?}", device_id, error);
1284 let mut devices = self.devices.lock().unwrap();
1285 let device_scope = devices
1286 .get_mut(&device_id)
1287 .expect("Device should not be dropped by this point");
1288 if let Some(error_scope_stack) = &mut device_scope.error_scope_stack {
1289 if let Some(error_scope) = error_scope_stack
1290 .iter_mut()
1291 .rev()
1292 .find(|error_scope| error_scope.filter == error.filter())
1293 {
1294 error_scope.errors.push(error);
1295 } else if self
1296 .script_sender
1297 .send(WebGPUMsg::UncapturedError {
1298 device: WebGPUDevice(device_id),
1299 pipeline_id: device_scope.pipeline_id,
1300 error: error.clone(),
1301 })
1302 .is_err()
1303 {
1304 warn!("Failed to send WebGPUMsg::UncapturedError: {error:?}");
1305 }
1306 } }
1308}