1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
use crate::{
    gpu, prelude::*, surface::BackendHandleAccess, ImageInfo, Surface, SurfaceCharacterization,
    SurfaceProps,
};

use skia_bindings as sb;

/// Returns [`Surface`] on GPU indicated by context. Allocates memory for pixels, based on the
/// width, height, and [`crate::ColorType`] in [`ImageInfo`].  budgeted selects whether allocation
/// for pixels is tracked by context. `image_info` describes the pixel format in
/// [`crate::ColorType`], and transparency in [`crate::AlphaType`], and color matching in
/// [`crate::ColorSpace`].
///
/// `sample_count` requests the number of samples per pixel. Pass zero to disable multi-sample
/// anti-aliasing.  The request is rounded up to the next supported count, or rounded down if it is
/// larger than the maximum supported count.
///
/// `surface_origin` pins either the top-left or the bottom-left corner to the origin.
///
/// `should_create_with_mips` hints that [`crate::Image`] returned by [`Surface::image_snapshot`] is
/// mip map.
///
/// * `context` - GPU context
/// * `image_info` - width, height, [`crate::ColorType`], [`crate::AlphaType`],
///                              [`crate::ColorSpace`]; width, or height, or both, may be zero
/// * `sample_count` - samples per pixel, or 0 to disable full scene anti-aliasing
/// * `surface_props` - LCD striping orientation and setting for device independent fonts; may be
///                              `None`
/// * `should_create_with_mips` - hint that [`Surface`] will host mip map images Returns:
/// [`Surface`] if all parameters are valid; otherwise, `None`
pub fn render_target(
    context: &mut gpu::RecordingContext,
    budgeted: gpu::Budgeted,
    image_info: &ImageInfo,
    sample_count: impl Into<Option<usize>>,
    surface_origin: impl Into<Option<gpu::SurfaceOrigin>>,
    surface_props: Option<&SurfaceProps>,
    should_create_with_mips: impl Into<Option<bool>>,
) -> Option<Surface> {
    Surface::from_ptr(unsafe {
        sb::C_SkSurfaces_RenderTarget(
            context.native_mut(),
            budgeted.into_native(),
            image_info.native(),
            sample_count.into().unwrap_or(0).try_into().unwrap(),
            surface_origin
                .into()
                .unwrap_or(gpu::SurfaceOrigin::BottomLeft),
            surface_props.native_ptr_or_null(),
            should_create_with_mips.into().unwrap_or_default(),
        )
    })
}

/// Returns [`Surface`] on GPU indicated by context that is compatible with the provided
/// characterization. budgeted selects whether allocation for pixels is tracked by context.
///
/// * `context` - GPU context
/// * `characterization` - description of the desired [`Surface`]
/// Returns: [`Surface`] if all parameters are valid; otherwise, `None`
pub fn render_target_with_characterization(
    context: &mut gpu::RecordingContext,
    characterization: &SurfaceCharacterization,
    budgeted: gpu::Budgeted,
) -> Option<Surface> {
    Surface::from_ptr(unsafe {
        sb::C_SkSurfaces_RenderTarget2(
            context.native_mut(),
            characterization.native(),
            budgeted.into_native(),
        )
    })
}

