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