fix(compat): restore BetterPortals Refitted end portal rendering - #110
Merged
Conversation
Repackage org.joml under org.embeddedt.embeddium.impl.shadow.joml inside the distributed jar, matching the upstream Celeritas shadow layout, while the bundled joml jar stays nested for third-party mods that link against the original namespace. Dev runs inject the shaded jar via crl.dev.extrapath only, keeping it invisible to the application classloader to avoid splitting mixin classes.
ExtraUtilities2's XUBlockStatic anonymous getQuads implementation mutates a plain HashMap from ChunkBuilderMeshingTask worker threads, crashing with ConcurrentModificationException once Celeritas meshing runs concurrently with portal view passes. Redirect computeIfAbsent through a synchronized wrapper; the accessor keeps refmap remapping by not disabling remap.
Strict preprocessor separation rejects shaders whose conditional directives interleave with GLSL tokens, which made BetterPortals' portal shader fail to initialize. Fall back to an evaluated-conditional path that keeps only the taken branch, hoist leading comments into the preprocessor section to avoid a glsl-lib injectFunction index fault, and parse integer literals before identifiers so version guards evaluate correctly.
Per-component writes to a pre-initialized texGenCoord let NVIDIA drivers dead-code-eliminate the uniform feeding a lone component (observed: u_TexGenEyePlaneS dropped from GL_ACTIVE_UNIFORMS while T/R survive), collapsing end-portal EYE_LINEAR texgen into stripes. Emit the equivalent single-expression vec4 constructor instead; regression test parses the generated GLSL and asserts the constructor feeds all eye planes.
BetterPortals draws its starfield overlay through a synthetic world-less dummy TileEntityEndPortal and relies on the vanilla render path's blend hooks (CONSTANT_ALPHA fade via shouldRenderFace) and projective texgen. The replacement-renderer mixin cancelled that call unconditionally, breaking the overlay. EndPortalRenderPolicy now routes only real world block entities to the core-profile renderer and leaves synthetic calls on the legacy path executed through the glsm FFP simulation.
The cached currentVertexFlags only reflect the last buffer-state setup, so a client-array draw could select an FFP variant reading attributes it does not provide (e.g. a black default vertex color for a POSITION-only draw). Raw draw entry points now use preDrawFFP(), which derives flags from the VAO's actually enabled attributes when client-side arrays are in play and keeps the cached flags otherwise.
The BPR render_portal regression slipped through because the case only asserted eliminated symbols. Also assert the uniforms Forge looks up by name (sampler, screenSize, opacity, fogColor, fogDensity) stay present.
…uential passes BetterPortals renders the remote dimension and the main world as two sequential renderWorldPass calls in one frame (swapping Minecraft.world and the target framebuffer between them). preparePipeline treated each dimension flip as a world unload: destroyPipeline() plus a full reload twice per frame, killing the celeritas workers every time so terrain never got rebuilt (5 fps, main world terrain gone once a portal entered the view). Keep one pipeline per dimension cached and switch between them; terrain chunk programs embed per-pipeline state, so IrisCeleritasChunkProgram Overrides now keys its program cache by pipeline instance. The Iris injections on renderWorldPass keep a pure-depth RenderWorldRecursionGuard as defense against true nested re-entry only; sequential passes are served by the cache. MinecraftFramebufferHelper resolves the current framebuffer dynamically so Iris composites land in the portal FBO that BetterPortals swapped in, giving both worlds their own shader effects.
…er under shaders With a shader pack active the starfield overlay of BetterPortals (a world-less dummy TileEntityEndPortal drawn through the vanilla TESR) could never execute its legacy path: an Iris gbuffers program owns the entity-phase draw and glsm defers to the bound program, so the texgen fixed-function emulation is bypassed and the Iris program misreads the POSITION_COLOR vertex stream. The overlay ended up nearly invisible and flickered while rotating the view. World-less render calls now go through the shader-compatible replacement renderer when a shader pack is in use (no-shader behavior unchanged). The BetterPortals fade hook still fires from its shouldRenderFace override during face evaluation: it is recognized by the tracked CONSTANT_ALPHA blend factor pair, the constant alpha is read back from the real GL state (the hook writes it through a raw glBlendColor that bypasses glsm tracking), and the opacity is folded into the first sky layer's vertex alpha, the exact SRC_ALPHA equivalent of the legacy CONSTANT_ALPHA blend. Additive layers keep full strength and precomposition is skipped for fading overlays since a single composited quad cannot fade the sky layer alone. The pre-hook blend state is restored after the call so the hook cannot leak into later rendering.
The per-dimension pipeline cache kept every visited dimension's pipeline (including its full-resolution render targets) alive until the next shaderpack reload or world unload, so portal mods and dimension travel accumulated GPU memory without bound. Pipelines now carry a last-used timestamp; preparePipeline runs a throttled scan (once per second) and destroys any non-active dimension pipeline that has been idle for more than 30 seconds, using the same teardown sequence as destroyPipeline(). The terrain chunk program cache lazily drops programs whose pipeline is no longer cached, so their GL objects do not leak either. The currently rendered dimensions refresh their timestamp every pass and are never evicted; recreating a pipeline after eviction is the same one-time cost as the first creation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
修复 BetterPortals Refitted(0.4.1)末地传送门的视觉兼容性。修复前:无光影下没有"看穿看到末地"的效果(洞口只见星野贴图)且视觉位置低约一格;开启光影后传送门进入视角即严重卡顿(约 5 fps)、主世界地形整体消失;风暴修复后星野叠加层仍几乎不可见且随视角转动闪烁。传送功能本身一直正常。
根因与改动(四层根因叠加,详见 docs/compat/betterportals.md)
d4af535):逐分量覆写模式让驱动 DCE 掉u_TexGenEyePlaneS,星野被拉成竖直条纹。改为单表达式vec4构造,语义等价。96e318d):BPR 用无 world 的合成 dummy TE 调原版 TESR 画星野叠加层,依赖 shouldRenderFace 里的 blend 钩子;新增EndPortalRenderPolicy按调用来源分流,无光影下放行 legacy 路径由 glsm FFP 模拟执行。e61d697)+ compat shader uniform 存活断言(a266e75)。7ccf0ce):BPR 顺序双 pass 每帧往返切换维度,preparePipeline 每次切换都销毁重建管线并杀 celeritas worker → 地形永远来不及重建。改为按维度缓存切换;地形 program 缓存按管线实例分键;合成写入动态读取的当前 framebuffer,两个世界各自获得完整光影效果。a26efe2):实体阶段 Iris gbuffers program 已绑定,glsm 让位导致 texgen FFP 仿真永远不执行。光影下合成 TE 改走为光影设计的替代渲染器,并完整复刻 BPR 的 CONSTANT_ALPHA 淡出钩子(检测因子对 + 从真实 GL 状态读回常量 alpha,折入首层顶点 alpha)。162ed0e):停止渲染 30 秒以上的维度管线自动销毁(render target 组不再永久驻留),地形 program 缓存惰性同步清理。如何验证
./gradlew build --no-daemon全绿(含check:JUnit 自动化测试 + remap jar 结构/桥契约测试)。Destroying idle pipeline for dimension,重新看门时管线一次性重建、无每帧风暴。验证过的光影包与模组
遗留
文档
docs/compat/betterportals.md:兼容状态更新为已验证,记录全部四层根因与验证记录。docs/compatibility-matrix.md:BetterPortals Refitted 行更新为已验证。