|
|
nono 1.0.0
//
// nono
// Copyright (C) 2024 nono project
// Licensed under nono-license.txt
//
//
// ビットマップ (AVX2)
//
#include "bitmap.h"
#include <x86intrin.h>
// I8 から RGBX への変換。
void
BitmapRGBX::CopyLineI8_avx2(uint32 *d32, const uint8 *s8, uint width,
const Color *palette)
{
uint packed = width & ~7;
const uint8 *s8total = s8 + width;
const uint8 *s8packed = s8 + packed;
for (; s8 < s8packed; ) {
// 8ピクセルずつ処理する
// s8 は BitmapI8 なのでビッグエンディアン並びに相当。
// idx0 = $00000000'00000000'I7I6I5I4'I3I2I1I0
__m128i idx0 = _mm_loadl_epi64((const __m128i *)s8);
s8 += 8;
// 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 *)d32, c);
d32 += 8;
}
// 残りは通常通り処理
if (s8 < s8total) {
CopyLineI8_gen(d32, s8, (width - packed), palette);
}
}
// RGBX から RGB への変換。
void
BitmapRGBX::ConvertToRGB_avx2(BitmapRGB& dst) const
{
const BitmapRGBX& src = *this;
// 256bit リニアに使えれば下詰めで済んだんだが、上位 128bit と
// 下位 128bit をまたいでシャッフルは出来なくて、かつこの後のストアは
// 連続領域への書き込みになるので、中央でつなげておく。うーん。
const __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
);
const __m256i mask = _mm256_set_epi32(0, -1, -1, -1, -1, -1, -1, 0);
// この変換は一次元配列とみなしても行える。
// モニタ等のパネルでも呼ばれるので何ピクセルで割り切れるかの前提は不可。
uint total = GetWidth() * GetHeight();
uint packed = total & ~7;
const uint32 *s32 = (const uint32 *)src.GetRowPtr(0);
const uint32 *s32total = s32 + total;
const uint32 *s32packed = s32 + packed;
uint32 *d32 = (uint32 *)dst.GetRowPtr(0);
for (; s32 < s32packed; ) {
// 8ピクセルずつ処理する
// c = $x7B7G7R7'x6B6G6R6'x5B5G5R5'x4B4G4R4'
// x3B3G3R3'x2B2G2R2'x1B1G1R1'x0B0G0R0
__m256i c = _mm256_load_si256((const __m256i *)s32);
s32 += 8;
// res= $00000000'B7G7R7B6'G6R6B5G5'R5B4G4R4'
// B3G3R3B2'G2R2B1G1'R1B0G0R0'00000000
__m256i res = _mm256_shuffle_epi8(c, shuff);
// 先頭(下位)と末尾(上位)の 32bit ずつを除いたところを書き出す。
_mm256_maskstore_epi32((int *)(d32 - 1), mask, res);
d32 += 6;
}
uint8 *d8 = (uint8 *)d32;
for (; s32 < s32total; ) {
// 残りを1ピクセルずつ処理する
Color c(*s32++);
*d8++ = c.r;
*d8++ = c.g;
*d8++ = c.b;
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.