Monogame XNA从少量Draw()调用中获得低帧率

时间:2013-06-07 09:07:30

标签: xna draw frame-rate monogame spritebatch

我一直在使用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);
    }
}

一旦我注释掉对ScrollingBackgroundLayer.Draw()的调用,所有的帧速率问题都会消失,所以这似乎是一个非常大的暗示,这个问题来自SpriteBatch尝试绘制滚动图层。显然,我想弄清楚为什么会这样。我查看了SpriteBatches的其他一些问题,我发现可能指向答案的最常见的事情是每当纹理发生变化时都会创建一个新的SpriteBatch,但即使将SpriteSortMode设置为Texture也没有任何改进。

帧速率下降发生在游戏的一个舞台上,该游戏有7个不同的ScollingBackgroundLayers,每个ScollingBackgroundLayers绘制一个大约700像素宽和900高的单独纹理(每层应该这样做不超过2次来解释滚动效果)。我觉得我必须遗漏一些明显的东西,因为游戏有时使用完全相同的重载渲染多达2-300个子弹,所以另外14个调用应该是一个下降。这只是一个问题,试图绘制太大的纹理,以便SpriteBatch有效处理?这不是Windows版本的问题,所以我想知道是否有一些特定于平台的解决方法,或者如果MonoGame的Draw实现效率低下。任何反馈都会受到欢迎。

感兴趣的人的完整资料来源:

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

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

编辑2:好吧,我最终只是咬着子弹并切断了我正在使用的透明层(就像某种不懒的人)。它解决了这个问题,大概是因为它不再需要渲染大量无用的像素,但它仍然让我想知道为什么这只是Linux上的一个问题。即使我暂时解决了我的问题,我还是会暂时保留这个问题,以防任何人对可能导致性能差异的原因有任何见解。

1 个答案:

答案 0 :(得分:2)

在这种情况下,我建议您使用着色器,以实现此目的。通过这样做,你会看到你的表现飙升。看看以下内容:

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

这样做可以减轻大量的CPU使用,并使GPU完成大部分工作。

您可能还希望将纹理存储为2的幂,而不是700x900。 (做512x512之类的事情)。您的图形管道具有与功率为2的纹理相关的性能提升。