Если вы PC-геймер, то, вероятно, постоянно обновляете драйверы GPU устройств AMD или NVIDIA. Обновление графических драйверов может повысить производительность и совместимость с новыми играми, поэтому нет никаких причин их не обновлять. Кроме того, обновление графических драйверов в Windows выполняется очень легко, или вручную через «Диспетчер устройств», или автоматически при помощи программы, предоставленной производителем GPU.
В Android нет простых способов обновления графических драйверов планшета или телефона. Если у вас отсутствует root-доступ, то самостоятельное обновление графических драйверов на большинстве устройств практически невозможно. В этой статье мы расскажем о том, как распространяются драйверы GPU, как Google и поставщики устройств пытались упростить их обновление, и что придумывают сторонние разработчики, чтобы обойти ограничения Android.
Сложности обновления драйверов GPU в Android
В отличие от AMD и NVIDIA, компании Qualcomm и Arm, являющиеся производителями двух наиболее популярных линеек GPU для устройств на Android, не имеют прямой связи с потребителями. Невозможно собрать собственный смартфон, как это происходит с PC, поэтому при покупке GPU вы никогда не передаёте свои деньги напрямую Qualcomm или Arm. Qualcomm продаёт свои GPU производителям смартфонов в составе «системы на чипе» (system-on-chip, SoC), а Arm продаёт лицензии на свои архитектуры GPU производителям наподобие MediaTek, которые, в свою очередь, проектируют SoC с использованием этих GPU. Таким образом, Qualcomm стала на один шаг дальше от смартфона, попадающего в руки потребителей, а Arm стала дальше на два шага.
Не имея прямой связи с потребителями, эти производители мобильных GPU практически не мотивированы предоставлять пользователям доступ к пакетам обновлённых графических драйверов. Драйверы GPU напрямую передаются производителям смартфонов как часть Board Support Package (BSP). BSP, как я ранее объяснял в своей статье о программе Google Requirements Freeze — это пакет, содержащий исходный код и заранее собранные двоичные файлы, необходимые для запуска Android (или других операционных систем) на платформе конкретного чипсета. BSP содержат слои аппаратных абстракций (hardware abstraction layers, HAL) и драйверы, которые нужны Android для общения с оборудованием пользовательского устройства, в том числе и с GPU. Этот код BSP содержится в разделе устройства поставщика, доступном только для чтения, и может обновляться только производителем устройства при поддержке поставщика SoC.
Поставщики SoC обновляют BSP в течение жизненного цикла чипсета, устанавливаемого поставщиком SoC, однако он может быть увеличен при помощи платных лицензий поддержки ПО. Не каждое обновление BSP содержит обновлённые драйверы GPU, но если оно их содержит, то производители смартфонов могут извлечь из их обновлённого BSP, а затем передать их на устройства при помощи обновления OTA. Однако если вы знаете, как работают обновления Android, то сразу увидите здесь проблему. Обновления Android фрагментированы, то есть фрагментированными оказываются и графические драйверы.
Во-первых, графические драйверы не относятся к конкретной SoC. Например, графические драйверы Qualcomm поддерживают много разных GPU Adreno. Это значит, что графические драйверы, содержащиеся в BSP для одного чипсета, могут быть совместимы с GPU в другом чипсете. Однако один BSP может содержать обновлённую версию этих графических драйверов, а другие могут не содержать, потенциально оставляя устройства на других чипсетах со старыми версиями драйверов. Например, графические драйверы для Snapdragon 8 Gen 1 напрямую поддерживают Snapdragon 845 и последующие платформы, или, если конкретнее, все GPU Adreno 6xx и 7XX.
Ещё одна серьёзная проблема заключается в том, что производители пользовательских устройств (OEM) должны объединять обновлённые графические драйверы из BSP в свои проекты, тестировать их, а затем передавать их на устройства через обновление OTA. Нет даже гарантии того, что ваше конкретное устройство на Android получит обновления от OEM, не говоря уже про обновление, включающее в себя более новые графические драйверы. Это значит, что даже устройства с одинаковым чипсетом могут иметь разные графические драйверы.
И наконец, поскольку большинство устройств на Android продаётся без доступа superuser для пользователя, нет никакой возможности обновить драйверы GPU самостоятельно, то есть вы полностью зависите от OEM, устройство которого купили. Если вы получите root-доступ, то сможете вручную обновить графические драйверы в разделе поставщика, если каким-то образом найдёте необходимые файлы. Обычно для этого приходится извлекать драйверы из прошивки другого устройства, именно так поступают некоторые экспериментаторы в сообществе XDA-Developers. Именно так мне удалось обновить графические драйверы на моём Pixel 3 XL с завершённым жизненным циклом, что существенно повысило графическую производительность телефона.
Слева: бенчмарк 3DMark на Pixel 3 XL со стандартными драйверами поставщика. Справа: бенчмарк 3DMark на Pixel 3 XL с последним драйвером поставщика.
Эти драйверы были от устройства со Snapdragon 8 Gen 1 и их сделал прошиваемыми на моём Pixel 3 XL со Snapdragon 845 разработчик bylaws, создавший shim для передачи вызовов между QtiMapper API, используемой новыми графическими драйверами Adreno, и gralloc API, доступным для старых Adreno.
Не так уж страшно, если ваше устройство не имеет самых новых графических драйверов, но пользователей и разработчиков игр это определённо может раздражать. Как говорилось выше, обновлённые графические драйверы могут обеспечить повышенную производительность, и это показывают результаты 3DMark на моём Pixel 3 XL. Более важно то, что новые драйверы могут устранять баги реализации некоторых функций графических API. Разработчикам игр и так сложно создавать проекты для Android из-за сильных различий между GPU в отношении поддержки функций. Если дополнить это разницей в версиях драйверов на устройствах с одинаковым GPU, то можно понять, почему Android является сложной платформой с точки зрения разработки игр. Разработчикам или нужно поддерживать огромное количество способов обхода багов драйверов, или ограничивать совместимость устройств, и оба эти варианта плохи. Google создаёт базовый профиль, чтобы разработчики игр проще могли определять, поддерживает ли устройство множество стандартных функций Vulkan, но это всё равно не решает проблему фрагментации.
Однако снизить фрагментацию можно, упростив процесс обновления графических драйверов. Google признала это много лет назад, и благодаря разделению систем и поставщиков, реализованному Project Treble, она может поставлять обновлённые графические драйверы как часть стандартного пакета приложений Android. Qualcomm признала потенциал такого подхода, поэтому компания начала маркетинговую кампанию с информацией о том, что её новые чипсеты поддерживают обновление драйверов GPU через магазин приложений. К сожалению, в конечном итоге это мало улучшило ситуацию.
Как Google и поставщики SoC пытались повысить удобство обновления драйверов
Благодаря тому, что Project Treble стандартизировал интерфейс между HAL и фреймворком ОС, упростился процесс обновления HAL без нарушения совместимости с фреймворком. В результате этого Treble упростил независимое обновление графических драйверов, устранив необходимость привязки обновлений графических драйверов к обновлениям всей прошивки. Однако сложность заключалась в том, чтобы разобраться, как доставлять эти обновления графических драйверов вне стандартного обновления OTA.
Решением этого вопроса стали пакеты приложений Android (файлы .APK). APK могут содержать общие библиотеки (файлы .so), к тому же они являются предпочтительным форматом доставки для любого магазина приложений Android, в том числе и Google Play. Поэтому неудивительно, что APK выбрали в качестве механизма для доставки обновлённых графических драйверов, даже вместо формата файлов APEX, внедрённого вместе с Project Mainline. В конце концов, если у вас есть APK, то вы можете создать страницу в Google Play для загружаемых графических драйверов.
С точки зрения маркетинга это великолепно. Представьте — пользователь открывает Google Play и видит обновление драйверов GPU своего телефона. Кто-то из пользователей может подумать: «Отлично, точно как на моём PC! Отлично придумано, *название компании*!» Думаю, именно такой реакции ожидали Qualcomm и Arm, и именно поэтому многие OEM наподобие Xiaomi, OPPO и Samsung начали распространять обновления драйверов GPU через магазины приложений.
Для устройств серий Samsung Galaxy S20 и Galaxy Note 20 можно получить обновления игровых драйверов через Google Play.
Однако с точки зрения безопасности этот механизм доставки вызывает некоторые вопросы. Как гарантировать, что к пользователям попадут только утверждённые APK, содержащие валидированные и протестированные графические драйверы? Если любой произвольный APK может обновлять графические драйверы телефона, тогда телефон может выйти из строя из-за неправильных драйверов или подвергнуть опасности свою безопасность. Как же OEM могут безопасно доставлять обновления графических драйверов через магазин приложений?
Сначала OEM должен создать и подписать пустой APK обновляемого драйвера. Этот APK должен иметь собственное уникальное имя, если OEM хочет опубликовать приложение в магазине. Этот APK должен быть установлен по пути /vendor/app в разделе поставщика, то есть туда, где расположены изначально установленные графические драйверы.
Далее OEM должен создать и подписать непустой APK обновляемого драйвера. Этот APK должен содержать обновлённые графические драйверы, которые нужно доставить пользователю, и он должен иметь те же имя и подпись пакета, что и пустой APK обновляемого драйвера. Благодаря верификации подписей Android отклоняет все приложения с тем же именем пакета, что и у APK драйвера, если он не подписан OEM, таким образом гарантируя, что только OEM сможет обновлять APK драйвера.
Так как раздел поставщика доступен только для чтения, изначально установленные графические драйверы не переписываются напрямую при обновлении APK драйвера (то же справедливо и для пустого APK обновляемого драйвера в /vendor/app). Единственный способ перезаписи этих файлов заключается в обновлении образа поставщика, то есть в выполнении стандартного процесса обновления OTA.
Чтобы обойти эту проблему, Google модифицировала Android, добавив поддержку загрузки библиотек графических драйверов из трёх источников: обновляемого драйвера в продакшене, находящегося в APK, обновляемого предрелизного драйвера в APK или системного графического драйвера, изначально установленного в раздел поставщика. Драйвер в продакшене предназначен для поставки на потребительские устройства, он содержится в APK, имеющем имя пакета, заданного в системном свойстве ro.gfx.driver.0. Предрелизный драйвер предназначен для тестирования драйвера до отправки его потребителям, он содержится в APK, имя пакета которого задаётся в свойстве ro.gfx.driver.1.
Содержимое Xiaomi GPU Driver Updater с именем пакета com.xiaomi.ugd.
Android принимает решение о том, какие драйверы загружать, на основе системы белых списков. Сам APK драйвера может содержать белый список пакетов, которые OEM хочет автоматически выбирать для использования драйвера, но разработчики могут перейти в Settings > Developer options > Graphics Driver Preferences
и выбрать там или графический драйвер, который должны использовать все приложения, или графический драйвер, который нужно использовать для выбранных приложений.
Скриншоты Graphics Driver Preferences в Developer options.
Чтобы минимизировать ущерб от обновления драйвера с багом, обновляемые драйверы никогда не загружаются для привилегированных или системных приложений. По той же причине поставщики SoC сами никогда не передают обновления графических драйверов при помощи такой схемы. Представьте, что было бы, если бы Qualcomm отправила обновление драйвера, которое поломало бы совместимость с играми в продукте OEM; OEM по понятным причинам был бы очень сердит на Qualcomm; вероятно поэтому поставщики комплектующих предоставляют APK предрелизных драйверов, требуя, чтобы OEM распаковывали, тщательно тестировали, запаковывали, подписывали, а затем сами отправляли обновление драйвера в продакшен.
Поставщики комплектующих могли бы решить проблему фрагментации драйверов GPU сами, если бы сами создавали страницы для APK их драйверов в магазинах приложений, потому что в них уже есть собственные пустые пустые предрелизные APK драйверов в их BSP. Всем OEM достаточно было бы просто не удалять пустой подписанный предрелизный APK драйвера поставщика комплектующих. Однако нежелание (откровенно говоря, разумное) поставщиков комплектующих нести ответственность за поставки обновлений драйверов с багами в конечном итоге подрывает всю систему обновляемых драйверов GPU. Единственное, что изменилось — это механизм доставки обновлений драйверов GPU: OEM по-прежнему ответственны за саму передачу обновлений, то есть обновлённые драйверы не будут выпускаться по единому принципу. Большинство OEM по умолчанию всё равно будет просто выпускать обновления драйверов с OTA прошивок, потому что им достаточно тестировать только одно сочетание драйвера и прошивки вместо множества. Таким образом, мы вернулись в самое начало.
Дикое решение проблемы несогласованности драйверов GPU от разработчиков Skyline
Недовольные несогласованностью драйверов GPU на Android, двое разработчиков Skyline — эмулятора Nintendo Switch для Android с открытым исходным кодом, решили взяться за решение самостоятельно. Разработчиков игр для Android раздражает необходимость иметь дело со множеством разных GPU и их различающимися возможностями, но ещё сильнее это раздражает разработчиков эмуляторов, вынужденных реализовывать кучу неуклюжих обходных решений для устранения проблем совместимости в играх, изменять которые они практически не могут.
Например, разработчик Skyline Марк «Pixelylon» недавно рассказал мне об одном из самых серьёзных ограничений, связанных с драйверами. Его команда работает над тем, чтобы его преодолеть. По его словам, во многих играх для Switch используется формат сжатия под названием BCn. В GPU Adreno аппаратная поддержка текстур BCn присутствовала много лет, однако Qualcomm не обеспечивала поддержку BCn в своих драйверах до эпохи Snapdragon 865. Марк считает, что причина заключается в патентах на BCn (срок действия которых уже истёк), но как бы то ни было, это представляло сложность для разработчиков Skyline, потому что у пользователей со старыми GPU Adreno могли бы возникать проблемы совместимости с играми, использующими BCn.
Ещё один разработчик Skyline под ником bylaws, которого я уже упоминал в этой статье, придумал решение. Он разработал библиотеку BCeNabler, которая патчит драйверы GPU Adreno, включая поддержку текстур BCn. Хотя это и сработало, такая система не могла быть жизнеспособным долговременным решением для разработчиков Skyline, потому что было сложно патчить проприетарные драйверы GPU Adreno компании Qualcomm, чтобы добавить что-то сверх простейших функций.
В процессе мозгового штурма в выборе дальнейших действий Марк шуточно предложил заменять, а не патчить загружаемый Skyline графический драйвер. Загрузка другого графического драйвера — не такая уж абсурдная идея, бОльшую часть этой статьи я как раз объяснял, как это сделать. Однако разработчики Skyline хотели реализовать это без поддержки Google, OEM и поставщиков SoC, а также без необходимости root-доступа. Иными словами, они хотели выполнить инъекцию совершенно другого драйвера, отличающегося от системного, и им нужно было это сделать без необходимости особых привилегий.
Разработчику bylaws пришла в голову гениальная идея: он придумал, как заменить загружаемый приложением драйвер пользовательского пространства, с условием, что драйвер пользовательского пространства будет совместим с драйвером ядра, который, по словам Марка «обычно достаточно стабилен и не очень часто меняется коренным образом». Bylaws дополнил BCeNabler, создав Adreno Tools — не требующую root библиотеку для применения модификаций или замен драйвера GPU Adreno. Библиотека поддерживает загрузку произвольных драйверов GPU, включение текстур BCn и перенаправление файловых операций, чтобы обеспечить доступ к дампам шейдеров и возможность изменения файла конфигурации драйвера.
Adreno Tools работает достаточно сложным образом, но в говорить вкратце, она пользуется тем, что приложения Android не загружают графический драйвер самостоятельно. Вместо этого они используют драйвер Android (libvulkan.so), загружающий сам драйвер (libvulkan.adreno.so). Adreno Tools перехватывает этот процесс, инъецируя в системные библиотеки обработчики, а затем выполняя замену на новый драйвер.
Благодаря Adreno Tools приложение Skyline может загружать Turnip — драйвер Vulkan с открытым исходным кодом для GPU Adreno, не требуя root-доступа. Это серьёзный прорыв для сцены эмуляции на Android, потому что любой проект, имеющий дело с драйвером GPU Adreno, может обойти эти проблемы, загрузив Turnip. Turnip разрабатывается в открытую командой разработчиков проекта Freedreno в рамках проекта Mesa. Благодаря его открытости пользователям проще общаться с разработчиками, сообщать о багах или отправлять патчи, поэтому Turnip является привлекательным способом обхода всех связанных с драйверами проблем, с которыми сталкиваются разработчики эмуляторов.
Например, разработчик эмулятора PlayStation 2 для Android AetherSX2 под ником Tahlreth уже пользуется Adreno Tools. По словам разработчика, использование Turnip устраняет проблемы в эмуляции, наблюдаемые с драйвером GPU Adreno 660, но его применение приводит к деградации производительности по сравнению с драйвером официального поставщика. Однако Tahlreth всё равно распространяет сборки AetherSX2 со встроенным драйвером Turnip, рассчитанные на тех пользователей, проблемы с эмуляцией у которых возникают из-за драйверов их устройств. Хотя разработчик сообщает, что эти сборки нельзя загружать в Google Play, недавно Марк из проекта Skyline сказал мне, что они недавно получили добро от Google на распространение их приложения с Turnip. Таким образом, есть шанс, что Tahlreth сможет сделать то же и с AetherSX2, чтобы пользователям не приходилось искать специальную версию эмулятора на веб-сайте проекта.
Если вы изучаете информацию в сообществах, где собираются фанаты эмуляции, то, вероятно, уже слышали такой совет: покупать устройства с GPU Adreno, потому что они лучше подходят для эмуляции. Этот совет возник из-за веры в то, что GPU Adreno обеспечивают более высокую производительность, имеют меньше багов в драйверах и поддерживают больше функций. Судя по моему опыту и информации, услышанной от разработчиков эмуляторов, это в течение многих лет было правдой, однако Марк сообщил мне, что GPU Mali компании Arm существенно сократили разрыв в качестве драйверов. GPU Adreno компании Qualcomm за последнюю пару лет тоже «сильно поднялись» и в них отсутствует поддержка только очень малого количества расширений Vulkan, поддерживаемых Turnip. Тем временем, драйвер для нового GPU Xclipse 920 компании Samsung в Galaxy S22 поддерживает ещё больше расширений, чем самые новые драйверы GPU Mali и Adreno, хотя, по словам Марка, на самом деле проекту Skyline не требуются все эти дополнительные функции.
Сравнение поддержки расширений Vulkan между ARM Mali-G78 и Qualcomm Adreno 660 в серии Galaxy S21.
Сравнение поддержки расширений Vulkan между Samsung Xclipse 920 и Qualcomm Adreno 730 в серии Galaxy S22.
Что же касается GPU Qualcomm, то Марк сообщил мне, что большинство необходимых проекту функций поддерживается оборудованием GPU Adreno, поэтому для доступа к ним достаточно лишь обновления драйверов. Это возможно благодаря Adreno Tools и Turnip, поэтому разработчики эмуляторов, пытающиеся справиться с проблемами драйверов на Android, могут попробовать поработать с библиотекой, созданной bylaws и Марк. Как только наберёт обороты разработка PanVK (драйвера Vulkan для GPU Mali с открытым исходным кодом), то разработчики увидят, можно ли будет дополнить Adreno Tools поддержкой устройств Mali. Надеемся, препятствий этому не будет, но это в любом случае потрясающий проект, за развитием которого интересно наблюдать.