Skip to main content

strat9_kernel/framebuffer/x86/
mod.rs

1//! SIMD pixel operations for x86_64.
2//!
3//! Currently exposes the SSE2 (+SSSE3 convert) implementations only.
4//!
5//! AVX2/AVX512 variants are TEMPORARILY removed: nightly
6//! `1.100.0-nightly (c656540d, LLVM 23.1-rust)` mis-compiles the custom
7//! `x86_64-unknown-none` target by emitting `+soft-float` into every
8//! function's target-features, which makes X86 instruction selection abort
9//! on 256-bit intrinsics (`llvm.x86.avx2.pshuf.b`) with:
10//!   "Do not know how to split the result of this operator!"
11//! Restore `avx2`/`avx512` once the toolchain issue is resolved. The
12//! streaming-store paths are disabled too; cached SSE2 remains available.
13
14use crate::framebuffer::{generic, FramebufferOps};
15pub mod sse2;
16
17pub fn detect_and_init_ops() -> FramebufferOps {
18    let cpuid = raw_cpuid::CpuId::new();
19
20    let has_sse41 = cpuid
21        .get_feature_info()
22        .map_or(false, |info| info.has_sse41());
23
24    let has_ssse3 = cpuid
25        .get_feature_info()
26        .map_or(false, |info| info.has_ssse3());
27
28    let has_sse2 = cpuid
29        .get_feature_info()
30        .map_or(false, |info| info.has_sse2());
31
32    if has_sse41 || has_sse2 {
33        // convert_bgr_to_argb requires SSSE3 (pshufb). Without it, use the scalar path.
34        let convert: crate::framebuffer::FnConvert = if has_ssse3 {
35            sse2::convert_bgr_to_argb_sse2
36        } else {
37            generic::convert_bgr_to_argb_generic
38        };
39        FramebufferOps {
40            fill: sse2::fill_sse2,
41            blit: sse2::blit_sse2,
42            blend: sse2::blend_sse2,
43            convert,
44        }
45    } else {
46        FramebufferOps {
47            fill: generic::fill_generic,
48            blit: generic::blit_generic,
49            blend: generic::blend_generic,
50            convert: generic::convert_bgr_to_argb_generic,
51        }
52    }
53}