use skia_safe as sk;
use crate::Error;
#[cfg(all(windows, feature = "gpu"))]
use crate::d3d::Dx12Backend;
#[cfg(all(any(target_os = "macos", target_os = "ios"), feature = "gpu"))]
use crate::metal::MetalBackend;
#[cfg(all(not(any(target_os = "macos", target_os = "ios")), feature = "gpu"))]
use crate::vulkan::VulkanBackend;
pub(crate) enum GaneshBackend {
#[cfg(any(target_os = "macos", target_os = "ios"))]
Metal(MetalBackend),
#[cfg(windows)]
Dx12(Dx12Backend),
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
Vulkan(VulkanBackend),
}
impl core::fmt::Debug for GaneshBackend {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
#[cfg(any(target_os = "macos", target_os = "ios"))]
Self::Metal(_) => f.write_str("GaneshBackend::Metal"),
#[cfg(windows)]
Self::Dx12(_) => f.write_str("GaneshBackend::Dx12"),
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
Self::Vulkan(_) => f.write_str("GaneshBackend::Vulkan"),
}
}
}
impl GaneshBackend {
pub(crate) const CANDIDATE_TEXTURE_FORMATS: &'static [wgpu::TextureFormat] = &[
wgpu::TextureFormat::Rgba8Unorm,
wgpu::TextureFormat::Rgba8UnormSrgb,
wgpu::TextureFormat::Bgra8Unorm,
wgpu::TextureFormat::Bgra8UnormSrgb,
wgpu::TextureFormat::Rgb10a2Unorm,
wgpu::TextureFormat::Rgba16Unorm,
wgpu::TextureFormat::Rgba16Float,
];
pub(crate) fn from_wgpu(
adapter: &wgpu::Adapter,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Result<Self, Error> {
#[cfg(any(target_os = "macos", target_os = "ios"))]
{
let _ = adapter;
return Ok(Self::Metal(MetalBackend::from_wgpu(device, queue)?));
}
#[cfg(windows)]
{
return match adapter.get_info().backend {
wgpu::Backend::Dx12 => {
Ok(Self::Dx12(Dx12Backend::from_wgpu(adapter, device, queue)?))
}
wgpu::Backend::Vulkan => Ok(Self::Vulkan(VulkanBackend::from_wgpu(device, queue)?)),
_ => Err(Error::UnsupportedGpuBackend),
};
}
#[cfg(not(any(target_os = "macos", target_os = "ios", windows)))]
{
let _ = adapter;
return Ok(Self::Vulkan(VulkanBackend::from_wgpu(device, queue)?));
}
#[allow(
unreachable_code,
reason = "platform cfgs can compile out all concrete backend branches"
)]
Err(Error::UnsupportedGpuBackend)
}
pub(crate) fn direct_context(&mut self) -> &mut sk::gpu::DirectContext {
match self {
#[cfg(any(target_os = "macos", target_os = "ios"))]
Self::Metal(backend) => backend.direct_context(),
#[cfg(windows)]
Self::Dx12(backend) => backend.direct_context(),
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
Self::Vulkan(backend) => backend.direct_context(),
}
}
pub(crate) fn wrap_texture(&mut self, texture: &wgpu::Texture) -> Result<sk::Surface, Error> {
match self {
#[cfg(any(target_os = "macos", target_os = "ios"))]
Self::Metal(backend) => backend.wrap_texture(texture),
#[cfg(windows)]
Self::Dx12(backend) => backend.wrap_texture(texture),
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
Self::Vulkan(backend) => backend.wrap_texture(texture),
}
}
pub(crate) fn supported_texture_formats(&self) -> Vec<wgpu::TextureFormat> {
match self {
#[cfg(any(target_os = "macos", target_os = "ios"))]
Self::Metal(_) => Self::CANDIDATE_TEXTURE_FORMATS
.iter()
.copied()
.filter(|format| MetalBackend::supports_texture_format(*format).is_ok())
.collect(),
#[cfg(windows)]
Self::Dx12(_) => Self::CANDIDATE_TEXTURE_FORMATS
.iter()
.copied()
.filter(|format| crate::d3d::supports_texture_format(*format).is_ok())
.collect(),
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
Self::Vulkan(_) => Self::CANDIDATE_TEXTURE_FORMATS
.iter()
.copied()
.filter(|format| crate::vulkan::supports_texture_format(*format).is_ok())
.collect(),
}
}
pub(crate) fn can_wrap_texture_format(
&self,
texture_format: wgpu::TextureFormat,
) -> Result<(), Error> {
match self {
#[cfg(any(target_os = "macos", target_os = "ios"))]
Self::Metal(_) => MetalBackend::supports_texture_format(texture_format),
#[cfg(windows)]
Self::Dx12(_) => crate::d3d::supports_texture_format(texture_format),
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
Self::Vulkan(_) => crate::vulkan::supports_texture_format(texture_format),
}
}
pub(crate) fn flush_surface(&mut self, surface: &mut sk::Surface) {
self.direct_context()
.flush_and_submit_surface(surface, sk::gpu::SyncCpu::No);
}
pub(crate) fn flush_surface_for_readback(&mut self, surface: &mut sk::Surface) {
self.direct_context()
.flush_and_submit_surface(surface, sk::gpu::SyncCpu::Yes);
}
}