gpt4 book ai didi

c++ - 使用查找表更快的 alpha 混合?

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:20:15 24 4
gpt4 key购买 nike

我制作了一个查找表,允许您使用单字节 alpha channel 混合两个单字节 channel (每个 channel 256 种颜色),不使用浮点值(因此没有 float 到 int 的转换)。查找表中的每个索引对应于 channel 的 256ths 的值,与 alpha 值相关。

总而言之,要完全计算 3 channel RGB 混合,需要对每个 channel 的数组进行两次查找,再加上一次加法。这总共是 6 次查找和 3 次添加。在下面的示例中,我将颜色拆分为单独的值以便于演示。此示例说明如何通过 0 到 256 之间的 alpha 值混合三个 channel ,R G 和 B。

BYTE r1, r2, rDest;
BYTE g1, g2, gDest;
BYTE b1, b2, bDest;

BYTE av; // Alpha value
BYTE rem = 255 - av; // Remaining fraction

rDest = _lookup[r1][rem] + _lookup[r2][av];
gDest = _lookup[g1][rem] + _lookup[g2][av];
bDest = _lookup[b1][rem] + _lookup[b2][av];

效果很好。尽可能精确地使用 256 个颜色 channel 。事实上,您将使用实际的浮点计算得到相同的精确值。查找表是使用 double 开始计算的。查找表太大,不适合这篇文章(65536 字节)。 (如果你想要它的拷贝,请发送电子邮件至 ten.turtle.toes@gmail.com,但不要指望明天之前回复,因为我现在要 sleep 了。)

那么……你怎么看?值不值?

最佳答案

我有兴趣查看一些基准。

有一种算法可以在没有任何浮点计算或查找表的情况下进行完美的 alpha 混合。您可以在以下 document 中找到更多信息(算法和代码在最后说明)

我很久以前也做了一个 SSE 实现,如果你有兴趣的话......

void PreOver_SSE2(void* dest, const void* source1, const void* source2, size_t size)
{
static const size_t STRIDE = sizeof(__m128i)*4;
static const u32 PSD = 64;

static const __m128i round = _mm_set1_epi16(128);
static const __m128i lomask = _mm_set1_epi32(0x00FF00FF);

assert(source1 != NULL && source2 != NULL && dest != NULL);
assert(size % STRIDE == 0);

const __m128i* source128_1 = reinterpret_cast<const __m128i*>(source1);
const __m128i* source128_2 = reinterpret_cast<const __m128i*>(source2);
__m128i* dest128 = reinterpret_cast<__m128i*>(dest);

__m128i d, s, a, rb, ag, t;

for(size_t k = 0, length = size/STRIDE; k < length; ++k)
{
// TODO: put prefetch between calculations?(R.N)
_mm_prefetch(reinterpret_cast<const s8*>(source128_1+PSD), _MM_HINT_NTA);
_mm_prefetch(reinterpret_cast<const s8*>(source128_2+PSD), _MM_HINT_NTA);

// work on entire cacheline before next prefetch
for(int n = 0; n < 4; ++n, ++dest128, ++source128_1, ++source128_2)
{
// TODO: assembly optimization use PSHUFD on moves before calculations, lower latency than MOVDQA (R.N) http://software.intel.com/en-us/articles/fast-simd-integer-move-for-the-intel-pentiumr-4-processor/

// TODO: load entire cacheline at the same time? are there enough registers? 32 bit mode (special compile for 64bit?) (R.N)
s = _mm_load_si128(source128_1); // AABGGRR
d = _mm_load_si128(source128_2); // AABGGRR

// PRELERP(S, D) = S+D - ((S*D[A]+0x80)>>8)+(S*D[A]+0x80))>>8
// T = S*D[A]+0x80 => PRELERP(S,D) = S+D - ((T>>8)+T)>>8

// set alpha to lo16 from dest_
a = _mm_srli_epi32(d, 24); // 000000AA
rb = _mm_slli_epi32(a, 16); // 00AA0000
a = _mm_or_si128(rb, a); // 00AA00AA

rb = _mm_and_si128(lomask, s); // 00BB00RR
rb = _mm_mullo_epi16(rb, a); // BBBBRRRR
rb = _mm_add_epi16(rb, round); // BBBBRRRR
t = _mm_srli_epi16(rb, 8);
t = _mm_add_epi16(t, rb);
rb = _mm_srli_epi16(t, 8); // 00BB00RR

ag = _mm_srli_epi16(s, 8); // 00AA00GG
ag = _mm_mullo_epi16(ag, a); // AAAAGGGG
ag = _mm_add_epi16(ag, round);
t = _mm_srli_epi16(ag, 8);
t = _mm_add_epi16(t, ag);
ag = _mm_andnot_si128(lomask, t); // AA00GG00

rb = _mm_or_si128(rb, ag); // AABGGRR pack

rb = _mm_sub_epi8(s, rb); // sub S-[(D[A]*S)/255]
d = _mm_add_epi8(d, rb); // add D+[S-(D[A]*S)/255]

_mm_stream_si128(dest128, d);
}
}
_mm_mfence(); //ensure last WC buffers get flushed to memory
}

关于c++ - 使用查找表更快的 alpha 混合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5438313/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com