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).then(|| 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())
94            .then(|| BackendFormat::from_native_ref(&self.native().fPlaneFormats[i]))
95    }
96
97    /// All plane formats.
98    pub fn plane_formats(&self) -> &[BackendFormat] {
99        unsafe {
100            let formats = BackendFormat::from_native_ref(&self.native().fPlaneFormats[0]);
101            safer::from_raw_parts(formats, self.num_planes())
102        }
103    }
104
105    /// Returns `true` if this has been configured with a valid [YUVAInfo] with compatible texture.
106    pub(crate) fn native_is_valid(info: &GrYUVABackendTextureInfo) -> bool {
107        YUVAInfo::native_is_valid(&info.fYUVAInfo)
108    }
109}
110
111/// A set of [BackendTexture]s that hold the planar data for an image described a [YUVAInfo].
112pub type YUVABackendTextures = Handle<GrYUVABackendTextures>;
113unsafe_send_sync!(YUVABackendTextures);
114
115impl NativeDrop for GrYUVABackendTextures {
116    fn drop(&mut self) {
117        unsafe { sb::C_GrYUVABackendTextures_destruct(self) }
118    }
119}
120
121impl fmt::Debug for YUVABackendTextures {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        f.debug_struct("YUVABackendTextures")
124            .field("yuva_info", &self.yuva_info())
125            .field("texture_origin", &self.texture_origin())
126            .field("textures", &self.textures())
127            .finish()
128    }
129}
130
131impl YUVABackendTextures {
132    pub fn new(
133        info: &YUVAInfo,
134        textures: &[BackendTexture],
135        texture_origin: SurfaceOrigin,
136    ) -> Option<Self> {
137        if textures.len() != info.num_planes() {
138            return None;
139        }
140        let new_invalid = BackendTexture::new_invalid();
141        let new_invalid_ptr = new_invalid.native() as *const _;
142
143        let mut texture_handles = textures
144            .iter()
145            .map(|tex| tex.native() as *const _)
146            .collect::<Vec<_>>();
147        texture_handles.extend(iter::repeat_n(
148            new_invalid_ptr,
149            YUVAInfo::MAX_PLANES - textures.len(),
150        ));
151        assert_eq!(texture_handles.len(), YUVAInfo::MAX_PLANES);
152
153        let n = construct(|cloned| unsafe {
154            sb::C_GrYUVABackendTextures_construct(
155                cloned,
156                info.native(),
157                texture_handles.as_ptr(),
158                texture_origin,
159            )
160        });
161        Self::native_is_valid(&n).then(|| Self::from_native_c(n))
162    }
163
164    pub fn textures(&self) -> Vec<BackendTexture> {
165        unsafe {
166            let textures_ptr = sb::C_GrYUVABackendTextures_textures(self.native());
167            let textures = safer::from_raw_parts(textures_ptr, self.num_planes());
168            textures
169                .iter()
170                .map(|native_texture_ref| {
171                    BackendTexture::from_ptr(sb::C_GrBackendTexture_Clone(native_texture_ref))
172                        .unwrap()
173                })
174                .collect()
175        }
176    }
177
178    pub fn texture(&self, i: usize) -> Option<BackendTexture> {
179        self.textures().get(i).cloned()
180    }
181
182    pub fn yuva_info(&self) -> &YUVAInfo {
183        YUVAInfo::from_native_ref(unsafe { &*sb::C_GrYUVABackendTextures_yuvaInfo(self.native()) })
184    }
185
186    pub fn num_planes(&self) -> usize {
187        self.yuva_info().num_planes()
188    }
189
190    pub fn texture_origin(&self) -> SurfaceOrigin {
191        unsafe { sb::C_GrYUVABackendTextures_textureOrigin(self.native()) }
192    }
193
194    pub(crate) fn native_is_valid(n: &GrYUVABackendTextures) -> bool {
195        YUVAInfo::native_is_valid(unsafe { &*sb::C_GrYUVABackendTextures_yuvaInfo(n) })
196    }
197}