--- nono/vm/accel_avx2.cpp 2026/04/29 17:05:25 1.1 +++ nono/vm/accel_avx2.cpp 2026/04/29 17:05:50 1.1.1.3 @@ -9,8 +9,6 @@ // #include "accel_avx2.h" -#include "planevram.h" -#include "renderer.h" #include "videoctlr.h" #include @@ -71,107 +69,26 @@ DetectAVX2() return false; } -// I8 から RGBX への変換。 -void -PlaneVRAMDevice::RenderI8toRGBX_avx2(BitmapRGBX& dst, const BitmapI8& view, - const std::vector& view_mod) -{ - for (int y = 0; y < view_mod.size(); y++) { - if (view_mod[y] == 0) { - continue; - } - - const uint8 *s8 = view.GetRowPtr(y); - uint32 *d = (uint32 *)dst.GetRowPtr(y); - - const uint32 *s = (const uint32 *)s8; - const uint32 *send = (const uint32 *)(s8 + view.GetWidth()); - for (; s < send;) { - // 8ピクセルずつ処理する - - // s は BitmapI8 なのでビッグエンディアン並びに相当。 - // idx0 = $00000000'00000000'I7I6I5I4'I3I2I1I0 - __m128i idx0 = _mm_loadl_epi64((const __m128i *)s); - s += 2; - - // idx = $000000I7'000000I6'000000I5'000000I4' - // 000000I3'000000I2'000000I1'000000I0 - __m256i idx = _mm256_cvtepu8_epi32(idx0); - - // 8個の 32bit インデックスから XBGR を取得 - // c = $00B7G7R7'00B6G6R6'00B5G5R5'00B4G4R4' - // 00B3G3R3'00B2G2R2'00B1G1R1'00B0G0R0 - __m256i c = _mm256_i32gather_epi32( - (const int *)palette, idx, 4); - - _mm256_storeu_si256((__m256i *)d, c); - d += 8; - } - } -} - -// RGBX から RGB への変換。 -/*static*/ void -Renderer::RGBXtoRGB_avx2(BitmapRGB& dst, const BitmapRGBX& src) -{ - for (int y = 0, yend = src.GetHeight(); y < yend; y++) { - const uint32 *s = (const uint32 *)src.GetRowPtr(y); - uint32 *d = (uint32 *)dst.GetRowPtr(y); - - const uint32 *send = s + src.GetWidth(); - for (; s < send; ) { - // 8ピクセルずつ処理する - - // c = $x7B7G7R7'x6B6G6R6'x5B5G5R5'x4B4G4R4' - // x3B3G3R3'x2B2G2R2'x1B1G1R1'x0B0G0R0 - __m256i c = _mm256_loadu_si256((const __m256i *)s); - s += 8; - - // 256bit リニアに使えれば下詰めで済んだんだが、 - // 上位 128bit と下位 128bit をまたいでシャッフルは - // 出来なくて、かつこの後のストアは連続領域への - // 書き込みになるので、中央でつなげておく。うーん。 - // c = $00000000'B7G7R7B6'G6R6B5G5'R5B4G4R4' - // B3G3R3B2'G2R2B1G1'R1B0G0R0'00000000 - __m256i shuff = _mm256_set_epi8( - -1,-1,-1,-1, 14,13,12,10, 9, 8, 6, 5, 4, 2, 1, 0, - 14,13,12,10, 9, 8, 6, 5, 4, 2, 1, 0, -1,-1,-1,-1 - ); - __m256i res = _mm256_shuffle_epi8(c, shuff); - - // 先頭(下位)と末尾(上位)の 32bit ずつを除いたところを - // 書き出す。 - __m256i mask = _mm256_set_epi32( - 0, -1, -1, -1, -1, -1, -1, 0 - ); - _mm256_maskstore_epi32((int *)(d - 1), mask, res); - d += 6; - } - } -} - -// コントラスト (0-254) を適用。 +// コントラスト (1-254) を適用。dst サイズでクリップする。 +// (ちなみに _gen は 409 usec) /*static*/ void VideoCtlrDevice::RenderContrast_avx2(BitmapRGBX& dst, const BitmapRGBX& src, uint32 contrast) { -#define USE_NEW - -#if defined(USE_NEW) // 8ビットのまま、筆算の掛け算と固定小数点の要領で、 // ビットが立っている桁だけ右シフトしたものを足していく。 // 例えば $b7(%1011'0111) を %1001'0000/256 (= 0.562) 倍する場合、 // 除数の - // b7=%1 なので $b7 >> 1 = %0101'1011 - // b4=%1 なので $b7 >> 4 = %0000'1011 - // : + - // ---------- - // 結果は %0110'0110 (= $66) + // bit7=%1 なので $b7 >> 1 = %0101'1011 + // bit4=%1 なので $b7 >> 4 = %0000'1011 + // + + // ---------- + // 結果は %0110'0110 (= $66) // // 立っているビット数が増えると演算回数で不利になるので、5 ビット // 以上立っている場合は被除数を反転して計算して元の値から引く。 - int n = contrast == 0 ? 0 : __builtin_popcount(contrast); bool use_sub; + uint n = __builtin_popcount(contrast); if (n <= 4) { use_sub = false; } else { @@ -188,87 +105,49 @@ VideoCtlrDevice::RenderContrast_avx2(Bit n++; } } -#else - const __m256i vcontrast = _mm256_set1_epi16(contrast); - const __m256i idxh = _mm256_set_epi32(-1, -1, -1, -1, 7, 6, 3, 2); - const __m256i idxl = _mm256_set_epi32(-1, -1, -1, -1, 5, 4, 1, 0); -#endif - - for (int y = 0, yend = src.GetHeight(); y < yend; y++) { - const uint32 *s = (const uint32 *)src.GetRowPtr(y); - uint32 *d = (uint32 *)dst.GetRowPtr(y); - - const uint32 *send = s + src.GetWidth(); - for (; s < send; ) { - // 8ピクセルずつ処理する - - __m256i a = _mm256_loadu_si256((const __m256i *)s); - s += 8; -#if defined(USE_NEW) - // 144 usec + + // 今のところ幅は 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; - if (__predict_false(n == 0)) { - r = _mm256_setzero_si256(); - } else { - // 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); - } + // 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); } -#else - // 146 usec - - // a = $x7B7G7R7'x6B6G6R6'x5B5G5R5'x4B4G4R4' - // x3B3G3R3'x2B2G2R2'x1B1G1R1'x0B0G0R0 - // 上位 128bit を下位 128bit に持っていく必要がどうせあるし、 - // 最後に packus 一発で元に戻せる位置に permute する。 - // ah = $...'x7B7G7R7'x6B6G6R6'x3B3G3R3'x2B2G2R2 - // al = $...'x5B5G5R5'x4B4G4R4'x1B1G1R1'x0B0G0R0 - __m256i ah = _mm256_permutevar8x32_epi32(a, idxh); - __m256i al = _mm256_permutevar8x32_epi32(a, idxl); - - // bh = $00x700B7'00G700R7'00x600B6'00G600R6' - // 00x300B3'00G300R3'00x200B2'00G200R2 - // bl = $00x500B5'00G500R5'00x400B4'00G400R4' - // 00x100B1'00G100R1'00x000B0'00G000R0 - __m256i bh = _mm256_cvtepu8_epi16(_mm256_castsi256_si128(ah)); - __m256i bl = _mm256_cvtepu8_epi16(_mm256_castsi256_si128(al)); - - __m256i ch = _mm256_mullo_epi16(bh, vcontrast); - __m256i cl = _mm256_mullo_epi16(bl, vcontrast); - - __m256i sh = _mm256_srli_epi16(ch, 8); - __m256i sl = _mm256_srli_epi16(cl, 8); - - // r = $x7B7G7R7'x6B6G6R6'x5B5G5R5'x4B4G4R4' - // x3B3G3R3'x2B2G2R2'x1B1G1R1'x0B0G0R0 - __m256i r = _mm256_packus_epi16(sl, sh); -#endif - _mm256_storeu_si256((__m256i *)d, r); - d += 8; + _mm256_store_si256((__m256i *)d32, r); + d32 += 8; } } }