Skip to content

Commit 30c3acf

Browse files
Glavo3gf8jv4dv
andauthored
增强对 Vulkan 的支持 (#5930)
1. 优化渲染器选项描述; 2. 添加 Vulkan 相关的渲染器选项。 --------- Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com>
1 parent 31f04db commit 30c3acf

File tree

20 files changed

+354
-96
lines changed

20 files changed

+354
-96
lines changed

HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ public LaunchOptions.Builder getLaunchOptions(String version, JavaRuntime javaVe
430430
.setNativesDirType(vs.getNativesDirType())
431431
.setNativesDir(vs.getNativesDir())
432432
.setProcessPriority(vs.getProcessPriority())
433+
.setGraphicsBackend(vs.getGraphicsBackend())
433434
.setRenderer(vs.getRenderer())
434435
.setEnableDebugLogOutput(vs.isEnableDebugLogOutput())
435436
.setUseNativeGLFW(vs.isUseNativeGLFW())

HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -174,26 +174,27 @@ private void launch0() {
174174
}),
175175
Task.composeAsync(() -> {
176176
Renderer renderer = setting.getRenderer();
177-
if (renderer != Renderer.DEFAULT && OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
178-
Library lib = NativePatcher.getWindowsMesaLoader(java, renderer, OperatingSystem.SYSTEM_VERSION);
179-
if (lib == null)
180-
return null;
181-
Path file = dependencyManager.getGameRepository().getLibraryFile(version.get(), lib);
182-
if (file.toAbsolutePath().toString().indexOf('=') >= 0) {
183-
LOG.warning("Invalid character '=' in the libraries directory path, unable to attach software renderer loader");
184-
return null;
185-
}
177+
if (renderer == null || renderer.getMesaDriverName() == null
178+
|| OperatingSystem.CURRENT_OS != OperatingSystem.WINDOWS) {
179+
return null;
180+
}
181+
182+
Library lib = NativePatcher.getWindowsMesaLoader(java, renderer, OperatingSystem.SYSTEM_VERSION);
183+
if (lib == null)
184+
return null;
185+
Path file = dependencyManager.getGameRepository().getLibraryFile(version.get(), lib);
186+
if (file.toAbsolutePath().toString().indexOf('=') >= 0) {
187+
LOG.warning("Invalid character '=' in the libraries directory path, unable to attach software renderer loader");
188+
return null;
189+
}
186190

187-
String agent = FileUtils.getAbsolutePath(file) + "=" + renderer.name().toLowerCase(Locale.ROOT);
191+
String agent = FileUtils.getAbsolutePath(file) + "=" + renderer.getMesaDriverName();
188192

189-
if (GameLibrariesTask.shouldDownloadLibrary(repository, version.get(), lib, integrityCheck)) {
190-
return new LibraryDownloadTask(dependencyManager, file, lib)
191-
.thenRunAsync(() -> javaAgents.add(agent));
192-
} else {
193-
javaAgents.add(agent);
194-
return null;
195-
}
193+
if (GameLibrariesTask.shouldDownloadLibrary(repository, version.get(), lib, integrityCheck)) {
194+
return new LibraryDownloadTask(dependencyManager, file, lib)
195+
.thenRunAsync(() -> javaAgents.add(agent));
196196
} else {
197+
javaAgents.add(agent);
197198
return null;
198199
}
199200
})
@@ -232,6 +233,7 @@ private void launch0() {
232233
if (quickPlayOption != null) {
233234
launchOptionsBuilder.setQuickPlayOption(quickPlayOption);
234235
}
236+
235237
LaunchOptions launchOptions = launchOptionsBuilder.create();
236238

237239
LOG.info("Here's the structure of game mod directory:\n" + FileUtils.printFileStructure(repository.getModsDirectory(selectedVersion), 10));

HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,20 @@ public void setProcessPriority(ProcessPriority processPriority) {
603603
processPriorityProperty.set(processPriority);
604604
}
605605

606+
private final ObjectProperty<GraphicsAPI> graphicsBackend = new SimpleObjectProperty<>(this, "graphicsBackend", GraphicsAPI.DEFAULT);
607+
608+
public ObjectProperty<GraphicsAPI> graphicsBackendProperty() {
609+
return graphicsBackend;
610+
}
611+
612+
public GraphicsAPI getGraphicsBackend() {
613+
return graphicsBackendProperty().get();
614+
}
615+
616+
public void setGraphicsBackend(GraphicsAPI api) {
617+
graphicsBackendProperty().set(api);
618+
}
619+
606620
private final ObjectProperty<Renderer> rendererProperty = new SimpleObjectProperty<>(this, "renderer", Renderer.DEFAULT);
607621

608622
public Renderer getRenderer() {
@@ -820,6 +834,7 @@ public JsonElement serialize(VersionSetting src, Type typeOfSrc, JsonSerializati
820834
}
821835
obj.addProperty("java", java);
822836

837+
obj.addProperty("graphicsBackend", src.getGraphicsBackend().name());
823838
obj.addProperty("renderer", src.getRenderer().name());
824839
if (src.getRenderer() == Renderer.LLVMPIPE)
825840
obj.addProperty("useSoftwareRenderer", true);
@@ -905,6 +920,15 @@ public VersionSetting deserialize(JsonElement json, Type typeOfT, JsonDeserializ
905920
return useSoftwareRenderer ? Renderer.LLVMPIPE : Renderer.DEFAULT;
906921
}));
907922

923+
vs.setGraphicsBackend(Optional.ofNullable(obj.get("graphicsBackend")).map(JsonElement::getAsString)
924+
.flatMap(name -> {
925+
try {
926+
return Optional.of(GraphicsAPI.valueOf(name.toUpperCase(Locale.ROOT)));
927+
} catch (IllegalArgumentException ignored) {
928+
return Optional.empty();
929+
}
930+
}).orElseGet(() -> vs.getRenderer().getApi()));
931+
908932
return vs;
909933
}
910934

HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/LineSelectButton.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import javafx.collections.ObservableList;
2929
import javafx.css.PseudoClass;
3030
import javafx.geometry.Pos;
31+
import javafx.scene.Node;
3132
import javafx.scene.control.Label;
3233
import javafx.scene.input.*;
3334
import javafx.scene.layout.StackPane;
@@ -49,6 +50,8 @@ public class LineSelectButton<T> extends LineButton {
4950
private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected");
5051

5152
private JFXPopup popup;
53+
@SuppressWarnings({"FieldCanBeLocal", "unused"})
54+
private ObservableList<Node> popupItems; // keep a reference
5255

5356
public LineSelectButton() {
5457
this.getStyleClass().add(DEFAULT_STYLE_CLASS);
@@ -87,7 +90,7 @@ public void fire() {
8790

8891
ripplerContainer.addEventFilter(ScrollEvent.ANY, ignored -> popup.hide());
8992

90-
Bindings.bindContent(popupMenu.getContent(), MappedObservableList.create(itemsProperty(), item -> {
93+
Bindings.bindContent(popupMenu.getContent(), popupItems = MappedObservableList.create(itemsProperty(), item -> {
9194
VBox vbox = new VBox();
9295

9396
var itemTitleLabel = new Label();

HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import javafx.scene.control.Label;
2626
import javafx.scene.control.ScrollPane;
2727
import javafx.scene.layout.*;
28+
import org.jackhuang.hmcl.game.GraphicsAPI;
2829
import org.jackhuang.hmcl.game.NativesDirectoryType;
2930
import org.jackhuang.hmcl.game.Renderer;
3031
import org.jackhuang.hmcl.setting.Profile;
@@ -36,6 +37,7 @@
3637
import org.jackhuang.hmcl.util.io.FileUtils;
3738
import org.jackhuang.hmcl.util.platform.OperatingSystem;
3839
import org.jackhuang.hmcl.util.platform.Platform;
40+
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
3941
import org.jetbrains.annotations.Nullable;
4042

4143
import java.nio.file.FileSystems;
@@ -69,6 +71,7 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
6971
private final ComponentSublist nativesDirSublist;
7072
private final MultiFileItem<NativesDirectoryType> nativesDirItem;
7173
private final MultiFileItem.FileOption<NativesDirectoryType> nativesDirCustomOption;
74+
private final LineSelectButton<GraphicsAPI> graphicsBackendPane;
7275
private final LineSelectButton<Renderer> rendererPane;
7376

7477
public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, VersionSetting versionSetting) {
@@ -79,6 +82,10 @@ public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, V
7982
versionId == null ? i18n("settings.advanced") : i18n("settings.advanced.title", versionId)
8083
));
8184

85+
@Nullable GameVersionNumber gameVersion = versionId != null
86+
? GameVersionNumber.asGameVersion(profile.getRepository().getGameVersion(versionId))
87+
: null;
88+
8289
this.getStyleClass().add("gray-background");
8390

8491
ScrollPane scrollPane = new ScrollPane();
@@ -185,14 +192,51 @@ public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, V
185192
nativesDirHint.setText(i18n("settings.advanced.natives_directory.hint"));
186193
nativesDirItem.getChildren().add(nativesDirHint);
187194

195+
graphicsBackendPane = new LineSelectButton<>();
196+
graphicsBackendPane.setTitle(i18n("settings.advanced.graphics_backend"));
197+
graphicsBackendPane.setConverter(backend -> i18n("settings.advanced.graphics_backend." + backend.name().toLowerCase(Locale.ROOT)));
198+
graphicsBackendPane.setDescriptionConverter(backend -> switch (backend) {
199+
case DEFAULT -> i18n("settings.advanced.graphics_backend.default.desc");
200+
case OPENGL -> i18n("settings.advanced.graphics_backend.opengl.desc");
201+
case VULKAN -> {
202+
if (gameVersion == null)
203+
yield i18n("settings.advanced.graphics_backend.vulkan.desc.global");
204+
else if (gameVersion.compareTo("26.2-snapshot-2") < 0)
205+
yield i18n("settings.advanced.graphics_backend.vulkan.desc.unsupported");
206+
else
207+
yield i18n("settings.advanced.graphics_backend.vulkan.desc");
208+
}
209+
default -> null;
210+
});
211+
graphicsBackendPane.setValue(GraphicsAPI.DEFAULT);
212+
graphicsBackendPane.setItems(GraphicsAPI.values());
213+
188214
rendererPane = new LineSelectButton<>();
189215
rendererPane.setTitle(i18n("settings.advanced.renderer"));
190216
rendererPane.setConverter(e -> i18n("settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT)));
191217
rendererPane.setDescriptionConverter(e -> {
192218
String bundleKey = "settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT) + ".desc";
193219
return I18n.hasKey(bundleKey) ? i18n(bundleKey) : null;
194220
});
195-
rendererPane.setItems(Renderer.values());
221+
rendererPane.setValue(Renderer.DEFAULT);
222+
rendererPane.setItems(Renderer.DEFAULT);
223+
224+
FXUtils.onChangeAndOperate(graphicsBackendPane.valueProperty(), backend -> {
225+
if (backend == null) { // unbind
226+
return;
227+
}
228+
229+
rendererPane.setItems(Renderer.SUPPORTED.get(backend));
230+
if (backend == GraphicsAPI.DEFAULT) {
231+
rendererPane.setDisable(true);
232+
rendererPane.setValue(Renderer.DEFAULT);
233+
} else {
234+
rendererPane.setDisable(false);
235+
if (rendererPane.getValue() == null || !rendererPane.getValue().isSupported(backend)) {
236+
rendererPane.setValue(Renderer.DEFAULT);
237+
}
238+
}
239+
});
196240

197241
noJVMArgsPane = new LineToggleButton();
198242
noJVMArgsPane.setTitle(i18n("settings.advanced.no_jvm_args"));
@@ -219,7 +263,7 @@ public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, V
219263
useNativeOpenALPane.setSubtitle(i18n("settings.advanced.linux_freebsd_only"));
220264

221265
workaroundPane.getContent().setAll(
222-
nativesDirSublist, rendererPane, noJVMArgsPane, noOptimizingJVMArgsPane, noGameCheckPane,
266+
nativesDirSublist, graphicsBackendPane, rendererPane, noJVMArgsPane, noOptimizingJVMArgsPane, noGameCheckPane,
223267
noJVMCheckPane, noNativesPatchPane
224268
);
225269

@@ -252,6 +296,7 @@ void bindProperties() {
252296
FXUtils.bindString(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
253297
FXUtils.bindString(txtPostExitCommand, versionSetting.postExitCommandProperty());
254298
rendererPane.valueProperty().bindBidirectional(versionSetting.rendererProperty());
299+
graphicsBackendPane.valueProperty().bindBidirectional(versionSetting.graphicsBackendProperty());
255300
noGameCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckGameProperty());
256301
noJVMCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckJVMProperty());
257302
noJVMArgsPane.selectedProperty().bindBidirectional(versionSetting.noJVMArgsProperty());
@@ -294,6 +339,7 @@ void unbindProperties() {
294339
FXUtils.unbind(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
295340
FXUtils.unbind(txtPostExitCommand, versionSetting.postExitCommandProperty());
296341
rendererPane.valueProperty().unbindBidirectional(versionSetting.rendererProperty());
342+
graphicsBackendPane.valueProperty().unbindBidirectional(versionSetting.graphicsBackendProperty());
297343
noGameCheckPane.selectedProperty().unbindBidirectional(versionSetting.notCheckGameProperty());
298344
noJVMCheckPane.selectedProperty().unbindBidirectional(versionSetting.notCheckJVMProperty());
299345
noJVMArgsPane.selectedProperty().unbindBidirectional(versionSetting.noJVMArgsProperty());

HMCL/src/main/java/org/jackhuang/hmcl/util/NativePatcher.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,15 +189,16 @@ public static Version patchNative(DefaultGameRepository repository,
189189
return version.setLibraries(newLibraries);
190190
}
191191

192-
public static @Nullable Library getWindowsMesaLoader(@NotNull JavaRuntime javaVersion, @NotNull Renderer renderer, @NotNull OSVersion windowsVersion) {
192+
/// @see <a href="https://github.com/HMCL-dev/mesa-loader-windows">Java Mesa Loader for Windows</a>
193+
public static @Nullable Library getWindowsMesaLoader(@NotNull JavaRuntime java, @NotNull Renderer renderer, @NotNull OSVersion windowsVersion) {
193194
if (renderer == Renderer.DEFAULT)
194195
return null;
195196

196197
if (windowsVersion.isAtLeast(OSVersion.WINDOWS_10)) {
197-
return getNatives(javaVersion.getPlatform()).get("mesa-loader");
198+
return getNatives(java.getPlatform()).get("mesa-loader");
198199
} else if (windowsVersion.isAtLeast(OSVersion.WINDOWS_7)) {
199200
if (renderer == Renderer.LLVMPIPE)
200-
return getNatives(javaVersion.getPlatform()).get("software-renderer-loader");
201+
return getNatives(java.getPlatform()).get("software-renderer-loader");
201202
else
202203
return null;
203204
} else {

HMCL/src/main/resources/assets/lang/I18N.properties

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,15 @@ settings.advanced.dont_patch_natives=Do not attempt to automatically replace nat
13371337
settings.advanced.environment_variables=Environment Variables
13381338
settings.advanced.game_dir.default=Default (".minecraft/")
13391339
settings.advanced.game_dir.independent=Isolated (".minecraft/versions/<instance name>/", except for assets and libraries)
1340+
settings.advanced.graphics_backend=Graphics API
1341+
settings.advanced.graphics_backend.default=Default
1342+
settings.advanced.graphics_backend.default.desc=Follow the game's settings
1343+
settings.advanced.graphics_backend.opengl=OpenGL
1344+
settings.advanced.graphics_backend.opengl.desc=Use OpenGL for rendering
1345+
settings.advanced.graphics_backend.vulkan=Vulkan
1346+
settings.advanced.graphics_backend.vulkan.desc=Use Vulkan for rendering
1347+
settings.advanced.graphics_backend.vulkan.desc.global=Use Vulkan for rendering (Since Minecraft 26.2)
1348+
settings.advanced.graphics_backend.vulkan.desc.unsupported=Use Vulkan for rendering (not supported for the current game version)
13401349
settings.advanced.java_permanent_generation_space=PermGen Space
13411350
settings.advanced.java_permanent_generation_space.prompt=in MiB
13421351
settings.advanced.jvm=JVM Options
@@ -1379,13 +1388,17 @@ settings.advanced.post_exit_command=Post-exit Command
13791388
settings.advanced.post_exit_command.prompt=Commands to execute after the game exits
13801389
settings.advanced.renderer=Renderer
13811390
settings.advanced.renderer.default=Default
1382-
settings.advanced.renderer.default.desc=OpenGL
1391+
settings.advanced.renderer.default.desc=Use System Default
13831392
settings.advanced.renderer.d3d12=Mesa D3D12
1384-
settings.advanced.renderer.d3d12.desc=DirectX 12 (Poor performance and compatibility)
1393+
settings.advanced.renderer.d3d12.desc=OpenGL renderer based on DirectX 12
1394+
settings.advanced.renderer.lavapipe=Mesa Lavapipe
1395+
settings.advanced.renderer.lavapipe.desc=Software Vulkan Renderer
13851396
settings.advanced.renderer.llvmpipe=Mesa LLVMpipe
1386-
settings.advanced.renderer.llvmpipe.desc=Software (Poor performance, best compatibility)
1397+
settings.advanced.renderer.llvmpipe.desc=Software OpenGL Renderer
1398+
settings.advanced.renderer.dozen=Mesa Dozen
1399+
settings.advanced.renderer.dozen.desc=Vulkan renderer based on DirectX 12 (Experimental)
13871400
settings.advanced.renderer.zink=Mesa Zink
1388-
settings.advanced.renderer.zink.desc=Vulkan (Best performance, poor compatibility)
1401+
settings.advanced.renderer.zink.desc=OpenGL renderer based on Vulkan
13891402
settings.advanced.server_ip=Server Address
13901403
settings.advanced.server_ip.prompt=Automatically join after launching the game
13911404
settings.advanced.unsupported_system_options=Settings not applicable to the current system

HMCL/src/main/resources/assets/lang/I18N_ar.properties

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,13 +1364,9 @@ settings.advanced.post_exit_command=أمر ما بعد الإغلاق
13641364
settings.advanced.post_exit_command.prompt=أوامر تُنفَّذ بعد إغلاق اللعبة
13651365
settings.advanced.renderer=المُصيِّر
13661366
settings.advanced.renderer.default=افتراضي
1367-
settings.advanced.renderer.default.desc=OpenGL
13681367
settings.advanced.renderer.d3d12=Mesa D3D12
1369-
settings.advanced.renderer.d3d12.desc=DirectX 12 (أداء وتوافق ضعيفان)
13701368
settings.advanced.renderer.llvmpipe=Mesa LLVMpipe
1371-
settings.advanced.renderer.llvmpipe.desc=برمجي (أداء ضعيف، توافق أفضل)
13721369
settings.advanced.renderer.zink=Mesa Zink
1373-
settings.advanced.renderer.zink.desc=Vulkan (أفضل أداء، توافق ضعيف)
13741370
settings.advanced.server_ip=عنوان الخادم
13751371
settings.advanced.server_ip.prompt=الانضمام تلقائياً بعد تشغيل اللعبة
13761372
settings.advanced.unsupported_system_options=إعدادات غير مطبّقة على النظام الحالي

HMCL/src/main/resources/assets/lang/I18N_es.properties

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,13 +1268,9 @@ settings.advanced.post_exit_command=Comando post-salida
12681268
settings.advanced.post_exit_command.prompt=El comando se ejecuta después de que el juego se detenga
12691269
settings.advanced.renderer=Renderizador
12701270
settings.advanced.renderer.default=Por defecto
1271-
settings.advanced.renderer.default.desc=OpenGL
12721271
settings.advanced.renderer.d3d12=Mesa D3D12
1273-
settings.advanced.renderer.d3d12.desc=DirectX 12 (Rendimiento y compatibilidad deficientes)
12741272
settings.advanced.renderer.llvmpipe=Mesa LLVMpipe
1275-
settings.advanced.renderer.llvmpipe.desc=Software (Bajo rendimiento, máxima compatibilidad)
12761273
settings.advanced.renderer.zink=Mesa Zink
1277-
settings.advanced.renderer.zink.desc=Vulkan (Máximo rendimiento, baja compatibilidad)
12781274
settings.advanced.server_ip=Dirección del servidor
12791275
settings.advanced.server_ip.prompt=Entrar automáticamente después de ejecutar el juego
12801276
settings.advanced.unsupported_system_options=Configuración no aplicable al sistema actual

0 commit comments

Comments
 (0)