单游戏XNA低帧率从很少的Draw()调用



我一直在使用MonoGame将我在XNA上制作的一款滚动射击游戏移植到Linux上。几乎一切都很顺利,但我在调用SpriteBatch.Draw()时遇到了一个问题,影响了帧率。大部分游戏运行正常,没有任何问题。它可以在没有任何减速的情况下同时吸引大量敌人和大量子弹。然而,导致掉帧的部分是一个分层的滚动背景。代码的相关部分在这里。

Level.cs:

public void Draw(SpriteBatch spriteBatch)
{
    foreach (ScrollingBackgroundLayer sbl in scrollingBackground)
    {
        sbl.Draw(spriteBatch);
    }
}

上面的"scrollingBackground"是一个ScrollingBackgroundLayers列表,其相关部分如下:

ScrollingBackgroundLayers.cs:

Vector2[] scrollingBackgroundImages;
public float DrawLayer;
public ScrollingBackgroundLayer(GameScene newScene, Texture2D texture, float scrollSpeed, Color color)
{
    layerColor = color;
    layerSpeed = scrollSpeed;
    layerTexture = texture;
    thisScene = newScene;
    Initialize();
}
public void Initialize()
{
    scrollingBackgroundImages = new Vector2[2];
    for (int i = 0; i < 2; i++)
    {
        scrollingBackgroundImages[i] = new Vector2(0, thisScene.ScreenArea.Height - (layerTexture.Height * i));
    }
}

public void Update(GameTime gameTime)
{
    for (int i = 0; i < scrollingBackgroundImages.Length; i++)
    {
        scrollingBackgroundImages[i].Y += (float)gameTime.ElapsedGameTime.TotalSeconds * layerSpeed;
        if (layerSpeed > 0 && scrollingBackgroundImages[i].Y >= thisScene.ScreenArea.Height)
        {
            scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y - layerTexture.Height * 2));
        }
        else if (layerSpeed < 0 && scrollingBackgroundImages[i].Y + layerTexture.Height <= 0)
        {
            scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y + layerTexture.Height * 2));
        }
    }
}
public void Draw(SpriteBatch spriteBatch)
{
    foreach (Vector2 sb in scrollingBackgroundImages)
    {
        spriteBatch.Draw(layerTexture, sb, null, layerColor, 0f, Vector2.Zero, 1f, SpriteEffects.None, DrawLayer);
    }
}

所有的帧率问题都消失了,只要我注释了scrolllingbackgroundlayer . draw()的调用,所以这似乎是一个相当大的暗示,问题是来自SpriteBatch绘制滚动层的尝试。显然,我想弄清楚为什么会这样。我研究了SpriteBatch的其他一些问题,我发现最常见的问题可能是每当纹理改变时都会创建一个新的SpriteBatch,但即使将SpriteSortMode设置为texture也没有任何改进。

帧率下降发生在有7个不同ScollingBackgroundLayers的游戏阶段,每个ScollingBackgroundLayers绘制一个单独的纹理,大约700像素宽,900像素高(每个图层应该这样做不超过2次,以解释滚动效果)。我觉得我一定错过了一些明显的东西,因为游戏有时会使用完全相同的过载来渲染多达2-300颗子弹,所以另外14次调用应该是沧海一粟。这是一个简单的问题,试图绘制太大的纹理SpriteBatch有效处理?这在Windows版本上并不是一个问题,所以我想知道是否存在一些特定平台的解决方案,或者是否一夫一妻制的Draw执行效率低下。欢迎提供任何反馈。

完整的源代码供感兴趣的人使用:

Linux - https://github.com/cmark89/AsteroidRebuttal-Linux
Windows - https://github.com/cmark89/AsteroidRebuttal

编辑:我试着修补它多一点。我更改了Draw()的调用,以确保目标矩形等于屏幕的可绘制区域,但没有明显的变化。我将纹理换成了一个非常小的,这样就消除了延迟,所以我猜这确实与纹理的大小有关。

编辑2:好吧,我最后只是咬紧牙关,切断了我正在使用的透明层(像一些不懒惰的人一样)。它解决了这个问题,大概是因为它不再需要渲染大量无用的像素,但它仍然让我想知道为什么这个问题只在Linux上存在。尽管我已经暂时解决了我的问题,但我将把这个问题留一点时间,以防有人对可能导致巨大性能差异的原因有任何见解。

在这种情况下,我建议你使用着色器代替,以实现这一点。通过这样做,你会看到你的表现突飞猛进。看一下以下内容:

http://www.david-gouveia.com/scrolling-textures-with-zoom-and-rotation/

这样做,将减轻大量的CPU使用,并使你的GPU做大量的工作。

你可能还想以2的幂来存储你的纹理,而不是700x900。(设置为512x512)。你的图形管道具有与纹理相关的性能提升。

最新更新