commit -m "better"
2.96K subscribers
873 photos
106 videos
3 files
2.08K links
just random thoughts
Download Telegram
У меня сегодня 2 истории, несколько технические, но, КМК, интересные.

В #tcmalloc нет реализации reallocarray(). В принципе, они в своем праве, потому что никому ничего не должны.

Проблема в том, что в musl reallocarray реализован.

Почему это проблема? Потому что у нас получается интересная ситуация - в stdlib.h есть сигнатура для reallocarray(), а в libmusl.a + libtcmalloc.a такого символа нет.

Дальше получается следующее:

1) Если configure проекта определяет наличие символа через компиляцию, то он получит, что reallocarray есть в наличии, и не включит у себя флажок, по которому бы код подставил свою реализацию. И в момент линковки будет ошибка.

2) Если configure определяет это через линковку, то он получит, что reallocarray нет, и включит флажок, по которому код включит у себя fallback на свою реализацию. Казалось бы, все хорошо? Нет, потому что эта рализация может не скомпилироваться, потому что в stdlib.h есть сигнатура от musl, и они могут, в деталях, не совпадать(например, throw()/noexept/etc).

Засада.

После ряда попыток это workaround в разных местах, я решил, что проще всего добавить реализацию в tcmalloc:

https://git.sr.ht/~pg/mix/tree/main/item/pkgs/lib/tcmalloc/mix.sh#L25

Кстати, в реализации, в которой я на это наткнулся, ошибка - https://git.sr.ht/~emersion/basu/tree/master/item/src/basic/alloc-util.h#L76 (впрочем, AFAIK стандарта на это еще нет, поэтому все в своем праве)

———
Решил я себе собрать #dosbox.

А он, зараза, зависит от SDL1, которая давно не обновляется, и собирать ее с wayland мне особо не хотелось.

Есть реализация api sdl1 через sdl2. https://github.com/libsdl-org/sdl12-compat/blob/main/src/SDL12_compat.c (в одном файле, да)

От автора sdl, судя по всему, он ее делал за деньги(потому что такое говно, как по этой ссылке, можно пилить только за деньги, и очень большие), работает хорошо.

Проблема в том, что у sdl1 и sdl2 один и тот же namespace, и функции пересекаются по именам. Поэтому коллега, ничтоже сумняшеся, загружает .so с SDL2 в RTLD_LOCAL режиме, и достает оттуда символы почем зря.

Мне пришлось соорудить интересную шутку - собрать библиотеку SDL2, и переложить все символы в другой namespace(по сути, добавить префикс V2_ ко всем экспортируемым именам). Я назвал библиотеку "SDL2 chimera". https://git.sr.ht/~pg/mix/tree/main/item/pkgs/lib/sdl/chimera/mix.sh#L12 После чего "загрузка" такой .a библиотеки дело техники - нужно всего лишь составить список вида [("SDL2", "SDL_xxx", &V2_SDL_xxx)] для моего загрузчика .so. https://git.sr.ht/~pg/mix/tree/main/item/pkgs/lib/sdl/chimera/dl/mix.sh#L14 Пересечений с SDL1 в общем пространстве имен бинарника не будет.

dosbox, сликованный в один бинарь с SDL2 - никто не умеет, а я умею :)

Отмечу, что вот это решение - оно вполне себе норм, то есть, это не хак, который будет разваливаться от каждого чиха. Переименование символов - хорошо определенная операция на объектных файлах, без странных side effect. Ну а добавить "V2_" - это очень разумная эмуляция для RTLD_LOCAL, найдите 5 отличий, что называется.
👍10🔥5
commit -m "better"
Будни #bootstrap, обещаный текст про сборку reddit desktop, #imgui * оно требует libmpv, для просмотра видосиков. Почему не ffmpeg напрямую - загадка. Все бы ничего, но сборка libmpv(или это свойство waf вообще) страдает обычным для OSS багом - "а давайте…
#imgui, #wayland, #sdl, #hidpi #gold

Так, третья, заключительная, часть рассказа про "собрать какое-нибудь приложение c imgui".

Прошлый рассказ я закончил на том, что у меня все собралось, запустилось, но было очень сильно замылено.

