inline unsigned interleave(unsigned n)
{
n = ((n << 18) | (n << 9) | n) & 0007007007; // 000000111 000000111 000000111
n = ((n << 6) | (n << 3) | n) & 0444444444; // 100100100 100100100 100100100
return n;
}
unsigned r = interleave(rByte);
unsigned g = interleave(gByte);
unsigned b = interleave(bByte);
unsigned rgb = r | (g >> 1) | (b >> 2);
TempLinebuff[((i*3)+0) +2] = rgb >> 16;
TempLinebuff[((i*3)+1) +2] = rgb >> 8;
TempLinebuff[((i*3)+2) +2] = rgb;
#define EXPANDBIT(x, n) (((x) & (1 << (n))) << (3*(n))))
#define EXPAND8BIT(a) (EXPANDBIT(a, 0) | EXPANDBIT(a, 1) | EXPANDBIT(a, 2) | EXPANDBIT(a, 3) | \
EXPANDBIT(a, 4) | EXPANDBIT(a, 5) | EXPANDBIT(a, 6) | EXPANDBIT(a, 7))
#define EXPAND16(A) EXPAND8BIT(16*(A)+ 0), EXPAND8BIT(16*(A)+ 1), EXPAND8BIT(16*(A)+ 2), EXPAND8BIT(16*(A)+ 3), \
EXPAND8BIT(16*(A)+ 4), EXPAND8BIT(16*(A)+ 5), EXPAND8BIT(16*(A)+ 6), EXPAND8BIT(16*(A)+ 7), \
EXPAND8BIT(16*(A)+ 8), EXPAND8BIT(16*(A)+ 9), EXPAND8BIT(16*(A)+10), EXPAND8BIT(16*(A)+11), \
EXPAND8BIT(16*(A)+12), EXPAND8BIT(16*(A)+13), EXPAND8BIT(16*(A)+14), EXPAND8BIT(16*(A)+15)
const uint32_t LUT[256] = {
EXPAND16( 0), EXPAND16( 1), EXPAND16( 2), EXPAND16( 3),
EXPAND16( 4), EXPAND16( 5), EXPAND16( 6), EXPAND16( 7),
EXPAND16( 8), EXPAND16( 9), EXPAND16(10), EXPAND16(11),
EXPAND16(12), EXPAND16(13), EXPAND16(14), EXPAND16(15)
};
output = LUT[rByte] | LUT[gByte] << 1 | LUT[bByte] << 2;
必要に応じて、ルックアップ テーブルのサイズを大きくすることができます。
BMI2を使用するx86 では、組み込み関数を介してアクセスできるPDEP命令によるハードウェア サポートがあります_pdep_u32
。ソリューションははるかに簡単になりました
output = _pdep_u32(rByte, 044444444U << 8)
| _pdep_u32(gByte, 022222222U << 8)
| _pdep_u32(bByte, 011111111U << 8);
別の方法は
このパッキング手法で乗算とマスクを使用したインターリーブ
これは、ハードウェア ビット デポジット命令を使用せず、高速乗算器を使用するアーキテクチャ用です。
uint32_t expand8bits(uint8_t b)
{
uint64_t MAGIC = 0x8040201008040201;
uint64_t MASK = 0x8080808080808080;
uint64_t expanded8bits = htobe64((MAGIC*b) & MASK);
uint64_t result = expanded8bits*0x2108421 & 0x9249000000009000;
// no need to shift if you want to get the bits in the high part
return ((result | (result << 30)) & (044444444ULL << 8)) >> 32;
}
uint32_t stripeBits(uint8_t rByte, uint8_t gByte, uint8_t bByte)
{
return expand8bits(rByte) | (expand8bits(gByte) >> 1) | (expand8bits(bByte) >> 2);
}
仕組みはこんな感じ
- 最初のステップでは、入力ビットを
abcdefgh
a0000000 b0000000 c0000000 d0000000 e0000000 f0000000 g0000000 h0000000に展開し、格納します。expand8bits
- 次に、次のステップで乗算とマスキングを行うことにより、離れたビットを近づけます。その後、a00b00c00d00e00f000000000000000000000000000000g00h000000000000
result
が含まれ、単一の値にマージする準備が整います
ビットを近づけるマジックナンバーはこんな感じで計算
a0000000b0000000c0000000d0000000e0000000f0000000g0000000h0000000
× 10000100001000010000100001 (0x2108421)
────────────────────────────────────────────────────────────────
a0000000b0000000c0000000d0000000e0000000f0000000g0000000h0000000
000b0000000c0000000d0000000e0000000f0000000g0000000h0000000
+ 000000c0000000d0000000e0000000f0000000g0000000h0000000
0c0000000d0000000e0000000f0000000g0000000h0000000
0000d0000000e0000000f0000000g0000000h0000000
0000000e0000000f0000000g0000000h0000000
────────────────────────────────────────────────────────────────
ac0bd0cebd0ce0dfce0df0egdf0eg0fheg0fh0g0fh0g00h0g00h0000h0000000
& 1001001001001001000000000000000000000000000000001001000000000000 (0x9249000000009000)
────────────────────────────────────────────────────────────────
a00b00c00d00e00f00000000000000000000000000000000g00h000000000000
あるいは、このような32 ビット マジック ナンバーの乗算のみexpand8bits
を使用して実装することもできます。
uint32_t expand8bits(uint8_t b)
{
const uint8_t RMASK_1458 = 0b10011001;
const uint32_t MAGIC_1458 = 0b00000001000001010000010000000000U;
const uint32_t MAGIC_2367 = 0b00000000010100000101000000000000U;
const uint32_t MASK_BIT1458 = 0b10000000010010000000010000000000U;
const uint32_t MASK_BIT2367 = 0b00010010000000010010000000000000U;
return (((b & RMASK_1458) * MAGIC_1458) & MASK_BIT1458)
| (((b & ~RMASK_1458) * MAGIC_2367) & MASK_BIT2367);
}
ここでは、8 ビットの数値を 2 つの 4 ビット部分に分割します。1 つはビット 1、4、5、8 で、残りはビット 2、3、6、7 です。マジック ナンバーは次のようになります。
a00de00h 0bc00fg0
× 00000001000001010000010000000000 × 00000000010100000101000000000000
──────────────────────────────── ────────────────────────────────
a00de00h 0bc00fg0
+ a00de00h + 0bc00fg0
a00de00h 0bc00fg0
a00de00h 0bc00fg0
──────────────────────────────── ────────────────────────────────
a00de0ahadedehah0de00h0000000000 000bcbcfgfgbcbcfgfg0000000000000
& 10000000010010000000010000000000 & 00010010000000010010000000000000
──────────────────────────────── ────────────────────────────────
a00000000d00e00000000h0000000000 000b00c00000000f00g0000000000000
見る