Портирование игр под Linux — Доклад от Valve и Nvidia

На конференции разработчиков игр (Game Developers Conference - GDC), компании Valve и Nvidia выступили с докладом, посвящённым портированию игр под Linux. Презентация с данного мероприятия доступна на сайте Nvidia.

Наиболее интересные моменты:

  • В качестве мотивов почему следует портировать игры на Linux, упоминаются:
    • Открытость операционной системы Linux и экосистемы.
    • Довольно быстрый рост популярности Linux в качестве игровой платформы.
    • Логичный промежуточный шаг при портировании игр на мобильные платформы, где также доминируют стандарты семейства OpenGL
    • Производительность.
    • Под Linux официально доступен Steam.
    • OpenGL предоставляет доступ к возможностям оборудования, оперируя при этом сугубо возможностями оборудования, а не версиями ОС или чем-либо ещё. В частности, в Китае в данный момент все ещё очень много пользователей с ОС семейства Windows XP, которые не могут пользоваться Direct3D 10/11. Тем не менее, при использовании OpenGL будут доступны полные возможности оборудования, в том числе и в данной версии ОС. Это позволит использовать возможности современного оборудования даже указанным пользователям.
    • Публично доступные спецификации стандарта.
    • Спецификации развиваются комитетом, в котором может принять участие любая заинтересованная сторона, для этого не требуются огромные суммы денег.
    • OpenGL проще расширять, любой вендор может предложить свои расширения.
    • OpenGL очень богат по своим возможностям.
  • Для управления окнами настоятельно рекомендуют использовать SDL, относительно небольшую и кроссплатформенную библиотеку на Си. SDL берет на себя все что касается работы с окнами, независимо от ОС, в том числе и на мобильных платформах. Valve пользуется данной библиотекой при портировании своих проектов, что доказывает пригодность библиотеки для достаточно требовательных применений. Кроме того, основной разработчик libsdl в настоящее время работает в Valve.
  • Проблемы с которыми столкнулись в Valve:
    • Файловые системы в unix-подобных ОС по умолчанию чувствительны к регистру имён файлов, тогда как в Windows файловые системы по умолчанию игнорируют регистр. Для игр это, как правило, не является проблемой так как игровые ресурсы обычно поставляются в платформо-нейтральных контейнерах. Тем не менее, в процессе разработки это может быть проблемой. Наиболее простым решением является перевести имена всех ресурсов в нижний регистр.
    • Ошибочные define`ы, например предполагающие, что на Linux может быть только выделенный игровой сервер и более ничего.
    • Проблемы с локалью могут вызывать проблемы в функциях printf/scanf. Решение: установить локалью en_US.utf8, а локализацию предоставить самому приложению. Так как в некоторых случаях локаль en_US.utf8 в системе может отсутствовать, следует предусмотреть вывод предупреждения в данном случае.
    • Шрифты: рекомендуется использовать библиотеки freetype и fontconfig. Тем не менее, может потребоваться пересчёт размера шрифтов.
    • Использование RDTSC (прецизионный таймер, основанный на счётчике тактов современных CPU х86). Вместо него рекомендуется использовать вызов clock_gettime(CLOCK_MONOTONIC), не зависящий от архитектуры процессора.
    • Использование raw mouse input, когда весь ввод мыши монопольно отправляется одной программе. Это очень хорошо работает для игр, однако некоторые оконные менеджеры при этом также перенаправляют и весь клавиатурный ввод. Это, в частности, может отключить работу alt-tab или аналогичных по смыслу горячих клавиш для переключения задач, что способно вызвать неудовольствие пользователей в некоторых ситуациях.
    • Более шероховатая поддержка многомониторных конфигураций. Тем не менее, libsdl способна взять большую часть проблем на себя.
  • Инструментарий:
    • Steam Linux Runtime и SDK предоставляют разработчикам игр ABI, не зависящий от дистрибутива.
    • Компилирование и отладка:
      • gcc - для компилирования.
      • gdb - для отладки.
      • cgdb - интерфейс на основе curses
      • ldd - отслеживание зависимостей бинарного файла от библиотек (эквивалент dumpbin).
      • nm - предоставляет информацию о символах, используемых программой.
      • objdump - дизассемблер и инструмент для просмотра подробных деталей о бинарных файлах.
      • readelf - инструмент для получения подробной информации об ELF файлах (основной формат исполняемых файлов в Linux).
      • make - средство сборки проекта.
    • Анализ производительности - CPU:
      • perf - свободный профайлер под Linux, использующий performance counters современных процессоров
      • vtune - инструмент от компании Intel, также существующий и в версии под Linux.
      • Telemetry - многие коммерческие разработчики игр уже и так используют данный инструментарий.
  • Примерное соответствие OpenGL и Direct3D:
    • Direct3D 9 примерно соответствует возможностям OpenGL2. Начиная с этой версии доступны шейдеры.
    • Direct3D 10 примерно соответствует семейству OpenGL3, появилось более актуальное API. Реализованы геометрические шейдеры.
    • Direct3D 11 примерно соответствует OpenGL4. Поддержка тесселяции и произвольных вычислений на шейдерах.
  • Ключевые отличия Direct3D от OpenGL с точки зрения разработчика:
    • В OpenGL у потоков есть локальные данные, поэтому:
      • У потока может быть только один текущий контекст.
      • Контекст может являться текущим только для одного потока.
      • Вызовы в OpenGL из потока без текущего контекста согласно спецификации не должны иметь никакого эффекта.
    • OpenGL основан на Си. Объекты передаются хэндлами.
      • Многие функции вообще не требуют указания хэндла и оперируют на выбранном в данный момент объекте.
      • Как правило хэндл имеет тип GLuint.
    • OpenGL поддерживает расширения.
    • Несмотря на то что OpenGL довольно многословен и на первый взгляд требует больше вызовов, он показывает впечатляющую эффективность и производительность.
    • В OpenGL отсуствуют проблемы с потерей устройств.
  • Расширения OpenGL:
    • Есть специфичные для поставщиков расширения с префиксами NV|AMD|APPLE. Тем не менее, ряд из них был реализован сразу несколькими поставщиками. Например, NV_bindless_texture.
    • Расширения с префиксом EXT реализуются сразу многими поставщиками. Например, EXT_separate_shader_objects
    • Расширения с префиксом ARB были рассмотрены и приняты комитетом развивающим стандарт. Например, ARB_multitexture.
    • Базовые расширения (Core extensions): базовые возможности из более поздних версий стандартов OpenGL представляются как расширения относительно прошлой версии стандарта.
    • Есть зависящие от специфики платформы расширения: WGL, GLX, AGL и EGL.
  • Советы разработчикам:
    • Поиск в интернете имеет смысл делать как с префиксом GL_ или gl у соответствующего вызова так и без него.
    • Чтение спецификаций стандарта себя оправдывает многократно.
    • Если вам не нравится текущее направление развития OpenGL, присоединитесь к Khronos Group и постарайтесь оказать влияние на развитие стандарта. Лучше всего определять свое будущее самому.
    • Core vs Compatibility: Некоторые производители утверждают что использование core-профайлов будет быстрее чем compat-, однако по факту подтверждение данного тезиса обнаружить не удалось. Поэтому можно пользоваться тем, что проще и удобнее конкретному разработчику. * Наиболее полезные расширения OpenGL по мнению разработчиков: EXT_direct_state_access, EXT_swap_interval (и EXT_swap_control_tear), ARB_debug_output, ARB_texture_storage и ARB_sampler_objects. Кроме того отмечаются NVX_gpu_memory_info и GL_ATI_meminfo позволяющие получить информацию о использовании памяти GPU.
  • Самые проблематичные места в плане производительности:
    • Вызов MakeCurrent очень дорогой. Следует избегать его вызова даже 1 раз на кадр.
    • Современные драйвера как правило используют более 1 потока. Программа по факту взаимодействует с относительно тонкой прослойкой которая может распределять работу на несколько потоков. Некоторые вызовы заставляют производить полный сброс буферов и ресинхронизацию между потоками что сильно просаживает скорость операций.
    • Наиболее проблемными оказались функции glGet() и glGetError() (вместо этой функции рекомендуется использовать ARB_debug_output)
Сломался единственный телевизор? Тогда вам нужен ремонт телевизоров, который вы можете заказать на сайте led-tvrem.ru.