Skip to main content

skia_safe/gpu/ganesh/
backend_surface.rs

1use std::fmt;
2
3use skia_bindings::{self as sb, GrBackendFormat, GrBackendRenderTarget, GrBackendTexture};
4
5use crate::gpu;
6use crate::{interop::AsStr, prelude::*, ISize};
7#[cfg(feature = "d3d")]
8use gpu::d3d;
9#[cfg(feature = "gl")]
10use gpu::gl;
11#[cfg(feature = "metal")]
12use gpu::mtl;
13#[cfg(feature = "vulkan")]
14use gpu::vk;
15use gpu::{BackendAPI, Mipmapped, MutableTextureState};
16
17pub type BackendFormat = Handle<GrBackendFormat>;
18unsafe_send_sync!(BackendFormat);
19
20impl NativeDrop for GrBackendFormat {
21    fn drop(&mut self) {
22        unsafe { sb::C_GrBackendFormat_destruct(self) }
23    }
24}
25
26impl NativeClone for GrBackendFormat {
27    fn clone(&self) -> Self {
28        unsafe { GrBackendFormat::new1(self) }
29    }
30}
31
32impl fmt::Debug for BackendFormat {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        let mut d = f.debug_struct("BackendFormat");
35        d.field("backend", &self.backend());
36        d.field("channel_mask", &self.channel_mask());
37        #[cfg(feature = "gl")]
38        d.field("gl_format", &self.as_gl_format());
39        #[cfg(feature = "vulkan")]
40        d.field("vk_format", &self.as_vk_format());
41        #[cfg(feature = "metal")]
42        d.field("mtl_format", &self.as_mtl_format());
43        #[cfg(feature = "d3d")]
44        d.field("dxgi_format", &self.as_dxgi_format());
45        d.finish()
46    }
47}
48
49impl BackendFormat {
50    #[deprecated(
51        note = "The creation of invalid BackendFormats isn't supported anymore",
52        since = "0.37.0"
53    )]
54    pub fn new() -> Self {
55        Self::new_invalid()
56    }
57
58    pub(crate) fn new_invalid() -> Self {
59        Self::construct(|bf| unsafe { sb::C_GrBackendFormat_Construct(bf) })
60    }
61
62    #[cfg(feature = "gl")]
63    pub fn new_gl(format: gl::Enum, target: gl::Enum) -> Self {
64        Self::construct(|bf| unsafe { sb::C_GrBackendFormats_ConstructGL(bf, format, target) })
65            .assert_valid()
66    }
67
68    #[cfg(feature = "vulkan")]
69    #[deprecated(since = "0.67.0", note = "use gpu::backend_formats::make_vk()")]
70    pub fn new_vulkan(
71        format: vk::Format,
72        will_use_drm_format_modifiers: impl Into<Option<bool>>,
73    ) -> Self {
74        gpu::backend_formats::make_vk(format, will_use_drm_format_modifiers)
75    }
76
77    #[cfg(feature = "vulkan")]
78    #[deprecated(since = "0.67.0", note = "use gpu::backend_formats::make_vk_ycbcr()")]
79    pub fn new_vulkan_ycbcr(
80        conversion_info: &vk::YcbcrConversionInfo,
81        will_use_drm_format_modifiers: impl Into<Option<bool>>,
82    ) -> Self {
83        gpu::backend_formats::make_vk_ycbcr(conversion_info, will_use_drm_format_modifiers)
84    }
85
86    #[cfg(feature = "metal")]
87    #[deprecated(since = "0.74.0", note = "use gpu::backend_formats::make_mtl()")]
88    pub fn new_metal(format: mtl::PixelFormat) -> Self {
89        gpu::backend_formats::make_mtl(format)
90    }
91
92    #[cfg(feature = "d3d")]
93    #[deprecated(since = "0.95.0", note = "use gpu::backend_formats::make_d3d()")]
94    pub fn new_dxgi(format: d3d::DXGI_FORMAT) -> Self {
95        gpu::backend_formats::make_d3d(format)
96    }
97
98    #[cfg(feature = "d3d")]
99    #[deprecated(since = "0.95.0", note = "use gpu::backend_formats::make_d3d()")]
100    pub fn new_d3d(format: d3d::DXGI_FORMAT) -> Self {
101        gpu::backend_formats::make_d3d(format)
102    }
103
104    pub fn backend(&self) -> BackendAPI {
105        self.native().fBackend
106    }
107
108    pub fn channel_mask(&self) -> u32 {
109        unsafe { self.native().channelMask() }
110    }
111
112    // m117: Even though Skia did, we won't deprecate these functions here for convenience.
113
114    #[cfg(feature = "gl")]
115    pub fn as_gl_format(&self) -> gl::Format {
116        gpu::backend_formats::as_gl_format(self)
117    }
118
119    #[cfg(feature = "gl")]
120    pub fn as_gl_format_enum(&self) -> gl::Enum {
121        gpu::backend_formats::as_gl_format_enum(self)
122    }
123
124    // Deprecated in Skia
125    #[cfg(feature = "vulkan")]
126    pub fn as_vk_format(&self) -> Option<vk::Format> {
127        gpu::backend_formats::as_vk_format(self)
128    }
129
130    #[cfg(feature = "metal")]
131    pub fn as_mtl_format(&self) -> Option<mtl::PixelFormat> {
132        gpu::backend_formats::as_mtl_format(self)
133    }
134
135    #[cfg(feature = "d3d")]
136    pub fn as_dxgi_format(&self) -> Option<d3d::DXGI_FORMAT> {
137        gpu::backend_formats::as_dxgi_format(self)
138    }
139
140    #[must_use]
141    pub fn to_texture_2d(&self) -> Self {
142        let mut new = Self::new_invalid();
143        unsafe { sb::C_GrBackendFormat_makeTexture2D(self.native(), new.native_mut()) };
144        assert!(Self::native_is_valid(new.native()));
145        new
146    }
147
148    #[deprecated(
149        note = "Invalid BackendFormats are not supported anymore",
150        since = "0.37.0"
151    )]
152    pub fn is_valid(&self) -> bool {
153        self.native().fValid
154    }
155
156    pub(crate) fn native_is_valid(format: &GrBackendFormat) -> bool {
157        format.fValid
158    }
159
160    pub(crate) fn assert_valid(self) -> Self {
161        assert!(Self::native_is_valid(self.native()));
162        self
163    }
164}
165
166// GrBackendTexture contains a string `fLabel`, and with SSO on some platforms, it can't be moved.
167// See <https://github.com/rust-skia/rust-skia/issues/750>.
168pub type BackendTexture = RefHandle<GrBackendTexture>;
169unsafe_send_sync!(BackendTexture);
170
171impl NativeDrop for GrBackendTexture {
172    fn drop(&mut self) {
173        unsafe { sb::C_GrBackendTexture_delete(self) }
174    }
175}
176
177impl Clone for BackendTexture {
178    fn clone(&self) -> Self {
179        unsafe { Self::from_ptr(sb::C_GrBackendTexture_Clone(self.native())) }.unwrap()
180    }
181}
182
183impl fmt::Debug for BackendTexture {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        let mut d = f.debug_struct("BackendTexture");
186        d.field("dimensions", &self.dimensions());
187        d.field("label", &self.label());
188        d.field("mipmapped", &self.mipmapped());
189        d.field("backend", &self.backend());
190        #[cfg(feature = "gl")]
191        d.field("gl_texture_info", &self.gl_texture_info());
192        #[cfg(feature = "vulkan")]
193        d.field("vulkan_image_info", &self.vulkan_image_info());
194        #[cfg(feature = "metal")]
195        d.field("metal_texture_info", &self.metal_texture_info());
196        #[cfg(feature = "d3d")]
197        d.field(
198            "d3d_texture_resource_info",
199            &self.d3d_texture_resource_info(),
200        );
201        d.field("backend_format", &self.backend_format());
202        d.field("is_protected", &self.is_protected());
203        d.finish()
204    }
205}
206
207impl BackendTexture {
208    pub(crate) fn new_invalid() -> Self {
209        Self::from_ptr(unsafe { sb::C_GrBackendTexture_new() }).unwrap()
210    }
211
212    #[cfg(feature = "gl")]
213    #[allow(clippy::missing_safety_doc)]
214    #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_gl()")]
215    pub unsafe fn new_gl(
216        (width, height): (i32, i32),
217        mipmapped: gpu::Mipmapped,
218        gl_info: gl::TextureInfo,
219    ) -> Self {
220        gpu::backend_textures::make_gl((width, height), mipmapped, gl_info, "")
221    }
222
223    #[cfg(feature = "gl")]
224    #[allow(clippy::missing_safety_doc)]
225    #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_gl()")]
226    pub unsafe fn new_gl_with_label(
227        (width, height): (i32, i32),
228        mipmapped: gpu::Mipmapped,
229        gl_info: gl::TextureInfo,
230        label: impl AsRef<str>,
231    ) -> Self {
232        gpu::backend_textures::make_gl((width, height), mipmapped, gl_info, label)
233    }
234
235    #[cfg(feature = "vulkan")]
236    #[allow(clippy::missing_safety_doc)]
237    #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_vk()")]
238    pub unsafe fn new_vulkan((width, height): (i32, i32), vk_info: &vk::ImageInfo) -> Self {
239        gpu::backend_textures::make_vk((width, height), vk_info, "")
240    }
241
242    #[cfg(feature = "vulkan")]
243    #[allow(clippy::missing_safety_doc)]
244    #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_vk()")]
245    pub unsafe fn new_vulkan_with_label(
246        (width, height): (i32, i32),
247        vk_info: &vk::ImageInfo,
248        label: impl AsRef<str>,
249    ) -> Self {
250        gpu::backend_textures::make_vk((width, height), vk_info, label)
251    }
252
253    #[cfg(feature = "metal")]
254    #[allow(clippy::missing_safety_doc)]
255    #[deprecated(since = "0.74.0", note = "use gpu::backend_textures::make_mtl()")]
256    pub unsafe fn new_metal(
257        (width, height): (i32, i32),
258        mipmapped: gpu::Mipmapped,
259        mtl_info: &mtl::TextureInfo,
260    ) -> Self {
261        gpu::backend_textures::make_mtl((width, height), mipmapped, mtl_info, "")
262    }
263
264    #[cfg(feature = "metal")]
265    #[allow(clippy::missing_safety_doc)]
266    #[deprecated(since = "0.74.0", note = "use gpu::backend_textures::make_mtl()")]
267    pub unsafe fn new_metal_with_label(
268        (width, height): (i32, i32),
269        mipmapped: gpu::Mipmapped,
270        mtl_info: &mtl::TextureInfo,
271        label: impl AsRef<str>,
272    ) -> Self {
273        gpu::backend_textures::make_mtl((width, height), mipmapped, mtl_info, label)
274    }
275
276    #[cfg(feature = "d3d")]
277    #[deprecated(since = "0.95.0", note = "use gpu::backend_textures::make_d3d()")]
278    pub fn new_d3d((width, height): (i32, i32), d3d_info: &d3d::TextureResourceInfo) -> Self {
279        gpu::backend_textures::make_d3d((width, height), d3d_info, "")
280    }
281
282    #[cfg(feature = "d3d")]
283    #[deprecated(since = "0.95.0", note = "use gpu::backend_textures::make_d3d()")]
284    pub fn new_d3d_with_label(
285        (width, height): (i32, i32),
286        d3d_info: &d3d::TextureResourceInfo,
287        label: impl AsRef<str>,
288    ) -> Self {
289        gpu::backend_textures::make_d3d((width, height), d3d_info, label)
290    }
291
292    pub(crate) unsafe fn from_native_if_valid(
293        backend_texture: *mut GrBackendTexture,
294    ) -> Option<BackendTexture> {
295        Self::native_is_valid(backend_texture)
296            .then(|| BackendTexture::from_ptr(backend_texture).unwrap())
297    }
298
299    pub fn dimensions(&self) -> ISize {
300        ISize::new(self.width(), self.height())
301    }
302
303    pub fn width(&self) -> i32 {
304        self.native().fWidth
305    }
306
307    pub fn height(&self) -> i32 {
308        self.native().fHeight
309    }
310
311    pub fn label(&self) -> &str {
312        self.native().fLabel.as_str()
313    }
314
315    pub fn mipmapped(&self) -> Mipmapped {
316        self.native().fMipmapped
317    }
318
319    #[deprecated(since = "0.35.0", note = "Use has_mipmaps()")]
320    pub fn has_mip_maps(&self) -> bool {
321        self.has_mipmaps()
322    }
323
324    pub fn has_mipmaps(&self) -> bool {
325        self.native().fMipmapped == Mipmapped::Yes
326    }
327
328    pub fn backend(&self) -> BackendAPI {
329        self.native().fBackend
330    }
331
332    // Deprecated in Skia
333    #[cfg(feature = "gl")]
334    pub fn gl_texture_info(&self) -> Option<gl::TextureInfo> {
335        gpu::backend_textures::get_gl_texture_info(self)
336    }
337
338    // Deprecated in Skia
339    #[cfg(feature = "gl")]
340    pub fn gl_texture_parameters_modified(&mut self) {
341        gpu::backend_textures::gl_texture_parameters_modified(self)
342    }
343
344    // Deprecated in Skia
345    #[cfg(feature = "vulkan")]
346    pub fn vulkan_image_info(&self) -> Option<vk::ImageInfo> {
347        gpu::backend_textures::get_vk_image_info(self)
348    }
349
350    // Deprecated in Skia
351    #[cfg(feature = "vulkan")]
352    pub fn set_vulkan_image_layout(&mut self, layout: vk::ImageLayout) -> &mut Self {
353        gpu::backend_textures::set_vk_image_layout(self, layout)
354    }
355
356    #[cfg(feature = "metal")]
357    pub fn metal_texture_info(&self) -> Option<mtl::TextureInfo> {
358        gpu::backend_textures::get_mtl_texture_info(self)
359    }
360
361    #[cfg(feature = "d3d")]
362    pub fn d3d_texture_resource_info(&self) -> Option<d3d::TextureResourceInfo> {
363        gpu::backend_textures::get_d3d_texture_resource_info(self)
364    }
365
366    #[cfg(feature = "d3d")]
367    pub fn set_d3d_resource_state(&mut self, resource_state: d3d::ResourceStateEnum) -> &mut Self {
368        gpu::backend_textures::set_d3d_resource_state(self, resource_state)
369    }
370
371    pub fn backend_format(&self) -> BackendFormat {
372        let mut format = BackendFormat::new_invalid();
373        unsafe { sb::C_GrBackendTexture_getBackendFormat(self.native(), format.native_mut()) };
374        assert!(BackendFormat::native_is_valid(format.native()));
375        format
376    }
377
378    pub fn set_mutable_state(&mut self, state: &MutableTextureState) {
379        unsafe { self.native_mut().setMutableState(state.native()) }
380    }
381
382    pub fn is_protected(&self) -> bool {
383        unsafe { self.native().isProtected() }
384    }
385
386    #[deprecated(note = "Invalid BackendTextures aren't supported", since = "0.37.0")]
387    pub fn is_valid(&self) -> bool {
388        self.native().fIsValid
389    }
390
391    pub(crate) unsafe fn native_is_valid(texture: *const GrBackendTexture) -> bool {
392        (*texture).fIsValid
393    }
394
395    #[allow(clippy::wrong_self_convention)]
396    pub fn is_same_texture(&mut self, texture: &BackendTexture) -> bool {
397        unsafe { self.native_mut().isSameTexture(texture.native()) }
398    }
399}
400
401pub type BackendRenderTarget = Handle<GrBackendRenderTarget>;
402unsafe_send_sync!(BackendRenderTarget);
403
404impl NativeDrop for GrBackendRenderTarget {
405    fn drop(&mut self) {
406        unsafe { sb::C_GrBackendRenderTarget_destruct(self) }
407    }
408}
409
410impl NativeClone for GrBackendRenderTarget {
411    fn clone(&self) -> Self {
412        construct(|render_target| unsafe {
413            sb::C_GrBackendRenderTarget_CopyConstruct(render_target, self)
414        })
415    }
416}
417
418impl fmt::Debug for BackendRenderTarget {
419    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420        let mut d = f.debug_struct("BackendRenderTarget");
421        d.field("dimensions", &self.dimensions());
422        d.field("sample_count", &self.sample_count());
423        d.field("stencil_bits", &self.stencil_bits());
424        d.field("backend", &self.backend());
425        d.field("is_framebuffer_only", &self.is_framebuffer_only());
426        #[cfg(feature = "gl")]
427        d.field("gl_framebuffer_info", &self.gl_framebuffer_info());
428        #[cfg(feature = "vulkan")]
429        d.field("vulkan_image_info", &self.vulkan_image_info());
430        #[cfg(feature = "metal")]
431        d.field("metal_texture_info", &self.metal_texture_info());
432        #[cfg(feature = "d3d")]
433        d.field(
434            "d3d_texture_resource_info",
435            &self.d3d_texture_resource_info(),
436        );
437        d.field("backend_format", &self.backend_format());
438        d.field("is_protected", &self.is_protected());
439        d.finish()
440    }
441}
442
443impl BackendRenderTarget {
444    #[cfg(feature = "gl")]
445    #[deprecated(since = "0.67.0", note = "use gpu::backend_render_targets::make_gl()")]
446    pub fn new_gl(
447        (width, height): (i32, i32),
448        sample_count: impl Into<Option<usize>>,
449        stencil_bits: usize,
450        info: gl::FramebufferInfo,
451    ) -> Self {
452        gpu::backend_render_targets::make_gl((width, height), sample_count, stencil_bits, info)
453    }
454
455    #[cfg(feature = "vulkan")]
456    #[deprecated(since = "0.67.0", note = "use gpu::backend_render_targets::make_vk()")]
457    pub fn new_vulkan((width, height): (i32, i32), info: &vk::ImageInfo) -> Self {
458        gpu::backend_render_targets::make_vk((width, height), info)
459    }
460
461    #[cfg(feature = "metal")]
462    #[deprecated(since = "0.74.0", note = "use gpu::backend_render_targets::make_mtl()")]
463    pub fn new_metal((width, height): (i32, i32), mtl_info: &mtl::TextureInfo) -> Self {
464        gpu::backend_render_targets::make_mtl((width, height), mtl_info)
465    }
466
467    #[cfg(feature = "d3d")]
468    #[deprecated(since = "0.95.0", note = "use gpu::backend_render_targets::make_d3d()")]
469    pub fn new_d3d((width, height): (i32, i32), d3d_info: &d3d::TextureResourceInfo) -> Self {
470        gpu::backend_render_targets::make_d3d((width, height), d3d_info)
471    }
472
473    pub(crate) fn from_native_c_if_valid(
474        native: GrBackendRenderTarget,
475    ) -> Option<BackendRenderTarget> {
476        let backend_render_target = BackendRenderTarget::from_native_c(native);
477        Self::native_is_valid(backend_render_target.native()).then_some(backend_render_target)
478    }
479
480    pub fn dimensions(&self) -> ISize {
481        ISize::new(self.width(), self.height())
482    }
483
484    pub fn width(&self) -> i32 {
485        self.native().fWidth
486    }
487
488    pub fn height(&self) -> i32 {
489        self.native().fHeight
490    }
491
492    pub fn sample_count(&self) -> usize {
493        self.native().fSampleCnt.try_into().unwrap()
494    }
495
496    pub fn stencil_bits(&self) -> usize {
497        self.native().fStencilBits.try_into().unwrap()
498    }
499
500    pub fn backend(&self) -> BackendAPI {
501        self.native().fBackend
502    }
503
504    pub fn is_framebuffer_only(&self) -> bool {
505        self.native().fFramebufferOnly
506    }
507
508    // Deprecated in Skia
509    #[cfg(feature = "gl")]
510    pub fn gl_framebuffer_info(&self) -> Option<gl::FramebufferInfo> {
511        gpu::backend_render_targets::get_gl_framebuffer_info(self)
512    }
513
514    // Deprecated in Skia
515    #[cfg(feature = "vulkan")]
516    pub fn vulkan_image_info(&self) -> Option<vk::ImageInfo> {
517        gpu::backend_render_targets::get_vk_image_info(self)
518    }
519
520    // Deprecated in Skia
521    #[cfg(feature = "vulkan")]
522    pub fn set_vulkan_image_layout(&mut self, layout: vk::ImageLayout) -> &mut Self {
523        gpu::backend_render_targets::set_vk_image_layout(self, layout)
524    }
525
526    #[cfg(feature = "metal")]
527    pub fn metal_texture_info(&self) -> Option<mtl::TextureInfo> {
528        gpu::backend_render_targets::get_mtl_texture_info(self)
529    }
530
531    #[cfg(feature = "d3d")]
532    pub fn d3d_texture_resource_info(&self) -> Option<d3d::TextureResourceInfo> {
533        gpu::backend_render_targets::get_d3d_texture_resource_info(self)
534    }
535
536    #[cfg(feature = "d3d")]
537    pub fn set_d3d_resource_state(&mut self, resource_state: d3d::ResourceStateEnum) -> &mut Self {
538        gpu::backend_render_targets::set_d3d_resource_state(self, resource_state)
539    }
540
541    pub fn backend_format(&self) -> BackendFormat {
542        BackendFormat::construct(|format| unsafe {
543            sb::C_GrBackendRenderTarget_getBackendFormat(self.native(), format)
544        })
545    }
546
547    pub fn set_mutable_state(&mut self, state: &MutableTextureState) {
548        unsafe { self.native_mut().setMutableState(state.native()) }
549    }
550
551    pub fn is_protected(&self) -> bool {
552        unsafe { self.native().isProtected() }
553    }
554
555    #[deprecated(
556        since = "0.37.0",
557        note = "Exposed BackendRenderTargets are always valid."
558    )]
559    pub fn is_valid(&self) -> bool {
560        self.native().fIsValid
561    }
562
563    pub(crate) fn native_is_valid(rt: &GrBackendRenderTarget) -> bool {
564        rt.fIsValid
565    }
566}
567
568#[cfg(test)]
569mod tests {
570    use super::BackendTexture;
571    use std::hint::black_box;
572
573    // Regression test for <https://github.com/rust-skia/rust-skia/issues/750>
574    #[test]
575    fn create_move_and_drop_backend_texture() {
576        let texture = force_move(BackendTexture::new_invalid());
577        drop(texture);
578    }
579
580    fn force_move<V>(src: V) -> V {
581        let src = black_box(src);
582        *black_box(Box::new(src))
583    }
584}