Skip to content

ShaderLoadUtil.getShaderSource() ignores the Identifier's namespace, so any mod's custom RenderPipeline with shaders in its own jar fails to compile (breaks Litematica schematic rendering) #881

Description

@GreenSurge

Summary

Any mod that registers its own RenderPipeline pointing at shaders bundled in that mod's own jar fails silently under VulkanMod, because ShaderLoadUtil's shader source lookup only ever searches inside VulkanMod's own jar and discards the Identifier's namespace when building the file path. This affects malilib's custom terrain pipelines (used by Litematica for schematic rendering), and presumably any other mod doing the same normal, spec-compliant thing with the RenderPipeline API.

Reproduction

  1. Install Fabric 1.21.11 + VulkanMod + malilib + Litematica.
  2. Load into a world with a schematic loaded in Litematica.
  3. Schematic renders blank, invisible, or with wrong/garbage coloring instead of the expected ghost-block overlay. Disabling VulkanMod (falling back to the vanilla renderer) fixes it immediately.

Root cause

net.vulkanmod.render.shader.ShaderLoadUtil:

public static final String RESOURCES_PATH =
    SpirvCompiler.class.getResource("/assets/vulkanmod").toExternalForm();
...
public static String getShaderSource(Identifier resourceLocation, ShaderType type) {
    String path = resourceLocation.getPath();   // namespace discarded here
    String[] splitPath = splitPath(path);
    String shaderName = "%s%s".formatted(splitPath[1], shaderExtension);
    String shaderFile = "%s/shaders/%s/%s".formatted(RESOURCES_PATH, path, shaderName);
    // falls back to "%s/shaders/%s%s".formatted(RESOURCES_PATH, path, shaderExtension)
    ...
}

RESOURCES_PATH is hardcoded to VulkanMod's own jar (/assets/vulkanmod), and resourceLocation.getNamespace() is never consulted. So when VkGpuDevice.compilePipeline (via VkRenderPass.setPipeline's lazy on-demand compile path) needs to resolve, say, malilib:legacy_terrain, it only ever looks for .../assets/vulkanmod/shaders/legacy_terrain... inside VulkanMod's own jar. It never finds it (the file actually lives in malilib's jar at assets/malilib/shaders/legacy_terrain.vsh/.fsh), getShaderSource returns null, and the pipeline compiles incorrectly/incompletely.

I confirmed this by cloning both xCollateral/VulkanMod (dev branch, MC 1.21.11) and sakura-ryoko/malilib (LTS/1.21.11) and tracing the actual call path:

  • fi.dy.masa.malilib.mixin.render.MixinRenderPipelines registers LEGACY_SOLID_TERRAIN_MASA etc. via the standard RenderPipelines/RenderPipeline.builder(...) API, pointing at getId("legacy_terrain") (i.e. malilib:legacy_terrain), with the actual shader files at src/main/resources/assets/malilib/shaders/legacy_terrain.vsh / .fsh in malilib's own jar.
  • fi.dy.masa.litematica.render.schematic.ChunkRenderLayers uses those pipelines for schematic terrain rendering.
  • net.vulkanmod.render.engine.VkRenderPass#setPipeline lazily calls VkGpuDevice#compilePipeline the first time a given RenderPipeline is drawn, which is otherwise a nice generic design (not a hardcoded whitelist) -- it's specifically the shader source lookup inside that path that's jar-scoped and namespace-blind.

Suggested fix

In getShaderSource(Identifier, ShaderType), when the in-jar lookup misses, fall back to resolving the Identifier's namespace to its owning mod (e.g. via Fabric Loader's FabricLoader.getInstance().getModContainer(namespace) and ModContainer#findPath(...)) and read the shader from there, mirroring the same two-tier path/name.ext -> path.ext lookup order already used for VulkanMod's own shaders. Happy to open a PR with this if useful -- I already wrote and tested the approach as a standalone compat mod (mixin into getShaderSource, fallback via ModContainer#findPath) and it's a small, self-contained change.

Environment

  • Minecraft 1.21.11
  • VulkanMod dev branch / 0.6.8+1.21.11-dev
  • malilib LTS/1.21.11 (sakura-ryoko fork), Litematica LTS/1.21.11 (sakura-ryoko fork)
  • Fabric Loader 0.19.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions