|
@@ -0,0 +1,205 @@
|
|
|
+use crate::bitmap::{BitmapData, BitmapDataMut};
|
|
|
+use crate::formats::{self, PixelFormatSpec, NUM_PIXEL_FORMATS};
|
|
|
+use crate::op::{self, BinaryOpSpec, UnaryOpSpec};
|
|
|
+
|
|
|
+pub type UnaryFunc<Params> = for<'l> fn(&'l mut dyn BitmapDataMut, &'l Params);
|
|
|
+pub type BinaryFunc<Params> = for<'l> fn(&'l mut dyn BitmapDataMut, &'l dyn BitmapData, &'l Params);
|
|
|
+
|
|
|
+pub trait GenericUnary<Params> {
|
|
|
+ fn perform<'l, Format: PixelFormatSpec>(
|
|
|
+ write_data: &'l mut dyn BitmapDataMut,
|
|
|
+ params: &'l Params,
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+pub trait GenericBinary<Params> {
|
|
|
+ fn perform<'l, Format: PixelFormatSpec, ReadFormat: PixelFormatSpec>(
|
|
|
+ write_data: &'l mut dyn BitmapDataMut,
|
|
|
+ read_data: &'l dyn BitmapData,
|
|
|
+ params: &'l Params,
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+pub struct UnaryDispatch<Params> {
|
|
|
+ op_array: [UnaryFunc<Params>; NUM_PIXEL_FORMATS],
|
|
|
+ changed: [bool; NUM_PIXEL_FORMATS],
|
|
|
+}
|
|
|
+
|
|
|
+impl<Params> UnaryDispatch<Params> {
|
|
|
+ pub fn with<Format: PixelFormatSpec>(mut self, specific_imp: UnaryFunc<Params>) -> Self {
|
|
|
+ self.op_array[Format::FORMAT_ENUM as usize] = specific_imp;
|
|
|
+ self.changed[Format::FORMAT_ENUM as usize] = true;
|
|
|
+ self
|
|
|
+ }
|
|
|
+ pub fn with_avx<Format: PixelFormatSpec>(mut self, avx_imp: UnaryFunc<Params>) -> Self {
|
|
|
+ if is_x86_feature_detected!("avx") {
|
|
|
+ self.op_array[Format::FORMAT_ENUM as usize] = avx_imp;
|
|
|
+ self.changed[Format::FORMAT_ENUM as usize] = true;
|
|
|
+ self
|
|
|
+ } else {
|
|
|
+ self
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn select<Format: PixelFormatSpec>(&self) -> UnaryFunc<Params> {
|
|
|
+ self.op_array[Format::FORMAT_ENUM as usize]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub struct BinaryDispatch<Params> {
|
|
|
+ op_array: [[BinaryFunc<Params>; NUM_PIXEL_FORMATS]; NUM_PIXEL_FORMATS],
|
|
|
+ changed: [[bool; NUM_PIXEL_FORMATS]; NUM_PIXEL_FORMATS],
|
|
|
+}
|
|
|
+
|
|
|
+impl<Params> BinaryDispatch<Params> {
|
|
|
+ pub fn with_avx<WriteFormat: PixelFormatSpec, ReadFormat: PixelFormatSpec>(
|
|
|
+ mut self,
|
|
|
+ avx_imp: BinaryFunc<Params>,
|
|
|
+ ) -> Self {
|
|
|
+ if is_x86_feature_detected!("avx") {
|
|
|
+ self.op_array[WriteFormat::FORMAT_ENUM as usize][ReadFormat::FORMAT_ENUM as usize] =
|
|
|
+ avx_imp;
|
|
|
+ self
|
|
|
+ } else {
|
|
|
+ self
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn select<WriteFormat: PixelFormatSpec, ReadFormat: PixelFormatSpec>(
|
|
|
+ &self,
|
|
|
+ ) -> BinaryFunc<Params> {
|
|
|
+ self.op_array[WriteFormat::FORMAT_ENUM as usize][ReadFormat::FORMAT_ENUM as usize]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+macro_rules! dispatch_entry {
|
|
|
+ (unary, $sn:ident, $opn:ident) => {
|
|
|
+ UnaryDispatch < <op::$sn::$opn as UnaryOpSpec>::Params<'l>>
|
|
|
+ };
|
|
|
+
|
|
|
+ (binary, $sn:ident, $opn:ident) => {
|
|
|
+ BinaryDispatch < <op::$sn::$opn as BinaryOpSpec>::Params<'l>>
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+pub struct KahloDispatch<'l> {
|
|
|
+ pub composite: dispatch_entry!(binary, composite, CompositeOp),
|
|
|
+ pub copy_from: dispatch_entry!(binary, copy_from, CopyFromOp),
|
|
|
+ pub fill: dispatch_entry!(unary, fill, FillOp),
|
|
|
+ pub fill_region: dispatch_entry!(unary, fill_region, FillRegionOp),
|
|
|
+ pub fill_region_masked: dispatch_entry!(unary, fill_region_masked, FillRegionMaskedOp),
|
|
|
+}
|
|
|
+
|
|
|
+impl<'l> Default for KahloDispatch<'l> {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ composite: op::composite::CompositeOp::build(),
|
|
|
+ copy_from: op::copy_from::CopyFromOp::build(),
|
|
|
+ fill: op::fill::FillOp::build(),
|
|
|
+ fill_region: op::fill_region::FillRegionOp::build(),
|
|
|
+ fill_region_masked: op::fill_region_masked::FillRegionMaskedOp::build(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<'l> KahloDispatch<'l> {
|
|
|
+ pub fn use_lifetime(&self) -> &KahloDispatch<'_> {
|
|
|
+ unsafe { std::mem::transmute(self) }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+lazy_static::lazy_static! {
|
|
|
+ pub static ref DISPATCH: KahloDispatch<'static> = KahloDispatch::default();
|
|
|
+}
|
|
|
+
|
|
|
+// long but simple implementations
|
|
|
+
|
|
|
+impl<Params> UnaryDispatch<Params> {
|
|
|
+ pub(crate) fn from_generic<G: GenericUnary<Params>>() -> Self {
|
|
|
+ Self {
|
|
|
+ op_array: [
|
|
|
+ G::perform::<formats::A8>,
|
|
|
+ G::perform::<formats::Abgr32>,
|
|
|
+ G::perform::<formats::Bgr24>,
|
|
|
+ G::perform::<formats::Bgr32>,
|
|
|
+ G::perform::<formats::Rgb24>,
|
|
|
+ G::perform::<formats::Rgb32>,
|
|
|
+ G::perform::<formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ changed: Default::default(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<Params> BinaryDispatch<Params> {
|
|
|
+ pub(crate) fn from_generic<G: GenericBinary<Params>>() -> Self {
|
|
|
+ Self {
|
|
|
+ op_array: [
|
|
|
+ [
|
|
|
+ G::perform::<formats::A8, formats::A8>,
|
|
|
+ G::perform::<formats::A8, formats::Abgr32>,
|
|
|
+ G::perform::<formats::A8, formats::Bgr24>,
|
|
|
+ G::perform::<formats::A8, formats::Bgr32>,
|
|
|
+ G::perform::<formats::A8, formats::Rgb24>,
|
|
|
+ G::perform::<formats::A8, formats::Rgb32>,
|
|
|
+ G::perform::<formats::A8, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ G::perform::<formats::Abgr32, formats::A8>,
|
|
|
+ G::perform::<formats::Abgr32, formats::Abgr32>,
|
|
|
+ G::perform::<formats::Abgr32, formats::Bgr24>,
|
|
|
+ G::perform::<formats::Abgr32, formats::Bgr32>,
|
|
|
+ G::perform::<formats::Abgr32, formats::Rgb24>,
|
|
|
+ G::perform::<formats::Abgr32, formats::Rgb32>,
|
|
|
+ G::perform::<formats::Abgr32, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ G::perform::<formats::Bgr24, formats::A8>,
|
|
|
+ G::perform::<formats::Bgr24, formats::Abgr32>,
|
|
|
+ G::perform::<formats::Bgr24, formats::Bgr24>,
|
|
|
+ G::perform::<formats::Bgr24, formats::Bgr32>,
|
|
|
+ G::perform::<formats::Bgr24, formats::Rgb24>,
|
|
|
+ G::perform::<formats::Bgr24, formats::Rgb32>,
|
|
|
+ G::perform::<formats::Bgr24, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ G::perform::<formats::Bgr32, formats::A8>,
|
|
|
+ G::perform::<formats::Bgr32, formats::Abgr32>,
|
|
|
+ G::perform::<formats::Bgr32, formats::Bgr24>,
|
|
|
+ G::perform::<formats::Bgr32, formats::Bgr32>,
|
|
|
+ G::perform::<formats::Bgr32, formats::Rgb24>,
|
|
|
+ G::perform::<formats::Bgr32, formats::Rgb32>,
|
|
|
+ G::perform::<formats::Bgr32, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ G::perform::<formats::Rgb24, formats::A8>,
|
|
|
+ G::perform::<formats::Rgb24, formats::Abgr32>,
|
|
|
+ G::perform::<formats::Rgb24, formats::Bgr24>,
|
|
|
+ G::perform::<formats::Rgb24, formats::Bgr32>,
|
|
|
+ G::perform::<formats::Rgb24, formats::Rgb24>,
|
|
|
+ G::perform::<formats::Rgb24, formats::Rgb32>,
|
|
|
+ G::perform::<formats::Rgb24, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ G::perform::<formats::Rgb32, formats::A8>,
|
|
|
+ G::perform::<formats::Rgb32, formats::Abgr32>,
|
|
|
+ G::perform::<formats::Rgb32, formats::Bgr24>,
|
|
|
+ G::perform::<formats::Rgb32, formats::Bgr32>,
|
|
|
+ G::perform::<formats::Rgb32, formats::Rgb24>,
|
|
|
+ G::perform::<formats::Rgb32, formats::Rgb32>,
|
|
|
+ G::perform::<formats::Rgb32, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ G::perform::<formats::Rgba32, formats::A8>,
|
|
|
+ G::perform::<formats::Rgba32, formats::Abgr32>,
|
|
|
+ G::perform::<formats::Rgba32, formats::Bgr24>,
|
|
|
+ G::perform::<formats::Rgba32, formats::Bgr32>,
|
|
|
+ G::perform::<formats::Rgba32, formats::Rgb24>,
|
|
|
+ G::perform::<formats::Rgba32, formats::Rgb32>,
|
|
|
+ G::perform::<formats::Rgba32, formats::Rgba32>,
|
|
|
+ ],
|
|
|
+ ],
|
|
|
+ changed: Default::default(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|