1 | use skia_bindings as sb; |
2 | |
3 | use crate::{ |
4 | gpu::{ |
5 | BackendTexture, Budgeted, DirectContext, Mipmapped, Protected, RecordingContext, |
6 | SurfaceOrigin, YUVABackendTextures, |
7 | }, |
8 | prelude::*, |
9 | AlphaType, ColorSpace, ColorType, Data, IRect, ISize, Image, Pixmap, TextureCompressionType, |
10 | }; |
11 | #[allow (unused)] // docs only |
12 | use crate::{ImageInfo, Surface, YUVAInfo, YUVAPixmaps}; |
13 | |
14 | /// Creates GPU-backed [`Image`] from `backend_texture` associated with context. |
15 | /// Skia will assume ownership of the resource and will release it when no longer needed. |
16 | /// A non-null [`Image`] is returned if format of `backend_texture` is recognized and supported. |
17 | /// Recognized formats vary by GPU backend. |
18 | /// * `context` - GPU context |
19 | /// * `backend_texture` - texture residing on GPU |
20 | /// * `texture_origin` - origin of `backend_texture` |
21 | /// * `color_type` - color type of the resulting image |
22 | /// * `alpha_type` - alpha type of the resulting image |
23 | /// * `color_space` - range of colors; may be `None` |
24 | /// |
25 | /// Returns: created [`Image`], or `None` |
26 | pub fn adopt_texture_from( |
27 | context: &mut RecordingContext, |
28 | backend_texture: &BackendTexture, |
29 | texture_origin: SurfaceOrigin, |
30 | color_type: ColorType, |
31 | alpha_type: impl Into<Option<AlphaType>>, |
32 | color_space: impl Into<Option<ColorSpace>>, |
33 | ) -> Option<Image> { |
34 | Image::from_ptr(unsafe { |
35 | sb::C_SkImages_AdoptTextureFrom( |
36 | context.native_mut(), |
37 | backendTexture:backend_texture.native(), |
38 | texture_origin, |
39 | colorType:color_type.into_native(), |
40 | alphaType:alpha_type.into().unwrap_or(AlphaType::Premul), |
41 | colorSpace:color_space.into().into_ptr_or_null(), |
42 | ) |
43 | }) |
44 | } |
45 | |
46 | /// Creates GPU-backed [`Image`] from the provided GPU texture associated with context. |
47 | /// GPU texture must stay valid and unchanged until `texture_release_proc` is called by Skia. |
48 | /// Skia will call `texture_release_proc` with the passed-in `release_context` when [`Image`] |
49 | /// is deleted or no longer refers to the texture. |
50 | /// A non-null [`Image`] is returned if format of `backend_texture` is recognized and supported. |
51 | /// Recognized formats vary by GPU backend. |
52 | /// Note: When using a DDL recording context, `texture_release_proc` will be called on the |
53 | /// GPU thread after the DDL is played back on the direct context. |
54 | /// * `context` - GPU context |
55 | /// * `backend_texture` - texture residing on GPU |
56 | /// * `color_space` - This describes the color space of this image's contents, as |
57 | /// seen after sampling. In general, if the format of the backend |
58 | /// texture is SRGB, some linear `color_space` should be supplied |
59 | /// (e.g., [`ColorSpace::new_srgb_linear()`]). If the format of the |
60 | /// backend texture is linear, then the `color_space` should include |
61 | /// a description of the transfer function as |
62 | /// well (e.g., [`ColorSpace::new_srgb()`]). |
63 | /// * `texture_release_proc` - function called when texture can be released |
64 | /// * `release_context` - state passed to `texture_release_proc` |
65 | /// |
66 | /// Returns: created [`Image`], or `None` |
67 | // TODO: add variant with TextureReleaseProc |
68 | pub fn borrow_texture_from( |
69 | context: &mut RecordingContext, |
70 | backend_texture: &BackendTexture, |
71 | origin: SurfaceOrigin, |
72 | color_type: ColorType, |
73 | alpha_type: AlphaType, |
74 | color_space: impl Into<Option<ColorSpace>>, |
75 | ) -> Option<Image> { |
76 | Image::from_ptr(unsafe { |
77 | sb::C_SkImages_BorrowTextureFrom( |
78 | context.native_mut(), |
79 | backendTexture:backend_texture.native(), |
80 | origin, |
81 | colorType:color_type.into_native(), |
82 | alphaType:alpha_type, |
83 | colorSpace:color_space.into().into_ptr_or_null(), |
84 | ) |
85 | }) |
86 | } |
87 | |
88 | /// Creates a GPU-backed [`Image`] from pixmap. It is uploaded to GPU backend using context. |
89 | /// Created [`Image`] is available to other GPU contexts, and is available across thread |
90 | /// boundaries. All contexts must be in the same GPU share group, or otherwise |
91 | /// share resources. |
92 | /// When [`Image`] is no longer referenced, context releases texture memory |
93 | /// asynchronously. |
94 | /// [`ColorSpace`] of [`Image`] is determined by `pixmap.color_space()`. |
95 | /// [`Image`] is returned referring to GPU backend if context is not `None`, |
96 | /// format of data is recognized and supported, and if context supports moving |
97 | /// resources between contexts. Otherwise, pixmap pixel data is copied and [`Image`] |
98 | /// as returned in raster format if possible; `None` may be returned. |
99 | /// Recognized GPU formats vary by platform and GPU backend. |
100 | /// * `context` - GPU context |
101 | /// * `pixmap` - [`ImageInfo`], pixel address, and row bytes |
102 | /// * `build_mips` - create [`Image`] as mip map if `true` |
103 | /// * `limit_to_max_texture_size` - downscale image to GPU maximum texture size, if necessary |
104 | /// |
105 | /// Returns: created [`Image`], or `None` |
106 | pub fn cross_context_texture_from_pixmap( |
107 | context: &mut DirectContext, |
108 | pixmap: &Pixmap, |
109 | build_mips: bool, |
110 | limit_to_max_texture_size: impl Into<Option<bool>>, |
111 | ) -> Option<Image> { |
112 | Image::from_ptr(unsafe { |
113 | sb::C_SkImages_CrossContextTextureFromPixmap( |
114 | context.native_mut(), |
115 | pixmap.native(), |
116 | buildMips:build_mips, |
117 | limitToMaxTextureSize:limit_to_max_texture_size.into().unwrap_or(false), |
118 | ) |
119 | }) |
120 | } |
121 | |
122 | // TODO: TextureFromCompressedTexture |
123 | |
124 | /// Creates a GPU-backed [`Image`] from compressed data. |
125 | /// This method will return an [`Image`] representing the compressed data. |
126 | /// If the GPU doesn't support the specified compression method, the data |
127 | /// will be decompressed and then wrapped in a GPU-backed image. |
128 | /// Note: one can query the supported compression formats via |
129 | /// [`RecordingContext::compressed_backend_format`]. |
130 | /// * `context` - GPU context |
131 | /// * `data` - compressed data to store in [`Image`] |
132 | /// * `width` - width of full [`Image`] |
133 | /// * `height` - height of full [`Image`] |
134 | /// * `ty` - type of compression used |
135 | /// * `mipmapped` - does 'data' contain data for all the mipmap levels? |
136 | /// * `is_protected` - do the contents of 'data' require DRM protection (on Vulkan)? |
137 | /// |
138 | /// Returns: created [`Image`], or `None` |
139 | pub fn texture_from_compressed_texture_data( |
140 | context: &mut DirectContext, |
141 | data: Data, |
142 | dimensions: impl Into<ISize>, |
143 | ty: TextureCompressionType, |
144 | mipmapped: impl Into<Option<Mipmapped>>, |
145 | is_protected: impl Into<Option<Protected>>, |
146 | ) -> Option<Image> { |
147 | let dimensions = dimensions.into(); |
148 | let mipmapped: skgpu_Mipmapped = mipmapped.into().unwrap_or(Mipmapped::No); |
149 | let is_protected: skgpu_Protected = is_protected.into().unwrap_or(Protected::No); |
150 | |
151 | Image::from_ptr(unsafe { |
152 | sb::C_SkImages_TextureFromCompressedTextureData( |
153 | context.native_mut(), |
154 | data.into_ptr(), |
155 | dimensions.width, |
156 | dimensions.height, |
157 | type_:ty, |
158 | mipmapped, |
159 | prot:is_protected, |
160 | ) |
161 | }) |
162 | } |
163 | |
164 | /// Returns [`Image`] backed by GPU texture associated with context. Returned [`Image`] is |
165 | /// compatible with [`Surface`] created with `dst_color_space`. The returned [`Image`] respects |
166 | /// mipmapped setting; if mipmapped equals [`Mipmapped::Yes`], the backing texture |
167 | /// allocates mip map levels. |
168 | /// The mipmapped parameter is effectively treated as `No` if MIP maps are not supported by the |
169 | /// GPU. |
170 | /// Returns original [`Image`] if the image is already texture-backed, the context matches, and |
171 | /// mipmapped is compatible with the backing GPU texture. skgpu::Budgeted is ignored in this |
172 | /// case. |
173 | /// Returns `None` if context is `None`, or if [`Image`] was created with another |
174 | /// [`DirectContext`]. |
175 | /// * `direct_context` - the [`DirectContext`] in play, if it exists |
176 | /// * `image` - a non-null pointer to an [`Image`]. |
177 | /// * `mipmapped` - Whether created [`Image`] texture must allocate mip map levels. |
178 | /// Defaults to `No`. |
179 | /// * `budgeted` - Whether to count a newly created texture for the returned image |
180 | /// counts against the context's budget. Defaults to `Yes`. |
181 | /// |
182 | /// Returns: created [`Image`], or `None` |
183 | pub fn texture_from_image( |
184 | direct_context: &mut DirectContext, |
185 | image: &Image, |
186 | mipmapped: Mipmapped, |
187 | budgeted: Budgeted, |
188 | ) -> Option<Image> { |
189 | Image::from_ptr(unsafe { |
190 | sb::C_SkImages_TextureFromImage( |
191 | context:direct_context.native_mut(), |
192 | self_:image.native(), |
193 | mipmapped, |
194 | budgeted.into_native(), |
195 | ) |
196 | }) |
197 | } |
198 | |
199 | /// Creates a GPU-backed [`Image`] from [`YUVAPixmaps`]. |
200 | /// The image will remain planar with each plane converted to a texture using the passed |
201 | /// [`RecordingContext`]. |
202 | /// [`YUVAPixmaps`] has a [`YUVAInfo`] which specifies the transformation from YUV to RGB. |
203 | /// The [`ColorSpace`] of the resulting RGB values is specified by `image_color_space`. This will |
204 | /// be the [`ColorSpace`] reported by the image and when drawn the RGB values will be converted |
205 | /// from this space into the destination space (if the destination is tagged). |
206 | /// Currently, this is only supported using the GPU backend and will fail if context is `None`. |
207 | /// [`YUVAPixmaps`] does not need to remain valid after this returns. |
208 | /// * `context` - GPU context |
209 | /// * `pixmaps` - The planes as pixmaps with supported [`YUVAInfo`] that |
210 | /// specifies conversion to RGB. |
211 | /// * `build_mips` - create internal YUVA textures as mip map if `k_yes`. This is |
212 | /// silently ignored if the context does not support mip maps. |
213 | /// * `limit_to_max_texture_size` - downscale image to GPU maximum texture size, if necessary |
214 | /// * `image_color_space` - range of colors of the resulting image; may be `None` |
215 | /// |
216 | /// Returns: created [`Image`], or `None` |
217 | pub fn texture_from_yuva_pixmaps( |
218 | context: &mut RecordingContext, |
219 | yuva_pixmaps: &crate::YUVAPixmaps, |
220 | build_mips: impl Into<Option<Mipmapped>>, |
221 | limit_to_max_texture_size: impl Into<Option<bool>>, |
222 | image_color_space: impl Into<Option<ColorSpace>>, |
223 | ) -> Option<Image> { |
224 | Image::from_ptr(unsafe { |
225 | sb::C_SkImages_TextureFromYUVAPixmaps( |
226 | context.native_mut(), |
227 | pixmaps:yuva_pixmaps.native(), |
228 | buildMips:build_mips.into().unwrap_or(Mipmapped::No), |
229 | limitToMaxTextureSize:limit_to_max_texture_size.into().unwrap_or(false), |
230 | imageColorSpace:image_color_space.into().into_ptr_or_null(), |
231 | ) |
232 | }) |
233 | } |
234 | |
235 | /// Creates a GPU-backed [`Image`] from `YUV[A]` planar textures. This requires that the textures |
236 | /// stay valid for the lifetime of the image. The ReleaseContext can be used to know when it is |
237 | /// safe to either delete or overwrite the textures. If ReleaseProc is provided it is also called |
238 | /// before return on failure. |
239 | /// * `context` - GPU context |
240 | /// * `yuva_textures` - A set of textures containing YUVA data and a description of the |
241 | /// data and transformation to RGBA. |
242 | /// * `image_color_space` - range of colors of the resulting image after conversion to RGB; |
243 | /// may be `None` |
244 | /// * `texture_release_proc` - called when the backend textures can be released |
245 | /// * `release_context` - state passed to `texture_release_proc` |
246 | /// |
247 | /// Returns: created [`Image`], or `None` |
248 | pub fn texture_from_yuva_textures( |
249 | context: &mut RecordingContext, |
250 | yuva_textures: &YUVABackendTextures, |
251 | image_color_space: impl Into<Option<ColorSpace>>, |
252 | ) -> Option<Image> { |
253 | Image::from_ptr(unsafe { |
254 | sb::C_SkImages_TextureFromYUVATextures( |
255 | context.native_mut(), |
256 | yuvaTextures:yuva_textures.native(), |
257 | imageColorSpace:image_color_space.into().into_ptr_or_null(), |
258 | ) |
259 | }) |
260 | } |
261 | |
262 | // TODO: PromiseTextureFrom |
263 | // TODO: PromiseTextureFromYUVA |
264 | |
265 | /// Retrieves the existing backend texture. If [`Image`] is not a Ganesh-backend texture image |
266 | /// or otherwise does not have such a texture, `false` is returned. Otherwise, returned will |
267 | /// be set to the image's texture. |
268 | /// |
269 | /// If `flush_pending_gr_context_io` is `true`, completes deferred I/O operations. |
270 | /// If origin in not `None`, copies location of content drawn into [`Image`]. |
271 | /// * `out_texture` - Will be set to the underlying texture of the image if non-null. |
272 | /// * `flush_pending_gr_context_io` - flag to flush outstanding requests |
273 | /// * `origin` - Will be set to the origin orientation of the image if non-null. |
274 | /// |
275 | /// Returns: `None` if a Ganesh backend texture cannot be retrieved. |
276 | pub fn get_backend_texture_from_image( |
277 | image: &Image, |
278 | flush_pending_gr_context_io: bool, |
279 | ) -> Option<(BackendTexture, SurfaceOrigin)> { |
280 | let mut origin: GrSurfaceOrigin = SurfaceOrigin::TopLeft; |
281 | unsafeOption> { |
282 | let backend_texture: *mut GrBackendTexture = sb::C_SkImages_GetBackendTextureFromImage( |
283 | self_:image.native(), |
284 | flushPendingGrContextIO:flush_pending_gr_context_io, |
285 | &mut origin, |
286 | ); |
287 | BackendTexture::from_native_if_valid(backend_texture) |
288 | } |
289 | .map(|texture: RefHandle| (texture, origin)) |
290 | } |
291 | |
292 | // TODO: MakeBackendTextureFromImage |
293 | // TODO: GetBackendTextureFromImage (legacy name) |
294 | |
295 | /// Returns subset of this image as a texture-backed image. |
296 | /// |
297 | /// Returns `None` if any of the following are true: |
298 | /// - Subset is empty |
299 | /// - Subset is not contained inside the image's bounds |
300 | /// - Pixels in the source image could not be read or copied |
301 | /// - The source image is texture-backed and context does not match the source image's context. |
302 | /// |
303 | /// * `context` - the [`DirectContext`] to which the subset should be uploaded. |
304 | /// * `subset` - bounds of returned [`Image`] |
305 | /// |
306 | /// Returns: the subsetted image, uploaded as a texture, or `None` |
307 | pub fn subset_texture_from( |
308 | context: &mut DirectContext, |
309 | image: &Image, |
310 | subset: impl AsRef<IRect>, |
311 | ) -> Option<Image> { |
312 | Image::from_ptr(unsafe { |
313 | sb::C_SkImages_SubsetTextureFrom( |
314 | context.native_mut(), |
315 | image.native(), |
316 | subset.as_ref().native(), |
317 | ) |
318 | }) |
319 | } |
320 | |