1use super::{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: *mut GrYUVABackendTextureInfo| unsafe { sb::C_GrYUVABackendTextureInfo_CopyConstruct(uninitialized:cloned, self) })
19 }
20}
21
22impl NativePartialEq for GrYUVABackendTextureInfo {
23 fn eq(&self, rhs: &Self) -> bool {
24 unsafe { sb::C_GrYUVABackendTextureInfo_equals(self, b:rhs) }
25 }
26}
27
28impl fmt::Debug for YUVABackendTextureInfo {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f&mut DebugStruct<'_, '_>.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(name:"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&mut DebugStruct<'_, '_>.debug_struct("YUVABackendTextures")
125 .field("yuva_info", &self.yuva_info())
126 .field("texture_origin", &self.texture_origin())
127 .field(name:"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
149 .extend(iter::repeat(new_invalid_ptr).take(YUVAInfo::MAX_PLANES - textures.len()));
150 assert_eq!(texture_handles.len(), YUVAInfo::MAX_PLANES);
151
152 let n = construct(|cloned| unsafe {
153 sb::C_GrYUVABackendTextures_construct(
154 cloned,
155 info.native(),
156 texture_handles.as_ptr(),
157 texture_origin,
158 )
159 });
160 Self::native_is_valid(&n).if_true_then_some(|| Self::from_native_c(n))
161 }
162
163 pub fn textures(&self) -> Vec<BackendTexture> {
164 unsafe {
165 let textures_ptr = sb::C_GrYUVABackendTextures_textures(self.native());
166 let textures = safer::from_raw_parts(textures_ptr, self.num_planes());
167 textures
168 .iter()
169 .map(|native_texture_ref| {
170 BackendTexture::from_ptr(sb::C_GrBackendTexture_Clone(native_texture_ref))
171 .unwrap()
172 })
173 .collect()
174 }
175 }
176
177 pub fn texture(&self, i: usize) -> Option<BackendTexture> {
178 self.textures().get(i).cloned()
179 }
180
181 pub fn yuva_info(&self) -> &YUVAInfo {
182 YUVAInfo::from_native_ref(&self.native().fYUVAInfo)
183 }
184
185 pub fn num_planes(&self) -> usize {
186 self.yuva_info().num_planes()
187 }
188
189 pub fn texture_origin(&self) -> SurfaceOrigin {
190 self.native().fTextureOrigin
191 }
192
193 pub(crate) fn native_is_valid(n: &GrYUVABackendTextures) -> bool {
194 YUVAInfo::native_is_valid(&n.fYUVAInfo)
195 }
196}
197