Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Image processing Lanczos SSE/AVX实施_Image Processing_Assembly_Sse_Avx_Lanczos - Fatal编程技术网

Image processing Lanczos SSE/AVX实施

Image processing Lanczos SSE/AVX实施,image-processing,assembly,sse,avx,lanczos,Image Processing,Assembly,Sse,Avx,Lanczos,有人对如何使用SSE/AVX(内在函数或汇编)实现(放大和缩小)算法有什么建议吗 我看过一些C实现,但是有很多分支,我真的不知道如何使用SSE/AVX智能地实现它 示例-标准化基数sin: // C implementation if (!x) return sin(x*M_PI)/(x*M_PI); else return 1; // AVX implementation PXOR ymm0, ymm0 MOVAPD ymm1, [x] // x - array of dou

有人对如何使用SSE/AVX(内在函数或汇编)实现(放大和缩小)算法有什么建议吗

我看过一些C实现,但是有很多分支,我真的不知道如何使用SSE/AVX智能地实现它

示例-标准化基数sin:

// C implementation
if (!x)
  return sin(x*M_PI)/(x*M_PI);
else
  return 1;

// AVX implementation
PXOR ymm0, ymm0
MOVAPD ymm1, [x]     // x - array of double
CMPPD ymm0, ymm1, 0  // if (!x)
// what now?

MOVAPD ymm3, [pi]    // pi - array of double = M_PI - is there better way?
PMULPD ymm1, ymm3    // ymm1 = x*pi
(SINPD ymm2, ymm1)   // found intrinsic _mm256_sin_pd - Intel math library, intrinsic functions are OK with me
DIVPD ymm2, ymm1     // result in ymm2
对于值x==0,我应该如何返回1?在这个索引上,我在CMPPD之后有11…11(真)


另外,我是为灰度,8位图片做的,所以一个像素只有(0..255)。使用浮球而不是双倍球对质量有什么影响?如果你不知道asm或SSE/AVX,一次学习一个可能会更容易些。与直接使用asm相比,使用C/C++内部函数编写向量算法将为您提供更具可移植性的实现。(编译32位与64位、windows或其他所有版本,而不需要2或4个不同的asm版本(或asm中的#ifdef等效宏)

在编写C时查看编译器输出会很有帮助,可以确保加载/存储按预期方式进行,并且编译器不会因为别名/对齐(缺少)假设或存储/生成常量而对臃肿的代码做任何愚蠢的事情

调试向量代码已经够难的了(因为有更多的状态需要跟踪,并且您必须在精神上通过洗牌来跟踪)

如果编译器还没有自动矢量化,我会先找到C中一些可能矢量化的部分,然后在C中使用内部函数。一旦这些工作正常,我可能会获取编译器输出,并在编译器没有生成最佳代码的地方手动调整它。(请参阅)


至于将图像数据处理为float vs.int,如果您可以使用16位定点,则速度会更快(除非需要更多说明)。请参阅关于使用float vs.fixed-point



SSE中唯一的数学指令(除了基本的add/sub/mul/div)是
sqrt
。Trig/log/exp都是库函数。请注意,在《英特尔内部指南》中,“指令”字段为空,表示它映射到多条指令。只有英特尔的编译器甚至提供这些复合内部函数

无论如何,您需要找到要内联的
sin
实现,或者保存一些寄存器并进行函数调用,一些或所有xmm寄存器可能会被函数阻塞。使用特定的
sin
实现会让您知道它需要哪些寄存器,并且只会溢出这些寄存器。(因为您是在asm中编程的,所以可以使函数比只遵循ABI更了解彼此。)

如果您只需要这样做,您可以制作一个自定义的
sin
函数来实现这一点,省去了预乘PI的麻烦。由于
sin
是理想的实现,您可能无法得到精确到尾数最后一位的向量化实现。幸运的是,您可能不需要这样做,所以谷歌up一个SSE sin(x)实现


SIMD向量中的条件是通过比较来处理的,比较生成一个全零或全一的元素向量。然后可以将AND或or添加到其他向量上。它适用于在标识值为
0
的位置进行添加。(
x+0=x
,因此在将向量添加到累加器之前,您可以从向量中筛选出一些元素)。如果需要根据向量0/-1在两个源元素之间进行选择,您可以将和/或内容组合在一起,或者使用
blendvps
(变量混合压缩标量,而不是编译时常量混合)

如果你想避免一开始就计算一个缓慢的除零运算,而不是通常只计算所有运算,然后掩蔽/混合,那么这个想法就有点失败了。因为当
x==0.0
时,你希望结果是
1
,最好的办法可能是将
x
的零个元素设置为FL在计算任何
sin(x*PI)/(x*PI)
之前,T_MIN*16或其他什么。这样,你就避免了被零除,并且除法的结果非常接近1。如果你需要精确到1.0f(并且没有一个
x
的值使得
sin(x*PI)==x*PI
sin/code>实现一致)然后你需要混合两次:一次在分子中,一次在分母中(将两者设置为相同的非零值)


请注意,
cmpps
在AVX VEX编码版本中比在SSE版本中有更广泛的谓词选择。

SSE中唯一的数学指令(除了基本的add/sub/mul/div)是
sqrt
。Trig/log/exp都是库函数。请注意,在《英特尔内部指南》中,“指令”字段为空,意味着它映射到多条指令。只有英特尔的编译器甚至提供了这些复合内部函数。您是否需要每像素一个任意的
x
,也就是说,您真的需要为每个像素计算新的Lanczos系数?(这个问题的答案取决于你尝试执行什么样的重采样或插值。)我需要调整图像的大小-包括放大和缩小。我是这方面的新手,仍在努力掌握它的工作原理。我有信号处理的基础知识(例如,我知道卷积是如何工作的,等等).这里是参考算法的主要部分(下面是垂直方向的类似代码):@PeterCordes是的,我也很害怕。但这应该不是问题。我正在使用MS Visual studio和其他内在函数(用于说明)行得通。如果他们的数学库也能用的话,我就得试试。现在当我考虑它的时候——有可能找到它映射到什么指令吗?那就意味着
vxorps     xmm15, xmm15, xmm15   ; if you can spare a reg to hold a zero constant



; inside your loop:  xmm0 holds { x3, x2, x1, x0 }.
vcmpeqps     xmm1, xmm0, xmm15   ;; mnemonic for vcmpps xmm1, xmm0, xmm15, 0.
;;  Different predicates are an immediate operand, not different opcodes


vblendvps  xmm2, xmm0, [memory_holding_vector_of_float_min], xmm1  ; Or cache it in a reg if you have one to spare
     ; blendv takes elements from the 2nd source operand when the selector (xmm1) has a 1-bit in the MSB (sign bit)

; xmm2 = (x==0.0f) ? FLT_MIN : x
;  xmm1 holds { sin(x3*pi), sin(x2*pi)... }