gpt4 book ai didi

c++ - 从预乘浮点 RGBA 转换为 8 位 RGBA 的有效方法?

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

我正在寻找一种更有效的方法,将在预乘色彩空间中存储为 double 的 RGBA 转换为 8 位整数/ channel RGBA 非预乘色彩空间。这对我的图像处理来说是一项巨大的成本。

对于一个 channel ,比如 R,代码看起来像这样:

double temp = alpha > 0 ? src_r / alpha : 0
uint8_t out_r = (uint8_t)min( 255, max( 0, int(temp * 255 + 0.5) ) )

这涉及三个条件,我认为它们会阻止编译器/CPU 尽可能地优化它。我认为某些芯片,特别是 x86_64 具有专门的双钳位操作,因此理论上上述可能无需条件就可以实现。

是否有一些技术或特殊功能可以使这种转换更快?

我正在使用 GCC,如果需要的话,我很乐意使用 C 或 C++ 或内联 ASM 的解决方案。

最佳答案

这是一个包含一些代码(未经测试)的大纲。这将一次转换四个像素。这种方法的主要优点是它只需要做一次除法(而不是四次)。 split 很慢。但它必须进行转换(AoS 到 SoA)才能做到这一点。它主要使用 SSE,除了将 double 转换为 float (这需要 AVX)。

1.) Load 16 doubles
2.) Convert them to floats
3.) Transpose from rgba rgba rgba rgba to rrrr gggg bbbb aaaa
4.) Divide all 4 alphas in one instruction
5.) Round floats to ints
6.) Compress 32-bit to 8-bit with saturation for underflow and overflow
7.) Transpose back to rgba rgba rgba rgba
9.) Write 4 pixels as integers in rgba format

#include <immintrin.h>
double rgba[16];
int out[4];

//load 16 doubles and convert to floats
__m128 tmp1 = _mm256_cvtpd_ps(_mm256_load_pd(&rgba[0]));
__m128 tmp2 = _mm256_cvtpd_ps(_mm256_load_pd(&rgba[4]));
__m128 tmp3 = _mm256_cvtpd_ps(_mm256_load_pd(&rgba[8]));
__m128 tmp4 = _mm256_cvtpd_ps(_mm256_load_pd(&rgba[12]));
//rgba rgba rgba rgba -> rrrr bbbb gggg aaaa
_MM_TRANSPOSE4_PS(tmp1,tmp2,tmp3,tmp4);
//fact = alpha > 0 ? 255.0f/ alpha : 0
__m128 fact = _mm_div_ps(_mm_set1_ps(255.0f),tmp4);
tmp1 = _mm_mul_ps(fact,tmp1); //rrrr
tmp2 = _mm_mul_ps(fact,tmp2); //gggg
tmp3 = _mm_mul_ps(fact,tmp3); //bbbb
tmp4 = _mm_mul_ps(_mm_set1_ps(255.0f), tmp4); //aaaa

//round to nearest int
__m128i tmp1i = _mm_cvtps_epi32(tmp1);
__m128i tmp2i = _mm_cvtps_epi32(tmp2);
__m128i tmp3i = _mm_cvtps_epi32(tmp3);
__m128i tmp4i = _mm_cvtps_epi32(tmp4);

//compress from 32bit to 8 bit
__m128i tmp5i = _mm_packs_epi32(tmp1i, tmp2i);
__m128i tmp6i = _mm_packs_epi32(tmp3i, tmp4i);
__m128i tmp7i = _mm_packs_epi16(tmp5i, tmp6i);

//transpose back to rgba rgba rgba rgba
__m128i out16 = _mm_shuffle_epi8(in16,_mm_setr_epi8(0x0,0x04,0x08,0x0c, 0x01,0x05,0x09,0x0d, 0x02,0x06,0x0a,0x0e, 0x03,0x07,0x0b,0x0f));
_mm_store_si128((__m128i*)out, tmp7i);

关于c++ - 从预乘浮点 RGBA 转换为 8 位 RGBA 的有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22244629/

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