Merge branch '1.20.1/dev' into 1.21.1/dev

This commit is contained in:
Jozufozu 2025-02-28 22:05:28 -08:00
commit f4123add3a
8 changed files with 112 additions and 111 deletions

View file

@ -15,7 +15,6 @@ import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.backend.FlwBackend;
import dev.engine_room.flywheel.backend.compile.core.ShaderException;
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
import dev.engine_room.flywheel.backend.engine.embed.Environment;
import dev.engine_room.flywheel.backend.engine.embed.EnvironmentStorage;
@ -96,7 +95,7 @@ public class EngineImpl implements Engine {
Uniforms.update(context);
environmentStorage.flush();
drawManager.render(lightStorage, environmentStorage);
} catch (ShaderException e) {
} catch (Exception e) {
FlwBackend.LOGGER.error("Falling back", e);
triggerFallback();
}
@ -106,7 +105,7 @@ public class EngineImpl implements Engine {
public void renderCrumbling(RenderContext context, List<CrumblingBlock> crumblingBlocks) {
try (var state = GlStateTracker.getRestoreState()) {
drawManager.renderCrumbling(crumblingBlocks);
} catch (ShaderException e) {
} catch (Exception e) {
FlwBackend.LOGGER.error("Falling back", e);
triggerFallback();
}

View file

@ -7,6 +7,7 @@ import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visual.TickableVisual;
import dev.engine_room.flywheel.api.visualization.VisualManager;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.impl.visualization.storage.Storage;
import dev.engine_room.flywheel.impl.visualization.storage.Transaction;
import dev.engine_room.flywheel.lib.task.SimplePlan;
@ -54,21 +55,25 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
queue.add(Transaction.update(obj));
}
public void processQueue(float partialTick) {
public void processQueue(VisualizationContext visualizationContext, float partialTick) {
var storage = getStorage();
Transaction<T> transaction;
while ((transaction = queue.poll()) != null) {
transaction.apply(storage, partialTick);
switch (transaction.action()) {
case ADD -> storage.add(visualizationContext, transaction.obj(), partialTick);
case REMOVE -> storage.remove(transaction.obj());
case UPDATE -> storage.update(transaction.obj(), partialTick);
}
}
}
public Plan<DynamicVisual.Context> framePlan() {
return SimplePlan.<DynamicVisual.Context>of(context -> processQueue(context.partialTick()))
public Plan<DynamicVisual.Context> framePlan(VisualizationContext visualizationContext) {
return SimplePlan.<DynamicVisual.Context>of(context -> processQueue(visualizationContext, context.partialTick()))
.then(storage.framePlan());
}
public Plan<TickableVisual.Context> tickPlan() {
return SimplePlan.<TickableVisual.Context>of(context -> processQueue(1))
public Plan<TickableVisual.Context> tickPlan(VisualizationContext visualizationContext) {
return SimplePlan.<TickableVisual.Context>of(context -> processQueue(visualizationContext, 1))
.then(storage.tickPlan());
}

View file

@ -59,9 +59,15 @@ public class VisualizationManagerImpl implements VisualizationManager {
private static final LevelAttached<VisualizationManagerImpl> MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete);
private final TaskExecutorImpl taskExecutor;
private final Engine engine;
private final DistanceUpdateLimiterImpl frameLimiter;
private final RenderDispatcherImpl renderDispatcher = new RenderDispatcherImpl();
private final LevelAccessor level;
// VisualizationManagerImpl can (and should!) be constructed off of the main thread, but it may be
// difficult for engines to avoid OpenGL calls which would not be safe. Shove all the init logic
// that depends on engine construction into here, and defer until we get invoked on the main thread.
@Nullable
private LateInit lateInit;
private final VisualManagerImpl<BlockEntity, BlockEntityStorage> blockEntities;
private final VisualManagerImpl<Entity, EntityStorage> entities;
@ -70,49 +76,14 @@ public class VisualizationManagerImpl implements VisualizationManager {
private final Flag frameFlag = new Flag("frame");
private final Flag tickFlag = new Flag("tick");
private final Plan<RenderContext> framePlan;
private final Plan<TickableVisual.Context> tickPlan;
private VisualizationManagerImpl(LevelAccessor level) {
this.level = level;
taskExecutor = FlwTaskExecutor.get();
engine = BackendManager.currentBackend()
.createEngine(level);
frameLimiter = createUpdateLimiter();
var visualizationContext = engine.createVisualizationContext();
var blockEntitiesStorage = new BlockEntityStorage(visualizationContext);
var entitiesStorage = new EntityStorage(visualizationContext);
var effectsStorage = new EffectStorage(visualizationContext);
blockEntities = new VisualManagerImpl<>(blockEntitiesStorage);
entities = new VisualManagerImpl<>(entitiesStorage);
effects = new VisualManagerImpl<>(effectsStorage);
var recreate = SimplePlan.<RenderContext>of(context -> blockEntitiesStorage.recreateAll(context.partialTick()),
context -> entitiesStorage.recreateAll(context.partialTick()),
context -> effectsStorage.recreateAll(context.partialTick()));
var update = MapContextPlan.map(this::createVisualFrameContext)
.to(NestedPlan.of(blockEntities.framePlan(), entities.framePlan(), effects.framePlan()));
framePlan = IfElsePlan.on((RenderContext ctx) -> engine.updateRenderOrigin(ctx.camera()))
.ifTrue(recreate)
.ifFalse(update)
.plan()
.then(SimplePlan.of(() -> {
if (blockEntities.areGpuLightSectionsDirty() || entities.areGpuLightSectionsDirty() || effects.areGpuLightSectionsDirty()) {
var out = new LongOpenHashSet();
out.addAll(blockEntities.gpuLightSections());
out.addAll(entities.gpuLightSections());
out.addAll(effects.gpuLightSections());
engine.lightSections(out);
}
}))
.then(engine.createFramePlan())
.then(RaisePlan.raise(frameFlag));
tickPlan = NestedPlan.of(blockEntities.tickPlan(), entities.tickPlan(), effects.tickPlan())
.then(RaisePlan.raise(tickFlag));
blockEntities = new VisualManagerImpl<>(new BlockEntityStorage());
entities = new VisualManagerImpl<>(new EntityStorage());
effects = new VisualManagerImpl<>(new EffectStorage());
if (level instanceof Level l) {
LevelExtension.getAllLoadedEntities(l)
@ -120,16 +91,65 @@ public class VisualizationManagerImpl implements VisualizationManager {
}
}
private DynamicVisual.Context createVisualFrameContext(RenderContext ctx) {
Vec3i renderOrigin = engine.renderOrigin();
var cameraPos = ctx.camera()
.getPosition();
private class LateInit {
private final Engine engine;
Matrix4f viewProjection = new Matrix4f(ctx.viewProjection());
viewProjection.translate((float) (renderOrigin.getX() - cameraPos.x), (float) (renderOrigin.getY() - cameraPos.y), (float) (renderOrigin.getZ() - cameraPos.z));
FrustumIntersection frustum = new FrustumIntersection(viewProjection);
private final Plan<RenderContext> framePlan;
private final Plan<TickableVisual.Context> tickPlan;
return new DynamicVisualContextImpl(ctx.camera(), frustum, ctx.partialTick(), frameLimiter);
private LateInit(LevelAccessor level) {
engine = BackendManager.currentBackend()
.createEngine(level);
var visualizationContext = engine.createVisualizationContext();
var recreate = SimplePlan.<RenderContext>of(context -> blockEntities.getStorage()
.recreateAll(visualizationContext, context.partialTick()), context -> entities.getStorage()
.recreateAll(visualizationContext, context.partialTick()), context -> effects.getStorage()
.recreateAll(visualizationContext, context.partialTick()));
var update = MapContextPlan.map(this::createVisualFrameContext)
.to(NestedPlan.of(blockEntities.framePlan(visualizationContext), entities.framePlan(visualizationContext), effects.framePlan(visualizationContext)));
framePlan = IfElsePlan.on((RenderContext ctx) -> engine.updateRenderOrigin(ctx.camera()))
.ifTrue(recreate)
.ifFalse(update)
.plan()
.then(SimplePlan.of(() -> {
if (blockEntities.areGpuLightSectionsDirty() || entities.areGpuLightSectionsDirty() || effects.areGpuLightSectionsDirty()) {
var out = new LongOpenHashSet();
out.addAll(blockEntities.gpuLightSections());
out.addAll(entities.gpuLightSections());
out.addAll(effects.gpuLightSections());
engine.lightSections(out);
}
}))
.then(engine.createFramePlan())
.then(RaisePlan.raise(frameFlag));
tickPlan = NestedPlan.of(blockEntities.tickPlan(visualizationContext), entities.tickPlan(visualizationContext), effects.tickPlan(visualizationContext))
.then(RaisePlan.raise(tickFlag));
}
private DynamicVisual.Context createVisualFrameContext(RenderContext ctx) {
Vec3i renderOrigin = engine.renderOrigin();
var cameraPos = ctx.camera()
.getPosition();
Matrix4f viewProjection = new Matrix4f(ctx.viewProjection());
viewProjection.translate((float) (renderOrigin.getX() - cameraPos.x), (float) (renderOrigin.getY() - cameraPos.y), (float) (renderOrigin.getZ() - cameraPos.z));
FrustumIntersection frustum = new FrustumIntersection(viewProjection);
return new DynamicVisualContextImpl(ctx.camera(), frustum, ctx.partialTick(), frameLimiter);
}
}
private LateInit lateInit() {
if (lateInit == null) {
lateInit = new LateInit(level);
}
return lateInit;
}
private DistanceUpdateLimiterImpl createUpdateLimiter() {
@ -191,7 +211,11 @@ public class VisualizationManagerImpl implements VisualizationManager {
@Override
public Vec3i renderOrigin() {
return engine.renderOrigin();
if (lateInit == null) {
return Vec3i.ZERO;
} else {
return lateInit.engine.renderOrigin();
}
}
@Override
@ -225,7 +249,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
taskExecutor.syncUntil(tickFlag::isRaised);
tickFlag.lower();
tickPlan.execute(taskExecutor, TickableVisualContextImpl.INSTANCE);
lateInit().tickPlan.execute(taskExecutor, TickableVisualContextImpl.INSTANCE);
}
/**
@ -240,7 +264,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
frameLimiter.tick();
framePlan.execute(taskExecutor, context);
lateInit().framePlan.execute(taskExecutor, context);
}
/**
@ -248,7 +272,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
*/
private void render(RenderContext context) {
taskExecutor.syncUntil(frameFlag::isRaised);
engine.render(context);
lateInit().engine.render(context);
}
private void renderCrumbling(RenderContext context, Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress) {
@ -292,12 +316,12 @@ public class VisualizationManagerImpl implements VisualizationManager {
}
if (!crumblingBlocks.isEmpty()) {
engine.renderCrumbling(context, crumblingBlocks);
lateInit().engine.renderCrumbling(context, crumblingBlocks);
}
}
public void onLightUpdate(SectionPos sectionPos, LightLayer layer) {
engine.onLightUpdate(sectionPos, layer);
lateInit().engine.onLightUpdate(sectionPos, layer);
long longPos = sectionPos.asLong();
blockEntities.onLightUpdate(longPos);
entities.onLightUpdate(longPos);
@ -315,7 +339,9 @@ public class VisualizationManagerImpl implements VisualizationManager {
blockEntities.invalidate();
entities.invalidate();
effects.invalidate();
engine.delete();
if (lateInit != null) {
lateInit.engine.delete();
}
}
private class RenderDispatcherImpl implements RenderDispatcher {
@ -335,6 +361,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
}
}
private record CrumblingBlockImpl(BlockPos pos, int progress, List<Instance> instances) implements Engine.CrumblingBlock {
private record CrumblingBlockImpl(BlockPos pos, int progress,
List<Instance> instances) implements dev.engine_room.flywheel.api.backend.Engine.CrumblingBlock {
}
}

View file

@ -15,10 +15,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
public class BlockEntityStorage extends Storage<BlockEntity> {
private final Long2ObjectMap<BlockEntityVisual<?>> posLookup = new Long2ObjectOpenHashMap<>();
public BlockEntityStorage(VisualizationContext visualizationContext) {
super(visualizationContext);
}
@Nullable
public BlockEntityVisual<?> visualAtPos(long pos) {
return posLookup.get(pos);
@ -50,7 +46,7 @@ public class BlockEntityStorage extends Storage<BlockEntity> {
@Override
@Nullable
protected BlockEntityVisual<?> createRaw(BlockEntity obj, float partialTick) {
protected BlockEntityVisual<?> createRaw(VisualizationContext visualizationContext, BlockEntity obj, float partialTick) {
var visualizer = VisualizationHelper.getVisualizer(obj);
if (visualizer == null) {
return null;
@ -72,9 +68,9 @@ public class BlockEntityStorage extends Storage<BlockEntity> {
}
@Override
public void recreateAll(float partialTick) {
public void recreateAll(VisualizationContext visualizationContext, float partialTick) {
posLookup.clear();
super.recreateAll(partialTick);
super.recreateAll(visualizationContext, partialTick);
}
@Override

View file

@ -5,12 +5,8 @@ import dev.engine_room.flywheel.api.visual.EffectVisual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
public class EffectStorage extends Storage<Effect> {
public EffectStorage(VisualizationContext visualizationContext) {
super(visualizationContext);
}
@Override
protected EffectVisual<?> createRaw(Effect obj, float partialTick) {
protected EffectVisual<?> createRaw(VisualizationContext visualizationContext, Effect obj, float partialTick) {
return obj.visualize(visualizationContext, partialTick);
}

View file

@ -7,18 +7,14 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
public class EntityStorage extends Storage<Entity> {
public EntityStorage(VisualizationContext visualizationContext) {
super(visualizationContext);
}
@Override
protected EntityVisual<?> createRaw(Entity obj, float partialTick) {
protected EntityVisual<?> createRaw(VisualizationContext context, Entity obj, float partialTick) {
var visualizer = VisualizationHelper.getVisualizer(obj);
if (visualizer == null) {
return null;
}
return visualizer.createVisual(visualizationContext, obj, partialTick);
return visualizer.createVisual(context, obj, partialTick);
}
@Override

View file

@ -25,8 +25,6 @@ import dev.engine_room.flywheel.lib.visual.SimpleTickableVisual;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
public abstract class Storage<T> {
protected final VisualizationContext visualizationContext;
private final Map<T, Visual> visuals = new Reference2ObjectOpenHashMap<>();
protected final PlanMap<DynamicVisual, DynamicVisual.Context> dynamicVisuals = new PlanMap<>();
protected final PlanMap<TickableVisual, TickableVisual.Context> tickableVisuals = new PlanMap<>();
@ -35,10 +33,6 @@ public abstract class Storage<T> {
protected final LightUpdatedVisualStorage lightUpdatedVisuals = new LightUpdatedVisualStorage();
protected final ShaderLightVisualStorage shaderLightVisuals = new ShaderLightVisualStorage();
public Storage(VisualizationContext visualizationContext) {
this.visualizationContext = visualizationContext;
}
public Collection<Visual> getAllVisuals() {
return visuals.values();
}
@ -71,11 +65,16 @@ public abstract class Storage<T> {
*/
public abstract boolean willAccept(T obj);
public void add(T obj, float partialTick) {
public void add(VisualizationContext visualizationContext, T obj, float partialTick) {
Visual visual = visuals.get(obj);
if (visual == null) {
create(obj, partialTick);
visual = createRaw(visualizationContext, obj, partialTick);
if (visual != null) {
setup(visual, partialTick);
visuals.put(obj, visual);
}
}
}
@ -120,7 +119,7 @@ public abstract class Storage<T> {
visual.update(partialTick);
}
public void recreateAll(float partialTick) {
public void recreateAll(VisualizationContext visualizationContext, float partialTick) {
dynamicVisuals.clear();
tickableVisuals.clear();
simpleDynamicVisuals.clear();
@ -131,7 +130,7 @@ public abstract class Storage<T> {
visuals.replaceAll((obj, visual) -> {
visual.delete();
var out = createRaw(obj, partialTick);
var out = createRaw(visualizationContext, obj, partialTick);
if (out != null) {
setup(out, partialTick);
@ -141,17 +140,8 @@ public abstract class Storage<T> {
});
}
private void create(T obj, float partialTick) {
var visual = createRaw(obj, partialTick);
if (visual != null) {
setup(visual, partialTick);
visuals.put(obj, visual);
}
}
@Nullable
protected abstract Visual createRaw(T obj, float partialTick);
protected abstract Visual createRaw(VisualizationContext visualizationContext, T obj, float partialTick);
private void setup(Visual visual, float partialTick) {
if (visual instanceof DynamicVisual dynamic) {

View file

@ -12,12 +12,4 @@ public record Transaction<T>(T obj, Action action) {
public static <T> Transaction<T> update(T obj) {
return new Transaction<>(obj, Action.UPDATE);
}
public void apply(Storage<T> storage, float partialTick) {
switch (action) {
case ADD -> storage.add(obj, partialTick);
case REMOVE -> storage.remove(obj);
case UPDATE -> storage.update(obj, partialTick);
}
}
}