奇怪的BufferStrategy问题 - 游戏仅在英特尔GPU上运行速度很快 [英] Strange BufferStrategy issue - Game runs fast only on Intel GPUs

查看:187
本文介绍了奇怪的BufferStrategy问题 - 游戏仅在英特尔GPU上运行速度很快的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个非常奇怪的问题,我试着寻找几天和几天的答案。
我的游戏刚刚获得了一个新的粒子系统,但速度太慢而无法播放。不幸的是,BufferedImage转换非常慢。爆炸效果包括从.png文件加载的大约200个白色精灵,随机旋转,缩放和着色,以随机速度移动。

I ran into a very strange problem, I tried searching for an answer for days and days. My game just got a new particle system, but was too slow to be playable. Unfortunately, BufferedImage transformations are very slow. The explosion effect consists of about 200 white sprites loaded from a .png file, rotated, scaled and coloured randomly, moving with a random speed.

我试图提高性能更好的三重/双重缓冲,并遇到一些问题。

I tried to make the performance better with triple / double buffering, and ran into some problems.

我的第一次尝试是使用JPanel进行游戏。我在JFrame的类(Main)中设置缓冲区,然后在Game(扩展JPanel)类中完成绘图,但没有Graphics g = bufferstrategy.getDrawGraphics();.然后,在绘图方法结束时,我显示缓冲区IF没有丢失。缓冲区总是丢失,因为我没有使用它的Graphics对象进行绘图。但!游戏运行得和地狱一样快!在实际使用中没有缓冲!但是如何?

My first try was with the JPanel the game was drawn on. I set up the buffers in the JFrame's class (Main), then done the drawing in the Game (extends JPanel) class, BUT, without Graphics g = bufferstrategy.getDrawGraphics();. Then, at the end of the drawing method, i showed the buffer IF it wasn't lost. The buffer was always "lost", as I didn't do the drawing with it's Graphics object. But! The game run as fast as hell! With no buffer in practical use! But how?

这次尝试最终没有出现图形错误,并且性能提升很大 - 但仅限于nVidia / AMD显卡。英特尔GPU无法处理此问题,屏幕呈现白色闪烁。

This try ended up with no graphical errors, and with a HUGE performance boost - but only on nVidia / AMD cards. Intel GPUs couldn't handle this, the screen was flashing white.

因此,我最终设置并正确使用BufferStrategy。
Game类现在扩展Canvas,而不是JPanel,因为从JFrame获取Graphics,并且使用它在JPanel上绘制最终会产生偏移,因为它是在标题栏下绘制的。仍然很快,修复60 FPS。

So, i ended up setting and using the BufferStrategy correctly. The Game class now extends Canvas, not JPanel, as getting the Graphics from a JFrame, and using it to draw on a JPanel ends up in an offset, as it is drawing under the title bar. Still fast, fix 60 FPS.

现在,当我在JFrame(主类)中创建BufferStrategy时,根本没有图片。我通过在Game类(Canvas)中设置BufferStrategy来纠正这个问题。图片现在是正确的,但游戏本身就像蜗牛一样慢。一次爆炸使FPS下降至~10,但仅限于nVidia / AMD。具有讽刺意味的。即使是老式的英特尔GPU也能以60 FPS处理它,我还是在一台具有5到6年历史的集成英特尔GPU上以60 FPS的速度运行了10000个粒子。发生爆炸时,我的卡会出现100%的负载。

Now, when i created the BufferStrategy in the JFrame (Main class), there was no picture at all. I corrected this by setting up the BufferStrategy in the Game class (Canvas). The picture is correct now, but the game itself is slow like a snail. One explosion tears the FPS down to ~10, but only on nVidia / AMD. Ironic. Even old Intel GPUs handle it with 60 FPS, i managed to get 10000 particles in motion at 60 FPS on a 5-6 year old integrated Intel GPU. My card bumps up to 100% load when an explosion occurs.

这是我的主要代码(整个代码不清楚且很长):

Here is my major code (the whole code is unclear and long) :

public class Game extends Canvas {
 -snip-
 public void tick() {
    BufferStrategy bf = getBufferStrategy();
    Graphics g = null;
    try {
        g = bf.getDrawGraphics();
        paint(g);
    } finally {
        g.dispose();
    }
    if (!bf.contentsLost()) {
        bf.show();
    } else {
        System.err.println("Buffer lost!");
    }
    Toolkit.getDefaultToolkit().sync();
 }
 public void setBuffers() {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gs = ge.getDefaultScreenDevice();
    GraphicsConfiguration gc = gs.getDefaultConfiguration();

    if (gc.getBufferCapabilities().isMultiBufferAvailable()) {
        createBufferStrategy(3);
        System.out.println("Triple buffering active");
    } else {
        createBufferStrategy(2);
        System.err.println("Triple buffering not supported by the GPU");
        System.out.println("Double buffering active");
    }
    System.out.println("FullScreen required: " + getBufferStrategy().getCapabilities().isFullScreenRequired());
    System.out.println("Page flipping: " + getBufferStrategy().getCapabilities().isPageFlipping());
 }
 public void paint(Graphics g) {
    super.paint(g);
    //set up RenderingHints, draw stuff
 }
 -snip snip-
}

当然,我在游戏开始后立即调用setBuffers()。

Of course, I call setBuffers() as soon as the Game is started.

