// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 use windows::Win32::Graphics::Direct3D12::{D3D12_RESOURCE_STATE_PRESENT, ID3D12Resource}; use windows::Win32::Graphics::Dxgi::Common::DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN; use windows::Win32::Graphics::Dxgi::Common::{ DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, }; use wgpu_29 as wgpu; /// # Safety /// `resource` must be a valid D3D12 resource for the lifetime of the returned Surface. unsafe fn wrap_dx12_texture( width: i32, height: i32, gr_context: &mut skia_safe::gpu::DirectContext, resource: ID3D12Resource, dxgi_format: windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT, color_type: skia_safe::ColorType, ) -> Option { unsafe { let texture_info = skia_safe::gpu::d3d::TextureResourceInfo { resource, alloc: None, resource_state: D3D12_RESOURCE_STATE_PRESENT, format: dxgi_format, sample_count: 1, level_count: 1, sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN, protected: skia_safe::gpu::Protected::No, }; let backend_render_target = skia_safe::gpu::BackendRenderTarget::new_d3d((width, height), &texture_info); skia_safe::gpu::surfaces::wrap_backend_render_target( gr_context, &backend_render_target, skia_safe::gpu::SurfaceOrigin::TopLeft, color_type, None, None, ) } } /// # Safety /// The caller must ensure `texture` was created by a DX12-backed wgpu device and remains /// valid for the lifetime of the returned `skia_safe::Surface`. pub unsafe fn make_dx12_surface( gr_context: &mut skia_safe::gpu::DirectContext, texture: &wgpu::Texture, ) -> Option { // SAFETY: texture is borrowed for the duration of this call; the D3D12 resource is // ref-counted (COM) and cloned into Skia's internal BackendRenderTarget via wrap_dx12_texture. unsafe { let dx12_texture = texture.as_hal::()?; let resource = windows_core::Interface::from_raw(windows_core::Interface::into_raw( dx12_texture.raw_resource().clone(), )); let size = texture.size(); let (dxgi_format, color_type) = match texture.format() { wgpu::TextureFormat::Rgba8Unorm => { (DXGI_FORMAT_R8G8B8A8_UNORM, skia_safe::ColorType::RGBA8888) } wgpu::TextureFormat::Rgba8UnormSrgb => { (DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, skia_safe::ColorType::SRGBA8888) } wgpu::TextureFormat::Bgra8Unorm => { (DXGI_FORMAT_B8G8R8A8_UNORM, skia_safe::ColorType::BGRA8888) } _ => return None, }; wrap_dx12_texture( size.width as i32, size.height as i32, gr_context, resource, dxgi_format, color_type, ) } } #[allow(non_snake_case)] pub unsafe fn import_dx12_texture( canvas: &skia_safe::Canvas, texture: wgpu::Texture, ) -> Option { unsafe { let dx12_texture = texture.as_hal::(); let resource: ID3D12Resource = windows_core::Interface::from_raw( windows_core::Interface::into_raw(dx12_texture.unwrap().raw_resource().clone()), ); let dxgi_texture_format = resource.GetDesc().Format; let color_type = match dxgi_texture_format { DXGI_FORMAT_R8G8B8A8_UNORM => skia_safe::ColorType::RGBA8888, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => skia_safe::ColorType::SRGBA8888, DXGI_FORMAT_B8G8R8A8_UNORM => skia_safe::ColorType::BGRA8888, _ => return None, }; let texture_info = skia_safe::gpu::d3d::TextureResourceInfo { resource, alloc: None, resource_state: D3D12_RESOURCE_STATE_PRESENT, format: dxgi_texture_format, sample_count: 1, level_count: 1, sample_quality_pattern: DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN, protected: skia_safe::gpu::Protected::No, }; let size = texture.size(); let backend_texture = skia_safe::gpu::BackendTexture::new_d3d( (size.width as i32, size.height as i32), &texture_info, ); Some( skia_safe::image::Image::from_texture( canvas.recording_context().as_mut().unwrap(), &backend_texture, skia_safe::gpu::SurfaceOrigin::TopLeft, color_type, skia_safe::AlphaType::Unpremul, None, ) .unwrap(), ) } } pub unsafe fn make_dx12_context( adapter: &wgpu::Adapter, _device: &wgpu::Device, queue: &wgpu::Queue, ) -> Option { let backend = unsafe { let maybe_dx12_queue = queue.as_hal::(); let dx12_adapter = adapter.as_hal::().unwrap(); maybe_dx12_queue.map(|dx12_queue| { let dx12_queue_raw = dx12_queue.as_raw(); let mut dx12_device_old: Option = None; dx12_queue_raw.GetDevice(&mut dx12_device_old as _).unwrap(); let dx12_device_old = dx12_device_old.unwrap(); let dx12_device = windows_core::Interface::from_raw(windows_core::Interface::into_raw( dx12_device_old, )); let idxgiadapter_3: windows::Win32::Graphics::Dxgi::IDXGIAdapter3 = dx12_adapter.as_raw().clone().into(); skia_safe::gpu::d3d::BackendContext { adapter: windows_core::Interface::from_raw(windows_core::Interface::into_raw( idxgiadapter_3, )), device: dx12_device, queue: windows_core::Interface::from_raw(windows_core::Interface::into_raw( dx12_queue_raw.clone(), )), memory_allocator: None, protected_context: skia_safe::gpu::Protected::No, } }) }; skia_safe::gpu::DirectContext::new_d3d(&backend.unwrap(), None) }