Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-or-later
3 : *
4 : * This file is part of colopresso
5 : *
6 : * Copyright (C) 2025-2026 COLOPL, Inc.
7 : *
8 : * Author: Go Kudo <g-kudo@colopl.co.jp>
9 : * Developed with AI (LLM) code assistance. See `NOTICE` for details.
10 : */
11 :
12 : #include "internal/simd.h"
13 :
14 : #if defined(CPRES_SIMD_SSE41) || defined(CPRES_SIMD_SSE2)
15 :
16 47677831 : static inline uint32_t color_distance_sq_sse(uint32_t lhs, uint32_t rhs)
17 : {
18 143033493 : __m128i a = _mm_cvtsi32_si128((int)lhs), b = _mm_cvtsi32_si128((int)rhs), a16, b16, diff,
19 : diff_sq;
20 : int result;
21 :
22 95355662 : a16 = _mm_unpacklo_epi8(a, _mm_setzero_si128());
23 95355662 : b16 = _mm_unpacklo_epi8(b, _mm_setzero_si128());
24 :
25 47677831 : diff = _mm_sub_epi16(a16, b16);
26 :
27 47677831 : diff_sq = _mm_madd_epi16(diff, diff);
28 :
29 47677831 : diff_sq = _mm_add_epi32(diff_sq, _mm_srli_si128(diff_sq, 8));
30 95355662 : diff_sq = _mm_add_epi32(diff_sq, _mm_srli_si128(diff_sq, 4));
31 :
32 47677831 : result = _mm_cvtsi128_si32(diff_sq);
33 :
34 47677831 : return (uint32_t)result;
35 : }
36 :
37 : #elif defined(CPRES_SIMD_NEON)
38 :
39 : static inline uint32_t color_distance_sq_neon(uint32_t lhs, uint32_t rhs)
40 : {
41 : uint8x8_t a = vreinterpret_u8_u32(vdup_n_u32(lhs)), b = vreinterpret_u8_u32(vdup_n_u32(rhs));
42 : int16x4_t a16 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(a))),
43 : b16 = vreinterpret_s16_u16(vget_low_u16(vmovl_u8(b))), diff = vsub_s16(a16, b16);
44 : int32x4_t diff_sq = vmull_s16(diff, diff);
45 : int32_t result = vgetq_lane_s32(diff_sq, 0) + vgetq_lane_s32(diff_sq, 1) +
46 : vgetq_lane_s32(diff_sq, 2) + vgetq_lane_s32(diff_sq, 3);
47 :
48 : return (uint32_t)result;
49 : }
50 :
51 : #elif defined(CPRES_SIMD_WASM128)
52 :
53 : static inline uint32_t color_distance_sq_wasm(uint32_t lhs, uint32_t rhs)
54 : {
55 : v128_t a = wasm_i32x4_splat((int32_t)lhs), b = wasm_i32x4_splat((int32_t)rhs),
56 : a16 = wasm_u16x8_extend_low_u8x16(a), b16 = wasm_u16x8_extend_low_u8x16(b),
57 : diff = wasm_i16x8_sub(a16, b16), diff_sq = wasm_i32x4_extmul_low_i16x8(diff, diff);
58 : int32_t result = wasm_i32x4_extract_lane(diff_sq, 0) + wasm_i32x4_extract_lane(diff_sq, 1) +
59 : wasm_i32x4_extract_lane(diff_sq, 2) + wasm_i32x4_extract_lane(diff_sq, 3);
60 :
61 : return (uint32_t)result;
62 : }
63 :
64 : #else
65 :
66 : static inline uint32_t color_distance_sq_scalar(uint32_t lhs, uint32_t rhs)
67 : {
68 : int32_t r1 = (int32_t)(lhs & 0xFF), g1 = (int32_t)((lhs >> 8) & 0xFF),
69 : b1 = (int32_t)((lhs >> 16) & 0xFF), a1 = (int32_t)((lhs >> 24) & 0xFF),
70 : r2 = (int32_t)(rhs & 0xFF), g2 = (int32_t)((rhs >> 8) & 0xFF),
71 : b2 = (int32_t)((rhs >> 16) & 0xFF), a2 = (int32_t)((rhs >> 24) & 0xFF), dr = r1 - r2,
72 : dg = g1 - g2, db = b1 - b2, da = a1 - a2;
73 :
74 : return (uint32_t)(dr * dr + dg * dg + db * db + da * da);
75 : }
76 :
77 : #endif
78 :
79 47677831 : extern uint32_t simd_color_distance_sq_u32(uint32_t lhs, uint32_t rhs)
80 : {
81 : #if defined(CPRES_SIMD_WASM128)
82 : return color_distance_sq_wasm(lhs, rhs);
83 : #elif defined(CPRES_SIMD_SSE41) || defined(CPRES_SIMD_SSE2)
84 47677831 : return color_distance_sq_sse(lhs, rhs);
85 : #elif defined(CPRES_SIMD_NEON)
86 : return color_distance_sq_neon(lhs, rhs);
87 : #else
88 : return color_distance_sq_scalar(lhs, rhs);
89 : #endif
90 : }
|