ShaderManager.java

net.minecraft.client.renderer.ShaderManager

信息

  • 全限定名:net.minecraft.client.renderer.ShaderManager
  • 类型:public class
  • 包:net.minecraft.client.renderer
  • 源码路径:src/main/java/net/minecraft/client/renderer/ShaderManager.java
  • 起始行号:L47
  • 继承:SimplePreparableReloadListener<ShaderManager.Configs>
  • 实现:AutoCloseable
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L48
    • 说明:

      TODO

  • MAX_LOG_LENGTH

    • 类型: int
    • 修饰符: public static final
    • 源码定位: L49
    • 说明:

      TODO

  • SHADER_PATH

    • 类型: String
    • 修饰符: public static final
    • 源码定位: L50
    • 说明:

      TODO

  • SHADER_INCLUDE_PATH

    • 类型: String
    • 修饰符: private static final
    • 源码定位: L51
    • 说明:

      TODO

  • POST_CHAIN_ID_CONVERTER

    • 类型: FileToIdConverter
    • 修饰符: private static final
    • 源码定位: L52
    • 说明:

      TODO

  • textureManager

    • 类型: TextureManager
    • 修饰符: private final
    • 源码定位: L53
    • 说明:

      TODO

  • recoveryHandler

    • 类型: Consumer<Exception>
    • 修饰符: private final
    • 源码定位: L54
    • 说明:

      TODO

  • compilationCache

    • 类型: ShaderManager.CompilationCache
    • 修饰符: private
    • 源码定位: L55
    • 说明:

      TODO

  • postChainProjection

    • 类型: Projection
    • 修饰符: private final
    • 源码定位: L56
    • 说明:

      TODO

  • postChainProjectionMatrixBuffer

    • 类型: ProjectionMatrixBuffer
    • 修饰符: private final
    • 源码定位: L57
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.renderer.ShaderManager.CompilationCache

    • 类型: class
    • 修饰符: private
    • 源码定位: L212
    • 说明:

      TODO

  • net.minecraft.client.renderer.ShaderManager.CompilationException

    • 类型: class
    • 修饰符: public static
    • 源码定位: L263
    • 说明:

      TODO

  • net.minecraft.client.renderer.ShaderManager.Configs

    • 类型: record
    • 修饰符: public
    • 源码定位: L270
    • 说明:

      TODO

  • net.minecraft.client.renderer.ShaderManager.ShaderSourceKey

    • 类型: record
    • 修饰符: private
    • 源码定位: L275
    • 说明:

      TODO

构造器

public ShaderManager(TextureManager textureManager, Consumer<Exception> recoveryHandler) @ L59

  • 构造器名:ShaderManager
  • 源码定位:L59
  • 修饰符:public

参数:

  • textureManager: TextureManager
  • recoveryHandler: Consumer

说明:

TODO

方法

下面的方法块按源码顺序生成。

protected ShaderManager.Configs prepare(ResourceManager manager, ProfilerFiller profiler) @ L65

  • 方法名:prepare
  • 源码定位:L65
  • 返回类型:ShaderManager.Configs
  • 修饰符:protected

参数:

  • manager: ResourceManager
  • profiler: ProfilerFiller

说明:

TODO

private static void loadShader(Identifier location, Resource resource, ShaderType type, Map<Identifier,Resource> files, Builder<ShaderManager.ShaderSourceKey,String> output) @ L86

  • 方法名:loadShader
  • 源码定位:L86
  • 返回类型:void
  • 修饰符:private static

参数:

  • location: Identifier
  • resource: Resource
  • type: ShaderType
  • files: Map<Identifier,Resource>
  • output: Builder<ShaderManager.ShaderSourceKey,String>

说明:

TODO

private static GlslPreprocessor createPreprocessor(Map<Identifier,Resource> files, Identifier location) @ L100

  • 方法名:createPreprocessor
  • 源码定位:L100
  • 返回类型:GlslPreprocessor
  • 修饰符:private static

参数:

  • files: Map<Identifier,Resource>
  • location: Identifier

说明:

TODO

private static void loadPostChain(Identifier location, Resource resource, Builder<Identifier,PostChainConfig> output) @ L138

  • 方法名:loadPostChain
  • 源码定位:L138
  • 返回类型:void
  • 修饰符:private static

参数:

  • location: Identifier
  • resource: Resource
  • output: Builder<Identifier,PostChainConfig>

说明:

TODO

private static boolean isShader(Identifier location) @ L149

  • 方法名:isShader
  • 源码定位:L149
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • location: Identifier

说明:

TODO

protected void apply(ShaderManager.Configs preparations, ResourceManager manager, ProfilerFiller profiler) @ L153

  • 方法名:apply
  • 源码定位:L153
  • 返回类型:void
  • 修饰符:protected

参数:

  • preparations: ShaderManager.Configs
  • manager: ResourceManager
  • profiler: ProfilerFiller

说明:

TODO

public String getName() @ L178

  • 方法名:getName
  • 源码定位:L178
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

