将坐标转换卸载到GPU

时间:2012-04-04 16:35:49

标签: c# opencl gpu gpgpu coordinate-transformation

我有一个使用WinForms的遗留地图查看器应用程序。它是sloooooow。 (速度过去是可以接受的,但谷歌地图,谷歌地球出现了,用户被宠坏了。现在我被允许做得更快:)

在完成所有明显的速度改进(缓存,并行执行,不绘制不需要绘制的内容等)之后,我的探查器向我显示真正的阻塞点是坐标转换将点从地图空间转换为屏幕空间。 通常,转换代码如下所示:

    public Point MapToScreen(PointF input)
    {
        // Note that North is negative!
        var result = new Point(
           (int)((input.X - this.currentView.X) * this.Scale),
           (int)((input.Y - this.currentView.Y) * this.Scale));
        return result;
    }

真正的实现比较棘手。 Latitude / longitues表示为整数。为了避免失去精确度,它们乘以2 ^ 20(~1百万)。这就是表示坐标的方式。

public struct Position
{
    public const int PrecisionCompensationPower = 20;
    public const int PrecisionCompensationScale = 1048576; // 2^20
    public readonly int LatitudeInt; // North is negative!
    public readonly int LongitudeInt;
}

重要的是,可能的比例因子也明确地与2的幂相关联。这允许我们用比特移位替换乘法。所以真正的算法看起来像这样:

    public Point MapToScreen(Position input)
    {
        Point result = new Point();
        result.X = (input.LongitudeInt - this.UpperLeftPosition.LongitudeInt) >>
                     (Position.PrecisionCompensationPower - this.ZoomLevel);
        result.Y = (input.LatitudeInt - this.UpperLeftPosition.LatitudeInt) >> 
                     (Position.PrecisionCompensationPower - this.ZoomLevel);
        return result;
    }

(UpperLeftPosition代表地图空间中屏幕的左上角。) 我现在正考虑将此计算卸载到GPU 。谁能告诉我一个如何做到这一点的例子?

我们使用.NET4.0,但代码最好也应该在Windows XP上运行。此外,我们无法使用GPL下的库。

4 个答案:

答案 0 :(得分:2)

我建议您使用OpenCL和Cloo来执行此操作 - 查看vector add example,然后更改此选项以使用两个ComputeBuffer来映射值(一个用于每个点LatitudeIntLongitudeInt中的每一个)到2个输出ComputeBuffer s。我怀疑OpenCL代码看起来像这样:

__kernel void CoordTrans(__global int *lat, 
                         __global int *lon, 
                         __constant int ulpLat,
                         __constant int ulpLon,
                         __constant int zl,
                         __global int *outx,
                         __global int *outy)
{
    int i = get_global_id(0);        
    const int pcp = 20;

    outx[i] = (lon[i] - ulpLon) >> (pcp - zl);
    outy[i] = (lat[i] - ulpLat) >> (pcp - zl);
}

但是你会为每个核心做多个coord-transform。我需要赶紧离开,我建议你在开始之前阅读opencl。

此外,如果坐标数量合理(<100,000 / 1,000,000),非基于gpu的解决方案可能会更快。

答案 1 :(得分:1)

我来自CUDA背景,并且只能代表NVIDIA GPU,但这里也是。

在GPU上执行此操作的问题是您的操作/传输时间。

每个元素执行大约1次操作。你真的想要为每个元素做更多的事情,以获得真正的速度提升。全局内存与GPU上的线程之间的带宽约为100GB / s。因此,如果必须加载一个4字节整数来执行一个FLOP,则理论最大速度为100/4 = 25 FLOPS。这远远不是广告中的数百个FLOPS。

注意这是理论上的最大值,实际结果可能更糟。如果您加载多个元素,情况会更糟。在你的情况下,它看起来像2,所以你最多可以获得12.5 FLOPS。在实践中,它几乎肯定会更低。

如果这听起来不错,那就去吧!

答案 2 :(得分:1)

XNA可用于执行您需要的所有转换,并提供非常好的性能。它也可以在winforms应用程序中显示:http://create.msdn.com/en-US/education/catalog/sample/winforms_series_1

答案 3 :(得分:1)

一年后,问题再次出现,我们发现了一个非常平庸的答案。我觉得有点愚蠢没有早点意识到它。我们通过普通的WinForms GDI将地理元素绘制到位图。 GDI是硬件加速的。我们所要做的就是不要自己进行转换,而是设置System.Drawing.Graphics对象的比例参数: Graphics.TranslateTransform(...)和Graphics.ScaleTransform(...) 我们甚至不需要移位的技巧。

:)