我使用Java创建了一个应用程序,它在Windows平台上运行顺畅。但是,当我使用4960HQ在我的Macbook Pro Retina 15'上进行测试时,显示的帧速率要低得多。
我已经将程序编码为以60fps的恒定速度运行动画,控制台显示在Mac和Windows上都绘制了60fps。但是,Mac上的程序看起来像是以8-8fps运行。
是否有适合Mac的特殊编码方法?或者java根本没有针对Mac OSX进行优化?
代码的最小工作样本:
long framerate = 1000 / 60;
// time the frame began
long frameStart;
// number of frames counted this second
long frameCount = 0;
// time elapsed during one frame
long elapsedTime;
// accumulates elapsed time over multiple frames
long totalElapsedTime = 0;
// the actual calculated framerate reported
while(true){
frameStart = System.currentTimeMillis();
world.moveBG(3);
// calculate the time it took to render the frame
elapsedTime = System.currentTimeMillis() - frameStart;
// sync the framerate
try {
// make sure framerate milliseconds have passed this frame
if (elapsedTime < framerate) {
Thread.sleep(framerate - elapsedTime);
} else {
// don't starve the garbage collector
Thread.sleep(5);
}
} catch (InterruptedException e) {
break;
}
++frameCount;
totalElapsedTime += (System.currentTimeMillis() - frameStart);
if (totalElapsedTime > 1000) {
reportedFramerate = (long) ((double) frameCount
/ (double) totalElapsedTime * 1000.0);
// show the framerate in the applet status window
System.out.println("fps: " + reportedFramerate);
// repaint();
frameCount = 0;
totalElapsedTime = 0;
}
}
这段代码处理控制fps,现在设置为60fps。 world.moveBG(3)
以每帧3个像素的速度在屏幕上移动和图像(由于它是一个小图像,因此不应该是性能密集型的)。 Mac以明显的10fps运行,窗口平滑60.两台机器上的控制台显示正在绘制60fps。
要澄清一下,并不是说Mac上的屏幕上的图像移动速度比Windows慢,而是Mac上的移动速度非常不稳定
答案 0 :(得分:1)
下一个代码启动执行程序并安排任务以完成帧速率。 在Windows上运行3秒钟,我的最后一条跟踪指示了179个任务,因此几乎每秒需要执行60个任务。
尝试使用此代码并告知我是否可以提高您的效果:
package com.nosolojava.test;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FrameRateExecutor {
private final Logger logger = Logger.getLogger(this.getClass().getCanonicalName());
final static long framerate = 1000 / 60;
// number of frames counted this second
AtomicInteger frameCount = new AtomicInteger(0);
ScheduledExecutorService executor;
private volatile AtomicBoolean running = new AtomicBoolean(false);
class Task implements Runnable {
private final long lastTaskTimeStamp;
public Task() {
super();
//get creation time so we can calculate delay after
this.lastTaskTimeStamp = System.currentTimeMillis();
}
public void run() {
// TODO implement logic
logger.log(
Level.INFO,
String.format("Do something, framecount: %02d %d", frameCount.addAndGet(1),
System.currentTimeMillis()));
//calculate when to execute next task and submit
long currentTime = System.currentTimeMillis();
long elapsed = currentTime - lastTaskTimeStamp;
long delay = (framerate - elapsed) +framerate;
logger.log(Level.INFO, String.format("elapsed %04d delay %04d", elapsed, delay));
//check finish condition
if (running.get()) {
executor.schedule(new Task(), delay, TimeUnit.MILLISECONDS);
}
}
};
public void stop() {
running.set(false);
executor.shutdown();
try {
executor.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Error stopping executor", e);
}
}
public void start() {
//check if is already up
if (this.running.compareAndSet(false, true)) {
//init scheduled executor
executor = new ScheduledThreadPoolExecutor(1);
//start first task
executor.execute(new Task());
}
}
public static void main(String[] args) throws InterruptedException {
FrameRateExecutor frameExecutor = new FrameRateExecutor();
frameExecutor.start();
Thread.sleep(3000);
frameExecutor.stop();
}
}