Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Simd/src/Simd/SimdAvx2BgrToHsv.cpp
Line
Count
Source
1
/*
2
* Simd Library (http://ermig1979.github.io/Simd).
3
*
4
* Copyright (c) 2011-2026 Yermalayeu Ihar.
5
*
6
* Permission is hereby granted, free of charge, to any person obtaining a copy
7
* of this software and associated documentation files (the "Software"), to deal
8
* in the Software without restriction, including without limitation the rights
9
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
* copies of the Software, and to permit persons to whom the Software is
11
* furnished to do so, subject to the following conditions:
12
*
13
* The above copyright notice and this permission notice shall be included in
14
* all copies or substantial portions of the Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
#include "Simd/SimdMemory.h"
25
#include "Simd/SimdStore.h"
26
#include "Simd/SimdConversion.h"
27
#include "Simd/SimdInterleave.h"
28
29
namespace Simd
30
{
31
#ifdef SIMD_AVX2_ENABLE
32
    namespace Avx2
33
    {
34
        SIMD_INLINE __m256i MulDiv32Hsv(__m256i dividend, __m256i divisor, const __m256& scale)
35
0
        {
36
0
            return _mm256_cvttps_epi32(_mm256_div_ps(_mm256_mul_ps(scale, _mm256_cvtepi32_ps(dividend)), _mm256_cvtepi32_ps(divisor)));
37
0
        }
38
39
        SIMD_INLINE __m256i MulDiv16Hsv(__m256i dividend, __m256i divisor, const __m256& scale)
40
0
        {
41
0
            const __m256i lo = MulDiv32Hsv(_mm256_unpacklo_epi16(dividend, K_ZERO), _mm256_unpacklo_epi16(divisor, K_ZERO), scale);
42
0
            const __m256i hi = MulDiv32Hsv(_mm256_unpackhi_epi16(dividend, K_ZERO), _mm256_unpackhi_epi16(divisor, K_ZERO), scale);
43
0
            return _mm256_packs_epi32(lo, hi);
44
0
        }
45
46
        SIMD_INLINE void BgrToHsv16(__m256i blue, __m256i green, __m256i red,
47
            __m256i& hue, __m256i& sat, __m256i& val,
48
            const __m256& KF_255_DIV_6, const __m256& K_255F)
49
0
        {
50
0
            __m256i max = MaxI16(red, green, blue);
51
0
            __m256i min = MinI16(red, green, blue);
52
0
            __m256i range = _mm256_sub_epi16(max, min);
53
54
            // Hue: determine which channel is the maximum
55
0
            __m256i redMaxMask = _mm256_cmpeq_epi16(red, max);
56
0
            __m256i greenMaxMask = _mm256_andnot_si256(redMaxMask, _mm256_cmpeq_epi16(green, max));
57
0
            __m256i blueMaxMask = _mm256_andnot_si256(_mm256_or_si256(redMaxMask, greenMaxMask), K_INV_ZERO);
58
59
0
            __m256i hueDividend = _mm256_or_si256(
60
0
                _mm256_and_si256(redMaxMask,
61
0
                    _mm256_add_epi16(_mm256_sub_epi16(green, blue), _mm256_mullo_epi16(range, K16_0006))),
62
0
                _mm256_or_si256(
63
0
                    _mm256_and_si256(greenMaxMask,
64
0
                        _mm256_add_epi16(_mm256_sub_epi16(blue, red), _mm256_mullo_epi16(range, K16_0002))),
65
0
                    _mm256_and_si256(blueMaxMask,
66
0
                        _mm256_add_epi16(_mm256_sub_epi16(red, green), _mm256_mullo_epi16(range, K16_0004)))));
67
68
0
            __m256i safeRange = _mm256_max_epi16(range, K16_0001);
69
0
            hue = _mm256_andnot_si256(_mm256_cmpeq_epi16(range, K_ZERO),
70
0
                _mm256_and_si256(MulDiv16Hsv(hueDividend, safeRange, KF_255_DIV_6), K16_00FF));
71
72
            // Value: V = max
73
0
            val = max;
74
75
            // Saturation: S = 255 * range / max, zero when max == 0
76
0
            __m256i safeMax = _mm256_max_epi16(max, K16_0001);
77
0
            sat = _mm256_andnot_si256(_mm256_cmpeq_epi16(max, K_ZERO),
78
0
                MulDiv16Hsv(range, safeMax, K_255F));
79
0
        }
80
81
        template <bool align> SIMD_INLINE void BgrToHsv32(const uint8_t* bgr, uint8_t* hsv,
82
            const __m256& KF_255_DIV_6, const __m256& K_255F)
83
0
        {
84
0
            __m256i bgr_data[3];
85
0
            bgr_data[0] = Load<align>((__m256i*)bgr + 0);
86
0
            bgr_data[1] = Load<align>((__m256i*)bgr + 1);
87
0
            bgr_data[2] = Load<align>((__m256i*)bgr + 2);
88
89
0
            __m256i blue8 = BgrToBlue(bgr_data);
90
0
            __m256i green8 = BgrToGreen(bgr_data);
91
0
            __m256i red8 = BgrToRed(bgr_data);
92
93
0
            __m256i blue_lo = _mm256_unpacklo_epi8(blue8, K_ZERO);
94
0
            __m256i blue_hi = _mm256_unpackhi_epi8(blue8, K_ZERO);
95
0
            __m256i green_lo = _mm256_unpacklo_epi8(green8, K_ZERO);
96
0
            __m256i green_hi = _mm256_unpackhi_epi8(green8, K_ZERO);
97
0
            __m256i red_lo = _mm256_unpacklo_epi8(red8, K_ZERO);
98
0
            __m256i red_hi = _mm256_unpackhi_epi8(red8, K_ZERO);
99
100
0
            __m256i hue_lo, sat_lo, val_lo, hue_hi, sat_hi, val_hi;
101
0
            BgrToHsv16(blue_lo, green_lo, red_lo, hue_lo, sat_lo, val_lo, KF_255_DIV_6, K_255F);
102
0
            BgrToHsv16(blue_hi, green_hi, red_hi, hue_hi, sat_hi, val_hi, KF_255_DIV_6, K_255F);
103
104
0
            __m256i hue8 = _mm256_packus_epi16(hue_lo, hue_hi);
105
0
            __m256i sat8 = _mm256_packus_epi16(sat_lo, sat_hi);
106
0
            __m256i val8 = _mm256_packus_epi16(val_lo, val_hi);
107
108
0
            Store<align>((__m256i*)hsv + 0, InterleaveBgr<0>(hue8, sat8, val8));
109
0
            Store<align>((__m256i*)hsv + 1, InterleaveBgr<1>(hue8, sat8, val8));
110
0
            Store<align>((__m256i*)hsv + 2, InterleaveBgr<2>(hue8, sat8, val8));
111
0
        }
Unexecuted instantiation: void Simd::Avx2::BgrToHsv32<true>(unsigned char const*, unsigned char*, float __vector(8) const&, float __vector(8) const&)
Unexecuted instantiation: void Simd::Avx2::BgrToHsv32<false>(unsigned char const*, unsigned char*, float __vector(8) const&, float __vector(8) const&)
112
113
        template <bool align> void BgrToHsv(const uint8_t* bgr, size_t width, size_t height, size_t bgrStride, uint8_t* hsv, size_t hsvStride)
114
0
        {
115
0
            assert(width >= A);
116
0
            if (align)
117
0
                assert(Aligned(bgr) && Aligned(bgrStride) && Aligned(hsv) && Aligned(hsvStride));
118
119
0
            size_t alignedWidth = AlignLo(width, A);
120
0
            const __m256 KF = _mm256_set1_ps(Base::KF_255_DIV_6);
121
0
            const __m256 K255 = _mm256_set1_ps(255.0f);
122
123
0
            for (size_t row = 0; row < height; ++row)
124
0
            {
125
0
                for (size_t col = 0; col < alignedWidth; col += A)
126
0
                    BgrToHsv32<align>(bgr + 3 * col, hsv + 3 * col, KF, K255);
127
0
                if (width != alignedWidth)
128
0
                    BgrToHsv32<false>(bgr + 3 * (width - A), hsv + 3 * (width - A), KF, K255);
129
0
                bgr += bgrStride;
130
0
                hsv += hsvStride;
131
0
            }
132
0
        }
Unexecuted instantiation: void Simd::Avx2::BgrToHsv<true>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned char*, unsigned long)
Unexecuted instantiation: void Simd::Avx2::BgrToHsv<false>(unsigned char const*, unsigned long, unsigned long, unsigned long, unsigned char*, unsigned long)
133
134
        void BgrToHsv(const uint8_t* bgr, size_t width, size_t height, size_t bgrStride, uint8_t* hsv, size_t hsvStride)
135
0
        {
136
0
            if (Aligned(bgr) && Aligned(bgrStride) && Aligned(hsv) && Aligned(hsvStride))
137
0
                BgrToHsv<true>(bgr, width, height, bgrStride, hsv, hsvStride);
138
0
            else
139
0
                BgrToHsv<false>(bgr, width, height, bgrStride, hsv, hsvStride);
140
0
        }
141
    }
142
#endif
143
}