From be1335c435c4d075cffff571606d17bd475cccf9 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sat, 11 Apr 2026 22:38:07 +0800 Subject: [PATCH 01/45] =?UTF-8?q?=E9=87=8D=E6=9E=84=20Renderer=20=E5=B9=B6?= =?UTF-8?q?=E5=BC=95=E5=85=A5=20Renderer2=20=E4=BB=A5=E5=A2=9E=E5=BC=BA=20?= =?UTF-8?q?Vulkan=20=E6=B8=B2=E6=9F=93=E5=99=A8=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jackhuang/hmcl/game/Renderer.java | 13 +- .../org/jackhuang/hmcl/game/Renderer2.java | 122 ++++++++++++++++++ 2 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index a0b0c68db6..4ef932509d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -36,6 +36,11 @@ public enum Renderer { // Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while DOZEN(GraphicsAPI.VULKAN, "dzn", "dzn"), + ASAHI(GraphicsAPI.VULKAN, null, "asahi"), + NVIDIA(GraphicsAPI.VULKAN, null, "nvidia"), + NOUVEAU(GraphicsAPI.VULKAN, null, "nouveau"), + + LLVMPIPE(GraphicsAPI.OPENGL, "llvmpipe", null), ZINK(GraphicsAPI.OPENGL, "zink", null), D3D12(GraphicsAPI.OPENGL, "d3d12", null), @@ -56,12 +61,12 @@ public enum Renderer { private final GraphicsAPI api; - private final @Nullable String loaderName; + private final @Nullable String mesaDriverName; private final @Nullable String icdName; - Renderer(GraphicsAPI api, @Nullable String loaderName, @Nullable String icdName) { + Renderer(GraphicsAPI api, @Nullable String mesaDriverName, @Nullable String icdName) { this.api = api; - this.loaderName = loaderName; + this.mesaDriverName = mesaDriverName; this.icdName = icdName; } @@ -75,7 +80,7 @@ public boolean isSupported(GraphicsAPI api) { } public @Nullable String getMesaDriverName() { - return loaderName; + return mesaDriverName; } public @Nullable String getIcdName() { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java new file mode 100644 index 0000000000..a26c3f3424 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java @@ -0,0 +1,122 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2026 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.game; + +import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.OperatingSystem; +import org.jackhuang.hmcl.util.platform.Platform; +import org.jetbrains.annotations.NotNullByDefault; + +@NotNullByDefault +public sealed interface Renderer2 { + + GraphicsAPI api(); + + String name(); + + default boolean isSupported(GraphicsAPI api) { + return this.api() == api || this.api() == GraphicsAPI.DEFAULT; + } + + enum Known implements Renderer2 { + DEFAULT(GraphicsAPI.DEFAULT, "", ""), + + // Vulkan + + /// @see LLVMpipe - The Mesa 3D Graphics Library + LAVAPIPE(GraphicsAPI.VULKAN, "lavapipe", "lvp"), + + /// ## Note + /// Currently, Dozen does not support the VK_KHR_push_descriptor feature, so it cannot launch Minecraft 26.2 + /// Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while + DOZEN(GraphicsAPI.VULKAN, "dzn", "dzn") { + @Override + boolean isAvailable(Platform platform) { + return platform.os() == OperatingSystem.WINDOWS; + } + }, + + /// @see Vulkan Open Standard Modern GPU API | NVIDIA Developer + NVIDIA(GraphicsAPI.VULKAN, "", "nvidia"), + + /// @see NVK - The Mesa 3D Graphics Library + NVIDIA_NVK(GraphicsAPI.VULKAN, "", "nouveau") { + @Override + boolean isAvailable(Platform platform) { + return platform.os() == OperatingSystem.LINUX; + } + }, + + /// @see RADV - The Mesa 3D Graphics Library + AMD_RADV(GraphicsAPI.VULKAN, "", "radeon"), + + /// @see ANV - The Mesa 3D Graphics Library + INTEL_ANV(GraphicsAPI.VULKAN, "", "intel"), + + /// Intel HasVK driver. + INTEL_HASVK(GraphicsAPI.VULKAN, "", "intel_hasvk"), + + /// @see KosmicKrisp - The Mesa 3D Graphics Library + KOSMIC_KRISP(GraphicsAPI.VULKAN, "", "kosmickrisp_mesa"), + + // OpenGL + + /// @see LLVMpipe - The Mesa 3D Graphics Library + LLVMPIPE(GraphicsAPI.OPENGL, "llvmpipe", ""), + ZINK(GraphicsAPI.OPENGL, "zink", ""), + D3D12(GraphicsAPI.OPENGL, "d3d12", "") { + @Override + boolean isAvailable(Platform platform) { + return platform.os() == OperatingSystem.WINDOWS; + } + }, + ; + + private final GraphicsAPI api; + + private final String mesaDriverName; + private final String icdName; + + Known(GraphicsAPI api, String mesaDriverName, String icdName) { + this.api = api; + this.mesaDriverName = mesaDriverName; + this.icdName = icdName; + } + + boolean isAvailable(Platform platform) { + return true; + } + + /// Get the Graphics API used by this renderer. + @Override + public GraphicsAPI api() { + return api; + } + + public String mesaDriverName() { + return mesaDriverName; + } + + public String icdName() { + return icdName; + } + } + + record Unknown(GraphicsAPI api, String name) implements Renderer2 { + } +} From 1d1f8e396ed7183e4664ebaab948f2dc3c3bbdfa Mon Sep 17 00:00:00 2001 From: Glavo Date: Sat, 11 Apr 2026 23:23:13 +0800 Subject: [PATCH 02/45] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20Renderer2=20?= =?UTF-8?q?=E5=B9=B6=E5=90=88=E5=B9=B6=E5=8A=9F=E8=83=BD=E5=88=B0=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=90=8E=E7=9A=84=20Renderer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackhuang/hmcl/game/LauncherHelper.java | 9 +- .../hmcl/setting/VersionSetting.java | 10 +- .../versions/AdvancedVersionSettingPage.java | 36 ++-- .../jackhuang/hmcl/util/NativePatcher.java | 4 +- .../assets/lang/I18N_zh_CN.properties | 24 ++- .../jackhuang/hmcl/game/LaunchOptions.java | 4 +- .../org/jackhuang/hmcl/game/Renderer.java | 182 +++++++++++++----- .../org/jackhuang/hmcl/game/Renderer2.java | 122 ------------ .../hmcl/launch/DefaultLauncher.java | 72 ++++--- 9 files changed, 218 insertions(+), 245 deletions(-) delete mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 6191a3ecdc..8de795d7a6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -173,11 +173,10 @@ private void launch0() { } }), Task.composeAsync(() -> { - Renderer renderer = setting.getRenderer(); - if (renderer == null || renderer.getMesaDriverName() == null - || OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS) { + if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS + || !(setting.getRenderer() instanceof Renderer.Known renderer) + || renderer.mesaDriverName() == null) return null; - } Library lib = NativePatcher.getWindowsMesaLoader(java, renderer, OperatingSystem.SYSTEM_VERSION); if (lib == null) @@ -188,7 +187,7 @@ private void launch0() { return null; } - String agent = FileUtils.getAbsolutePath(file) + "=" + renderer.getMesaDriverName(); + String agent = FileUtils.getAbsolutePath(file) + "=" + renderer.mesaDriverName(); if (GameLibrariesTask.shouldDownloadLibrary(repository, version.get(), lib, integrityCheck)) { return new LibraryDownloadTask(dependencyManager, file, lib) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java index 27f51ac250..b6e8e9d9db 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java @@ -617,7 +617,7 @@ public void setGraphicsBackend(GraphicsAPI api) { graphicsBackendProperty().set(api); } - private final ObjectProperty rendererProperty = new SimpleObjectProperty<>(this, "renderer", Renderer.DEFAULT); + private final ObjectProperty rendererProperty = new SimpleObjectProperty<>(this, "renderer", Renderer.Known.DEFAULT); public Renderer getRenderer() { return rendererProperty.get(); @@ -836,7 +836,7 @@ public JsonElement serialize(VersionSetting src, Type typeOfSrc, JsonSerializati obj.addProperty("graphicsBackend", src.getGraphicsBackend().name()); obj.addProperty("renderer", src.getRenderer().name()); - if (src.getRenderer() == Renderer.LLVMPIPE) + if (src.getRenderer() == Renderer.Known.LLVMPIPE) obj.addProperty("useSoftwareRenderer", true); return obj; @@ -911,13 +911,13 @@ public VersionSetting deserialize(JsonElement json, Type typeOfT, JsonDeserializ vs.setRenderer(Optional.ofNullable(obj.get("renderer")).map(JsonElement::getAsString) .flatMap(name -> { try { - return Optional.of(Renderer.valueOf(name.toUpperCase(Locale.ROOT))); + return Optional.of(Renderer.Known.valueOf(name.toUpperCase(Locale.ROOT))); } catch (IllegalArgumentException ignored) { return Optional.empty(); } }).orElseGet(() -> { boolean useSoftwareRenderer = Optional.ofNullable(obj.get("useSoftwareRenderer")).map(JsonElement::getAsBoolean).orElse(false); - return useSoftwareRenderer ? Renderer.LLVMPIPE : Renderer.DEFAULT; + return useSoftwareRenderer ? Renderer.Known.LLVMPIPE : Renderer.Known.DEFAULT; })); vs.setGraphicsBackend(Optional.ofNullable(obj.get("graphicsBackend")).map(JsonElement::getAsString) @@ -927,7 +927,7 @@ public VersionSetting deserialize(JsonElement json, Type typeOfT, JsonDeserializ } catch (IllegalArgumentException ignored) { return Optional.empty(); } - }).orElseGet(() -> vs.getRenderer().getApi())); + }).orElseGet(() -> vs.getRenderer() instanceof Renderer.Known renderer ? renderer.api() : GraphicsAPI.DEFAULT)); return vs; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java index 0b2d2bbeb5..4b5ee1b89a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java @@ -42,6 +42,7 @@ import java.nio.file.FileSystems; import java.util.Arrays; +import java.util.List; import java.util.Locale; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -196,18 +197,18 @@ public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, V graphicsBackendPane.setTitle(i18n("settings.advanced.graphics_backend")); graphicsBackendPane.setConverter(backend -> i18n("settings.advanced.graphics_backend." + backend.name().toLowerCase(Locale.ROOT))); graphicsBackendPane.setDescriptionConverter(backend -> switch (backend) { - case DEFAULT -> i18n("settings.advanced.graphics_backend.default.desc"); - case OPENGL -> i18n("settings.advanced.graphics_backend.opengl.desc"); - case VULKAN -> { - if (gameVersion == null) - yield i18n("settings.advanced.graphics_backend.vulkan.desc.global"); - else if (gameVersion.compareTo("26.2-snapshot-2") < 0) - yield i18n("settings.advanced.graphics_backend.vulkan.desc.unsupported"); - else - yield i18n("settings.advanced.graphics_backend.vulkan.desc"); - } - default -> null; - }); + case DEFAULT -> i18n("settings.advanced.graphics_backend.default.desc"); + case OPENGL -> i18n("settings.advanced.graphics_backend.opengl.desc"); + case VULKAN -> { + if (gameVersion == null) + yield i18n("settings.advanced.graphics_backend.vulkan.desc.global"); + else if (gameVersion.compareTo("26.2-snapshot-2") < 0) + yield i18n("settings.advanced.graphics_backend.vulkan.desc.unsupported"); + else + yield i18n("settings.advanced.graphics_backend.vulkan.desc"); + } + default -> null; + }); graphicsBackendPane.setValue(GraphicsAPI.DEFAULT); graphicsBackendPane.setItems(GraphicsAPI.values()); @@ -218,22 +219,23 @@ else if (gameVersion.compareTo("26.2-snapshot-2") < 0) String bundleKey = "settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT) + ".desc"; return I18n.hasKey(bundleKey) ? i18n(bundleKey) : null; }); - rendererPane.setValue(Renderer.DEFAULT); - rendererPane.setItems(Renderer.DEFAULT); + rendererPane.setValue(Renderer.Known.DEFAULT); FXUtils.onChangeAndOperate(graphicsBackendPane.valueProperty(), backend -> { if (backend == null) { // unbind return; } - rendererPane.setItems(Renderer.SUPPORTED.get(backend)); + @SuppressWarnings("unchecked") + var renderers = (List) (List) Renderer.Known.SUPPORTED.get(backend); + rendererPane.setItems(renderers); if (backend == GraphicsAPI.DEFAULT) { rendererPane.setDisable(true); - rendererPane.setValue(Renderer.DEFAULT); + rendererPane.setValue(Renderer.Known.DEFAULT); } else { rendererPane.setDisable(false); if (rendererPane.getValue() == null || !rendererPane.getValue().isSupported(backend)) { - rendererPane.setValue(Renderer.DEFAULT); + rendererPane.setValue(Renderer.Known.DEFAULT); } } }); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java index 8c72acd6ad..b204deeb8d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java @@ -191,13 +191,13 @@ public static Version patchNative(DefaultGameRepository repository, /// @see Java Mesa Loader for Windows public static @Nullable Library getWindowsMesaLoader(@NotNull JavaRuntime java, @NotNull Renderer renderer, @NotNull OSVersion windowsVersion) { - if (renderer == Renderer.DEFAULT) + if (renderer == Renderer.Known.DEFAULT) return null; if (windowsVersion.isAtLeast(OSVersion.WINDOWS_10)) { return getNatives(java.getPlatform()).get("mesa-loader"); } else if (windowsVersion.isAtLeast(OSVersion.WINDOWS_7)) { - if (renderer == Renderer.LLVMPIPE) + if (renderer == Renderer.Known.LLVMPIPE) return getNatives(java.getPlatform()).get("software-renderer-loader"); else return null; diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index ba95ad274e..19ffcf511e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1181,14 +1181,30 @@ settings.advanced.post_exit_command.prompt=将在游戏结束后调用 settings.advanced.renderer=渲染器 settings.advanced.renderer.default=默认 settings.advanced.renderer.default.desc=使用系统默认渲染器 -settings.advanced.renderer.d3d12=Mesa D3D12 -settings.advanced.renderer.d3d12.desc=基于 DirectX 12 的 OpenGL 渲染器 -settings.advanced.renderer.dozen=Mesa Dozen -settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) +# Vulkan Renderers settings.advanced.renderer.lavapipe=Mesa Lavapipe settings.advanced.renderer.lavapipe.desc=软件 Vulkan 渲染器 +settings.advanced.renderer.dozen=Mesa Dozen +settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) +settings.advanced.renderer.nvidia=NVIDIA +settings.advanced.renderer.nvidia.desc=基于 NVIDIA 显卡的 Vulkan 渲染器 +settings.advanced.renderer.nvidia_nvk=Nouveau +settings.advanced.renderer.nvidia_nvk.desc=基于 NVIDIA 显卡的开源 Vulkan 渲染器 +settings.advanced.renderer.amd_radv=RADV +settings.advanced.renderer.amd_radv.desc=基于 AMD 显卡的开源 Vulkan 渲染器 +settings.advanced.renderer.intel_anv=Intel +settings.advanced.renderer.intel_anv.desc=基于 Intel 显卡的 Vulkan 渲染器 +settings.advanced.renderer.intel_hasvk=Intel HASVK +settings.advanced.renderer.intel_hasvk.desc=基于旧 Intel 显卡的 Vulkan 渲染器 +settings.advanced.renderer.moltenvk=MoltenVK +settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 +settings.advanced.renderer.kosmickrisp=KosmicKrisp +settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 +# OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe settings.advanced.renderer.llvmpipe.desc=软件 OpenGL 渲染器 +settings.advanced.renderer.d3d12=Mesa D3D12 +settings.advanced.renderer.d3d12.desc=基于 DirectX 12 的 OpenGL 渲染器 settings.advanced.renderer.zink=Mesa Zink settings.advanced.renderer.zink.desc=基于 Vulkan 的 OpenGL 渲染器 settings.advanced.server_ip=服务器地址 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java index cd7d960d03..9e3a88da97 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java @@ -57,7 +57,7 @@ public class LaunchOptions implements Serializable { private String nativesDir; private ProcessPriority processPriority = ProcessPriority.NORMAL; private GraphicsAPI graphicsBackend = GraphicsAPI.DEFAULT; - private Renderer renderer = Renderer.DEFAULT; + private Renderer renderer = Renderer.Known.DEFAULT; private boolean useNativeGLFW; private boolean useNativeOpenAL; private boolean enableDebugLogOutput; @@ -446,7 +446,7 @@ public Builder setGraphicsBackend(GraphicsAPI backend) { } public Builder setRenderer(Renderer renderer) { - options.renderer = Objects.requireNonNullElse(renderer, Renderer.DEFAULT); + options.renderer = Objects.requireNonNullElse(renderer, Renderer.Known.DEFAULT); return this; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 4ef932509d..70bb232022 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -17,6 +17,9 @@ */ package org.jackhuang.hmcl.game; +import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.OperatingSystem; +import org.jackhuang.hmcl.util.platform.Platform; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; @@ -25,70 +28,151 @@ import java.util.Map; import java.util.stream.Stream; -/// @author Glavo @NotNullByDefault -public enum Renderer { - DEFAULT(GraphicsAPI.DEFAULT, null, null), +public sealed interface Renderer { - LAVAPIPE(GraphicsAPI.VULKAN, "lavapipe", "lvp"), + GraphicsAPI api(); - // Currently, Dozen does not support the VK_KHR_push_descriptor feature, so it cannot launch Minecraft 26.2 - // Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while - DOZEN(GraphicsAPI.VULKAN, "dzn", "dzn"), + String name(); - ASAHI(GraphicsAPI.VULKAN, null, "asahi"), - NVIDIA(GraphicsAPI.VULKAN, null, "nvidia"), - NOUVEAU(GraphicsAPI.VULKAN, null, "nouveau"), - - - LLVMPIPE(GraphicsAPI.OPENGL, "llvmpipe", null), - ZINK(GraphicsAPI.OPENGL, "zink", null), - D3D12(GraphicsAPI.OPENGL, "d3d12", null), - ; - - /// Map the graphics API to supported renderers. - public static final Map> SUPPORTED; - - static { - var map = new EnumMap>(GraphicsAPI.class); + default boolean isSupported(GraphicsAPI api) { + return this.api() == api || this.api() == GraphicsAPI.DEFAULT; + } - for (var api : GraphicsAPI.values()) { - map.put(api, Stream.of(values()).filter(it -> it.isSupported(api)).toList()); + enum Known implements Renderer { + DEFAULT(GraphicsAPI.DEFAULT, ""), + + // Vulkan + + /// @see LLVMpipe - The Mesa 3D Graphics Library + LAVAPIPE(GraphicsAPI.VULKAN, "lvp") { + @Override + public String mesaDriverName() { + return "lavapipe"; + } + }, + + /// ## Note + /// Currently, Dozen does not support the VK_KHR_push_descriptor feature, so it cannot launch Minecraft 26.2 + /// Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while + DOZEN(GraphicsAPI.VULKAN, "dzn") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.WINDOWS; + } + + @Override + public String mesaDriverName() { + return "dzn"; + } + }, + + /// @see Vulkan Open Standard Modern GPU API | NVIDIA Developer + NVIDIA(GraphicsAPI.VULKAN, "nvidia"), + + /// @see NVK - The Mesa 3D Graphics Library + NVIDIA_NVK(GraphicsAPI.VULKAN, "nouveau") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.LINUX; + } + }, + + /// @see RADV - The Mesa 3D Graphics Library + AMD_RADV(GraphicsAPI.VULKAN, "radeon"), + + /// @see ANV - The Mesa 3D Graphics Library + INTEL_ANV(GraphicsAPI.VULKAN, "intel"), + + /// Intel HasVK driver. + INTEL_HASVK(GraphicsAPI.VULKAN, "intel_hasvk"), + + MOLTENVK(GraphicsAPI.VULKAN, "MoltenVK") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.MACOS; + } + }, + + /// @see KosmicKrisp - The Mesa 3D Graphics Library + KOSMICKRISP(GraphicsAPI.VULKAN, "kosmickrisp_mesa") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.MACOS && platform.arch() == Architecture.ARM64; + } + }, + + // OpenGL + + /// @see LLVMpipe - The Mesa 3D Graphics Library + LLVMPIPE(GraphicsAPI.OPENGL, "") { + @Override + public String mesaDriverName() { + return "llvmpipe"; + } + }, + ZINK(GraphicsAPI.OPENGL, "") { + @Override + public String mesaDriverName() { + return "zink"; + } + }, + D3D12(GraphicsAPI.OPENGL, "") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.WINDOWS; + } + + @Override + public String mesaDriverName() { + return "d3d12"; + } + }, + ; + + /// Map the graphics API to supported renderers. + public static final Map> SUPPORTED; + + static { + var map = new EnumMap>(GraphicsAPI.class); + + for (var api : GraphicsAPI.values()) { + map.put(api, Stream.of(values()) + .filter(it -> it.isSupported(api) && it.isSupportedOn(Platform.SYSTEM_PLATFORM)) + .toList()); + } + + SUPPORTED = map; } - SUPPORTED = map; - } - - private final GraphicsAPI api; + private final GraphicsAPI api; - private final @Nullable String mesaDriverName; - private final @Nullable String icdName; + private final String icdName; - Renderer(GraphicsAPI api, @Nullable String mesaDriverName, @Nullable String icdName) { - this.api = api; - this.mesaDriverName = mesaDriverName; - this.icdName = icdName; - } + Known(GraphicsAPI api, String icdName) { + this.api = api; + this.icdName = icdName; + } - /// Get the Graphics API used by this renderer. - public GraphicsAPI getApi() { - return api; - } + /// Get the Graphics API used by this renderer. + @Override + public GraphicsAPI api() { + return api; + } - public boolean isSupported(GraphicsAPI api) { - return this.api == api || this.api == GraphicsAPI.DEFAULT; - } + public @Nullable String mesaDriverName() { + return null; + } - public @Nullable String getMesaDriverName() { - return mesaDriverName; + public String icdName() { + return icdName; + } } - public @Nullable String getIcdName() { - return icdName; + record Unknown(GraphicsAPI api, String name) implements Renderer { } - public @Nullable String getIcdFileName() { - return icdName != null ? icdName + "_icd.json" : null; + default boolean isSupportedOn(Platform platform) { + return true; } - } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java deleted file mode 100644 index a26c3f3424..0000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer2.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2026 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.game; - -import org.jackhuang.hmcl.util.platform.Architecture; -import org.jackhuang.hmcl.util.platform.OperatingSystem; -import org.jackhuang.hmcl.util.platform.Platform; -import org.jetbrains.annotations.NotNullByDefault; - -@NotNullByDefault -public sealed interface Renderer2 { - - GraphicsAPI api(); - - String name(); - - default boolean isSupported(GraphicsAPI api) { - return this.api() == api || this.api() == GraphicsAPI.DEFAULT; - } - - enum Known implements Renderer2 { - DEFAULT(GraphicsAPI.DEFAULT, "", ""), - - // Vulkan - - /// @see LLVMpipe - The Mesa 3D Graphics Library - LAVAPIPE(GraphicsAPI.VULKAN, "lavapipe", "lvp"), - - /// ## Note - /// Currently, Dozen does not support the VK_KHR_push_descriptor feature, so it cannot launch Minecraft 26.2 - /// Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while - DOZEN(GraphicsAPI.VULKAN, "dzn", "dzn") { - @Override - boolean isAvailable(Platform platform) { - return platform.os() == OperatingSystem.WINDOWS; - } - }, - - /// @see Vulkan Open Standard Modern GPU API | NVIDIA Developer - NVIDIA(GraphicsAPI.VULKAN, "", "nvidia"), - - /// @see NVK - The Mesa 3D Graphics Library - NVIDIA_NVK(GraphicsAPI.VULKAN, "", "nouveau") { - @Override - boolean isAvailable(Platform platform) { - return platform.os() == OperatingSystem.LINUX; - } - }, - - /// @see RADV - The Mesa 3D Graphics Library - AMD_RADV(GraphicsAPI.VULKAN, "", "radeon"), - - /// @see ANV - The Mesa 3D Graphics Library - INTEL_ANV(GraphicsAPI.VULKAN, "", "intel"), - - /// Intel HasVK driver. - INTEL_HASVK(GraphicsAPI.VULKAN, "", "intel_hasvk"), - - /// @see KosmicKrisp - The Mesa 3D Graphics Library - KOSMIC_KRISP(GraphicsAPI.VULKAN, "", "kosmickrisp_mesa"), - - // OpenGL - - /// @see LLVMpipe - The Mesa 3D Graphics Library - LLVMPIPE(GraphicsAPI.OPENGL, "llvmpipe", ""), - ZINK(GraphicsAPI.OPENGL, "zink", ""), - D3D12(GraphicsAPI.OPENGL, "d3d12", "") { - @Override - boolean isAvailable(Platform platform) { - return platform.os() == OperatingSystem.WINDOWS; - } - }, - ; - - private final GraphicsAPI api; - - private final String mesaDriverName; - private final String icdName; - - Known(GraphicsAPI api, String mesaDriverName, String icdName) { - this.api = api; - this.mesaDriverName = mesaDriverName; - this.icdName = icdName; - } - - boolean isAvailable(Platform platform) { - return true; - } - - /// Get the Graphics API used by this renderer. - @Override - public GraphicsAPI api() { - return api; - } - - public String mesaDriverName() { - return mesaDriverName; - } - - public String icdName() { - return icdName; - } - } - - record Unknown(GraphicsAPI api, String name) implements Renderer2 { - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 0ce41792bc..a6f3321337 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -266,8 +266,8 @@ private Command generateCommandLine(Path nativeFolder) throws IOException { } if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS - && options.getRenderer() != null - && options.getRenderer().getMesaDriverName() != null) { + && options.getRenderer() instanceof Renderer.Known knownRenderer + && knownRenderer.mesaDriverName() != null) { res.addDefault("-Dorg.glavo.mesa.loader.nativeDir=", FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader"))); } @@ -634,50 +634,44 @@ private Map getEnvVars(Path nativeFolder) { env.put("INST_MC_DIR", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))); env.put("INST_JAVA", options.getJava().getBinary().toString()); - Renderer renderer = options.getRenderer(); - if (renderer != Renderer.DEFAULT) { - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - if (renderer.getMesaDriverName() != null) { - if (renderer.getApi() == GraphicsAPI.OPENGL && renderer != Renderer.LLVMPIPE) - env.put("GALLIUM_DRIVER", renderer.getMesaDriverName()); + if (options.getRenderer() instanceof Renderer.Known renderer) { + //noinspection StatementWithEmptyBody + if (renderer == Renderer.Known.DEFAULT) { + // Do nothing + } else if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + if (renderer.mesaDriverName() != null) { + if (renderer.api() == GraphicsAPI.OPENGL && renderer != Renderer.Known.LLVMPIPE) + env.put("GALLIUM_DRIVER", renderer.mesaDriverName()); - if (renderer.getApi() == GraphicsAPI.VULKAN) { - String icdFile = FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader/" + renderer.getIcdFileName())); + if (renderer.api() == GraphicsAPI.VULKAN) { + String icdFile = FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader/" + renderer.icdName() + "_icd.json")); env.put("VK_ICD_FILENAMES", icdFile); env.put("VK_DRIVER_FILES", icdFile); } } } else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) { - switch (renderer) { - case LLVMPIPE: { - env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); - env.put("LIBGL_ALWAYS_SOFTWARE", "1"); - break; - } - case ZINK: { - env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); - env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); - /* - * The amdgpu DDX is missing support for modifiers, causing Zink to fail. - * Disable DRI3 to workaround this issue. - * - * Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10093 - */ - env.put("LIBGL_KOPPER_DRI2", "1"); - break; - } - case LAVAPIPE: { - Path lvp = findVulkanDescriptorFile( - List.of(Path.of("/usr/share/vulkan/icd.d"), Path.of("/etc/vulkan/icd.d")), - "lvp_icd" - ); - if (lvp != null) { - env.put("VK_ICD_FILENAMES", FileUtils.getAbsolutePath(lvp)); - env.put("VK_DRIVER_FILES", FileUtils.getAbsolutePath(lvp)); - } - - break; + if (renderer == Renderer.Known.LLVMPIPE) { + env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); + env.put("LIBGL_ALWAYS_SOFTWARE", "1"); + } else if (renderer == Renderer.Known.ZINK) { + env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); + env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); + /* + * The amdgpu DDX is missing support for modifiers, causing Zink to fail. + * Disable DRI3 to workaround this issue. + * + * Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10093 + */ + env.put("LIBGL_KOPPER_DRI2", "1"); + } else if (renderer.api() == GraphicsAPI.VULKAN) { + Path lvp = findVulkanDescriptorFile( + List.of(Path.of("/usr/share/vulkan/icd.d"), Path.of("/etc/vulkan/icd.d")), + renderer.icdName() + ); + if (lvp != null) { + env.put("VK_ICD_FILENAMES", FileUtils.getAbsolutePath(lvp)); + env.put("VK_DRIVER_FILES", FileUtils.getAbsolutePath(lvp)); } } } From dea15699a4e91089946b58a2b10f493864aaacb9 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 00:21:43 +0800 Subject: [PATCH 03/45] =?UTF-8?q?=E9=87=8D=E6=9E=84=20Renderer=20=E5=B9=B6?= =?UTF-8?q?=E5=BC=95=E5=85=A5=20Renderer.DEFAULT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/setting/VersionSetting.java | 6 +++--- .../versions/AdvancedVersionSettingPage.java | 6 +++--- .../jackhuang/hmcl/util/NativePatcher.java | 2 +- .../jackhuang/hmcl/game/LaunchOptions.java | 4 ++-- .../org/jackhuang/hmcl/game/Renderer.java | 19 +++++++++++++++++-- .../hmcl/launch/DefaultLauncher.java | 5 +---- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java index b6e8e9d9db..1d01303b04 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java @@ -617,7 +617,7 @@ public void setGraphicsBackend(GraphicsAPI api) { graphicsBackendProperty().set(api); } - private final ObjectProperty rendererProperty = new SimpleObjectProperty<>(this, "renderer", Renderer.Known.DEFAULT); + private final ObjectProperty rendererProperty = new SimpleObjectProperty<>(this, "renderer", Renderer.DEFAULT); public Renderer getRenderer() { return rendererProperty.get(); @@ -911,13 +911,13 @@ public VersionSetting deserialize(JsonElement json, Type typeOfT, JsonDeserializ vs.setRenderer(Optional.ofNullable(obj.get("renderer")).map(JsonElement::getAsString) .flatMap(name -> { try { - return Optional.of(Renderer.Known.valueOf(name.toUpperCase(Locale.ROOT))); + return Optional.of(Renderer.Known.valueOf(name.toUpperCase(Locale.ROOT))); } catch (IllegalArgumentException ignored) { return Optional.empty(); } }).orElseGet(() -> { boolean useSoftwareRenderer = Optional.ofNullable(obj.get("useSoftwareRenderer")).map(JsonElement::getAsBoolean).orElse(false); - return useSoftwareRenderer ? Renderer.Known.LLVMPIPE : Renderer.Known.DEFAULT; + return useSoftwareRenderer ? Renderer.Known.LLVMPIPE : Renderer.DEFAULT; })); vs.setGraphicsBackend(Optional.ofNullable(obj.get("graphicsBackend")).map(JsonElement::getAsString) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java index 4b5ee1b89a..c3a9e323b9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java @@ -219,7 +219,7 @@ else if (gameVersion.compareTo("26.2-snapshot-2") < 0) String bundleKey = "settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT) + ".desc"; return I18n.hasKey(bundleKey) ? i18n(bundleKey) : null; }); - rendererPane.setValue(Renderer.Known.DEFAULT); + rendererPane.setValue(Renderer.DEFAULT); FXUtils.onChangeAndOperate(graphicsBackendPane.valueProperty(), backend -> { if (backend == null) { // unbind @@ -231,11 +231,11 @@ else if (gameVersion.compareTo("26.2-snapshot-2") < 0) rendererPane.setItems(renderers); if (backend == GraphicsAPI.DEFAULT) { rendererPane.setDisable(true); - rendererPane.setValue(Renderer.Known.DEFAULT); + rendererPane.setValue(Renderer.DEFAULT); } else { rendererPane.setDisable(false); if (rendererPane.getValue() == null || !rendererPane.getValue().isSupported(backend)) { - rendererPane.setValue(Renderer.Known.DEFAULT); + rendererPane.setValue(Renderer.DEFAULT); } } }); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java index b204deeb8d..dd3e21b833 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java @@ -191,7 +191,7 @@ public static Version patchNative(DefaultGameRepository repository, /// @see Java Mesa Loader for Windows public static @Nullable Library getWindowsMesaLoader(@NotNull JavaRuntime java, @NotNull Renderer renderer, @NotNull OSVersion windowsVersion) { - if (renderer == Renderer.Known.DEFAULT) + if (renderer == Renderer.DEFAULT) return null; if (windowsVersion.isAtLeast(OSVersion.WINDOWS_10)) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java index 9e3a88da97..cd7d960d03 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/LaunchOptions.java @@ -57,7 +57,7 @@ public class LaunchOptions implements Serializable { private String nativesDir; private ProcessPriority processPriority = ProcessPriority.NORMAL; private GraphicsAPI graphicsBackend = GraphicsAPI.DEFAULT; - private Renderer renderer = Renderer.Known.DEFAULT; + private Renderer renderer = Renderer.DEFAULT; private boolean useNativeGLFW; private boolean useNativeOpenAL; private boolean enableDebugLogOutput; @@ -446,7 +446,7 @@ public Builder setGraphicsBackend(GraphicsAPI backend) { } public Builder setRenderer(Renderer renderer) { - options.renderer = Objects.requireNonNullElse(renderer, Renderer.Known.DEFAULT); + options.renderer = Objects.requireNonNullElse(renderer, Renderer.DEFAULT); return this; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 70bb232022..6b6fdcbdc3 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -31,6 +31,8 @@ @NotNullByDefault public sealed interface Renderer { + Default DEFAULT = new Default(); + GraphicsAPI api(); String name(); @@ -39,9 +41,22 @@ default boolean isSupported(GraphicsAPI api) { return this.api() == api || this.api() == GraphicsAPI.DEFAULT; } - enum Known implements Renderer { - DEFAULT(GraphicsAPI.DEFAULT, ""), + final class Default implements Renderer { + private Default() { + } + + @Override + public GraphicsAPI api() { + return GraphicsAPI.DEFAULT; + } + + @Override + public String name() { + return "DEFAULT"; + } + } + enum Known implements Renderer { // Vulkan /// @see LLVMpipe - The Mesa 3D Graphics Library diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index a6f3321337..4e9e7dbf60 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -635,10 +635,7 @@ private Map getEnvVars(Path nativeFolder) { env.put("INST_JAVA", options.getJava().getBinary().toString()); if (options.getRenderer() instanceof Renderer.Known renderer) { - //noinspection StatementWithEmptyBody - if (renderer == Renderer.Known.DEFAULT) { - // Do nothing - } else if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { if (renderer.mesaDriverName() != null) { if (renderer.api() == GraphicsAPI.OPENGL && renderer != Renderer.Known.LLVMPIPE) env.put("GALLIUM_DRIVER", renderer.mesaDriverName()); From f493c53ebcdb654fe2fc864fd09b2faa2d09e53a Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 01:57:08 +0800 Subject: [PATCH 04/45] =?UTF-8?q?=E9=87=8D=E6=9E=84=20Renderer=20=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=8C=E6=9B=B4=E6=96=B0=E9=A9=B1=E5=8A=A8=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=B8=BA=20Renderer.Driver=EF=BC=8C=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E5=AF=B9=20Vulkan=20=E5=92=8C=20OpenGL=20=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackhuang/hmcl/game/LauncherHelper.java | 2 +- .../hmcl/setting/VersionSetting.java | 14 +- .../versions/AdvancedVersionSettingPage.java | 2 +- .../jackhuang/hmcl/util/NativePatcher.java | 2 +- .../org/jackhuang/hmcl/game/Renderer.java | 149 ++++++++++-------- .../hmcl/launch/DefaultLauncher.java | 21 ++- 6 files changed, 100 insertions(+), 90 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 8de795d7a6..40446100a3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -174,7 +174,7 @@ private void launch0() { }), Task.composeAsync(() -> { if (OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS - || !(setting.getRenderer() instanceof Renderer.Known renderer) + || !(setting.getRenderer() instanceof Renderer.Driver renderer) || renderer.mesaDriverName() == null) return null; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java index 1d01303b04..389c5ca363 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java @@ -836,7 +836,7 @@ public JsonElement serialize(VersionSetting src, Type typeOfSrc, JsonSerializati obj.addProperty("graphicsBackend", src.getGraphicsBackend().name()); obj.addProperty("renderer", src.getRenderer().name()); - if (src.getRenderer() == Renderer.Known.LLVMPIPE) + if (src.getRenderer() == Renderer.OpenGL.LLVMPIPE) obj.addProperty("useSoftwareRenderer", true); return obj; @@ -909,15 +909,9 @@ public VersionSetting deserialize(JsonElement json, Type typeOfT, JsonDeserializ } vs.setRenderer(Optional.ofNullable(obj.get("renderer")).map(JsonElement::getAsString) - .flatMap(name -> { - try { - return Optional.of(Renderer.Known.valueOf(name.toUpperCase(Locale.ROOT))); - } catch (IllegalArgumentException ignored) { - return Optional.empty(); - } - }).orElseGet(() -> { + .map(Renderer::of).orElseGet(() -> { boolean useSoftwareRenderer = Optional.ofNullable(obj.get("useSoftwareRenderer")).map(JsonElement::getAsBoolean).orElse(false); - return useSoftwareRenderer ? Renderer.Known.LLVMPIPE : Renderer.DEFAULT; + return useSoftwareRenderer ? Renderer.OpenGL.LLVMPIPE : Renderer.DEFAULT; })); vs.setGraphicsBackend(Optional.ofNullable(obj.get("graphicsBackend")).map(JsonElement::getAsString) @@ -927,7 +921,7 @@ public VersionSetting deserialize(JsonElement json, Type typeOfT, JsonDeserializ } catch (IllegalArgumentException ignored) { return Optional.empty(); } - }).orElseGet(() -> vs.getRenderer() instanceof Renderer.Known renderer ? renderer.api() : GraphicsAPI.DEFAULT)); + }).orElseGet(() -> vs.getRenderer() instanceof Renderer.Driver renderer ? renderer.api() : GraphicsAPI.DEFAULT)); return vs; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java index c3a9e323b9..1c52632021 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java @@ -227,7 +227,7 @@ else if (gameVersion.compareTo("26.2-snapshot-2") < 0) } @SuppressWarnings("unchecked") - var renderers = (List) (List) Renderer.Known.SUPPORTED.get(backend); + var renderers = (List) (List) Renderer.Driver.SUPPORTED.get(backend); rendererPane.setItems(renderers); if (backend == GraphicsAPI.DEFAULT) { rendererPane.setDisable(true); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java index dd3e21b833..c10c6a01b5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java @@ -197,7 +197,7 @@ public static Version patchNative(DefaultGameRepository repository, if (windowsVersion.isAtLeast(OSVersion.WINDOWS_10)) { return getNatives(java.getPlatform()).get("mesa-loader"); } else if (windowsVersion.isAtLeast(OSVersion.WINDOWS_7)) { - if (renderer == Renderer.Known.LLVMPIPE) + if (renderer == Renderer.OpenGL.LLVMPIPE) return getNatives(java.getPlatform()).get("software-renderer-loader"); else return null; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 6b6fdcbdc3..9306a83ce1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -20,47 +20,66 @@ import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.Platform; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; +import java.util.Locale; @NotNullByDefault -public sealed interface Renderer { +public sealed interface Renderer permits Renderer.Default, Renderer.Driver, Renderer.Unknown { Default DEFAULT = new Default(); - GraphicsAPI api(); + /// Parse a renderer from a string. + static Renderer of(String name) { + if ("DEFAULT".equalsIgnoreCase(name) || name.isBlank()) + return DEFAULT; - String name(); + String upper = name.toUpperCase(Locale.ROOT).trim(); + + try { + return OpenGL.valueOf(upper); + } catch ( + IllegalArgumentException ignored2) {/// If this driver can be loaded via [mesa-loader-windows](https://github.com/HMCL-dev/mesa-loader-windows), return the driver name, otherwise return `null`. + } + + try { + return Vulkan.valueOf(upper); + } catch (IllegalArgumentException ignored) { + } - default boolean isSupported(GraphicsAPI api) { - return this.api() == api || this.api() == GraphicsAPI.DEFAULT; + return new Unknown(name); } + String name(); + final class Default implements Renderer { private Default() { } - @Override - public GraphicsAPI api() { - return GraphicsAPI.DEFAULT; - } - @Override public String name() { return "DEFAULT"; } } - enum Known implements Renderer { - // Vulkan + sealed interface Driver extends Renderer permits Vulkan, OpenGL { + + /// The graphics API that this driver belongs to. + GraphicsAPI api(); + + /// If this driver can be loaded via [mesa-loader-windows](https://github.com/HMCL-dev/mesa-loader-windows), + /// return the driver name, otherwise return `null`. + @Contract(pure = true) + default @Nullable String mesaDriverName() { + return null; + } + } + enum Vulkan implements Driver { /// @see LLVMpipe - The Mesa 3D Graphics Library - LAVAPIPE(GraphicsAPI.VULKAN, "lvp") { + LAVAPIPE("lvp") { @Override public String mesaDriverName() { return "lavapipe"; @@ -70,7 +89,7 @@ public String mesaDriverName() { /// ## Note /// Currently, Dozen does not support the VK_KHR_push_descriptor feature, so it cannot launch Minecraft 26.2 /// Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while - DOZEN(GraphicsAPI.VULKAN, "dzn") { + DOZEN("dzn") { @Override public boolean isSupportedOn(Platform platform) { return platform.os() == OperatingSystem.WINDOWS; @@ -83,10 +102,18 @@ public String mesaDriverName() { }, /// @see Vulkan Open Standard Modern GPU API | NVIDIA Developer - NVIDIA(GraphicsAPI.VULKAN, "nvidia"), + NVIDIA("nvidia"), /// @see NVK - The Mesa 3D Graphics Library - NVIDIA_NVK(GraphicsAPI.VULKAN, "nouveau") { + NVIDIA_NVK("nouveau") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.LINUX; + } + }, + + /// @see GPUOpen-Drivers/AMDVLK - GitHub + AMDVLK("amd") { @Override public boolean isSupportedOn(Platform platform) { return platform.os() == OperatingSystem.LINUX; @@ -94,15 +121,15 @@ public boolean isSupportedOn(Platform platform) { }, /// @see RADV - The Mesa 3D Graphics Library - AMD_RADV(GraphicsAPI.VULKAN, "radeon"), + AMD_RADV("radeon"), /// @see ANV - The Mesa 3D Graphics Library - INTEL_ANV(GraphicsAPI.VULKAN, "intel"), + INTEL_ANV("intel"), /// Intel HasVK driver. - INTEL_HASVK(GraphicsAPI.VULKAN, "intel_hasvk"), + INTEL_HASVK("intel_hasvk"), - MOLTENVK(GraphicsAPI.VULKAN, "MoltenVK") { + MOLTENVK("MoltenVK") { @Override public boolean isSupportedOn(Platform platform) { return platform.os() == OperatingSystem.MACOS; @@ -110,29 +137,52 @@ public boolean isSupportedOn(Platform platform) { }, /// @see KosmicKrisp - The Mesa 3D Graphics Library - KOSMICKRISP(GraphicsAPI.VULKAN, "kosmickrisp_mesa") { + KOSMICKRISP("kosmickrisp_mesa") { @Override public boolean isSupportedOn(Platform platform) { return platform.os() == OperatingSystem.MACOS && platform.arch() == Architecture.ARM64; } }, - // OpenGL + /// @see PowerVR - The Mesa 3D Graphics Library + POWERVR("powervr") { + @Override + public boolean isSupportedOn(Platform platform) { + return platform.os() == OperatingSystem.LINUX; + } + }; + + private final String icdName; + + Vulkan(String icdName) { + this.icdName = icdName; + } + + @Override + public GraphicsAPI api() { + return GraphicsAPI.VULKAN; + } + public String icdName() { + return icdName; + } + } + + enum OpenGL implements Driver { /// @see LLVMpipe - The Mesa 3D Graphics Library - LLVMPIPE(GraphicsAPI.OPENGL, "") { + LLVMPIPE { @Override public String mesaDriverName() { return "llvmpipe"; } }, - ZINK(GraphicsAPI.OPENGL, "") { + ZINK { @Override public String mesaDriverName() { return "zink"; } }, - D3D12(GraphicsAPI.OPENGL, "") { + D3D12 { @Override public boolean isSupportedOn(Platform platform) { return platform.os() == OperatingSystem.WINDOWS; @@ -142,49 +192,16 @@ public boolean isSupportedOn(Platform platform) { public String mesaDriverName() { return "d3d12"; } - }, - ; - - /// Map the graphics API to supported renderers. - public static final Map> SUPPORTED; - - static { - var map = new EnumMap>(GraphicsAPI.class); - - for (var api : GraphicsAPI.values()) { - map.put(api, Stream.of(values()) - .filter(it -> it.isSupported(api) && it.isSupportedOn(Platform.SYSTEM_PLATFORM)) - .toList()); - } + }; - SUPPORTED = map; - } - - private final GraphicsAPI api; - - private final String icdName; - - Known(GraphicsAPI api, String icdName) { - this.api = api; - this.icdName = icdName; - } - - /// Get the Graphics API used by this renderer. @Override public GraphicsAPI api() { - return api; - } - - public @Nullable String mesaDriverName() { - return null; - } - - public String icdName() { - return icdName; + return GraphicsAPI.VULKAN; } } - record Unknown(GraphicsAPI api, String name) implements Renderer { + /// Unknown renderer. + record Unknown(String name) implements Renderer { } default boolean isSupportedOn(Platform platform) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 4e9e7dbf60..1674dba58f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -266,8 +266,8 @@ private Command generateCommandLine(Path nativeFolder) throws IOException { } if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS - && options.getRenderer() instanceof Renderer.Known knownRenderer - && knownRenderer.mesaDriverName() != null) { + && options.getRenderer() instanceof Renderer.Driver renderer + && renderer.mesaDriverName() != null) { res.addDefault("-Dorg.glavo.mesa.loader.nativeDir=", FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader"))); } @@ -634,24 +634,23 @@ private Map getEnvVars(Path nativeFolder) { env.put("INST_MC_DIR", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))); env.put("INST_JAVA", options.getJava().getBinary().toString()); - if (options.getRenderer() instanceof Renderer.Known renderer) { + if (options.getRenderer() instanceof Renderer.Driver renderer) { if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { if (renderer.mesaDriverName() != null) { - if (renderer.api() == GraphicsAPI.OPENGL && renderer != Renderer.Known.LLVMPIPE) + if (renderer instanceof Renderer.OpenGL && renderer != Renderer.OpenGL.LLVMPIPE) env.put("GALLIUM_DRIVER", renderer.mesaDriverName()); - - if (renderer.api() == GraphicsAPI.VULKAN) { - String icdFile = FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader/" + renderer.icdName() + "_icd.json")); + else if (renderer instanceof Renderer.Vulkan vulkanDriver) { + String icdFile = FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader/" + vulkanDriver.icdName() + "_icd.json")); env.put("VK_ICD_FILENAMES", icdFile); env.put("VK_DRIVER_FILES", icdFile); } } } else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) { - if (renderer == Renderer.Known.LLVMPIPE) { + if (renderer == Renderer.OpenGL.LLVMPIPE) { env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); env.put("LIBGL_ALWAYS_SOFTWARE", "1"); - } else if (renderer == Renderer.Known.ZINK) { + } else if (renderer == Renderer.OpenGL.ZINK) { env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); /* @@ -661,10 +660,10 @@ private Map getEnvVars(Path nativeFolder) { * Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10093 */ env.put("LIBGL_KOPPER_DRI2", "1"); - } else if (renderer.api() == GraphicsAPI.VULKAN) { + } else if (renderer instanceof Renderer.Vulkan vulkanDriver) { Path lvp = findVulkanDescriptorFile( List.of(Path.of("/usr/share/vulkan/icd.d"), Path.of("/etc/vulkan/icd.d")), - renderer.icdName() + vulkanDriver.icdName() ); if (lvp != null) { env.put("VK_ICD_FILENAMES", FileUtils.getAbsolutePath(lvp)); From 6ebd5ea040a183959d130a4b958816b64b47ba58 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 01:57:47 +0800 Subject: [PATCH 05/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=20Renderer.java=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86=EF=BC=8C?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 9306a83ce1..8514b4909a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -40,8 +40,7 @@ static Renderer of(String name) { try { return OpenGL.valueOf(upper); - } catch ( - IllegalArgumentException ignored2) {/// If this driver can be loaded via [mesa-loader-windows](https://github.com/HMCL-dev/mesa-loader-windows), return the driver name, otherwise return `null`. + } catch (IllegalArgumentException ignored) { } try { From 50a44382c0701bda6bf759a71f919689931615d5 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 02:05:28 +0800 Subject: [PATCH 06/45] =?UTF-8?q?=E5=A2=9E=E5=BC=BA=20Renderer=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=EF=BC=8C=E7=AE=80=E5=8C=96=E8=8E=B7=E5=8F=96=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=9A=84=E6=B8=B2=E6=9F=93=E5=99=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../versions/AdvancedVersionSettingPage.java | 8 ++------ .../org/jackhuang/hmcl/game/Renderer.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java index 1c52632021..33281b1700 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java @@ -42,7 +42,6 @@ import java.nio.file.FileSystems; import java.util.Arrays; -import java.util.List; import java.util.Locale; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -226,17 +225,14 @@ else if (gameVersion.compareTo("26.2-snapshot-2") < 0) return; } - @SuppressWarnings("unchecked") - var renderers = (List) (List) Renderer.Driver.SUPPORTED.get(backend); - rendererPane.setItems(renderers); + rendererPane.setItems(Renderer.getSupported(backend)); if (backend == GraphicsAPI.DEFAULT) { rendererPane.setDisable(true); rendererPane.setValue(Renderer.DEFAULT); } else { rendererPane.setDisable(false); - if (rendererPane.getValue() == null || !rendererPane.getValue().isSupported(backend)) { + if (!(rendererPane.getValue() instanceof Renderer.Driver driver) || driver.api() != backend) rendererPane.setValue(Renderer.DEFAULT); - } } }); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 8514b4909a..6ab35e44ce 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -23,8 +23,12 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.stream.Stream; @NotNullByDefault public sealed interface Renderer permits Renderer.Default, Renderer.Driver, Renderer.Unknown { @@ -51,6 +55,17 @@ static Renderer of(String name) { return new Unknown(name); } + /// Get all supported renderers for a given graphics API. + static @Unmodifiable List getSupported(GraphicsAPI api) { + var result = new ArrayList(); + result.add(DEFAULT); + switch (api) { + case VULKAN -> result.addAll(Vulkan.SUPPORTED); + case OPENGL -> result.addAll(OpenGL.SUPPORTED); + } + return result; + } + String name(); final class Default implements Renderer { @@ -151,6 +166,8 @@ public boolean isSupportedOn(Platform platform) { } }; + static final List SUPPORTED = Stream.of(Vulkan.values()).filter(it -> it.isSupportedOn(Platform.CURRENT_PLATFORM)).toList(); + private final String icdName; Vulkan(String icdName) { @@ -193,6 +210,8 @@ public String mesaDriverName() { } }; + static final List SUPPORTED = Stream.of(OpenGL.values()).filter(it -> it.isSupportedOn(Platform.CURRENT_PLATFORM)).toList(); + @Override public GraphicsAPI api() { return GraphicsAPI.VULKAN; From 22d6e4c57fae5c0b8990053c53bce80ea4db4891 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 02:58:48 +0800 Subject: [PATCH 07/45] Refactor Vulkan driver detection and improve renderer support --- .../org/jackhuang/hmcl/game/Renderer.java | 124 ++++++++++++++++-- .../hmcl/launch/DefaultLauncher.java | 41 +++--- 2 files changed, 132 insertions(+), 33 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 6ab35e44ce..7d26262e7a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -17,6 +17,8 @@ */ package org.jackhuang.hmcl.game; +import javafx.css.Match; +import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.Platform; @@ -25,11 +27,18 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + @NotNullByDefault public sealed interface Renderer permits Renderer.Default, Renderer.Driver, Renderer.Unknown { @@ -57,13 +66,11 @@ static Renderer of(String name) { /// Get all supported renderers for a given graphics API. static @Unmodifiable List getSupported(GraphicsAPI api) { - var result = new ArrayList(); - result.add(DEFAULT); - switch (api) { - case VULKAN -> result.addAll(Vulkan.SUPPORTED); - case OPENGL -> result.addAll(OpenGL.SUPPORTED); - } - return result; + return switch (api) { + case DEFAULT -> List.of(DEFAULT); + case VULKAN -> Vulkan.Holder.SUPPORTED; + case OPENGL -> OpenGL.SUPPORTED; + }; } String name(); @@ -143,6 +150,7 @@ public boolean isSupportedOn(Platform platform) { /// Intel HasVK driver. INTEL_HASVK("intel_hasvk"), + /// @see MoltenVK - The Mesa 3D Graphics Library MOLTENVK("MoltenVK") { @Override public boolean isSupportedOn(Platform platform) { @@ -166,7 +174,86 @@ public boolean isSupportedOn(Platform platform) { } }; - static final List SUPPORTED = Stream.of(Vulkan.values()).filter(it -> it.isSupportedOn(Platform.CURRENT_PLATFORM)).toList(); + private static final class Holder { + static final List SUPPORTED; + static final Map DRIVER_TO_ICD_FILE; + + static { + var driverToIcdFile = new EnumMap(Vulkan.class); + var supported = new LinkedHashSet(); + supported.add(DEFAULT); + + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { + supported.addAll(List.of(LAVAPIPE, DOZEN)); // TODO: More Vulkan drivers for Windows + } else { + String archName = switch (Architecture.SYSTEM_ARCH) { + case X86 -> "i686"; + case X86_64 -> "x86_64"; + default -> Architecture.SYSTEM_ARCH.getCheckedName(); + }; + + if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { + // LWJGL integrates MoltenVK, so it is always available + supported.add(MOLTENVK); + + var prefix = Architecture.SYSTEM_ARCH == Architecture.X86_64 + ? Path.of("/usr/local") + : Path.of("/opt/homebrew"); + + // We need libvulkan.1.dylib to load custom Vulkan drivers + if (Files.isRegularFile(prefix.resolve("lib/libvulkan.1.dylib"))) { + if (Files.isRegularFile(prefix.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"))) { + supported.add(LAVAPIPE); + } + + if (Architecture.SYSTEM_ARCH == Architecture.ARM64 + && Files.isRegularFile(prefix.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"))) { + supported.add(KOSMICKRISP); + } + } + } else { + List icdDirs = switch (OperatingSystem.CURRENT_OS) { + case LINUX -> List.of( + Path.of("/usr/share/vulkan/icd.d"), + Path.of("/etc/vulkan/icd.d") + ); + case FREEBSD -> List.of(Path.of("/usr/local/share/vulkan/icd.d")); + default -> List.of(); + }; + + Map icdNameToDriver = Stream.of(values()).collect(Collectors.toMap(Vulkan::icdName, Function.identity())); + + var pattern = Pattern.compile("(?[a-zA-Z0-9_-]+)_icd(?:\\." + Pattern.quote(archName) + ")?\\.json"); + + for (Path icdDir : icdDirs) { + if (!Files.isDirectory(icdDir)) + continue; + try (Stream stream = Files.list(icdDir)) { + for (Path icdFile : Lang.toIterable(stream)) { + String fileName = icdFile.getFileName().toString(); + + Matcher matcher = pattern.matcher(fileName); + if (matcher.matches()) { + String icdName = matcher.group("name"); + + Vulkan driver = icdNameToDriver.get(icdName); + if (driver != null) { + driverToIcdFile.put(driver, icdFile); + supported.add(driver); + } + } + } + } catch (IOException e) { + LOG.warning("Failed to read Vulkan ICD files in " + icdDir, e); + } + } + } + } + + SUPPORTED = List.copyOf(supported); + DRIVER_TO_ICD_FILE = Collections.unmodifiableMap(driverToIcdFile); + } + } private final String icdName; @@ -179,9 +266,18 @@ public GraphicsAPI api() { return GraphicsAPI.VULKAN; } + @Contract(pure = true) public String icdName() { return icdName; } + + /// Get the path to the ICD file for this driver. + /// + /// If the ICD file does not exist, return `null`. + @Contract(pure = true) + public @Nullable Path icdFile() { + return Holder.DRIVER_TO_ICD_FILE.get(this); + } } enum OpenGL implements Driver { @@ -210,7 +306,11 @@ public String mesaDriverName() { } }; - static final List SUPPORTED = Stream.of(OpenGL.values()).filter(it -> it.isSupportedOn(Platform.CURRENT_PLATFORM)).toList(); + static final List SUPPORTED = + Stream.concat( + Stream.of(DEFAULT), + Stream.of(OpenGL.values()).filter(it -> it.isSupportedOn(Platform.CURRENT_PLATFORM)) + ).toList(); @Override public GraphicsAPI api() { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 1674dba58f..61433cfba0 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -647,27 +647,26 @@ else if (renderer instanceof Renderer.Vulkan vulkanDriver) { } } } else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) { - if (renderer == Renderer.OpenGL.LLVMPIPE) { - env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); - env.put("LIBGL_ALWAYS_SOFTWARE", "1"); - } else if (renderer == Renderer.OpenGL.ZINK) { - env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); - env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); - /* - * The amdgpu DDX is missing support for modifiers, causing Zink to fail. - * Disable DRI3 to workaround this issue. - * - * Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10093 - */ - env.put("LIBGL_KOPPER_DRI2", "1"); - } else if (renderer instanceof Renderer.Vulkan vulkanDriver) { - Path lvp = findVulkanDescriptorFile( - List.of(Path.of("/usr/share/vulkan/icd.d"), Path.of("/etc/vulkan/icd.d")), - vulkanDriver.icdName() - ); - if (lvp != null) { - env.put("VK_ICD_FILENAMES", FileUtils.getAbsolutePath(lvp)); - env.put("VK_DRIVER_FILES", FileUtils.getAbsolutePath(lvp)); + if (renderer instanceof Renderer.OpenGL driver) { + if (driver == Renderer.OpenGL.LLVMPIPE) { + env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); + env.put("LIBGL_ALWAYS_SOFTWARE", "1"); + } else if (driver == Renderer.OpenGL.ZINK) { + env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); + env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); + /* + * The amdgpu DDX is missing support for modifiers, causing Zink to fail. + * Disable DRI3 to workaround this issue. + * + * Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10093 + */ + env.put("LIBGL_KOPPER_DRI2", "1"); + } + } else if (renderer instanceof Renderer.Vulkan driver) { + if (driver.icdFile() != null) { + String absolutePath = FileUtils.getAbsolutePath(driver.icdFile()); + env.put("VK_ICD_FILENAMES", absolutePath); + env.put("VK_DRIVER_FILES", absolutePath); } } } From 257402c902bc3b9404baa66e991bac125c2cbbb5 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:05:51 +0800 Subject: [PATCH 08/45] Refactor Vulkan driver detection and improve renderer support --- .../org/jackhuang/hmcl/game/Renderer.java | 71 ++++++++++++++----- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 7d26262e7a..c7565397e1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -17,11 +17,13 @@ */ package org.jackhuang.hmcl.game; -import javafx.css.Match; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.Platform; +import org.jackhuang.hmcl.util.platform.SystemInfo; +import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; +import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; @@ -112,7 +114,7 @@ public String mesaDriverName() { /// Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while DOZEN("dzn") { @Override - public boolean isSupportedOn(Platform platform) { + public boolean isSupported(Platform platform, @Nullable List cards) { return platform.os() == OperatingSystem.WINDOWS; } @@ -123,37 +125,57 @@ public String mesaDriverName() { }, /// @see Vulkan Open Standard Modern GPU API | NVIDIA Developer - NVIDIA("nvidia"), + NVIDIA("nvidia") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return Vulkan.hasCard(cards, HardwareVendor.NVIDIA); + } + }, /// @see NVK - The Mesa 3D Graphics Library NVIDIA_NVK("nouveau") { @Override - public boolean isSupportedOn(Platform platform) { - return platform.os() == OperatingSystem.LINUX; + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() == OperatingSystem.LINUX && Vulkan.hasCard(cards, HardwareVendor.NVIDIA); } }, /// @see GPUOpen-Drivers/AMDVLK - GitHub AMDVLK("amd") { @Override - public boolean isSupportedOn(Platform platform) { - return platform.os() == OperatingSystem.LINUX; + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() == OperatingSystem.LINUX && Vulkan.hasCard(cards, HardwareVendor.AMD); } }, /// @see RADV - The Mesa 3D Graphics Library - AMD_RADV("radeon"), + AMD_RADV("radeon") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return Vulkan.hasCard(cards, HardwareVendor.AMD); + } + }, /// @see ANV - The Mesa 3D Graphics Library - INTEL_ANV("intel"), + INTEL_ANV("intel") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return Vulkan.hasCard(cards, HardwareVendor.INTEL); + } + }, /// Intel HasVK driver. - INTEL_HASVK("intel_hasvk"), + INTEL_HASVK("intel_hasvk") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return Vulkan.hasCard(cards, HardwareVendor.INTEL); + } + }, /// @see MoltenVK - The Mesa 3D Graphics Library MOLTENVK("MoltenVK") { @Override - public boolean isSupportedOn(Platform platform) { + public boolean isSupported(Platform platform, @Nullable List cards) { return platform.os() == OperatingSystem.MACOS; } }, @@ -161,7 +183,7 @@ public boolean isSupportedOn(Platform platform) { /// @see KosmicKrisp - The Mesa 3D Graphics Library KOSMICKRISP("kosmickrisp_mesa") { @Override - public boolean isSupportedOn(Platform platform) { + public boolean isSupported(Platform platform, @Nullable List cards) { return platform.os() == OperatingSystem.MACOS && platform.arch() == Architecture.ARM64; } }, @@ -169,8 +191,8 @@ public boolean isSupportedOn(Platform platform) { /// @see PowerVR - The Mesa 3D Graphics Library POWERVR("powervr") { @Override - public boolean isSupportedOn(Platform platform) { - return platform.os() == OperatingSystem.LINUX; + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() == OperatingSystem.LINUX && Vulkan.hasCard(cards, HardwareVendor.IMG); } }; @@ -239,7 +261,10 @@ private static final class Holder { Vulkan driver = icdNameToDriver.get(icdName); if (driver != null) { driverToIcdFile.put(driver, icdFile); - supported.add(driver); + + if (driver.isSupported(Platform.CURRENT_PLATFORM, SystemInfo.getGraphicsCards())) { + supported.add(driver); + } } } } @@ -261,6 +286,10 @@ private static final class Holder { this.icdName = icdName; } + private static boolean hasCard(@Nullable List cards, HardwareVendor vendor) { + return cards != null && cards.stream().anyMatch(card -> card.getVendor() == vendor); + } + @Override public GraphicsAPI api() { return GraphicsAPI.VULKAN; @@ -296,7 +325,7 @@ public String mesaDriverName() { }, D3D12 { @Override - public boolean isSupportedOn(Platform platform) { + public boolean isSupported(Platform platform, @Nullable List cards) { return platform.os() == OperatingSystem.WINDOWS; } @@ -309,7 +338,10 @@ public String mesaDriverName() { static final List SUPPORTED = Stream.concat( Stream.of(DEFAULT), - Stream.of(OpenGL.values()).filter(it -> it.isSupportedOn(Platform.CURRENT_PLATFORM)) + Stream.of(OpenGL.values()).filter(it -> it.isSupported( + Platform.CURRENT_PLATFORM, + null // We don't need to pass graphics cards for OpenGL yet + )) ).toList(); @Override @@ -322,7 +354,10 @@ public GraphicsAPI api() { record Unknown(String name) implements Renderer { } - default boolean isSupportedOn(Platform platform) { + /// Whether this renderer is supported on the given platform and graphics cards. + /// + /// If `cards` is `null`, it means that the graphics cards are unknown. + default boolean isSupported(Platform platform, @Nullable List cards) { return true; } } From 4e89a61e4777074c25d397b3057bff4a757e11b4 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:25:19 +0800 Subject: [PATCH 09/45] Enhance Vulkan driver documentation with detailed descriptions for each driver --- .../org/jackhuang/hmcl/game/Renderer.java | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index c7565397e1..ef82d64180 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -101,6 +101,10 @@ sealed interface Driver extends Renderer permits Vulkan, OpenGL { } enum Vulkan implements Driver { + /// Mesa Lavapipe driver. + /// + /// It is a software rasterizer. + /// /// @see LLVMpipe - The Mesa 3D Graphics Library LAVAPIPE("lvp") { @Override @@ -109,6 +113,10 @@ public String mesaDriverName() { } }, + /// Mesa Dozen driver. + /// + /// It is a Vulkan driver based on DirectX 12. + /// /// ## Note /// Currently, Dozen does not support the VK_KHR_push_descriptor feature, so it cannot launch Minecraft 26.2 /// Using Dozen can run Minecraft 1.21.11 + VulkanMod, but it will cause the game to crash after playing for a while @@ -124,14 +132,22 @@ public String mesaDriverName() { } }, + /// NVIDIA Vulkan driver. + /// + /// It is a Vulkan driver for NVIDIA GPUs. + /// /// @see Vulkan Open Standard Modern GPU API | NVIDIA Developer - NVIDIA("nvidia") { + NVIDIA_VULKAN("nvidia") { @Override public boolean isSupported(Platform platform, @Nullable List cards) { return Vulkan.hasCard(cards, HardwareVendor.NVIDIA); } }, + /// Mesa NVK driver. + /// + /// It is a Vulkan driver for NVIDIA GPUs. + /// /// @see NVK - The Mesa 3D Graphics Library NVIDIA_NVK("nouveau") { @Override @@ -140,6 +156,10 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// AMD Open Source Driver for Vulkan + /// + /// It is a Vulkan driver for AMD GPUs. + /// /// @see GPUOpen-Drivers/AMDVLK - GitHub AMDVLK("amd") { @Override @@ -148,6 +168,10 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// Mesa RADV driver. + /// + /// It is a Vulkan driver for AMD GCN/RDNA GPUs. + /// /// @see RADV - The Mesa 3D Graphics Library AMD_RADV("radeon") { @Override @@ -156,6 +180,10 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// Mesa ANV driver. + /// + /// It is a Vulkan driver for Intel GPUs. + /// /// @see ANV - The Mesa 3D Graphics Library INTEL_ANV("intel") { @Override @@ -165,6 +193,10 @@ public boolean isSupported(Platform platform, @Nullable List cards }, /// Intel HasVK driver. + /// + /// It is a Vulkan driver for Intel Gen7 (Ivy Bridge / Haswell) and Gen8 (Broadwell) graphics. + /// + /// @see intel: split vulkan driver between gfx7/8 and above INTEL_HASVK("intel_hasvk") { @Override public boolean isSupported(Platform platform, @Nullable List cards) { @@ -172,6 +204,10 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// MoltenVK driver. + /// + /// It is a Vulkan driver for macOS, iOS, tvOS, and visionOS. + /// /// @see MoltenVK - The Mesa 3D Graphics Library MOLTENVK("MoltenVK") { @Override @@ -180,6 +216,10 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// Mesa KosmicKrisp driver. + /// + /// It is a Vulkan driver for Apple Silicon hardware. + /// /// @see KosmicKrisp - The Mesa 3D Graphics Library KOSMICKRISP("kosmickrisp_mesa") { @Override @@ -188,13 +228,24 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// Mesa PowerVR driver. + /// + /// It is a Vulkan driver for Imagination Technologies PowerVR GPUs. + /// /// @see PowerVR - The Mesa 3D Graphics Library POWERVR("powervr") { @Override public boolean isSupported(Platform platform, @Nullable List cards) { return platform.os() == OperatingSystem.LINUX && Vulkan.hasCard(cards, HardwareVendor.IMG); } - }; + }, + + /// Mesa PanVK driver. + /// + /// It is a Vulkan driver for ARM Mali GPUs. + /// + /// @see Panfrost - The Mesa 3D Graphics Library + PANVK("panfrost"); private static final class Holder { static final List SUPPORTED; From 34cab67a53673fa1d68ccf326c766d5d2433349b Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:26:47 +0800 Subject: [PATCH 10/45] Add isSupported implementation for PANVK Vulkan driver --- .../main/java/org/jackhuang/hmcl/game/Renderer.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index ef82d64180..3f5a408d73 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -41,9 +41,11 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG; +/// @author Glavo @NotNullByDefault public sealed interface Renderer permits Renderer.Default, Renderer.Driver, Renderer.Unknown { + /// Default renderer. Default DEFAULT = new Default(); /// Parse a renderer from a string. @@ -245,7 +247,14 @@ public boolean isSupported(Platform platform, @Nullable List cards /// It is a Vulkan driver for ARM Mali GPUs. /// /// @see Panfrost - The Mesa 3D Graphics Library - PANVK("panfrost"); + PANVK("panfrost") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() == OperatingSystem.LINUX + && (platform.arch() == Architecture.ARM32 || platform.arch() == Architecture.ARM64) + && Vulkan.hasCard(cards, HardwareVendor.ARM); + } + }; private static final class Holder { static final List SUPPORTED; From 835e0d9161c2a9a921ab216083b201152c278d7f Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:31:32 +0800 Subject: [PATCH 11/45] Add ARM architecture support and update Vulkan driver checks for Broadcom --- .../org/jackhuang/hmcl/game/Renderer.java | 21 +++++++++++++++---- .../hmcl/launch/DefaultLauncher.java | 2 +- .../hmcl/util/platform/Architecture.java | 4 ++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 3f5a408d73..327235a490 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -250,11 +250,24 @@ public boolean isSupported(Platform platform, @Nullable List cards PANVK("panfrost") { @Override public boolean isSupported(Platform platform, @Nullable List cards) { - return platform.os() == OperatingSystem.LINUX - && (platform.arch() == Architecture.ARM32 || platform.arch() == Architecture.ARM64) - && Vulkan.hasCard(cards, HardwareVendor.ARM); + return platform.os() == OperatingSystem.LINUX && platform.arch().isArm() + && Vulkan.hasCard(cards, HardwareVendor.BROADCOM); } - }; + }, + + /// Mesa V3DV driver. + /// + /// It is a Vulkan driver for the Raspberry Pi 4 and Raspberry Pi 5. + /// + /// @see V3DV - The Mesa 3D Graphics Library + V3DV("broadcom") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() == OperatingSystem.LINUX && platform.arch().isArm() + && Vulkan.hasCard(cards, HardwareVendor.BROADCOM); + } + } + ; private static final class Holder { static final List SUPPORTED; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 61433cfba0..b0c0c26d15 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -646,7 +646,7 @@ else if (renderer instanceof Renderer.Vulkan vulkanDriver) { env.put("VK_DRIVER_FILES", icdFile); } } - } else if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) { + } else if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { if (renderer instanceof Renderer.OpenGL driver) { if (driver == Renderer.OpenGL.LLVMPIPE) { env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java index 7815131f39..a319227841 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java @@ -86,6 +86,10 @@ public boolean isX86() { return this == X86 || this == X86_64; } + public boolean isArm() { + return this == ARM32 || this == ARM64; + } + public static final Architecture CURRENT_ARCH; public static final Architecture SYSTEM_ARCH; From e2d7fd20a2bab2953e0511006d8981204970aaf3 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:33:58 +0800 Subject: [PATCH 12/45] Refactor renderer variable naming in DefaultLauncher.java --- .../hmcl/launch/DefaultLauncher.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index b0c0c26d15..7acf4a08f7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -634,12 +634,12 @@ private Map getEnvVars(Path nativeFolder) { env.put("INST_MC_DIR", FileUtils.getAbsolutePath(repository.getRunDirectory(version.getId()))); env.put("INST_JAVA", options.getJava().getBinary().toString()); - if (options.getRenderer() instanceof Renderer.Driver renderer) { + if (options.getRenderer() instanceof Renderer.Driver driver) { if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - if (renderer.mesaDriverName() != null) { - if (renderer instanceof Renderer.OpenGL && renderer != Renderer.OpenGL.LLVMPIPE) - env.put("GALLIUM_DRIVER", renderer.mesaDriverName()); - else if (renderer instanceof Renderer.Vulkan vulkanDriver) { + if (driver.mesaDriverName() != null) { + if (driver instanceof Renderer.OpenGL && driver != Renderer.OpenGL.LLVMPIPE) + env.put("GALLIUM_DRIVER", driver.mesaDriverName()); + else if (driver instanceof Renderer.Vulkan vulkanDriver) { String icdFile = FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader/" + vulkanDriver.icdName() + "_icd.json")); env.put("VK_ICD_FILENAMES", icdFile); @@ -647,11 +647,11 @@ else if (renderer instanceof Renderer.Vulkan vulkanDriver) { } } } else if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { - if (renderer instanceof Renderer.OpenGL driver) { - if (driver == Renderer.OpenGL.LLVMPIPE) { + if (driver instanceof Renderer.OpenGL oglDriver) { + if (oglDriver == Renderer.OpenGL.LLVMPIPE) { env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); env.put("LIBGL_ALWAYS_SOFTWARE", "1"); - } else if (driver == Renderer.OpenGL.ZINK) { + } else if (oglDriver == Renderer.OpenGL.ZINK) { env.put("__GLX_VENDOR_LIBRARY_NAME", "mesa"); env.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); /* @@ -662,9 +662,9 @@ else if (renderer instanceof Renderer.Vulkan vulkanDriver) { */ env.put("LIBGL_KOPPER_DRI2", "1"); } - } else if (renderer instanceof Renderer.Vulkan driver) { - if (driver.icdFile() != null) { - String absolutePath = FileUtils.getAbsolutePath(driver.icdFile()); + } else if (driver instanceof Renderer.Vulkan vulkanDriver) { + if (vulkanDriver.icdFile() != null) { + String absolutePath = FileUtils.getAbsolutePath(vulkanDriver.icdFile()); env.put("VK_ICD_FILENAMES", absolutePath); env.put("VK_DRIVER_FILES", absolutePath); } From 12dcddee0c32ef568f81a15af145b2fb73dbfde5 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:34:31 +0800 Subject: [PATCH 13/45] Remove unused Vulkan descriptor file finder method --- .../hmcl/launch/DefaultLauncher.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 7acf4a08f7..83e949096e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -602,28 +602,6 @@ public ManagedProcess launch() throws IOException, InterruptedException { return p; } - private @Nullable Path findVulkanDescriptorFile(List dirs, String driverNameBase) { - String archName = switch (options.getJava().getArchitecture()) { - case X86 -> "i686"; - case X86_64 -> "x86_64"; - default -> options.getJava().getArchitecture().getCheckedName(); - }; - - for (Path dir : dirs) { - if (Files.isDirectory(dir)) { - Path file = dir.resolve(driverNameBase + "." + archName + ".json"); - if (Files.isRegularFile(file)) - return file; - - file = dir.resolve(driverNameBase + ".json"); - if (Files.isRegularFile(file)) - return file; - } - } - - return null; - } - private Map getEnvVars(Path nativeFolder) { String versionName = Optional.ofNullable(options.getVersionName()).orElse(version.getId()); From 5571445dc0abfa06ca6ed7fc9ed8214867c9e393 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:40:03 +0800 Subject: [PATCH 14/45] Update Vulkan renderer names and descriptions in Chinese localization --- .../resources/assets/lang/I18N_zh_CN.properties | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 19ffcf511e..a18a0c61d5 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1186,11 +1186,13 @@ settings.advanced.renderer.lavapipe=Mesa Lavapipe settings.advanced.renderer.lavapipe.desc=软件 Vulkan 渲染器 settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) -settings.advanced.renderer.nvidia=NVIDIA -settings.advanced.renderer.nvidia.desc=基于 NVIDIA 显卡的 Vulkan 渲染器 -settings.advanced.renderer.nvidia_nvk=Nouveau +settings.advanced.renderer.nvidia_vulkan=NVIDIA Vulkan +settings.advanced.renderer.nvidia_vulkan.desc=基于 NVIDIA 显卡的 Vulkan 渲染器 +settings.advanced.renderer.nvidia_nvk=Mesa NVK settings.advanced.renderer.nvidia_nvk.desc=基于 NVIDIA 显卡的开源 Vulkan 渲染器 -settings.advanced.renderer.amd_radv=RADV +settings.advanced.renderer.amdvlk=AMDVLK +settings.advanced.renderer.amdvlk.desc=基于 AMD 显卡的过时开源 Vulkan 渲染器 +settings.advanced.renderer.amd_radv=Mesa RADV settings.advanced.renderer.amd_radv.desc=基于 AMD 显卡的开源 Vulkan 渲染器 settings.advanced.renderer.intel_anv=Intel settings.advanced.renderer.intel_anv.desc=基于 Intel 显卡的 Vulkan 渲染器 @@ -1200,6 +1202,12 @@ settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 +settings.advanced.renderer.powervr=Mesa PowerVR +settings.advanced.renderer.powervr.desc=基于 Imagination Technologies PowerVR 显卡的 Vulkan 渲染器 +settings.advanced.renderer.panvk=Mesa PanVK +settings.advanced.renderer.panvk.desc=基于 Arm Mali 显卡的 Vulkan 渲染器 +settings.advanced.renderer.v3dv=Mesa V3DV +settings.advanced.renderer.v3dv.desc=基于博通显卡的 Vulkan 渲染器 # OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe settings.advanced.renderer.llvmpipe.desc=软件 OpenGL 渲染器 From 5244fba6500990cb3858fad9645f6361ba6f05eb Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:45:46 +0800 Subject: [PATCH 15/45] Update Vulkan renderer descriptions in Chinese localization --- .../assets/lang/I18N_zh_CN.properties | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index a18a0c61d5..90a823c86b 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1187,27 +1187,27 @@ settings.advanced.renderer.lavapipe.desc=软件 Vulkan 渲染器 settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) settings.advanced.renderer.nvidia_vulkan=NVIDIA Vulkan -settings.advanced.renderer.nvidia_vulkan.desc=基于 NVIDIA 显卡的 Vulkan 渲染器 +settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA 显卡的官方 Vulkan 驱动 settings.advanced.renderer.nvidia_nvk=Mesa NVK -settings.advanced.renderer.nvidia_nvk.desc=基于 NVIDIA 显卡的开源 Vulkan 渲染器 +settings.advanced.renderer.nvidia_nvk.desc=NVIDIA 显卡的开源 Vulkan 驱动 settings.advanced.renderer.amdvlk=AMDVLK -settings.advanced.renderer.amdvlk.desc=基于 AMD 显卡的过时开源 Vulkan 渲染器 +settings.advanced.renderer.amdvlk.desc=AMD 显卡的过时开源 Vulkan 驱动 settings.advanced.renderer.amd_radv=Mesa RADV -settings.advanced.renderer.amd_radv.desc=基于 AMD 显卡的开源 Vulkan 渲染器 +settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 settings.advanced.renderer.intel_anv=Intel -settings.advanced.renderer.intel_anv.desc=基于 Intel 显卡的 Vulkan 渲染器 +settings.advanced.renderer.intel_anv.desc=Intel 显卡的 Vulkan 驱动 settings.advanced.renderer.intel_hasvk=Intel HASVK -settings.advanced.renderer.intel_hasvk.desc=基于旧 Intel 显卡的 Vulkan 渲染器 +settings.advanced.renderer.intel_hasvk.desc=Intel 旧处理器集成显卡的 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 settings.advanced.renderer.powervr=Mesa PowerVR -settings.advanced.renderer.powervr.desc=基于 Imagination Technologies PowerVR 显卡的 Vulkan 渲染器 +settings.advanced.renderer.powervr.desc=PowerVR 显卡的 Vulkan 驱动 settings.advanced.renderer.panvk=Mesa PanVK -settings.advanced.renderer.panvk.desc=基于 Arm Mali 显卡的 Vulkan 渲染器 +settings.advanced.renderer.panvk.desc=Arm Mali 显卡的 Vulkan 驱动 settings.advanced.renderer.v3dv=Mesa V3DV -settings.advanced.renderer.v3dv.desc=基于博通显卡的 Vulkan 渲染器 +settings.advanced.renderer.v3dv.desc=树莓派 4/5 集成显卡的 Vulkan 驱动 # OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe settings.advanced.renderer.llvmpipe.desc=软件 OpenGL 渲染器 From f67fb0e846bd6e732ce74a69871fb69712b19cb4 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:48:21 +0800 Subject: [PATCH 16/45] Refactor Vulkan driver detection and improve renderer support --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 2 +- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 90a823c86b..a2c82c12b4 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1194,7 +1194,7 @@ settings.advanced.renderer.amdvlk=AMDVLK settings.advanced.renderer.amdvlk.desc=AMD 显卡的过时开源 Vulkan 驱动 settings.advanced.renderer.amd_radv=Mesa RADV settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 -settings.advanced.renderer.intel_anv=Intel +settings.advanced.renderer.intel_anv=Mesa ANV settings.advanced.renderer.intel_anv.desc=Intel 显卡的 Vulkan 驱动 settings.advanced.renderer.intel_hasvk=Intel HASVK settings.advanced.renderer.intel_hasvk.desc=Intel 旧处理器集成显卡的 Vulkan 驱动 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 327235a490..ca86b46f65 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -320,6 +320,7 @@ private static final class Holder { var pattern = Pattern.compile("(?[a-zA-Z0-9_-]+)_icd(?:\\." + Pattern.quote(archName) + ")?\\.json"); + EnumSet foundSupported = EnumSet.noneOf(Vulkan.class); for (Path icdDir : icdDirs) { if (!Files.isDirectory(icdDir)) continue; @@ -336,7 +337,7 @@ private static final class Holder { driverToIcdFile.put(driver, icdFile); if (driver.isSupported(Platform.CURRENT_PLATFORM, SystemInfo.getGraphicsCards())) { - supported.add(driver); + foundSupported.add(driver); } } } @@ -345,6 +346,8 @@ private static final class Holder { LOG.warning("Failed to read Vulkan ICD files in " + icdDir, e); } } + + supported.addAll(foundSupported); } } From d9923c69534bac456b3d178444a4cb1ed14333a9 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:51:51 +0800 Subject: [PATCH 17/45] Update Vulkan renderer names in Chinese localization --- .../resources/assets/lang/I18N_zh_CN.properties | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index a2c82c12b4..98b85bab16 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1188,25 +1188,25 @@ settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) settings.advanced.renderer.nvidia_vulkan=NVIDIA Vulkan settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA 显卡的官方 Vulkan 驱动 -settings.advanced.renderer.nvidia_nvk=Mesa NVK +settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) settings.advanced.renderer.nvidia_nvk.desc=NVIDIA 显卡的开源 Vulkan 驱动 -settings.advanced.renderer.amdvlk=AMDVLK +settings.advanced.renderer.amdvlk=AMD (AMDVLK) settings.advanced.renderer.amdvlk.desc=AMD 显卡的过时开源 Vulkan 驱动 -settings.advanced.renderer.amd_radv=Mesa RADV +settings.advanced.renderer.amd_radv=AMD (RADV) settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 -settings.advanced.renderer.intel_anv=Mesa ANV +settings.advanced.renderer.intel_anv=Intel (ANV) settings.advanced.renderer.intel_anv.desc=Intel 显卡的 Vulkan 驱动 -settings.advanced.renderer.intel_hasvk=Intel HASVK +settings.advanced.renderer.intel_hasvk=Intel (HASVK) settings.advanced.renderer.intel_hasvk.desc=Intel 旧处理器集成显卡的 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 -settings.advanced.renderer.powervr=Mesa PowerVR +settings.advanced.renderer.powervr=PowerVR settings.advanced.renderer.powervr.desc=PowerVR 显卡的 Vulkan 驱动 -settings.advanced.renderer.panvk=Mesa PanVK +settings.advanced.renderer.panvk=PanVK settings.advanced.renderer.panvk.desc=Arm Mali 显卡的 Vulkan 驱动 -settings.advanced.renderer.v3dv=Mesa V3DV +settings.advanced.renderer.v3dv=V3DV settings.advanced.renderer.v3dv.desc=树莓派 4/5 集成显卡的 Vulkan 驱动 # OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe From a63d5002946939b86969bf79f515bf2b36d6d741 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:58:40 +0800 Subject: [PATCH 18/45] Comment out Intel HasVK driver implementation in Renderer.java --- .../org/jackhuang/hmcl/game/Renderer.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index ca86b46f65..b8bfa83401 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -194,17 +194,17 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, - /// Intel HasVK driver. - /// - /// It is a Vulkan driver for Intel Gen7 (Ivy Bridge / Haswell) and Gen8 (Broadwell) graphics. - /// - /// @see intel: split vulkan driver between gfx7/8 and above - INTEL_HASVK("intel_hasvk") { - @Override - public boolean isSupported(Platform platform, @Nullable List cards) { - return Vulkan.hasCard(cards, HardwareVendor.INTEL); - } - }, +// /// Intel HasVK driver. +// /// +// /// It is a Vulkan driver for Intel Gen7 (Ivy Bridge / Haswell) and Gen8 (Broadwell) graphics. +// /// +// /// @see intel: split vulkan driver between gfx7/8 and above +// INTEL_HASVK("intel_hasvk") { +// @Override +// public boolean isSupported(Platform platform, @Nullable List cards) { +// return Vulkan.hasCard(cards, HardwareVendor.INTEL); +// } +// }, /// MoltenVK driver. /// From 4428940e0ae8d3f858dd0b0074b782c335ee5cba Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 03:59:59 +0800 Subject: [PATCH 19/45] Update Vulkan renderer descriptions in Chinese localization --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 98b85bab16..52e5fa3470 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1191,9 +1191,9 @@ settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA 显卡的官方 Vulkan 驱 settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) settings.advanced.renderer.nvidia_nvk.desc=NVIDIA 显卡的开源 Vulkan 驱动 settings.advanced.renderer.amdvlk=AMD (AMDVLK) -settings.advanced.renderer.amdvlk.desc=AMD 显卡的过时开源 Vulkan 驱动 +settings.advanced.renderer.amdvlk.desc=AMD 显卡的过时 Vulkan 驱动 settings.advanced.renderer.amd_radv=AMD (RADV) -settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 +settings.advanced.renderer.amd_radv.desc=AMD 显卡的 Vulkan 驱动 settings.advanced.renderer.intel_anv=Intel (ANV) settings.advanced.renderer.intel_anv.desc=Intel 显卡的 Vulkan 驱动 settings.advanced.renderer.intel_hasvk=Intel (HASVK) From fbdebef43343c16439a753aff839123a96b7606d Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 04:13:39 +0800 Subject: [PATCH 20/45] Add HomebrewUtils for macOS Homebrew path detection --- .../org/jackhuang/hmcl/game/Renderer.java | 11 ++-- .../hmcl/launch/DefaultLauncher.java | 18 +++++++ .../util/platform/macos/HomebrewUtils.java | 50 +++++++++++++++++++ 3 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index b8bfa83401..aa4fe12be7 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -24,6 +24,7 @@ import org.jackhuang.hmcl.util.platform.SystemInfo; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor; +import org.jackhuang.hmcl.util.platform.macos.HomebrewUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; @@ -291,18 +292,14 @@ private static final class Holder { // LWJGL integrates MoltenVK, so it is always available supported.add(MOLTENVK); - var prefix = Architecture.SYSTEM_ARCH == Architecture.X86_64 - ? Path.of("/usr/local") - : Path.of("/opt/homebrew"); - // We need libvulkan.1.dylib to load custom Vulkan drivers - if (Files.isRegularFile(prefix.resolve("lib/libvulkan.1.dylib"))) { - if (Files.isRegularFile(prefix.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"))) { + if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"))) { + if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"))) { supported.add(LAVAPIPE); } if (Architecture.SYSTEM_ARCH == Architecture.ARM64 - && Files.isRegularFile(prefix.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"))) { + && Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"))) { supported.add(KOSMICKRISP); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 83e949096e..592c76ac69 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -27,6 +27,7 @@ import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.Unzipper; import org.jackhuang.hmcl.util.platform.*; +import org.jackhuang.hmcl.util.platform.macos.HomebrewUtils; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jetbrains.annotations.Nullable; @@ -271,6 +272,15 @@ private Command generateCommandLine(Path nativeFolder) throws IOException { res.addDefault("-Dorg.glavo.mesa.loader.nativeDir=", FileUtils.getAbsolutePath(nativeFolder.resolve("mesa-loader"))); } + if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS + && options.getRenderer() instanceof Renderer.Vulkan vulkanDriver + && vulkanDriver.icdFile() != null) { + Path vulkanLibrary = HomebrewUtils.HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"); + if (Files.isRegularFile(vulkanLibrary)) { + res.addDefault("-Dorg.lwjgl.vulkan.libname=", FileUtils.getAbsolutePath(vulkanLibrary)); + } + } + Set classpath = repository.getClasspath(version); if (analyzer.has(LibraryAnalyzer.LibraryType.CLEANROOM)) { @@ -647,6 +657,14 @@ else if (driver instanceof Renderer.Vulkan vulkanDriver) { env.put("VK_DRIVER_FILES", absolutePath); } } + } else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { + if (driver instanceof Renderer.Vulkan vulkanDriver + && vulkanDriver != Renderer.Vulkan.MOLTENVK + && vulkanDriver.icdFile() != null) { + String absolutePath = FileUtils.getAbsolutePath(vulkanDriver.icdFile()); + env.put("VK_ICD_FILENAMES", absolutePath); + env.put("VK_DRIVER_FILES", absolutePath); + } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java new file mode 100644 index 0000000000..d61bb8c09d --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java @@ -0,0 +1,50 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2026 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.util.platform.macos; + +import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.OperatingSystem; +import org.jetbrains.annotations.NotNullByDefault; + +import java.nio.file.Path; + +/// @author Glavo +@NotNullByDefault +public final class HomebrewUtils { + + /// The path to Homebrew prefix. + /// + /// - For macOS x86_64, it is `/usr/local`; + /// - For macOS ARM64, it is `/opt/homebrew`; + /// - For other operating systems, it is undefined. + public static final Path HOMEBREW_PREFIX; + + static { + HOMEBREW_PREFIX = switch (OperatingSystem.CURRENT_OS) { + // TODO: custom Homebrew prefix for macOS + case MACOS -> Architecture.SYSTEM_ARCH.isX86() + ? Path.of("/usr/local") + : Path.of("/opt/homebrew"); + // For other operating systems, we don't need Homebrew. + default -> Path.of(""); + }; + } + + private HomebrewUtils() { + } +} From 7dab5f608565467af23af6b377222e8969fc78f5 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 04:16:27 +0800 Subject: [PATCH 21/45] Refactor Vulkan driver detection for Homebrew on macOS --- .../src/main/java/org/jackhuang/hmcl/game/Renderer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index aa4fe12be7..58fa88170b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -294,12 +294,15 @@ private static final class Holder { // We need libvulkan.1.dylib to load custom Vulkan drivers if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"))) { - if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"))) { + Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); + if (Files.isRegularFile(lvpIcd)) { + driverToIcdFile.put(LAVAPIPE, lvpIcd); supported.add(LAVAPIPE); } - if (Architecture.SYSTEM_ARCH == Architecture.ARM64 - && Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"))) { + Path kosmickrispIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"); + if (Files.isRegularFile(kosmickrispIcd)) { + driverToIcdFile.put(KOSMICKRISP, kosmickrispIcd); supported.add(KOSMICKRISP); } } From 1df4e035bd68657d071797c510b2447deacd78f2 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 04:21:17 +0800 Subject: [PATCH 22/45] Add ARM64 architecture support in Renderer.java --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 58fa88170b..32f8888aa2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -285,6 +285,7 @@ private static final class Holder { String archName = switch (Architecture.SYSTEM_ARCH) { case X86 -> "i686"; case X86_64 -> "x86_64"; + case ARM64 -> "aarch64"; default -> Architecture.SYSTEM_ARCH.getCheckedName(); }; From 966df281f4673bd2a4e89b6edbc8fda58cdf2a25 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 04:24:21 +0800 Subject: [PATCH 23/45] Refactor Homebrew Vulkan library path handling --- .../java/org/jackhuang/hmcl/game/Renderer.java | 2 +- .../jackhuang/hmcl/launch/DefaultLauncher.java | 5 ++--- .../hmcl/util/platform/macos/HomebrewUtils.java | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 32f8888aa2..d641ab83b1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -294,7 +294,7 @@ private static final class Holder { supported.add(MOLTENVK); // We need libvulkan.1.dylib to load custom Vulkan drivers - if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"))) { + if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); if (Files.isRegularFile(lvpIcd)) { driverToIcdFile.put(LAVAPIPE, lvpIcd); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 592c76ac69..649bdc3e3e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -275,9 +275,8 @@ private Command generateCommandLine(Path nativeFolder) throws IOException { if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS && options.getRenderer() instanceof Renderer.Vulkan vulkanDriver && vulkanDriver.icdFile() != null) { - Path vulkanLibrary = HomebrewUtils.HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"); - if (Files.isRegularFile(vulkanLibrary)) { - res.addDefault("-Dorg.lwjgl.vulkan.libname=", FileUtils.getAbsolutePath(vulkanLibrary)); + if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { + res.addDefault("-Dorg.lwjgl.vulkan.libname=", FileUtils.getAbsolutePath(HomebrewUtils.HOMEBREW_PREFIX)); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java index d61bb8c09d..d72a57be7e 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java @@ -34,15 +34,24 @@ public final class HomebrewUtils { /// - For other operating systems, it is undefined. public static final Path HOMEBREW_PREFIX; + /// The path to `libvulkan.1.dylib`. + /// + /// For non-macOS operating systems, it is undefined. + public static final Path LIB_VULKAN; + static { - HOMEBREW_PREFIX = switch (OperatingSystem.CURRENT_OS) { + if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { // TODO: custom Homebrew prefix for macOS - case MACOS -> Architecture.SYSTEM_ARCH.isX86() + HOMEBREW_PREFIX = Architecture.SYSTEM_ARCH.isX86() ? Path.of("/usr/local") : Path.of("/opt/homebrew"); + + LIB_VULKAN = HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"); + } else { // For other operating systems, we don't need Homebrew. - default -> Path.of(""); - }; + HOMEBREW_PREFIX = Path.of(""); + LIB_VULKAN = Path.of(""); + } } private HomebrewUtils() { From 88eb30147bb8f8f6252c52fe506ab8e49914b736 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 04:38:28 +0800 Subject: [PATCH 24/45] Add architecture check for Vulkan driver on macOS --- .../java/org/jackhuang/hmcl/launch/DefaultLauncher.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 649bdc3e3e..09957c655f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -273,6 +273,7 @@ private Command generateCommandLine(Path nativeFolder) throws IOException { } if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS + && options.getJava().getArchitecture() == Architecture.SYSTEM_ARCH && options.getRenderer() instanceof Renderer.Vulkan vulkanDriver && vulkanDriver.icdFile() != null) { if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { @@ -649,14 +650,16 @@ else if (driver instanceof Renderer.Vulkan vulkanDriver) { */ env.put("LIBGL_KOPPER_DRI2", "1"); } - } else if (driver instanceof Renderer.Vulkan vulkanDriver) { + } else if (driver instanceof Renderer.Vulkan vulkanDriver + && options.getJava().getArchitecture() == Architecture.SYSTEM_ARCH) { if (vulkanDriver.icdFile() != null) { String absolutePath = FileUtils.getAbsolutePath(vulkanDriver.icdFile()); env.put("VK_ICD_FILENAMES", absolutePath); env.put("VK_DRIVER_FILES", absolutePath); } } - } else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { + } else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS + && options.getJava().getArchitecture() == Architecture.SYSTEM_ARCH) { if (driver instanceof Renderer.Vulkan vulkanDriver && vulkanDriver != Renderer.Vulkan.MOLTENVK && vulkanDriver.icdFile() != null) { From 98f2a9b9b01180ce8c96794170c7ebb3634b5802 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 05:01:40 +0800 Subject: [PATCH 25/45] Update Vulkan renderer descriptions in Chinese localization --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 52e5fa3470..86b2091267 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1191,9 +1191,9 @@ settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA 显卡的官方 Vulkan 驱 settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) settings.advanced.renderer.nvidia_nvk.desc=NVIDIA 显卡的开源 Vulkan 驱动 settings.advanced.renderer.amdvlk=AMD (AMDVLK) -settings.advanced.renderer.amdvlk.desc=AMD 显卡的过时 Vulkan 驱动 +settings.advanced.renderer.amdvlk.desc=AMD 显卡的官方 Vulkan 驱动 settings.advanced.renderer.amd_radv=AMD (RADV) -settings.advanced.renderer.amd_radv.desc=AMD 显卡的 Vulkan 驱动 +settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 settings.advanced.renderer.intel_anv=Intel (ANV) settings.advanced.renderer.intel_anv.desc=Intel 显卡的 Vulkan 驱动 settings.advanced.renderer.intel_hasvk=Intel (HASVK) From d6c1e7642d873f99f2c1a5b1b850161b3849cae8 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 05:49:56 +0800 Subject: [PATCH 26/45] Add Vulkan driver file detection for Windows GPUs --- .../assets/lang/I18N_zh_CN.properties | 10 ++- .../org/jackhuang/hmcl/game/Renderer.java | 89 +++++++++++++++---- .../util/platform/hardware/GraphicsCard.java | 54 +++++++---- .../platform/windows/WindowsGPUDetector.java | 25 ++++++ 4 files changed, 141 insertions(+), 37 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 86b2091267..913764f7a8 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1186,18 +1186,20 @@ settings.advanced.renderer.lavapipe=Mesa Lavapipe settings.advanced.renderer.lavapipe.desc=软件 Vulkan 渲染器 settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) -settings.advanced.renderer.nvidia_vulkan=NVIDIA Vulkan +settings.advanced.renderer.nvidia_vulkan=NVIDIA settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA 显卡的官方 Vulkan 驱动 settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) settings.advanced.renderer.nvidia_nvk.desc=NVIDIA 显卡的开源 Vulkan 驱动 -settings.advanced.renderer.amdvlk=AMD (AMDVLK) +settings.advanced.renderer.amdvlk=AMD settings.advanced.renderer.amdvlk.desc=AMD 显卡的官方 Vulkan 驱动 settings.advanced.renderer.amd_radv=AMD (RADV) settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 +settings.advanced.renderer.intel_vulkan=Intel +settings.advanced.renderer.intel_vulkan.desc=Intel 显卡的官方 Vulkan 驱动 settings.advanced.renderer.intel_anv=Intel (ANV) -settings.advanced.renderer.intel_anv.desc=Intel 显卡的 Vulkan 驱动 +settings.advanced.renderer.intel_anv.desc=Intel 显卡的开源 Vulkan 驱动 settings.advanced.renderer.intel_hasvk=Intel (HASVK) -settings.advanced.renderer.intel_hasvk.desc=Intel 旧处理器集成显卡的 Vulkan 驱动 +settings.advanced.renderer.intel_hasvk.desc=Intel 旧核心显卡的 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index d641ab83b1..04d467adcf 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -18,19 +18,23 @@ package org.jackhuang.hmcl.game; import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.Bits; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.Platform; import org.jackhuang.hmcl.util.platform.SystemInfo; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor; import org.jackhuang.hmcl.util.platform.macos.HomebrewUtils; +import org.jackhuang.hmcl.util.platform.windows.WinReg; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; import java.io.IOException; +import java.nio.file.InvalidPathException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -183,6 +187,16 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// Intel Vulkan driver. + /// + /// It is a Vulkan driver for Intel GPUs. + INTEL_VULKAN("ig") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() == OperatingSystem.WINDOWS && Vulkan.hasCard(cards, HardwareVendor.INTEL); + } + }, + /// Mesa ANV driver. /// /// It is a Vulkan driver for Intel GPUs. @@ -191,7 +205,7 @@ public boolean isSupported(Platform platform, @Nullable List cards INTEL_ANV("intel") { @Override public boolean isSupported(Platform platform, @Nullable List cards) { - return Vulkan.hasCard(cards, HardwareVendor.INTEL); + return platform.os() != OperatingSystem.WINDOWS && Vulkan.hasCard(cards, HardwareVendor.INTEL); } }, @@ -203,7 +217,7 @@ public boolean isSupported(Platform platform, @Nullable List cards // INTEL_HASVK("intel_hasvk") { // @Override // public boolean isSupported(Platform platform, @Nullable List cards) { -// return Vulkan.hasCard(cards, HardwareVendor.INTEL); +// return platform.os() != OperatingSystem.WINDOWS && Vulkan.hasCard(cards, HardwareVendor.INTEL); // } // }, @@ -267,8 +281,7 @@ public boolean isSupported(Platform platform, @Nullable List cards return platform.os() == OperatingSystem.LINUX && platform.arch().isArm() && Vulkan.hasCard(cards, HardwareVendor.BROADCOM); } - } - ; + }; private static final class Holder { static final List SUPPORTED; @@ -277,18 +290,64 @@ private static final class Holder { static { var driverToIcdFile = new EnumMap(Vulkan.class); var supported = new LinkedHashSet(); + + + // Helper + String archName = switch (Architecture.SYSTEM_ARCH) { + case X86 -> "i686"; + case X86_64 -> "x86_64"; + case ARM64 -> "aarch64"; + default -> Architecture.SYSTEM_ARCH.getCheckedName(); + }; + + String archNamePattern = Platform.SYSTEM_PLATFORM.equals(Platform.WINDOWS_ARM64) + ? "aarch64|arm64x" + : Pattern.quote(archName); + + var icdFileNamePattern = Pattern.compile("(?[a-zA-Z0-9_-]+)_icd(?:\\." + archNamePattern + ")?\\.json"); + Map icdNameToDriver = Stream.of(values()).collect(Collectors.toMap(Vulkan::icdName, Function.identity())); + supported.add(DEFAULT); if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { - supported.addAll(List.of(LAVAPIPE, DOZEN)); // TODO: More Vulkan drivers for Windows - } else { - String archName = switch (Architecture.SYSTEM_ARCH) { - case X86 -> "i686"; - case X86_64 -> "x86_64"; - case ARM64 -> "aarch64"; - default -> Architecture.SYSTEM_ARCH.getCheckedName(); - }; + supported.addAll(List.of(LAVAPIPE, DOZEN)); + + List graphicsCards = SystemInfo.getGraphicsCards(); + if (graphicsCards != null) { + EnumSet foundSupported = EnumSet.noneOf(Vulkan.class); + for (GraphicsCard card : graphicsCards) { + if (!card.getVulkanDriverFiles().isEmpty()) { + for (Path icdFile : card.getVulkanDriverFiles()) { + String fileName = FileUtils.getName(icdFile); + if (!fileName.endsWith(".json")) + continue; + Vulkan driver; + + Matcher matcher = icdFileNamePattern.matcher(fileName); + if (matcher.matches()) { + String icdName = matcher.group("name"); + driver = icdNameToDriver.get(icdName); + } else { + switch (fileName.substring(0, fileName.length() - ".json".length())) { + case "igvk64", "igvk32" -> driver = INTEL_VULKAN; + case "nv-vk64", "nv-vk32" -> driver = NVIDIA_VULKAN; + case "amd-vulkan64", "amd-vulkan32" -> driver = AMDVLK; + default -> { + continue; + } + } + } + + driverToIcdFile.putIfAbsent(driver, icdFile); + foundSupported.add(driver); + } + } + } + supported.addAll(foundSupported); + } + + } else { if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { // LWJGL integrates MoltenVK, so it is always available supported.add(MOLTENVK); @@ -317,10 +376,6 @@ private static final class Holder { default -> List.of(); }; - Map icdNameToDriver = Stream.of(values()).collect(Collectors.toMap(Vulkan::icdName, Function.identity())); - - var pattern = Pattern.compile("(?[a-zA-Z0-9_-]+)_icd(?:\\." + Pattern.quote(archName) + ")?\\.json"); - EnumSet foundSupported = EnumSet.noneOf(Vulkan.class); for (Path icdDir : icdDirs) { if (!Files.isDirectory(icdDir)) @@ -329,7 +384,7 @@ private static final class Holder { for (Path icdFile : Lang.toIterable(stream)) { String fileName = icdFile.getFileName().toString(); - Matcher matcher = pattern.matcher(fileName); + Matcher matcher = icdFileNamePattern.matcher(fileName); if (matcher.matches()) { String icdName = matcher.group("name"); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/hardware/GraphicsCard.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/hardware/GraphicsCard.java index d7323836c7..1eca335718 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/hardware/GraphicsCard.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/hardware/GraphicsCard.java @@ -18,18 +18,22 @@ package org.jackhuang.hmcl.util.platform.hardware; import org.jackhuang.hmcl.util.StringUtils; +import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; +import org.jetbrains.annotations.Unmodifiable; +import java.nio.file.Path; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** - * @author Glavo - */ +/// @author Glavo +@NotNullByDefault public final class GraphicsCard { - public static String cleanName(String name) { + @UnknownNullability + public static String cleanName(@UnknownNullability String name) { if (name == null) return null; @@ -58,13 +62,15 @@ public static Builder builder() { private final @Nullable Type type; private final @Nullable String driver; private final @Nullable String driverVersion; + private final @Unmodifiable List vulkanDriverFiles; - private GraphicsCard(String name, @Nullable HardwareVendor vendor, @Nullable Type type, @Nullable String driver, @Nullable String driverVersion) { + private GraphicsCard(String name, @Nullable HardwareVendor vendor, @Nullable Type type, @Nullable String driver, @Nullable String driverVersion, List vulkanDriverFiles) { this.name = Objects.requireNonNull(name); this.vendor = vendor; this.type = type; this.driver = driver; this.driverVersion = driverVersion; + this.vulkanDriverFiles = vulkanDriverFiles; } public String getName() { @@ -79,6 +85,10 @@ public String getName() { return driverVersion; } + public List getVulkanDriverFiles() { + return vulkanDriverFiles; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(name); @@ -96,11 +106,12 @@ public enum Type { } public static final class Builder { - private String name; - private HardwareVendor vendor; - private Type type; - private String driver; - private String driverVersion; + private @Nullable String name; + private @Nullable HardwareVendor vendor; + private @Nullable Type type; + private @Nullable String driver; + private @Nullable String driverVersion; + private @Nullable List vulkanDriverFiles; public GraphicsCard build() { String name = this.name; @@ -111,10 +122,12 @@ public GraphicsCard build() { name = "Unknown"; } - return new GraphicsCard(name, vendor, type, driver, driverVersion); + List vulkanDriverFiles = Objects.requireNonNullElse(this.vulkanDriverFiles, List.of()); + + return new GraphicsCard(name, vendor, type, driver, driverVersion, List.copyOf(vulkanDriverFiles)); } - public String getName() { + public @Nullable String getName() { return name; } @@ -123,7 +136,7 @@ public Builder setName(String name) { return this; } - public HardwareVendor getVendor() { + public @Nullable HardwareVendor getVendor() { return vendor; } @@ -132,7 +145,7 @@ public Builder setVendor(HardwareVendor vendor) { return this; } - public Type getType() { + public @Nullable Type getType() { return type; } @@ -141,7 +154,7 @@ public Builder setType(Type type) { return this; } - public String getDriver() { + public @Nullable String getDriver() { return driver; } @@ -150,7 +163,7 @@ public Builder setDriver(String driver) { return this; } - public String getDriverVersion() { + public @Nullable String getDriverVersion() { return driverVersion; } @@ -158,5 +171,14 @@ public Builder setDriverVersion(String driverVersion) { this.driverVersion = driverVersion; return this; } + + public @Nullable List getVulkanDriverFiles() { + return vulkanDriverFiles; + } + + public Builder setVulkanDriverFiles(@Nullable List files) { + this.vulkanDriverFiles = files; + return this; + } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/windows/WindowsGPUDetector.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/windows/WindowsGPUDetector.java index b94c21873d..6a8c479990 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/windows/WindowsGPUDetector.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/windows/WindowsGPUDetector.java @@ -28,8 +28,11 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; import java.util.*; import java.util.regex.Pattern; +import java.util.stream.Stream; import static org.jackhuang.hmcl.util.logging.Logger.LOG; @@ -48,6 +51,25 @@ private static GraphicsCard.Type fromDacType(String adapterDACType) { } } + private static @Nullable List parseVulkanDriverFiles(Object vulkanDriverFiles) { + if (vulkanDriverFiles instanceof String file) { + try { + return List.of(Path.of(file)); + } catch (InvalidPathException e) { + LOG.warning("Failed to parse Vulkan ICD file path: " + file, e); + return null; + } + } else if (vulkanDriverFiles instanceof String[] files) { + try { + return Stream.of(files).map(Path::of).toList(); + } catch (InvalidPathException e) { + LOG.warning("Failed to parse Vulkan ICD file paths: " + Arrays.toString(files), e); + return null; + } + } else + return null; + } + private static List detectByCim() { try { String getCimInstance = OperatingSystem.SYSTEM_VERSION.getVersion().startsWith("6.1") @@ -116,6 +138,7 @@ private static List detectByRegistry(WinReg reg) { String vendor = regValueToString(reg.queryValue(hkey, subkey, "ProviderName")); String driverVersion = regValueToString(reg.queryValue(hkey, subkey, "DriverVersion")); String dacType = regValueToString(reg.queryValue(hkey, subkey, "HardwareInformation.DacType")); + Object vulkanDriverName = reg.queryValue(hkey, subkey, "VulkanDriverName"); GraphicsCard.Builder builder = GraphicsCard.builder(); if (name != null) @@ -126,6 +149,8 @@ private static List detectByRegistry(WinReg reg) { builder.setDriverVersion(driverVersion); if (dacType != null) builder.setType(fromDacType(dacType)); + if (vulkanDriverName != null) + builder.setVulkanDriverFiles(parseVulkanDriverFiles(vulkanDriverName)); result.add(builder.build()); } return result; From 6cbe21bbd3d39c37dbb639468e959730b7bbf041 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 05:52:05 +0800 Subject: [PATCH 27/45] Add Vulkan driver environment variable handling for system architecture --- .../java/org/jackhuang/hmcl/launch/DefaultLauncher.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 09957c655f..edead6d6c1 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -633,6 +633,13 @@ else if (driver instanceof Renderer.Vulkan vulkanDriver) { env.put("VK_ICD_FILENAMES", icdFile); env.put("VK_DRIVER_FILES", icdFile); } + } else if (driver instanceof Renderer.Vulkan vulkanDriver + && vulkanDriver.icdFile() != null + && options.getJava().getArchitecture() == Architecture.SYSTEM_ARCH) { + String icdFile = FileUtils.getAbsolutePath(vulkanDriver.icdFile()); + + env.put("VK_ICD_FILENAMES", icdFile); + env.put("VK_DRIVER_FILES", icdFile); } } else if (OperatingSystem.CURRENT_OS.isLinuxOrBSD()) { if (driver instanceof Renderer.OpenGL oglDriver) { From 1bfcc84627c4d0b852bde38465e3c93f8bb9ad85 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 05:56:04 +0800 Subject: [PATCH 28/45] Update Vulkan renderer descriptions in Chinese localization --- .../assets/lang/I18N_zh_CN.properties | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 913764f7a8..c59f71d035 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1187,29 +1187,27 @@ settings.advanced.renderer.lavapipe.desc=软件 Vulkan 渲染器 settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=基于 DirectX 12 的 Vulkan 渲染器 (实验性) settings.advanced.renderer.nvidia_vulkan=NVIDIA -settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA 显卡的官方 Vulkan 驱动 +settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA GPU 的官方 Vulkan 驱动 settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) -settings.advanced.renderer.nvidia_nvk.desc=NVIDIA 显卡的开源 Vulkan 驱动 +settings.advanced.renderer.nvidia_nvk.desc=NVIDIA GPU 的开源 Vulkan 驱动 settings.advanced.renderer.amdvlk=AMD -settings.advanced.renderer.amdvlk.desc=AMD 显卡的官方 Vulkan 驱动 +settings.advanced.renderer.amdvlk.desc=AMD GPU 的官方 Vulkan 驱动 settings.advanced.renderer.amd_radv=AMD (RADV) -settings.advanced.renderer.amd_radv.desc=AMD 显卡的开源 Vulkan 驱动 +settings.advanced.renderer.amd_radv.desc=AMD GPU 的开源 Vulkan 驱动 settings.advanced.renderer.intel_vulkan=Intel -settings.advanced.renderer.intel_vulkan.desc=Intel 显卡的官方 Vulkan 驱动 +settings.advanced.renderer.intel_vulkan.desc=Intel GPU 的官方 Vulkan 驱动 settings.advanced.renderer.intel_anv=Intel (ANV) -settings.advanced.renderer.intel_anv.desc=Intel 显卡的开源 Vulkan 驱动 -settings.advanced.renderer.intel_hasvk=Intel (HASVK) -settings.advanced.renderer.intel_hasvk.desc=Intel 旧核心显卡的 Vulkan 驱动 +settings.advanced.renderer.intel_anv.desc=Intel GPU 的开源 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 settings.advanced.renderer.powervr=PowerVR -settings.advanced.renderer.powervr.desc=PowerVR 显卡的 Vulkan 驱动 +settings.advanced.renderer.powervr.desc=PowerVR GPU 的 Vulkan 驱动 settings.advanced.renderer.panvk=PanVK -settings.advanced.renderer.panvk.desc=Arm Mali 显卡的 Vulkan 驱动 +settings.advanced.renderer.panvk.desc=Arm Mali GPU 的 Vulkan 驱动 settings.advanced.renderer.v3dv=V3DV -settings.advanced.renderer.v3dv.desc=树莓派 4/5 集成显卡的 Vulkan 驱动 +settings.advanced.renderer.v3dv.desc=树莓派 4/5 GPU 的 Vulkan 驱动 # OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe settings.advanced.renderer.llvmpipe.desc=软件 OpenGL 渲染器 From 387b5f4fd6e238f7530b2a9ad45464ea8b64d473 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 06:46:07 +0800 Subject: [PATCH 29/45] Refactor Vulkan driver detection logic for macOS and Linux --- .../org/jackhuang/hmcl/game/Renderer.java | 98 +++++++++---------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 04d467adcf..696214cd0c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -347,64 +347,62 @@ private static final class Holder { supported.addAll(foundSupported); } - } else { - if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { - // LWJGL integrates MoltenVK, so it is always available - supported.add(MOLTENVK); - - // We need libvulkan.1.dylib to load custom Vulkan drivers - if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { - Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); - if (Files.isRegularFile(lvpIcd)) { - driverToIcdFile.put(LAVAPIPE, lvpIcd); - supported.add(LAVAPIPE); - } - - Path kosmickrispIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"); - if (Files.isRegularFile(kosmickrispIcd)) { - driverToIcdFile.put(KOSMICKRISP, kosmickrispIcd); - supported.add(KOSMICKRISP); - } + } else if (OperatingSystem.CURRENT_OS == OperatingSystem.MACOS) { + // LWJGL integrates MoltenVK, so it is always available + supported.add(MOLTENVK); + + // We need libvulkan.1.dylib to load custom Vulkan drivers + if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { + Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); + if (Files.isRegularFile(lvpIcd)) { + driverToIcdFile.put(LAVAPIPE, lvpIcd); + supported.add(LAVAPIPE); } - } else { - List icdDirs = switch (OperatingSystem.CURRENT_OS) { - case LINUX -> List.of( - Path.of("/usr/share/vulkan/icd.d"), - Path.of("/etc/vulkan/icd.d") - ); - case FREEBSD -> List.of(Path.of("/usr/local/share/vulkan/icd.d")); - default -> List.of(); - }; - - EnumSet foundSupported = EnumSet.noneOf(Vulkan.class); - for (Path icdDir : icdDirs) { - if (!Files.isDirectory(icdDir)) - continue; - try (Stream stream = Files.list(icdDir)) { - for (Path icdFile : Lang.toIterable(stream)) { - String fileName = icdFile.getFileName().toString(); - - Matcher matcher = icdFileNamePattern.matcher(fileName); - if (matcher.matches()) { - String icdName = matcher.group("name"); - - Vulkan driver = icdNameToDriver.get(icdName); - if (driver != null) { - driverToIcdFile.put(driver, icdFile); - if (driver.isSupported(Platform.CURRENT_PLATFORM, SystemInfo.getGraphicsCards())) { - foundSupported.add(driver); - } + Path kosmickrispIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"); + if (Files.isRegularFile(kosmickrispIcd)) { + driverToIcdFile.put(KOSMICKRISP, kosmickrispIcd); + supported.add(KOSMICKRISP); + } + } + } else { + List icdDirs = switch (OperatingSystem.CURRENT_OS) { + case LINUX -> List.of( + Path.of("/usr/share/vulkan/icd.d"), + Path.of("/etc/vulkan/icd.d") + ); + case FREEBSD -> List.of(Path.of("/usr/local/share/vulkan/icd.d")); + default -> List.of(); + }; + + EnumSet foundSupported = EnumSet.noneOf(Vulkan.class); + for (Path icdDir : icdDirs) { + if (!Files.isDirectory(icdDir)) + continue; + try (Stream stream = Files.list(icdDir)) { + for (Path icdFile : Lang.toIterable(stream)) { + String fileName = icdFile.getFileName().toString(); + + Matcher matcher = icdFileNamePattern.matcher(fileName); + if (matcher.matches()) { + String icdName = matcher.group("name"); + + Vulkan driver = icdNameToDriver.get(icdName); + if (driver != null) { + driverToIcdFile.put(driver, icdFile); + + if (driver.isSupported(Platform.CURRENT_PLATFORM, SystemInfo.getGraphicsCards())) { + foundSupported.add(driver); } } } - } catch (IOException e) { - LOG.warning("Failed to read Vulkan ICD files in " + icdDir, e); } + } catch (IOException e) { + LOG.warning("Failed to read Vulkan ICD files in " + icdDir, e); } - - supported.addAll(foundSupported); } + + supported.addAll(foundSupported); } SUPPORTED = List.copyOf(supported); From fc1cdbae78843395de2dd103fc255a1844f6169f Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 06:49:28 +0800 Subject: [PATCH 30/45] Refactor Vulkan driver detection logic for macOS and Linux --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 696214cd0c..8434063394 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -352,7 +352,7 @@ private static final class Holder { supported.add(MOLTENVK); // We need libvulkan.1.dylib to load custom Vulkan drivers - if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { + if (Files.isRegularFile(HomebrewUtils.LIB_VULKAN)) { Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); if (Files.isRegularFile(lvpIcd)) { driverToIcdFile.put(LAVAPIPE, lvpIcd); From 6c7f313ab632304a97a1280bb6f840f2b537001d Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 06:50:56 +0800 Subject: [PATCH 31/45] Refactor Homebrew Vulkan library path handling --- .../main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index edead6d6c1..91103b786a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -276,8 +276,8 @@ private Command generateCommandLine(Path nativeFolder) throws IOException { && options.getJava().getArchitecture() == Architecture.SYSTEM_ARCH && options.getRenderer() instanceof Renderer.Vulkan vulkanDriver && vulkanDriver.icdFile() != null) { - if (Files.isRegularFile(HomebrewUtils.HOMEBREW_PREFIX)) { - res.addDefault("-Dorg.lwjgl.vulkan.libname=", FileUtils.getAbsolutePath(HomebrewUtils.HOMEBREW_PREFIX)); + if (Files.isRegularFile(HomebrewUtils.LIB_VULKAN)) { + res.addDefault("-Dorg.lwjgl.vulkan.libname=", FileUtils.getAbsolutePath(HomebrewUtils.LIB_VULKAN)); } } From 979be5e88dbf76cd8835ba64367f7ab08a5e8b6c Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 06:54:34 +0800 Subject: [PATCH 32/45] Update Vulkan renderer descriptions in Chinese localization --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index c59f71d035..cf02e29218 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1201,13 +1201,13 @@ settings.advanced.renderer.intel_anv.desc=Intel GPU 的开源 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp -settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 +settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 (实验性) settings.advanced.renderer.powervr=PowerVR -settings.advanced.renderer.powervr.desc=PowerVR GPU 的 Vulkan 驱动 +settings.advanced.renderer.powervr.desc=PowerVR GPU 的 Vulkan 驱动 (实验性) settings.advanced.renderer.panvk=PanVK -settings.advanced.renderer.panvk.desc=Arm Mali GPU 的 Vulkan 驱动 +settings.advanced.renderer.panvk.desc=Arm Mali GPU 的 Vulkan 驱动 (实验性) settings.advanced.renderer.v3dv=V3DV -settings.advanced.renderer.v3dv.desc=树莓派 4/5 GPU 的 Vulkan 驱动 +settings.advanced.renderer.v3dv.desc=树莓派 4/5 GPU 的 Vulkan 驱动 (实验性) # OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe settings.advanced.renderer.llvmpipe.desc=软件 OpenGL 渲染器 From 7ead7d8e4194b69b65a19c411723585c000bedf1 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 13:15:41 +0800 Subject: [PATCH 33/45] Update Vulkan renderer descriptions in Chinese localization --- HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index cf02e29218..e0e786378d 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1178,7 +1178,7 @@ settings.advanced.process_priority.high=高 settings.advanced.process_priority.high.desc=优先保证游戏运行,但可能会导致其他程序卡顿 settings.advanced.post_exit_command=游戏结束后执行命令 settings.advanced.post_exit_command.prompt=将在游戏结束后调用 -settings.advanced.renderer=渲染器 +settings.advanced.renderer=渲染器/驱动 settings.advanced.renderer.default=默认 settings.advanced.renderer.default.desc=使用系统默认渲染器 # Vulkan Renderers @@ -1203,11 +1203,11 @@ settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp settings.advanced.renderer.kosmickrisp.desc=基于 Metal 4 的 Vulkan 渲染器 (实验性) settings.advanced.renderer.powervr=PowerVR -settings.advanced.renderer.powervr.desc=PowerVR GPU 的 Vulkan 驱动 (实验性) +settings.advanced.renderer.powervr.desc=PowerVR GPU 的开源 Vulkan 驱动 (实验性) settings.advanced.renderer.panvk=PanVK -settings.advanced.renderer.panvk.desc=Arm Mali GPU 的 Vulkan 驱动 (实验性) +settings.advanced.renderer.panvk.desc=Arm Mali GPU 的开源 Vulkan 驱动 (实验性) settings.advanced.renderer.v3dv=V3DV -settings.advanced.renderer.v3dv.desc=树莓派 4/5 GPU 的 Vulkan 驱动 (实验性) +settings.advanced.renderer.v3dv.desc=树莓派 4/5 GPU 的开源 Vulkan 驱动 (实验性) # OpenGL Renderers settings.advanced.renderer.llvmpipe=Mesa LLVMpipe settings.advanced.renderer.llvmpipe.desc=软件 OpenGL 渲染器 From d62d984a61a42f20e465584f3d8b0b80b0c23ac8 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 13:23:58 +0800 Subject: [PATCH 34/45] Refactor Vulkan driver detection order for macOS Homebrew --- .../main/java/org/jackhuang/hmcl/game/Renderer.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 8434063394..c8e62b9231 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -353,17 +353,17 @@ private static final class Holder { // We need libvulkan.1.dylib to load custom Vulkan drivers if (Files.isRegularFile(HomebrewUtils.LIB_VULKAN)) { - Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); - if (Files.isRegularFile(lvpIcd)) { - driverToIcdFile.put(LAVAPIPE, lvpIcd); - supported.add(LAVAPIPE); - } - Path kosmickrispIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/kosmickrisp_mesa_icd." + archName + ".json"); if (Files.isRegularFile(kosmickrispIcd)) { driverToIcdFile.put(KOSMICKRISP, kosmickrispIcd); supported.add(KOSMICKRISP); } + + Path lvpIcd = HomebrewUtils.HOMEBREW_PREFIX.resolve("share/vulkan/icd.d/lvp_icd." + archName + ".json"); + if (Files.isRegularFile(lvpIcd)) { + driverToIcdFile.put(LAVAPIPE, lvpIcd); + supported.add(LAVAPIPE); + } } } else { List icdDirs = switch (OperatingSystem.CURRENT_OS) { From c78f674f5863540499411e0254eba3a0c759d6aa Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 14:10:24 +0800 Subject: [PATCH 35/45] Refactor Vulkan driver file pattern for Windows ARM64 --- .../src/main/java/org/jackhuang/hmcl/game/Renderer.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index c8e62b9231..d198f33702 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -300,11 +300,7 @@ private static final class Holder { default -> Architecture.SYSTEM_ARCH.getCheckedName(); }; - String archNamePattern = Platform.SYSTEM_PLATFORM.equals(Platform.WINDOWS_ARM64) - ? "aarch64|arm64x" - : Pattern.quote(archName); - - var icdFileNamePattern = Pattern.compile("(?[a-zA-Z0-9_-]+)_icd(?:\\." + archNamePattern + ")?\\.json"); + var icdFileNamePattern = Pattern.compile("(?[a-zA-Z0-9_-]+)_icd(?:\\." + Pattern.quote(archName) + ")?\\.json"); Map icdNameToDriver = Stream.of(values()).collect(Collectors.toMap(Vulkan::icdName, Function.identity())); supported.add(DEFAULT); From d49d56cef33d2dc5185e8a94709d004d13013959 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 15:07:26 +0800 Subject: [PATCH 36/45] Refactor Homebrew Vulkan library path handling --- .../jackhuang/hmcl/util/platform/macos/HomebrewUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java index d72a57be7e..343668e6df 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/macos/HomebrewUtils.java @@ -49,8 +49,9 @@ public final class HomebrewUtils { LIB_VULKAN = HOMEBREW_PREFIX.resolve("lib/libvulkan.1.dylib"); } else { // For other operating systems, we don't need Homebrew. - HOMEBREW_PREFIX = Path.of(""); - LIB_VULKAN = Path.of(""); + var placeholder = Path.of(""); + HOMEBREW_PREFIX = placeholder; + LIB_VULKAN = placeholder; } } From 2f4f954773b12980bc4a99e00deda224d4871831 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 16:34:32 +0800 Subject: [PATCH 37/45] Add Intel HASVK Vulkan driver support --- .../assets/lang/I18N_zh_CN.properties | 2 ++ .../org/jackhuang/hmcl/game/Renderer.java | 24 ++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index e0e786378d..556de220ff 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1198,6 +1198,8 @@ settings.advanced.renderer.intel_vulkan=Intel settings.advanced.renderer.intel_vulkan.desc=Intel GPU 的官方 Vulkan 驱动 settings.advanced.renderer.intel_anv=Intel (ANV) settings.advanced.renderer.intel_anv.desc=Intel GPU 的开源 Vulkan 驱动 +settings.advanced.renderer.intel_hasvk=Intel (HASVK) +settings.advanced.renderer.intel_hasvk.desc=Intel 旧 GPU 的开源 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index d198f33702..526d2cc13a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -209,17 +209,19 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, -// /// Intel HasVK driver. -// /// -// /// It is a Vulkan driver for Intel Gen7 (Ivy Bridge / Haswell) and Gen8 (Broadwell) graphics. -// /// -// /// @see intel: split vulkan driver between gfx7/8 and above -// INTEL_HASVK("intel_hasvk") { -// @Override -// public boolean isSupported(Platform platform, @Nullable List cards) { -// return platform.os() != OperatingSystem.WINDOWS && Vulkan.hasCard(cards, HardwareVendor.INTEL); -// } -// }, + /// Intel HASVK driver. + /// + /// It is a Vulkan driver for Intel Gen7 (Ivy Bridge / Haswell) and Gen8 (Broadwell) graphics. + /// + /// @see intel: split vulkan driver between gfx7/8 and above + INTEL_HASVK("intel_hasvk") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() != OperatingSystem.WINDOWS + && cards != null + && cards.stream().anyMatch(card -> card.getVendor() == HardwareVendor.INTEL && card.getName().startsWith("Intel HD Graphics ")); + } + }, /// MoltenVK driver. /// From 5a0f037861b4cd374ec5a92dfe3853f23854b1c9 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 16:46:12 +0800 Subject: [PATCH 38/45] Add Qualcomm and Turnip Vulkan driver support --- .../assets/lang/I18N_zh_CN.properties | 4 +++ .../org/jackhuang/hmcl/game/Renderer.java | 25 ++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 556de220ff..46827e9ae1 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -1200,6 +1200,10 @@ settings.advanced.renderer.intel_anv=Intel (ANV) settings.advanced.renderer.intel_anv.desc=Intel GPU 的开源 Vulkan 驱动 settings.advanced.renderer.intel_hasvk=Intel (HASVK) settings.advanced.renderer.intel_hasvk.desc=Intel 旧 GPU 的开源 Vulkan 驱动 +settings.advanced.renderer.qualcomm=高通 +settings.advanced.renderer.qualcomm.desc=高通 Adreno GPU 的官方 Vulkan 驱动 +settings.advanced.renderer.turnip=高通 (Turnip) +settings.advanced.renderer.turnip.desc=高通 Adreno GPU 的开源 Vulkan 驱动 settings.advanced.renderer.moltenvk=MoltenVK settings.advanced.renderer.moltenvk.desc=基于 Metal 的 Vulkan 渲染器 settings.advanced.renderer.kosmickrisp=KosmicKrisp diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 526d2cc13a..78ee699f2d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -20,21 +20,18 @@ import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.platform.Architecture; -import org.jackhuang.hmcl.util.platform.Bits; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.Platform; import org.jackhuang.hmcl.util.platform.SystemInfo; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor; import org.jackhuang.hmcl.util.platform.macos.HomebrewUtils; -import org.jackhuang.hmcl.util.platform.windows.WinReg; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNullByDefault; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; import java.io.IOException; -import java.nio.file.InvalidPathException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -223,6 +220,28 @@ public boolean isSupported(Platform platform, @Nullable List cards } }, + /// Qualcomm Vulkan driver. + /// + /// It is a Vulkan driver for Qualcomm Adreno GPUs. + QUALCOMM("qc") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.equals(Platform.WINDOWS_ARM64); + } + }, + + /// Mesa Turnip driver. + /// + /// It is a Vulkan driver for Qualcomm Adreno GPUs. + /// + /// @see Freedreno - The Mesa 3D Graphics Library + TURNIP("freedreno") { + @Override + public boolean isSupported(Platform platform, @Nullable List cards) { + return platform.os() != OperatingSystem.WINDOWS && platform.arch().isArm(); + } + }, + /// MoltenVK driver. /// /// It is a Vulkan driver for macOS, iOS, tvOS, and visionOS. From e6403d76c3b9202370522eb6e9a1db6ae10d8155 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 16:55:24 +0800 Subject: [PATCH 39/45] Add Qualcomm Vulkan driver support for Windows ARM64 --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 78ee699f2d..3e56b15ea6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -350,6 +350,7 @@ private static final class Holder { case "igvk64", "igvk32" -> driver = INTEL_VULKAN; case "nv-vk64", "nv-vk32" -> driver = NVIDIA_VULKAN; case "amd-vulkan64", "amd-vulkan32" -> driver = AMDVLK; + case "qcvk_icd_arm64x" -> driver = QUALCOMM; default -> { continue; } From 143fd1848db8fd71bb64b925e28b25c414781079 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 17:29:27 +0800 Subject: [PATCH 40/45] Add Vulkan renderer options and reorganize renderer list --- .../resources/assets/lang/I18N.properties | 38 ++++++++++++++++-- .../resources/assets/lang/I18N_zh.properties | 40 ++++++++++++++++--- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 02d918b457..6c12a0ffb3 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -1389,14 +1389,44 @@ settings.advanced.post_exit_command.prompt=Commands to execute after the game ex settings.advanced.renderer=Renderer settings.advanced.renderer.default=Default settings.advanced.renderer.default.desc=Use System Default -settings.advanced.renderer.d3d12=Mesa D3D12 -settings.advanced.renderer.d3d12.desc=OpenGL renderer based on DirectX 12 +# Vulkan Renderers settings.advanced.renderer.lavapipe=Mesa Lavapipe settings.advanced.renderer.lavapipe.desc=Software Vulkan Renderer -settings.advanced.renderer.llvmpipe=Mesa LLVMpipe -settings.advanced.renderer.llvmpipe.desc=Software OpenGL Renderer settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=Vulkan renderer based on DirectX 12 (Experimental) +settings.advanced.renderer.nvidia_vulkan=NVIDIA +settings.advanced.renderer.nvidia_vulkan.desc=Official Vulkan driver for NVIDIA GPUs +settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) +settings.advanced.renderer.nvidia_nvk.desc=Open-source Vulkan driver for NVIDIA GPUs +settings.advanced.renderer.amdvlk=AMD +settings.advanced.renderer.amdvlk.desc=Official Vulkan driver for AMD GPUs +settings.advanced.renderer.amd_radv=AMD (RADV) +settings.advanced.renderer.amd_radv.desc=Open-source Vulkan driver for AMD GPUs +settings.advanced.renderer.intel_vulkan=Intel +settings.advanced.renderer.intel_vulkan.desc=Official Vulkan driver for Intel GPUs +settings.advanced.renderer.intel_anv=Intel (ANV) +settings.advanced.renderer.intel_anv.desc=Open-source Vulkan driver for Intel GPUs +settings.advanced.renderer.intel_hasvk=Intel (HASVK) +settings.advanced.renderer.intel_hasvk.desc=Open-source Vulkan driver for older Intel GPUs +settings.advanced.renderer.qualcomm=Qualcomm +settings.advanced.renderer.qualcomm.desc=Official Vulkan driver for Qualcomm Adreno GPUs +settings.advanced.renderer.turnip=Qualcomm (Turnip) +settings.advanced.renderer.turnip.desc=Open-source Vulkan driver for Qualcomm Adreno GPUs +settings.advanced.renderer.moltenvk=MoltenVK +settings.advanced.renderer.moltenvk.desc=Vulkan renderer based on Metal +settings.advanced.renderer.kosmickrisp=KosmicKrisp +settings.advanced.renderer.kosmickrisp.desc=Vulkan renderer based on Metal 4 (Experimental) +settings.advanced.renderer.powervr=PowerVR +settings.advanced.renderer.powervr.desc=Open-source Vulkan driver for PowerVR GPUs (Experimental) +settings.advanced.renderer.panvk=PanVK +settings.advanced.renderer.panvk.desc=Open-source Vulkan driver for Arm Mali GPUs (Experimental) +settings.advanced.renderer.v3dv=V3DV +settings.advanced.renderer.v3dv.desc=Open-source Vulkan driver for Raspberry Pi 4/5 GPUs (Experimental) +# OpenGL Renderers +settings.advanced.renderer.llvmpipe=Mesa LLVMpipe +settings.advanced.renderer.llvmpipe.desc=Software OpenGL renderer +settings.advanced.renderer.d3d12=Mesa D3D12 +settings.advanced.renderer.d3d12.desc=OpenGL renderer based on DirectX 12 settings.advanced.renderer.zink=Mesa Zink settings.advanced.renderer.zink.desc=OpenGL renderer based on Vulkan settings.advanced.server_ip=Server Address diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 2bcfec2041..69234dc765 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -1173,17 +1173,47 @@ settings.advanced.process_priority.high=高 settings.advanced.process_priority.high.desc=優先保證遊戲執行,但可能會導致其他程式卡頓 settings.advanced.post_exit_command=遊戲結束後執行指令 settings.advanced.post_exit_command.prompt=將在遊戲結束後呼叫使用 -settings.advanced.renderer=繪製器 +settings.advanced.renderer=繪製器/驅動 settings.advanced.renderer.default=預設 settings.advanced.renderer.default.desc=使用系統預設繪製器 -settings.advanced.renderer.d3d12=Mesa D3D12 -settings.advanced.renderer.d3d12.desc=基於 DirectX 12 的 OpenGL 繪製器 +# Vulkan Renderers settings.advanced.renderer.lavapipe=Mesa Lavapipe settings.advanced.renderer.lavapipe.desc=軟體 Vulkan 繪製器 -settings.advanced.renderer.llvmpipe=Mesa LLVMpipe -settings.advanced.renderer.llvmpipe.desc=軟體 OpenGL 繪製器 settings.advanced.renderer.dozen=Mesa Dozen settings.advanced.renderer.dozen.desc=基於 DirectX 12 的 Vulkan 繪製器 (實驗性) +settings.advanced.renderer.nvidia_vulkan=NVIDIA +settings.advanced.renderer.nvidia_vulkan.desc=NVIDIA GPU 的官方 Vulkan 驅動 +settings.advanced.renderer.nvidia_nvk=NVIDIA (NVK) +settings.advanced.renderer.nvidia_nvk.desc=NVIDIA GPU 的開源 Vulkan 驅動 +settings.advanced.renderer.amdvlk=AMD +settings.advanced.renderer.amdvlk.desc=AMD GPU 的官方 Vulkan 驅動 +settings.advanced.renderer.amd_radv=AMD (RADV) +settings.advanced.renderer.amd_radv.desc=AMD GPU 的開源 Vulkan 驅動 +settings.advanced.renderer.intel_vulkan=Intel +settings.advanced.renderer.intel_vulkan.desc=Intel GPU 的官方 Vulkan 驅動 +settings.advanced.renderer.intel_anv=Intel (ANV) +settings.advanced.renderer.intel_anv.desc=Intel GPU 的開源 Vulkan 驅動 +settings.advanced.renderer.intel_hasvk=Intel (HASVK) +settings.advanced.renderer.intel_hasvk.desc=Intel 舊 GPU 的開源 Vulkan 驅動 +settings.advanced.renderer.qualcomm=高通 +settings.advanced.renderer.qualcomm.desc=高通 Adreno GPU 的官方 Vulkan 驅動 +settings.advanced.renderer.turnip=高通 (Turnip) +settings.advanced.renderer.turnip.desc=高通 Adreno GPU 的開源 Vulkan 驅動 +settings.advanced.renderer.moltenvk=MoltenVK +settings.advanced.renderer.moltenvk.desc=基於 Metal 的 Vulkan 繪製器 +settings.advanced.renderer.kosmickrisp=KosmicKrisp +settings.advanced.renderer.kosmickrisp.desc=基於 Metal 4 的 Vulkan 繪製器 (實驗性) +settings.advanced.renderer.powervr=PowerVR +settings.advanced.renderer.powervr.desc=PowerVR GPU 的開源 Vulkan 驅動 (實驗性) +settings.advanced.renderer.panvk=PanVK +settings.advanced.renderer.panvk.desc=Arm Mali GPU 的開源 Vulkan 驅動 (實驗性) +settings.advanced.renderer.v3dv=V3DV +settings.advanced.renderer.v3dv.desc=樹莓派 4/5 GPU 的開源 Vulkan 驅動 (實驗性) +# OpenGL Renderers +settings.advanced.renderer.llvmpipe=Mesa LLVMpipe +settings.advanced.renderer.llvmpipe.desc=軟體 OpenGL 繪製器 +settings.advanced.renderer.d3d12=Mesa D3D12 +settings.advanced.renderer.d3d12.desc=基於 DirectX 12 的 OpenGL 繪製器 settings.advanced.renderer.zink=Mesa Zink settings.advanced.renderer.zink.desc=基於 Vulkan 的 OpenGL 繪製器 settings.advanced.server_ip=伺服器位址 From 9e3a96b7364b40c589be7e6a16f648318e49c775 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 17:38:04 +0800 Subject: [PATCH 41/45] Update Vulkan renderer descriptions in Chinese localization --- .../versions/AdvancedVersionSettingPage.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java index 33281b1700..8c11c68ba2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java @@ -196,18 +196,18 @@ public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, V graphicsBackendPane.setTitle(i18n("settings.advanced.graphics_backend")); graphicsBackendPane.setConverter(backend -> i18n("settings.advanced.graphics_backend." + backend.name().toLowerCase(Locale.ROOT))); graphicsBackendPane.setDescriptionConverter(backend -> switch (backend) { - case DEFAULT -> i18n("settings.advanced.graphics_backend.default.desc"); - case OPENGL -> i18n("settings.advanced.graphics_backend.opengl.desc"); - case VULKAN -> { - if (gameVersion == null) - yield i18n("settings.advanced.graphics_backend.vulkan.desc.global"); - else if (gameVersion.compareTo("26.2-snapshot-2") < 0) - yield i18n("settings.advanced.graphics_backend.vulkan.desc.unsupported"); - else - yield i18n("settings.advanced.graphics_backend.vulkan.desc"); - } - default -> null; - }); + case DEFAULT -> i18n("settings.advanced.graphics_backend.default.desc"); + case OPENGL -> i18n("settings.advanced.graphics_backend.opengl.desc"); + case VULKAN -> { + if (gameVersion == null) + yield i18n("settings.advanced.graphics_backend.vulkan.desc.global"); + else if (gameVersion.compareTo("26.2-snapshot-2") < 0) + yield i18n("settings.advanced.graphics_backend.vulkan.desc.unsupported"); + else + yield i18n("settings.advanced.graphics_backend.vulkan.desc"); + } + default -> null; + }); graphicsBackendPane.setValue(GraphicsAPI.DEFAULT); graphicsBackendPane.setItems(GraphicsAPI.values()); From ddbe930e0ab8d2b6e547d88fe01903984d02b505 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 17:44:48 +0800 Subject: [PATCH 42/45] Change default renderer from Vulkan to OpenGL --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 3e56b15ea6..6ed51da4b3 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -494,7 +494,7 @@ public String mesaDriverName() { @Override public GraphicsAPI api() { - return GraphicsAPI.VULKAN; + return GraphicsAPI.OPENGL; } } From 4115df5cc9e552d79873adf42dbed07465fbbfef Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 17:50:40 +0800 Subject: [PATCH 43/45] Remove hardware vendor check from panfrost support condition --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 6ed51da4b3..0bf5c471e4 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -286,8 +286,7 @@ public boolean isSupported(Platform platform, @Nullable List cards PANVK("panfrost") { @Override public boolean isSupported(Platform platform, @Nullable List cards) { - return platform.os() == OperatingSystem.LINUX && platform.arch().isArm() - && Vulkan.hasCard(cards, HardwareVendor.BROADCOM); + return platform.os() == OperatingSystem.LINUX && platform.arch().isArm(); } }, From fa3814f9f1755a7b30767b7bfddd3b84cbff3b8d Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 17:55:14 +0800 Subject: [PATCH 44/45] Remove hardware vendor check from panfrost support condition --- .../org/jackhuang/hmcl/game/Renderer.java | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 0bf5c471e4..808ac060cd 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -19,10 +19,7 @@ import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.platform.Architecture; -import org.jackhuang.hmcl.util.platform.OperatingSystem; -import org.jackhuang.hmcl.util.platform.Platform; -import org.jackhuang.hmcl.util.platform.SystemInfo; +import org.jackhuang.hmcl.util.platform.*; import org.jackhuang.hmcl.util.platform.hardware.GraphicsCard; import org.jackhuang.hmcl.util.platform.hardware.HardwareVendor; import org.jackhuang.hmcl.util.platform.macos.HomebrewUtils; @@ -346,10 +343,48 @@ private static final class Holder { driver = icdNameToDriver.get(icdName); } else { switch (fileName.substring(0, fileName.length() - ".json".length())) { - case "igvk64", "igvk32" -> driver = INTEL_VULKAN; - case "nv-vk64", "nv-vk32" -> driver = NVIDIA_VULKAN; - case "amd-vulkan64", "amd-vulkan32" -> driver = AMDVLK; - case "qcvk_icd_arm64x" -> driver = QUALCOMM; + case "igvk64" -> { + if (Architecture.SYSTEM_ARCH.getBits() == Bits.BIT_64) + driver = INTEL_VULKAN; + else + continue; + } + case "igvk32" -> { + if (Architecture.SYSTEM_ARCH.getBits() == Bits.BIT_32) + driver = INTEL_VULKAN; + else + continue; + } + case "nv-vk64" -> { + if (Architecture.SYSTEM_ARCH.getBits() == Bits.BIT_64) + driver = NVIDIA_VULKAN; + else + continue; + } + case "nv-vk32" -> { + if (Architecture.SYSTEM_ARCH.getBits() == Bits.BIT_32) + driver = NVIDIA_VULKAN; + else + continue; + } + case "amd-vulkan64" -> { + if (Architecture.SYSTEM_ARCH.getBits() == Bits.BIT_64) + driver = AMDVLK; + else + continue; + } + case "amd-vulkan32" -> { + if (Architecture.SYSTEM_ARCH.getBits() == Bits.BIT_32) + driver = AMDVLK; + else + continue; + } + case "qcvk_icd_arm64x" -> { + if (Architecture.SYSTEM_ARCH == Architecture.ARM64) + driver = QUALCOMM; + else + continue; + } default -> { continue; } From c495a7ddb633f308d8bfc247d5a2465c6137cc39 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 12 Apr 2026 20:37:09 +0800 Subject: [PATCH 45/45] Update MoltenVK link description in renderer comments --- HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java index 808ac060cd..146747d646 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Renderer.java @@ -243,7 +243,7 @@ public boolean isSupported(Platform platform, @Nullable List cards /// /// It is a Vulkan driver for macOS, iOS, tvOS, and visionOS. /// - /// @see MoltenVK - The Mesa 3D Graphics Library + /// @see KhronosGroup/MoltenVK - GitHub MOLTENVK("MoltenVK") { @Override public boolean isSupported(Platform platform, @Nullable List cards) {