use std::{
borrow::Cow,
os::raw::c_void,
sync::{Arc, Mutex},
};
use drawing_api::{
Capabilities, ColorSource, DrawingContext, GraphicsApi, ImageFilter, TextureDescriptor,
};
use crate::{ImpellerSurface, ImpellerTexture};
#[derive(Clone)]
pub struct ImpellerContextVulkan {
context: Arc<Mutex<impellers::Context>>,
}
unsafe impl Send for ImpellerContextVulkan {}
unsafe impl Sync for ImpellerContextVulkan {}
impl DrawingContext for ImpellerContextVulkan {
type ColorSourceFragment = crate::ColorSourceFragment;
type DisplayList = crate::DisplayList;
type DisplayListBuilder = crate::DisplayListBuilder;
type Fonts = crate::Fonts;
type FragmentProgram = crate::ImpellerFragmentProgram;
type ImageFilterFragment = crate::ImageFilterFragment;
type Paint = crate::Paint;
type ParagraphBuilder = crate::ParagraphBuilder;
type PathBuilder = crate::PathBuilder;
type Surface = ImpellerSurface;
type Texture = ImpellerTexture;
fn get_api_capabilities(api: drawing_api::GraphicsApi) -> Option<drawing_api::Capabilities> {
let mut capabilities = Capabilities {
api: GraphicsApi::OpenGL { major: 3, minor: 1 },
transformations: true,
layers: true,
rect_clipping: true,
path_clipping: true,
color_filters: true,
image_filters: true,
mask_filters: true,
textures: true,
text_metrics: true,
text_decorations: true,
shadows: true,
fragment_color_sources: true,
fragment_image_filters: true,
};
match api {
drawing_api::GraphicsApi::OpenGL { major, minor } => {
if major >= 4 || major == 3 && minor >= 1 {
capabilities.api = GraphicsApi::OpenGL { major: 3, minor: 1 };
Some(capabilities)
} else {
None
}
}
drawing_api::GraphicsApi::OpenGLES { major, minor: _ } => {
if major >= 2 {
capabilities.api = GraphicsApi::OpenGLES { major: 2, minor: 0 };
Some(capabilities)
} else {
None
}
}
drawing_api::GraphicsApi::Vulkan { major, minor } => {
if major >= 2 || major == 1 && minor >= 1 {
capabilities.api = GraphicsApi::Vulkan { major: 1, minor: 1 };
Some(capabilities)
} else {
None
}
}
}
}
fn get_capabilities(&self) -> drawing_api::Capabilities {
Self::get_api_capabilities(drawing_api::GraphicsApi::Vulkan { major: 1, minor: 1 }).unwrap()
}
unsafe fn create_texture(
&self,
contents: Cow<'static, [u8]>,
descriptor: TextureDescriptor,
) -> Result<Self::Texture, &'static str> {
if descriptor.color_format != drawing_api::ColorFormat::RGBA {
return Err("color format not supported!");
}
let texture = unsafe {
self.context.lock().unwrap().create_texture_with_rgba8(
contents,
descriptor.width,
descriptor.height,
)?
};
Ok(ImpellerTexture {
texture,
descriptor,
})
}
unsafe fn new_color_source_from_fragment_program(
&self,
frag_program: &Self::FragmentProgram,
samplers: &[Self::Texture],
uniform_data: &[u8],
) -> ColorSource<Self::Texture, Self::ColorSourceFragment> {
let color_source = unsafe {
self.context
.lock()
.unwrap()
.new_color_source_from_fragment_program(
&frag_program.fragment_program,
&samplers
.iter()
.map(|s| s.texture.clone())
.collect::<Vec<_>>(),
uniform_data,
)
};
let color_source_fragment = Self::ColorSourceFragment { color_source };
ColorSource::Fragment {
color_source: color_source_fragment,
}
}
unsafe fn new_image_filter_from_fragment_program(
&self,
frag_program: &Self::FragmentProgram,
samplers: &[Self::Texture],
uniform_data: &[u8],
) -> ImageFilter<Self::ImageFilterFragment> {
let image_filter = unsafe {
self.context
.lock()
.unwrap()
.new_image_filter_from_fragment_program(
&frag_program.fragment_program,
&samplers
.iter()
.map(|s| s.texture.clone())
.collect::<Vec<_>>(),
uniform_data,
)
};
let image_filter_fragment = Self::ImageFilterFragment { image_filter };
ImageFilter::Fragment {
image_filter: image_filter_fragment,
}
}
}
impl drawing_api::ContextVulkan for ImpellerContextVulkan {
type VulkanSwapchain = crate::VulkanSwapchain;
unsafe fn new_vulkan<F>(
enable_validation: bool,
proc_address_callback: F,
) -> Result<Self, &'static str>
where
F: FnMut(*mut c_void, *const std::os::raw::c_char) -> *mut c_void,
{
unsafe {
let context = Arc::new(Mutex::new(impellers::Context::new_vulkan(
enable_validation,
proc_address_callback,
)?));
Ok(Self { context })
}
}
fn get_vulkan_info(&self) -> Result<drawing_api::ContextVulkanInfo, &'static str> {
let vulkan_info = self.context.lock().unwrap().get_vulkan_info()?;
Ok(drawing_api::ContextVulkanInfo {
vk_instance: vulkan_info.vk_instance,
vk_physical_device: vulkan_info.vk_physical_device,
vk_logical_device: vulkan_info.vk_logical_device,
graphics_queue_family_index: vulkan_info.graphics_queue_family_index,
graphics_queue_index: vulkan_info.graphics_queue_index,
})
}
unsafe fn create_new_vulkan_swapchain(
&self,
vulkan_surface_khr: *mut c_void,
) -> Result<Self::VulkanSwapchain, &'static str> {
unsafe {
let vk_swapchain = self
.context
.lock()
.unwrap()
.create_new_vulkan_swapchain(vulkan_surface_khr)
.ok_or("impeller: cannot create new vulkan swapchain")?;
Ok(Self::VulkanSwapchain { vk_swapchain })
}
}
}