mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-03 16:54:57 +01:00
First try
- Implement instance hiding by deleting/stealing - Work around instancer persistence by storing a recreation supplier in the instance handle - Rework instancer ctors to just take an InstancerKey - Parameterize InstanceHandle by I extends Instance so the steal method and the supplier can be safely assigned
This commit is contained in:
parent
e1b594ac47
commit
5a75fe972f
8 changed files with 87 additions and 40 deletions
|
@ -7,4 +7,8 @@ public interface InstanceHandle {
|
|||
void setChanged();
|
||||
|
||||
void setDeleted();
|
||||
|
||||
void setVisible(boolean visible);
|
||||
|
||||
boolean isVisible();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dev.engine_room.flywheel.backend.engine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -13,26 +14,32 @@ import dev.engine_room.flywheel.backend.util.AtomicBitSet;
|
|||
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
||||
public final InstanceType<I> type;
|
||||
public final Environment environment;
|
||||
private final Supplier<AbstractInstancer<I>> recreate;
|
||||
|
||||
// Lock for all instances, only needs to be used in methods that may run on the TaskExecutor.
|
||||
protected final Object lock = new Object();
|
||||
protected final ArrayList<I> instances = new ArrayList<>();
|
||||
protected final ArrayList<InstanceHandleImpl> handles = new ArrayList<>();
|
||||
protected final ArrayList<InstanceHandleImpl<I>> handles = new ArrayList<>();
|
||||
|
||||
protected final AtomicBitSet changed = new AtomicBitSet();
|
||||
protected final AtomicBitSet deleted = new AtomicBitSet();
|
||||
|
||||
protected AbstractInstancer(InstanceType<I> type, Environment environment) {
|
||||
this.type = type;
|
||||
this.environment = environment;
|
||||
protected AbstractInstancer(InstancerKey<I> key, Supplier<AbstractInstancer<I>> recreate) {
|
||||
this.type = key.type();
|
||||
this.environment = key.environment();
|
||||
this.recreate = recreate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public I createInstance() {
|
||||
synchronized (lock) {
|
||||
var i = instances.size();
|
||||
var handle = new InstanceHandleImpl(this, i);
|
||||
var handle = new InstanceHandleImpl<I>();
|
||||
handle.instancer = this;
|
||||
handle.recreate = recreate;
|
||||
handle.index = i;
|
||||
I instance = type.create(handle);
|
||||
handle.instance = instance;
|
||||
|
||||
addLocked(instance, handle);
|
||||
return instance;
|
||||
|
@ -47,12 +54,15 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
|||
|
||||
var instanceHandle = instance.handle();
|
||||
|
||||
if (!(instanceHandle instanceof InstanceHandleImpl handle)) {
|
||||
if (!(instanceHandle instanceof InstanceHandleImpl<?>)) {
|
||||
// UB: do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle.instancer == this) {
|
||||
// Should InstanceType have an isInstance method?
|
||||
var handle = (InstanceHandleImpl<I>) instanceHandle;
|
||||
|
||||
if (handle.instancer == this && handle.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -65,19 +75,23 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
|||
// is filtering deleted instances later, so is safe.
|
||||
handle.setDeleted();
|
||||
|
||||
// Only lock now that we'll be mutating our state.
|
||||
synchronized (lock) {
|
||||
// Add the instance to this instancer.
|
||||
handle.instancer = this;
|
||||
handle.index = instances.size();
|
||||
addLocked(instance, handle);
|
||||
// Add the instance to this instancer.
|
||||
handle.instancer = this;
|
||||
handle.recreate = recreate;
|
||||
|
||||
if (handle.visible) {
|
||||
// Only lock now that we'll be mutating our state.
|
||||
synchronized (lock) {
|
||||
handle.index = instances.size();
|
||||
addLocked(instance, handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls must be synchronized on {@link #lock}.
|
||||
*/
|
||||
private void addLocked(I instance, InstanceHandleImpl handle) {
|
||||
private void addLocked(I instance, InstanceHandleImpl<I> handle) {
|
||||
instances.add(instance);
|
||||
handles.add(handle);
|
||||
changed.set(handle.index);
|
||||
|
@ -163,7 +177,7 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
|||
* Clear all instances without freeing resources.
|
||||
*/
|
||||
public void clear() {
|
||||
for (InstanceHandleImpl handle : handles) {
|
||||
for (InstanceHandleImpl<I> handle : handles) {
|
||||
// Only clear instances that belong to this instancer.
|
||||
// If one of these handles was stolen by another instancer,
|
||||
// clearing it here would cause significant visual artifacts and instance leaks.
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||
import dev.engine_room.flywheel.api.backend.Engine;
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||
|
@ -36,9 +35,13 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||
*/
|
||||
protected final Queue<UninitializedInstancer<N, ?>> initializationQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public <I extends Instance> AbstractInstancer<I> getInstancer(Environment environment, InstanceType<I> type, Model model, VisualType visualType, int bias) {
|
||||
return getInstancer(new InstancerKey<>(environment, type, model, visualType, bias));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Instance> Instancer<I> getInstancer(Environment environment, InstanceType<I> type, Model model, VisualType visualType, int bias) {
|
||||
return (Instancer<I>) instancers.computeIfAbsent(new InstancerKey<>(environment, type, model, visualType, bias), this::createAndDeferInit);
|
||||
public <I extends Instance> AbstractInstancer<I> getInstancer(InstancerKey<I> key) {
|
||||
return (AbstractInstancer<I>) instancers.computeIfAbsent(key, this::createAndDeferInit);
|
||||
}
|
||||
|
||||
public void flush(LightStorage lightStorage, EnvironmentStorage environmentStorage) {
|
||||
|
@ -94,8 +97,8 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected static <I extends AbstractInstancer<?>> Map<GroupKey<?>, Int2ObjectMap<List<Pair<I, InstanceHandleImpl>>>> doCrumblingSort(Class<I> clazz, List<Engine.CrumblingBlock> crumblingBlocks) {
|
||||
Map<GroupKey<?>, Int2ObjectMap<List<Pair<I, InstanceHandleImpl>>>> byType = new HashMap<>();
|
||||
protected static <I extends AbstractInstancer<?>> Map<GroupKey<?>, Int2ObjectMap<List<Pair<I, InstanceHandleImpl<?>>>>> doCrumblingSort(Class<I> clazz, List<Engine.CrumblingBlock> crumblingBlocks) {
|
||||
Map<GroupKey<?>, Int2ObjectMap<List<Pair<I, InstanceHandleImpl<?>>>>> byType = new HashMap<>();
|
||||
for (Engine.CrumblingBlock block : crumblingBlocks) {
|
||||
int progress = block.progress();
|
||||
|
||||
|
@ -107,7 +110,7 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||
// Filter out instances that weren't created by this engine.
|
||||
// If all is well, we probably shouldn't take the `continue`
|
||||
// branches but better to do checked casts.
|
||||
if (!(instance.handle() instanceof InstanceHandleImpl impl)) {
|
||||
if (!(instance.handle() instanceof InstanceHandleImpl<?> impl)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
package dev.engine_room.flywheel.backend.engine;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
||||
|
||||
public class InstanceHandleImpl implements InstanceHandle {
|
||||
public AbstractInstancer<?> instancer;
|
||||
public class InstanceHandleImpl<I extends Instance> implements InstanceHandle {
|
||||
@UnknownNullability
|
||||
public AbstractInstancer<I> instancer;
|
||||
@UnknownNullability
|
||||
public I instance;
|
||||
@UnknownNullability
|
||||
public Supplier<AbstractInstancer<I>> recreate;
|
||||
public boolean visible = true;
|
||||
public int index;
|
||||
|
||||
public InstanceHandleImpl(AbstractInstancer<?> instancer, int index) {
|
||||
this.instancer = instancer;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
instancer.notifyDirty(index);
|
||||
|
@ -23,6 +29,27 @@ public class InstanceHandleImpl implements InstanceHandle {
|
|||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
if (this.visible == visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.visible = visible;
|
||||
|
||||
if (visible) {
|
||||
recreate.get().stealInstance(instance);
|
||||
} else {
|
||||
instancer.notifyRemoval(index);
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
index = -1;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
|
||||
@Override
|
||||
protected <I extends Instance> IndirectInstancer<?> create(InstancerKey<I> key) {
|
||||
return new IndirectInstancer<>(key.type(), key.environment(), key.model());
|
||||
return new IndirectInstancer<>(key, () -> getInstancer(key));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -2,17 +2,16 @@ package dev.engine_room.flywheel.backend.engine.indirect;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.joml.Vector4fc;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceWriter;
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
import dev.engine_room.flywheel.backend.engine.AbstractInstancer;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||
import dev.engine_room.flywheel.backend.engine.InstancerKey;
|
||||
import dev.engine_room.flywheel.backend.util.AtomicBitSet;
|
||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||
|
||||
|
@ -29,12 +28,12 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
private int modelIndex = -1;
|
||||
private int baseInstance = -1;
|
||||
|
||||
public IndirectInstancer(InstanceType<I> type, Environment environment, Model model) {
|
||||
super(type, environment);
|
||||
public IndirectInstancer(InstancerKey<I> key, Supplier<AbstractInstancer<I>> recreate) {
|
||||
super(key, recreate);
|
||||
instanceStride = MoreMath.align4(type.layout()
|
||||
.byteSize());
|
||||
writer = this.type.writer();
|
||||
boundingSphere = model.boundingSphere();
|
||||
boundingSphere = key.model().boundingSphere();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -128,7 +128,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||
|
||||
@Override
|
||||
protected <I extends Instance> InstancedInstancer<I> create(InstancerKey<I> key) {
|
||||
return new InstancedInstancer<>(key.type(), key.environment());
|
||||
return new InstancedInstancer<>(key, () -> getInstancer(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,14 +2,14 @@ package dev.engine_room.flywheel.backend.engine.instancing;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceWriter;
|
||||
import dev.engine_room.flywheel.backend.engine.AbstractInstancer;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||
import dev.engine_room.flywheel.backend.engine.InstancerKey;
|
||||
import dev.engine_room.flywheel.backend.gl.TextureBuffer;
|
||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBufferUsage;
|
||||
|
@ -25,8 +25,8 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
|
||||
private final List<InstancedDraw> draws = new ArrayList<>();
|
||||
|
||||
public InstancedInstancer(InstanceType<I> type, Environment environment) {
|
||||
super(type, environment);
|
||||
public InstancedInstancer(InstancerKey<I> key, Supplier<AbstractInstancer<I>> recreate) {
|
||||
super(key, recreate);
|
||||
var layout = type.layout();
|
||||
// Align to one texel in the texture buffer
|
||||
instanceStride = MoreMath.align16(layout.byteSize());
|
||||
|
|
Loading…
Reference in a new issue