|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2024 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ビットマップ (AVX2)
9: //
10:
11: #include "bitmap.h"
12: #include <x86intrin.h>
13:
14: // I8 から RGBX への変換。
15: void
16: BitmapRGBX::CopyLineI8_avx2(uint32 *d32, const uint8 *s8, uint width,
17: const Color *palette)
18: {
19: uint packed = width & ~7;
20:
21: const uint8 *s8total = s8 + width;
22: const uint8 *s8packed = s8 + packed;
23:
24: for (; s8 < s8packed; ) {
25: // 8ピクセルずつ処理する
26:
27: // s8 は BitmapI8 なのでビッグエンディアン並びに相当。
28: // idx0 = $00000000'00000000'I7I6I5I4'I3I2I1I0
29: __m128i idx0 = _mm_loadl_epi64((const __m128i *)s8);
30: s8 += 8;
31:
32: // idx = $000000I7'000000I6'000000I5'000000I4'
33: // 000000I3'000000I2'000000I1'000000I0
34: __m256i idx = _mm256_cvtepu8_epi32(idx0);
35:
36: // 8個の 32bit インデックスから XBGR を取得
37: // c = $00B7G7R7'00B6G6R6'00B5G5R5'00B4G4R4'
38: // 00B3G3R3'00B2G2R2'00B1G1R1'00B0G0R0
39: __m256i c = _mm256_i32gather_epi32((const int *)palette, idx, 4);
40:
41: _mm256_storeu_si256((__m256i *)d32, c);
42: d32 += 8;
43: }
44:
45: // 残りは通常通り処理
46: if (s8 < s8total) {
47: CopyLineI8_gen(d32, s8, (width - packed), palette);
48: }
49: }
50:
51: // RGBX から RGB への変換。
52: void
53: BitmapRGBX::ConvertToRGB_avx2(BitmapRGB& dst) const
54: {
55: const BitmapRGBX& src = *this;
56:
57: // 256bit リニアに使えれば下詰めで済んだんだが、上位 128bit と
58: // 下位 128bit をまたいでシャッフルは出来なくて、かつこの後のストアは
59: // 連続領域への書き込みになるので、中央でつなげておく。うーん。
60: const __m256i shuff = _mm256_set_epi8(
61: -1,-1,-1,-1, 14,13,12,10, 9, 8, 6, 5, 4, 2, 1, 0,
62: 14,13,12,10, 9, 8, 6, 5, 4, 2, 1, 0, -1,-1,-1,-1
63: );
64: const __m256i mask = _mm256_set_epi32(0, -1, -1, -1, -1, -1, -1, 0);
65:
66: // この変換は一次元配列とみなしても行える。
67: // モニタ等のパネルでも呼ばれるので何ピクセルで割り切れるかの前提は不可。
68: uint total = GetWidth() * GetHeight();
69: uint packed = total & ~7;
70:
71: const uint32 *s32 = (const uint32 *)src.GetRowPtr(0);
72: const uint32 *s32total = s32 + total;
73: const uint32 *s32packed = s32 + packed;
74:
75: uint32 *d32 = (uint32 *)dst.GetRowPtr(0);
76: for (; s32 < s32packed; ) {
77: // 8ピクセルずつ処理する
78:
79: // c = $x7B7G7R7'x6B6G6R6'x5B5G5R5'x4B4G4R4'
80: // x3B3G3R3'x2B2G2R2'x1B1G1R1'x0B0G0R0
81: __m256i c = _mm256_load_si256((const __m256i *)s32);
82: s32 += 8;
83:
84: // res= $00000000'B7G7R7B6'G6R6B5G5'R5B4G4R4'
85: // B3G3R3B2'G2R2B1G1'R1B0G0R0'00000000
86: __m256i res = _mm256_shuffle_epi8(c, shuff);
87:
88: // 先頭(下位)と末尾(上位)の 32bit ずつを除いたところを書き出す。
89: _mm256_maskstore_epi32((int *)(d32 - 1), mask, res);
90: d32 += 6;
91: }
92:
93: uint8 *d8 = (uint8 *)d32;
94: for (; s32 < s32total; ) {
95: // 残りを1ピクセルずつ処理する
96: Color c(*s32++);
97: *d8++ = c.r;
98: *d8++ = c.g;
99: *d8++ = c.b;
100: }
101: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.