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].
112///
113// Because BackendTexture itself is a RefHandle, we need to put GrYUVABackendTextures on the heap, too.
114// See <https://github.com/rust-skia/rust-skia/issues/1246>
115pub type YUVABackendTextures = RefHandle<GrYUVABackendTextures>;
116unsafe_send_sync!(YUVABackendTextures);
117
118impl NativeDrop for GrYUVABackendTextures {
119    fn drop(&mut self) {
120        unsafe { sb::C_GrYUVABackendTextures_delete(self) }
121    }
122}
123
124impl fmt::Debug for YUVABackendTextures {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        f.debug_struct("YUVABackendTextures")
127            .field("yuva_info", &self.yuva_info())
128            .field("texture_origin", &self.texture_origin())
129            .field("textures", &self.textures())
130            .finish()
131    }
132}
133
134impl YUVABackendTextures {
135    pub fn new(
136        info: &YUVAInfo,
137        textures: &[BackendTexture],
138        texture_origin: SurfaceOrigin,
139    ) -> Option<Self> {
140        if textures.len() != info.num_planes() {
141            return None;
142        }
143        let new_invalid = BackendTexture::new_invalid();
144        let new_invalid_ptr = new_invalid.native() as *const _;
145
146        let mut texture_handles = textures
147            .iter()
148            .map(|tex| tex.native() as *const _)
149            .collect::<Vec<_>>();
150        texture_handles.extend(iter::repeat_n(
151            new_invalid_ptr,
152            YUVAInfo::MAX_PLANES - textures.len(),
153        ));
154        assert_eq!(texture_handles.len(), YUVAInfo::MAX_PLANES);
155
156        let textures = Self::from_ptr(unsafe {
157            sb::C_GrYUVABackendTextures_new(info.native(), texture_handles.as_ptr(), texture_origin)
158        })?;
159        Self::native_is_valid(textures.native()).then_some(textures)
160    }
161
162    pub fn textures(&self) -> Vec<BackendTexture> {
163        unsafe {
164            let textures_ptr = sb::C_GrYUVABackendTextures_textures(self.native());
165            let textures = safer::from_raw_parts(textures_ptr, self.num_planes());
166            textures
167                .iter()
168                .map(|native_texture_ref| {
169                    BackendTexture::from_ptr(sb::C_GrBackendTexture_Clone(native_texture_ref))
170                        .unwrap()
171                })
172                .collect()
173        }
174    }
175
176    pub fn texture(&self, i: usize) -> Option<BackendTexture> {
177        self.textures().get(i).cloned()
178    }
179
180    pub fn yuva_info(&self) -> &YUVAInfo {
181        YUVAInfo::from_native_ref(unsafe { &*sb::C_GrYUVABackendTextures_yuvaInfo(self.native()) })
182    }
183
184    pub fn num_planes(&self) -> usize {
185        self.yuva_info().num_planes()
186    }
187
188    pub fn texture_origin(&self) -> SurfaceOrigin {
189        unsafe { sb::C_GrYUVABackendTextures_textureOrigin(self.native()) }
190    }
191
192    pub(crate) fn native_is_valid(n: &GrYUVABackendTextures) -> bool {
193        YUVAInfo::native_is_valid(unsafe { &*sb::C_GrYUVABackendTextures_yuvaInfo(n) })
194    }
195}