Как масштабировать до разрешения в SDL?

Я пишу 2D-платформерную игру, используя SDL с С++. Однако я столкнулся с огромной проблемой, связанной с масштабированием до разрешения. Я хочу, чтобы игра выглядела хорошо в полном HD, поэтому все изображения для игры были созданы так, чтобы естественное разрешение игры было 1920x1080. Однако я хочу, чтобы игра уменьшалась до правильного разрешения, если кто-то использует меньшее разрешение или масштабируется больше, если кто-то использует большее разрешение.

Проблема заключается в том, что я не смог найти эффективный способ сделать это. Я начал с использования библиотеки SDL_gfx для предварительного масштабирования всех изображений, но это не работает, поскольку оно создает много автономных, одна ошибка, когда один пиксель терялся. И поскольку мои анимации содержатся в одном изображении, когда анимация будет воспроизводиться, анимация будет слегка перемещаться вверх или вниз по каждому кадру.

Затем, после некоторого оглядки, я попытался использовать opengl для обработки масштабирования. В настоящее время моя программа рисует все изображения на SDL_Surface, которая составляет 1920x1080. Затем он преобразует эту поверхность в текстуру opengl, масштабирует эту текстуру до разрешения экрана, затем рисует текстуру. Это прекрасно работает визуально, но проблема в том, что он неэффективен вообще. В настоящее время я получаю max fps 18: (

Итак, мой вопрос: кто-нибудь знает об эффективном способе масштабирования отображения SDL на разрешение экрана?

Ответ 1

Это неэффективно, потому что OpenGL не был разработан таким образом. Основные проблемы с производительностью:

  • Первая проблема: вы растрируете программное обеспечение с помощью SDL. Извините, но независимо от того, что вы делаете с этой конфигурацией, это будет узким местом. При разрешении 1920x1080 у вас есть 2073,600 пикселей для цвета. Предполагая, что вам потребуется 10 тактов, чтобы затенять каждый 4-канальный пиксель, на процессоре 2 ГГц вы используете максимум 96,4 кадра в секунду. Это не звучит плохо, за исключением того, что вы, вероятно, не можете быстро отбрасывать пиксели, и вы до сих пор не сделали AI, пользовательский ввод, игровую механику, звук, физику и все остальное, и вы, вероятно, рисуете несколько пикселей хотя бы один раз. SDL_gfx может быть быстрым, но для больших разрешений CPU просто полностью перегружен.
  • Вторая проблема: каждый кадр, вы копируете данные через графическую шину на графический процессор. Это самая медленная вещь, которую вы можете сделать с графикой. Данные изображения, вероятно, хуже всего, потому что обычно их так много. В принципе, каждый кадр, который вы сообщаете графическому процессору, копирует два миллиона некоторых пикселей из ОЗУ в VRAM. Согласно Wikipedia, вы можете ожидать, что для 2 073 600 пикселей по 4 байта каждый, не более 258,9 кадров в секунду, что опять не звучит плохо пока вы не вспомните все остальное, что вам нужно сделать.

Моя рекомендация: полностью переключите приложение на OpenGL. Это устраняет необходимость визуализации текстуры и копирования на экран - просто визуализируйте непосредственно на экран! Кроме того, масштабирование обрабатывается автоматически с помощью вашей матрицы представлений (glOrtho/gluOrtho2D для 2D), поэтому вам вообще не нужно заботиться о проблеме масштабирования - ваш видовой экран будет показывать все в одном масштабе. Это идеальное решение вашей проблемы.

Теперь он имеет один главный недостаток: вам нужно перекодировать все с помощью команд рисования OpenGL (что работает, но не слишком сложно, особенно в конечном итоге). Кроме того, вы можете попробовать следующие идеи для повышения скорости:

  • ОПО. Объекты буфера пикселов могут использоваться для решения проблемы два путем создания/копирования текстур асинхронными.
  • Многопоточность рендеринга. Большинство процессоров имеют как минимум два ядра, а на более новых чипах можно сохранить два состояния регистров для одного ядра (Hyperthreading). Вы по сути дублируете то, как GPU решает проблему рендеринга (имеет много потоков). Я не уверен, насколько безопасен поток SDL_gfx, но я уверен, что что-то может быть выработано, особенно если вы работаете одновременно с разными частями изображения.
  • Удостоверьтесь, что вы обращаете внимание на то, в каком месте ваша поверхность рисования находится в SDL. Вероятно, это должно быть SDL_SWSURFACE (потому что вы используете CPU).
  • Удалить VSync. Это может повысить производительность, даже если вы не работаете на частоте 60 Гц
  • Убедитесь, что вы рисуете исходную текстуру - НЕ масштабируйте ее вверх или вниз до новой. Нарисуйте его в другом размере, и пусть растеризатор выполнит работу!
  • Спорадическое обновление: обновлять только половину изображения за раз. Вероятно, это близко к удвоению вашей частоты кадров, и это (обычно) не заметно.
  • Точно так же обновляйте изменяющиеся части изображения.

Надеюсь, что это поможет.