diff --git a/common/src/api/java/dev/engine_room/flywheel/api/backend/Backend.java b/common/src/api/java/dev/engine_room/flywheel/api/backend/Backend.java
index ca63659c7..6cc6228f9 100644
--- a/common/src/api/java/dev/engine_room/flywheel/api/backend/Backend.java
+++ b/common/src/api/java/dev/engine_room/flywheel/api/backend/Backend.java
@@ -14,9 +14,15 @@ public interface Backend {
Engine createEngine(LevelAccessor level);
/**
- * Get a fallback backend in case this backend is not supported.
+ * The priority of this backend.
+ *
The backend with the highest priority upon first launch will be chosen as the default backend.
+ *
+ *
If the selected backend becomes unavailable for whatever reason, the next supported backend
+ * with a LOWER priority than the selected one will be chosen.
+ *
+ * @return The priority of this backend.
*/
- Backend findFallback();
+ int priority();
/**
* Check if this backend is supported.
diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/Backends.java b/common/src/backend/java/dev/engine_room/flywheel/backend/Backends.java
index 59e255cd5..81cdf2408 100644
--- a/common/src/backend/java/dev/engine_room/flywheel/backend/Backends.java
+++ b/common/src/backend/java/dev/engine_room/flywheel/backend/Backends.java
@@ -17,6 +17,7 @@ public final class Backends {
*/
public static final Backend INSTANCING = SimpleBackend.builder()
.engineFactory(level -> new EngineImpl(level, new InstancedDrawManager(InstancingPrograms.get()), 256))
+ .priority(500)
.supported(() -> GlCompat.SUPPORTS_INSTANCING && InstancingPrograms.allLoaded() && !ShadersModHandler.isShaderPackInUse())
.register(Flywheel.rl("instancing"));
@@ -25,7 +26,7 @@ public final class Backends {
*/
public static final Backend INDIRECT = SimpleBackend.builder()
.engineFactory(level -> new EngineImpl(level, new IndirectDrawManager(IndirectPrograms.get()), 256))
- .fallback(() -> Backends.INSTANCING)
+ .priority(1000)
.supported(() -> GlCompat.SUPPORTS_INDIRECT && IndirectPrograms.allLoaded() && !ShadersModHandler.isShaderPackInUse())
.register(Flywheel.rl("indirect"));
diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/backend/SimpleBackend.java b/common/src/lib/java/dev/engine_room/flywheel/lib/backend/SimpleBackend.java
index cdec1433f..bc09227c1 100644
--- a/common/src/lib/java/dev/engine_room/flywheel/lib/backend/SimpleBackend.java
+++ b/common/src/lib/java/dev/engine_room/flywheel/lib/backend/SimpleBackend.java
@@ -3,22 +3,20 @@
import java.util.Objects;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
-import java.util.function.Supplier;
import dev.engine_room.flywheel.api.backend.Backend;
-import dev.engine_room.flywheel.api.backend.BackendManager;
import dev.engine_room.flywheel.api.backend.Engine;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.LevelAccessor;
public final class SimpleBackend implements Backend {
private final Function engineFactory;
- private final Supplier fallback;
+ private final int priority;
private final BooleanSupplier isSupported;
- public SimpleBackend(Function engineFactory, Supplier fallback, BooleanSupplier isSupported) {
+ public SimpleBackend(int priority, Function engineFactory, BooleanSupplier isSupported) {
+ this.priority = priority;
this.engineFactory = engineFactory;
- this.fallback = fallback;
this.isSupported = isSupported;
}
@@ -32,13 +30,8 @@ public Engine createEngine(LevelAccessor level) {
}
@Override
- public Backend findFallback() {
- if (isSupported()) {
- return this;
- } else {
- return fallback.get()
- .findFallback();
- }
+ public int priority() {
+ return priority;
}
@Override
@@ -48,7 +41,7 @@ public boolean isSupported() {
public static final class Builder {
private Function engineFactory;
- private Supplier fallback = BackendManager::offBackend;
+ private int priority = 0;
private BooleanSupplier isSupported;
public Builder engineFactory(Function engineFactory) {
@@ -56,8 +49,8 @@ public Builder engineFactory(Function engineFactory) {
return this;
}
- public Builder fallback(Supplier fallback) {
- this.fallback = fallback;
+ public Builder priority(int priority) {
+ this.priority = priority;
return this;
}
@@ -68,10 +61,9 @@ public Builder supported(BooleanSupplier isSupported) {
public Backend register(ResourceLocation id) {
Objects.requireNonNull(engineFactory);
- Objects.requireNonNull(fallback);
Objects.requireNonNull(isSupported);
- return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineFactory, fallback, isSupported));
+ return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(priority, engineFactory, isSupported));
}
}
}
diff --git a/common/src/main/java/dev/engine_room/flywheel/impl/BackendManagerImpl.java b/common/src/main/java/dev/engine_room/flywheel/impl/BackendManagerImpl.java
index bd2ae4a78..75133adeb 100644
--- a/common/src/main/java/dev/engine_room/flywheel/impl/BackendManagerImpl.java
+++ b/common/src/main/java/dev/engine_room/flywheel/impl/BackendManagerImpl.java
@@ -1,8 +1,9 @@
package dev.engine_room.flywheel.impl;
+import java.util.ArrayList;
+
import dev.engine_room.flywheel.api.Flywheel;
import dev.engine_room.flywheel.api.backend.Backend;
-import dev.engine_room.flywheel.backend.Backends;
import dev.engine_room.flywheel.impl.visualization.VisualizationManagerImpl;
import dev.engine_room.flywheel.lib.backend.SimpleBackend;
import net.minecraft.client.multiplayer.ClientLevel;
@@ -31,21 +32,48 @@ public static boolean isBackendOn() {
return backend != OFF_BACKEND;
}
+ // Don't store this statically because backends can theoretically change their priorities at runtime.
+ private static ArrayList backendsByPriority() {
+ var backends = new ArrayList<>(Backend.REGISTRY.getAll());
+
+ // Sort with keys backwards so that the highest priority is first.
+ backends.sort((a, b) -> Integer.compare(b.priority(), a.priority()));
+ return backends;
+ }
+
private static Backend findDefaultBackend() {
- // TODO: Automatically select the best default config based on the user's driver
- // TODO: Figure out how this will work if custom backends are registered and without hardcoding the default backends
- return Backends.INDIRECT;
+ var backendsByPriority = backendsByPriority();
+ if (backendsByPriority.isEmpty()) {
+ // This probably shouldn't happen, but fail gracefully.
+ FlwImpl.LOGGER.warn("No backends registered, defaulting to 'flywheel:off'");
+ return OFF_BACKEND;
+ }
+
+ return backendsByPriority.get(0);
}
private static void chooseBackend() {
var preferred = FlwConfig.INSTANCE.backend();
- var actual = preferred.findFallback();
+ if (preferred.isSupported()) {
+ backend = preferred;
+ return;
+ }
+
+ var backendsByPriority = backendsByPriority();
+
+ var startIndex = backendsByPriority.indexOf(preferred) + 1;
- if (preferred != actual) {
- FlwImpl.LOGGER.warn("Flywheel backend fell back from '{}' to '{}'", Backend.REGISTRY.getIdOrThrow(preferred), Backend.REGISTRY.getIdOrThrow(actual));
+ // For safety in case we don't find anything
+ backend = OFF_BACKEND;
+ for (int i = startIndex; i < backendsByPriority.size(); i++) {
+ var candidate = backendsByPriority.get(i);
+ if (candidate.isSupported()) {
+ backend = candidate;
+ break;
+ }
}
- backend = actual;
+ FlwImpl.LOGGER.warn("Flywheel backend fell back from '{}' to '{}'", Backend.REGISTRY.getIdOrThrow(preferred), Backend.REGISTRY.getIdOrThrow(backend));
}
public static String getBackendString() {