1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::sync::Arc;
4use core::{mem, ops::Range};
5
6use arrayvec::ArrayVec;
7
8use super::{conv, Command as C};
9
10#[derive(Clone, Copy, Debug, Default)]
11struct TextureSlotDesc {
12 tex_target: super::BindTarget,
13 sampler_index: Option<u8>,
14}
15
16pub(super) struct State {
17 topology: u32,
18 primitive: super::PrimitiveState,
19 index_format: wgt::IndexFormat,
20 index_offset: wgt::BufferAddress,
21 vertex_buffers: [(
22 Option<super::VertexBufferDesc>,
23 Option<super::BufferBinding>,
24 ); crate::MAX_VERTEX_BUFFERS],
25 vertex_attributes: ArrayVec<super::AttributeDesc, { super::MAX_VERTEX_ATTRIBUTES }>,
26 color_targets: ArrayVec<super::ColorTargetDesc, { crate::MAX_COLOR_ATTACHMENTS }>,
27 stencil: super::StencilState,
28 depth_bias: wgt::DepthBiasState,
29 alpha_to_coverage_enabled: bool,
30 samplers: [Option<glow::Sampler>; super::MAX_SAMPLERS],
31 texture_slots: [TextureSlotDesc; super::MAX_TEXTURE_SLOTS],
32 render_size: wgt::Extent3d,
33 resolve_attachments: ArrayVec<(u32, super::TextureView), { crate::MAX_COLOR_ATTACHMENTS }>,
34 invalidate_attachments: ArrayVec<u32, { crate::MAX_COLOR_ATTACHMENTS + 2 }>,
35 has_pass_label: bool,
36 instance_vbuf_mask: usize,
37 dirty_vbuf_mask: usize,
38 active_first_instance: u32,
39 current_immediates_data: [u32; super::MAX_IMMEDIATES],
41 end_of_pass_timestamp: Option<glow::Query>,
42 clip_distance_count: u32,
43}
44
45impl Default for State {
46 fn default() -> Self {
47 Self {
48 topology: Default::default(),
49 primitive: Default::default(),
50 index_format: Default::default(),
51 index_offset: Default::default(),
52 vertex_buffers: Default::default(),
53 vertex_attributes: Default::default(),
54 color_targets: Default::default(),
55 stencil: Default::default(),
56 depth_bias: Default::default(),
57 alpha_to_coverage_enabled: Default::default(),
58 samplers: Default::default(),
59 texture_slots: Default::default(),
60 render_size: Default::default(),
61 resolve_attachments: Default::default(),
62 invalidate_attachments: Default::default(),
63 has_pass_label: Default::default(),
64 instance_vbuf_mask: Default::default(),
65 dirty_vbuf_mask: Default::default(),
66 active_first_instance: Default::default(),
67 current_immediates_data: [0; super::MAX_IMMEDIATES],
68 end_of_pass_timestamp: Default::default(),
69 clip_distance_count: Default::default(),
70 }
71 }
72}
73
74impl super::CommandBuffer {
75 fn clear(&mut self) {
76 self.label = None;
77 self.commands.clear();
78 self.data_bytes.clear();
79 self.queries.clear();
80 }
81
82 fn add_marker(&mut self, marker: &str) -> Range<u32> {
83 let start = self.data_bytes.len() as u32;
84 self.data_bytes.extend(marker.as_bytes());
85 start..self.data_bytes.len() as u32
86 }
87
88 fn add_immediates_data(&mut self, data: &[u32]) -> Range<u32> {
89 let data_raw = bytemuck::cast_slice(data);
90 let start = self.data_bytes.len();
91 assert!(start < u32::MAX as usize);
92 self.data_bytes.extend_from_slice(data_raw);
93 let end = self.data_bytes.len();
94 assert!(end < u32::MAX as usize);
95 (start as u32)..(end as u32)
96 }
97}
98
99impl Drop for super::CommandEncoder {
100 fn drop(&mut self) {
101 use crate::CommandEncoder;
102 unsafe { self.discard_encoding() }
103 self.counters.command_encoders.sub(1);
104 }
105}
106
107impl super::CommandEncoder {
108 fn rebind_stencil_func(&mut self) {
109 fn make(s: &super::StencilSide, face: u32) -> C {
110 C::SetStencilFunc {
111 face,
112 function: s.function,
113 reference: s.reference,
114 read_mask: s.mask_read,
115 }
116 }
117
118 let s = &self.state.stencil;
119 if s.front.function == s.back.function
120 && s.front.mask_read == s.back.mask_read
121 && s.front.reference == s.back.reference
122 {
123 self.cmd_buffer
124 .commands
125 .push(make(&s.front, glow::FRONT_AND_BACK));
126 } else {
127 self.cmd_buffer.commands.push(make(&s.front, glow::FRONT));
128 self.cmd_buffer.commands.push(make(&s.back, glow::BACK));
129 }
130 }
131
132 fn rebind_vertex_data(&mut self, first_instance: u32) {
133 if self
134 .private_caps
135 .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
136 {
137 for (index, pair) in self.state.vertex_buffers.iter().enumerate() {
138 if self.state.dirty_vbuf_mask & (1 << index) == 0 {
139 continue;
140 }
141 let (buffer_desc, vb) = match *pair {
142 (Some(ref vb_desc), Some(ref vb)) => (vb_desc.clone(), vb),
143 (_, _) => continue,
145 };
146 let instance_offset = match buffer_desc.step {
147 wgt::VertexStepMode::Vertex => 0,
148 wgt::VertexStepMode::Instance => first_instance * buffer_desc.stride,
149 };
150
151 self.cmd_buffer.commands.push(C::SetVertexBuffer {
152 index: index as u32,
153 buffer: super::BufferBinding {
154 raw: vb.raw,
155 offset: vb.offset + instance_offset as wgt::BufferAddress,
156 },
157 buffer_desc,
158 });
159 self.state.dirty_vbuf_mask ^= 1 << index;
160 }
161 } else {
162 let mut vbuf_mask = 0;
163 for attribute in self.state.vertex_attributes.iter() {
164 if self.state.dirty_vbuf_mask & (1 << attribute.buffer_index) == 0 {
165 continue;
166 }
167 let (buffer_desc, vb) =
168 match self.state.vertex_buffers[attribute.buffer_index as usize] {
169 (Some(ref vb_desc), Some(ref vb)) => (vb_desc.clone(), vb),
170 (_, _) => continue,
172 };
173
174 let mut attribute_desc = attribute.clone();
175 attribute_desc.offset += vb.offset as u32;
176 if buffer_desc.step == wgt::VertexStepMode::Instance {
177 attribute_desc.offset += buffer_desc.stride * first_instance;
178 }
179
180 self.cmd_buffer.commands.push(C::SetVertexAttribute {
181 buffer: Some(vb.raw),
182 buffer_desc,
183 attribute_desc,
184 });
185 vbuf_mask |= 1 << attribute.buffer_index;
186 }
187 self.state.dirty_vbuf_mask ^= vbuf_mask;
188 }
189 }
190
191 fn rebind_sampler_states(&mut self, dirty_textures: u32, dirty_samplers: u32) {
192 for (texture_index, slot) in self.state.texture_slots.iter().enumerate() {
193 if dirty_textures & (1 << texture_index) != 0
194 || slot
195 .sampler_index
196 .is_some_and(|si| dirty_samplers & (1 << si) != 0)
197 {
198 let sampler = slot
199 .sampler_index
200 .and_then(|si| self.state.samplers[si as usize]);
201 self.cmd_buffer
202 .commands
203 .push(C::BindSampler(texture_index as u32, sampler));
204 }
205 }
206 }
207
208 fn prepare_draw(&mut self, first_instance: u32) {
209 let emulated_first_instance_value = if self
212 .private_caps
213 .contains(super::PrivateCapabilities::FULLY_FEATURED_INSTANCING)
214 {
215 0
216 } else {
217 first_instance
218 };
219
220 if emulated_first_instance_value != self.state.active_first_instance {
221 self.state.dirty_vbuf_mask |= self.state.instance_vbuf_mask;
223 self.state.active_first_instance = emulated_first_instance_value;
224 }
225 if self.state.dirty_vbuf_mask != 0 {
226 self.rebind_vertex_data(emulated_first_instance_value);
227 }
228 }
229
230 fn set_pipeline_inner(&mut self, inner: &Arc<super::PipelineInner>) {
231 self.cmd_buffer.commands.push(C::SetProgram(Arc::clone(inner)));
232
233 let mut dirty_textures = 0u32;
235 for (texture_index, (slot, &sampler_index)) in self
236 .state
237 .texture_slots
238 .iter_mut()
239 .zip(inner.sampler_map.iter())
240 .enumerate()
241 {
242 if slot.sampler_index != sampler_index {
243 slot.sampler_index = sampler_index;
244 dirty_textures |= 1 << texture_index;
245 }
246 }
247 if dirty_textures != 0 {
248 self.rebind_sampler_states(dirty_textures, 0);
249 }
250 }
251}
252
253impl crate::CommandEncoder for super::CommandEncoder {
254 type A = super::Api;
255
256 unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> {
257 self.state = State::default();
258 self.cmd_buffer.label = label.map(String::from);
259 Ok(())
260 }
261 unsafe fn discard_encoding(&mut self) {
262 self.cmd_buffer.clear();
263 }
264 unsafe fn end_encoding(&mut self) -> Result<super::CommandBuffer, crate::DeviceError> {
265 Ok(mem::take(&mut self.cmd_buffer))
266 }
267 unsafe fn reset_all<I>(&mut self, _command_buffers: I) {
268 }
270
271 unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
272 where
273 T: Iterator<Item = crate::BufferBarrier<'a, super::Buffer>>,
274 {
275 if !self
276 .private_caps
277 .contains(super::PrivateCapabilities::MEMORY_BARRIERS)
278 {
279 return;
280 }
281 for bar in barriers {
282 if !bar.usage.from.contains(wgt::BufferUses::STORAGE_READ_WRITE) {
284 continue;
285 }
286 self.cmd_buffer
287 .commands
288 .push(C::BufferBarrier(bar.buffer.raw.unwrap(), bar.usage.to));
289 }
290 }
291
292 unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
293 where
294 T: Iterator<Item = crate::TextureBarrier<'a, super::Texture>>,
295 {
296 if !self
297 .private_caps
298 .contains(super::PrivateCapabilities::MEMORY_BARRIERS)
299 {
300 return;
301 }
302
303 let mut combined_usage = wgt::TextureUses::empty();
304 for bar in barriers {
305 if !bar.usage.from.intersects(
308 wgt::TextureUses::STORAGE_READ_WRITE | wgt::TextureUses::STORAGE_WRITE_ONLY,
309 ) {
310 continue;
311 }
312 combined_usage |= bar.usage.to;
315 }
316
317 if !combined_usage.is_empty() {
318 self.cmd_buffer
319 .commands
320 .push(C::TextureBarrier(combined_usage));
321 }
322 }
323
324 unsafe fn clear_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange) {
325 self.cmd_buffer
326 .commands
327 .push(C::ClearBuffer(Box::new(super::ClearBufferOp {
328 dst: buffer.clone(),
329 dst_target: buffer.target,
330 range,
331 })));
332 }
333
334 unsafe fn copy_buffer_to_buffer<T>(
335 &mut self,
336 src: &super::Buffer,
337 dst: &super::Buffer,
338 regions: T,
339 ) where
340 T: Iterator<Item = crate::BufferCopy>,
341 {
342 let (src_target, dst_target) = if src.target == dst.target {
343 (glow::COPY_READ_BUFFER, glow::COPY_WRITE_BUFFER)
344 } else {
345 (src.target, dst.target)
346 };
347 for copy in regions {
348 self.cmd_buffer
349 .commands
350 .push(C::CopyBufferToBuffer(Box::new(super::BufferToBufferCopy {
351 src: src.clone(),
352 src_target,
353 dst: dst.clone(),
354 dst_target,
355 copy,
356 })))
357 }
358 }
359
360 #[cfg(webgl)]
361 unsafe fn copy_external_image_to_texture<T>(
362 &mut self,
363 src: &wgt::CopyExternalImageSourceInfo,
364 dst: &super::Texture,
365 dst_premultiplication: bool,
366 regions: T,
367 ) where
368 T: Iterator<Item = crate::TextureCopy>,
369 {
370 let (dst_raw, dst_target) = dst.inner.as_native();
371 for copy in regions {
372 self.cmd_buffer
373 .commands
374 .push(C::CopyExternalImageToTexture(Box::new(
375 super::ExternalImageToTextureCopy {
376 src: src.clone(),
377 dst: dst_raw,
378 dst_target,
379 dst_format: dst.format,
380 dst_premultiplication,
381 copy,
382 },
383 )))
384 }
385 }
386
387 unsafe fn copy_texture_to_texture<T>(
388 &mut self,
389 src: &super::Texture,
390 _src_usage: wgt::TextureUses,
391 dst: &super::Texture,
392 regions: T,
393 ) where
394 T: Iterator<Item = crate::TextureCopy>,
395 {
396 let (src_raw, src_target) = src.inner.as_native();
397 let (dst_raw, dst_target) = dst.inner.as_native();
398 for mut copy in regions {
399 copy.clamp_size_to_virtual(&src.copy_size, &dst.copy_size);
400 self.cmd_buffer
401 .commands
402 .push(C::CopyTextureToTexture(Box::new(
403 super::TextureToTextureCopy {
404 src: src_raw,
405 src_target,
406 dst: dst_raw,
407 dst_target,
408 copy,
409 },
410 )))
411 }
412 }
413
414 unsafe fn copy_buffer_to_texture<T>(
415 &mut self,
416 src: &super::Buffer,
417 dst: &super::Texture,
418 regions: T,
419 ) where
420 T: Iterator<Item = crate::BufferTextureCopy>,
421 {
422 let (dst_raw, dst_target) = dst.inner.as_native();
423
424 for mut copy in regions {
425 copy.clamp_size_to_virtual(&dst.copy_size);
426 self.cmd_buffer
427 .commands
428 .push(C::CopyBufferToTexture(Box::new(
429 super::BufferToTextureCopy {
430 src: src.clone(),
431 src_target: src.target,
432 dst: dst_raw,
433 dst_target,
434 dst_format: dst.format,
435 copy,
436 },
437 )))
438 }
439 }
440
441 unsafe fn copy_texture_to_buffer<T>(
442 &mut self,
443 src: &super::Texture,
444 _src_usage: wgt::TextureUses,
445 dst: &super::Buffer,
446 regions: T,
447 ) where
448 T: Iterator<Item = crate::BufferTextureCopy>,
449 {
450 let (src_raw, src_target) = src.inner.as_native();
451 for mut copy in regions {
452 copy.clamp_size_to_virtual(&src.copy_size);
453 self.cmd_buffer
454 .commands
455 .push(C::CopyTextureToBuffer(Box::new(
456 super::TextureToBufferCopy {
457 src: src_raw,
458 src_target,
459 src_format: src.format,
460 dst: dst.clone(),
461 dst_target: dst.target,
462 copy,
463 },
464 )))
465 }
466 }
467
468 unsafe fn begin_query(&mut self, set: &super::QuerySet, index: u32) {
469 let query = set.queries[index as usize];
470 self.cmd_buffer
471 .commands
472 .push(C::BeginQuery(query, set.target));
473 }
474 unsafe fn end_query(&mut self, set: &super::QuerySet, _index: u32) {
475 self.cmd_buffer.commands.push(C::EndQuery(set.target));
476 }
477 unsafe fn write_timestamp(&mut self, set: &super::QuerySet, index: u32) {
478 let query = set.queries[index as usize];
479 self.cmd_buffer.commands.push(C::TimestampQuery(query));
480 }
481 unsafe fn reset_queries(&mut self, _set: &super::QuerySet, _range: Range<u32>) {
482 }
484 unsafe fn copy_query_results(
485 &mut self,
486 set: &super::QuerySet,
487 range: Range<u32>,
488 buffer: &super::Buffer,
489 offset: wgt::BufferAddress,
490 _stride: wgt::BufferSize,
491 ) {
492 let start = self.cmd_buffer.queries.len();
493 self.cmd_buffer
494 .queries
495 .extend_from_slice(&set.queries[range.start as usize..range.end as usize]);
496 let query_range = start as u32..self.cmd_buffer.queries.len() as u32;
497 self.cmd_buffer
498 .commands
499 .push(C::CopyQueryResults(Box::new(super::QueryResultsCopy {
500 query_range,
501 dst: buffer.clone(),
502 dst_target: buffer.target,
503 dst_offset: offset,
504 })));
505 }
506
507 unsafe fn begin_render_pass(
510 &mut self,
511 desc: &crate::RenderPassDescriptor<super::QuerySet, super::TextureView>,
512 ) -> Result<(), crate::DeviceError> {
513 debug_assert!(self.state.end_of_pass_timestamp.is_none());
514 if let Some(ref t) = desc.timestamp_writes {
515 if let Some(index) = t.beginning_of_pass_write_index {
516 unsafe { self.write_timestamp(t.query_set, index) }
517 }
518 self.state.end_of_pass_timestamp = t
519 .end_of_pass_write_index
520 .map(|index| t.query_set.queries[index as usize]);
521 }
522
523 self.state.render_size = desc.extent;
524 self.state.resolve_attachments.clear();
525 self.state.invalidate_attachments.clear();
526 if let Some(label) = desc.label {
527 let range = self.cmd_buffer.add_marker(label);
528 self.cmd_buffer.commands.push(C::PushDebugGroup(range));
529 self.state.has_pass_label = true;
530 }
531
532 let rendering_to_external_framebuffer = desc
533 .color_attachments
534 .iter()
535 .filter_map(|at| at.as_ref())
536 .any(|at| match at.target.view.inner {
537 #[cfg(webgl)]
538 super::TextureInner::ExternalFramebuffer { .. } => true,
539 #[cfg(native)]
540 super::TextureInner::ExternalNativeFramebuffer { .. } => true,
541 _ => false,
542 });
543
544 if rendering_to_external_framebuffer && desc.color_attachments.len() != 1 {
545 panic!("Multiple render attachments with external framebuffers are not supported.");
546 }
547
548 assert!(desc.color_attachments.len() <= 32);
550
551 match desc
552 .color_attachments
553 .first()
554 .filter(|at| at.is_some())
555 .and_then(|at| at.as_ref().map(|at| &at.target.view.inner))
556 {
557 Some(&super::TextureInner::DefaultRenderbuffer) => {
559 self.cmd_buffer
560 .commands
561 .push(C::ResetFramebuffer { is_default: true });
562 }
563 _ => {
564 self.cmd_buffer
566 .commands
567 .push(C::ResetFramebuffer { is_default: false });
568
569 for (i, cat) in desc.color_attachments.iter().enumerate() {
570 if let Some(cat) = cat.as_ref() {
571 let attachment = glow::COLOR_ATTACHMENT0 + i as u32;
572 if let Some(ref rat) = cat.resolve_target {
574 if matches!(rat.view.inner, super::TextureInner::Texture { .. })
575 && self.private_caps.contains(
576 super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE,
577 )
578 && !cat.ops.contains(crate::AttachmentOps::STORE)
579 && i == 0
581 {
582 self.cmd_buffer.commands.push(C::BindAttachment(Box::new(
583 super::AttachmentBinding {
584 attachment,
585 view: rat.view.clone(),
586 depth_slice: None,
587 sample_count: desc.sample_count,
588 },
589 )));
590 continue;
591 }
592 }
593 self.cmd_buffer.commands.push(C::BindAttachment(Box::new(
594 super::AttachmentBinding {
595 attachment,
596 view: cat.target.view.clone(),
597 depth_slice: cat.depth_slice,
598 sample_count: 1,
599 },
600 )));
601 if let Some(ref rat) = cat.resolve_target {
602 self.state
603 .resolve_attachments
604 .push((attachment, rat.view.clone()));
605 }
606 if cat.ops.contains(crate::AttachmentOps::STORE_DISCARD) {
607 self.state.invalidate_attachments.push(attachment);
608 }
609 }
610 }
611 if let Some(ref dsat) = desc.depth_stencil_attachment {
612 let aspects = dsat.target.view.aspects;
613 let attachment = match aspects {
614 crate::FormatAspects::DEPTH => glow::DEPTH_ATTACHMENT,
615 crate::FormatAspects::STENCIL => glow::STENCIL_ATTACHMENT,
616 _ => glow::DEPTH_STENCIL_ATTACHMENT,
617 };
618 self.cmd_buffer.commands.push(C::BindAttachment(Box::new(
619 super::AttachmentBinding {
620 attachment,
621 view: dsat.target.view.clone(),
622 depth_slice: None,
623 sample_count: 1,
624 },
625 )));
626 if aspects.contains(crate::FormatAspects::DEPTH)
627 && dsat.depth_ops.contains(crate::AttachmentOps::STORE_DISCARD)
628 {
629 self.state
630 .invalidate_attachments
631 .push(glow::DEPTH_ATTACHMENT);
632 }
633 if aspects.contains(crate::FormatAspects::STENCIL)
634 && dsat
635 .stencil_ops
636 .contains(crate::AttachmentOps::STORE_DISCARD)
637 {
638 self.state
639 .invalidate_attachments
640 .push(glow::STENCIL_ATTACHMENT);
641 }
642 }
643 }
644 }
645
646 let rect = crate::Rect {
647 x: 0,
648 y: 0,
649 w: desc.extent.width as i32,
650 h: desc.extent.height as i32,
651 };
652 self.cmd_buffer.commands.push(C::SetScissor(rect.clone()));
653 self.cmd_buffer.commands.push(C::SetViewport {
654 rect,
655 depth: 0.0..1.0,
656 });
657
658 if !rendering_to_external_framebuffer {
659 self.cmd_buffer
661 .commands
662 .push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8));
663 }
664
665 for (i, cat) in desc
667 .color_attachments
668 .iter()
669 .filter_map(|at| at.as_ref())
670 .enumerate()
671 {
672 if cat.ops.contains(crate::AttachmentOps::LOAD_CLEAR) {
673 let c = &cat.clear_value;
674 self.cmd_buffer.commands.push(
675 match cat.target.view.format.sample_type(None, None).unwrap() {
676 wgt::TextureSampleType::Float { .. } => C::ClearColorF {
677 draw_buffer: i as u32,
678 color: [c.r as f32, c.g as f32, c.b as f32, c.a as f32],
679 is_srgb: cat.target.view.format.is_srgb(),
680 },
681 wgt::TextureSampleType::Uint => C::ClearColorU(
682 i as u32,
683 [c.r as u32, c.g as u32, c.b as u32, c.a as u32],
684 ),
685 wgt::TextureSampleType::Sint => C::ClearColorI(
686 i as u32,
687 [c.r as i32, c.g as i32, c.b as i32, c.a as i32],
688 ),
689 wgt::TextureSampleType::Depth => unreachable!(),
690 },
691 );
692 }
693 }
694
695 if let Some(ref dsat) = desc.depth_stencil_attachment {
696 let clear_depth = dsat.depth_ops.contains(crate::AttachmentOps::LOAD_CLEAR);
697 let clear_stencil = dsat.stencil_ops.contains(crate::AttachmentOps::LOAD_CLEAR);
698
699 if clear_depth && clear_stencil {
700 self.cmd_buffer.commands.push(C::ClearDepthAndStencil(
701 dsat.clear_value.0,
702 dsat.clear_value.1,
703 ));
704 } else if clear_depth {
705 self.cmd_buffer
706 .commands
707 .push(C::ClearDepth(dsat.clear_value.0));
708 } else if clear_stencil {
709 self.cmd_buffer
710 .commands
711 .push(C::ClearStencil(dsat.clear_value.1));
712 }
713 }
714 Ok(())
715 }
716 unsafe fn end_render_pass(&mut self) {
717 for (attachment, dst) in self.state.resolve_attachments.drain(..) {
718 self.cmd_buffer.commands.push(C::ResolveAttachment(Box::new(
719 super::AttachmentResolve {
720 attachment,
721 dst,
722 size: self.state.render_size,
723 },
724 )));
725 }
726 if !self.state.invalidate_attachments.is_empty() {
727 self.cmd_buffer.commands.push(C::InvalidateAttachments(
728 self.state.invalidate_attachments.clone(),
729 ));
730 self.state.invalidate_attachments.clear();
731 }
732 if self.state.has_pass_label {
733 self.cmd_buffer.commands.push(C::PopDebugGroup);
734 self.state.has_pass_label = false;
735 }
736 self.state.instance_vbuf_mask = 0;
737 self.state.dirty_vbuf_mask = 0;
738 self.state.active_first_instance = 0;
739 self.state.color_targets.clear();
740 for vat in &self.state.vertex_attributes {
741 self.cmd_buffer
742 .commands
743 .push(C::UnsetVertexAttribute(vat.location));
744 }
745 self.state.vertex_attributes.clear();
746 self.state.primitive = super::PrimitiveState::default();
747
748 if let Some(query) = self.state.end_of_pass_timestamp.take() {
749 self.cmd_buffer.commands.push(C::TimestampQuery(query));
750 }
751 }
752
753 unsafe fn set_bind_group(
754 &mut self,
755 layout: &super::PipelineLayout,
756 index: u32,
757 group: &super::BindGroup,
758 dynamic_offsets: &[wgt::DynamicOffset],
759 ) {
760 let mut do_index = 0;
761 let mut dirty_textures = 0u32;
762 let mut dirty_samplers = 0u32;
763 let group_info = layout.group_infos[index as usize].as_ref().unwrap();
764
765 for (binding_layout, raw_binding) in group_info.entries.iter().zip(group.contents.iter()) {
766 let slot = group_info.binding_to_slot[binding_layout.binding as usize] as u32;
767 match *raw_binding {
768 super::RawBinding::Buffer {
769 raw,
770 offset: base_offset,
771 size,
772 } => {
773 let mut offset = base_offset;
774 let target = match binding_layout.ty {
775 wgt::BindingType::Buffer {
776 ty,
777 has_dynamic_offset,
778 min_binding_size: _,
779 } => {
780 if has_dynamic_offset {
781 offset += dynamic_offsets[do_index] as i32;
782 do_index += 1;
783 }
784 match ty {
785 wgt::BufferBindingType::Uniform => glow::UNIFORM_BUFFER,
786 wgt::BufferBindingType::Storage { .. } => {
787 glow::SHADER_STORAGE_BUFFER
788 }
789 }
790 }
791 _ => unreachable!(),
792 };
793 self.cmd_buffer.commands.push(C::BindBuffer {
794 target,
795 slot,
796 buffer: raw,
797 offset,
798 size,
799 });
800 }
801 super::RawBinding::Sampler(sampler) => {
802 dirty_samplers |= 1 << slot;
803 self.state.samplers[slot as usize] = Some(sampler);
804 }
805 super::RawBinding::Texture {
806 raw,
807 target,
808 aspects,
809 ref mip_levels,
810 } => {
811 dirty_textures |= 1 << slot;
812 self.state.texture_slots[slot as usize].tex_target = target;
813 self.cmd_buffer.commands.push(C::BindTexture {
814 slot,
815 texture: raw,
816 target,
817 aspects,
818 mip_levels: mip_levels.clone(),
819 });
820 }
821 super::RawBinding::Image(ref binding) => {
822 self.cmd_buffer.commands.push(C::BindImage {
823 slot,
824 binding: binding.clone(),
825 });
826 }
827 }
828 }
829
830 self.rebind_sampler_states(dirty_textures, dirty_samplers);
831 }
832
833 unsafe fn set_immediates(
834 &mut self,
835 _layout: &super::PipelineLayout,
836 offset_bytes: u32,
837 data: &[u32],
838 ) {
839 let start_words = offset_bytes / 4;
847 let end_words = start_words + data.len() as u32;
848 self.state.current_immediates_data[start_words as usize..end_words as usize]
849 .copy_from_slice(data);
850
851 let data = self
854 .cmd_buffer
855 .add_immediates_data(&self.state.current_immediates_data);
856 self.cmd_buffer.commands.push(C::SetImmediates { data });
857 }
858
859 unsafe fn insert_debug_marker(&mut self, label: &str) {
860 let range = self.cmd_buffer.add_marker(label);
861 self.cmd_buffer.commands.push(C::InsertDebugMarker(range));
862 }
863 unsafe fn begin_debug_marker(&mut self, group_label: &str) {
864 let range = self.cmd_buffer.add_marker(group_label);
865 self.cmd_buffer.commands.push(C::PushDebugGroup(range));
866 }
867 unsafe fn end_debug_marker(&mut self) {
868 self.cmd_buffer.commands.push(C::PopDebugGroup);
869 }
870
871 unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {
872 self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology);
873
874 if self
875 .private_caps
876 .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
877 {
878 for vat in pipeline.vertex_attributes.iter() {
879 let vb = pipeline.vertex_buffers[vat.buffer_index as usize]
880 .as_ref()
881 .unwrap();
882 self.cmd_buffer.commands.push(C::SetVertexAttribute {
884 buffer: None,
885 buffer_desc: vb.clone(),
886 attribute_desc: vat.clone(),
887 });
888 }
889 } else {
890 for vat in &self.state.vertex_attributes {
891 self.cmd_buffer
892 .commands
893 .push(C::UnsetVertexAttribute(vat.location));
894 }
895 self.state.vertex_attributes.clear();
896
897 self.state.dirty_vbuf_mask = 0;
898 for vat in pipeline.vertex_attributes.iter() {
900 self.state.dirty_vbuf_mask |= 1 << vat.buffer_index;
902 self.state.vertex_attributes.push(vat.clone());
903 }
904 }
905
906 self.state.instance_vbuf_mask = 0;
907 for (index, (&mut (ref mut state_desc, _), pipe_desc)) in self
909 .state
910 .vertex_buffers
911 .iter_mut()
912 .zip(pipeline.vertex_buffers.iter())
913 .enumerate()
914 {
915 let Some(pipe_desc) = pipe_desc else {
916 continue;
917 };
918 if pipe_desc.step == wgt::VertexStepMode::Instance {
919 self.state.instance_vbuf_mask |= 1 << index;
920 }
921 if state_desc.as_ref() != Some(pipe_desc) {
922 self.state.dirty_vbuf_mask |= 1 << index;
923 *state_desc = Some(pipe_desc.clone());
924 }
925 }
926
927 self.set_pipeline_inner(&pipeline.inner);
928
929 let prim_state = conv::map_primitive_state(&pipeline.primitive);
931 if prim_state != self.state.primitive {
932 self.cmd_buffer
933 .commands
934 .push(C::SetPrimitive(prim_state.clone()));
935 self.state.primitive = prim_state;
936 }
937
938 let mut aspects = crate::FormatAspects::empty();
940 if pipeline.depth_bias != self.state.depth_bias {
941 self.state.depth_bias = pipeline.depth_bias;
942 self.cmd_buffer
943 .commands
944 .push(C::SetDepthBias(pipeline.depth_bias));
945 }
946 if let Some(ref depth) = pipeline.depth {
947 aspects |= crate::FormatAspects::DEPTH;
948 self.cmd_buffer.commands.push(C::SetDepth(depth.clone()));
949 }
950 if let Some(ref stencil) = pipeline.stencil {
951 aspects |= crate::FormatAspects::STENCIL;
952 self.state.stencil = stencil.clone();
953 self.rebind_stencil_func();
954 if stencil.front.ops == stencil.back.ops
955 && stencil.front.mask_write == stencil.back.mask_write
956 {
957 self.cmd_buffer.commands.push(C::SetStencilOps {
958 face: glow::FRONT_AND_BACK,
959 write_mask: stencil.front.mask_write,
960 ops: stencil.front.ops.clone(),
961 });
962 } else {
963 self.cmd_buffer.commands.push(C::SetStencilOps {
964 face: glow::FRONT,
965 write_mask: stencil.front.mask_write,
966 ops: stencil.front.ops.clone(),
967 });
968 self.cmd_buffer.commands.push(C::SetStencilOps {
969 face: glow::BACK,
970 write_mask: stencil.back.mask_write,
971 ops: stencil.back.ops.clone(),
972 });
973 }
974 }
975 self.cmd_buffer
976 .commands
977 .push(C::ConfigureDepthStencil(aspects));
978
979 if pipeline.alpha_to_coverage_enabled != self.state.alpha_to_coverage_enabled {
981 self.state.alpha_to_coverage_enabled = pipeline.alpha_to_coverage_enabled;
982 self.cmd_buffer
983 .commands
984 .push(C::SetAlphaToCoverage(pipeline.alpha_to_coverage_enabled));
985 }
986
987 if self.state.color_targets[..] != pipeline.color_targets[..] {
989 if pipeline
990 .color_targets
991 .iter()
992 .skip(1)
993 .any(|ct| *ct != pipeline.color_targets[0])
994 {
995 for (index, ct) in pipeline.color_targets.iter().enumerate() {
996 self.cmd_buffer.commands.push(C::SetColorTarget {
997 draw_buffer_index: Some(index as u32),
998 desc: ct.clone(),
999 });
1000 }
1001 } else {
1002 self.cmd_buffer.commands.push(C::SetColorTarget {
1003 draw_buffer_index: None,
1004 desc: pipeline.color_targets.first().cloned().unwrap_or_default(),
1005 });
1006 }
1007 }
1008 self.state.color_targets.clear();
1009 for ct in pipeline.color_targets.iter() {
1010 self.state.color_targets.push(ct.clone());
1011 }
1012
1013 if pipeline.inner.clip_distance_count != self.state.clip_distance_count {
1015 self.cmd_buffer.commands.push(C::SetClipDistances {
1016 old_count: self.state.clip_distance_count,
1017 new_count: pipeline.inner.clip_distance_count,
1018 });
1019 self.state.clip_distance_count = pipeline.inner.clip_distance_count;
1020 }
1021 }
1022
1023 unsafe fn set_index_buffer<'a>(
1024 &mut self,
1025 binding: crate::BufferBinding<'a, super::Buffer>,
1026 format: wgt::IndexFormat,
1027 ) {
1028 self.state.index_offset = binding.offset;
1029 self.state.index_format = format;
1030 self.cmd_buffer
1031 .commands
1032 .push(C::SetIndexBuffer(binding.buffer.raw.unwrap()));
1033 }
1034 unsafe fn set_vertex_buffer<'a>(
1035 &mut self,
1036 index: u32,
1037 binding: crate::BufferBinding<'a, super::Buffer>,
1038 ) {
1039 self.state.dirty_vbuf_mask |= 1 << index;
1040 let (_, ref mut vb) = self.state.vertex_buffers[index as usize];
1041 *vb = Some(super::BufferBinding {
1042 raw: binding.buffer.raw.unwrap(),
1043 offset: binding.offset,
1044 });
1045 }
1046 unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth: Range<f32>) {
1047 self.cmd_buffer.commands.push(C::SetViewport {
1048 rect: crate::Rect {
1049 x: rect.x as i32,
1050 y: rect.y as i32,
1051 w: rect.w as i32,
1052 h: rect.h as i32,
1053 },
1054 depth,
1055 });
1056 }
1057 unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {
1058 self.cmd_buffer.commands.push(C::SetScissor(crate::Rect {
1059 x: rect.x as i32,
1060 y: rect.y as i32,
1061 w: rect.w as i32,
1062 h: rect.h as i32,
1063 }));
1064 }
1065 unsafe fn set_stencil_reference(&mut self, value: u32) {
1066 self.state.stencil.front.reference = value;
1067 self.state.stencil.back.reference = value;
1068 self.rebind_stencil_func();
1069 }
1070 unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) {
1071 self.cmd_buffer.commands.push(C::SetBlendConstant(*color));
1072 }
1073
1074 unsafe fn draw(
1075 &mut self,
1076 first_vertex: u32,
1077 vertex_count: u32,
1078 first_instance: u32,
1079 instance_count: u32,
1080 ) {
1081 self.prepare_draw(first_instance);
1082 self.cmd_buffer.commands.push(C::Draw {
1083 topology: self.state.topology,
1084 first_vertex,
1085 vertex_count,
1086 first_instance,
1087 instance_count,
1088 });
1089 }
1090 unsafe fn draw_indexed(
1091 &mut self,
1092 first_index: u32,
1093 index_count: u32,
1094 base_vertex: i32,
1095 first_instance: u32,
1096 instance_count: u32,
1097 ) {
1098 self.prepare_draw(first_instance);
1099 let (index_size, index_type) = match self.state.index_format {
1100 wgt::IndexFormat::Uint16 => (2, glow::UNSIGNED_SHORT),
1101 wgt::IndexFormat::Uint32 => (4, glow::UNSIGNED_INT),
1102 };
1103 let index_offset = self.state.index_offset + index_size * first_index as wgt::BufferAddress;
1104 self.cmd_buffer.commands.push(C::DrawIndexed {
1105 topology: self.state.topology,
1106 index_type,
1107 index_offset,
1108 index_count,
1109 base_vertex,
1110 first_instance,
1111 instance_count,
1112 });
1113 }
1114 unsafe fn draw_mesh_tasks(
1115 &mut self,
1116 _group_count_x: u32,
1117 _group_count_y: u32,
1118 _group_count_z: u32,
1119 ) {
1120 unreachable!()
1121 }
1122 unsafe fn draw_indirect(
1123 &mut self,
1124 buffer: &super::Buffer,
1125 offset: wgt::BufferAddress,
1126 draw_count: u32,
1127 ) {
1128 self.prepare_draw(0);
1129 for draw in 0..draw_count as wgt::BufferAddress {
1130 let indirect_offset =
1131 offset + draw * size_of::<wgt::DrawIndirectArgs>() as wgt::BufferAddress;
1132 self.cmd_buffer.commands.push(C::DrawIndirect {
1133 topology: self.state.topology,
1134 indirect_buf: buffer.raw.unwrap(),
1135 indirect_offset,
1136 });
1137 }
1138 }
1139 unsafe fn draw_indexed_indirect(
1140 &mut self,
1141 buffer: &super::Buffer,
1142 offset: wgt::BufferAddress,
1143 draw_count: u32,
1144 ) {
1145 self.prepare_draw(0);
1146 let index_type = match self.state.index_format {
1147 wgt::IndexFormat::Uint16 => glow::UNSIGNED_SHORT,
1148 wgt::IndexFormat::Uint32 => glow::UNSIGNED_INT,
1149 };
1150 for draw in 0..draw_count as wgt::BufferAddress {
1151 let indirect_offset =
1152 offset + draw * size_of::<wgt::DrawIndexedIndirectArgs>() as wgt::BufferAddress;
1153 self.cmd_buffer.commands.push(C::DrawIndexedIndirect {
1154 topology: self.state.topology,
1155 index_type,
1156 indirect_buf: buffer.raw.unwrap(),
1157 indirect_offset,
1158 });
1159 }
1160 }
1161 unsafe fn draw_mesh_tasks_indirect(
1162 &mut self,
1163 _buffer: &<Self::A as crate::Api>::Buffer,
1164 _offset: wgt::BufferAddress,
1165 _draw_count: u32,
1166 ) {
1167 unreachable!()
1168 }
1169 unsafe fn draw_indirect_count(
1170 &mut self,
1171 _buffer: &super::Buffer,
1172 _offset: wgt::BufferAddress,
1173 _count_buffer: &super::Buffer,
1174 _count_offset: wgt::BufferAddress,
1175 _max_count: u32,
1176 ) {
1177 unreachable!()
1178 }
1179 unsafe fn draw_indexed_indirect_count(
1180 &mut self,
1181 _buffer: &super::Buffer,
1182 _offset: wgt::BufferAddress,
1183 _count_buffer: &super::Buffer,
1184 _count_offset: wgt::BufferAddress,
1185 _max_count: u32,
1186 ) {
1187 unreachable!()
1188 }
1189 unsafe fn draw_mesh_tasks_indirect_count(
1190 &mut self,
1191 _buffer: &<Self::A as crate::Api>::Buffer,
1192 _offset: wgt::BufferAddress,
1193 _count_buffer: &<Self::A as crate::Api>::Buffer,
1194 _count_offset: wgt::BufferAddress,
1195 _max_count: u32,
1196 ) {
1197 unreachable!()
1198 }
1199
1200 unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor<super::QuerySet>) {
1203 debug_assert!(self.state.end_of_pass_timestamp.is_none());
1204 if let Some(ref t) = desc.timestamp_writes {
1205 if let Some(index) = t.beginning_of_pass_write_index {
1206 unsafe { self.write_timestamp(t.query_set, index) }
1207 }
1208 self.state.end_of_pass_timestamp = t
1209 .end_of_pass_write_index
1210 .map(|index| t.query_set.queries[index as usize]);
1211 }
1212
1213 if let Some(label) = desc.label {
1214 let range = self.cmd_buffer.add_marker(label);
1215 self.cmd_buffer.commands.push(C::PushDebugGroup(range));
1216 self.state.has_pass_label = true;
1217 }
1218 }
1219 unsafe fn end_compute_pass(&mut self) {
1220 if self.state.has_pass_label {
1221 self.cmd_buffer.commands.push(C::PopDebugGroup);
1222 self.state.has_pass_label = false;
1223 }
1224
1225 if let Some(query) = self.state.end_of_pass_timestamp.take() {
1226 self.cmd_buffer.commands.push(C::TimestampQuery(query));
1227 }
1228 }
1229
1230 unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {
1231 self.set_pipeline_inner(&pipeline.inner);
1232 }
1233
1234 unsafe fn dispatch_workgroups(&mut self, count: [u32; 3]) {
1235 if count.contains(&0) {
1237 return;
1238 }
1239 self.cmd_buffer.commands.push(C::Dispatch(count));
1240 }
1241 unsafe fn dispatch_workgroups_indirect(
1242 &mut self,
1243 buffer: &super::Buffer,
1244 offset: wgt::BufferAddress,
1245 ) {
1246 self.cmd_buffer.commands.push(C::DispatchIndirect {
1247 indirect_buf: buffer.raw.unwrap(),
1248 indirect_offset: offset,
1249 });
1250 }
1251
1252 unsafe fn build_acceleration_structures<'a, T>(
1253 &mut self,
1254 _descriptor_count: u32,
1255 _descriptors: T,
1256 ) where
1257 super::Api: 'a,
1258 T: IntoIterator<
1259 Item = crate::BuildAccelerationStructureDescriptor<
1260 'a,
1261 super::Buffer,
1262 super::AccelerationStructure,
1263 >,
1264 >,
1265 {
1266 unimplemented!()
1267 }
1268
1269 unsafe fn place_acceleration_structure_barrier(
1270 &mut self,
1271 _barriers: crate::AccelerationStructureBarrier,
1272 ) {
1273 unimplemented!()
1274 }
1275
1276 unsafe fn copy_acceleration_structure_to_acceleration_structure(
1277 &mut self,
1278 _src: &super::AccelerationStructure,
1279 _dst: &super::AccelerationStructure,
1280 _copy: wgt::AccelerationStructureCopy,
1281 ) {
1282 unimplemented!()
1283 }
1284
1285 unsafe fn read_acceleration_structure_compact_size(
1286 &mut self,
1287 _acceleration_structure: &super::AccelerationStructure,
1288 _buf: &super::Buffer,
1289 ) {
1290 unimplemented!()
1291 }
1292
1293 unsafe fn set_acceleration_structure_dependencies(
1294 _command_buffers: &[&super::CommandBuffer],
1295 _dependencies: &[&super::AccelerationStructure],
1296 ) {
1297 unimplemented!()
1298 }
1299
1300 unsafe fn begin_ray_tracing_pass(&mut self, _desc: &crate::RayTracingPassDescriptor) {
1301 unimplemented!()
1302 }
1303
1304 unsafe fn end_ray_tracing_pass(&mut self) {
1305 unimplemented!()
1306 }
1307
1308 unsafe fn set_ray_tracing_pipeline(
1309 &mut self,
1310 _pipeline: &<Self::A as crate::Api>::RayTracingPipeline,
1311 ) {
1312 unimplemented!()
1313 }
1314
1315 unsafe fn trace_rays(
1316 &mut self,
1317 _count: [u32; 3],
1318 _ray_generation_group_data: crate::PipelineGroupData<super::Buffer>,
1319 _miss_group_data: crate::PipelineGroupData<super::Buffer>,
1320 _intersection_group_data: crate::PipelineGroupData<super::Buffer>,
1321 ) {
1322 unimplemented!()
1323 }
1324}