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 pub fn new_dxgi(format: d3d::DXGI_FORMAT) -> Self {
94 Self::construct(|bf| unsafe {
95 sb::C_GrBackendFormat_ConstructDxgi(bf, format.into_native())
96 })
97 .assert_valid()
98 }
99
100 pub fn backend(&self) -> BackendAPI {
101 self.native().fBackend
102 }
103
104 pub fn channel_mask(&self) -> u32 {
105 unsafe { self.native().channelMask() }
106 }
107
108 #[cfg(feature = "gl")]
111 pub fn as_gl_format(&self) -> gl::Format {
112 gpu::backend_formats::as_gl_format(self)
113 }
114
115 #[cfg(feature = "gl")]
116 pub fn as_gl_format_enum(&self) -> gl::Enum {
117 gpu::backend_formats::as_gl_format_enum(self)
118 }
119
120 #[cfg(feature = "vulkan")]
122 pub fn as_vk_format(&self) -> Option<vk::Format> {
123 gpu::backend_formats::as_vk_format(self)
124 }
125
126 #[cfg(feature = "metal")]
127 pub fn as_mtl_format(&self) -> Option<mtl::PixelFormat> {
128 gpu::backend_formats::as_mtl_format(self)
129 }
130
131 #[cfg(feature = "d3d")]
132 pub fn as_dxgi_format(&self) -> Option<d3d::DXGI_FORMAT> {
133 let mut f = sb::DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
134 unsafe { self.native().asDxgiFormat(&mut f) }.then_some(d3d::DXGI_FORMAT::from_native_c(f))
135 }
136
137 #[must_use]
138 pub fn to_texture_2d(&self) -> Self {
139 let mut new = Self::new_invalid();
140 unsafe { sb::C_GrBackendFormat_makeTexture2D(self.native(), new.native_mut()) };
141 assert!(Self::native_is_valid(new.native()));
142 new
143 }
144
145 #[deprecated(
146 note = "Invalid BackendFormats are not supported anymore",
147 since = "0.37.0"
148 )]
149 pub fn is_valid(&self) -> bool {
150 self.native().fValid
151 }
152
153 pub(crate) fn native_is_valid(format: &GrBackendFormat) -> bool {
154 format.fValid
155 }
156
157 pub(crate) fn assert_valid(self) -> Self {
158 assert!(Self::native_is_valid(self.native()));
159 self
160 }
161}
162
163pub type BackendTexture = RefHandle<GrBackendTexture>;
166unsafe_send_sync!(BackendTexture);
167
168impl NativeDrop for GrBackendTexture {
169 fn drop(&mut self) {
170 unsafe { sb::C_GrBackendTexture_delete(self) }
171 }
172}
173
174impl Clone for BackendTexture {
175 fn clone(&self) -> Self {
176 unsafe { Self::from_ptr(sb::C_GrBackendTexture_Clone(self.native())) }.unwrap()
177 }
178}
179
180impl fmt::Debug for BackendTexture {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 let mut d = f.debug_struct("BackendTexture");
183 d.field("dimensions", &self.dimensions());
184 d.field("label", &self.label());
185 d.field("mipmapped", &self.mipmapped());
186 d.field("backend", &self.backend());
187 #[cfg(feature = "gl")]
188 d.field("gl_texture_info", &self.gl_texture_info());
189 #[cfg(feature = "vulkan")]
190 d.field("vulkan_image_info", &self.vulkan_image_info());
191 #[cfg(feature = "metal")]
192 d.field("metal_texture_info", &self.metal_texture_info());
193 #[cfg(feature = "d3d")]
194 d.field(
195 "d3d_texture_resource_info",
196 &self.d3d_texture_resource_info(),
197 );
198 d.field("backend_format", &self.backend_format());
199 d.field("is_protected", &self.is_protected());
200 d.finish()
201 }
202}
203
204impl BackendTexture {
205 pub(crate) fn new_invalid() -> Self {
206 Self::from_ptr(unsafe { sb::C_GrBackendTexture_new() }).unwrap()
207 }
208
209 #[cfg(feature = "gl")]
210 #[allow(clippy::missing_safety_doc)]
211 #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_gl()")]
212 pub unsafe fn new_gl(
213 (width, height): (i32, i32),
214 mipmapped: gpu::Mipmapped,
215 gl_info: gl::TextureInfo,
216 ) -> Self {
217 gpu::backend_textures::make_gl((width, height), mipmapped, gl_info, "")
218 }
219
220 #[cfg(feature = "gl")]
221 #[allow(clippy::missing_safety_doc)]
222 #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_gl()")]
223 pub unsafe fn new_gl_with_label(
224 (width, height): (i32, i32),
225 mipmapped: gpu::Mipmapped,
226 gl_info: gl::TextureInfo,
227 label: impl AsRef<str>,
228 ) -> Self {
229 gpu::backend_textures::make_gl((width, height), mipmapped, gl_info, label)
230 }
231
232 #[cfg(feature = "vulkan")]
233 #[allow(clippy::missing_safety_doc)]
234 #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_vk()")]
235 pub unsafe fn new_vulkan((width, height): (i32, i32), vk_info: &vk::ImageInfo) -> Self {
236 gpu::backend_textures::make_vk((width, height), vk_info, "")
237 }
238
239 #[cfg(feature = "vulkan")]
240 #[allow(clippy::missing_safety_doc)]
241 #[deprecated(since = "0.67.0", note = "use gpu::backend_textures::make_vk()")]
242 pub unsafe fn new_vulkan_with_label(
243 (width, height): (i32, i32),
244 vk_info: &vk::ImageInfo,
245 label: impl AsRef<str>,
246 ) -> Self {
247 gpu::backend_textures::make_vk((width, height), vk_info, label)
248 }
249
250 #[cfg(feature = "metal")]
251 #[allow(clippy::missing_safety_doc)]
252 #[deprecated(since = "0.74.0", note = "use gpu::backend_textures::make_mtl()")]
253 pub unsafe fn new_metal(
254 (width, height): (i32, i32),
255 mipmapped: gpu::Mipmapped,
256 mtl_info: &mtl::TextureInfo,
257 ) -> Self {
258 gpu::backend_textures::make_mtl((width, height), mipmapped, mtl_info, "")
259 }
260
261 #[cfg(feature = "metal")]
262 #[allow(clippy::missing_safety_doc)]
263 #[deprecated(since = "0.74.0", note = "use gpu::backend_textures::make_mtl()")]
264 pub unsafe fn new_metal_with_label(
265 (width, height): (i32, i32),
266 mipmapped: gpu::Mipmapped,
267 mtl_info: &mtl::TextureInfo,
268 label: impl AsRef<str>,
269 ) -> Self {
270 gpu::backend_textures::make_mtl((width, height), mipmapped, mtl_info, label)
271 }
272
273 #[cfg(feature = "d3d")]
274 pub fn new_d3d((width, height): (i32, i32), d3d_info: &d3d::TextureResourceInfo) -> Self {
275 Self::new_d3d_with_label((width, height), d3d_info, "")
276 }
277
278 #[cfg(feature = "d3d")]
279 pub fn new_d3d_with_label(
280 (width, height): (i32, i32),
281 d3d_info: &d3d::TextureResourceInfo,
282 label: impl AsRef<str>,
283 ) -> Self {
284 let label = label.as_ref().as_bytes();
285 unsafe {
286 Self::from_native_if_valid(sb::C_GrBackendTexture_newD3D(
287 width,
288 height,
289 d3d_info.native(),
290 label.as_ptr() as _,
291 label.len(),
292 ))
293 }
294 .unwrap()
295 }
296
297 pub(crate) unsafe fn from_native_if_valid(
298 backend_texture: *mut GrBackendTexture,
299 ) -> Option<BackendTexture> {
300 Self::native_is_valid(backend_texture)
301 .then(|| BackendTexture::from_ptr(backend_texture).unwrap())
302 }
303
304 pub fn dimensions(&self) -> ISize {
305 ISize::new(self.width(), self.height())
306 }
307
308 pub fn width(&self) -> i32 {
309 self.native().fWidth
310 }
311
312 pub fn height(&self) -> i32 {
313 self.native().fHeight
314 }
315
316 pub fn label(&self) -> &str {
317 self.native().fLabel.as_str()
318 }
319
320 pub fn mipmapped(&self) -> Mipmapped {
321 self.native().fMipmapped
322 }
323
324 #[deprecated(since = "0.35.0", note = "Use has_mipmaps()")]
325 pub fn has_mip_maps(&self) -> bool {
326 self.has_mipmaps()
327 }
328
329 pub fn has_mipmaps(&self) -> bool {
330 self.native().fMipmapped == Mipmapped::Yes
331 }
332
333 pub fn backend(&self) -> BackendAPI {
334 self.native().fBackend
335 }
336
337 #[cfg(feature = "gl")]
339 pub fn gl_texture_info(&self) -> Option<gl::TextureInfo> {
340 gpu::backend_textures::get_gl_texture_info(self)
341 }
342
343 #[cfg(feature = "gl")]
345 pub fn gl_texture_parameters_modified(&mut self) {
346 gpu::backend_textures::gl_texture_parameters_modified(self)
347 }
348
349 #[cfg(feature = "vulkan")]
351 pub fn vulkan_image_info(&self) -> Option<vk::ImageInfo> {
352 gpu::backend_textures::get_vk_image_info(self)
353 }
354
355 #[cfg(feature = "vulkan")]
357 pub fn set_vulkan_image_layout(&mut self, layout: vk::ImageLayout) -> &mut Self {
358 gpu::backend_textures::set_vk_image_layout(self, layout)
359 }
360
361 #[cfg(feature = "metal")]
362 pub fn metal_texture_info(&self) -> Option<mtl::TextureInfo> {
363 gpu::backend_textures::get_mtl_texture_info(self)
364 }
365
366 #[cfg(feature = "d3d")]
367 pub fn d3d_texture_resource_info(&self) -> Option<d3d::TextureResourceInfo> {
368 unsafe {
369 let mut info = sb::GrD3DTextureResourceInfo::default();
370 self.native().getD3DTextureResourceInfo(&mut info).then(|| {
371 assert!(!info.fResource.fObject.is_null());
372 d3d::TextureResourceInfo::from_native_c(info)
373 })
374 }
375 }
376
377 #[cfg(feature = "d3d")]
378 pub fn set_d3d_resource_state(&mut self, resource_state: d3d::ResourceStateEnum) -> &mut Self {
379 unsafe { self.native_mut().setD3DResourceState(resource_state) }
380 self
381 }
382
383 pub fn backend_format(&self) -> BackendFormat {
384 let mut format = BackendFormat::new_invalid();
385 unsafe { sb::C_GrBackendTexture_getBackendFormat(self.native(), format.native_mut()) };
386 assert!(BackendFormat::native_is_valid(format.native()));
387 format
388 }
389
390 pub fn set_mutable_state(&mut self, state: &MutableTextureState) {
391 unsafe { self.native_mut().setMutableState(state.native()) }
392 }
393
394 pub fn is_protected(&self) -> bool {
395 unsafe { self.native().isProtected() }
396 }
397
398 #[deprecated(note = "Invalid BackendTextures aren't supported", since = "0.37.0")]
399 pub fn is_valid(&self) -> bool {
400 self.native().fIsValid
401 }
402
403 pub(crate) unsafe fn native_is_valid(texture: *const GrBackendTexture) -> bool {
404 (*texture).fIsValid
405 }
406
407 #[allow(clippy::wrong_self_convention)]
408 pub fn is_same_texture(&mut self, texture: &BackendTexture) -> bool {
409 unsafe { self.native_mut().isSameTexture(texture.native()) }
410 }
411}
412
413pub type BackendRenderTarget = Handle<GrBackendRenderTarget>;
414unsafe_send_sync!(BackendRenderTarget);
415
416impl NativeDrop for GrBackendRenderTarget {
417 fn drop(&mut self) {
418 unsafe { sb::C_GrBackendRenderTarget_destruct(self) }
419 }
420}
421
422impl NativeClone for GrBackendRenderTarget {
423 fn clone(&self) -> Self {
424 construct(|render_target| unsafe {
425 sb::C_GrBackendRenderTarget_CopyConstruct(render_target, self)
426 })
427 }
428}
429
430impl fmt::Debug for BackendRenderTarget {
431 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432 let mut d = f.debug_struct("BackendRenderTarget");
433 d.field("dimensions", &self.dimensions());
434 d.field("sample_count", &self.sample_count());
435 d.field("stencil_bits", &self.stencil_bits());
436 d.field("backend", &self.backend());
437 d.field("is_framebuffer_only", &self.is_framebuffer_only());
438 #[cfg(feature = "gl")]
439 d.field("gl_framebuffer_info", &self.gl_framebuffer_info());
440 #[cfg(feature = "vulkan")]
441 d.field("vulkan_image_info", &self.vulkan_image_info());
442 #[cfg(feature = "metal")]
443 d.field("metal_texture_info", &self.metal_texture_info());
444 #[cfg(feature = "d3d")]
445 d.field(
446 "d3d_texture_resource_info",
447 &self.d3d_texture_resource_info(),
448 );
449 d.field("backend_format", &self.backend_format());
450 d.field("is_protected", &self.is_protected());
451 d.finish()
452 }
453}
454
455impl BackendRenderTarget {
456 #[cfg(feature = "gl")]
457 #[deprecated(since = "0.67.0", note = "use gpu::backend_render_targets::make_gl()")]
458 pub fn new_gl(
459 (width, height): (i32, i32),
460 sample_count: impl Into<Option<usize>>,
461 stencil_bits: usize,
462 info: gl::FramebufferInfo,
463 ) -> Self {
464 gpu::backend_render_targets::make_gl((width, height), sample_count, stencil_bits, info)
465 }
466
467 #[cfg(feature = "vulkan")]
468 #[deprecated(since = "0.67.0", note = "use gpu::backend_render_targets::make_vk()")]
469 pub fn new_vulkan((width, height): (i32, i32), info: &vk::ImageInfo) -> Self {
470 gpu::backend_render_targets::make_vk((width, height), info)
471 }
472
473 #[cfg(feature = "metal")]
474 #[deprecated(since = "0.74.0", note = "use gpu::backend_render_targets::make_mtl()")]
475 pub fn new_metal((width, height): (i32, i32), mtl_info: &mtl::TextureInfo) -> Self {
476 gpu::backend_render_targets::make_mtl((width, height), mtl_info)
477 }
478
479 #[cfg(feature = "d3d")]
480 pub fn new_d3d((width, height): (i32, i32), d3d_info: &d3d::TextureResourceInfo) -> Self {
481 Self::construct(|brt| unsafe {
482 sb::C_GrBackendRenderTarget_ConstructD3D(brt, width, height, d3d_info.native())
483 })
484 }
485
486 pub(crate) fn from_native_c_if_valid(
487 native: GrBackendRenderTarget,
488 ) -> Option<BackendRenderTarget> {
489 let backend_render_target = BackendRenderTarget::from_native_c(native);
490 Self::native_is_valid(backend_render_target.native()).then_some(backend_render_target)
491 }
492
493 pub fn dimensions(&self) -> ISize {
494 ISize::new(self.width(), self.height())
495 }
496
497 pub fn width(&self) -> i32 {
498 self.native().fWidth
499 }
500
501 pub fn height(&self) -> i32 {
502 self.native().fHeight
503 }
504
505 pub fn sample_count(&self) -> usize {
506 self.native().fSampleCnt.try_into().unwrap()
507 }
508
509 pub fn stencil_bits(&self) -> usize {
510 self.native().fStencilBits.try_into().unwrap()
511 }
512
513 pub fn backend(&self) -> BackendAPI {
514 self.native().fBackend
515 }
516
517 pub fn is_framebuffer_only(&self) -> bool {
518 self.native().fFramebufferOnly
519 }
520
521 #[cfg(feature = "gl")]
523 pub fn gl_framebuffer_info(&self) -> Option<gl::FramebufferInfo> {
524 gpu::backend_render_targets::get_gl_framebuffer_info(self)
525 }
526
527 #[cfg(feature = "vulkan")]
529 pub fn vulkan_image_info(&self) -> Option<vk::ImageInfo> {
530 gpu::backend_render_targets::get_vk_image_info(self)
531 }
532
533 #[cfg(feature = "vulkan")]
535 pub fn set_vulkan_image_layout(&mut self, layout: vk::ImageLayout) -> &mut Self {
536 gpu::backend_render_targets::set_vk_image_layout(self, layout)
537 }
538
539 #[cfg(feature = "metal")]
540 pub fn metal_texture_info(&self) -> Option<mtl::TextureInfo> {
541 gpu::backend_render_targets::get_mtl_texture_info(self)
542 }
543
544 #[cfg(feature = "d3d")]
545 pub fn d3d_texture_resource_info(&self) -> Option<d3d::TextureResourceInfo> {
546 let mut info = sb::GrD3DTextureResourceInfo::default();
547 unsafe { self.native().getD3DTextureResourceInfo(&mut info) }.then(|| {
548 assert!(!info.fResource.fObject.is_null());
549 d3d::TextureResourceInfo::from_native_c(info)
550 })
551 }
552
553 #[cfg(feature = "d3d")]
554 pub fn set_d3d_resource_state(&mut self, resource_state: d3d::ResourceStateEnum) -> &mut Self {
555 unsafe { self.native_mut().setD3DResourceState(resource_state) }
556 self
557 }
558
559 pub fn backend_format(&self) -> BackendFormat {
560 BackendFormat::construct(|format| unsafe {
561 sb::C_GrBackendRenderTarget_getBackendFormat(self.native(), format)
562 })
563 }
564
565 pub fn set_mutable_state(&mut self, state: &MutableTextureState) {
566 unsafe { self.native_mut().setMutableState(state.native()) }
567 }
568
569 pub fn is_protected(&self) -> bool {
570 unsafe { self.native().isProtected() }
571 }
572
573 #[deprecated(
574 since = "0.37.0",
575 note = "Exposed BackendRenderTargets are always valid."
576 )]
577 pub fn is_valid(&self) -> bool {
578 self.native().fIsValid
579 }
580
581 pub(crate) fn native_is_valid(rt: &GrBackendRenderTarget) -> bool {
582 rt.fIsValid
583 }
584}
585
586#[cfg(test)]
587mod tests {
588 use super::BackendTexture;
589 use std::hint::black_box;
590
591 #[test]
593 fn create_move_and_drop_backend_texture() {
594 let texture = force_move(BackendTexture::new_invalid());
595 drop(texture);
596 }
597
598 fn force_move<V>(src: V) -> V {
599 let src = black_box(src);
600 *black_box(Box::new(src))
601 }
602}