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}