skia_safe/gpu/ganesh/
yuva_backend_textures.rs

1use crate::gpu::{BackendFormat, BackendTexture, Mipmapped, SurfaceOrigin};
2use crate::{prelude::*, YUVAInfo, YUVColorSpace};
3use skia_bindings::{self as sb, GrYUVABackendTextureInfo, GrYUVABackendTextures};
4use std::{fmt, iter};
5
6/// A description of a set [BackendTexture]s that hold the planar data described by a [YUVAInfo].
7pub type YUVABackendTextureInfo = Handle<GrYUVABackendTextureInfo>;
8unsafe_send_sync!(YUVABackendTextureInfo);
9
10impl NativeDrop for GrYUVABackendTextureInfo {
11    fn drop(&mut self) {
12        unsafe { sb::C_GrYUVABackendTextureInfo_destruct(self) }
13    }
14}
15
16impl NativeClone for GrYUVABackendTextureInfo {
17    fn clone(&self) -> Self {
18        construct(|cloned| unsafe { sb::C_GrYUVABackendTextureInfo_CopyConstruct(cloned, self) })
19    }
20}
21
22impl NativePartialEq for GrYUVABackendTextureInfo {
23    fn eq(&self, rhs: &Self) -> bool {
24        unsafe { sb::C_GrYUVABackendTextureInfo_equals(self, rhs) }
25    }
26}
27
28impl fmt::Debug for YUVABackendTextureInfo {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.debug_struct("YUVABackendTextureInfo")
31            .field("yuva_info", &self.yuva_info())
32            .field("yuv_color_space", &self.yuv_color_space())
33            .field("mipmapped", &self.mipmapped())
34            .field("texture_origin", &self.texture_origin())
35            .field("plane_formats", &self.plane_formats())
36            .finish()
37    }
38}
39
40impl YUVABackendTextureInfo {
41    pub const MAX_PLANES: usize = YUVAInfo::MAX_PLANES;
42
43    /// Initializes a [YUVABackendTextureInfo] to describe a set of textures that can store the
44    /// planes indicated by the [YUVAInfo]. The texture dimensions are taken from the [YUVAInfo]'s
45    /// plane dimensions. All the described textures share a common origin. The planar image this
46    /// describes will be mip mapped if all the textures are individually mip mapped as indicated
47    /// by [Mipmapped]. This will return [None] if the passed formats' channels don't agree with [YUVAInfo].
48    pub fn new(
49        info: &YUVAInfo,
50        formats: &[BackendFormat],
51        mip_mapped: Mipmapped,
52        origin: SurfaceOrigin,
53    ) -> Option<Self> {
54        if formats.len() != info.num_planes() {
55            return None;
56        }
57
58        let mut formats = formats.to_vec();
59        formats.extend(
60            iter::repeat_with(BackendFormat::new_invalid).take(Self::MAX_PLANES - formats.len()),
61        );
62        assert_eq!(formats.len(), Self::MAX_PLANES);
63
64        let n = unsafe {
65            GrYUVABackendTextureInfo::new(info.native(), formats[0].native(), mip_mapped, origin)
66        };
67        Self::native_is_valid(&n).if_true_then_some(|| Self::from_native_c(n))
68    }
69
70    pub fn yuva_info(&self) -> &YUVAInfo {
71        YUVAInfo::from_native_ref(&self.native().fYUVAInfo)
72    }
73
74    pub fn yuv_color_space(&self) -> YUVColorSpace {
75        self.yuva_info().yuv_color_space()
76    }
77
78    pub fn mipmapped(&self) -> Mipmapped {
79        self.native().fMipmapped
80    }
81
82    pub fn texture_origin(&self) -> SurfaceOrigin {
83        self.native().fTextureOrigin
84    }
85
86    /// The number of [crate::Pixmap] planes.
87    pub fn num_planes(&self) -> usize {
88        self.yuva_info().num_planes()
89    }
90
91    /// Format of the ith plane, or `None` if `i >= Self::num_planes()`
92    pub fn plane_format(&self, i: usize) -> Option<&BackendFormat> {
93        (i < self.num_planes()).if_true_some(BackendFormat::from_native_ref(
94            &self.native().fPlaneFormats[i],
95        ))
96    }
97
98    /// All plane formats.
99    pub fn plane_formats(&self) -> &[BackendFormat] {
100        unsafe {
101            let formats = BackendFormat::from_native_ref(&self.native().fPlaneFormats[0]);
102            safer::from_raw_parts(formats, self.num_planes())
103        }
104    }
105
106    /// Returns `true` if this has been configured with a valid [YUVAInfo] with compatible texture.
107    pub(crate) fn native_is_valid(info: &GrYUVABackendTextureInfo) -> bool {
108        YUVAInfo::native_is_valid(&info.fYUVAInfo)
109    }
110}
111
112/// A set of [BackendTexture]s that hold the planar data for an image described a [YUVAInfo].
113pub type YUVABackendTextures = Handle<GrYUVABackendTextures>;
114unsafe_send_sync!(YUVABackendTextures);
115
116impl NativeDrop for GrYUVABackendTextures {
117    fn drop(&mut self) {
118        unsafe { sb::C_GrYUVABackendTextures_destruct(self) }
119    }
120}
121
122impl fmt::Debug for YUVABackendTextures {
123    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        f.debug_struct("YUVABackendTextures")
125            .field("yuva_info", &self.yuva_info())
126            .field("texture_origin", &self.texture_origin())
127            .field("textures", &self.textures())
128            .finish()
129    }
130}
131
132impl YUVABackendTextures {
133    pub fn new(
134        info: &YUVAInfo,
135        textures: &[BackendTexture],
136        texture_origin: SurfaceOrigin,
137    ) -> Option<Self> {
138        if textures.len() != info.num_planes() {
139            return None;
140        }
141        let new_invalid = BackendTexture::new_invalid();
142        let new_invalid_ptr = new_invalid.native() as *const _;
143
144        let mut texture_handles = textures
145            .iter()
146            .map(|tex| tex.native() as *const _)
147            .collect::<Vec<_>>();
148        texture_handles.extend(iter::repeat_n(
149            new_invalid_ptr,
150            YUVAInfo::MAX_PLANES - textures.len(),
151        ));
152        assert_eq!(texture_handles.len(), YUVAInfo::MAX_PLANES);
153
154        let n = construct(|cloned| unsafe {
155            sb::C_GrYUVABackendTextures_construct(
156                cloned,
157                info.native(),
158                texture_handles.as_ptr(),
159                texture_origin,
160            )
161        });
162        Self::native_is_valid(&n).if_true_then_some(|| Self::from_native_c(n))
163    }
164
165    pub fn textures(&self) -> Vec<BackendTexture> {
166        unsafe {
167            let textures_ptr = sb::C_GrYUVABackendTextures_textures(self.native());
168            let textures = safer::from_raw_parts(textures_ptr, self.num_planes());
169            textures
170                .iter()
171                .map(|native_texture_ref| {
172                    BackendTexture::from_ptr(sb::C_GrBackendTexture_Clone(native_texture_ref))
173                        .unwrap()
174                })
175                .collect()
176        }
177    }
178
179    pub fn texture(&self, i: usize) -> Option<BackendTexture> {
180        self.textures().get(i).cloned()
181    }
182
183    pub fn yuva_info(&self) -> &YUVAInfo {
184        YUVAInfo::from_native_ref(unsafe { &*sb::C_GrYUVABackendTextures_yuvaInfo(self.native()) })
185    }
186
187    pub fn num_planes(&self) -> usize {
188        self.yuva_info().num_planes()
189    }
190
191    pub fn texture_origin(&self) -> SurfaceOrigin {
192        unsafe { sb::C_GrYUVABackendTextures_textureOrigin(self.native()) }
193    }
194
195    pub(crate) fn native_is_valid(n: &GrYUVABackendTextures) -> bool {
196        YUVAInfo::native_is_valid(unsafe { &*sb::C_GrYUVABackendTextures_yuvaInfo(n) })
197    }
198}