Stage 4 Vulkan groundwork. Before this, RenderBackendOps.current() unconditionally returned GlRenderBackendOps.INSTANCE with a 'Stage 3-prep' comment. Under Vulkan the GL impl is still harmless (its methods all short-circuit on OptimizeToggles and the GL mixins never fire), but the interface lied about the active backend. - New misc/optimize/vulkan/VulkanRenderBackendOps: singleton, no-op stub, all *Supported() return false, cache/map methods do nothing. This is the skeleton the Stage 4 items (persistent VkPipelineCache, VulkanRenderPass state cache) will grow into. - RenderBackendOps.current() inspects RenderSystem.getDevice().getClass().getName() and returns VulkanRenderBackendOps for com.mojang.blaze3d.vulkan.* devices, GlRenderBackendOps otherwise. Class-name check (not instanceof) so this method itself does not force linking of GlDevice/VulkanDevice. - Wrapped getDevice() in try/catch: unit tests call current() before RenderSystem has a device and previously took the GL path; now they still do via the fallback. Doc: Stage 4 kickoff entry in the changelog.
32 KiB
Слой оптимизации (Optimize): перенос референсных оптимизаций, улучшения и Vulkan
Статус: Этапы 1-3 готовы (2026-10-12). Этап 4 (Vulkan) — стартуем с универсально-полезных пунктов. Цель MC: 26.2.
История изменений
- 2026-10-12: Этап 4 старт —
RenderBackendOps.current()теперь определяет активный бэкенд черезRenderSystem.getDevice().getClass().getName()(class-name, неinstanceof, чтобы не форсировать линковкуGlDevice/VulkanDevice); добавленmisc/optimize/vulkan/VulkanRenderBackendOps— no-op-заглушка со всеми*Supported() == false. Под GL всё работает как раньше; под Vulkan mixins изmixins/optimize/gl/*не загружаются, и теперь хотя бы интерфейс честно возвращает правильный бэкенд. Живые Vulkan-пути (VkPipelineCache, state cache) — следующий шаг. - 2026-10-12: убран гейт «меряем на Windows до включения». Бенчмарки больше не блокируют работу: универсально-полезные
GL/Vulkan-оптимизации делаем сразу за default-off тумблерами (пользователь включает сам), отчёт цифр остаётся как
факультативная задача владельца и не входит в план. Этап 3 закрыт по всем пунктам, кроме п.9 (
no_item_sort/item_single_copy— API 26.2 не даёт, отложен не по замерам, а по дизайну). - 2026-10-12: референсная реализация обновлена с 1.0.1 до 1.0.3 (сверка исходников). Корректировки плана ниже, в разделе «Что нового в референсе 1.0.2-1.0.3».
- 2026-10-10: Этап 1 завершён — 11 портированных файлов (
core/LruMap,entity/{EntityLod,CachedName,StateEntity,CachedStack},particle/{ParticleLod,Workers},hud/HudWorth,block/{TickCached,CachedLight,CachedValidity,SpawnerCache},text/StableText) +OptimizeToggles+mod/NOTICE. 53 теста. Патчи:0001-feat-mod-...patch,0002-test-mod-...patch. - 2026-10-10: Этап 2 завершён —
FrameBudget(mode + target FPS + per-subsystem caps),FrameProfiler(5 секций EMA-таймингов),OptimizePropertyBridge(-Dlovisual.opt.*overrides),OptimizeDebugHudMixin(F3 overlay). 22 новых теста.Optimize.javaрасширен тумблерамиbudget_mode/target_fps/show_profiler. - 2026-10-10: Этап 3 (частично) —
RenderBackendOpsинтерфейс +GlRenderBackendOpsреализация (lazy clear, TBO cache, RenderTypes cache). Три mixin'а зарегистрированы вlovisual.mixins.json:RenderTypesMixin,GlCommandEncoderClearMixin,GlCommandEncoderTexBufferMixin. SkinAtlas/AnimFreeze/HudCache/FrameFence оставлены на поздний Этап 3.
Решение
Все оптимизации из референса (слои common, 26.x, 26.2) переносятся в наш модуль Optimize, а не живут отдельным
модом. Sodium остаётся необязательным (suggests), выбор GL/Vulkan делается по бэкенду Blaze3D, а не по наличию Sodium.
Две независимые оси
| Ось | Чем определяется | Что меняет |
|---|---|---|
| Бэкенд | RenderSystem.getDevice() instanceof GlDevice, иначе Vulkan |
какая реализация gl/ или vulkan/ включается |
| Sodium | FabricLoader.isModLoaded("sodium") |
только быстрые пути записи вершин (VertexBufferWriter) |
Без Sodium ландшафт остаётся ванильным. Ускорение ландшафта вне этого плана (возможный отдельный проект: форк Sodium).
Структура
Пакет features/module/modules/misc/optimize/. Правила проекта: ≤4 .java на папку, ≤250 строк на файл,
JUnit на чистую логику, helper-классы вне mixins.*, миксины в mixins/optimize/.
optimize/
Optimize.java модуль и настройки (ключи совместимы с .lvcfg)
core/ бэкенд-независимая логика: LOD-пороги, LRU, кэши, бюджет кадра
entity/ particle/ hud/ block/ text/ перенос из референса по категориям
gl/ GL-реализации: shared FBO, GpuFence, lazy clear, glCopyImageSubData
vulkan/ Vulkan-реализации: vkCmdCopyImage, VkPipelineCache, кэш состояния
profile/ профилировщик секций кадра
Выбор реализации один раз при старте через интерфейс RenderBackendOps (копирование текстур, фенсы, кольцо буфера).
Что переносим (всё из референса)
- GL/рендер-пайплайн (то, что реально есть в слоях 26.x/26.2): Shared Frame Fence (
FrameFence,RealFence), Lazy Clear, FBO Sharing (SharedDepthFbos,FrameBufferCacheMixin,GlBufferCloseMixin), TBO Cache, RenderType Cache, VertexConsumer Cache, Entity Sort Skip. Immediate Ring Buffer и Ring Auto-Tune существуют только в слоях 1.21.x, в 26.x их нет (ванильные буферы там другие), поэтому в порт не входят; ring делаем заново только если замер покажет пользу (см. ниже). - Сущности: AnimFreeze, Entity LOD, Player LOD, Item LOD, Item Bounds Cache, Skin Atlas, Cached Name, CachedStack.
- Частицы: Particle LOD, Parallel Particles, Parallel Vertices, Particle Light Cache, Particle Physics Skip, Bubble Column Cache.
- Блоки: Spawner Cull, Spawner Tick Cache, Spawner Replay, Moving Block Cache, Piston Biome Cache, Sign Cache, Block Entity Cache (CachedLight, CachedValidity).
- HUD: HUD Cache, HUD Worth, GUI Animated Items, GUI Item Atlas, совместимость с ImmediatelyFast Atlas.
- Текст: Bidi Cache, Prepared Text Cache, StableText.
- Микро: MemoryStack Cache, Sign Lookup Cache, Bubble Fluid Cache.
Поток кадра как в референсе: FrameFence.endFrame -> SkinAtlas.endFrame -> AnimFreeze.frame++
-> OptConfig.refresh() (флаги резолвятся один раз за кадр в примитивные поля).
Что делаем лучше, чем в референсе
- Единый бюджет кадра. Один объект раздаёт лимиты LOD, частицам и нашим эффектам (ProjectileTrails, ElytraTrails, DeathEffects, Blizzard, GodRays): дистанция, число точек и вершин на кадр. Режим «Выкл / Мягко / Агрессивно», по умолчанию «Выкл», целевой FPS задаёт пользователь. Это не авто-деградация, прежнее решение (Фаза 9) не нарушается.
- Профилировщик секций (сущности, частицы, HUD, эффекты, текст) в debug-оверлее.
- Один конфиг в
Optimize, без отдельного экрана референса. - Авто-порог параллельных частиц по замеру (в референсе порог 4+ ядра взят из одного прогона).
→ Упрощено 2026-10-12: сделано как в референсе —
CORES >= 4+-Dlovisual.opt.parallel_particles=auto|true|false. МодульOptimize.parallel_particles(default true = AUTO) иWorkers.shouldParallelParticles()— plumbing готов, mixin-точка на vanilla extraction приложится позже (26.2QuadParticleGroup/SpriteBillboardParticle). - Кэш статичных HUD-виджетов в текстуру (перерисовка только при изменении).
- Флаги для бенчмарков:
-Dlovisual.opt.<key>.
Дополнительные GL-оптимизации (наши)
Реализуем за default-off тумблерами (-Dlovisual.opt.<key> или поле в модуле); включать или нет решает пользователь.
Автомерялок не ждём — если пункт безопасен (не меняет картинку) и дешёв, он имеет смысл и при выключенном состоянии,
тумблер даёт путь включить.
- ✅ Кэш состояния GL шире, чем в референсе: пропуск повторных
glUseProgram,glBindVertexArray,glBindTexture,glBlendFunc,glDepthMask(LoVisual уже имеетGlStateManagerMixin, расширяем). Готово 2026-10-12, частичнo:glUseProgramиglBindVertexArray— по байткодуcom.mojang.blaze3d.opengl.GlStateManagerв 26.2 это единственный два «сырых» бинда без ванильного кэша; остальные (glBindTexture/glBlendFunc/glDepthMask) уже идут через ванильныеTEXTURES/BLEND/DEPTHstate-массивы, дублировать их кэш — только хуже.render/engine/optimize/gl/state/GlStateCache- миксин
mixins/optimize/gl/state/GlStateManagerCacheMixin, гейтmicro_opts, 6 тестов, invalidация наglDeleteProgramи наOptimize.onDisable.
- миксин
- Сортировка draw по pipeline и текстуре внутри слоя там, где порядок не влияет на результат (наши квады
Renderer2D, ленты trails). - Persistent mapped ring для динамических вершин наших эффектов и HUD (
GL_ARB_buffer_storage), если профиль покажет стоимостьglBufferSubData/map. Ring Auto-Tune из референса берём как идею размера. - Батчинг HUD: меньше смен пайплайна между виджетами (общий batch для
Renderer2D.COLOR/TEXTURE). - Инвалидация глубины/stencil (
glInvalidateFramebuffer) после проходов, чьё содержимое не читается: выгодно на тайловых и мобильных драйверах, на десктопе эффект мал. - Пропуск лишних clear наших пост-процесс целей (
MenuBackgroundRenderer, блюр), когда цель целиком перезаписывается. - Меньше FBO-переключений в post-process цепочках (объединение проходов, общий ping-pong).
- Uniform-блоки: один обновляемый UBO на кадр вместо множества мелких обновлений (в LoVisual есть
DynamicUniformStorageMixin).
Разбор GL-части референса для 26.x/26.2 (что реально делает код)
Файлы референса:
26.x/.../gl/FrameFence.java+26.2/.../gl/RealFence.java: один общийGpuFenceна кадр вместо фенса на каждый запрос; если его ждут до конца кадра, реальный фенс создаётся сразу, как в ваниле. Подмена черезGlCommandEncoderMixin.createFence.26.x/.../mixin/gl/GlCommandEncoderClearMixin.java(Lazy Clear): послеclearColorAndDepthTexturesне делается лишний_glBindFramebuffer(.., 0), следующий проход всё равно привязывает свою цель.26.2/.../gl/SharedDepthFbos.java+FrameBufferCacheMixin,GlBufferCloseMixin,GlCommandEncoderDepthClearMixin: очистка глубины через кэшированный FBO иglClearNamedFramebufferfv(DSA), без attach/detach. Нужен GL 4.5 илиARB_direct_state_access.common/.../gl/TexBufferCache.java+GlCommandEncoderTexBufferMixin: не перепривязывает буфер к texel-buffer текстуре, если связка (формат, буфер) не менялась.26.x/.../mixin/gl/RenderTypesMixin.java: кэшentityTranslucentпоIdentifierвместоUtil.memoizeсPair.common/.../gl/RingAutoTune.java: логика подбора размера кольца (в 26.x самого ring нет).- Жёстко привязаны к GL (на Vulkan нужен свой путь или отключение):
SkinAtlas(glCopyImageSubData),SharedDepthFbos,RealFence, TBO-миксины.
Наш собственный GL-код (render/engine/rhi/backend/gl, Renderer2D, GlStateManagerMixin) читается по мере работы
над каждым пунктом; отдельного «профиля перед Этапом 3» не делаем — Этап 3 уже закрыт, счётчики DrawStats в F3
остались как справочный инструмент.
Vulkan
Универсально-полезное (не зависит от замеров) делаем сразу, остальное — по мере надобности.
| Пункт | Зачем | Статус |
|---|---|---|
Персистентный VkPipelineCache на диск |
меньше фризов компиляции шейдеров, у нас уже есть pipelineVariants |
берём в Этапе 4 первым |
Кэш состояния (pipeline, descriptor set, viewport/scissor) в VulkanRenderPass |
пропуск повторных bind | берём |
vkCmdCopyImage вместо glCopyImageSubData (SkinAtlas) |
SkinAtlas вычеркнут — пункт не нужен | ❌ |
FrameFence) через общий интерфейс |
FrameFence вычеркнут — ваниль 26.2 делает сама | ❌ |
| Лишние барьеры и layout-переходы между проходами | точечная правка | по мере чтения кода Blaze3D |
| Staging через host-visible VMA одним большим кольцом | опционально | по мере надобности |
| Асинхронная загрузка текстур на transfer-очереди | риск | отложено |
Существующие Vulkan-миксины LoVisual (VulkanDeviceMixin и др.) не переписываем, новый код подключается рядом.
Что нового в референсе 1.0.2-1.0.3 (сверено 2026-10-12)
Референс обновился с 1.0.1 до 1.0.3 (+166 файлов). Что важно для нашего плана:
- FrameFence/RealFence для 26.2 не нужен. Комментарий в
26.1.2/gl/GlCommandEncoderMixin: «26.1 ещё делает GL-sync на каждый fence; с 26.2 ваниль делает один fence на submit и ждёт его по индексу submit'а». ХукcreateFenceпереехал из26.xв модуль26.1.2, в 26.2 его нет; в changelog прямо сказано, что опция «Один fence на кадр» оставлена только для 26.1.2, с 26.2 это делает игра. Плюс история краша Xaero's World Map («Cannot wait on a fence for the current submit») при общем fence — риск, который ваниль уже закрыла. => Пункт «FrameFence/RealFence» из Этапа 3 вычеркиваем; остаётся только хук конца кадра (MinecraftFrameMixin:SkinAtlas.endFrame,AnimFreeze.frame++,refresh()конфига). - Счётчики draw-вызовов (
DrawStats,common/gl/DrawStats.java, 75 строк) — ровно наше заявленное предусловие «перед Этапом 3 нужен профиль HUD: число draw-вызовов и смен состояния на кадр». Считает draws/flush'и слоёв/FBO-bind'ы, средние за секунду, топ-5 слоёв, рисует только пока открыт F3. Дёшево, даёт данные для раздела «Дополнительные GL-оптимизации». => Включить в Этап 3 первым пунктом. - Parallel Models (крупное новое, Impact HIGH).
26.2/ModelFeatureRendererMixinперехватываетbuildGroupи собирает группу submit'ов на нескольких ядрах (ParallelModelHook+ParallelModels+ два invoker'а). Заявлено +20-50% FPS в толпе бронированных мобов, отдельная опция. Отключается при <4 ядрах и при активном шейдерпаке Iris (!(IRIS && IrisApi…isShaderPackInUse())— Iris собирает расширенные атрибуты из вершин, отданных по одной). Зависит отAnimFreeze.freezes()(часть, которую нельзя реплеить) — ставить после AnimFreeze. - ItemLod получил точный таргет в 26.2:
entity/ItemFeatureRendererMixin—@WrapOperationнаSubmit.quads()вprepareMainSubmit/prepareOutlineSubmit/prepareFoilSubmit, плоские квады дальшеItemLod.distanceSq(). - Выброшенные предметы (новое):
no_item_sort(пропуск сортировкиitem_entity_translucent_cull, по умолчанию вкл, до +40% FPS на кучах),item_single_copy(стак одним предметом),ItemBounds(кэш AABB модели предмета, IdentityHashMap с полной очисткой >4096 — render state пересоздаётся каждый кадр, его собственный кэш умирает вместе с ним).BufferSourceMixin+RenderTypeAccessorживут в модуле26.1.2, в26.xих нет — перед переносом проверить, есть ли в 26.2MultiBufferSource.BufferSource.endBatch(RenderType, BufferBuilder)иRenderType.sortOnUpload(). - Фиксы HudCache, которые надо взять сразу (иначе воспроизведём баги): главный target снимается в
beginFrame(main = gameRenderer.mainRenderTarget()) и сравнение идёт с ним, а не с «текущим» — иначе редиректим чужой target (Xaero подменяет свой, пока рисует); двойной троттлингGuiItemRefresh+HudCacheприводил к пропавшим зачарованным предметам хотбара (фикс: пропускать свой троттлинг, когдаHudCache.active()); composite — premultiplied + write mask 7 (RGB), depth clear 0 (reversed depth в 26.x); кэш выключается при чужих HUD-кэшах (axolotlclient,exordium,gnetum) и под VulkanMod; интервал = рефреш-рейт монитора (MonitorRate, GLFW-опрос 1 раз в секунду). - Правило утечек: кэши с нативной памятью/GL-объектами чистить и на перезагрузку ресурсов (F3+T), и на смену мира.
Фикс 1.0.3:
BubbleColumnUpParticleMixinдержалClientLevelв статике через сильную ссылку — теперьWeakReference- очистка карты при смене уровня;
MovingBlockCache/ParallelModelsчинили утечки native/model.
- очистка карты при смене уровня;
- Порог параллельных частиц: план п.4 («авто-порог по замеру») упрощаем до того, что сделано в референсе —
CORES >= 4+-D…=auto|true|false; 6+ ядер оказалось догадкой (замер на 4 ядрах дал +12%), вернули к 4.Workersполучилstream()— публикация задач по мере готовности, рабочие берут их сразу, пока готовится остальное. - MixinPlugin — условная регистрация миксинов (Sodium/Vulkan/Lunar,
shouldApplyMixin+getMixins), а тумблеры в UI прячутся, если миксин не построен/не применяется (available()→MixinPlugin::applies). У нас уже естьmixins/LoVisualMixinPlugin— расширить для Vulkan (Этап 4) и для «миксин есть не всегда». - Не берём: Lunar multi-draw (лаунчер Lunar, не наш случай);
blockEntityEarlyCullперенесён только в1.21.9+, в26.xего нет — при случае проверить, применим ли к 26.2;26.3поддержка и26.3/renames.txtпригодятся при апгрейде версии (пакетcom.mojang.blaze3d→com.mojang.renderpearl).
Этапы
- ✅
core/+ helpers + adapter interfaces +OptimizeToggles(бэкенд-независимые части). Тесты, сборка. Завершён 2026-10-10 — 11 портированных .java, 53 теста, 0 падений,checkFolderLimitOK. - ✅ Бюджет кадра, профилировщик,
-Dlovisual.opt.*. Завершён 2026-10-10 —FrameBudget(3 режима: OFF/SOFT/AGGRESSIVE, target FPS, per-subsystem caps для entities/particles/HUD/effects/text/trails),FrameProfiler(5 секций, EMA, decay через 2 с idle),OptimizePropertyBridge(10 системных свойств +all=falseотключает всё),OptimizeDebugHudMixin(F3 overlay показывает тумблеры + бюджет + тайминги секций + override'ы). 22 новых теста. - ✅
gl/+ остаток рендера. Закрыт 2026-10-12, кроме п.9 (API-гейт). Готово 2026-10-10:RenderBackendOps,GlRenderBackendOps,RenderTypesMixin,GlCommandEncoderClearMixin,GlCommandEncoderTexBufferMixin. Готово 2026-10-10…10-11: миксиныLivingEntityLodMixin,ParticleMixin,BubbleColumnUpParticleMixin,SodiumEntityRendererMixin,BlockEntity*,ChestRendererMixin,LevelRendererOutlineMixin,BaseSpawnerMixin,EntityName/State/Renderer*. Осталось, в порядке приоритета (порядок пересмотрен 2026-10-12 по референсу 1.0.3):- ✅
DrawStats+ строки в F3 — счётчики draw/flush/bind за кадр (предусловие для решений о GL-оптимизациях; дёшево). Готово 2026-10-12 —DrawStats, миксиныmixins/optimize/stats/*(executeDraw/Draws/Indirect/Multiple, setPipeline, glBindFramebuffer), строка F3draws/pipelines/fbo binds, подключеныFrameProfiler.beginFrame/endFrame(баг Стадии 2: не вызывались в проде), 7 тестов. - ✅
SharedDepthFbosкластер —SharedDepthFbos(DSAglClearNamedFramebufferfv, fallback на ваниль без GL4.5/DSA),FrameBufferCacheMixin(remember/forget поgetFbo/destroyFbo),GlCommandEncoderDepthClearMixin(clearDepthTextureHEAD, cancellable),GlBufferCloseMixin(forgetTboCache()приcloseGlBuffer.Direct — чинит протухание TBO-кэша, id буфера переиспользуется). Готово 2026-10-12 — тумблерfbo_share(модуль +-Dlovisual.opt.fbo_share), методыRenderBackendOps.fboShareSupported/clearDepthInPlace, миксины вmixins/optimize/gl/иmixins/optimize/gl/fbo/, 8+3 тестов. Выкинут 2026-10-12 — в референсе 1.0.3 фичи нет на 26.2 (вSkinAtlasкластер26.2/нетSkinAtlas.java/LivingEntityRendererSkinMixin, флагskinAtlas()никем не вызывается; атлас скинов был только для 1.21.4, см. историю версий референса, раздел «1.21.4»). Как и FrameFence, не переносим.- ✅
AnimFreezeкластер —AnimFreeze(capture раз в тик, реплей в вершины),EntityAnimHolderMixin,AnimHolder, методfreezes(state, pose)(часть, построенная каждый кадр в другом месте, не реплеим — это и чинит рябь брони),RawVertices/SodiumVertices. Готово 2026-10-12 —AnimFreeze.configure(enabled, distance)(свой холдер, не OptimizeToggles), тумблерыentity_anim_freeze(по умолчанию выкл) +entity_anim_distance(16),frame++вMinecraftMixin.renderFrameHEAD, вызов изModelFeatureRendererMixin.prepareModel(@WrapOperationнаModel.renderToBuffer), инфраструктура сырых вершин из п.7 (RawBuffer/BufferBuilderRawMixin/RawVertices/SodiumVertices/VertexConsumerUtilsMixin), 3 теста. TypeBuilders не выделялся — свёрнут в приватные хелперыAnimFreeze. - ✅
ItemLod—ItemLod+ItemFeatureRendererMixin(@WrapOperationнаSubmit.quads()вprepareMain/Outline/FoilSubmit) +ItemBounds. Готово 2026-10-12 —ItemLod/ItemBoundsвrender/engine/optimize/entity/(вentity/теперь ровно 4 файла — лимит исчерпан), LOD-хук добавлен в существующийItemFeatureRendererMixin,ItemStackRenderStateMixin+ItemLayerAccessorвmixins/render/item/bounds/, тумблерыitem_lod/item_lod_distance(8)/item_bounds, 9 тестов. - ✅
HudCacheкластер —HudCache,MonitorRate,HudWorth(есть), миксиныGameRendererHudMixin,GuiHudMixin,GuiRendererTargetMixin,HudInvoker,HudLiveMixin; все фиксы совместимости из раздела выше — сразу. Готово 2026-10-12 — тумблерhud_cacheпо умолчанию выкл (взаимодействует с нашими deferred-HUD-маркерами вGuiRendererMixin); гейт наaxolotlclient/exordium/gnetum/vulkanmodчерез FabricLoader; main target снимается вbeginFrame; composite premultiplied + write mask 7, depth clear 0;HudInvokerв подпапкеhud/cache/invoker/(лимит 4 файлов), 9 тестов (MonitorRate clamp+троттлинг, HudWorth-гистерезис). - ✅
VertexConsumerUtilsMixin(кэшVertexBufferWriter, только при Sodium — вOPTIONAL_SODIUM_MIXINS) +BufferBuilderRawMixin/RawBuffer(запись без Sodium) +RawVertices/SodiumVertices. Готово 2026-10-12 (упреждённо, как предусловие п.4) — гейт наmicro_opts, 2 миксина вmixins/optimize/gl/raw/. - ✅
ParallelModels—ParallelModelHook,ModelFeatureRendererMixin(buildGroupcancellable), invoker'ы; послеAnimFreeze(зависит отfreezes()). Готово 2026-10-12 —ParallelModels/ParallelModelHook/ModelGeometry/ModelBuilderвrender/engine/optimize/parallel/(оригинальный 348-строчный класс разбит на 4 файла, лимит 250),Workersполучилstream()(публикация по мере готовности), 3 интефейса вmixins/optimize/entity/parallel/,buildGroup-inject добавлен в существующийModelFeatureRendererMixin, тумблерparallel_models(on) с внутренними гейтами: ≥4 ядер, нет активного Iris-шейдерпака, взаимоисключение сAnimFreeze, форматDefaultVertexFormat.ENTITY(36 байт, оффсеты сверены javap),parts[0]=nullпротив утечки weak-map, native-страницы освобождаются вreset(), 7 тестов (3 stream + 4 гейтинг). - ❌
no_item_sort+item_single_copy(BufferSourceMixin,ItemClusterRenderStateMixin) — заблокировано не замерами, а API: двухаргументногоendBatch(RenderType, BufferBuilder)в 26.2BufferSourceнет,MeshData.DrawStateбез sort-методов; в референсе эти миксины живут в26.1.2, на26.xих нет. Нужен дизайн под 26.2-API, а не отчёт по FPS. Хук конца кадра не нужен отдельнымMinecraftFrameMixin:renderFrameу нас уже перехвачен (mixins/render/main/MinecraftMixin), туда же вешаемSkinAtlas.endFrame/AnimFreeze.frame++/конфиг-refresh(). FrameFence/RealFence вычеркнут — см. «Что нового», ваниль 26.2 делает это сама.
- ✅
- 🔄
vulkan/: начинаем с универсально-полезного — персистентныйVkPipelineCache, кэш состояния вVulkanRenderPass. Барьеры/staging/async — по мере чтения Blaze3D-кода, не по замерам. Готово 2026-10-12:не начат→ старт, первый пункт. - (опционально, вне плана) Отчёт цифр «до/после» на реальной сборке — факультативно, не блокирует Этапы 3-4.
Оценки для Этапов 3-4 (после Stage 1-2)
- Этап 3: закрыт, кроме п.9 (заблокирован API 26.2).
- Этап 4: два универсально-полезных пункта (
VkPipelineCache, state cache) — по 1 сессии каждый; барьеры/staging/async — по ходу чтения Blaze3D.
Риски
- Миксины 26.2 проверяются компиляцией и юнитами; живой запуск (
./gradlew runClient) — на стороне того, у есть GUI-машина, но это не гейт: код слияем, default-off тумблеры снижают риск. - Совместимость с ImmediatelyFast и Iris в 26.2 не проверена in-code; держим дефолты консервативными.
- Лимиты размера файлов проекта требуют дробить крупные классы референса (фасад + package-private хелперы) — соблюдается.
- Выигрыш по Vulkan подтверждаем чтением
com.mojang.blaze3d.vulkan, а не замерами; если пункт окажется вредным — default-off.
Вне объёма
Ускорение ландшафта (замена Sodium), авто-деградация без явного включения пользователем.