Скриншот мне делать лень, поэтому просто представьте себе, что картинка была rendered в буфер 100x100, который был растянут на экран 200x200.

Кстати, ровно та же проблема у меня наблюдалась с #dosbox.

Суммарно на решение это проблемы я потратил часов 10, фактически, все прошлые выходные. Зачем? Ну, потому что интересен процесс, а не результат. И потому что, предполагается, что владелец дистрибутива способен такие проблемы пользователей решать, я так думаю.

Я, пожалуй, не буду вдаваться в детали процесса, это слишком долго, я просто расскажу, как устроен hidpi в wayland, к чему это привело в модели sdl, и что я с этим сделал.

* В wayland у каждого буфера, в том числе on screen, есть, кроме обычных WxH(+ формат, но нам это не интересно), еще параметр scale. На мой взгляд, назван он неверно, и это долго меня сбивало с толку.

* Когда композитор отрисовыает буфер приложения в экранный буффер, он масштабирует буфер приложения в отношение scale этих двух буферов. Ну, то есть, если screen->scale == 2, app->scale == 1, то буфер от приложения будет увеличен в 2 раза.

* После чего композитор попиксельно отображает буфер приложения в экранный буффер, отсекая лишнее.

Давайте на примерах:

* screen == 200x200x2, app == 100x100x1. Увеличим app buffer в 2 раза, отобразим получившуюся картинку 200x200 as is. Так, фактически, работают старые приложения, которые не hidpi-aware.

* screen == 200x200x2, app == 100x100x2. Мы получим, что приложение заняло верхнюю левую четверть отведенного ей экрана.

* screen == 200x200x2, app == 200x200x2. Четкая, pixel perfect, картинка.

Что еще важно понимать?

Если композитор имеет размер буфера для приложения 200x200, и screen scale 2, то он, в качестве желаемых размерностей пошлет приложению 100x100, чтобы non-hidpi-aware приложения как-то работали. hidpi aware приложения, для того, чтобы рассчитать размер буфера для отрисовки, должны эту величину умножить на переданный scale.

А дальше все тулкиты изголяются, кто во что горазд.

Например, что делает SDL:

* Он hidpi aware, поэтому он выделяет буфер размера w * scale, h * scale. То есть, цепочка: композитор имеет буфер 200x200x2, он передает в SDL 100x100x2, SDL выделяет буфер для рисования 200x200x2. https://github.com/libsdl-org/SDL/blob/main/src/video/wayland/SDL_waylandwindow.c#L1901-L1905

* Далее SDL делает что-то странное. Он говорит, что всю отрисовку теперь мы будем делать в неких point, point у нас 100x100, каждый point физически отображается в 2 пикселя. https://discourse.libsdl.org/t/high-dpi-mode/34411

* ImGui берет размерности экрана в этих point, 100x100, делает gl viewport 100x100 над буфером 200x200, и рисует в свое удовольствие заблюренный контент.

То есть, как будто hidpi aware приложение само готовит контент низкого разрешения.

Я пробовал починить это разными способами, лучше всего сработал такой - https://git.sr.ht/~pg/ix/commit/fab9a5086801ea5e41d1e454f6c3a26abe9a06ed#pkgs/bin/reddit/desktop/hidpi/imgui_impl_sdl.cpp:

* В коде ImGui умножить размеры, передаваемые SDL, на scale.

* Получится так, что мы создадим viewport 200x200 над буфером 200x200, и отрисовка будет pixel perfect.

Почему я не могу расценивать это как финальное решение:

* Потому что, кроме gui, SDL возвращает масштабированными события от мыши, и получается, когда я их умножаю на scale, я теряю точность(мышка двигается по 2 пикселя по вертикали и гризонтали). Я не смог это заметить глазами на retina display, но как-то неаккуратно. https://forums.libsdl.org/viewtopic.php?p=43373

На мой взгляд, тут баг в SDL, что, когда приложение говорит, что оно hidpi aware, то надо ему возвращать настоящие пиксели, а не points.

Что мне делать с моим патчем в ImGui, я пока не понимаю.

BTW, должен сказать, что, после моего фикса, hidpi support в imgui кажется очень классным, потому что все размеры во float, и привязаны к размеру шрифта.
🔥9👍2