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::path::Path;
34use std::sync::atomic::{AtomicU64, Ordering};
35
36use alpha2_media::{ColorMetadata, EncodeError, VideoRateControl};
37use alpha2_time::{FrameRate, MediaTime};
38
39#[cfg(all(test, target_os = "windows"))]
40pub(crate) use d3d12va::encode_no_rate_control_frames;
41#[cfg(target_os = "windows")]
42pub(crate) use d3d12va::probe_d3d12va_rate_control;
43#[cfg(target_os = "windows")]
44pub use d3d12va::{
45 D3D12EncodeProbe, D3D12RateControlOpen, D3D12RateControlRunner, D3D12TestEncodeRunner,
46 D3D12VA_TEST_ENCODE_SIZE, d3d12va_encoder, open_d3d12va_rate_control, probe_d3d12va_encode,
47 set_d3d12va_rate_control_runner, set_d3d12va_test_encode_runner,
48};
49#[cfg(target_os = "macos")]
50pub use videotoolbox::{VideoToolboxEncodeProbe, probe_videotoolbox_encode};
51#[cfg(target_os = "linux")]
52pub(crate) use vulkan::probe_vulkan_rate_control;
53#[cfg(target_os = "linux")]
54pub use vulkan::{VulkanEncodeProbe, probe_vulkan_encode};
55
56use crate::{EncodeStageTimings, NativeVideoCodec, NativeVideoEncoderSelection};
57
58#[derive(Copy, Clone, Debug, Eq, PartialEq)]
60pub enum HardwareEncodeBackend {
61 Vulkan,
63 VideoToolbox,
66 D3D12Va,
68}
69
70impl HardwareEncodeBackend {
71 #[must_use]
73 pub const fn as_str(self) -> &'static str {
74 match self {
75 Self::Vulkan => "vulkan",
76 Self::VideoToolbox => "videotoolbox",
77 Self::D3D12Va => "d3d12va",
78 }
79 }
80}
81
82#[derive(Copy, Clone, Debug, Eq, PartialEq)]
84pub enum EncoderInputLayout {
85 Nv12,
88}
89
90impl EncoderInputLayout {
91 #[must_use]
93 pub const fn as_str(self) -> &'static str {
94 match self {
95 Self::Nv12 => "nv12",
96 }
97 }
98
99 #[must_use]
101 pub const fn frame_bytes(self, width: u32, height: u32) -> u64 {
102 match self {
103 Self::Nv12 => {
104 let luma = width as u64 * height as u64;
105 luma + luma / 2
106 }
107 }
108 }
109}
110
111#[derive(Copy, Clone, Debug, Eq, PartialEq)]
113pub enum EncoderInputHandoff {
114 GpuCopy,
117 DirectTarget,
120}
121
122impl EncoderInputHandoff {
123 #[must_use]
125 pub const fn as_str(self) -> &'static str {
126 match self {
127 Self::GpuCopy => "gpu-copy",
128 Self::DirectTarget => "direct-target",
129 }
130 }
131}
132
133#[derive(Clone, Debug, Eq, PartialEq)]
135pub struct HardwareEncodeCapability {
136 pub backend: HardwareEncodeBackend,
138 pub encoder: &'static str,
140 pub codec: NativeVideoCodec,
142 pub gpu_input_only: bool,
146 pub input_layout: EncoderInputLayout,
148 pub handoff: EncoderInputHandoff,
150 pub shares_renderer_device: bool,
153 pub minimum: (u32, u32),
155 pub maximum: (u32, u32),
157 pub granularity: (u32, u32),
159 pub max_p_picture_l0_references: Option<u32>,
161 pub max_b_picture_l0_references: Option<u32>,
165 pub max_l1_references: Option<u32>,
167 pub rate_control_modes: Vec<&'static str>,
170 pub plane_ring_slots: usize,
174 pub handoff_retained_surfaces: usize,
179 pub codec_retained_surfaces: usize,
182}
183
184impl HardwareEncodeCapability {
185 #[must_use]
187 pub const fn retained_surfaces(&self) -> usize {
188 self.handoff_retained_surfaces
189 .saturating_add(self.codec_retained_surfaces)
190 }
191}
192
193impl HardwareEncodeCapability {
194 #[must_use]
196 pub const fn coded(&self, width: u32, height: u32) -> (u32, u32) {
197 (
198 align_up(width, self.granularity.0),
199 align_up(height, self.granularity.1),
200 )
201 }
202
203 pub fn accepts(&self, width: u32, height: u32) -> Result<(), String> {
208 if !width.is_multiple_of(2) || !height.is_multiple_of(2) {
209 return Err(format!(
210 "a {width}x{height} output has no 4:2:0 chroma plane"
211 ));
212 }
213 let coded = self.coded(width, height);
214 if coded.0 < self.minimum.0
215 || coded.1 < self.minimum.1
216 || coded.0 > self.maximum.0
217 || coded.1 > self.maximum.1
218 {
219 return Err(format!(
220 "a {width}x{height} output codes as {}x{}, outside {}'s {}x{}..{}x{}",
221 coded.0,
222 coded.1,
223 self.encoder,
224 self.minimum.0,
225 self.minimum.1,
226 self.maximum.0,
227 self.maximum.1
228 ));
229 }
230 Ok(())
231 }
232}
233
234const fn align_up(value: u32, granularity: u32) -> u32 {
235 if granularity <= 1 {
236 return value;
237 }
238 value.div_ceil(granularity).saturating_mul(granularity)
239}
240
241#[derive(Clone)]
243pub struct HardwareEncodeDevice {
244 #[cfg(target_os = "linux")]
245 vulkan: alpha2_native_gpu::SharedVulkanContext,
246 #[cfg(target_os = "macos")]
247 metal: alpha2_native_gpu::SharedMetalContext,
248 #[cfg(target_os = "windows")]
249 d3d12: alpha2_native_gpu::SharedD3D12Context,
250}
251
252impl std::fmt::Debug for HardwareEncodeDevice {
253 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 formatter
255 .debug_struct("HardwareEncodeDevice")
256 .finish_non_exhaustive()
257 }
258}
259
260#[derive(Clone, Debug)]
262pub struct HardwareEncodeRequest<'a> {
263 pub width: u32,
265 pub height: u32,
267 pub codec: NativeVideoCodec,
270 pub frame_rate: FrameRate,
272 pub rate_control: VideoRateControl,
274 pub color: ColorMetadata,
276 pub output: &'a Path,
278 pub audio: Option<crate::AacStreamConfig>,
280}
281
282pub(crate) fn session_frame_rate(rate: FrameRate) -> Result<(i32, i32), EncodeError> {
287 match (
288 i32::try_from(rate.numerator()),
289 i32::try_from(rate.denominator()),
290 ) {
291 (Ok(numerator), Ok(denominator)) => Ok((numerator, denominator)),
292 _ => Err(EncodeError::Adapter(format!(
293 "frame rate {}/{} is out of range",
294 rate.numerator(),
295 rate.denominator()
296 ))),
297 }
298}
299
300#[derive(Debug)]
302pub enum HardwareEncodeOpenError {
303 Refused(String),
306 Failed(EncodeError),
308}
309
310impl std::fmt::Display for HardwareEncodeOpenError {
311 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
312 match self {
313 Self::Refused(reason) => formatter.write_str(reason),
314 Self::Failed(error) => write!(formatter, "{error}"),
315 }
316 }
317}
318
319impl HardwareEncodeDevice {
320 #[cfg(target_os = "linux")]
322 #[must_use]
323 pub const fn vulkan(context: alpha2_native_gpu::SharedVulkanContext) -> Self {
324 Self { vulkan: context }
325 }
326
327 #[cfg(target_os = "macos")]
329 #[must_use]
330 pub const fn metal(context: alpha2_native_gpu::SharedMetalContext) -> Self {
331 Self { metal: context }
332 }
333
334 #[cfg(target_os = "windows")]
336 #[must_use]
337 pub const fn d3d12(context: alpha2_native_gpu::SharedD3D12Context) -> Self {
338 Self { d3d12: context }
339 }
340
341 #[cfg_attr(
349 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
350 allow(clippy::unused_self)
351 )]
352 pub fn capability(&self, codec: NativeVideoCodec) -> Result<HardwareEncodeCapability, String> {
353 #[cfg(target_os = "windows")]
354 return d3d12va::capability(&self.d3d12, codec);
355 #[cfg(any(target_os = "linux", target_os = "macos"))]
356 {
357 let capability = self.preferred_capability()?;
358 if capability.codec == codec {
359 Ok(capability)
360 } else {
361 Err(format!(
362 "{} encodes {}, not {}",
363 capability.encoder,
364 capability.codec.as_str(),
365 codec.as_str()
366 ))
367 }
368 }
369 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
370 Err("this platform has no hardware encode backend yet".to_owned())
371 }
372
373 #[cfg_attr(
379 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
380 allow(clippy::unused_self)
381 )]
382 pub fn preferred_capability(&self) -> Result<HardwareEncodeCapability, String> {
383 #[cfg(target_os = "linux")]
384 return vulkan::capability(&self.vulkan);
385 #[cfg(target_os = "macos")]
386 return videotoolbox::capability(&self.metal);
387 #[cfg(target_os = "windows")]
388 return d3d12va::preferred_capability(&self.d3d12);
389 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
390 Err("this platform has no hardware encode backend yet".to_owned())
391 }
392
393 #[cfg_attr(
401 not(any(target_os = "linux", target_os = "macos", target_os = "windows")),
402 allow(clippy::unused_self)
403 )]
404 pub fn open(
405 &self,
406 request: &HardwareEncodeRequest<'_>,
407 ) -> Result<(HardwareEncodeSession, HardwareEncodeInput), HardwareEncodeOpenError> {
408 let generation = NEXT_POOL_GENERATION.fetch_add(1, Ordering::Relaxed);
409 #[cfg(any(target_os = "linux", target_os = "macos"))]
411 self.capability(request.codec)
412 .map_err(HardwareEncodeOpenError::Refused)?;
413 #[cfg(target_os = "linux")]
414 {
415 let (session, input) = vulkan::open(&self.vulkan, request, generation)?;
416 Ok((
417 HardwareEncodeSession(SessionBackend::Vulkan(session)),
418 HardwareEncodeInput {
419 backend: InputBackend::Vulkan(input),
420 generation,
421 },
422 ))
423 }
424 #[cfg(target_os = "macos")]
425 {
426 let (session, input) = videotoolbox::open(&self.metal, request, generation)?;
427 Ok((
428 HardwareEncodeSession(SessionBackend::VideoToolbox(session)),
429 HardwareEncodeInput {
430 backend: InputBackend::VideoToolbox(input),
431 generation,
432 },
433 ))
434 }
435 #[cfg(target_os = "windows")]
436 {
437 let (session, input) = d3d12va::open(&self.d3d12, request, generation)?;
438 Ok((
439 HardwareEncodeSession(SessionBackend::D3D12(session)),
440 HardwareEncodeInput {
441 backend: InputBackend::D3D12(input),
442 generation,
443 },
444 ))
445 }
446 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
447 {
448 let _ = (request, generation);
449 Err(HardwareEncodeOpenError::Refused(
450 "this platform has no hardware encode backend yet".to_owned(),
451 ))
452 }
453 }
454}
455
456static NEXT_POOL_GENERATION: AtomicU64 = AtomicU64::new(1);
460
461#[derive(Copy, Clone, Debug, Eq, PartialEq)]
463pub struct EncoderSurfaceDescriptor {
464 pub backend: HardwareEncodeBackend,
466 pub pool_generation: u64,
468 pub layout: EncoderInputLayout,
470 pub visible: (u32, u32),
472 pub color: ColorMetadata,
474}
475
476pub struct EncoderSurface {
481 descriptor: EncoderSurfaceDescriptor,
482 backing: SurfaceBacking,
483}
484
485enum SurfaceBacking {
486 #[cfg(target_os = "linux")]
487 Vulkan(vulkan::VulkanEncoderFrame),
488 #[cfg(target_os = "macos")]
489 VideoToolbox(videotoolbox::VideoToolboxEncoderFrame),
490 #[cfg(target_os = "windows")]
491 D3D12(d3d12va::D3D12EncoderFrame),
492 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
493 Unsupported(std::convert::Infallible),
494}
495
496impl EncoderSurface {
497 #[must_use]
499 pub const fn descriptor(&self) -> &EncoderSurfaceDescriptor {
500 &self.descriptor
501 }
502}
503
504#[must_use = "a begun frame must be submitted, or its planes stay claimed"]
507pub struct InputFrame {
508 #[cfg(any(target_os = "linux", target_os = "windows"))]
510 slot: usize,
511 #[cfg(target_os = "macos")]
513 pixel_buffer: usize,
514}
515
516#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
518pub struct EncoderPoolStats {
519 pub acquired: u64,
521 pub allocated: u64,
525 pub copy_operations: u64,
527 pub copy_bytes: u64,
529}
530
531pub struct HardwareEncodeInput {
533 backend: InputBackend,
534 generation: u64,
535}
536
537enum InputBackend {
538 #[cfg(target_os = "linux")]
539 Vulkan(vulkan::VulkanEncodeInput),
540 #[cfg(target_os = "macos")]
541 VideoToolbox(videotoolbox::VideoToolboxEncodeInput),
542 #[cfg(target_os = "windows")]
543 D3D12(d3d12va::D3D12EncodeInput),
544 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
545 Unsupported(std::convert::Infallible),
546}
547
548impl HardwareEncodeInput {
549 pub fn acquire_surface(&mut self) -> Result<EncoderSurface, EncodeError> {
557 match &mut self.backend {
558 #[cfg(target_os = "linux")]
559 InputBackend::Vulkan(input) => {
560 let frame = input.acquire_frame()?;
561 Ok(EncoderSurface {
562 descriptor: input.descriptor(self.generation),
563 backing: SurfaceBacking::Vulkan(frame),
564 })
565 }
566 #[cfg(target_os = "macos")]
567 InputBackend::VideoToolbox(input) => {
568 let frame = input.acquire_frame()?;
569 Ok(EncoderSurface {
570 descriptor: input.descriptor(self.generation),
571 backing: SurfaceBacking::VideoToolbox(frame),
572 })
573 }
574 #[cfg(target_os = "windows")]
575 InputBackend::D3D12(input) => {
576 let frame = input.acquire_frame()?;
577 Ok(EncoderSurface {
578 descriptor: input.descriptor(self.generation),
579 backing: SurfaceBacking::D3D12(frame),
580 })
581 }
582 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
583 InputBackend::Unsupported(never) => match *never {},
584 }
585 }
586
587 pub fn begin_frame(&mut self, surface: &EncoderSurface) -> Result<InputFrame, EncodeError> {
596 self.check(surface)?;
597 match &mut self.backend {
598 #[cfg(target_os = "linux")]
599 InputBackend::Vulkan(input) => input.begin_frame(),
600 #[cfg(target_os = "macos")]
601 InputBackend::VideoToolbox(input) => match &surface.backing {
602 SurfaceBacking::VideoToolbox(backing) => input.begin_frame(backing),
603 },
604 #[cfg(target_os = "windows")]
605 InputBackend::D3D12(input) => input.begin_frame(),
606 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
607 InputBackend::Unsupported(never) => match *never {},
608 }
609 }
610
611 #[must_use]
613 pub fn planes(&self, frame: &InputFrame) -> (&wgpu::Texture, &wgpu::Texture) {
614 match &self.backend {
615 #[cfg(target_os = "linux")]
616 InputBackend::Vulkan(input) => input.planes(frame),
617 #[cfg(target_os = "macos")]
618 InputBackend::VideoToolbox(input) => input.planes(frame),
619 #[cfg(target_os = "windows")]
620 InputBackend::D3D12(input) => input.planes(frame),
621 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
622 InputBackend::Unsupported(never) => match *never {},
623 }
624 }
625
626 pub fn submit(
633 &mut self,
634 frame: InputFrame,
635 surface: &mut EncoderSurface,
636 ) -> Result<(), EncodeError> {
637 self.check(surface)?;
638 match (&mut self.backend, &mut surface.backing) {
639 #[cfg(target_os = "linux")]
640 (InputBackend::Vulkan(input), SurfaceBacking::Vulkan(backing)) => {
641 input.submit(frame, backing)
642 }
643 #[cfg(target_os = "macos")]
644 (InputBackend::VideoToolbox(input), SurfaceBacking::VideoToolbox(backing)) => {
645 input.submit(frame, backing)
646 }
647 #[cfg(target_os = "windows")]
648 (InputBackend::D3D12(input), SurfaceBacking::D3D12(backing)) => {
649 input.submit(frame, backing)
650 }
651 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
652 (InputBackend::Unsupported(never), _) => match *never {},
653 }
654 }
655
656 pub fn set_time(&self, surface: &mut EncoderSurface, time: MediaTime) {
658 match (&self.backend, &mut surface.backing) {
659 #[cfg(target_os = "linux")]
660 (InputBackend::Vulkan(input), SurfaceBacking::Vulkan(backing)) => {
661 backing.set_pts(input.timestamp(time));
662 }
663 #[cfg(target_os = "macos")]
664 (InputBackend::VideoToolbox(input), SurfaceBacking::VideoToolbox(backing)) => {
665 backing.set_pts(input.timestamp(time));
666 }
667 #[cfg(target_os = "windows")]
668 (InputBackend::D3D12(input), SurfaceBacking::D3D12(backing)) => {
669 backing.set_pts(input.timestamp(time));
670 }
671 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
672 (InputBackend::Unsupported(never), _) => match *never {},
673 }
674 }
675
676 #[must_use]
678 pub fn stats(&self) -> EncoderPoolStats {
679 match &self.backend {
680 #[cfg(target_os = "linux")]
681 InputBackend::Vulkan(input) => input.stats(),
682 #[cfg(target_os = "macos")]
683 InputBackend::VideoToolbox(input) => input.stats(),
684 #[cfg(target_os = "windows")]
685 InputBackend::D3D12(input) => input.stats(),
686 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
687 InputBackend::Unsupported(never) => match *never {},
688 }
689 }
690
691 pub fn finish(self) -> Result<(), EncodeError> {
697 match self.backend {
698 #[cfg(target_os = "linux")]
699 InputBackend::Vulkan(input) => input.finish(),
700 #[cfg(target_os = "macos")]
701 InputBackend::VideoToolbox(input) => input.finish(),
702 #[cfg(target_os = "windows")]
703 InputBackend::D3D12(input) => input.finish(),
704 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
705 InputBackend::Unsupported(never) => match never {},
706 }
707 }
708
709 fn check(&self, surface: &EncoderSurface) -> Result<(), EncodeError> {
710 if surface.descriptor.pool_generation == self.generation {
711 Ok(())
712 } else {
713 Err(EncodeError::Adapter(format!(
714 "encoder surface from pool {} reached pool {}",
715 surface.descriptor.pool_generation, self.generation
716 )))
717 }
718 }
719}
720
721pub struct HardwareEncodeSession(SessionBackend);
723
724enum SessionBackend {
725 #[cfg(target_os = "linux")]
726 Vulkan(vulkan::VulkanEncodeSession),
727 #[cfg(target_os = "macos")]
728 VideoToolbox(videotoolbox::VideoToolboxEncodeSession),
729 #[cfg(target_os = "windows")]
730 D3D12(d3d12va::D3D12EncodeSession),
731 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
732 Unsupported(std::convert::Infallible),
733}
734
735impl HardwareEncodeSession {
736 #[must_use]
739 pub fn selection(&self) -> &NativeVideoEncoderSelection {
740 match &self.0 {
741 #[cfg(target_os = "linux")]
742 SessionBackend::Vulkan(session) => session.selection(),
743 #[cfg(target_os = "macos")]
744 SessionBackend::VideoToolbox(session) => session.selection(),
745 #[cfg(target_os = "windows")]
746 SessionBackend::D3D12(session) => session.selection(),
747 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
748 SessionBackend::Unsupported(never) => match *never {},
749 }
750 }
751
752 #[must_use]
755 pub fn stage_timings(&self) -> EncodeStageTimings {
756 match &self.0 {
757 #[cfg(target_os = "linux")]
758 SessionBackend::Vulkan(session) => session.stage_timings(),
759 #[cfg(target_os = "macos")]
760 SessionBackend::VideoToolbox(session) => session.stage_timings(),
761 #[cfg(target_os = "windows")]
762 SessionBackend::D3D12(session) => session.stage_timings(),
763 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
764 SessionBackend::Unsupported(never) => match *never {},
765 }
766 }
767
768 pub fn encode(&mut self, surface: &EncoderSurface) -> Result<(), EncodeError> {
774 match (&mut self.0, &surface.backing) {
775 #[cfg(target_os = "linux")]
776 (SessionBackend::Vulkan(session), SurfaceBacking::Vulkan(frame)) => {
777 session.encode(surface.descriptor.pool_generation, frame)
778 }
779 #[cfg(target_os = "macos")]
780 (SessionBackend::VideoToolbox(session), SurfaceBacking::VideoToolbox(frame)) => {
781 session.encode(surface.descriptor.pool_generation, frame)
782 }
783 #[cfg(target_os = "windows")]
784 (SessionBackend::D3D12(session), SurfaceBacking::D3D12(frame)) => {
785 session.encode(surface.descriptor.pool_generation, frame)
786 }
787 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
788 (SessionBackend::Unsupported(never), _) => match *never {},
789 }
790 }
791
792 pub fn write_audio(&mut self, block: &alpha2_media::AudioBlock) -> Result<(), EncodeError> {
798 match &mut self.0 {
799 #[cfg(target_os = "linux")]
800 SessionBackend::Vulkan(session) => session.write_audio(block),
801 #[cfg(target_os = "macos")]
802 SessionBackend::VideoToolbox(session) => session.write_audio(block),
803 #[cfg(target_os = "windows")]
804 SessionBackend::D3D12(session) => session.write_audio(block),
805 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
806 SessionBackend::Unsupported(never) => match *never {},
807 }
808 }
809
810 pub fn finish(&mut self) -> Result<(), EncodeError> {
816 match &mut self.0 {
817 #[cfg(target_os = "linux")]
818 SessionBackend::Vulkan(session) => session.finish(),
819 #[cfg(target_os = "macos")]
820 SessionBackend::VideoToolbox(session) => session.finish(),
821 #[cfg(target_os = "windows")]
822 SessionBackend::D3D12(session) => session.finish(),
823 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
824 SessionBackend::Unsupported(never) => match *never {},
825 }
826 }
827
828 pub fn abort(&mut self) {
830 match &mut self.0 {
831 #[cfg(target_os = "linux")]
832 SessionBackend::Vulkan(session) => session.abort(),
833 #[cfg(target_os = "macos")]
834 SessionBackend::VideoToolbox(session) => session.abort(),
835 #[cfg(target_os = "windows")]
836 SessionBackend::D3D12(session) => session.abort(),
837 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
838 SessionBackend::Unsupported(never) => match *never {},
839 }
840 }
841}