private void tryTriggerRecovery(Exception exception) @ L183

  • 方法名:tryTriggerRecovery
  • 源码定位:L183
  • 返回类型:void
  • 修饰符:private

参数:

  • exception: Exception

说明:

TODO

public PostChain getPostChain(Identifier id, Set<Identifier> allowedTargets) @ L190

  • 方法名:getPostChain
  • 源码定位:L190
  • 返回类型:PostChain
  • 修饰符:public

参数:

  • id: Identifier
  • allowedTargets: Set

说明:

TODO

public void close() @ L201

  • 方法名:close
  • 源码定位:L201
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public String getShader(Identifier id, ShaderType type) @ L207

  • 方法名:getShader
  • 源码定位:L207
  • 返回类型:String
  • 修饰符:public

参数:

  • id: Identifier
  • type: ShaderType

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class ShaderManager extends SimplePreparableReloadListener<ShaderManager.Configs> implements AutoCloseable {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final int MAX_LOG_LENGTH = 32768;
    public static final String SHADER_PATH = "shaders";
    private static final String SHADER_INCLUDE_PATH = "shaders/include/";
    private static final FileToIdConverter POST_CHAIN_ID_CONVERTER = FileToIdConverter.json("post_effect");
    private final TextureManager textureManager;
    private final Consumer<Exception> recoveryHandler;
    private ShaderManager.CompilationCache compilationCache = new ShaderManager.CompilationCache(ShaderManager.Configs.EMPTY);
    private final Projection postChainProjection = new Projection();
    private final ProjectionMatrixBuffer postChainProjectionMatrixBuffer = new ProjectionMatrixBuffer("post");
 
    public ShaderManager(TextureManager textureManager, Consumer<Exception> recoveryHandler) {
        this.textureManager = textureManager;
        this.recoveryHandler = recoveryHandler;
        this.postChainProjection.setupOrtho(0.1F, 1000.0F, 1.0F, 1.0F, false);
    }
 
    protected ShaderManager.Configs prepare(ResourceManager manager, ProfilerFiller profiler) {
        Builder<ShaderManager.ShaderSourceKey, String> shaderSources = ImmutableMap.builder();
        Map<Identifier, Resource> files = manager.listResources("shaders", ShaderManager::isShader);
 
        for (Entry<Identifier, Resource> entry : files.entrySet()) {
            Identifier location = entry.getKey();
            ShaderType shaderType = ShaderType.byLocation(location);
            if (shaderType != null) {
                loadShader(location, entry.getValue(), shaderType, files, shaderSources);
            }
        }
 
        Builder<Identifier, PostChainConfig> postChains = ImmutableMap.builder();
 
        for (Entry<Identifier, Resource> entryx : POST_CHAIN_ID_CONVERTER.listMatchingResources(manager).entrySet()) {
            loadPostChain(entryx.getKey(), entryx.getValue(), postChains);
        }
 
        return new ShaderManager.Configs(shaderSources.build(), postChains.build());
    }
 
    private static void loadShader(
        Identifier location, Resource resource, ShaderType type, Map<Identifier, Resource> files, Builder<ShaderManager.ShaderSourceKey, String> output
    ) {
        Identifier id = type.idConverter().fileToId(location);
        GlslPreprocessor preprocessor = createPreprocessor(files, location);
 
        try (Reader reader = resource.openAsReader()) {
            String source = IOUtils.toString(reader);
            output.put(new ShaderManager.ShaderSourceKey(id, type), String.join("", preprocessor.process(source)));
        } catch (IOException var12) {
            LOGGER.error("Failed to load shader source at {}", location, var12);
        }
    }
 
    private static GlslPreprocessor createPreprocessor(Map<Identifier, Resource> files, Identifier location) {
        final Identifier parentLocation = location.withPath(FileUtil::getFullResourcePath);
        return new GlslPreprocessor() {
            private final Set<Identifier> importedLocations = new ObjectArraySet<>();
 
            @Override
            public @Nullable String applyImport(boolean isRelative, String path) {
                Identifier locationx;
                try {
                    if (isRelative) {
                        locationx = parentLocation.withPath(parentPath -> FileUtil.normalizeResourcePath(parentPath + path));
                    } else {
                        locationx = Identifier.parse(path).withPrefix("shaders/include/");
                    }
                } catch (IdentifierException var8) {
                    ShaderManager.LOGGER.error("Malformed GLSL import {}: {}", path, var8.getMessage());
                    return "#error " + var8.getMessage();
                }
 
                if (!this.importedLocations.add(locationx)) {
                    return null;
                } else {
                    try {
                        String var5;
                        try (Reader importResource = files.get(locationx).openAsReader()) {
                            var5 = IOUtils.toString(importResource);
                        }
 
                        return var5;
                    } catch (IOException var10) {
                        ShaderManager.LOGGER.error("Could not open GLSL import {}: {}", locationx, var10.getMessage());
                        return "#error " + var10.getMessage();
                    }
                }
            }
        };
    }
 
    private static void loadPostChain(Identifier location, Resource resource, Builder<Identifier, PostChainConfig> output) {
        Identifier id = POST_CHAIN_ID_CONVERTER.fileToId(location);
 
        try (Reader reader = resource.openAsReader()) {
            JsonElement json = StrictJsonParser.parse(reader);
            output.put(id, PostChainConfig.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(JsonSyntaxException::new));
        } catch (JsonParseException | IOException var9) {
            LOGGER.error("Failed to parse post chain at {}", location, var9);
        }
    }
 
    private static boolean isShader(Identifier location) {
        return ShaderType.byLocation(location) != null || location.getPath().endsWith(".glsl");
    }
 
    protected void apply(ShaderManager.Configs preparations, ResourceManager manager, ProfilerFiller profiler) {
        ShaderManager.CompilationCache newCompilationCache = new ShaderManager.CompilationCache(preparations);
        Set<RenderPipeline> pipelinesToPreload = new HashSet<>(RenderPipelines.getStaticPipelines());
        List<Identifier> failedLoads = new ArrayList<>();
        GpuDevice device = RenderSystem.getDevice();
        device.clearPipelineCache();
 
        for (RenderPipeline pipeline : pipelinesToPreload) {
            CompiledRenderPipeline compiled = device.precompilePipeline(pipeline, newCompilationCache::getShaderSource);
            if (!compiled.isValid()) {
                failedLoads.add(pipeline.getLocation());
            }
        }
 
        if (!failedLoads.isEmpty()) {
            device.clearPipelineCache();
            throw new RuntimeException(
                "Failed to load required shader programs:\n" + failedLoads.stream().map(entry -> " - " + entry).collect(Collectors.joining("\n"))
            );
        } else {
            this.compilationCache.close();
            this.compilationCache = newCompilationCache;
        }
    }
 
    @Override
    public String getName() {
        return "Shader Loader";
    }
 
    private void tryTriggerRecovery(Exception exception) {
        if (!this.compilationCache.triggeredRecovery) {
            this.recoveryHandler.accept(exception);
            this.compilationCache.triggeredRecovery = true;
        }
    }
 
    public @Nullable PostChain getPostChain(Identifier id, Set<Identifier> allowedTargets) {
        try {
            return this.compilationCache.getOrLoadPostChain(id, allowedTargets);
        } catch (ShaderManager.CompilationException var4) {
            LOGGER.error("Failed to load post chain: {}", id, var4);
            this.compilationCache.postChains.put(id, Optional.empty());
            this.tryTriggerRecovery(var4);
            return null;
        }
    }
 
    @Override
    public void close() {
        this.compilationCache.close();
        this.postChainProjectionMatrixBuffer.close();
    }
 
    public @Nullable String getShader(Identifier id, ShaderType type) {
        return this.compilationCache.getShaderSource(id, type);
    }
 
    @OnlyIn(Dist.CLIENT)
    private class CompilationCache implements AutoCloseable {
        private final ShaderManager.Configs configs;
        private final Map<Identifier, Optional<PostChain>> postChains;
        private boolean triggeredRecovery;
 
        private CompilationCache(ShaderManager.Configs configs) {
            Objects.requireNonNull(ShaderManager.this);
            super();
            this.postChains = new HashMap<>();
            this.configs = configs;
        }
 
        public @Nullable PostChain getOrLoadPostChain(Identifier id, Set<Identifier> allowedTargets) throws ShaderManager.CompilationException {
            Optional<PostChain> cached = this.postChains.get(id);
            if (cached != null) {
                return cached.orElse(null);
            } else {
                PostChain postChain = this.loadPostChain(id, allowedTargets);
                this.postChains.put(id, Optional.of(postChain));
                return postChain;
            }
        }
 
        private PostChain loadPostChain(Identifier id, Set<Identifier> allowedTargets) throws ShaderManager.CompilationException {
            PostChainConfig config = this.configs.postChains.get(id);
            if (config == null) {
                throw new ShaderManager.CompilationException("Could not find post chain with id: " + id);
            } else {
                return PostChain.load(
                    config,
                    ShaderManager.this.textureManager,
                    allowedTargets,
                    id,
                    ShaderManager.this.postChainProjection,
                    ShaderManager.this.postChainProjectionMatrixBuffer
                );
            }
        }
 
        @Override
        public void close() {
            this.postChains.values().forEach(chain -> chain.ifPresent(PostChain::close));
            this.postChains.clear();
        }
 
        public @Nullable String getShaderSource(Identifier id, ShaderType type) {
            return this.configs.shaderSources.get(new ShaderManager.ShaderSourceKey(id, type));
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public static class CompilationException extends Exception {
        public CompilationException(String message) {
            super(message);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Configs(Map<ShaderManager.ShaderSourceKey, String> shaderSources, Map<Identifier, PostChainConfig> postChains) {
        public static final ShaderManager.Configs EMPTY = new ShaderManager.Configs(Map.of(), Map.of());
    }
 
    @OnlyIn(Dist.CLIENT)
    private record ShaderSourceKey(Identifier id, ShaderType type) {
        @Override
        public String toString() {
            return this.id + " (" + this.type + ")";
        }
    }
}

引用的其他类