Кэш скомпилированных шейдеров - один из тех механизмов, которые незаметно работают до тех пор, пока не начинают мешать. При первом запуске игры или тяжёлого приложения видеодрайвер компилирует шейдеры под конкретное железо, что занимает секунды или даже минуты. Повторные запуски должны быть мгновенными, но на практике размер кэша ограничен, старые записи вытесняются, а при обновлении драйвера кэш полностью инвалидируется. Понимание переменных окружения, путей хранения и способов прогрева позволяет убрать микрофризы, сократить время запуска и предсказуемо управлять дисковым пространством.
Устройство кэша шейдеров в Mesa и его размещение на диске
В Mesa кэш шейдеров реализован в двух вариациях: классический многофайловый и современный однобайтовый на базе Fossilize. По умолчанию в Mesa 24.x включён многофайловый формат, данные складываются в каталог ~/.cache/mesa_shader_cache (или $XDG_CACHE_HOME/mesa_shader_cache). Каждый скомпилированный шейдер сохраняется как отдельный файл, что создаёт десятки тысяч мелких записей. Альтернативный однобайтовый формат включается переменной MESA_DISK_CACHE_SINGLE_FILE=1 - создаётся база mesa_shader_cache_sf с бинарниками и индексами. Третий вариант - Mesa-DB - активируется через MESA_DISK_CACHE_DATABASE=1, кладёт данные в ~/.cache/mesa_shader_cache_db, поддерживает лимит через MESA_SHADER_CACHE_MAX_SIZE и разбивает базу на 50 частей (меняется через MESA_DISK_CACHE_DATABASE_NUM_PARTS).
Переменная MESA_SHADER_CACHE_MAX_SIZE задаёт порог в байтах с суффиксами K, M, G (гигабайты по умолчанию). Если лимит не задан - используется 1 ГБ на архитектуру, на системе с 32- и 64-битными драйверами - два гигабайта суммарно. MESA_SHADER_CACHE_DIR переопределяет корневой каталог для переноса кэша на NVMe или tmpfs. MESA_SHADER_CACHE_DISABLE=true выключает дисковый кэш, MESA_SHADER_CACHE_SHOW_STATS=true заставляет драйвер выводить статистику попаданий и промахов при завершении приложения.
Для Vulkan-драйверов RADV и ANV действуют те же переменные - они используют общую инфраструктуру Mesa. RADV_PERFTEST=rgp включает захват трасс для Radeon GPU Profiler, показывая время компиляции конвейеров в сцене. MESA_DISK_CACHE_DATABASE_EVICTION_SCORE_2X_PERIOD (по умолчанию 2592000 секунд - 30 дней) управляет алгоритмом вытеснения: чем дольше запись не запрашивалась, тем выше её штраф. Для задач через ROCm полезно увеличить до 7776000 (90 дней). MESA_DISK_CACHE_READ_ONLY_FOZ_DBS подключает до восьми готовых Fossilize-баз для мгновенного прогрева.
Кэш шейдеров NVIDIA переменные и нюансы очистки
Проприетарный драйвер NVIDIA хранит кэш в $XDG_CACHE_HOME/nvidia/GLCache (или ~/.cache/nvidia/GLCache). До 470-й серии использовался ~/.nv/GLCache - если остался, драйвер продолжит его использовать. Три переменные управляют поведением: __GL_SHADER_DISK_CACHE (0 или 1) включает или выключает кэш для прямого рендеринга, __GL_SHADER_DISK_CACHE_PATH задаёт каталог, __GL_SHADER_DISK_CACHE_SIZE ограничивает размер в байтах с суффиксами k, M, G. Если __GL_SHADER_DISK_CACHE_SIZE задан локально для одного приложения, а затем запускается другое без переменной, драйвер сбросит кэш до дефолтного размера и удалит лишнее. Экспортируйте переменную в ~/.profile или /etc/environment.
Переменная __GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1 отключает автоматическую очистку устаревших записей - полезно при профилировании. По умолчанию драйвер сам удаляет старые шейдеры при достижении лимита. Кэш привязан к версии драйвера: обновление с 550 на 560-ю серию заставит перекомпилировать всё заново. Для диагностики удобно включить __GL_SHADER_DISK_CACHE=1 и __GL_SYNC_TO_VBLANK=0 вместе с MESA_SHADER_CACHE_SHOW_STATS на стороне Mesa-приложений под Zink. __GL_HEAP_ALLOC_LIMIT (например, 20MB) ограничивает кучу драйвера и косвенно влияет на кэш. В драйвере 550.127 флаг SKIP_CLEANUP заработал для Vulkan-контекстов единообразно с OpenGL.
DXVK и vkd3d-proton свой кэш поверх Vulkan
DXVK кэширует не только скомпилированные SPIR-V, но и промежуточное представление конвейеров. Переменная DXVK_SHADER_CACHE=0 отключает внутренний кэш полностью, DXVK_SHADER_CACHE_PATH перенаправляет файлы - по умолчанию $XDG_CACHE_HOME/dxvk или ~/.cache/dxvk в нативном Linux, в Wine-префиксе это %LOCALAPPDATA%/dxvk. DXVK_STATE_CACHE_PATH (или устаревшее DXVK_STATE_CACHE) указывает путь для кэша состояний конвейеров - отдельной базы, где хранятся уже слинкованные объекты VkPipeline. Разделение шейдерного и стейт-кэша позволяет чистить одно не трогая другое.
Включение DXVK_HUD=compiler показывает активность компилятора в реальном времени: количество ожидающих задач, занятость рабочих потоков, время компиляции отдельного конвейера. На слабых процессорах при запуске игры с Graphics Pipeline Library (VK_EXT_graphics_pipeline_library) может возникнуть пик загрузки CPU на 100% в течение 20-60 секунд - это нормально, шейдеры компилируются заранее, а не в момент отрисовки. Прогрев кэша делается простым запуском игры с DXVK_HUD=compiler и ожиданием, пока счётчик задач упадёт до нуля.
vkd3d-proton для Direct3D 12 использует схожие переменные: VKD3D_SHADER_CACHE=0 отключает кэш, VKD3D_SHADER_CACHE_PATH меняет каталог, VKD3D_CONFIG=shader_cache_size=2G задаёт лимит через конфиг-строку. Дополнительно VKD3D_DEBUG=shaderdb включает логирование попаданий в кэш. При использовании Steam Play переменные прокидываются через PROTON_SHADER_CACHE_DIR и PROTON_SHADER_CACHE_SIZE - удобно для переноса кэша на отдельный раздел. Переменная VKD3D_CONFIG=disable_cached_pipelines=1 полностью отключает кэширование конвейеров, оставляя только шейдерный кэш - полезно для отладки ошибок линковки. DXVK_CONFIG_FILE указывает путь к .conf с тонкими настройками: dxgi.maxFrameLatency = 1, d3d11.forceMapFlags = True влияют на то, как и когда DXVK запрашивает компиляцию. Параметр compiler.threads в конфиге ограничивает число рабочих потоков компилятора - на 4-ядерных CPU ставим 2, на 16-ядерных - 8, чтобы не убить отзывчивость системы во время прогрева.
Прогрев кэша рендерингом от теории к практике
Прогрев - это запуск приложения с целью заполнить кэш всеми шейдерами, которые встретятся в реальной игре. Самый надёжный способ: пройтись по всем меню, загрузить несколько сохранений, поиграть 10-15 минут в типичных сценах. Для автоматизации используют скрипты, которые эмулируют ввод через xdotool или ydotool, либо запускают игру в безголовом режиме с переменной MESA_VK_TRACE=rgp для захвата трассы. В Mesa 24.2 появилась переменная MESA_VK_TRACE_FRAME=N - она автоматически останавливает трассировку на N-м кадре, что позволяет снять профиль именно этапа прогрева.
Числовой пример: в Cyberpunk 2077 на Radeon 6800 XT с Mesa 24.1 первый запуск после очистки кэша занял 42 секунды до главного меню, повторный - 18 секунд. После целенаправленного прогрева (прохождение тюториала, бой, вождение) третий запуск составил 12 секунд. Размер кэша вырос с 180 МБ до 1.2 ГБ. Включение MESA_DISK_CACHE_DATABASE=1 сократило число файлов с 47 тысяч до 3, а время запуска ещё на 15% - за счёт отсутствия накладных расходов на inode.
Для NVIDIA аналогичный тест на RTX 4070 с драйвером 550.127: первый запуск 38 секунд, после прогрева 14 секунд. Кэш в ~/.cache/nvidia/GLCache занял 890 МБ. Установка __GL_SHADER_DISK_CACHE_SIZE=2G предотвратила вытеснение при следующих обновлениях игры. Дополнительный тест на Intel Arc A770 с Mesa 24.2: ANV с MESA_DISK_CACHE_DATABASE=1 и INTEL_MEASURE=frame показал сокращение времени запуска Shadow of the Tomb Raider с 31 до 19 секунд после прогрева. Кэш mesa_shader_cache_db разросся до 640 МБ на 50 частях, среднее время компиляции конвейера снизилось с 8.4 мс до 0.3 мс за счёт попаданий в кэш. Автоматизированный прогрев для регрессионного тестирования: скрипт запускает игру с MESA_VK_TRACE=rgp MESA_VK_TRACE_FRAME=200, ждёт завершения, парсит .rgp через rgp_cli --csv, считает сумму PipelineCompileDuration. Если сумма превышает порог (например, 500 мс на запуск) - кэш считается "холодным", прогрев не завершён.
Измерение времени компиляции и поиск узких мест
Инструменты профилирования делятся на два класса: встроенные в драйверы и внешние. INTEL_MEASURE=draw,file=/tmp/measure.csv на Intel-графике выдаёт CSV с таймингами каждого draw-вызова, включая стадию компиляции шейдеров. RADV_PERFTEST=rgp генерирует .rgp-файл для Radeon GPU Profiler - там видно, сколько микросекунд ушло на каждый этап конвейера: компиляция SPIR-V в NIR, оптимизация NIR, генерация машинного кода, линковка.
В Mesa MESA_VK_TRACE=rgp работает для любого Vulkan-приложения, включая DXVK и vkd3d-proton. Запуск: