2012-07-13 87 views
2

我目前正在尝试改进地图渲染库的性能。在准时符号的情况下,图书馆经常在每个位置上一次又一次地绘制相同的图像。但是绘制过程可能非常复杂,因为符号的参数化非常丰富。对于每个点,我都有一个树结构来计算要绘制的图像。当参数不依赖于我正在处理的数据时,如前所述,我只是多次绘制一个复杂的符号。图像缓存和性能

我试着实现一个缓存机制。我存储已经绘制的图像,如果我遇到已经满足的配置,我会得到图像并再次绘制。我做的第一个测试是一个非常简单的符号。这是一个圆形,其形状和内部都充满了。

因为我知道符号在所有位置都是不变的,所以我将它缓存起来,然后再从缓存的图像中绘制出来。这有效......但我面临两个重要问题:

  • 绘制的符号的质量很难被破坏。
  • 问题更多:渲染地图所需的时间与缓存相比,无需缓存。这对于高速缓存^ _^

当缓存机制上的核心代码非常令人失望的是:在drawCachedImageOnGeometry取得

if(pc.isCached(map)){ 
    BufferedImage bi = pc.getCachedValue(map); 
    drawCachedImageOnGeometry(g2, sds, fid, selected, mt, the_geom, bi); 
} else { 
    BufferedImage bi = g2.getDeviceConfiguration().createCompatibleImage(200, 200); 
    Graphics2D tg2 = bi.createGraphics(); 
    graphic.draw(tg2, map, selected, mt, AffineTransform.getTranslateInstance(100, 100)); 
    drawCachedImageOnGeometry(g2, sds, fid, selected, mt, the_geom, bi); 
    pc.cacheSymbol(map, bi); 
} 

唯一有趣的通话

g2.drawRenderedImage(bi, AffineTransform.getTranslateInstance(x-100,y-100)); 

我已经尝试过使用VolatileImage实例而不是BufferedImage,但是这会导致更深的问题(我无法确定每次需要时都会正确呈现图像)。

我也做了一些分析,看来在使用我的缓存时,花费最长时间的操作是在awt中进行的渲染操作。

这么说,我想我的策略是错误的......因此,我的问题是:

  • 是否有任何有效的方式来实现我已经解释的目标是什么?
  • 更准确地说,存储用于绘制我的符号的AWT指令并根据需要翻译它们会更快吗?我假设可以检索用于构建符号的“命令”......但是我没有在万维网上找到很多有关这方面的信息,但是......如果可能的话,那将节省我都是符号的计算时间(如前所述,这可能非常复杂)以及我的符号的质量。

预先感谢所有的信息和资源,你给我:-)

Agemen。

编辑:这里是一些关于可以呈现的图形的细节。根据我正在实施的符号体系模型,图形可以非常简单(即其形状为实心正方形)以及非常复杂(例如,标签的形状和填充都用阴影绘制,即使光环如果我想要的话)。我想使用缓存,因为我敢肯定,在大多数配置中我将能够:

  • differenciate已被用于绘制有风格具有相同的同一源的两个不同的符号参数样式。
  • 确保具有相同参数(位置除外)的两个源将为相同样式生成相同的符号,但在两个不同的位置(仅需要翻译)。

由于这两点,缓存似乎是一个很好的策略。而且,在同一图像中可能会绘制数千个重复的符号。

回答

1

对于您的绘图真正需要什么样的操作,您是非常含糊的,所以我可以给你的只是一些非常一般的指针。

1.)绘制预渲染图像不一定比使用Graphics2D操作绘制相同图像更快。这很大程度上取决于绘制图像所需的复杂性。作为一种极端情况,考虑fillRect()与包含预渲染矩形的图像的drawImage()(fillRect仅写入目标像素,其中drawImage还需要从源复制)。

2.)在大多数情况下,你从来没有想要直接与VolatileImage混淆。 BufferedImage会自动利用VolatileImage,除非你搞乱了Image DataBuffer。如果您有许多预先呈现的图像,则可能会用尽加速的视频内存,并且会降低图像绘制性能。 3.)预渲染图像的实时缩放/旋转等可能非常昂贵(取决于平台和当前的图形转换)。

4.)您创建的'兼容图像'可能与绘图目标不兼容。您可以获得与默认屏幕设备兼容的图像,这可能与多监视器设置中的实际目标不兼容。使用实际的目标组件createImage()可以获得更好的结果。

编辑:

5.)翻译渲染操作的坐标可以改变所产生的目的地像素。一种明显的情况是,坐标是非整数时(坐标本身或间接通过图形上的AffineTransform设置)。此外,文本和其他基元的抗锯齿可能会受到坐标的轻微影响(想到子像素渲染)。


如果符号大概是快速渲染或慢速渲染,那么您可以尝试一种区分方法。快速的被直接渲染,而慢速的被缓存。这里的主要问题是在决定哪些是快/慢时,我认为这是不重要的决定。

另外,我想知道当你说有几千个符号需要渲染时,我想大多数应该被剪掉,因为只有一小部分图形适合窗口/框架?如果是这样的话,请不要在高速缓存中烦恼。完全在当前剪辑边界之外的绘图操作将会相对便宜 - 所有图形目标对他们来说确实会做的就是检测它们是否完全看不见,什么时候什么都不做。如果目标是生成要保存到磁盘/打印(无论)的图像,我不会加速渲染,因为这是一个相对较少的操作,实际打印可能远远超过渲染所需的时间无论如何。

如果以上都不适用于你的情况,有些小心,你的缓存不使用更多的时间/内存来决定是否缓存版本存在比它确实在渲染时间节省。您还需要考虑到accound,建立一个缓存的图像,而不是渲染目标直接做成本你,如果该图像是永远不会重复使用一段时间。如果图像被重复使用至少一次,最好有更多的时间缓存只能得到你一些速度。

如果您通过组合primitve渲染操作对象(如存在Rectangle,Halo和Text渲染对象子类)从原始操作构建符号,则可能需要为它们分配成本指示符并仅缓存那些符号超过一些(待定)成本门槛。也可能实现的hashCode()为每个基本操作和符号本身快速(ER)等于检测一个好主意。

+0

我会添加有关我可能会遇到操作索姆细节。我很高兴读你2):-) 3)我的缓存图像只需要进行翻译(见我的编辑)4)我会尽可能快地提高了这一点,并让你知道。 – Agemen 2012-07-13 20:38:38