1 | /* |
2 | * Copyright (c) 2023. |
3 | * |
4 | * This software is free software; |
5 | * |
6 | * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license |
7 | */ |
8 | |
9 | #![allow ( |
10 | clippy::many_single_char_names, |
11 | clippy::similar_names, |
12 | clippy::cast_possible_truncation, |
13 | clippy::cast_sign_loss, |
14 | clippy::cast_possible_wrap, |
15 | clippy::too_many_arguments, |
16 | clippy::doc_markdown |
17 | )] |
18 | |
19 | //! Color space conversion routines |
20 | //! |
21 | //! This files exposes functions to convert one colorspace to another in a jpeg |
22 | //! image |
23 | //! |
24 | //! Currently supported conversions are |
25 | //! |
26 | //! - `YCbCr` to `RGB,RGBA,GRAYSCALE,RGBX`. |
27 | //! |
28 | //! |
29 | //! Hey there, if your reading this it means you probably need something, so let me help you. |
30 | //! |
31 | //! There are 3 supported cpu extensions here. |
32 | //! 1. Scalar |
33 | //! 2. SSE |
34 | //! 3. AVX |
35 | //! |
36 | //! There are two types of the color convert functions |
37 | //! |
38 | //! 1. Acts on 16 pixels. |
39 | //! 2. Acts on 8 pixels. |
40 | //! |
41 | //! The reason for this is because when implementing the AVX part it occurred to me that we can actually |
42 | //! do better and process 2 MCU's if we change IDCT return type to be `i16's`, since a lot of |
43 | //! CPU's these days support AVX extensions, it becomes nice if we optimize for that path , |
44 | //! therefore AVX routines can process 16 pixels directly and SSE and Scalar just compensate. |
45 | //! |
46 | //! By compensating, I mean I wrote the 16 pixels version operating on the 8 pixel version twice. |
47 | //! |
48 | //! Therefore if your looking to optimize some routines, probably start there. |
49 | |
50 | pub use scalar::ycbcr_to_grayscale; |
51 | use zune_core::colorspace::ColorSpace; |
52 | use zune_core::options::DecoderOptions; |
53 | |
54 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
55 | #[cfg (feature = "x86" )] |
56 | pub use crate::color_convert::avx::{ycbcr_to_rgb_avx2, ycbcr_to_rgba_avx2}; |
57 | use crate::decoder::ColorConvert16Ptr; |
58 | |
59 | mod avx; |
60 | mod scalar; |
61 | #[allow (unused_variables)] |
62 | pub fn choose_ycbcr_to_rgb_convert_func( |
63 | type_need: ColorSpace, options: &DecoderOptions |
64 | ) -> Option<ColorConvert16Ptr> { |
65 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
66 | #[cfg (feature = "x86" )] |
67 | { |
68 | use zune_core::log::debug; |
69 | if options.use_avx2() { |
70 | debug!("Using AVX optimised color conversion functions" ); |
71 | |
72 | // I believe avx2 means sse4 is also available |
73 | // match colorspace |
74 | match type_need { |
75 | ColorSpace::RGB => return Some(ycbcr_to_rgb_avx2), |
76 | ColorSpace::RGBA => return Some(ycbcr_to_rgba_avx2), |
77 | _ => () // fall through to scalar, which has more types |
78 | }; |
79 | } |
80 | } |
81 | // when there is no x86 or we haven't returned by here, resort to scalar |
82 | return match type_need { |
83 | ColorSpace::RGB => Some(scalar::ycbcr_to_rgb_inner_16_scalar::<false>), |
84 | ColorSpace::RGBA => Some(scalar::ycbcr_to_rgba_inner_16_scalar::<false>), |
85 | ColorSpace::BGRA => Some(scalar::ycbcr_to_rgba_inner_16_scalar::<true>), |
86 | ColorSpace::BGR => Some(scalar::ycbcr_to_rgb_inner_16_scalar::<true>), |
87 | _ => None |
88 | }; |
89 | } |
90 | |