bak*_*408 4 java performance drawing javafx
我创建了一个需要绘制简单矩形(1x1 - 3x3大小)的应用程序取决于以20,40或甚至60 FPS速率存储在相应大小(900x900 - 300x300大小)的数组中的一些变量.
这是我的绘图方法:
protected void drawCurrentState()
{
for (int i=0; i<gameLogic.size; i++)
{
for (int j=0; j<gameLogic.size; j++)
{
if (gameLogic.previousStepTable == null || gameLogic.previousStepTable[i][j] != gameLogic.gameTable[i][j])
{
if (gameLogic.gameTable[i][j].state)
graphicsContext.setFill(gameLogic.gameTable[i][j].color);
else
graphicsContext.setFill(Color.WHITE);
graphicsContext.fillRect(leftMargin + (j * (cellSize + cellMargin)),
topMargin + (i * (cellSize + cellMargin)), cellSize, cellSize);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可能已经注意到,只有在需要时(当状态从上一步开始改变时)才执行绘图.所有其他操作(gameLogic等中的计算变量状态)几乎不需要时间,也不会影响性能.
JavaFX执行此操作非常慢!在5-10秒内绘制10次迭代(应该在20FPS速率下以0.5秒绘制),这在这种情况下显然是不可接受的.
有没有办法大规模地将绘图操作加速到预期的性能水平(例如,每秒40或60次迭代)?
那么在这种情况下绘画表现如此糟糕的原因是什么?
我在几个不同的实现上运行了一些基准测试,如下所示:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.scene.image.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.nio.IntBuffer;
public class CanvasUpdater extends Application {
private static final int CELL_SIZE = 2;
private static final int BOARD_SIZE = 900;
private static final int W = BOARD_SIZE * CELL_SIZE;
private static final int H = BOARD_SIZE * CELL_SIZE;
private static final double CYCLE_TIME_IN_MS = 5_000;
private final WritablePixelFormat<IntBuffer> pixelFormat =
PixelFormat.getIntArgbPreInstance();
private Canvas canvas = new Canvas(W, H);
private GraphicsContext gc = canvas.getGraphicsContext2D();
private int[] buffer = new int[W * H];
@Override
public void start(Stage stage) {
final long start = System.nanoTime();
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
double t =
((now - start) % (1_000_000 * CYCLE_TIME_IN_MS * 2)) /
(1_000_000.0 * CYCLE_TIME_IN_MS);
if (t > 1) t = 1 - (t - 1);
Color c1 = Color.RED.interpolate(Color.BLUE, t);
Color c2 = Color.BLUE.interpolate(Color.RED, t);
gc.clearRect(0, 0, W, H);
// Draw using fillRect
//
// for (int i = 0; i < W; i += CELL_SIZE) {
// for (int j = 0; j < H; j += CELL_SIZE) {
// gc.setFill(
// (i/CELL_SIZE + j/CELL_SIZE) % 2 == 0
// ? c1
// : c2
// );
// gc.fillRect(i, j, CELL_SIZE, CELL_SIZE);
// }
// }
// Draw using setColor
//
// PixelWriter p = gc.getPixelWriter();
// for (int i = 0; i < W; i += CELL_SIZE) {
// for (int j = 0; j < H; j += CELL_SIZE) {
// Color c =
// (i/CELL_SIZE + j/CELL_SIZE) % 2 == 0
// ? c1
// : c2;
// for (int dx = 0; dx < CELL_SIZE; dx++) {
// for (int dy = 0 ; dy < CELL_SIZE; dy++) {
// p.setColor(i + dx, j + dy, c);
// }
// }
// }
// }
// Draw using buffer
//
int ci1 = toInt(c1);
int ci2 = toInt(c2);
for (int i = 0; i < W; i += CELL_SIZE) {
for (int j = 0; j < H; j += CELL_SIZE) {
int ci =
(i/CELL_SIZE + j/CELL_SIZE) % 2 == 0
? ci1
: ci2;
for (int dx = 0; dx < CELL_SIZE; dx++) {
for (int dy = 0 ; dy < CELL_SIZE; dy++) {
buffer[i + dx + W * (j + dy)] = ci;
}
}
}
}
PixelWriter p = gc.getPixelWriter();
p.setPixels(0, 0, W, H, pixelFormat, buffer, 0, W);
}
};
timer.start();
stage.setScene(new Scene(new Group(canvas)));
stage.show();
}
private int toInt(Color c) {
return
( 255 << 24) |
((int) (c.getRed() * 255) << 16) |
((int) (c.getGreen() * 255) << 8) |
((int) (c.getBlue() * 255));
}
public static void main(String[] args) {
launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的程序在JavaFX PulseLogger打开的情况下运行了各种实现-Djavafx.pulseLogger=true
.如您所见,使用缓冲区设置PixelWriter中的像素比填充画布中的矩形快50倍,比调用PixelWriter上的setColor快100倍.
fillrect
//PULSE: 81 [217ms:424ms]
//T15 (58 +0ms): CSS Pass
//T15 (58 +0ms): Layout Pass
//T15 (58 +0ms): Update bounds
//T15 (58 +155ms): Waiting for previous rendering
//T15 (214 +0ms): Copy state to render graph
//T12 (214 +0ms): Dirty Opts Computed
//T12 (214 +209ms): Painting
//T12 (424 +0ms): Presenting
//Counters:
//Nodes rendered: 2
//Nodes visited during render: 2
Run Code Online (Sandbox Code Playgroud)
使用setColor的pixelwriter
//PULSE: 33 [370ms:716ms]
//T15 (123 +0ms): CSS Pass
//T15 (123 +0ms): Layout Pass
//T15 (123 +0ms): Update bounds
//T15 (123 +244ms): Waiting for previous rendering
//T15 (368 +0ms): Copy state to render graph
//T12 (368 +0ms): Dirty Opts Computed
//T12 (368 +347ms): Painting
//T12 (715 +0ms): Presenting
//Counters:
//Nodes rendered: 2
//Nodes visited during render: 2
Run Code Online (Sandbox Code Playgroud)
pixelwriter使用缓冲区
//PULSE: 270 [33ms:37ms]
//T15 (28 +0ms): CSS Pass
//T15 (28 +0ms): Layout Pass
//T15 (28 +0ms): Update bounds
//T15 (28 +0ms): Waiting for previous rendering
//T15 (28 +0ms): Copy state to render graph
//T12 (29 +0ms): Dirty Opts Computed
//T12 (29 +7ms): Painting
//T12 (36 +0ms): Presenting
//Counters:
//Nodes rendered: 2
//Nodes visited during render: 2
Run Code Online (Sandbox Code Playgroud)
这看起来像是一个标准问题:按像素绘制非常慢。绘制小矩形几乎是按像素进行的。
如果您直接在画布上绘图,请尝试 a BufferedImage
,它是一种正常内存数据结构,应该比访问显卡内存快得多。然后将图像绘制到它所属的位置。
int[] rgbArray
否则,通过手动设置像素并使用或类似方式绘制BufferedImage#setRGB
。
归档时间: |
|
查看次数: |
2830 次 |
最近记录: |