Optimization 优化随机存取双线性抽样

Optimization 优化随机存取双线性抽样,optimization,graphics,Optimization,Graphics,我在做一个老式的“图像扭曲”过滤器。基本上,我有一个2D像素数组(暂时忽略它们是否为颜色、灰度、浮点、RGBA等问题)和另一个2D向量数组(带有浮点组件),图像至少与向量数组一样大。在伪代码中,我要执行以下操作: FOR EACH PIXEL (x,y) vec = vectors[x,y] // Get vector val = get(img, x + vec.x, y + vec.y) // Get input at <x,

我在做一个老式的“图像扭曲”过滤器。基本上,我有一个2D像素数组(暂时忽略它们是否为颜色、灰度、浮点、RGBA等问题)和另一个2D向量数组(带有浮点组件),图像至少与向量数组一样大。在伪代码中,我要执行以下操作:

FOR EACH PIXEL (x,y)      
  vec = vectors[x,y]                    // Get vector
  val = get(img, x + vec.x, y + vec.y)  // Get input at <x,y> + vec
  output[x,y] = val                     // Write to output
lerp()
只是

FUNCTION lerp(a,b,x) 
  RETURN (1-x)*a + x*b
假设事先既不知道输入图像也不知道向量数组,那么什么样的高级优化是可能的?(注意:“使用GPU”是欺骗。)我能想到的一件事是在
get()
中重新安排插值数学,以便我们可以缓存给定(ix,iy)的像素读取和中间计算。这样,如果连续访问同一个亚像素四边形,我们可以避免一些工作。如果向量数组是预先知道的,那么我们可以重新排列它,以便传递给
get()
的坐标更为局部。这可能也有助于缓存的局部性,但代价是写入
输出的内容到处都是。但是,我们不能做一些奇特的事情,比如动态缩放向量,甚至不能将扭曲效果从其原始的预先计算位置移动

唯一的另一种可能性是使用定点向量分量,可能只有非常有限的分数部分。例如,如果向量只有2位分数分量,那么只有16个子像素区域可以访问。我们可以预先计算这些参数的权重,完全避免很多插值运算,但要保证质量

还有其他想法吗?在实现它们之前,我想积累一些不同的方法,看看哪一种是最好的。如果有人能告诉我一个快速实现的源代码,那就太好了。

有趣的问题

您的问题定义基本上强制了对[x,y]中的不可预测的访问,因为可能会提供任何向量。假设向量图像倾向于引用局部像素,第一个优化将是确保以适当的顺序遍历内存,以充分利用缓存局部性。这可能意味着在“每个像素”循环中扫描32*32块,以便在短时间内尽可能多地在[x,y]中点击相同的像素

最有可能的是,算法的性能将受到两个因素的限制

  • 从主存加载向量[x,y]
  • 和[x,y]的速度有多快
  • 乘法和求和需要多长时间
  • SSE指令可以一次将多个元素相乘,然后将它们相加(相乘和累加)。你应该做的是计算

    af = (1 - xf) * ( 1 - yf )
    bf = (    xf) * ( 1 - yf )
    cf = (1 - xf) * (     yf )
    df = (    xf) * (     yf )
    
    然后计算

    a *= af
    b *= bf 
    c *= cf
    d *= cf
    return (a + b + c + d)
    
    这两个步骤很有可能都可以通过少量的SSE指令(取决于像素表示)来完成

    我认为缓存中间值不太可能有用-向量请求中超过1%的向量不太可能指向完全相同的位置,缓存内容将花费比节省更多的内存带宽

    如果在处理
    向量[x,y]
    时,使用cpu上的预取指令在[vectors[x+1,y]]中预取
    ,可能会提高内存性能,否则cpu将无法预测内存的随机漫游

    提高算法性能的最后一种方法是一次处理输入像素块,即
    x[0..4],x[5..8]
    -这可以展开内部数学循环。但是,您很可能内存不足,因此这不会有任何帮助

    a *= af
    b *= bf 
    c *= cf
    d *= cf
    return (a + b + c + d)