Per mod/docs/optimize-layer-design.md Stage 3 (partial). This commit ships
the simplest GL mixins and the strategy interface that splits GL/Vulkan
backends. SkinAtlas/AnimFreeze/HudCache/FrameFence deferred to a later pass
because they're more complex (vertex-format / glCopyImageSubData /
RenderPipeline+RenderPass).
RenderBackendOps interface (features/.../optimize/gl/RenderBackendOps.java):
- Backend-agnostic surface for lazy clear, TBO cache, RenderTypes cache.
- current() resolves the active backend — returns GlRenderBackendOps on GL,
null on Vulkan (so all WrapOperations fall through to the vanilla call).
- Stage 4 will add a VulkanRenderBackendOps no-op implementation.
GlRenderBackendOps (features/.../optimize/gl/GlRenderBackendOps.java):
- Concrete GL implementation. Three caches ported from ZakoOpt:
* Lazy clear (from zako.opt.mixin.gl.GlCommandEncoderClearMixin).
* TBO cache (from zako.opt.gl.TexBufferCache + the TexBufferMixin).
* RenderTypes cache (from zako.opt.mixin.gl.RenderTypesMixin).
- All three gated on OptimizeToggles.microOpts() (the Stage 1 'micro_opts'
toggle wired in Optimize.java).
- Includes test helpers (resetForTesting, boundTboTextureForTesting,
cachedRenderTypeCountForTesting).
Three new mixins (mixins/optimize/):
- RenderTypesMixin: WrapOperation on RenderTypes.entityTranslucent's
BiFunction.apply — cache by Identifier when flag=true (the common case).
Drops the per-call Objects.hash(Pair) hit.
- GlCommandEncoderClearMixin: WrapOperation on GlCommandEncoder's
clearColorAndDepthTextures → GlStateManager._glBindFramebuffer — skip the
bind-framebuffer-0 because the next render pass binds its own target
anyway and GlStateManager's cache already skips redundant binds.
- GlCommandEncoderTexBufferMixin: WrapOperation on GlCommandEncoder's
trySetup → glBindTexture (track bound) and glTexBuffer (skip re-attach
when the same (format, buffer) pair is already attached). Re-attaching
makes the driver revalidate the texture (clouds: ~2% of a frame).
lovisual.mixins.json:
- Register all three mixins + OptimizeDebugHudMixin in the 'client' array,
alphabetically under optimize.* (before accessors.*).
OptimizeDebugHudMixin (mixins/optimize/OptimizeDebugHudMixin.java):
- F3 overlay for the Optimize layer — Stage 2 of the design doc.
- Adds three blocks of lines to F3 (after the existing LoVisual Engine block):
* 'LoVisual Optimize' — toggles summary + budget mode + scale + frame time.
* 'frame:' — EMA-averaged per-section timings (entities/particles/HUD/effects/text).
* 'props:' — when any -Dlovisual.opt.* is set, list which ones.
- Mirrors the existing hud.DebugHudMixin pattern (ModifyArg on extractLines).
Tests (JUnit 5): 11 new tests in GlRenderBackendOpsTest — pure-logic pieces
of RenderBackendOps + Identifier equality/hash. Total suite: 849 tests,
0 failures. checkFolderLimit: OK (0 folders >4).