/// Wraps a GPU-backed texture into [`Surface`]. Caller must ensure the texture is
/// valid for the lifetime of returned [`Surface`]. If `sample_cnt` greater than zero,
/// creates an intermediate MSAA [`Surface`] which is used for drawing `backend_texture`.
///
/// [`Surface`] is returned if all parameters are valid. `backend_texture` is valid if
/// its pixel configuration agrees with `color_space` and context; for instance, if
/// `backend_texture` has an sRGB configuration, then context must support sRGB,
/// and `color_space` must be present. Further, `backend_texture` width and height must
/// not exceed context capabilities, and the context must be able to support
/// back-end textures.
///
/// * `context` - GPU context
/// * `backend_texture` - texture residing on GPU
/// * `sample_cnt` - samples per pixel, or 0 to disable full scene anti-aliasing
/// * `color_space` - range of colors; may be `None`
/// * `surface_props` - LCD striping orientation and setting for device independent
///                            fonts; may be `None`
/// Returns: [`Surface`] if all parameters are valid; otherwise, `None`
pub fn wrap_backend_texture(
    context: &mut gpu::RecordingContext,
    backend_texture: &gpu::BackendTexture,
    origin: gpu::SurfaceOrigin,
    sample_cnt: impl Into<Option<usize>>,
    color_type: crate::ColorType,
    color_space: impl Into<Option<crate::ColorSpace>>,
    surface_props: Option<&SurfaceProps>,
) -> Option<Surface> {
    Surface::from_ptr(unsafe {
        sb::C_SkSurfaces_WrapBackendTexture(
            context.native_mut(),
            backend_texture.native(),
            origin,
            sample_cnt.into().unwrap_or(0).try_into().unwrap(),
            color_type.into_native(),
            color_space.into().into_ptr_or_null(),
            surface_props.native_ptr_or_null(),
        )
    })
}

/// Wraps a GPU-backed buffer into [`Surface`]. Caller must ensure `backend_render_target`
/// is valid for the lifetime of returned [`Surface`].
///
/// [`Surface`] is returned if all parameters are valid. `backend_render_target` is valid if
/// its pixel configuration agrees with `color_space` and context; for instance, if
/// `backend_render_target` has an sRGB configuration, then context must support sRGB,
/// and `color_space` must be present. Further, `backend_render_target` width and height must
/// not exceed context capabilities, and the context must be able to support
/// back-end render targets.
///
/// * `context` - GPU context
/// * `backend_render_target` - GPU intermediate memory buffer
/// * `color_space` - range of colors
/// * `surface_props` - LCD striping orientation and setting for device independent
///                                 fonts; may be `None`
/// Returns: [`Surface`] if all parameters are valid; otherwise, `None`
pub fn wrap_backend_render_target(
    context: &mut gpu::RecordingContext,
    backend_render_target: &gpu::BackendRenderTarget,
    origin: gpu::SurfaceOrigin,
    color_type: crate::ColorType,
    color_space: impl Into<Option<crate::ColorSpace>>,
    surface_props: Option<&SurfaceProps>,
) -> Option<Surface> {
    Surface::from_ptr(unsafe {
        sb::C_SkSurfaces_WrapBackendRenderTarget(
            context.native_mut(),
            backend_render_target.native(),
            origin,
            color_type.into_native(),
            color_space.into().into_ptr_or_null(),
            surface_props.native_ptr_or_null(),
        )
    })
}

/// Retrieves the back-end texture. If [`Surface`] has no back-end texture, `None`
/// is returned.
///
/// The returned [`gpu::BackendTexture`] should be discarded if the [`Surface`] is drawn to or deleted.
///
/// Returns: GPU texture reference; `None` on failure
pub fn get_backend_texture(
    surface: &mut Surface,
    handle_access: BackendHandleAccess,
) -> Option<gpu::BackendTexture> {
    unsafe {
        let ptr = sb::C_SkSurfaces_GetBackendTexture(surface.native_mut(), handle_access);
        gpu::BackendTexture::from_native_if_valid(ptr)
    }
}

/// Retrieves the back-end render target. If [`Surface`] has no back-end render target, `None`
/// is returned.
///
/// The returned [`gpu::BackendRenderTarget`] should be discarded if the [`Surface`] is drawn to
/// or deleted.
///
/// Returns: GPU render target reference; `None` on failure
pub fn get_backend_render_target(
    surface: &mut Surface,
    handle_access: BackendHandleAccess,
) -> Option<gpu::BackendRenderTarget> {
    unsafe {
        let mut backend_render_target = construct(|rt| sb::C_GrBackendRenderTarget_Construct(rt));
        sb::C_SkSurfaces_GetBackendRenderTarget(
            surface.native_mut(),
            handle_access,
            &mut backend_render_target,
        );

        gpu::BackendRenderTarget::from_native_c_if_valid(backend_render_target)
    }
}