我希望你能帮助我,这个问题是非常重要,因为在我看来使用VolatileImage不会提升性能,因为需要使用BufferedImage完成图像处理。我打赌我错过了一些微不足道的事情,或者做错了事。

I hope you can help me, this problem is very important, as using VolatileImage in my opinion won't give a performance boost, as image manipulating needs to be done using BufferedImage. I bet I'm missing something trivial, or doing something the wrong way.

这是我的电脑规格,只是为了表明它不是硬件问题:
英特尔酷睿i7-3770k @ 4.3GHz,
nVidia GTX 460,
12 GB内存

Here are my computer specs, just to show it's not a hardware problem: Intel Core i7-3770k @ 4.3GHz, nVidia GTX 460, 12 GB ram

快速电脑:
英特尔Core 2 Duo @ 2.7 GHz,
集成Intel Graphics,
2 GB ram

The "fast" computer: Intel Core 2 Duo @ 2.7 GHz, Integrated Intel Graphics, 2 GB ram

感谢您的帮助和时间! :)

Thank you for your help and time! :)

编辑
VolatileImage有帮助吗?如果我知道的话,必须使用BufferedImages进行图像处理,但是绘制它们是缓慢的。

EDIT Could VolatileImage help? If I know right, image manipulation must be done using BufferedImages, but drawing them is sluggish.

推荐答案

这里有几件事需要检查:

Here's a few things to check:

在不知道setBuffers函数的控制台/错误输出的情况下,很难说清楚。英特尔是否使用createBufferStrategy(2);而NV使用createBufferStrategy(3); ?如果是这样可能是使用额外内存的问题的一部分。

Without knowing the console/error output of your setBuffers function it's difficult to tell. Is Intel using createBufferStrategy(2); while NV uses createBufferStrategy(3); ? if so that could be part of the issue with it using extra memory.

您是否尝试过java2d System.properties ? http://docs.oracle.com/javase/1.5 .0 / docs / guide / 2d / flags.html 特别是用于调试的trace属性。

Have you tried the java2d System.properties yet? http://docs.oracle.com/javase/1.5.0/docs/guide/2d/flags.html Especially the trace property for debugging.

仅限Windows

System.setProperty("sun.java2d.transaccel", "True");
System.setProperty("sun.java2d.d3d", "True");
System.setProperty("sun.java2d.ddforcevram", "True");

所有平台

System.setProperty("sun.java2d.opengl", "True");

用于调试

System.setProperty("sun.java2d.trace", "timestamp,log,count");
//// -Dsun.java2d.trace=[log[,timestamp]],[count],[out:<filename>],[help],[verbose]






Toolkit.getDefaultToolkit()。sync();实际上并没有强制监视VSync,这是由BufferCapabilities(在你的setBuffers函数中)完成的。


Toolkit.getDefaultToolkit().sync(); doesn't actually force monitor VSync, that's done by BufferCapabilities (in your setBuffers function).

    BufferStrategy bf = getBufferStrategy();
    if (bf != null) {
        BufferCapabilities caps = bf.getCapabilities();
        try {
            Class ebcClass = Class.forName(
                "sun.java2d.pipe.hw.ExtendedBufferCapabilities");
            Class vstClass = Class.forName(
                "sun.java2d.pipe.hw.ExtendedBufferCapabilities$VSyncType");

            Constructor ebcConstructor = ebcClass.getConstructor(
                new Class[] { BufferCapabilities.class, vstClass });
            Object vSyncType = vstClass.getField("VSYNC_ON").get(null);

            BufferCapabilities newCaps = (BufferCapabilities)ebcConstructor.newInstance(
                new Object[] { caps, vSyncType });

            createBufferStrategy(2, newCaps);

            // TODO: if success, setCanChangeRefreshRate(false) and setRefreshRate(60). 
            // Possibly override refreshRateSync()?
        }
        catch (Throwable t) {
            // Ignore
            t.printStackTrace();
        }
    }

编辑此代码原为来自( http://pulpcore.googlecode.com /hg-history/3c4001969922b93048e0a166395115df059a2059/src/pulpcore/platform/applet/BufferStrategySurface.java

此外,你应该在Canvas构造函数之后调用setBuffers运行,它已被添加到JFrame。

Also, you should be calling setBuffers AFTER the Canvas constructor has run and it's been added to the JFrame.

我相对肯定你不需要打电话给超级.paint(克);我不知道它是什么导致你的具体问题,但你应该从你的绘画功能中删除该行。

I'm "relatively sure" you don't need to call super.paint(g); I don't know if its what's causing your specific issue, but you should remove the line from your paint function.

虽然您没有显示代码,但使用200个随机移动的精灵的爆炸机制可能是导致错误的主要原因。计算出您希望一次在屏幕上显示的最大爆炸次数,并在手工生成这些精灵N * 200之前,将它们放入数组列表ArrayList(N)中,然后在您的代码中循环引用它们。 ExplosionClass = explosionList.get(currentExplosionIndex%explosionList.size());

Though you don't show the code, your explosion mechanism using 200 randomly moving sprites could be a major cause for errors. Figure out the maximum number of explosions you want to have on the screen at one time and generate those sprites N * 200 before hand, put them in an array list ArrayList(N) and then in your code reference them cyclically. ExplosionClass = explosionList.get(currentExplosionIndex % explosionList.size());

这篇关于奇怪的BufferStrategy问题 - 游戏仅在英特尔GPU上运行速度很快的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