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