Низкая частота кадров Monogame XNA из-за нескольких вызовов Draw ()

Я портировал шутер со скроллингом, созданный на XNA, на Linux с помощью MonoGame. Почти все прошло гладко, но у меня в одном месте проблема с вызовами 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, каждый из которых рисует отдельную текстуру шириной около 700 пикселей и высотой 900 пикселей (каждый слой должен делать это не более 2 раз, чтобы учесть эффект прокрутки). . Я чувствую, что мне не хватает чего-то очевидного, потому что игра иногда отображает до 2-300 пуль, используя ту же самую перегрузку, поэтому еще 14 вызовов должны быть каплей в море. Это просто проблема с попыткой нарисовать текстуры, слишком большие для того, чтобы SpriteBatch мог эффективно справиться с ними? Это не проблема для версии для Windows, поэтому мне интересно, нет ли какого-либо обходного пути для конкретной платформы, или реализация Draw в MonoGame просто неэффективна. Любые отзывы приветствуются.

Полный исходный код для заинтересованных:

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

Изменить: я попытался немного повозиться с этим. Я изменил вызов на Draw (), чтобы убедиться, что целевой прямоугольник равен доступной для рисования области экрана, но заметных изменений не произошло. Я поменял текстуру на очень маленькую, и это устранило задержку, так что я предполагаю, что это как-то связано с размером текстуры.

Редактировать 2: Хорошо, я закончил тем, что просто укусил пулю и разрезал слои прозрачности, которые я использовал (как какой-то не-ленивый парень). Он решил проблему, по-видимому, поскольку ему больше не нужно отображать огромное количество бесполезных пикселей, но он все еще заставляет меня задуматься, почему это проблема только в Linux. Несмотря на то, что я решил свою проблему на данный момент, я собираюсь оставить это открытым на всякий случай, если кто-то знает, что может вызвать резкую разницу в производительности.


person cmark89    schedule 07.06.2013    source источник
comment
Я не могу вспомнить затраты на производительность для разных вещей, но заставлять графический процессор рисовать столько текстур с высоким разрешением, вероятно, не очень хорошая идея, и вы должны иметь возможность создавать по-другому. Если память мне не изменяет, эти текстуры в конечном итоге будут текстурами 1024 * 1024 (из-за требования мощности 2 и преобразования в этот размер во время выполнения) при отправке на графический процессор.   -  person Daniel MesSer    schedule 07.06.2013
comment
Проблема в этом случае заключается в том, что каждое изображение фона прокручивается с разной скоростью или имеет разный уровень прозрачности. Некоторые из них я определенно мог бы разделить и создать слои, которые прорисовывают меньшие области экрана, но некоторые из них (в основном слои прозрачности) не так просты. Я не знал, что графический процессор все равно изменял размер без питания двух текстур; возможно, я изменю их размер и посмотрю, изменится ли что-нибудь. Независимо от оптимизаций, которые я собираюсь сделать, я действительно не понимаю, почему эта проблема не возникает в Windows.   -  person cmark89    schedule 07.06.2013


Ответы (1)


В этой ситуации я бы посоветовал вам вместо этого использовать шейдер для достижения этой цели. Сделав это, вы увидите, как ваша производительность взлетит до небес. Взгляните на следующее:

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

Это снизит нагрузку на ЦП и заставит ваш графический процессор выполнять основную часть работы.

Вы также можете сохранить свои текстуры в степени 2 вместо 700x900. (сделайте что-нибудь вроде 512x512). У вашего графического конвейера есть прирост производительности, связанный с текстурами, имеющими степень двойки.

person jgallant    schedule 07.06.2013
comment
Я изучаю это, но это может быть излишним для того, что мне нужно сделать. Может быть, это просто потому, что меня пугают шейдеры. Я вернусь к вам, когда у меня будет возможность попробовать это. - person cmark89; 07.06.2013
comment
Это не перебор, уверяю вас, это очень просто. Вам даже не нужно ничего знать о шейдерах, чтобы это работало;) - person jgallant; 07.06.2013
comment
Я не дошел до того, чтобы попробовать это, так как в итоге я просто использовал более простую работу, но поскольку это единственный ответ, я помечаю его как принятый. Это действительно выглядит как очень хорошее решение, если вы можете заставить файл эффекта работать (косвенно, очевидно, что это что-то вроде испытания с текущей версией MonoGame, поэтому я не пробовал его). - person cmark89; 10.06.2013
comment
Ты прав. Попытка написать собственные шейдеры в моноигре на данный момент немного изворотлива. Я вообще-то думаю, что этот конкретный шейдер даже с ним несовместим. - person jgallant; 10.06.2013
comment
Это позор. Это показалось отличной идеей для реализации в другом проекте. Надеюсь, в будущем совместимость шейдеров получит большее развитие. Тогда у меня будет больше стимулов перестать бояться их. - person cmark89; 10.06.2013