Когда хочется красивый GUI, а gpu нет
Обычно для рабочих утилит не требуется вменяемый UI, с кнопками, списками, окнами, поддержкой мыши и прочей мелочевкой, большинство рабочих «хотелок» можно упаковать в скрипты и иногда запускать их с параметром --help, и так будет даже правильней с точки зрения настройки и масштабирования. Все становится хуже, когда тулами начинают пользоваться не только команда разработки, но и сторонние люди. А они не всегда готовы вникать в стройные мысли, уложенные в строчки кода. И тогда приходится городить UI, а он у разработчиков выходит обычно простой, квадратный, функциональный и совсем скучный. Некоторое время назад я работал над небольшой системой управления вентиляцией/обогрева/камерами и еще того «что придумает вон тот дядечка в желтой каске» для подземной автостоянки.
(Здесь была картинка с UI системы, но разработчик попросил её убрать. Если вам не хочется читать о прогулках по граблевому полю, то ссылки на гитхаб в конце статьи)
Система была построена на китайском нонейм SoC, для которой производитель расстарался портировать SDL фреймворк первой версии. Внутренние тулы и скрипты доработали до такой степени, что они превратились в развесистый и «красивый» макет c вкладками, списками, попапами, тенями, градиентом, прозрачностью и другими плюшками.
Для реализации всех красивостей был выбран nanogui, простой и неприхотливый, и при этом «могущий» всё что было нужно. Ровно было на бумаге, да забыли про OpenGLовраги. Почти полностью реализованный UI системы управления стали запускать на железе, а там черный экран, все инициализации OpenGL3 проходят без ошибок, буферы ставятся, а шейдеры компилятся, но нет… черный экран, под каким углом не посмотри.
Сначала грешили на мои кривые руки, потом на руки Антохи-разработчика, ответственного за драйвера и железо, потом запустили тестовый пример рендера треугольника из состава сдк SoC, и снова черный экран, документацию и примеры как обычно читают в последнюю очередь.
Что-то тут неправильно подумали мы с коллегой и пошли сначала на китайский форум, а не найдя там внятных ответов уже и к разработчику, ответ был неутешительный, реализации opengl нет, и скорее всего не будет, потому что линейку снимают с производства.
— А как же SDL фреймворк? — спросили мы
— Рисуем попиксельно в видеопамять. — Ответили нам наши китайские друзья.
В тот день я увидел грустные глаза программиста, который подсчитывает сколько LoC он отправит в /dev/null. Но бросать уже готовое решение было очень обидно, (в интернетах найдется всё) оказывается жить без OpenGL в nanogui можно на software рендере.
Только жить получается очень медленно, на большом ПК пару секунд на фрейм, на китайском чуде инженерной мысли уже примерно 20–25 секунд для отрисовки. Тогда решили рендерить не весь UI сразу, а только нужные (измененные) части виджетов, но даже в таком режиме, со всеми хаками и оптимизациями выходило больше 10 секунд на один фрейм, нежизнеспособно…
Покурив немного примеры сдк выяснили, что копирование готовых текстур в видеопамять «мгновенное» (по сравнению с 10 секундами конечно), и занимает примерно 1 мс на текстуру 512×512 без прозрачности и 2 мс для такой же с прозрачностью, если копировать несколько таких текстур друг за другом то время растет нелинейно катастрофически, связано это оказалось с ограниченным объемом буфера видеопамяти, переполнение которого приводило к сбросу буфера и рендеру того что было на экран (велик не мой, он уже там стоял), т.е. для не совсем мертвого интерфейса мы можем копировать не более 50–100 текстур за фрейм и не сразу, а только дождавшись пока видеодрайвер заберет данные из буфера.
Следующей итерацией стал рендер виджета в собственную текстуру в потоке, а на время создания текстуры виджет рисовался примерно похожим на финальный результат, только квадратным способом, рисовать всякие линии, фигуры можно было сразу в видеопамять бесплатно.
Почти победив чудо китайской мысли «без» GPU, все таки нельзя назвать 20 FPS достойным результатом, и почти сдав проект, я попросил у заказчика разрешения забрать часть наработок в опенсорс. Первый SDL сейчас не очень в моде, поэтому было решено использовать рендер nanogui в software режиме на SDL2 и выложить это на гитхабе. Может кому понадобится :)
Дочитав до конца статью, %хабраюзер% вправе спросить, а зачем было городить эту кучу кода
ради скругленных уголков и теней? Во первых это красиво ©, во вторых «вон тот дядечка в желтой каске» уже оплатил разработку системы и скругленные уголки там, к сожалению, (или счастью) попали в ТЗ, осталось сделать их с градиентом и добавить немного теней.
Вот такое было оригинальное лето 2017 года в солнечном Сочи.
Так выглядит OpenGL рендер
Так выглядит software рендер на ПК
Ссылки:
Оригинальный wjakob/nanogui
NanoVG software render
NanoGUI + SDL + software render
P.S. Не верьте китайцамразработчикам, говорящим о наличие OpenGL в системе, проверяйте работоспособность всех компонентов, знать бы еще как:)