player/
lib.rs

1//! This is a player library for WebGPU traces.
2
3#![cfg(not(target_arch = "wasm32"))]
4#![warn(clippy::allow_attributes, unsafe_op_in_unsafe_fn)]
5
6extern crate wgpu_core as wgc;
7extern crate wgpu_types as wgt;
8
9use std::{borrow::Cow, convert::Infallible, sync::Arc};
10
11use hashbrown::HashMap;
12
13use wgc::{
14    binding_model::BindingResource,
15    command::{ArcCommand, ArcReferences, BasePass, Command, PointerReferences},
16    device::trace::{self, DataKind, DataLoader},
17    id::{Marker, PointerId},
18};
19
20pub struct Player {
21    pipeline_layouts: HashMap<
22        wgc::id::PointerId<wgc::id::markers::PipelineLayout>,
23        Arc<wgc::binding_model::PipelineLayout>,
24    >,
25    shader_modules: HashMap<
26        wgc::id::PointerId<wgc::id::markers::ShaderModule>,
27        Arc<wgc::pipeline::ShaderModule>,
28    >,
29    bind_group_layouts: HashMap<
30        wgc::id::PointerId<wgc::id::markers::BindGroupLayout>,
31        Arc<wgc::binding_model::BindGroupLayout>,
32    >,
33    bind_groups: HashMap<
34        wgc::id::PointerId<wgc::id::markers::BindGroup>,
35        Arc<wgc::binding_model::BindGroup>,
36    >,
37    render_bundles: HashMap<
38        wgc::id::PointerId<wgc::id::markers::RenderBundle>,
39        Arc<wgc::command::RenderBundle>,
40    >,
41    render_pipelines: HashMap<
42        wgc::id::PointerId<wgc::id::markers::RenderPipeline>,
43        Arc<wgc::pipeline::RenderPipeline>,
44    >,
45    compute_pipelines: HashMap<
46        wgc::id::PointerId<wgc::id::markers::ComputePipeline>,
47        Arc<wgc::pipeline::ComputePipeline>,
48    >,
49    pipeline_caches: HashMap<
50        wgc::id::PointerId<wgc::id::markers::PipelineCache>,
51        Arc<wgc::pipeline::PipelineCache>,
52    >,
53    query_sets:
54        HashMap<wgc::id::PointerId<wgc::id::markers::QuerySet>, Arc<wgc::resource::QuerySet>>,
55    buffers: HashMap<wgc::id::PointerId<wgc::id::markers::Buffer>, Arc<wgc::resource::Buffer>>,
56    textures: HashMap<wgc::id::PointerId<wgc::id::markers::Texture>, Arc<wgc::resource::Texture>>,
57    texture_views:
58        HashMap<wgc::id::PointerId<wgc::id::markers::TextureView>, Arc<wgc::resource::TextureView>>,
59    external_textures: HashMap<
60        wgc::id::PointerId<wgc::id::markers::ExternalTexture>,
61        Arc<wgc::resource::ExternalTexture>,
62    >,
63    samplers: HashMap<wgc::id::PointerId<wgc::id::markers::Sampler>, Arc<wgc::resource::Sampler>>,
64    blas_s: HashMap<wgc::id::PointerId<wgc::id::markers::Blas>, Arc<wgc::resource::Blas>>,
65    tlas_s: HashMap<wgc::id::PointerId<wgc::id::markers::Tlas>, Arc<wgc::resource::Tlas>>,
66}
67
68impl Default for Player {
69    fn default() -> Self {
70        Self {
71            pipeline_layouts: HashMap::new(),
72            shader_modules: HashMap::new(),
73            bind_group_layouts: HashMap::new(),
74            bind_groups: HashMap::new(),
75            render_bundles: HashMap::new(),
76            render_pipelines: HashMap::new(),
77            compute_pipelines: HashMap::new(),
78            pipeline_caches: HashMap::new(),
79            query_sets: HashMap::new(),
80            buffers: HashMap::new(),
81            textures: HashMap::new(),
82            texture_views: HashMap::new(),
83            external_textures: HashMap::new(),
84            samplers: HashMap::new(),
85            blas_s: HashMap::new(),
86            tlas_s: HashMap::new(),
87        }
88    }
89}
90
91fn process_result<T: Marker, U>(
92    op: &str,
93    map: &mut HashMap<PointerId<T>, U>,
94    id: Option<PointerId<T>>,
95    value: Result<U, impl std::error::Error>,
96) {
97    match (id, value) {
98        (Some(id), Ok(value)) => {
99            map.insert(id, value);
100        }
101        (Some(_), Err(err)) => {
102            panic!("{op} succeeded when recording, but failed on playback: {err}");
103        }
104        (None, Ok(_)) => {
105            panic!("{op} failed when recording, but succeeded on playback");
106        }
107        (None, Err(err)) => {
108            panic!("{op} failed when recording, and failed on playback: {err}");
109        }
110    }
111}
112
113impl Player {
114    pub fn process(
115        &mut self,
116        device: &Arc<wgc::device::Device>,
117        queue: &Arc<wgc::device::queue::Queue>,
118        action: trace::Action<PointerReferences>,
119        loader: impl DataLoader,
120    ) {
121        use wgc::device::trace::Action;
122        log::debug!("action {action:?}");
123        match action {
124            Action::Init { .. } => {
125                panic!("Unexpected Action::Init: has to be the first action only")
126            }
127            Action::ConfigureSurface { .. }
128            | Action::Present(_)
129            | Action::DiscardSurfaceTexture(_) => {
130                panic!("Unexpected Surface action: winit feature is not enabled")
131            }
132            Action::CreateBuffer(id, desc) => {
133                let buffer = device.create_buffer(&desc).expect("create_buffer error");
134                self.buffers.insert(id, buffer);
135            }
136            Action::DestroyBuffer(id) => {
137                let buffer = self.buffers.get(&id).expect("invalid buffer");
138                buffer.destroy();
139            }
140            Action::DropBuffer(id) => {
141                let buffer = self.buffers.remove(&id).expect("invalid buffer");
142                let _ = buffer.unmap();
143            }
144            Action::CreateTexture(id, desc) => {
145                let texture = device.create_texture(&desc).expect("create_texture error");
146                self.textures.insert(id, texture);
147            }
148            Action::DestroyTexture(id) => {
149                let texture = self.textures.get(&id).expect("invalid texture");
150                texture.destroy();
151            }
152            Action::DropTexture(id) => {
153                self.textures.remove(&id).expect("invalid texture");
154            }
155            Action::CreateTextureView { id, parent, desc } => {
156                let parent_texture = self.resolve_texture_id(parent);
157                let texture_view = device
158                    .create_texture_view(&parent_texture, &desc)
159                    .expect("create_texture_view error");
160                self.texture_views.insert(id, texture_view);
161            }
162            Action::DropTextureView(id) => {
163                self.texture_views
164                    .remove(&id)
165                    .expect("invalid texture view");
166            }
167            Action::CreateExternalTexture { id, desc, planes } => {
168                let planes = planes
169                    .iter()
170                    .map(|&id| self.resolve_texture_view_id(id))
171                    .collect::<Vec<_>>();
172                let external_texture = device
173                    .create_external_texture(&desc, &planes)
174                    .expect("create_external_texture error");
175                self.external_textures.insert(id, external_texture);
176            }
177            Action::DestroyExternalTexture(id) => {
178                let external_texture = self
179                    .external_textures
180                    .get(&id)
181                    .expect("invalid external texture");
182                external_texture.destroy();
183            }
184            Action::DropExternalTexture(id) => {
185                self.external_textures
186                    .remove(&id)
187                    .expect("invalid external texture");
188            }
189            Action::CreateSampler(id, desc) => {
190                let sampler = device.create_sampler(&desc).expect("create_sampler error");
191                self.samplers.insert(id, sampler);
192            }
193            Action::DropSampler(id) => {
194                self.samplers.remove(&id).expect("invalid sampler");
195            }
196            Action::GetSurfaceTexture { .. } => {
197                unimplemented!()
198            }
199            Action::CreateBindGroupLayout(id, desc) => {
200                let bind_group_layout = device
201                    .create_bind_group_layout(&desc)
202                    .expect("create_bind_group_layout error");
203                self.bind_group_layouts.insert(id, bind_group_layout);
204            }
205            Action::GetRenderPipelineBindGroupLayout {
206                id,
207                pipeline,
208                index,
209            } => {
210                let pipeline = self.resolve_render_pipeline_id(pipeline);
211                let bgl = pipeline
212                    .get_bind_group_layout(index)
213                    .expect("invalid render pipeline");
214                self.bind_group_layouts.insert(id, bgl);
215            }
216            Action::GetComputePipelineBindGroupLayout {
217                id,
218                pipeline,
219                index,
220            } => {
221                let pipeline = self.resolve_compute_pipeline_id(pipeline);
222                let bgl = pipeline
223                    .get_bind_group_layout(index)
224                    .expect("invalid compute pipeline");
225                self.bind_group_layouts.insert(id, bgl);
226            }
227            Action::DropBindGroupLayout(id) => {
228                self.bind_group_layouts
229                    .remove(&id)
230                    .expect("invalid bind group layout");
231            }
232            Action::CreatePipelineLayout(id, desc) => {
233                let bind_group_layouts: Vec<_> = desc
234                    .bind_group_layouts
235                    .to_vec()
236                    .into_iter()
237                    .map(|bgl_id| bgl_id.map(|bgl_id| self.resolve_bind_group_layout_id(bgl_id)))
238                    .collect();
239
240                let resolved_desc = wgc::binding_model::ResolvedPipelineLayoutDescriptor {
241                    label: desc.label.clone(),
242                    bind_group_layouts: Cow::from(&bind_group_layouts),
243                    immediate_size: desc.immediate_size,
244                };
245
246                let pipeline_layout = device
247                    .create_pipeline_layout(&resolved_desc)
248                    .expect("create_pipeline_layout error");
249                self.pipeline_layouts.insert(id, pipeline_layout);
250            }
251            Action::DropPipelineLayout(id) => {
252                self.pipeline_layouts
253                    .remove(&id)
254                    .expect("invalid pipeline layout");
255            }
256            Action::CreateBindGroup(id, desc) => {
257                let resolved_desc = self.resolve_bind_group_descriptor(desc);
258                let bind_group = device
259                    .create_bind_group(resolved_desc)
260                    .expect("create_bind_group error");
261                self.bind_groups.insert(id, bind_group);
262            }
263            Action::DropBindGroup(id) => {
264                let _bind_group = self.bind_groups.remove(&id).expect("invalid bind group");
265            }
266            Action::CreateShaderModule { id, desc, data } => {
267                let code = loader.load_utf8(&data);
268                let source = if data.kind() == DataKind::Wgsl {
269                    wgc::pipeline::ShaderModuleSource::Wgsl(code.clone())
270                } else if data.kind() == DataKind::Ron {
271                    let module = ron::de::from_str(&code).unwrap();
272                    wgc::pipeline::ShaderModuleSource::Naga(module)
273                } else {
274                    panic!(
275                        "Unknown data kind for CreateShaderModule: {:?}",
276                        data.kind()
277                    );
278                };
279                match device.create_shader_module(&desc, source) {
280                    Ok(module) => self.shader_modules.insert(id, module),
281                    Err(e) => panic!("shader compilation error:\n---{code}\n---\n{e}"),
282                };
283            }
284            Action::CreateShaderModulePassthrough {
285                id,
286                data,
287                label,
288                entry_points,
289            } => {
290                let spirv = data.iter().find_map(|a| {
291                    if a.kind() == DataKind::Spv {
292                        let data = loader.load(a);
293                        assert!(data.len().is_multiple_of(4));
294
295                        Some(Cow::Owned(bytemuck::pod_collect_to_vec(&data)))
296                    } else {
297                        None
298                    }
299                });
300                let dxil = data.iter().find_map(|a| {
301                    (a.kind() == DataKind::Dxil).then(|| Cow::Owned(loader.load(a).into_owned()))
302                });
303                let hlsl = data.iter().find_map(|a| {
304                    (a.kind() == DataKind::Hlsl)
305                        .then(|| Cow::Owned(loader.load_utf8(a).into_owned()))
306                });
307                let metallib = data.iter().find_map(|a| {
308                    (a.kind() == DataKind::MetalLib)
309                        .then(|| Cow::Owned(loader.load(a).into_owned()))
310                });
311                let msl = data.iter().find_map(|a| {
312                    (a.kind() == DataKind::Msl)
313                        .then(|| Cow::Owned(loader.load_utf8(a).into_owned()))
314                });
315                let glsl = data.iter().find_map(|a| {
316                    (a.kind() == DataKind::Glsl)
317                        .then(|| Cow::Owned(loader.load_utf8(a).into_owned()))
318                });
319                let wgsl = data.iter().find_map(|a| {
320                    (a.kind() == DataKind::Wgsl)
321                        .then(|| Cow::Owned(loader.load_utf8(a).into_owned()))
322                });
323
324                let desc = wgt::CreateShaderModuleDescriptorPassthrough {
325                    label,
326                    entry_points,
327
328                    spirv,
329                    dxil,
330                    hlsl,
331                    metallib,
332                    msl,
333                    glsl,
334                    wgsl,
335                };
336                match unsafe { device.create_shader_module_passthrough(&desc) } {
337                    Ok(module) => self.shader_modules.insert(id, module),
338                    Err(e) => panic!("shader compilation error:\n{e}"),
339                };
340            }
341            Action::DropShaderModule(id) => {
342                self.shader_modules
343                    .remove(&id)
344                    .expect("invalid shader module");
345            }
346            Action::CreateComputePipeline { id, desc } => {
347                let resolved_desc = self.resolve_compute_pipeline_descriptor(desc);
348                let pipeline = device.create_compute_pipeline(resolved_desc);
349                process_result(
350                    "create_compute_pipeline",
351                    &mut self.compute_pipelines,
352                    id,
353                    pipeline,
354                );
355            }
356            Action::DropComputePipeline(id) => {
357                self.compute_pipelines
358                    .remove(&id)
359                    .expect("invalid compute pipeline");
360            }
361            Action::CreateGeneralRenderPipeline { id, desc } => {
362                // Note that this is the `General` version of the render
363                // pipeline descriptor that can represent either a conventional
364                // pipeline or a mesh shading pipeline.
365                let resolved_desc = self.resolve_render_pipeline_descriptor(desc);
366                let pipeline = device.create_render_pipeline(resolved_desc);
367                process_result(
368                    "create_render_pipeline",
369                    &mut self.render_pipelines,
370                    id,
371                    pipeline,
372                );
373            }
374            Action::DropRenderPipeline(id) => {
375                self.render_pipelines
376                    .remove(&id)
377                    .expect("invalid render pipeline");
378            }
379            Action::CreatePipelineCache { id, desc } => {
380                let cache = unsafe { device.create_pipeline_cache(&desc) }.unwrap();
381                self.pipeline_caches.insert(id, cache);
382            }
383            Action::DropPipelineCache(id) => {
384                self.pipeline_caches
385                    .remove(&id)
386                    .expect("invalid pipeline cache");
387            }
388            Action::CreateRenderBundle { .. } => {
389                unimplemented!("traced render bundles are not supported");
390            }
391            Action::DropRenderBundle(id) => {
392                self.render_bundles
393                    .remove(&id)
394                    .expect("invalid render bundle");
395            }
396            Action::CreateQuerySet { id, desc } => {
397                let query_set = device
398                    .create_query_set(&desc)
399                    .expect("create_query_set error");
400                self.query_sets.insert(id, query_set);
401            }
402            Action::DestroyQuerySet(id) => {
403                let query_set = self.query_sets.get(&id).expect("invalid query set");
404                query_set.destroy();
405            }
406            Action::DropQuerySet(id) => {
407                self.query_sets.remove(&id).expect("invalid query set");
408            }
409            Action::WriteBuffer {
410                id,
411                data,
412                offset,
413                size,
414                queued,
415            } => {
416                let buffer = self.resolve_buffer_id(id);
417                let bin = loader.load(&data);
418                if queued {
419                    queue
420                        .write_buffer(buffer, offset, &bin[..size.try_into().unwrap()])
421                        .expect("Queue::write_buffer error");
422                } else {
423                    device
424                        .set_buffer_data(&buffer, offset, &bin[..size.try_into().unwrap()])
425                        .expect("Device::set_buffer_data error");
426                }
427            }
428            Action::WriteTexture {
429                to,
430                data,
431                layout,
432                size,
433            } => {
434                let to = self.resolve_texel_copy_texture_info(to);
435                let bin = loader.load(&data);
436                queue
437                    .write_texture(to, &bin, &layout, &size)
438                    .expect("Queue::write_texture error");
439            }
440            Action::Submit(_index, ref commands) if commands.is_empty() => {
441                queue.submit(&[]).unwrap();
442            }
443            Action::Submit(_index, commands) => {
444                let resolved_commands: Vec<_> = commands
445                    .into_iter()
446                    .map(|cmd| self.resolve_command(cmd))
447                    .collect();
448                let buffer = wgc::command::CommandBuffer::from_trace(device, resolved_commands);
449                queue.submit(&[buffer]).unwrap();
450            }
451            Action::FailedCommands {
452                commands,
453                failed_at_submit,
454                error,
455            } => {
456                let action = if failed_at_submit.is_some() {
457                    "submitting"
458                } else {
459                    "encoding"
460                };
461                if let Some(commands) = commands {
462                    log::trace!(
463                        "Trace recorded an error {action} the following commands: {commands:#?}"
464                    );
465                }
466                panic!("Error recorded in trace: {error}");
467            }
468            Action::CreateBlas { id, desc, sizes } => {
469                let blas = device.create_blas(&desc, sizes).expect("create_blas error");
470                self.blas_s.insert(id, blas);
471            }
472            Action::DropBlas(id) => {
473                self.blas_s.remove(&id).expect("invalid blas");
474            }
475            Action::CreateTlas { id, desc } => {
476                let tlas = device.create_tlas(&desc).expect("create_tlas error");
477                self.tlas_s.insert(id, tlas);
478            }
479            Action::DropTlas(id) => {
480                self.tlas_s.remove(&id).expect("invalid tlas");
481            }
482        }
483    }
484
485    // This one is a little strange because the surface is held by the
486    // `player` application but we want to insert the texture into our
487    // map so we can find it for rendering.
488    pub fn get_surface_texture(
489        &mut self,
490        id: wgc::id::PointerId<wgc::id::markers::Texture>,
491        surface: &wgc::instance::Surface,
492    ) {
493        let frame = surface
494            .get_current_texture()
495            .expect("get_current_texture error");
496        let texture = frame.texture.expect("did not obtain a surface texture");
497        self.textures.insert(id, texture);
498    }
499
500    pub fn resolve_buffer_id(
501        &self,
502        id: wgc::id::PointerId<wgc::id::markers::Buffer>,
503    ) -> Arc<wgc::resource::Buffer> {
504        self.buffers.get(&id).expect("invalid buffer").clone()
505    }
506
507    fn resolve_texture_id(
508        &self,
509        id: wgc::id::PointerId<wgc::id::markers::Texture>,
510    ) -> Arc<wgc::resource::Texture> {
511        self.textures.get(&id).expect("invalid texture").clone()
512    }
513
514    fn resolve_texture_view_id(
515        &self,
516        id: wgc::id::PointerId<wgc::id::markers::TextureView>,
517    ) -> Arc<wgc::resource::TextureView> {
518        self.texture_views
519            .get(&id)
520            .expect("invalid texture view")
521            .clone()
522    }
523
524    fn resolve_external_texture_id(
525        &self,
526        id: wgc::id::PointerId<wgc::id::markers::ExternalTexture>,
527    ) -> Arc<wgc::resource::ExternalTexture> {
528        self.external_textures
529            .get(&id)
530            .expect("invalid external texture")
531            .clone()
532    }
533
534    fn resolve_sampler_id(
535        &self,
536        id: wgc::id::PointerId<wgc::id::markers::Sampler>,
537    ) -> Arc<wgc::resource::Sampler> {
538        self.samplers.get(&id).expect("invalid sampler").clone()
539    }
540
541    fn resolve_bind_group_layout_id(
542        &self,
543        id: wgc::id::PointerId<wgc::id::markers::BindGroupLayout>,
544    ) -> Arc<wgc::binding_model::BindGroupLayout> {
545        self.bind_group_layouts
546            .get(&id)
547            .expect("invalid bind group layout")
548            .clone()
549    }
550
551    fn resolve_bind_group_id(
552        &self,
553        id: wgc::id::PointerId<wgc::id::markers::BindGroup>,
554    ) -> Arc<wgc::binding_model::BindGroup> {
555        self.bind_groups
556            .get(&id)
557            .expect("invalid bind group")
558            .clone()
559    }
560
561    fn resolve_pipeline_layout_id(
562        &self,
563        id: wgc::id::PointerId<wgc::id::markers::PipelineLayout>,
564    ) -> Arc<wgc::binding_model::PipelineLayout> {
565        self.pipeline_layouts
566            .get(&id)
567            .expect("invalid pipeline layout")
568            .clone()
569    }
570
571    fn resolve_shader_module_id(
572        &self,
573        id: wgc::id::PointerId<wgc::id::markers::ShaderModule>,
574    ) -> Arc<wgc::pipeline::ShaderModule> {
575        self.shader_modules
576            .get(&id)
577            .expect("invalid shader module")
578            .clone()
579    }
580
581    fn resolve_render_pipeline_id(
582        &self,
583        id: wgc::id::PointerId<wgc::id::markers::RenderPipeline>,
584    ) -> Arc<wgc::pipeline::RenderPipeline> {
585        self.render_pipelines
586            .get(&id)
587            .expect("invalid render pipeline")
588            .clone()
589    }
590
591    fn resolve_compute_pipeline_id(
592        &self,
593        id: wgc::id::PointerId<wgc::id::markers::ComputePipeline>,
594    ) -> Arc<wgc::pipeline::ComputePipeline> {
595        self.compute_pipelines
596            .get(&id)
597            .expect("invalid compute pipeline")
598            .clone()
599    }
600
601    fn resolve_pipeline_cache_id(
602        &self,
603        id: wgc::id::PointerId<wgc::id::markers::PipelineCache>,
604    ) -> Arc<wgc::pipeline::PipelineCache> {
605        self.pipeline_caches
606            .get(&id)
607            .expect("invalid pipeline cache")
608            .clone()
609    }
610
611    fn resolve_render_bundle_id(
612        &self,
613        id: wgc::id::PointerId<wgc::id::markers::RenderBundle>,
614    ) -> Arc<wgc::command::RenderBundle> {
615        self.render_bundles
616            .get(&id)
617            .expect("invalid render bundle")
618            .clone()
619    }
620
621    fn resolve_query_set_id(
622        &self,
623        id: wgc::id::PointerId<wgc::id::markers::QuerySet>,
624    ) -> Arc<wgc::resource::QuerySet> {
625        self.query_sets.get(&id).expect("invalid query set").clone()
626    }
627
628    fn resolve_blas_id(
629        &self,
630        id: wgc::id::PointerId<wgc::id::markers::Blas>,
631    ) -> Arc<wgc::resource::Blas> {
632        self.blas_s.get(&id).expect("invalid blas").clone()
633    }
634
635    fn resolve_tlas_id(
636        &self,
637        id: wgc::id::PointerId<wgc::id::markers::Tlas>,
638    ) -> Arc<wgc::resource::Tlas> {
639        self.tlas_s.get(&id).expect("invalid tlas").clone()
640    }
641
642    fn resolve_texel_copy_texture_info(
643        &self,
644        info: wgt::TexelCopyTextureInfo<wgc::id::PointerId<wgc::id::markers::Texture>>,
645    ) -> wgt::TexelCopyTextureInfo<Arc<wgc::resource::Texture>> {
646        wgt::TexelCopyTextureInfo {
647            texture: self.resolve_texture_id(info.texture),
648            mip_level: info.mip_level,
649            origin: info.origin,
650            aspect: info.aspect,
651        }
652    }
653
654    fn resolve_compute_pipeline_descriptor<'a>(
655        &self,
656        desc: wgc::device::trace::TraceComputePipelineDescriptor<'a>,
657    ) -> wgc::pipeline::ResolvedComputePipelineDescriptor<'a> {
658        wgc::pipeline::ResolvedComputePipelineDescriptor {
659            label: desc.label,
660            layout: desc.layout.map(|id| self.resolve_pipeline_layout_id(id)),
661            stage: wgc::pipeline::ResolvedProgrammableStageDescriptor {
662                module: self.resolve_shader_module_id(desc.stage.module),
663                entry_point: desc.stage.entry_point,
664                constants: desc.stage.constants,
665                zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
666            },
667            cache: desc.cache.map(|id| self.resolve_pipeline_cache_id(id)),
668        }
669    }
670
671    fn resolve_render_pipeline_descriptor<'a>(
672        &self,
673        desc: wgc::device::trace::TraceGeneralRenderPipelineDescriptor<'a>,
674    ) -> wgc::pipeline::ResolvedGeneralRenderPipelineDescriptor<'a> {
675        let layout = desc.layout.map(|id| self.resolve_pipeline_layout_id(id));
676
677        let vertex = match desc.vertex {
678            wgc::pipeline::RenderPipelineVertexProcessor::Vertex(vertex_state) => {
679                wgc::pipeline::RenderPipelineVertexProcessor::Vertex(
680                    wgc::pipeline::ResolvedVertexState {
681                        stage: wgc::pipeline::ResolvedProgrammableStageDescriptor {
682                            module: self.resolve_shader_module_id(vertex_state.stage.module),
683                            entry_point: vertex_state.stage.entry_point,
684                            constants: vertex_state.stage.constants,
685                            zero_initialize_workgroup_memory: vertex_state
686                                .stage
687                                .zero_initialize_workgroup_memory,
688                        },
689                        buffers: vertex_state.buffers,
690                    },
691                )
692            }
693            wgc::pipeline::RenderPipelineVertexProcessor::Mesh(task_state, mesh_state) => {
694                let resolved_task = task_state.map(|task| wgc::pipeline::ResolvedTaskState {
695                    stage: wgc::pipeline::ResolvedProgrammableStageDescriptor {
696                        module: self.resolve_shader_module_id(task.stage.module),
697                        entry_point: task.stage.entry_point,
698                        constants: task.stage.constants,
699                        zero_initialize_workgroup_memory: task
700                            .stage
701                            .zero_initialize_workgroup_memory,
702                    },
703                });
704                let resolved_mesh = wgc::pipeline::ResolvedMeshState {
705                    stage: wgc::pipeline::ResolvedProgrammableStageDescriptor {
706                        module: self.resolve_shader_module_id(mesh_state.stage.module),
707                        entry_point: mesh_state.stage.entry_point,
708                        constants: mesh_state.stage.constants,
709                        zero_initialize_workgroup_memory: mesh_state
710                            .stage
711                            .zero_initialize_workgroup_memory,
712                    },
713                };
714                wgc::pipeline::RenderPipelineVertexProcessor::Mesh(resolved_task, resolved_mesh)
715            }
716        };
717
718        let fragment = desc
719            .fragment
720            .map(|fragment_state| wgc::pipeline::ResolvedFragmentState {
721                stage: wgc::pipeline::ResolvedProgrammableStageDescriptor {
722                    module: self.resolve_shader_module_id(fragment_state.stage.module),
723                    entry_point: fragment_state.stage.entry_point,
724                    constants: fragment_state.stage.constants,
725                    zero_initialize_workgroup_memory: fragment_state
726                        .stage
727                        .zero_initialize_workgroup_memory,
728                },
729                targets: fragment_state.targets,
730            });
731
732        wgc::pipeline::ResolvedGeneralRenderPipelineDescriptor {
733            label: desc.label,
734            layout,
735            vertex,
736            primitive: desc.primitive,
737            depth_stencil: desc.depth_stencil,
738            multisample: desc.multisample,
739            fragment,
740            multiview_mask: desc.multiview_mask,
741            cache: desc.cache.map(|id| self.resolve_pipeline_cache_id(id)),
742        }
743    }
744
745    fn resolve_bind_group_descriptor<'a>(
746        &self,
747        desc: wgc::device::trace::TraceBindGroupDescriptor<'a>,
748    ) -> wgc::binding_model::ResolvedBindGroupDescriptor<'a> {
749        let layout = self.resolve_bind_group_layout_id(desc.layout);
750
751        let entries: Vec<wgc::binding_model::ResolvedBindGroupEntry> = desc
752            .entries
753            .to_vec()
754            .into_iter()
755            .map(|entry| {
756                let resource = match entry.resource {
757                    BindingResource::Buffer(buffer_binding) => {
758                        let buffer = self.resolve_buffer_id(buffer_binding.buffer);
759                        wgc::binding_model::ResolvedBindingResource::Buffer(
760                            wgc::binding_model::ResolvedBufferBinding {
761                                buffer,
762                                offset: buffer_binding.offset,
763                                size: buffer_binding.size,
764                            },
765                        )
766                    }
767                    BindingResource::BufferArray(buffer_bindings) => {
768                        let resolved_buffers: Vec<_> = buffer_bindings
769                            .to_vec()
770                            .into_iter()
771                            .map(|bb| {
772                                let buffer = self.resolve_buffer_id(bb.buffer);
773                                wgc::binding_model::ResolvedBufferBinding {
774                                    buffer,
775                                    offset: bb.offset,
776                                    size: bb.size,
777                                }
778                            })
779                            .collect();
780                        wgc::binding_model::ResolvedBindingResource::BufferArray(Cow::Owned(
781                            resolved_buffers,
782                        ))
783                    }
784                    BindingResource::Sampler(sampler_id) => {
785                        let sampler = self.resolve_sampler_id(sampler_id);
786                        wgc::binding_model::ResolvedBindingResource::Sampler(sampler)
787                    }
788                    BindingResource::SamplerArray(sampler_ids) => {
789                        let resolved_samplers: Vec<_> = sampler_ids
790                            .to_vec()
791                            .into_iter()
792                            .map(|id| self.resolve_sampler_id(id))
793                            .collect();
794                        wgc::binding_model::ResolvedBindingResource::SamplerArray(Cow::Owned(
795                            resolved_samplers,
796                        ))
797                    }
798                    BindingResource::TextureView(texture_view_id) => {
799                        let texture_view = self.resolve_texture_view_id(texture_view_id);
800                        wgc::binding_model::ResolvedBindingResource::TextureView(texture_view)
801                    }
802                    BindingResource::TextureViewArray(texture_view_ids) => {
803                        let resolved_views: Vec<_> = texture_view_ids
804                            .to_vec()
805                            .into_iter()
806                            .map(|id| self.resolve_texture_view_id(id))
807                            .collect();
808                        wgc::binding_model::ResolvedBindingResource::TextureViewArray(Cow::Owned(
809                            resolved_views,
810                        ))
811                    }
812                    BindingResource::AccelerationStructure(tlas_id) => {
813                        let tlas = self.resolve_tlas_id(tlas_id);
814                        wgc::binding_model::ResolvedBindingResource::AccelerationStructure(tlas)
815                    }
816                    BindingResource::AccelerationStructureArray(tlas_ids) => {
817                        let resolved_tlas: Vec<_> = tlas_ids
818                            .to_vec()
819                            .into_iter()
820                            .map(|id| self.resolve_tlas_id(id))
821                            .collect();
822                        wgc::binding_model::ResolvedBindingResource::AccelerationStructureArray(
823                            Cow::Owned(resolved_tlas),
824                        )
825                    }
826                    BindingResource::ExternalTexture(external_texture_id) => {
827                        let external_texture =
828                            self.resolve_external_texture_id(external_texture_id);
829                        wgc::binding_model::ResolvedBindingResource::ExternalTexture(
830                            external_texture,
831                        )
832                    }
833                };
834
835                wgc::binding_model::ResolvedBindGroupEntry {
836                    binding: entry.binding,
837                    resource,
838                }
839            })
840            .collect();
841
842        wgc::binding_model::ResolvedBindGroupDescriptor {
843            label: desc.label.clone(),
844            layout,
845            entries: entries.into(),
846        }
847    }
848
849    fn resolve_command(&self, command: Command<PointerReferences>) -> ArcCommand {
850        match command {
851            Command::CopyBufferToBuffer {
852                src,
853                src_offset,
854                dst,
855                dst_offset,
856                size,
857            } => Command::CopyBufferToBuffer {
858                src: self.resolve_buffer_id(src),
859                src_offset,
860                dst: self.resolve_buffer_id(dst),
861                dst_offset,
862                size,
863            },
864            Command::CopyBufferToTexture { src, dst, size } => Command::CopyBufferToTexture {
865                src: self.resolve_texel_copy_buffer_info(src),
866                dst: self.resolve_texel_copy_texture_info(dst),
867                size,
868            },
869            Command::CopyTextureToBuffer { src, dst, size } => Command::CopyTextureToBuffer {
870                src: self.resolve_texel_copy_texture_info(src),
871                dst: self.resolve_texel_copy_buffer_info(dst),
872                size,
873            },
874            Command::CopyTextureToTexture { src, dst, size } => Command::CopyTextureToTexture {
875                src: self.resolve_texel_copy_texture_info(src),
876                dst: self.resolve_texel_copy_texture_info(dst),
877                size,
878            },
879            Command::ClearBuffer { dst, offset, size } => Command::ClearBuffer {
880                dst: self.resolve_buffer_id(dst),
881                offset,
882                size,
883            },
884            Command::ClearTexture {
885                dst,
886                subresource_range,
887            } => Command::ClearTexture {
888                dst: self.resolve_texture_id(dst),
889                subresource_range,
890            },
891            Command::WriteTimestamp {
892                query_set,
893                query_index,
894            } => Command::WriteTimestamp {
895                query_set: self.resolve_query_set_id(query_set),
896                query_index,
897            },
898            Command::ResolveQuerySet {
899                query_set,
900                start_query,
901                query_count,
902                destination,
903                destination_offset,
904            } => Command::ResolveQuerySet {
905                query_set: self.resolve_query_set_id(query_set),
906                start_query,
907                query_count,
908                destination: self.resolve_buffer_id(destination),
909                destination_offset,
910            },
911            Command::PushDebugGroup(label) => Command::PushDebugGroup(label.clone()),
912            Command::PopDebugGroup => Command::PopDebugGroup,
913            Command::InsertDebugMarker(label) => Command::InsertDebugMarker(label.clone()),
914            Command::RunComputePass {
915                pass,
916                timestamp_writes,
917            } => Command::RunComputePass {
918                pass: self.resolve_compute_pass(pass),
919                timestamp_writes: timestamp_writes.map(|tw| self.resolve_pass_timestamp_writes(tw)),
920            },
921            Command::RunRenderPass {
922                pass,
923                color_attachments,
924                depth_stencil_attachment,
925                timestamp_writes,
926                occlusion_query_set,
927                multiview_mask,
928            } => Command::RunRenderPass {
929                pass: self.resolve_render_pass(pass),
930                color_attachments: self.resolve_color_attachments(color_attachments),
931                depth_stencil_attachment: depth_stencil_attachment
932                    .map(|att| self.resolve_depth_stencil_attachment(att)),
933                timestamp_writes: timestamp_writes.map(|tw| self.resolve_pass_timestamp_writes(tw)),
934                occlusion_query_set: occlusion_query_set.map(|qs| self.resolve_query_set_id(qs)),
935                multiview_mask,
936            },
937            Command::BuildAccelerationStructures { blas, tlas } => {
938                Command::BuildAccelerationStructures {
939                    blas: blas
940                        .into_iter()
941                        .map(|entry| self.resolve_blas_build_entry(entry))
942                        .collect(),
943                    tlas: tlas
944                        .into_iter()
945                        .map(|package| self.resolve_tlas_package(package))
946                        .collect(),
947                }
948            }
949            Command::TransitionResources {
950                buffer_transitions,
951                texture_transitions,
952            } => Command::TransitionResources {
953                buffer_transitions: buffer_transitions
954                    .into_iter()
955                    .map(|trans| self.resolve_buffer_transition(trans))
956                    .collect(),
957                texture_transitions: texture_transitions
958                    .into_iter()
959                    .map(|trans| self.resolve_texture_transition(trans))
960                    .collect(),
961            },
962        }
963    }
964
965    // Helper methods for command resolution
966    fn resolve_texel_copy_buffer_info(
967        &self,
968        info: wgt::TexelCopyBufferInfo<PointerId<wgc::id::markers::Buffer>>,
969    ) -> wgt::TexelCopyBufferInfo<Arc<wgc::resource::Buffer>> {
970        wgt::TexelCopyBufferInfo {
971            buffer: self
972                .buffers
973                .get(&info.buffer)
974                .cloned()
975                .expect("invalid buffer"),
976            layout: info.layout,
977        }
978    }
979
980    fn resolve_compute_pass(
981        &self,
982        pass: BasePass<wgc::command::ComputeCommand<PointerReferences>, Infallible>,
983    ) -> BasePass<wgc::command::ComputeCommand<ArcReferences>, Infallible> {
984        let BasePass {
985            label,
986            error,
987            commands,
988            dynamic_offsets,
989            immediates_data,
990            string_data,
991        } = pass;
992
993        BasePass {
994            label,
995            error,
996            commands: commands
997                .into_iter()
998                .map(|cmd| self.resolve_compute_command(cmd))
999                .collect(),
1000            dynamic_offsets,
1001            immediates_data,
1002            string_data,
1003        }
1004    }
1005
1006    fn resolve_render_pass(
1007        &self,
1008        pass: BasePass<wgc::command::RenderCommand<PointerReferences>, Infallible>,
1009    ) -> BasePass<wgc::command::RenderCommand<ArcReferences>, Infallible> {
1010        let BasePass {
1011            label,
1012            error,
1013            commands,
1014            dynamic_offsets,
1015            immediates_data,
1016            string_data,
1017        } = pass;
1018
1019        BasePass {
1020            label,
1021            error,
1022            commands: commands
1023                .into_iter()
1024                .map(|cmd| self.resolve_render_command(cmd))
1025                .collect(),
1026            dynamic_offsets,
1027            immediates_data,
1028            string_data,
1029        }
1030    }
1031
1032    fn resolve_compute_command(
1033        &self,
1034        command: wgc::command::ComputeCommand<PointerReferences>,
1035    ) -> wgc::command::ComputeCommand<ArcReferences> {
1036        use wgc::command::ComputeCommand as C;
1037        match command {
1038            C::SetBindGroup {
1039                index,
1040                num_dynamic_offsets,
1041                bind_group,
1042            } => C::SetBindGroup {
1043                index,
1044                num_dynamic_offsets,
1045                bind_group: bind_group.map(|bg| self.resolve_bind_group_id(bg)),
1046            },
1047            C::SetPipeline(id) => C::SetPipeline(self.resolve_compute_pipeline_id(id)),
1048            C::SetImmediate {
1049                offset,
1050                size_bytes,
1051                values_offset,
1052            } => C::SetImmediate {
1053                offset,
1054                size_bytes,
1055                values_offset,
1056            },
1057            C::DispatchWorkgroups(groups) => C::DispatchWorkgroups(groups),
1058            C::DispatchWorkgroupsIndirect { buffer, offset } => C::DispatchWorkgroupsIndirect {
1059                buffer: self.resolve_buffer_id(buffer),
1060                offset,
1061            },
1062            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
1063            C::PopDebugGroup => C::PopDebugGroup,
1064            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
1065            C::WriteTimestamp {
1066                query_set,
1067                query_index,
1068            } => C::WriteTimestamp {
1069                query_set: self.resolve_query_set_id(query_set),
1070                query_index,
1071            },
1072            C::BeginPipelineStatisticsQuery {
1073                query_set,
1074                query_index,
1075            } => C::BeginPipelineStatisticsQuery {
1076                query_set: self.resolve_query_set_id(query_set),
1077                query_index,
1078            },
1079            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
1080            C::TransitionResources {
1081                buffer_transitions,
1082                texture_transitions,
1083            } => C::TransitionResources {
1084                buffer_transitions: buffer_transitions
1085                    .into_iter()
1086                    .map(|buffer_transition| wgt::BufferTransition {
1087                        buffer: self.resolve_buffer_id(buffer_transition.buffer),
1088                        state: buffer_transition.state,
1089                    })
1090                    .collect(),
1091                texture_transitions: texture_transitions
1092                    .into_iter()
1093                    .map(|texture_transition| wgt::TextureTransition {
1094                        texture: self.resolve_texture_view_id(texture_transition.texture),
1095                        selector: texture_transition.selector,
1096                        state: texture_transition.state,
1097                    })
1098                    .collect(),
1099            },
1100        }
1101    }
1102
1103    fn resolve_render_command(
1104        &self,
1105        command: wgc::command::RenderCommand<PointerReferences>,
1106    ) -> wgc::command::RenderCommand<ArcReferences> {
1107        use wgc::command::RenderCommand as C;
1108        match command {
1109            C::SetBindGroup {
1110                index,
1111                num_dynamic_offsets,
1112                bind_group,
1113            } => C::SetBindGroup {
1114                index,
1115                num_dynamic_offsets,
1116                bind_group: bind_group.map(|bg| self.resolve_bind_group_id(bg)),
1117            },
1118            C::SetPipeline(id) => C::SetPipeline(self.resolve_render_pipeline_id(id)),
1119            C::SetIndexBuffer {
1120                buffer,
1121                index_format,
1122                offset,
1123                size,
1124            } => C::SetIndexBuffer {
1125                buffer: self.resolve_buffer_id(buffer),
1126                index_format,
1127                offset,
1128                size,
1129            },
1130            C::SetVertexBuffer {
1131                slot,
1132                buffer,
1133                offset,
1134                size,
1135            } => C::SetVertexBuffer {
1136                slot,
1137                buffer: buffer.map(|buffer| self.resolve_buffer_id(buffer)),
1138                offset,
1139                size,
1140            },
1141            C::SetBlendConstant(color) => C::SetBlendConstant(color),
1142            C::SetStencilReference(val) => C::SetStencilReference(val),
1143            C::SetViewport {
1144                rect,
1145                depth_min,
1146                depth_max,
1147            } => C::SetViewport {
1148                rect,
1149                depth_min,
1150                depth_max,
1151            },
1152            C::SetScissor(rect) => C::SetScissor(rect),
1153            C::SetImmediate {
1154                offset,
1155                size_bytes,
1156                values_offset,
1157            } => C::SetImmediate {
1158                offset,
1159                size_bytes,
1160                values_offset,
1161            },
1162            C::Draw {
1163                vertex_count,
1164                instance_count,
1165                first_vertex,
1166                first_instance,
1167            } => C::Draw {
1168                vertex_count,
1169                instance_count,
1170                first_vertex,
1171                first_instance,
1172            },
1173            C::DrawIndexed {
1174                index_count,
1175                instance_count,
1176                first_index,
1177                base_vertex,
1178                first_instance,
1179            } => C::DrawIndexed {
1180                index_count,
1181                instance_count,
1182                first_index,
1183                base_vertex,
1184                first_instance,
1185            },
1186            C::DrawMeshTasks {
1187                group_count_x,
1188                group_count_y,
1189                group_count_z,
1190            } => C::DrawMeshTasks {
1191                group_count_x,
1192                group_count_y,
1193                group_count_z,
1194            },
1195            C::DrawIndirect {
1196                buffer,
1197                offset,
1198                count,
1199                family,
1200                vertex_or_index_limit,
1201                instance_limit,
1202            } => C::DrawIndirect {
1203                buffer: self.resolve_buffer_id(buffer),
1204                offset,
1205                count,
1206                family,
1207                vertex_or_index_limit,
1208                instance_limit,
1209            },
1210            C::MultiDrawIndirectCount {
1211                buffer,
1212                offset,
1213                count_buffer,
1214                count_buffer_offset,
1215                max_count,
1216                family,
1217            } => C::MultiDrawIndirectCount {
1218                buffer: self.resolve_buffer_id(buffer),
1219                offset,
1220                count_buffer: self.resolve_buffer_id(count_buffer),
1221                count_buffer_offset,
1222                max_count,
1223                family,
1224            },
1225            C::PushDebugGroup { color, len } => C::PushDebugGroup { color, len },
1226            C::PopDebugGroup => C::PopDebugGroup,
1227            C::InsertDebugMarker { color, len } => C::InsertDebugMarker { color, len },
1228            C::WriteTimestamp {
1229                query_set,
1230                query_index,
1231            } => C::WriteTimestamp {
1232                query_set: self.resolve_query_set_id(query_set),
1233                query_index,
1234            },
1235            C::BeginOcclusionQuery { query_index } => C::BeginOcclusionQuery { query_index },
1236            C::EndOcclusionQuery => C::EndOcclusionQuery,
1237            C::BeginPipelineStatisticsQuery {
1238                query_set,
1239                query_index,
1240            } => C::BeginPipelineStatisticsQuery {
1241                query_set: self.resolve_query_set_id(query_set),
1242                query_index,
1243            },
1244            C::EndPipelineStatisticsQuery => C::EndPipelineStatisticsQuery,
1245            C::ExecuteBundle(bundle) => C::ExecuteBundle(self.resolve_render_bundle_id(bundle)),
1246        }
1247    }
1248
1249    fn resolve_pass_timestamp_writes(
1250        &self,
1251        writes: wgc::command::PassTimestampWrites<PointerId<wgc::id::markers::QuerySet>>,
1252    ) -> wgc::command::PassTimestampWrites<Arc<wgc::resource::QuerySet>> {
1253        wgc::command::PassTimestampWrites {
1254            query_set: self.resolve_query_set_id(writes.query_set),
1255            beginning_of_pass_write_index: writes.beginning_of_pass_write_index,
1256            end_of_pass_write_index: writes.end_of_pass_write_index,
1257        }
1258    }
1259
1260    fn resolve_color_attachments(
1261        &self,
1262        attachments: wgc::command::ColorAttachments<PointerId<wgc::id::markers::TextureView>>,
1263    ) -> wgc::command::ColorAttachments<Arc<wgc::resource::TextureView>> {
1264        attachments
1265            .into_iter()
1266            .map(|opt| {
1267                opt.map(|att| wgc::command::RenderPassColorAttachment {
1268                    view: self.resolve_texture_view_id(att.view),
1269                    depth_slice: att.depth_slice,
1270                    resolve_target: att
1271                        .resolve_target
1272                        .map(|rt| self.resolve_texture_view_id(rt)),
1273                    load_op: att.load_op,
1274                    store_op: att.store_op,
1275                })
1276            })
1277            .collect()
1278    }
1279
1280    fn resolve_depth_stencil_attachment(
1281        &self,
1282        attachment: wgc::command::ResolvedRenderPassDepthStencilAttachment<
1283            PointerId<wgc::id::markers::TextureView>,
1284        >,
1285    ) -> wgc::command::ResolvedRenderPassDepthStencilAttachment<Arc<wgc::resource::TextureView>>
1286    {
1287        wgc::command::ResolvedRenderPassDepthStencilAttachment {
1288            view: self.resolve_texture_view_id(attachment.view),
1289            depth: attachment.depth,
1290            stencil: attachment.stencil,
1291        }
1292    }
1293
1294    fn resolve_blas_build_entry(
1295        &self,
1296        entry: wgc::ray_tracing::OwnedBlasBuildEntry<PointerReferences>,
1297    ) -> wgc::ray_tracing::OwnedBlasBuildEntry<ArcReferences> {
1298        wgc::ray_tracing::OwnedBlasBuildEntry {
1299            blas: self.resolve_blas_id(entry.blas),
1300            geometries: self.resolve_blas_geometries(entry.geometries),
1301        }
1302    }
1303
1304    fn resolve_tlas_package(
1305        &self,
1306        package: wgc::ray_tracing::OwnedTlasPackage<PointerReferences>,
1307    ) -> wgc::ray_tracing::OwnedTlasPackage<ArcReferences> {
1308        wgc::ray_tracing::OwnedTlasPackage {
1309            tlas: self.resolve_tlas_id(package.tlas),
1310            instances: package
1311                .instances
1312                .into_iter()
1313                .map(|opt| opt.map(|inst| self.resolve_tlas_instance(inst)))
1314                .collect(),
1315            lowest_unmodified: package.lowest_unmodified,
1316        }
1317    }
1318
1319    // Helper functions for ray tracing structures
1320    fn resolve_blas_geometries(
1321        &self,
1322        geometries: wgc::ray_tracing::OwnedBlasGeometries<PointerReferences>,
1323    ) -> wgc::ray_tracing::OwnedBlasGeometries<ArcReferences> {
1324        match geometries {
1325            wgc::ray_tracing::OwnedBlasGeometries::TriangleGeometries(geos) => {
1326                wgc::ray_tracing::OwnedBlasGeometries::TriangleGeometries(
1327                    geos.into_iter()
1328                        .map(|geo| self.resolve_blas_triangle_geometry(geo))
1329                        .collect(),
1330                )
1331            }
1332            wgc::ray_tracing::OwnedBlasGeometries::AabbGeometries(geos) => {
1333                wgc::ray_tracing::OwnedBlasGeometries::AabbGeometries(
1334                    geos.into_iter()
1335                        .map(|geo| self.resolve_blas_aabb_geometry(geo))
1336                        .collect(),
1337                )
1338            }
1339        }
1340    }
1341
1342    fn resolve_blas_triangle_geometry(
1343        &self,
1344        geometry: wgc::ray_tracing::OwnedBlasTriangleGeometry<PointerReferences>,
1345    ) -> wgc::ray_tracing::OwnedBlasTriangleGeometry<ArcReferences> {
1346        wgc::ray_tracing::OwnedBlasTriangleGeometry {
1347            size: geometry.size,
1348            vertex_buffer: self.resolve_buffer_id(geometry.vertex_buffer),
1349            index_buffer: geometry.index_buffer.map(|buf| self.resolve_buffer_id(buf)),
1350            transform_buffer: geometry
1351                .transform_buffer
1352                .map(|buf| self.resolve_buffer_id(buf)),
1353            first_vertex: geometry.first_vertex,
1354            vertex_stride: geometry.vertex_stride,
1355            first_index: geometry.first_index,
1356            transform_buffer_offset: geometry.transform_buffer_offset,
1357        }
1358    }
1359
1360    fn resolve_blas_aabb_geometry(
1361        &self,
1362        geometry: wgc::ray_tracing::OwnedBlasAabbGeometry<PointerReferences>,
1363    ) -> wgc::ray_tracing::OwnedBlasAabbGeometry<ArcReferences> {
1364        wgc::ray_tracing::OwnedBlasAabbGeometry {
1365            size: geometry.size,
1366            stride: geometry.stride,
1367            aabb_buffer: self.resolve_buffer_id(geometry.aabb_buffer),
1368            primitive_offset: geometry.primitive_offset,
1369        }
1370    }
1371
1372    fn resolve_tlas_instance(
1373        &self,
1374        instance: wgc::ray_tracing::OwnedTlasInstance<PointerReferences>,
1375    ) -> wgc::ray_tracing::OwnedTlasInstance<ArcReferences> {
1376        wgc::ray_tracing::OwnedTlasInstance {
1377            blas: self.resolve_blas_id(instance.blas),
1378            transform: instance.transform,
1379            custom_data: instance.custom_data,
1380            mask: instance.mask,
1381        }
1382    }
1383
1384    fn resolve_buffer_transition(
1385        &self,
1386        trans: wgt::BufferTransition<PointerId<wgc::id::markers::Buffer>>,
1387    ) -> wgt::BufferTransition<Arc<wgc::resource::Buffer>> {
1388        wgt::BufferTransition {
1389            buffer: self
1390                .buffers
1391                .get(&trans.buffer)
1392                .cloned()
1393                .expect("invalid buffer"),
1394            state: trans.state,
1395        }
1396    }
1397
1398    fn resolve_texture_transition(
1399        &self,
1400        trans: wgt::TextureTransition<PointerId<wgc::id::markers::Texture>>,
1401    ) -> wgt::TextureTransition<Arc<wgc::resource::Texture>> {
1402        wgt::TextureTransition {
1403            texture: self
1404                .textures
1405                .get(&trans.texture)
1406                .cloned()
1407                .expect("invalid texture"),
1408            selector: trans.selector.clone(),
1409            state: trans.state,
1410        }
1411    }
1412}