1.15.11+mc26.2-2026-07-10
Compatibility
Changes
Vulkan PostFX 1.15.11
This release focuses on the native VPFX render target lifecycle, improving performance, resource safety, temporal effect correctness, and backend fallback reliability.
Highlights
- Native render targets are now reused across frames instead of being recreated every frame.
- Render target resources are now owned by the active VPFX session.
- History and persistent targets are isolated between pack activations.
- History buffers now advance only when their target was actually written during the frame.
- Native runtime failures continue to fall back safely to Minecraft PostChain.
Added
-
Added a session-scoped native render target resource manager.
-
Added reusable caching for:
- Scene color snapshots
- Transient render targets
- Persistent render targets
- History targets
- Cross-frame ping-pong targets
-
Added immutable native target descriptors containing:
- Target identifier
- Width and height
- Texture format
- Depth usage
- Target type
-
Added native resource lifecycle statistics:
- Allocations
- Reuses
- Recreations
- Disposals
- Allocation failures
- Active owned resources
- Active borrowed resources
- Resource generation
-
Added native target statistics to the VPFX debug HUD.
-
Added lifecycle validation tests for resource reuse, resizing, failures, history state, session isolation, and fallback behavior.
Changed
-
Native render targets now remain allocated for the lifetime of the active VPFX session when their descriptors remain unchanged.
-
The meaning of a transient target has been clarified:
- Its contents do not persist between sessions.
- Its GPU allocation may still be reused between frames.
-
Persistent, history, and ping-pong resources are now fully session-scoped instead of being stored globally by runtime namespace.
-
Render target recreation now follows a safer sequence:
Create the replacement resource
→ Replace the cached reference
→ Destroy the previous resource
-
Native fallback now immediately releases native resources owned by the failed session.
-
Re-selecting the same shader pack still creates a new session and retries the native runtime.
-
Frame render target wrappers are now explicitly non-owning.
- GPU resource destruction is handled exclusively by the session resource manager.
-
Native clear behavior is now more deterministic:
- Transient targets are cleared on their first write each frame.
- Subsequent writes during the same frame preserve existing contents.
- Persistent and history buffers are initialized when created or resized.
- Depth targets use a default clear depth of
1.0.
-
Clear-color values are now defensively copied to prevent accidental shared-state modification.
Fixed
- Fixed native render targets being repeatedly created and destroyed every frame.
- Fixed old sessions potentially interfering with resources created by a new activation of the same pack.
- Fixed resource leaks when only part of a history or ping-pong target pair could be created.
- Fixed failed target recreation destroying the previous valid resource too early.
- Fixed failed allocations leaving incomplete cache entries.
- Fixed disposed native sessions silently returning to per-frame target allocation.
- Fixed native resources remaining allocated after the current session fell back to PostChain.
- Fixed history buffers sampling undefined memory on their first frame.
- Fixed failed frames incorrectly advancing history state.
- Fixed history and ping-pong targets being recreated without correctly invalidating previous history.
- Fixed native target format changes incorrectly reusing an incompatible cached target.
- Fixed persistent and history targets being reported as externally borrowed resources.
- Fixed per-frame logging caused by reused persistent targets.
- Fixed mutable default clear-color arrays being exposed to callers.
- Fixed history targets advancing even when no pass wrote to them during the frame.
History Buffer Correctness
History and cross-frame ping-pong targets now advance only when both conditions are met:
- The native frame completes successfully.
- The specific target was actually written during that frame.
Targets that were not written retain their previous:
- Read buffer
- Write buffer
- History validity state
This prevents temporal effects from accidentally sampling cleared, stale, or unwritten buffers.
Resource Ownership
VPFX now distinguishes between resources it owns and resources borrowed from Minecraft or other systems.
VPFX-owned resources
- Scene color snapshots
- Transient render targets
- Persistent render targets
- History buffer pairs
- Cross-frame ping-pong buffer pairs
- Diagnostic native targets
Borrowed resources
- Minecraft main framebuffer
- Scene depth
- Shadow depth
- External runtime textures
Borrowed resources are never destroyed by VPFX.
Validation
The native target lifecycle validation suite now contains 36 passing checks, covering:
- Resource reuse
- Resize recreation
- Format changes
- Allocation failure recovery
- Partial double-buffer creation rollback
- Session disposal
- Same-namespace session isolation
- Delayed old-session fallback
- History initialization and commit behavior
- Native fallback cleanup
- Pack switching
- Clear-color isolation
- History commit gating
Notes
- Ping-pong targets currently use cross-frame double buffering.
- Same-frame multi-pass ping-pong alternation is not yet supported.
- This release does not add new built-in visual effects.
- VPFX continues to prefer the native runtime and falls back to Minecraft PostChain only for the current failed activation.
- Selecting the pack again will retry the native backend.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:TsmOcOBN:QEAMyiVC"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:TsmOcOBN:QEAMyiVC"
}

