1#[cfg(feature = "in_place")]
30use crate::InPlaceTransformExecutor;
31use crate::conversions::TransformMatrixShaper;
32use crate::conversions::rgbxyz::{
33 TransformMatrixShaperOptimized, make_rgb_xyz_rgb_transform, make_rgb_xyz_rgb_transform_opt,
34};
35use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_opt;
36use crate::{CmsError, Layout, TransformExecutor, TransformOptions};
37use num_traits::AsPrimitive;
38use std::sync::Arc;
39
40const FIXED_POINT_SCALE: i32 = 13; pub(crate) trait RgbXyzFactory<T: Clone + AsPrimitive<usize> + Default> {
43 fn make_transform<const LINEAR_CAP: usize, const GAMMA_LUT: usize, const BIT_DEPTH: usize>(
44 src_layout: Layout,
45 dst_layout: Layout,
46 profile: TransformMatrixShaper<T, LINEAR_CAP>,
47 transform_options: TransformOptions,
48 ) -> Result<Arc<dyn TransformExecutor<T> + Send + Sync>, CmsError>;
49
50 #[cfg(feature = "in_place")]
51 fn make_in_place_transform<
52 const LINEAR_CAP: usize,
53 const GAMMA_LUT: usize,
54 const BIT_DEPTH: usize,
55 >(
56 layout: Layout,
57 profile: TransformMatrixShaper<T, LINEAR_CAP>,
58 transform_options: TransformOptions,
59 ) -> Result<Arc<dyn InPlaceTransformExecutor<T> + Send + Sync>, CmsError>;
60}
61
62pub(crate) trait RgbXyzFactoryOpt<T: Clone + AsPrimitive<usize> + Default> {
63 fn make_optimized_transform<
64 const LINEAR_CAP: usize,
65 const GAMMA_LUT: usize,
66 const BIT_DEPTH: usize,
67 >(
68 src_layout: Layout,
69 dst_layout: Layout,
70 profile: TransformMatrixShaperOptimized<T, LINEAR_CAP>,
71 transform_options: TransformOptions,
72 ) -> Result<Arc<dyn TransformExecutor<T> + Send + Sync>, CmsError>;
73
74 #[cfg(feature = "in_place")]
75 fn make_in_place_optimized_transform<
76 const LINEAR_CAP: usize,
77 const GAMMA_LUT: usize,
78 const BIT_DEPTH: usize,
79 >(
80 layout: Layout,
81 profile: TransformMatrixShaperOptimized<T, LINEAR_CAP>,
82 transform_options: TransformOptions,
83 ) -> Result<Arc<dyn InPlaceTransformExecutor<T> + Send + Sync>, CmsError>;
84}
85
86impl RgbXyzFactory<u16> for u16 {
87 fn make_transform<const LINEAR_CAP: usize, const GAMMA_LUT: usize, const BIT_DEPTH: usize>(
88 src_layout: Layout,
89 dst_layout: Layout,
90 profile: TransformMatrixShaper<u16, LINEAR_CAP>,
91 _: TransformOptions,
92 ) -> Result<Arc<dyn TransformExecutor<u16> + Send + Sync>, CmsError> {
93 make_rgb_xyz_rgb_transform::<u16, LINEAR_CAP>(
94 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
95 )
96 }
97
98 #[cfg(feature = "in_place")]
99 fn make_in_place_transform<
100 const LINEAR_CAP: usize,
101 const GAMMA_LUT: usize,
102 const BIT_DEPTH: usize,
103 >(
104 layout: Layout,
105 profile: TransformMatrixShaper<u16, LINEAR_CAP>,
106 _: TransformOptions,
107 ) -> Result<Arc<dyn InPlaceTransformExecutor<u16> + Send + Sync>, CmsError> {
108 use crate::conversions::rgbxyz::make_in_place_rgb_xyz_transform;
109 make_in_place_rgb_xyz_transform::<u16, LINEAR_CAP>(layout, profile, GAMMA_LUT, BIT_DEPTH)
110 }
111}
112
113impl RgbXyzFactory<f32> for f32 {
114 fn make_transform<const LINEAR_CAP: usize, const GAMMA_LUT: usize, const BIT_DEPTH: usize>(
115 src_layout: Layout,
116 dst_layout: Layout,
117 profile: TransformMatrixShaper<f32, LINEAR_CAP>,
118 _: TransformOptions,
119 ) -> Result<Arc<dyn TransformExecutor<f32> + Send + Sync>, CmsError> {
120 make_rgb_xyz_rgb_transform::<f32, LINEAR_CAP>(
121 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
122 )
123 }
124
125 #[cfg(feature = "in_place")]
126 fn make_in_place_transform<
127 const LINEAR_CAP: usize,
128 const GAMMA_LUT: usize,
129 const BIT_DEPTH: usize,
130 >(
131 layout: Layout,
132 profile: TransformMatrixShaper<f32, LINEAR_CAP>,
133 _: TransformOptions,
134 ) -> Result<Arc<dyn InPlaceTransformExecutor<f32> + Send + Sync>, CmsError> {
135 use crate::conversions::rgbxyz::make_in_place_rgb_xyz_transform;
136 make_in_place_rgb_xyz_transform::<f32, LINEAR_CAP>(layout, profile, GAMMA_LUT, BIT_DEPTH)
137 }
138}
139
140impl RgbXyzFactory<f64> for f64 {
141 fn make_transform<const LINEAR_CAP: usize, const GAMMA_LUT: usize, const BIT_DEPTH: usize>(
142 src_layout: Layout,
143 dst_layout: Layout,
144 profile: TransformMatrixShaper<f64, LINEAR_CAP>,
145 _: TransformOptions,
146 ) -> Result<Arc<dyn TransformExecutor<f64> + Send + Sync>, CmsError> {
147 make_rgb_xyz_rgb_transform::<f64, LINEAR_CAP>(
148 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
149 )
150 }
151
152 #[cfg(feature = "in_place")]
153 fn make_in_place_transform<
154 const LINEAR_CAP: usize,
155 const GAMMA_LUT: usize,
156 const BIT_DEPTH: usize,
157 >(
158 layout: Layout,
159 profile: TransformMatrixShaper<f64, LINEAR_CAP>,
160 _: TransformOptions,
161 ) -> Result<Arc<dyn InPlaceTransformExecutor<f64> + Send + Sync>, CmsError> {
162 use crate::conversions::rgbxyz::make_in_place_rgb_xyz_transform;
163 make_in_place_rgb_xyz_transform::<f64, LINEAR_CAP>(layout, profile, GAMMA_LUT, BIT_DEPTH)
164 }
165}
166
167impl RgbXyzFactory<u8> for u8 {
168 fn make_transform<const LINEAR_CAP: usize, const GAMMA_LUT: usize, const BIT_DEPTH: usize>(
169 src_layout: Layout,
170 dst_layout: Layout,
171 profile: TransformMatrixShaper<u8, LINEAR_CAP>,
172 _: TransformOptions,
173 ) -> Result<Arc<dyn TransformExecutor<u8> + Send + Sync>, CmsError> {
174 make_rgb_xyz_rgb_transform::<u8, LINEAR_CAP>(src_layout, dst_layout, profile, GAMMA_LUT, 8)
175 }
176
177 #[cfg(feature = "in_place")]
178 fn make_in_place_transform<
179 const LINEAR_CAP: usize,
180 const GAMMA_LUT: usize,
181 const BIT_DEPTH: usize,
182 >(
183 layout: Layout,
184 profile: TransformMatrixShaper<u8, LINEAR_CAP>,
185 _: TransformOptions,
186 ) -> Result<Arc<dyn InPlaceTransformExecutor<u8> + Send + Sync>, CmsError> {
187 use crate::conversions::rgbxyz::make_in_place_rgb_xyz_transform;
188 make_in_place_rgb_xyz_transform::<u8, LINEAR_CAP>(layout, profile, GAMMA_LUT, BIT_DEPTH)
189 }
190}
191
192impl RgbXyzFactoryOpt<u16> for u16 {
195 fn make_optimized_transform<
196 const LINEAR_CAP: usize,
197 const GAMMA_LUT: usize,
198 const BIT_DEPTH: usize,
199 >(
200 src_layout: Layout,
201 dst_layout: Layout,
202 profile: TransformMatrixShaperOptimized<u16, LINEAR_CAP>,
203 transform_options: TransformOptions,
204 ) -> Result<Arc<dyn TransformExecutor<u16> + Send + Sync>, CmsError> {
205 if BIT_DEPTH >= 12 && transform_options.prefer_fixed_point {
206 #[cfg(all(target_arch = "aarch64", feature = "neon_shaper_fixed_point_paths"))]
207 {
208 if std::arch::is_aarch64_feature_detected!("rdm") {
209 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q1_30_opt;
210 return make_rgb_xyz_q1_30_opt::<u16, LINEAR_CAP, 30>(
211 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
212 );
213 }
214 }
215 }
216 if BIT_DEPTH < 16 && transform_options.prefer_fixed_point {
217 #[cfg(all(target_arch = "x86_64", feature = "avx_shaper_fixed_point_paths"))]
218 {
219 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_avx2_opt;
220 if std::arch::is_x86_feature_detected!("avx2") {
221 return make_rgb_xyz_q2_13_transform_avx2_opt::<
222 u16,
223 LINEAR_CAP,
224 FIXED_POINT_SCALE,
225 >(
226 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH
227 );
228 }
229 }
230 #[cfg(all(
231 any(target_arch = "x86", target_arch = "x86_64"),
232 feature = "sse_shaper_fixed_point_paths"
233 ))]
234 {
235 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_sse_41_opt;
236 if std::arch::is_x86_feature_detected!("sse4.1") {
237 return make_rgb_xyz_q2_13_transform_sse_41_opt::<
238 u16,
239 LINEAR_CAP,
240 FIXED_POINT_SCALE,
241 >(
242 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH
243 );
244 }
245 }
246 #[cfg(all(target_arch = "aarch64", feature = "neon"))]
247 {
248 return make_rgb_xyz_q2_13_opt::<u16, LINEAR_CAP, FIXED_POINT_SCALE>(
249 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
250 );
251 }
252 }
253 make_rgb_xyz_rgb_transform_opt::<u16, LINEAR_CAP>(
254 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
255 )
256 }
257
258 #[cfg(feature = "in_place")]
259 fn make_in_place_optimized_transform<
260 const LINEAR_CAP: usize,
261 const GAMMA_LUT: usize,
262 const BIT_DEPTH: usize,
263 >(
264 layout: Layout,
265 profile: TransformMatrixShaperOptimized<u16, LINEAR_CAP>,
266 transform_options: TransformOptions,
267 ) -> Result<Arc<dyn InPlaceTransformExecutor<u16> + Send + Sync>, CmsError> {
268 if transform_options.prefer_fixed_point && BIT_DEPTH < 16 {
269 #[cfg(all(
270 target_arch = "aarch64",
271 feature = "in_place",
272 feature = "neon_shaper_fixed_point_paths"
273 ))]
274 {
275 use crate::conversions::rgbxyz::make_rgb_xyz_in_place_transform_q2_13_opt;
276 return make_rgb_xyz_in_place_transform_q2_13_opt::<
277 u16,
278 LINEAR_CAP,
279 FIXED_POINT_SCALE,
280 >(layout, profile, GAMMA_LUT, BIT_DEPTH);
281 }
282
283 #[cfg(all(
284 target_arch = "x86_64",
285 feature = "in_place",
286 feature = "avx_shaper_fixed_point_paths"
287 ))]
288 {
289 if std::arch::is_x86_feature_detected!("avx2") {
290 use crate::conversions::rgbxyz::make_avx_rgb_xyz_in_place_transform_q2_13_opt;
291 return make_avx_rgb_xyz_in_place_transform_q2_13_opt::<
292 u16,
293 LINEAR_CAP,
294 FIXED_POINT_SCALE,
295 >(layout, profile, GAMMA_LUT, BIT_DEPTH);
296 }
297 }
298
299 #[cfg(all(
300 any(target_arch = "x86_64", target_arch = "x86"),
301 feature = "in_place",
302 feature = "sse_shaper_fixed_point_paths"
303 ))]
304 {
305 if std::arch::is_x86_feature_detected!("sse4.1") {
306 use crate::conversions::rgbxyz::make_sse_rgb_xyz_in_place_transform_q2_13_opt;
307 return make_sse_rgb_xyz_in_place_transform_q2_13_opt::<
308 u16,
309 LINEAR_CAP,
310 FIXED_POINT_SCALE,
311 >(layout, profile, GAMMA_LUT, BIT_DEPTH);
312 }
313 }
314 }
315 use crate::conversions::rgbxyz::make_rgb_xyz_in_place_transform_opt;
316 make_rgb_xyz_in_place_transform_opt::<u16, LINEAR_CAP>(
317 layout, profile, GAMMA_LUT, BIT_DEPTH,
318 )
319 }
320}
321
322impl RgbXyzFactoryOpt<f32> for f32 {
323 fn make_optimized_transform<
324 const LINEAR_CAP: usize,
325 const GAMMA_LUT: usize,
326 const BIT_DEPTH: usize,
327 >(
328 src_layout: Layout,
329 dst_layout: Layout,
330 profile: TransformMatrixShaperOptimized<f32, LINEAR_CAP>,
331 transform_options: TransformOptions,
332 ) -> Result<Arc<dyn TransformExecutor<f32> + Send + Sync>, CmsError> {
333 if transform_options.prefer_fixed_point {
334 #[cfg(all(target_arch = "x86_64", feature = "avx_shaper_fixed_point_paths"))]
335 {
336 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_avx2_opt;
337 if std::arch::is_x86_feature_detected!("avx2") {
338 return make_rgb_xyz_q2_13_transform_avx2_opt::<
339 f32,
340 LINEAR_CAP,
341 FIXED_POINT_SCALE,
342 >(
343 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH
344 );
345 }
346 }
347 #[cfg(all(
348 any(target_arch = "x86", target_arch = "x86_64"),
349 feature = "sse_shaper_fixed_point_paths"
350 ))]
351 {
352 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_sse_41_opt;
353 if std::arch::is_x86_feature_detected!("sse4.1") {
354 return make_rgb_xyz_q2_13_transform_sse_41_opt::<
355 f32,
356 LINEAR_CAP,
357 FIXED_POINT_SCALE,
358 >(
359 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH
360 );
361 }
362 }
363 #[cfg(all(target_arch = "aarch64", feature = "neon_shaper_fixed_point_paths"))]
364 {
365 return if std::arch::is_aarch64_feature_detected!("rdm") {
366 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q1_30_opt;
367 make_rgb_xyz_q1_30_opt::<f32, LINEAR_CAP, 30>(
368 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
369 )
370 } else {
371 make_rgb_xyz_q2_13_opt::<f32, LINEAR_CAP, FIXED_POINT_SCALE>(
372 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
373 )
374 };
375 }
376 }
377 make_rgb_xyz_rgb_transform_opt::<f32, LINEAR_CAP>(
378 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
379 )
380 }
381
382 #[cfg(feature = "in_place")]
383 fn make_in_place_optimized_transform<
384 const LINEAR_CAP: usize,
385 const GAMMA_LUT: usize,
386 const BIT_DEPTH: usize,
387 >(
388 layout: Layout,
389 profile: TransformMatrixShaperOptimized<f32, LINEAR_CAP>,
390 _: TransformOptions,
391 ) -> Result<Arc<dyn InPlaceTransformExecutor<f32> + Send + Sync>, CmsError> {
392 use crate::conversions::rgbxyz::make_rgb_xyz_in_place_transform_opt;
393 make_rgb_xyz_in_place_transform_opt::<f32, LINEAR_CAP>(
394 layout, profile, GAMMA_LUT, BIT_DEPTH,
395 )
396 }
397}
398
399impl RgbXyzFactoryOpt<f64> for f64 {
400 fn make_optimized_transform<
401 const LINEAR_CAP: usize,
402 const GAMMA_LUT: usize,
403 const BIT_DEPTH: usize,
404 >(
405 src_layout: Layout,
406 dst_layout: Layout,
407 profile: TransformMatrixShaperOptimized<f64, LINEAR_CAP>,
408 transform_options: TransformOptions,
409 ) -> Result<Arc<dyn TransformExecutor<f64> + Send + Sync>, CmsError> {
410 if transform_options.prefer_fixed_point {
411 #[cfg(all(target_arch = "aarch64", feature = "neon_shaper_fixed_point_paths"))]
412 {
413 if std::arch::is_aarch64_feature_detected!("rdm") {
414 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q1_30_opt;
415 return make_rgb_xyz_q1_30_opt::<f64, LINEAR_CAP, 30>(
416 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
417 );
418 }
419 }
420 }
421 make_rgb_xyz_rgb_transform_opt::<f64, LINEAR_CAP>(
422 src_layout, dst_layout, profile, GAMMA_LUT, BIT_DEPTH,
423 )
424 }
425
426 #[cfg(feature = "in_place")]
427 fn make_in_place_optimized_transform<
428 const LINEAR_CAP: usize,
429 const GAMMA_LUT: usize,
430 const BIT_DEPTH: usize,
431 >(
432 layout: Layout,
433 profile: TransformMatrixShaperOptimized<f64, LINEAR_CAP>,
434 _: TransformOptions,
435 ) -> Result<Arc<dyn InPlaceTransformExecutor<f64> + Send + Sync>, CmsError> {
436 use crate::conversions::rgbxyz::make_rgb_xyz_in_place_transform_opt;
437 make_rgb_xyz_in_place_transform_opt::<f64, LINEAR_CAP>(
438 layout, profile, GAMMA_LUT, BIT_DEPTH,
439 )
440 }
441}
442
443impl RgbXyzFactoryOpt<u8> for u8 {
444 fn make_optimized_transform<
445 const LINEAR_CAP: usize,
446 const GAMMA_LUT: usize,
447 const BIT_DEPTH: usize,
448 >(
449 src_layout: Layout,
450 dst_layout: Layout,
451 profile: TransformMatrixShaperOptimized<u8, LINEAR_CAP>,
452 transform_options: TransformOptions,
453 ) -> Result<Arc<dyn TransformExecutor<u8> + Send + Sync>, CmsError> {
454 if transform_options.prefer_fixed_point {
455 #[cfg(all(target_arch = "x86_64", feature = "avx512_shaper_fixed_point_paths"))]
456 {
457 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_avx512_opt;
458 if std::arch::is_x86_feature_detected!("avx512bw")
459 && std::arch::is_x86_feature_detected!("avx512vl")
460 {
461 return make_rgb_xyz_q2_13_transform_avx512_opt::<
462 u8,
463 LINEAR_CAP,
464 FIXED_POINT_SCALE,
465 >(src_layout, dst_layout, profile, GAMMA_LUT, 8);
466 }
467 }
468 #[cfg(all(target_arch = "x86_64", feature = "avx_shaper_fixed_point_paths"))]
469 {
470 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_avx2_opt;
471 if std::arch::is_x86_feature_detected!("avx2") {
472 return make_rgb_xyz_q2_13_transform_avx2_opt::<
473 u8,
474 LINEAR_CAP,
475 FIXED_POINT_SCALE,
476 >(src_layout, dst_layout, profile, GAMMA_LUT, 8);
477 }
478 }
479 #[cfg(all(
480 any(target_arch = "x86", target_arch = "x86_64"),
481 feature = "sse_shaper_fixed_point_paths"
482 ))]
483 {
484 use crate::conversions::rgbxyz_fixed::make_rgb_xyz_q2_13_transform_sse_41_opt;
485 if std::arch::is_x86_feature_detected!("sse4.1") {
486 return make_rgb_xyz_q2_13_transform_sse_41_opt::<
487 u8,
488 LINEAR_CAP,
489 FIXED_POINT_SCALE,
490 >(src_layout, dst_layout, profile, GAMMA_LUT, 8);
491 }
492 }
493 make_rgb_xyz_q2_13_opt::<u8, LINEAR_CAP, FIXED_POINT_SCALE>(
494 src_layout, dst_layout, profile, GAMMA_LUT, 8,
495 )
496 } else {
497 make_rgb_xyz_rgb_transform_opt::<u8, LINEAR_CAP>(
498 src_layout, dst_layout, profile, GAMMA_LUT, 8,
499 )
500 }
501 }
502
503 #[cfg(feature = "in_place")]
504 fn make_in_place_optimized_transform<
505 const LINEAR_CAP: usize,
506 const GAMMA_LUT: usize,
507 const BIT_DEPTH: usize,
508 >(
509 layout: Layout,
510 profile: TransformMatrixShaperOptimized<u8, LINEAR_CAP>,
511 transform_options: TransformOptions,
512 ) -> Result<Arc<dyn InPlaceTransformExecutor<u8> + Send + Sync>, CmsError> {
513 if transform_options.prefer_fixed_point {
514 #[cfg(all(
515 target_arch = "aarch64",
516 feature = "in_place",
517 feature = "neon_shaper_fixed_point_paths"
518 ))]
519 {
520 use crate::conversions::rgbxyz::make_rgb_xyz_in_place_transform_q2_13_opt;
521 return make_rgb_xyz_in_place_transform_q2_13_opt::<
522 u8,
523 LINEAR_CAP,
524 FIXED_POINT_SCALE,
525 >(layout, profile, GAMMA_LUT, 8);
526 }
527
528 #[cfg(all(
529 target_arch = "x86_64",
530 feature = "in_place",
531 feature = "avx_shaper_fixed_point_paths"
532 ))]
533 {
534 if std::arch::is_x86_feature_detected!("avx2") {
535 use crate::conversions::rgbxyz::make_avx_rgb_xyz_in_place_transform_q2_13_opt;
536 return make_avx_rgb_xyz_in_place_transform_q2_13_opt::<
537 u8,
538 LINEAR_CAP,
539 FIXED_POINT_SCALE,
540 >(layout, profile, GAMMA_LUT, 8);
541 }
542 }
543
544 #[cfg(all(
545 any(target_arch = "x86_64", target_arch = "x86"),
546 feature = "in_place",
547 feature = "sse_shaper_fixed_point_paths"
548 ))]
549 {
550 if std::arch::is_x86_feature_detected!("sse4.1") {
551 use crate::conversions::rgbxyz::make_sse_rgb_xyz_in_place_transform_q2_13_opt;
552 return make_sse_rgb_xyz_in_place_transform_q2_13_opt::<
553 u8,
554 LINEAR_CAP,
555 FIXED_POINT_SCALE,
556 >(layout, profile, GAMMA_LUT, 8);
557 }
558 }
559 }
560 use crate::conversions::rgbxyz::make_rgb_xyz_in_place_transform_opt;
561 make_rgb_xyz_in_place_transform_opt::<u8, LINEAR_CAP>(layout, profile, GAMMA_LUT, 8)
562 }
563}