diff --git a/mod/docs/optimize-layer-design.md b/mod/docs/optimize-layer-design.md index f240bf10..56609205 100644 --- a/mod/docs/optimize-layer-design.md +++ b/mod/docs/optimize-layer-design.md @@ -3,6 +3,12 @@ Статус: Этапы 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` / diff --git a/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/gl/RenderBackendOps.java b/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/gl/RenderBackendOps.java index 00605c8f..3f2feedf 100644 --- a/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/gl/RenderBackendOps.java +++ b/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/gl/RenderBackendOps.java @@ -1,5 +1,8 @@ package dev.loki.lovisual.features.module.modules.misc.optimize.gl; +import com.mojang.blaze3d.systems.RenderSystem; +import dev.loki.lovisual.features.module.modules.misc.optimize.vulkan.VulkanRenderBackendOps; + /** * Backend-agnostic surface for the optimization layer's GL/Vulkan hooks. * @@ -29,8 +32,30 @@ package dev.loki.lovisual.features.module.modules.misc.optimize.gl; */ public interface RenderBackendOps { - /** Resolve the current backend — GL backend if GL is active, otherwise {@code null}. */ + /** + * Resolve the current backend by inspecting the active {@code GpuDeviceBackend}. + * Class-name check (not {@code instanceof}) so this method itself does not + * force the loader to link {@code GlDevice} or {@code VulkanDevice}; the + * Blaze3D jar always ships both, but keeping the check by string means the + * dispatch stays correct even when only one backend's class has been + * resolved. Falls back to the GL impl when the device is null (early boot) + * so mixins' {@code supported()} short-circuits behave the same as before. + */ static RenderBackendOps current() { + Object device; + try { + device = RenderSystem.getDevice(); + } catch (Throwable ignored) { + // Tests and pre-init paths call current() before RenderSystem has a + // device; fall through to GL so existing unit tests keep passing. + device = null; + } + if (device != null) { + String name = device.getClass().getName(); + if (name.startsWith("com.mojang.blaze3d.vulkan.")) { + return VulkanRenderBackendOps.current(); + } + } return GlRenderBackendOps.current(); } diff --git a/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/vulkan/VulkanRenderBackendOps.java b/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/vulkan/VulkanRenderBackendOps.java new file mode 100644 index 00000000..fccf117a --- /dev/null +++ b/mod/src/main/java/dev/loki/lovisual/features/module/modules/misc/optimize/vulkan/VulkanRenderBackendOps.java @@ -0,0 +1,97 @@ +package dev.loki.lovisual.features.module.modules.misc.optimize.vulkan; + +import dev.loki.lovisual.features.module.modules.misc.optimize.gl.RenderBackendOps; + +/** + * Vulkan-side implementation of {@link RenderBackendOps}. All GPU-object ops + * (lazy clear, TBO cache, shared depth FBO, RenderTypes cache) currently live + * in the GL mixin set — under Vulkan those mixins never load, so this class is + * a no-op placeholder that lets {@code RenderBackendOps.current()} dispatch by + * actual backend instead of unconditionally returning the GL impl. + * + *

Every {@code *Supported} reports {@code false}. Callers already gate on + * supported before attempting, so the effect is the same as "Optimize GPU + * features off" for backend-dependent items. Stage 4 adds Vulkan-specific + * paths (persistent {@code VkPipelineCache}, {@code VulkanRenderPass} state + * cache) by flipping the corresponding {@code *Supported} here to true and + * implementing the op body. + * + *

Doc reference: {@code mod/docs/optimize-layer-design.md}, "Этап 4" and + * "Что уже решено в архитектуре" → "Рендер-бэкенды". + */ +public final class VulkanRenderBackendOps implements RenderBackendOps { + + private static final VulkanRenderBackendOps INSTANCE = new VulkanRenderBackendOps(); + + private VulkanRenderBackendOps() { + } + + /** Singleton — no state, no per-device instance needed. */ + public static VulkanRenderBackendOps current() { + return INSTANCE; + } + + // --- Lazy clear --- + + @Override + public boolean lazyClearSupported() { + return false; + } + + @Override + public boolean skipBindFramebufferZero(int framebuffer) { + return false; + } + + // --- TBO cache --- + + @Override + public boolean tboCacheSupported() { + return false; + } + + @Override + public void trackBoundTboTexture(int texture) { + } + + @Override + public boolean tboAlreadyAttached(int format, int buffer) { + return false; + } + + @Override + public void markTboAttached(int format, int buffer) { + } + + @Override + public void forgetTboCache() { + } + + // --- FBO share --- + + @Override + public boolean fboShareSupported() { + return false; + } + + @Override + public boolean clearDepthInPlace(int depthId, double value) { + return false; + } + + // --- RenderTypes cache --- + + @Override + public boolean renderTypesCacheSupported() { + return false; + } + + @Override + public Object renderTypeFor(Identifier id) { + return null; + } + + @Override + public void cacheRenderType(Identifier id, Object type) { + } +}