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