skia_safe/gpu/ganesh/image_ganesh.rs
1use skia_bindings as sb;
2
3use 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
12use 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`
26pub 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 backend_texture.native(),
38 texture_origin,
39 color_type.into_native(),
40 alpha_type.into().unwrap_or(AlphaType::Premul),
41 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
68pub 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 backend_texture.native(),
80 origin,
81 color_type.into_native(),
82 alpha_type,
83 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`
106pub 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 build_mips,
117 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`
139pub 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 = mipmapped.into().unwrap_or(Mipmapped::No);
149 let is_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 ty,
158 mipmapped,
159 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`
183pub 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 direct_context.native_mut(),
192 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`
217pub 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 yuva_pixmaps.native(),
228 build_mips.into().unwrap_or(Mipmapped::No),
229 limit_to_max_texture_size.into().unwrap_or(false),
230 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`
248pub 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 yuva_textures.native(),
257 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.
276pub fn get_backend_texture_from_image(
277 image: &Image,
278 flush_pending_gr_context_io: bool,
279) -> Option<(BackendTexture, SurfaceOrigin)> {
280 let mut origin = SurfaceOrigin::TopLeft;
281 unsafe {
282 let backend_texture = sb::C_SkImages_GetBackendTextureFromImage(
283 image.native(),
284 flush_pending_gr_context_io,
285 &mut origin,
286 );
287 BackendTexture::from_native_if_valid(backend_texture)
288 }
289 .map(|texture| (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`
307pub 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}