xash3d-fwgs
xash3d-fwgs copied to clipboard
Textures Manager
Менеджер текстур
Цель
Данный PR нацелен на создание менеджера текстур для упрощения рендеров и избавления от дублирующего кода
Мотивация
Впервые с необходимостью в отдельном менеджере я столкнулся при переключении рендера на лету. Перезагрузка ресурсов, в частности, текстур -- краеугольный камень для смены рендера без перезапуска движка. В своём черновике для принудительного обновления текстур были применены грязные хаки с флагами и отключением важных проверок. Желая избавится от них была начата работа в этом направлении
Перспектива
Менеджер преимущественно разрабатывается на перспективу. В недалёком будущем планируется:
- Вынос системы патчей материалов из ref_vk в менеджер ресурсов
- Реализовать переключение рендеров. Meta issue с обобщением опыта будет в скором времени
- Доработать менеджер текстур до полноценного менеджера ресурсов
План
Работу планирую разделить на два глобальных этапа
Этап 1
Этап нацелен на создание дублирующего слоя: менеджера текстур, работающего полностью идентично текущему
- [x] Создать прокси между движком и рендером, для последующей реализации менеджера текстур
- [x] Повторить загрузку, хранение текстур
- [x] Повторить генерацию текстур-заглушек из рендера
- [x] Восстановить недостающий код флагов
- [x] Починить сломанные спрайты
- [x] Починить сломанные модели и декали
- [x] Починить сломанные лайтстили
- [x] Реализовать очистку памяти
- [ ] ~~Реализовать релокацию, если текстур больше, чем 4096~~ (пока нет необходимости)
- [x] Прокидывание методов менеджера ресурсов в ref_api
- [x] Прокидывание методов менеджера ресурсов в render_api
Этап 2
Этап нацелен на фиксы и облегчение ref_gl. Этот рендер стабилен, реализует все возможности движка и идеально подходит для экспериментов
- [x] Удалить хранение текстур
- [x] Удалить генерацию текстур-заглушек
Второй этап может выполняться параллельно с первым. Но потребует чужой помощи. Я не разбираюсь в рендерах. И патчинг ref_gl займёт у меня времени больше, чем у знающего человека
Это как-то повлияет на рендеры, реализованные внутри клиентской игрокой библиотеки через RenderAPI?
Это как-то повлияет на рендеры, реализованные внутри клиентской игрокой библиотеки через RenderAPI?
~~Возможно, повлияет. Не думал, не тестировал. Если требуется, протестирую и поддержу~~
Нет, не повлияет. Никаких изменений в render api я не вношу принципиально. Сейчас он будет работать некорректно: проксирование методов мной не реализовано. Это сделаю позднее, как дойду до работ в рендере
@SNMetamorph рендеры наверное зовут что-то типа ref.dllFuncs.GL_LoadTexture? тогда менеджер текстур по идее это перехватывает.
Эксперименты в mainui попали в данный PR случайно
Сейчас глитчи с текстурами стен происходят из-за расхождения texnum в рендере и моём менеджере текстур. Расхождение возникает из-за функции Mod_ProcessRenderData
, которая подгружает текстуры спрайтов. Если её захачить, то глитчи уходят, но и весь движок падает через несколько секунд
Я вижу несколько сценариев, как поступать с функцией Mod_ProcessRenderData
.
Первый. Закрыть глаза на глитчи, мёрж сделать в отдельную ветку resman
. И при дальнейшей реализации вынести загрузку спрайтов в двиг, за одно решив эту проблему
Второй. Вытащить функцию и всё ей сопутствующее в двиг, превратив PR в Resource Manager
. Я попытался на скорую руку, но там очень много кода. Неизвестно, что ещё придётся распутать
Третий. Пока что захачить texnum, чтобы он всегда был идентичен рендеровскому до тех пор, пока не будет удалён менеджер текстур в рендере
Четвёртый. Добавить методы менеджера ресурсов в gEngfuncs
, пропатчив рендер так, чтобы он подгружал текстуры через двиг, а не напрямую в себя. Тупо, но практично
Как поступить лучше всего, @a1batross? Мне по душе четвёртый сценарий. Ибо он проще всего и не создаст много задач одномоментно
В каком состоянии находится функция Mod_ProcessRenderData
? Часть веток закомментированна без комментариев. Саму функцию дёргают непонятно кто и непонятно откуда в больших количествах. Я не могу распутать клубок вызовов(
При смене рендера я всё это хачил. Много, муторно, методично. Сейчас же хочу разобраться и сделать более-менее красиво
Дополнительно отмечу, что где-то утекает ref_api.h. Если его подключить несколько раз подряд, случается такое на несколько экранов:
Лучше за основу как раз брать ref_gl, а ref_vk уже подпиливать. Я в целом пока рекомендую забить на существование ref_vk, неизвестно насколько корректно он реализован.
Mod_ProcessRenderData исключительно рендероспецифичная. То что она наполовину закомментирована ничего страшного -- значит ничего делать. Вызывается при загрузке и выгрузке модели.
Лучше за основу как раз брать ref_gl, а ref_vk уже подпиливать. Я в целом пока рекомендую забить на существование ref_vk, неизвестно насколько корректно он реализован
За основу взят общий код для обоих рендеров
Mod_ProcessRenderData исключительно рендероспецифичная. То что она наполовину закомментирована ничего страшного -- значит ничего делать. Вызывается при загрузке и выгрузке модели.
Понял. Как мне лучше поступить с ней? Четыре сценария изложил выше
Ничего не делать. Это загрузка моделей, она не связана с текстурами.
Возможно, лучше завести новый коллбэк, который будет оповещать рендер что пора загрузить текстуру в видеопамять и присвоить ей рендероспецифичный handle.
Ничего не делать. Это загрузка моделей, она не связана с текстурами.
Вы не правы. При загрузке моделей происходит загрузка и текстур через функцию R_SpriteLoadFrame
(см. gl_sprite.c:50). Происходит это в обход движка. И именно это я пытаюсь решить. То ли хачить пока не поправлю рендер, то ли прокидывать менеджер ресурсов в рендер
Возможно, лучше завести новый коллбэк, который будет оповещать рендер что пора загрузить текстуру в видеопамять и присвоить ей рендероспецифичный handle.
Да, так и будет сделано, как буду вырезать управление текстурами из рендера. Сейчас я этого не делаю для упрощения отладки
Ничего там в обход не происходит. У тебя уже есть LoadTexture в движке, пусть он движковый и вызывает.
После коммита d50edac ушли глитчи из меню в рендере ref_soft. Сами уровни не запускал, ибо ref_soft не работает на x64 и пока не удалось его пропатчить
После коммита 54fc8a0 починились лайтмапы на GL
На карте test_brush всё ещё наблюдаются глитчи. Надо гонять статические анализаторы и санитайзеры. Похоже на утечку памяти, коих на этой карте стреляет очень много на ref_vk
Возможно, всё же, где то поплыли индексы, судя по редким глитчам в меню. По логам не вижу, буду исследовать позднее, в процессе патчей ref api
Удалось зафиксить ref_soft на x64, успешно работает с менеджером текстур Больше тестов красивых и разных для менеджера
Как полностью удалишь менеджер текстур из ref_gl, то и индексы начнут совпадать.
Дело все в том, что загрузка текстур в нём почему-то игнорирует вызов glCreateTextures и в качестве texnum берёт порядковый номер загруженной текстуры. Про это поведение в спеках OpenGL я находил целое ничего, так что удивительно что оно вообще работает.
Как полностью удалишь менеджер текстур из ref_gl, то и индексы начнут совпадать
Они и сейчас должны совпадать. Но я согласен, что после удаления проблема уйдёт точно. Надеюсь, в ближайшие пару дней у меня получится придти к этому. Сначала нужно перенести текстуры-заглушки, флаги и поправить работу с хэш мапой
Дело все в том, что загрузка текстур в нём почему-то игнорирует вызов glCreateTextures и в качестве texnum берёт порядковый номер загруженной текстуры. Про это поведение в спеках OpenGL я находил целое ничего, так что удивительно что оно вообще работает
Повеселил! Хоть не я один не понимаю, что вообще происходит в рендере и как оно работает
А ведь я хочу перед сменой рендера ещё попытаться в ref_common...
Дело все в том, что загрузка текстур в нём почему-то игнорирует вызов glCreateTextures и в качестве texnum берёт порядковый номер загруженной текстуры. Про это поведение в спеках OpenGL я находил целое ничего, так что удивительно что оно вообще работает
Иван @w23 ответил следующее:
https://www.khronos.org/registry/OpenGL/specs/gl/glspec21.pdf раздел 3.8.12, страница 182 (196 в пдф) The name space for texture objects is the unsigned integers, with zero reserved by the GL. A texture object is created by binding an unused name to TEXTURE 1D, TEXTURE 2D, TEXTURE 3D, or TEXTURE CUBE MAP.
glCreateTextures издревле был не то, чтобы очень нужен. это просто соломка, если тебе влом самому за интами следить
Спустя продолжительный перерыв вернулся к работе над PR.
В коммите 8b2e6f3 я объединил сразу несколько важных изменений:
- Удаление менеджмента текстур из
ref_gl
Теперь API упрощено до методов загрузки и удаления текстуры по индексу, всем прочим занят менеджер Пока пришлось выключитьref_soft
, ибо он не адаптирован под изменения. - Переработка хэш таблицы в менеджере текстур Изначально реализация была перенесена из рендера, но с ней были странные проблемы. Проще было написать свою несложную, чем выяснять-чинить
- Реализация удаления текстур в менеджере
Всё в совокупности дало результат, идентичный натуральному. Ничего не падает, явным образом не глитчует.
Остаются проблемы:
- Не реализованы текстуры-заглушки
- Не перенесены флаги
- Не вынесены хитрые манипуляции в менеджер текстур
Теперь нужно решить, как тестировать реализацию. @a1batross, подскажи, пожалуйста, как выявить регрессии? Временно использую тестовые карты от @0x4E69676874466F78, но и они не абсолют
@zgdump тестирование на регрессии у нас нет.
Сейчас ручная работа. Берёшь порт, берёшь мод и тестируешь. Впрочем, если в Half-Life, PrimeXT, Paranoia 2 всё в порядке, то высока вероятность что заработает скорее всего везде.
Навскидку можно пробежать моды под GS и под ксашем из этого списка: https://pastebin.com/tJseQ7PG
После реализации стандартных текстур, внезапно, стало очень хорошо. Ушли ошибки, пропали глитчи с лайтмап. Во текущем виде, менеджер текстур достаточно стабилен, основные задачи выполнены
Далее нужно пройти несколько игр на этой реализации, исправляя все найденные проблемы. Отрефакторить код, пройтись анализатором, починить утечки. И восстановить недостающие методы
Да, встроенные текстуры важны. Важно ещё соблюдать им имена, но я их все вынес в RefAPI.
Надо пожалуй перейти на твою ветку и дорабатывать её до мержабельного (от слова морж походу) состояния.
Да, встроенные текстуры важны. Важно ещё соблюдать им имена, но я их все вынес в RefAPI.
В ref_api.h
добавил ещё *cintexture
и *dlight
, почему-то они не были задефанены и в ref_gl
использовались строками.
Из всех стандартных текстур не перенёс solid_sky
и alpha_sky
. Код для генерации в gl_warp.c:652. Испужался, оставил на когда-нибудь)
Надо пожалуй перейти на твою ветку и дорабатывать её до мержабельного (от слова морж походу) состояния.
Про моржа не понял. Если поможешь, буду крайне признателен. Тут нужны и тесты, и почин под linux (f ansient c), и напильник
С текущей архитектурой менеджера текстур есть одна весомая проблема. Все текстуры хранятся в памяти, если, допустим, мод использует текстур на пару гигабайт, то всё это будет висеть в памяти игры просто ради того, чтобы рендер можно было менять на ходу. Мне кажется, стоит сделать это поведение конфигурируемым, далеко не всегда рационально жертвовать оперативной памятью ради горячей смены рендеров. Я предлагаю сделать возможность со стороны клиента игры отключить такое поведение, либо чтобы это конфигурировалось кваром.
Продублирую мысли, сформулированные в Discord.
Хранение оригиналов текстур не моя идея. Так было сделано до меня в ref_gl
, это же перекочевало в ref_soft
и ref_vk
. И это не просто архитектурное решение, но ий инвариант, на который полагается логика.
Для смены рендера оригиналы хранить вовсе не обязательно. Достаточно знать имена текстур. И при смене рендера они будут вновь прогружены из файловой системы
Я попробовал на скорую руку пропатчить ref_gl
и убрать хранение оригинальной текстуры. Для этого мне пришлось:
- Захачить GL_ProcessTexture
- Захачить GL_ProcessImage
- Убрать метод GL_GetTextureOriginalBuffer из ref_api
И оно собралось, заработало, но буквально на первом повороте уровня c1a1d
взорвалось в кишках:
Безусловно, уверен, всё можно изменить, поправить, исправить, закрыть глаза на патчи GAME_EXPORT функций. Вопрос трудозатрат
Как компромисс с @SNMetamorph могу сделать опцию для менедера текстур, чтобы оригинал отчищался сразу после загрузки, а в original хранился NULL
Хе-хе. Вы что-то не то делаете с хранением оригинальной текстуры или я вас неправильно понимаю.
Во-первых, гигабайты текстур мода и правда не должны храниться в оперативной памяти. Но есть один нюанс, о нём чуть позже.
Во-вторых, запрос хранения оригинала текстур исходит не от пользователя и даже не от разработчика мода, а от того кто пишет рендерер или собственно разрабатывает движок.
Есть у загрузчика флаг TF_KEEP_SOURCE
. Где он используется вам расскажет код, но навскидку -- он нужен для ремаппинга палитры, баловства, типа чтобы вписывать номер билда в Quake и самое важное, тот самый нюанс о котором я говорил -- ENGINE_IMPROVED_LINETRACE
. Это трейс через дырчатые текстуры. Это может занимать гигабайты, но разработчик мода сам запросил эту фичу движка и знал на что идёт, если хотел чтобы трейс, учитывал дырчатые текстуры, типа сеточек, заборов и прочего.
И только на этот флаг и надо ориентироваться. Задача же горячей смены рендерера -- это то, что нужно выделить за scope этого гигантского патча, а не пытаться решать всё подряд и запутываться в своём же собственном коде.
@a1batross
Со сменой рендера на лету будем разбираться и правда потом. Нам бы со текстурнёй разобраться. Патч маленький, но его бы победить для начала
Со хранением, кажется, я сам запутался. Обращение внимания на флаг TF_KEEP_SOURCE
меня расшатало, сообразил. Мне не нужно хранить оригинал. Это должен делать сам рендер, если выставлен флаг. Это объясняет мне FS_CopyImage
. Спасибо. Простите, если кого запутал