retro_pixel/
u16_ext.rs

1//! Module for code specific to `u16` base images.
2//!
3//! The channel order of the pixel value processing functions here is assumed to
4//! be `A1_B5_G5_R5`, which matches up with OpenGL's
5//! `GL_UNSIGNED_SHORT_1_5_5_5_REV` pixel type.
6//!
7//! In the future, I will attempt to make this able to unpack, use, and repack
8//! other color channel orderings.
9
10#![cfg(target_endian = "little")]
11#![allow(dead_code)]
12#![allow(unused_macros)]
13
14use super::*;
15
16/// This allows `u16` specific extensions to the `WritableImage` concepts.
17pub trait WritableImageU16Ext: WritableImage<u16> {
18  /// This copies the data from the source into the destination any time the
19  /// source's alpha bit is set.
20  ///
21  /// Currently this is the same as a call to `blit_generic`, but in future
22  /// versions this will attempt to take advantage of SIMD for a speed boost.
23  fn blit_rgba16<RI>(&mut self, src: &RI, offset: (isize, isize))
24  where
25    RI: ReadableImage<u16>,
26  {
27    // /*
28    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
29    {
30      // We're on x86 or x86_64, so we'll use explicit SIMD versions as
31      // appropriate, because the compiler just isn't smart enough to unroll it
32      // by hand.
33      #[cfg(feature = "std")]
34      {
35        if is_x86_feature_detected!("avx2") {
36          unsafe { blit_rgb16_avx2_explicit(self, src, offset) };
37        } else if is_x86_feature_detected!("sse2") {
38          unsafe { blit_rgb16_sse2_explicit(self, src, offset) };
39        } else {
40          // holy cripes how old is your CPU? these were added to x86 in 2001!
41          unsafe { blit_rgb16_fully_unrolled_no_intrinsics(self, src, offset) };
42        }
43      }
44      #[cfg(all(not(feature = "std"), target_feature = "avx2"))]
45      {
46        unsafe { blit_rgb16_avx2_explicit(self, src, offset) };
47      }
48      #[cfg(all(not(feature = "std"), not(target_feature = "avx2"), target_feature = "sse2"))]
49      {
50        unsafe { blit_rgb16_sse2_explicit(self, src, offset) };
51      }
52      #[cfg(all(not(feature = "std"), not(target_feature = "avx2"), not(target_feature = "sse2")))]
53      {
54        unsafe { blit_rgb16_fully_unrolled_no_intrinsics(self, src, offset) };
55      }
56    }
57    // */
58    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
59    {
60      // We're NOT on x86 or x86_64, so we just do it using a fully unrolled
61      // loop, which is faster than using blit_generic at least.
62      unsafe { blit_blend_rectilinear_fully_unrolled_no_intrinsics(self, src, offset) };
63    }
64  }
65}
66
67unsafe fn blit_rgb16_fully_unrolled_no_intrinsics<WI, RI>(dest: &mut WI, src: &RI, offset: (isize, isize))
68where
69  WI: WritableImage<u16> + ?Sized,
70  RI: ReadableImage<u16>,
71{
72  dest.blit_generic(src, offset, |src, dest| if (src as i16) < 0 { src } else { dest });
73}
74
75#[target_feature(enable = "sse2")]
76#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
77unsafe fn blit_rgb16_sse2_explicit<WI, RI>(dest: &mut WI, src: &RI, offset: (isize, isize))
78where
79  WI: WritableImage<u16> + ?Sized,
80  RI: ReadableImage<u16>,
81{
82  // TODO: use sse2 for the gba blit
83  dest.blit_generic(src, offset, |src, dest| if (src as i16) < 0 { src } else { dest });
84}
85
86#[target_feature(enable = "avx2")]
87#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
88unsafe fn blit_rgb16_avx2_explicit<WI, RI>(dest: &mut WI, src: &RI, offset: (isize, isize))
89where
90  WI: WritableImage<u16> + ?Sized,
91  RI: ReadableImage<u16>,
92{
93  // TODO: use avx2 for the gba blit
94  dest.blit_generic(src, offset, |src, dest| if (src as i16) < 0 { src } else { dest });
95}