I've looked at a few threads related to this question, in particular here and here however The first one was asked many years ago (before java 7 even I think) and the second one is asking about a simplified case of drawing a single color which has a much better solution that was provided, namely using Graphics.fillRect
.
I also did try out some of the suggestions made in the first thread, such as using a compatible image format in my case I was already using it (TYPE_INT_ARGB
) and I also tried telling java to use openGL; this one had the cool result of rendering most of my application as a black window...
So here I am asking the question again in hopes of getting a better solution to this issue.
So here is the issue:
I am working on an application that needs to draw a new auto generated and constantly changing image based on user interaction. The user interaction tends to run at an abysmal 4-10fps and I narrowed the culprit down to a call to Graphics2D.drawImage
this function starts out running in a reasonable time, less than 10 milliseconds but quickly, as in after the first 2-3 calls, increases to more than 250 milliseconds. The image itself is can vary in size but in my testing was consistently less than 1000x1000 pixels and is a BufferedImage
using type TYPE_INT_ARGB
which is the compatible type for my system. Any help on this would be greatly appreciated!
As requested here is a minimal reproducible example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class LowFPS {
public static final int SIZE = 700;
public static final BufferedImage image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_RGB);
public static void main(String args[]) {
JFrame frame = new JFrame("Low FPS Example");
JComponent view = new ImageComponent();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(view, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static class ImageComponent extends JComponent {
public ImageComponent() {
setPreferredSize(new Dimension(SIZE, SIZE));
setOpaque(true);
addMouseMotionListener(
new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
double start = System.nanoTime()/1e9;
int raster[] = new int[SIZE*SIZE];
int g = 0;
Random rand = new Random();
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
g = rand.nextInt(156)+100;
raster[SIZE*j+i] = (0xff << 24) | (g << 16) | (g << 8) | g;
}
}
synchronized(image) {
image.getRaster().setDataElements(
0, 0, SIZE, SIZE, raster
);
}
double stop = System.nanoTime()/1e9;
System.out.printf("generate time: %f\n", stop-start);
ImageComponent.this.repaint();
}
}
);
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
synchronized(image) {
double start = System.nanoTime()/1e9;
g2.drawImage(image, null, 0, 0);
double stop = System.nanoTime()/1e9;
System.out.printf("draw time: %f\n", stop-start);
}
}
}
}
and here is some output I got from running this:
draw time: 0.005215
draw time: 0.003509
generate time: 0.025820
generate time: 0.009886
draw time: 0.001034
generate time: 0.008111
generate time: 0.007449
draw time: 0.000753
generate time: 0.005950
generate time: 0.005828
draw time: 0.000670
generate time: 0.005807
generate time: 0.005737
draw time: 0.000619
generate time: 0.005666
draw time: 0.000657
generate time: 0.005559
draw time: 0.000530
generate time: 0.005521
draw time: 0.000508
generate time: 0.005455
draw time: 0.000487
generate time: 0.005410
draw time: 0.002473
generate time: 0.005392
generate time: 0.005406
draw time: 0.011764
generate time: 0.006291
generate time: 0.006608
draw time: 0.042349
generate time: 0.016228
generate time: 0.010290
draw time: 0.111547
generate time: 0.016587
generate time: 0.010646
draw time: 0.240194
generate time: 0.016043
generate time: 0.010762
draw time: 0.125226
generate time: 0.016076
generate time: 0.010350
draw time: 0.104254
generate time: 0.015372
generate time: 0.009877
draw time: 0.234022
generate time: 0.016878
generate time: 0.010765
draw time: 0.103371
generate time: 0.015868
generate time: 0.010262
draw time: 0.232200
generate time: 0.015839
generate time: 0.009695
draw time: 0.118478
generate time: 0.015144
generate time: 0.009925
draw time: 0.100979
generate time: 0.015897
generate time: 0.010610
draw time: 0.245413
generate time: 0.015212
generate time: 0.009755
draw time: 0.123311
generate time: 0.014929
generate time: 0.009887
draw time: 0.115697
generate time: 0.016013
generate time: 0.010928
draw time: 0.251448
generate time: 0.015607
generate time: 0.010624
draw time: 0.117246
generate time: 0.015960
generate time: 0.010239
draw time: 0.117721
generate time: 0.016382
generate time: 0.010506
draw time: 0.122491
generate time: 0.015746
generate time: 0.010153
draw time: 0.117414
generate time: 0.015598
generate time: 0.010362
draw time: 0.117872
generate time: 0.015859
generate time: 0.010637
draw time: 0.113869
generate time: 0.016953
generate time: 0.010780
draw time: 0.111810
generate time: 0.016389
generate time: 0.010655
draw time: 0.246486
generate time: 0.016682
generate time: 0.010737
draw time: 0.121975
generate time: 0.015779
generate time: 0.010437
draw time: 0.125625
generate time: 0.016359
generate time: 0.010636
draw time: 0.221910
generate time: 0.016156
generate time: 0.010369
draw time: 0.122495
generate time: 0.016397
generate time: 0.010612
draw time: 0.238445
generate time: 0.015114
generate time: 0.009899
draw time: 0.113739
generate time: 0.015389
generate time: 0.010127
draw time: 0.126756
generate time: 0.018503
generate time: 0.011559
draw time: 0.243606
generate time: 0.016405
generate time: 0.010426
draw time: 0.116460
generate time: 0.015355
generate time: 0.010080
draw time: 0.119474
generate time: 0.016397
generate time: 0.010536
draw time: 0.258496
generate time: 0.015853
generate time: 0.010504
draw time: 0.102392
generate time: 0.021260
generate time: 0.009640
draw time: 0.121522
generate time: 0.015351
generate time: 0.009437
draw time: 0.119224
generate time: 0.015698
generate time: 0.010410
draw time: 0.113848
generate time: 0.014471
generate time: 0.009880
draw time: 0.241783
generate time: 0.016351
generate time: 0.010552
draw time: 0.127653
generate time: 0.016064
generate time: 0.010969
draw time: 0.127003
generate time: 0.014897
generate time: 0.009697
draw time: 0.251630
generate time: 0.015527
generate time: 0.010259
draw time: 0.111767
generate time: 0.015485
generate time: 0.010329
draw time: 0.123999
generate time: 0.014251
generate time: 0.009680
draw time: 0.239466
generate time: 0.015720
generate time: 0.011239
draw time: 0.112809
generate time: 0.015376
generate time: 0.010115
draw time: 0.113489
generate time: 0.015563
generate time: 0.010294
draw time: 0.117295
generate time: 0.013725
generate time: 0.009450
draw time: 0.123859
generate time: 0.014134
generate time: 0.009614
draw time: 0.237366
generate time: 0.014752
generate time: 0.010723
draw time: 0.120068
generate time: 0.014044
draw time: 0.129768
As you can see the generation time is capable of supporting at a minimum 50fps however the time it takes to draw the image is reducing the frame rate to about 8fps.