1#![cfg_attr(
22 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
23 allow(dead_code, unused_variables, clippy::needless_pass_by_value)
24)]
25
26#[cfg(target_os = "windows")]
27mod d3d12va;
28#[cfg(target_os = "macos")]
29mod videotoolbox;
30#[cfg(target_os = "linux")]
31mod vulkan;
32
33use std::sync::atomic::{AtomicU64, Ordering};
34
35use alpha2_media::{ColorMetadata, EncodeError, VideoRateControl};
36use alpha2_time::{FrameRate, MediaTime};
37
38#[cfg(all(test, target_os = "windows"))]
39pub(crate) use d3d12va::encode_no_rate_control_frames;
40#[cfg(target_os = "windows")]
41pub(crate) use d3d12va::probe_d3d12va_rate_control;
42#[cfg(target_os = "windows")]
43pub use d3d12va::{
44 D3D12EncodeProbe, D3D12RateControlOpen, D3D12RateControlRunner, D3D12TestEncodeRunner,
45 D3D12VA_TEST_ENCODE_SIZE, d3d12va_encoder, open_d3d12va_rate_control, probe_d3d12va_encode,
46 set_d3d12va_rate_control_runner, set_d3d12va_test_encode_runner,
47};
48#[cfg(target_os = "macos")]
49pub use videotoolbox::{VideoToolboxEncodeProbe, probe_videotoolbox_encode};
50#[cfg(target_os = "linux")]
51pub(crate) use vulkan::probe_vulkan_rate_control;
52#[cfg(target_os = "linux")]
53pub use vulkan::{VulkanEncodeProbe, probe_vulkan_encode};
54
55use crate::{EncodeStageTimings, NativeVideoCodec, NativeVideoEncoderSelection};
56
57#[derive(Copy, Clone, Debug, Eq, PartialEq)]
59pub enum HardwareEncodeBackend {
60 Vulkan,
62 VideoToolbox,
65 D3D12Va,
67}
68
69impl HardwareEncodeBackend {
70 #[must_use]
72 pub const fn as_str(self) -> &'static str {
73 match self {
74 Self::Vulkan => "vulkan",
75 Self::VideoToolbox => "videotoolbox",
76 Self::D3D12Va => "d3d12va",
77 }
78 }
79}
80
81#[derive(Copy, Clone, Debug, Eq, PartialEq)]
83pub enum EncoderInputLayout {
84 Nv12,
87}
88
89impl EncoderInputLayout {
90 #[must_use]
92 pub const fn as_str(self) -> &'static str {
93 match self {
94 Self::Nv12 => "nv12",
95 }
96 }
97
98 #[must_use]
100 pub const fn frame_bytes(self, width: u32, height: u32) -> u64 {
101 match self {
102 Self::Nv12 => {
103 let luma = width as u64 * height as u64;
104 luma + luma / 2
105 }
106 }
107 }
108}
109
110#[derive(Copy, Clone, Debug, Eq, PartialEq)]
112pub enum EncoderInputHandoff {
113 GpuCopy,
116 DirectTarget,
119}
120
121impl EncoderInputHandoff {
122 #[must_use]
124 pub const fn as_str(self) -> &'static str {
125 match self {
126 Self::GpuCopy => "gpu-copy",
127 Self::DirectTarget => "direct-target",
128 }
129 }
130}
131
132#[derive(Clone, Debug, Eq, PartialEq)]
134pub struct HardwareEncodeCapability {
135 pub backend: HardwareEncodeBackend,
137 pub encoder: &'static str,
139 pub codec: NativeVideoCodec,
141 pub gpu_input_only: bool,
145 pub input_layout: EncoderInputLayout,
147 pub handoff: EncoderInputHandoff,
149 pub shares_renderer_device: bool,
152 pub minimum: (u32, u32),
154 pub maximum: (u32, u32),
156 pub granularity: (u32, u32),
158 pub max_p_picture_l0_references: Option<u32>,
160 pub max_b_picture_l0_references: Option<u32>,
164 pub max_l1_references: Option<u32>,
166 pub rate_control_modes: Vec<&'static str>,
169 pub plane_ring_slots: usize,
173 pub handoff_retained_surfaces: usize,
178 pub codec_retained_surfaces: usize,
181}
182
183impl HardwareEncodeCapability {
184 #[must_use]
186 pub const fn retained_surfaces(&self) -> usize {
187 self.handoff_retained_surfaces
188 .saturating_add(self.codec_retained_surfaces)
189 }
190}
191
192impl HardwareEncodeCapability {
193 #[must_use]
195 pub const fn coded(&self, width: u32, height: u32) -> (u32, u32) {
196 (
197 align_up(width, self.granularity.0),
198 align_up(height, self.granularity.1),
199 )
200 }
201
202 pub fn accepts(&self, width: u32, height: u32) -> Result<(), String> {
207 if !width.is_multiple_of(2) || !height.is_multiple_of(2) {
208 return Err(format!(
209 "a {width}x{height} output has no 4:2:0 chroma plane"
210 ));
211 }
212 let coded = self.coded(width, height);
213 if coded.0 < self.minimum.0
214 || coded.1 < self.minimum.1
215 || coded.0 > self.maximum.0
216 || coded.1 > self.maximum.1
217 {
218 return Err(format!(
219 "a {width}x{height} output codes as {}x{}, outside {}'s {}x{}..{}x{}",
220 coded.0,
221 coded.1,
222 self.encoder,
223 self.minimum.0,
224 self.minimum.1,
225 self.maximum.0,
226 self.maximum.1
227 ));
228 }
229 Ok(())
230 }
231}
232
233const fn align_up(value: u32, granularity: u32) -> u32 {
234 if granularity <= 1 {
235 return value;
236 }
237 value.div_ceil(granularity).saturating_mul(granularity)
238}
239
240#[derive(Clone)]
242pub struct HardwareEncodeDevice {
243 #[cfg(target_os = "linux")]
244 vulkan: alpha2_native_gpu::SharedVulkanContext,
245 #[cfg(target_os = "macos")]
246 metal: alpha2_native_gpu::SharedMetalContext,
247 #[cfg(target_os = "windows")]
248 d3d12: alpha2_native_gpu::SharedD3D12Context,
249}
250
251impl std::fmt::Debug for HardwareEncodeDevice {
252 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 formatter
254 .debug_struct("HardwareEncodeDevice")
255 .finish_non_exhaustive()
256 }
257}
258
259#[derive(Clone, Debug)]
261pub struct HardwareEncodeRequest<'a> {
262 pub width: u32,
264 pub height: u32,
266 pub codec: NativeVideoCodec,
269 pub frame_rate: FrameRate,
271 pub rate_control: VideoRateControl,
273 pub color: ColorMetadata,
275 pub output: &'a crate::OutputTarget,
278 pub container: alpha2_media::Container,
281 pub audio: Option<crate::AudioStreamConfig>,
283}
284
285pub(crate) fn session_frame_rate(rate: FrameRate) -> Result<(i32, i32), EncodeError> {
290 match (
291 i32::try_from(rate.numerator()),
292 i32::try_from(rate.denominator()),
293 ) {
294 (Ok(numerator), Ok(denominator)) => Ok((numerator, denominator)),
295 _ => Err(EncodeError::Adapter(format!(
296 "frame rate {}/{} is out of range",
297 rate.numerator(),
298 rate.denominator()
299 ))),
300 }
301}
302
303#[derive(Debug)]
305pub enum HardwareEncodeOpenError {
306 Refused(String),
309 Failed(EncodeError),
311}
312
313impl std::fmt::Display for HardwareEncodeOpenError {
314 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315 match self {
316 Self::Refused(reason) => formatter.write_str(reason),
317 Self::Failed(error) => write!(formatter, "{error}"),
318 }
319 }
320}
321
322impl HardwareEncodeDevice {
323 #[cfg(target_os = "linux")]
325 #[must_use]
326 pub const fn vulkan(context: alpha2_native_gpu::SharedVulkanContext) -> Self {
327 Self { vulkan: context }
328 }
329
330 #[cfg(target_os = "macos")]
332 #[must_use]
333 pub const fn metal(context: alpha2_native_gpu::SharedMetalContext) -> Self {
334 Self { metal: context }
335 }
336
337 #[cfg(target_os = "windows")]
339 #[must_use]
340 pub const fn d3d12(context: alpha2_native_gpu::SharedD3D12Context) -> Self {
341 Self { d3d12: context }
342 }
343
344 #[cfg_attr(
352 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
353 allow(clippy::unused_self)
354 )]
355 pub fn capability(&self, codec: NativeVideoCodec) -> Result<HardwareEncodeCapability, String> {
356 #[cfg(target_os = "windows")]
357 return d3d12va::capability(&self.d3d12, codec);
358 #[cfg(any(target_os = "linux", target_os = "macos"))]
359 {
360 let capability = self.preferred_capability()?;
361 if capability.codec == codec {
362 Ok(capability)
363 } else {
364 Err(format!(
365 "{} encodes {}, not {}",
366 capability.encoder,
367 capability.codec.as_str(),
368 codec.as_str()
369 ))
370 }
371 }
372 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
373 Err("this platform has no hardware encode backend yet".to_owned())
374 }
375
376 #[cfg_attr(
382 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
383 allow(clippy::unused_self)
384 )]
385 pub fn preferred_capability(&self) -> Result<HardwareEncodeCapability, String> {
386 #[cfg(target_os = "linux")]
387 return vulkan::capability(&self.vulkan);
388 #[cfg(target_os = "macos")]
389 return videotoolbox::capability(&self.metal);
390 #[cfg(target_os = "windows")]
391 return d3d12va::preferred_capability(&self.d3d12);
392 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
393 Err("this platform has no hardware encode backend yet".to_owned())
394 }
395
396 #[cfg_attr(
404 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
405 allow(clippy::unused_self)
406 )]
407 pub fn open(
408 &self,
409 request: &HardwareEncodeRequest<'_>,
410 ) -> Result<(HardwareEncodeSession, HardwareEncodeInput), HardwareEncodeOpenError> {
411 let generation = NEXT_POOL_GENERATION.fetch_add(1, Ordering::Relaxed);
412 #[cfg(any(target_os = "linux", target_os = "macos"))]
414 self.capability(request.codec)
415 .map_err(HardwareEncodeOpenError::Refused)?;
416 #[cfg(target_os = "linux")]
417 {
418 let (session, input) = vulkan::open(&self.vulkan, request, generation)?;
419 Ok((
420 HardwareEncodeSession(SessionBackend::Vulkan(session)),
421 HardwareEncodeInput {
422 backend: InputBackend::Vulkan(input),
423 generation,
424 },
425 ))
426 }
427 #[cfg(target_os = "macos")]
428 {
429 let (session, input) = videotoolbox::open(&self.metal, request, generation)?;
430 Ok((
431 HardwareEncodeSession(SessionBackend::VideoToolbox(session)),
432 HardwareEncodeInput {
433 backend: InputBackend::VideoToolbox(input),
434 generation,
435 },
436 ))
437 }
438 #[cfg(target_os = "windows")]
439 {
440 let (session, input) = d3d12va::open(&self.d3d12, request, generation)?;
441 Ok((
442 HardwareEncodeSession(SessionBackend::D3D12(session)),
443 HardwareEncodeInput {
444 backend: InputBackend::D3D12(input),
445 generation,
446 },
447 ))
448 }
449 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
450 {
451 let _ = (request, generation);
452 Err(HardwareEncodeOpenError::Refused(
453 "this platform has no hardware encode backend yet".to_owned(),
454 ))
455 }
456 }
457}
458
459static NEXT_POOL_GENERATION: AtomicU64 = AtomicU64::new(1);
463
464#[derive(Copy, Clone, Debug, Eq, PartialEq)]
466pub struct EncoderSurfaceDescriptor {
467 pub backend: HardwareEncodeBackend,
469 pub pool_generation: u64,
471 pub layout: EncoderInputLayout,
473 pub visible: (u32, u32),
475 pub color: ColorMetadata,
477}
478
479pub struct EncoderSurface {
484 descriptor: EncoderSurfaceDescriptor,
485 backing: SurfaceBacking,
486}
487
488enum SurfaceBacking {
489 #[cfg(target_os = "linux")]
490 Vulkan(vulkan::VulkanEncoderFrame),
491 #[cfg(target_os = "macos")]
492 VideoToolbox(videotoolbox::VideoToolboxEncoderFrame),
493 #[cfg(target_os = "windows")]
494 D3D12(d3d12va::D3D12EncoderFrame),
495 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
496 Unsupported(std::convert::Infallible),
497}
498
499impl EncoderSurface {
500 #[must_use]
502 pub const fn descriptor(&self) -> &EncoderSurfaceDescriptor {
503 &self.descriptor
504 }
505}
506
507#[must_use = "a begun frame must be submitted, or its planes stay claimed"]
510pub struct InputFrame {
511 #[cfg(any(target_os = "linux", target_os = "windows"))]
513 slot: usize,
514 #[cfg(target_os = "macos")]
516 pixel_buffer: usize,
517}
518
519#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
521pub struct EncoderPoolStats {
522 pub acquired: u64,
524 pub allocated: u64,
528 pub copy_operations: u64,
530 pub copy_bytes: u64,
532}
533
534pub struct HardwareEncodeInput {
536 backend: InputBackend,
537 generation: u64,
538}
539
540enum InputBackend {
541 #[cfg(target_os = "linux")]
542 Vulkan(vulkan::VulkanEncodeInput),
543 #[cfg(target_os = "macos")]
544 VideoToolbox(videotoolbox::VideoToolboxEncodeInput),
545 #[cfg(target_os = "windows")]
546 D3D12(d3d12va::D3D12EncodeInput),
547 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
548 Unsupported(std::convert::Infallible),
549}
550
551impl HardwareEncodeInput {
552 pub fn acquire_surface(&mut self) -> Result<EncoderSurface, EncodeError> {
560 match &mut self.backend {
561 #[cfg(target_os = "linux")]
562 InputBackend::Vulkan(input) => {
563 let frame = input.acquire_frame()?;
564 Ok(EncoderSurface {
565 descriptor: input.descriptor(self.generation),
566 backing: SurfaceBacking::Vulkan(frame),
567 })
568 }
569 #[cfg(target_os = "macos")]
570 InputBackend::VideoToolbox(input) => {
571 let frame = input.acquire_frame()?;
572 Ok(EncoderSurface {
573 descriptor: input.descriptor(self.generation),
574 backing: SurfaceBacking::VideoToolbox(frame),
575 })
576 }
577 #[cfg(target_os = "windows")]
578 InputBackend::D3D12(input) => {
579 let frame = input.acquire_frame()?;
580 Ok(EncoderSurface {
581 descriptor: input.descriptor(self.generation),
582 backing: SurfaceBacking::D3D12(frame),
583 })
584 }
585 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
586 InputBackend::Unsupported(never) => match *never {},
587 }
588 }
589
590 pub fn begin_frame(&mut self, surface: &EncoderSurface) -> Result<InputFrame, EncodeError> {
599 self.check(surface)?;
600 match &mut self.backend {
601 #[cfg(target_os = "linux")]
602 InputBackend::Vulkan(input) => input.begin_frame(),
603 #[cfg(target_os = "macos")]
604 InputBackend::VideoToolbox(input) => match &surface.backing {
605 SurfaceBacking::VideoToolbox(backing) => input.begin_frame(backing),
606 },
607 #[cfg(target_os = "windows")]
608 InputBackend::D3D12(input) => input.begin_frame(),
609 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
610 InputBackend::Unsupported(never) => match *never {},
611 }
612 }
613
614 #[must_use]
616 pub fn planes(&self, frame: &InputFrame) -> (&wgpu::Texture, &wgpu::Texture) {
617 match &self.backend {
618 #[cfg(target_os = "linux")]
619 InputBackend::Vulkan(input) => input.planes(frame),
620 #[cfg(target_os = "macos")]
621 InputBackend::VideoToolbox(input) => input.planes(frame),
622 #[cfg(target_os = "windows")]
623 InputBackend::D3D12(input) => input.planes(frame),
624 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
625 InputBackend::Unsupported(never) => match *never {},
626 }
627 }
628
629 pub fn submit(
636 &mut self,
637 frame: InputFrame,
638 surface: &mut EncoderSurface,
639 ) -> Result<(), EncodeError> {
640 self.check(surface)?;
641 match (&mut self.backend, &mut surface.backing) {
642 #[cfg(target_os = "linux")]
643 (InputBackend::Vulkan(input), SurfaceBacking::Vulkan(backing)) => {
644 input.submit(frame, backing)
645 }
646 #[cfg(target_os = "macos")]
647 (InputBackend::VideoToolbox(input), SurfaceBacking::VideoToolbox(backing)) => {
648 input.submit(frame, backing)
649 }
650 #[cfg(target_os = "windows")]
651 (InputBackend::D3D12(input), SurfaceBacking::D3D12(backing)) => {
652 input.submit(frame, backing)
653 }
654 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
655 (InputBackend::Unsupported(never), _) => match *never {},
656 }
657 }
658
659 pub fn set_time(&self, surface: &mut EncoderSurface, time: MediaTime) {
661 match (&self.backend, &mut surface.backing) {
662 #[cfg(target_os = "linux")]
663 (InputBackend::Vulkan(input), SurfaceBacking::Vulkan(backing)) => {
664 backing.set_pts(input.timestamp(time));
665 }
666 #[cfg(target_os = "macos")]
667 (InputBackend::VideoToolbox(input), SurfaceBacking::VideoToolbox(backing)) => {
668 backing.set_pts(input.timestamp(time));
669 }
670 #[cfg(target_os = "windows")]
671 (InputBackend::D3D12(input), SurfaceBacking::D3D12(backing)) => {
672 backing.set_pts(input.timestamp(time));
673 }
674 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
675 (InputBackend::Unsupported(never), _) => match *never {},
676 }
677 }
678
679 #[must_use]
681 pub fn stats(&self) -> EncoderPoolStats {
682 match &self.backend {
683 #[cfg(target_os = "linux")]
684 InputBackend::Vulkan(input) => input.stats(),
685 #[cfg(target_os = "macos")]
686 InputBackend::VideoToolbox(input) => input.stats(),
687 #[cfg(target_os = "windows")]
688 InputBackend::D3D12(input) => input.stats(),
689 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
690 InputBackend::Unsupported(never) => match *never {},
691 }
692 }
693
694 pub fn finish(self) -> Result<(), EncodeError> {
700 match self.backend {
701 #[cfg(target_os = "linux")]
702 InputBackend::Vulkan(input) => input.finish(),
703 #[cfg(target_os = "macos")]
704 InputBackend::VideoToolbox(input) => input.finish(),
705 #[cfg(target_os = "windows")]
706 InputBackend::D3D12(input) => input.finish(),
707 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
708 InputBackend::Unsupported(never) => match never {},
709 }
710 }
711
712 fn check(&self, surface: &EncoderSurface) -> Result<(), EncodeError> {
713 if surface.descriptor.pool_generation == self.generation {
714 Ok(())
715 } else {
716 Err(EncodeError::Adapter(format!(
717 "encoder surface from pool {} reached pool {}",
718 surface.descriptor.pool_generation, self.generation
719 )))
720 }
721 }
722}
723
724pub struct HardwareEncodeSession(SessionBackend);
726
727enum SessionBackend {
728 #[cfg(target_os = "linux")]
729 Vulkan(vulkan::VulkanEncodeSession),
730 #[cfg(target_os = "macos")]
731 VideoToolbox(videotoolbox::VideoToolboxEncodeSession),
732 #[cfg(target_os = "windows")]
733 D3D12(d3d12va::D3D12EncodeSession),
734 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
735 Unsupported(std::convert::Infallible),
736}
737
738impl HardwareEncodeSession {
739 #[must_use]
742 pub fn selection(&self) -> &NativeVideoEncoderSelection {
743 match &self.0 {
744 #[cfg(target_os = "linux")]
745 SessionBackend::Vulkan(session) => session.selection(),
746 #[cfg(target_os = "macos")]
747 SessionBackend::VideoToolbox(session) => session.selection(),
748 #[cfg(target_os = "windows")]
749 SessionBackend::D3D12(session) => session.selection(),
750 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
751 SessionBackend::Unsupported(never) => match *never {},
752 }
753 }
754
755 #[must_use]
758 pub fn stage_timings(&self) -> EncodeStageTimings {
759 match &self.0 {
760 #[cfg(target_os = "linux")]
761 SessionBackend::Vulkan(session) => session.stage_timings(),
762 #[cfg(target_os = "macos")]
763 SessionBackend::VideoToolbox(session) => session.stage_timings(),
764 #[cfg(target_os = "windows")]
765 SessionBackend::D3D12(session) => session.stage_timings(),
766 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
767 SessionBackend::Unsupported(never) => match *never {},
768 }
769 }
770
771 pub fn encode(&mut self, surface: &EncoderSurface) -> Result<(), EncodeError> {
777 match (&mut self.0, &surface.backing) {
778 #[cfg(target_os = "linux")]
779 (SessionBackend::Vulkan(session), SurfaceBacking::Vulkan(frame)) => {
780 session.encode(surface.descriptor.pool_generation, frame)
781 }
782 #[cfg(target_os = "macos")]
783 (SessionBackend::VideoToolbox(session), SurfaceBacking::VideoToolbox(frame)) => {
784 session.encode(surface.descriptor.pool_generation, frame)
785 }
786 #[cfg(target_os = "windows")]
787 (SessionBackend::D3D12(session), SurfaceBacking::D3D12(frame)) => {
788 session.encode(surface.descriptor.pool_generation, frame)
789 }
790 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
791 (SessionBackend::Unsupported(never), _) => match *never {},
792 }
793 }
794
795 pub fn write_audio(&mut self, block: &alpha2_media::AudioBlock) -> Result<(), EncodeError> {
801 match &mut self.0 {
802 #[cfg(target_os = "linux")]
803 SessionBackend::Vulkan(session) => session.write_audio(block),
804 #[cfg(target_os = "macos")]
805 SessionBackend::VideoToolbox(session) => session.write_audio(block),
806 #[cfg(target_os = "windows")]
807 SessionBackend::D3D12(session) => session.write_audio(block),
808 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
809 SessionBackend::Unsupported(never) => match *never {},
810 }
811 }
812
813 pub fn finish(&mut self) -> Result<(), EncodeError> {
819 match &mut self.0 {
820 #[cfg(target_os = "linux")]
821 SessionBackend::Vulkan(session) => session.finish(),
822 #[cfg(target_os = "macos")]
823 SessionBackend::VideoToolbox(session) => session.finish(),
824 #[cfg(target_os = "windows")]
825 SessionBackend::D3D12(session) => session.finish(),
826 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
827 SessionBackend::Unsupported(never) => match *never {},
828 }
829 }
830
831 pub fn abort(&mut self) {
833 match &mut self.0 {
834 #[cfg(target_os = "linux")]
835 SessionBackend::Vulkan(session) => session.abort(),
836 #[cfg(target_os = "macos")]
837 SessionBackend::VideoToolbox(session) => session.abort(),
838 #[cfg(target_os = "windows")]
839 SessionBackend::D3D12(session) => session.abort(),
840 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
841 SessionBackend::Unsupported(never) => match *never {},
842 }
843 }
844}