JavaFX GrowableDataBuffer,Canvas 性能问题
JavaFX GrowableDataBuffer, Canvas performance hiccup
所以我有一个应用程序(游戏),它可以绘制多个分层的 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=真
我无法提供 SSCE,因为正确的示例需要滚动等和精灵才能正确重现。正如您在代码中看到的那样,为了减少绘制操作,我正在测试每个网格段是否在 canvas 区域内而不是在外部绘制。这让我在使用中提高了大约 30FPS,但导致了一个奇怪的问题:通常在循环的每个周期,在 4K 显示器上,渲染器是 5 部分网格的 "skipping" 3 部分 - (如预期的那样)。即渲染器正在将两个图像绘制到屏幕上。就我在实践中可以隔离的而言,当跳过 4 个部分时会出现打嗝(即绘制了一个填满整个屏幕的图像)。然后在滚动中出现明显的打嗝。有时这很重要,而且总是很明显。在更高的分辨率(超过 4k)上,当 2 移动到 3 个跳过的部分时,小跳跃很明显。
图像在 x 中很大 2800。太大而无法在非 DX12 卡上一次调用渲染。我的温度。解决方案是强制执行另一个绘图调用,如您在注释代码部分中所见。这有助于解决问题。我怀疑,这完全是猜测,随着图形所需区域的大小加倍,GrowableDataBuffer 正在迅速变化。我在 GraphicsContext 中查了一下,这个 'could' 似乎是问题的候选者,因为它似乎以 n^2 的速度增长。
我的温度。解决方案可能是可行的,因为即使在不同的分辨率下,也会绘制不同数量的网格,始终需要至少 2 个这种大小的网格,这将为大型 n^2 纹理留出空间。但我更喜欢一个不那么被黑的解决方案。我确实尝试访问缓冲区,但它受程序包保护。
我想知道——如果这是问题所在——是否有建议 GrowableDataBuffer 不要收缩,并保持其较大的大小?或者也许有人知道是什么原因造成的。
您的 "hack" 的另一种(但更合乎逻辑的)实现方式是绘制那些稍微偏离屏幕并可能在接下来的几帧出现在屏幕上的背景图块:
for (Image anImage : image) {
if ((x + offset + width) >= -RENDER_MARGIN && x + offset <= (canvasWidth + RENDER_MARGIN)) {
gc.drawImage(anImage, x + offset, y, width, height);
drawn++;
} else {
segmentsSkipped++;
}
offset += width;
}
常量 RENDER_MARGIN
从而定义了一个图块可以在屏幕外但仍被绘制的像素数。实际值取决于您的滚动速度。
但是,我建议改进渲染逻辑,通过使用方法 GraphicsContext.drawImage(Image img, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh)
使 GrowableDataBuffer
保持恒定大小,它允许您定义源区域和目标区域,即仅绘制当前帧屏幕上图像的确切区域。
题外话:我建议将你的背景图像分成更小的块以减少内存使用并可能提高整体渲染性能。
所以我有一个应用程序(游戏),它可以绘制多个分层的 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=真
我无法提供 SSCE,因为正确的示例需要滚动等和精灵才能正确重现。正如您在代码中看到的那样,为了减少绘制操作,我正在测试每个网格段是否在 canvas 区域内而不是在外部绘制。这让我在使用中提高了大约 30FPS,但导致了一个奇怪的问题:通常在循环的每个周期,在 4K 显示器上,渲染器是 5 部分网格的 "skipping" 3 部分 - (如预期的那样)。即渲染器正在将两个图像绘制到屏幕上。就我在实践中可以隔离的而言,当跳过 4 个部分时会出现打嗝(即绘制了一个填满整个屏幕的图像)。然后在滚动中出现明显的打嗝。有时这很重要,而且总是很明显。在更高的分辨率(超过 4k)上,当 2 移动到 3 个跳过的部分时,小跳跃很明显。
图像在 x 中很大 2800。太大而无法在非 DX12 卡上一次调用渲染。我的温度。解决方案是强制执行另一个绘图调用,如您在注释代码部分中所见。这有助于解决问题。我怀疑,这完全是猜测,随着图形所需区域的大小加倍,GrowableDataBuffer 正在迅速变化。我在 GraphicsContext 中查了一下,这个 'could' 似乎是问题的候选者,因为它似乎以 n^2 的速度增长。
我的温度。解决方案可能是可行的,因为即使在不同的分辨率下,也会绘制不同数量的网格,始终需要至少 2 个这种大小的网格,这将为大型 n^2 纹理留出空间。但我更喜欢一个不那么被黑的解决方案。我确实尝试访问缓冲区,但它受程序包保护。
我想知道——如果这是问题所在——是否有建议 GrowableDataBuffer 不要收缩,并保持其较大的大小?或者也许有人知道是什么原因造成的。
您的 "hack" 的另一种(但更合乎逻辑的)实现方式是绘制那些稍微偏离屏幕并可能在接下来的几帧出现在屏幕上的背景图块:
for (Image anImage : image) {
if ((x + offset + width) >= -RENDER_MARGIN && x + offset <= (canvasWidth + RENDER_MARGIN)) {
gc.drawImage(anImage, x + offset, y, width, height);
drawn++;
} else {
segmentsSkipped++;
}
offset += width;
}
常量 RENDER_MARGIN
从而定义了一个图块可以在屏幕外但仍被绘制的像素数。实际值取决于您的滚动速度。
但是,我建议改进渲染逻辑,通过使用方法 GraphicsContext.drawImage(Image img, double sx, double sy, double sw, double sh, double dx, double dy, double dw, double dh)
使 GrowableDataBuffer
保持恒定大小,它允许您定义源区域和目标区域,即仅绘制当前帧屏幕上图像的确切区域。
题外话:我建议将你的背景图像分成更小的块以减少内存使用并可能提高整体渲染性能。