当前位置: 首页 > 知识库问答 >
问题:

奇怪的缓冲策略问题-游戏仅在英特尔GPU上运行速度快

莫骞仕
2023-03-14

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

我试图通过三重/双缓冲提高性能,但遇到了一些问题。

我的第一次尝试是与JPanel的游戏是绘制。我在JFrame的类(Main)中设置了缓冲区,然后在Game(extends JPanel)类中完成了绘图,但是没有图形g=bufferstrategy。getDrawGraphics();。然后,在绘图方法的最后,我显示了缓冲区,如果它没有丢失。缓冲区总是“丢失”,因为我没有用它的图形对象绘制。但是游戏跑得飞快!实际使用中没有缓冲区!但是怎么做呢?

这一尝试最终没有出现图形错误,并带来了巨大的性能提升——但仅限于nVidia/AMD卡。英特尔GPU无法处理此问题,屏幕呈白色闪烁。

因此,我最终正确地设置和使用了缓冲策略。Game类现在扩展了Canvas,而不是JPanel,因为它从JFrame中获取图形,并使用它在JPanel上绘制,最终会出现偏移,就像它在标题栏下绘制一样。仍然很快,修正每秒60帧。

现在,当我在JFrame(Main类)中创建BufferStrategy时,根本没有图片。我通过在游戏类(画布)中设置缓冲策略来纠正这一点。图片现在是正确的,但游戏本身却慢得像蜗牛。一次爆炸将FPS撕裂至约10,但仅限于nVidia/AMD。讽刺。即使旧的英特尔GPU处理它与60 FPS,我设法得到10000粒子运动在60 FPS在一个5-6岁的集成英特尔GPU.当爆炸发生时,我的卡会碰撞到100%的负载。

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

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.getDefaultConfigurathtml" target="_blank">ion();

    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()。

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

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

“快速”计算机:英特尔Core 2 Duo@2.7 GHz,集成英特尔图形,2 GB内存

谢谢你的帮助和时间!:)

编辑你的年龄能帮上忙吗?如果我知道的没错,图像处理必须使用BuffereImage来完成,但是绘制它们很慢。

共有3个答案

阮炯
2023-03-14

当你把东西发送到GPU时,GPU会从GDRAM中读取信息。如果通过调用getDrawGraphics将数据读入内存,那么内存可能会从图形卡读回RAM。CPU只能访问RAM(DRAM),GPU只能访问GDRAM。然而,对于板载GPU,这是不同的,因为它们没有自带RAM,它们使用常规RAM的一部分。

要使代码快速运行,请确定您拥有的硬件,然后相应地调用相应的方法(代码更改前的方法或代码更改后的方法)。

袁奇文
2023-03-14

检查图片与缓存的大小,并尝试诊断缓存未命中的数量。阅读面向数据的设计,这通常是其中的一部分。

另一种方法是将爆炸方式改为不加载200个精灵并将其分散(是重复使用它们,还是每次爆炸时都加载它们?)。制作一个动画爆炸需要更少的能量,虽然它可能没有那么壮观,你需要做一些动画。

Java也不是制作游戏的最佳语言。你的工作水平很高,而JVM会让事情慢一点。我的朋友们在制作小游戏时也遇到了类似的问题,很难制作一个没有延迟的游戏。

元胡媚
2023-03-14

这里有几件事要检查:

如果不知道setBuffers函数的控制台/错误输出,很难判断。Intel是否使用createBufferStrategy(2);而NV使用createBufferStrategy(3);?如果是这样,那可能是使用额外内存的部分问题。

你试过java2d系统吗。有房子了吗?http://docs.oracle.com/javase/1.5.0/docs/guide/2d/flags.html特别是用于调试的跟踪属性。

只有窗户

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]

工具箱。getDefaultToolkit()。sync();实际上并不强制监视VSync,这是由BufferCapabilities(在setBuffers函数中)完成的。

    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)

此外,应该在画布构造函数运行并添加到JFrame之后调用setBuffers。

我“相对确定”你不需要叫super。油漆(g);我不知道这是否是导致您的特定问题的原因,但您应该从绘制功能中删除该行。

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

 类似资料:
  • 问题内容: 我是Java的新手。我想做一个游戏。经过大量研究,我不了解缓冲策略的工作原理。.我了解基础知识..它创建了一个屏幕外图像,您以后可以将其放入Windows对象中。 我不知道..我已经研究了很长时间了..根本没有运气..我不知道..也许所有的东西都在里面,而且它很清楚很简单,我我太愚蠢而看不见.. 感谢所有的帮助.. :) 问题答案: 运作方式如下: 该构造了一个当你调用。该知道它属于那

  • 根据Karpath的RL教程,我正在尝试为游戏2048实现一个策略网络代理。我知道算法将需要玩一些游戏,记住输入和采取的行动,规范化和平均中心的结局分数。然而,我在损失函数的设计上陷入了困境。如何正确地鼓励最终得分较高的行为,并阻止最终得分较低的行为? 当在输出层使用softmax时,我沿着这个设计了一些东西: 其中,操作采用一种热格式。然而,这一损失似乎没有多大作用,网络没有学到什么。我在PyT

  • 我刚刚购买了RX2070,安装了microsoft visual studio,然后是CUDA,然后是cuDNN。在此之后,我安装了anaconda并发出命令 pip安装tensorflow gpu pip安装keras 从理论上讲,使用tensorflow gpu的功能版本,我尝试运行在cpu版本下工作的神经网络,出现了以下错误。 在尝试导入tensorflow时,也会出现相同的错误 File"

  • 我无法在最简单的JSF2.2页面上使用侦听器。赋值,但监听器是聋子。奇怪的是,如果我将替换为,同样的代码工作得非常好。下面是HTML: 对于两种侦听器方法类型都不触发。将bean制作为和使用不同的ajax事件类型也无济于事。 该问题出现在Apache Tomee升级到7.0.1版本(MyFaces 2.2.10,JSF 2.2)之后。MyFaces到2.2.11也有同样的问题。 web应用程序绑定

  • 对标岗位:系统策划、关卡策划 游戏品类:MOBA,射击,电竞 对标游戏:Valorant,守望先锋,彩六围攻,Apex 不整花活,单刀直入。 问题1(游戏机制与平衡):分析其干员设计的平衡性。如果有不平衡的情况存在,你将如何调整以达到更好的平衡? 问题2(用户体验):某些干员的技能可能对新手来说过于复杂。你认为游戏应该如何调整以降低入门难度,同时保持深度和复杂性? 问题3(赛季内容更新):定期更新