--- nono/vm/accel_avx2.cpp 2026/04/29 17:05:29 1.1.1.2 +++ nono/vm/accel_avx2.cpp 2026/04/29 17:05:50 1.1.1.3 @@ -69,28 +69,12 @@ DetectAVX2() return false; } -// コントラスト (0-254) を適用。 +// コントラスト (1-254) を適用。dst サイズでクリップする。 // (ちなみに _gen は 409 usec) /*static*/ void VideoCtlrDevice::RenderContrast_avx2(BitmapRGBX& dst, const BitmapRGBX& src, uint32 contrast) { - // この変換は一次元配列とみなしても行える。 - // また必ずテキスト画面全域なので端数の考慮は不要。 - uint pxlen = src.GetWidth() * src.GetHeight(); - const uint32 *s32 = (const uint32 *)src.GetRowPtr(0); - uint32 *d32 = (uint32 *)dst.GetRowPtr(0); - uint32 *d32end = d32 + pxlen; - - if (__predict_false(contrast == 0)) { - __m256i zero = _mm256_setzero_si256(); - for (; d32 < d32end; ) { - _mm256_store_si256((__m256i *)d32, zero); - d32 += 8; - } - return; - } - // 8ビットのまま、筆算の掛け算と固定小数点の要領で、 // ビットが立っている桁だけ右シフトしたものを足していく。 // 例えば $b7(%1011'0111) を %1001'0000/256 (= 0.562) 倍する場合、 @@ -122,41 +106,48 @@ VideoCtlrDevice::RenderContrast_avx2(Bit } } - for (; d32 < d32end; ) { - // 8ピクセルずつ処理する - // 101 usec - - __m256i a = _mm256_load_si256((const __m256i *)s32); - s32 += 8; - - __m256i r; - // AVX には 8 ビットのシフト演算がないので、16 ビット - // 単位で右シフトして、右にはみ出た分をマスクする…。 - auto b0 = _mm256_srli_epi16(a, shift_count[0]); - r = _mm256_and_si256(b0, shift_mask[0]); - - if (n >= 2) { - auto b1 = _mm256_srli_epi16(a, shift_count[1]); - auto c1 = _mm256_and_si256(b1, shift_mask[1]); - r = _mm256_add_epi8(r, c1); - - if (n >= 3) { - auto b2 = _mm256_srli_epi16(a, shift_count[2]); - auto c2 = _mm256_and_si256(b2, shift_mask[2]); - r = _mm256_add_epi8(r, c2); - - if (n >= 4) { - auto b3 = _mm256_srli_epi16(a, shift_count[3]); - auto c3 = _mm256_and_si256(b3, shift_mask[3]); - r = _mm256_add_epi8(r, c3); + // 今のところ幅は 8ピクセルで割り切れる。 + uint width = dst.GetWidth(); + for (uint y = 0, yend = dst.GetHeight(); y < yend; y++) { + const uint32 *s32 = (const uint32 *)src.GetRowPtr(y); + uint32 *d32 = (uint32 *)dst.GetRowPtr(y); + uint32 *d32end = d32 + width; + for (; d32 < d32end; ) { + // 8ピクセルずつ処理する。 + // 101 usec + + __m256i a = _mm256_load_si256((const __m256i *)s32); + s32 += 8; + + __m256i r; + // AVX には 8 ビットのシフト演算がないので、16 ビット + // 単位で右シフトして、右にはみ出た分をマスクする…。 + auto b0 = _mm256_srli_epi16(a, shift_count[0]); + r = _mm256_and_si256(b0, shift_mask[0]); + + if (n >= 2) { + auto b1 = _mm256_srli_epi16(a, shift_count[1]); + auto c1 = _mm256_and_si256(b1, shift_mask[1]); + r = _mm256_add_epi8(r, c1); + + if (n >= 3) { + auto b2 = _mm256_srli_epi16(a, shift_count[2]); + auto c2 = _mm256_and_si256(b2, shift_mask[2]); + r = _mm256_add_epi8(r, c2); + + if (n >= 4) { + auto b3 = _mm256_srli_epi16(a, shift_count[3]); + auto c3 = _mm256_and_si256(b3, shift_mask[3]); + r = _mm256_add_epi8(r, c3); + } } } - } - if (use_sub) { - r = _mm256_sub_epi8(a, r); - } + if (use_sub) { + r = _mm256_sub_epi8(a, r); + } - _mm256_store_si256((__m256i *)d32, r); - d32 += 8; + _mm256_store_si256((__m256i *)d32, r); + d32 += 8; + } } }