【发布时间】:2018-07-30 19:09:33
【问题描述】:
所以我有一个应用程序(一个游戏),它可以在网格中绘制许多分层的 PNG 来显示屏幕。
for (Image anImage : image) {
if ((x + offset + width) >= 0 && x + offset <= canvasWidth) {
gc.drawImage(anImage, x + offset, y, width, height);
drawn++;
} else {
segmentsSkipped++;
}
offset += width;
}
// if (drawn == 1) gc.drawImage(image[0], x + offset, y, width, height);
这进展很快,而且是一个简单的循环。我在跑
-Djavafx.animation.fullspeed=true
我无法提供 SSCE,因为适当的示例需要滚动等和精灵才能正确再现。正如您在代码中看到的,为了减少绘制操作,我正在测试每个网格段是否在画布区域内,而不是在画布区域外绘制。这给了我大约 30FPS 的使用改进,但导致了一个奇怪的问题:通常在循环的每个循环中,在 4K 监视器上,渲染器“跳过”5 部分网格的 3 部分 - (如预期的那样)。即渲染器正在将两个图像绘制到屏幕上。据我在实践中可以隔离,当跳过 4 个部分时会发生打嗝(即绘制的单个图像会填满整个屏幕)。滚动中有一个明显的打嗝。有时这很重要,而且总是很明显。在更高分辨率(超过 4k)上,随着 2 次移动到 3 个跳过的部分,小跳过很明显。
图片大小为 2800 in x。太大而无法在非 DX12 卡上一次调用。我的温度解决方案是强制另一个绘图调用,正如您在注释代码部分中看到的那样。这有助于解决问题。我的怀疑,这是一个完整的猜测,是 GrowableDataBuffer 正在迅速变化,因为图形所需区域的大小翻了一番。我在 GraphicsContext 中闲逛了一下,这“可能”似乎是问题的候选者,因为它似乎在 n^2 处增长。
我的温度。解决方案可能是可行的,因为即使在不同的分辨率下,绘制了不同数量的网格,在这种尺寸下总是需要至少 2 块,这将为大的 n^2 纹理留出空间。但我更喜欢黑客攻击较少的解决方案。我确实尝试过访问缓冲区,但它是受包保护的。
我想知道——如果这是问题所在——有没有建议 GrowableDataBuffer 不要缩小,并保持它更大的大小?或者也许有人知道是什么原因造成的。
【问题讨论】:
-
您是否尝试连接 VM 监视器(例如 VisualVM)来尝试查找原因?它可能与堆内存和 GC 有关,在这种情况下分配更多的初始/最大堆空间可能会有所帮助。
-
好的,谢谢你,Itai。我试过一个VisualVM。该应用程序调整得很好,但使用了大量的 RAM。我已经在这个游戏上工作了一段时间,没有足够的 RAM 集确实会导致类似的问题。但我设置了 -Xms4G 和 -Dprism.targetvram=1G
-
所以打嗝与 GC 激活和/或已用堆空间减少不一致?
-
很难说。但我有一些疑问,因为记忆明智,在这些问题点上没有发生任何其他重要的事情。就 VisualVM 而言,故障很难在游戏之外重现 - 并且是毫秒事件。使用第二台监视器可以很容易地跟踪尖峰:我将对其进行研究。我需要将玩家角色在世界各地运行到渲染器仅绘制一个网格图像的区域。打嗝恰好发生在这一点附近。
-
我在渲染大量粒子时遇到了类似的症状(使用
canvas.fillRect())。性能绝对不错,但会突然在大约 120`000 个粒子时停止,甚至移动 FX 窗口也非常缓慢。