mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-05 01:34:58 +01:00
Proper task engine
- Manual threadpool - More control
This commit is contained in:
parent
3049601e4a
commit
80b3c1ed35
11 changed files with 245 additions and 66 deletions
|
@ -0,0 +1,172 @@
|
||||||
|
package com.jozufozu.flywheel.backend.instancing;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.batching.WaitGroup;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
|
// https://github.com/CaffeineMC/sodium-fabric/blob/5d364ed5ba63f9067fcf72a078ca310bff4db3e9/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java
|
||||||
|
public class BatchExecutor implements TaskEngine {
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger("BatchExecutor");
|
||||||
|
|
||||||
|
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||||
|
private final WaitGroup wg = new WaitGroup();
|
||||||
|
|
||||||
|
private final Deque<Runnable> jobQueue = new ConcurrentLinkedDeque<>();
|
||||||
|
private final List<Thread> threads = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Object jobNotifier = new Object();
|
||||||
|
|
||||||
|
private final int threadCount;
|
||||||
|
|
||||||
|
public BatchExecutor() {
|
||||||
|
threadCount = getOptimalThreadCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spawns a number of work-stealing threads to process results in the build queue. If the builder is already
|
||||||
|
* running, this method does nothing and exits.
|
||||||
|
*/
|
||||||
|
public void startWorkers() {
|
||||||
|
if (this.running.getAndSet(true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.threads.isEmpty()) {
|
||||||
|
throw new IllegalStateException("Threads are still alive while in the STOPPED state");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.threadCount; i++) {
|
||||||
|
|
||||||
|
Thread thread = new Thread(new WorkerRunnable(), "Engine Executor " + i);
|
||||||
|
thread.setPriority(Math.max(0, Thread.NORM_PRIORITY - 2));
|
||||||
|
thread.start();
|
||||||
|
|
||||||
|
this.threads.add(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Started {} worker threads", this.threads.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopWorkers() {
|
||||||
|
if (!this.running.getAndSet(false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.threads.isEmpty()) {
|
||||||
|
throw new IllegalStateException("No threads are alive but the executor is in the RUNNING state");
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this.jobNotifier) {
|
||||||
|
this.jobNotifier.notifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (Thread thread : this.threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.threads.clear();
|
||||||
|
|
||||||
|
this.jobQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a task to the pool.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void submit(@NotNull Runnable command) {
|
||||||
|
this.jobQueue.add(command);
|
||||||
|
this.wg.add(1);
|
||||||
|
|
||||||
|
synchronized (this.jobNotifier) {
|
||||||
|
this.jobNotifier.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for all running jobs to finish.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void syncPoint() {
|
||||||
|
Runnable job;
|
||||||
|
|
||||||
|
// Finish everyone else's work...
|
||||||
|
while ((job = getNextTask(false)) != null) {
|
||||||
|
processTask(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
// and wait for any stragglers.
|
||||||
|
try {
|
||||||
|
this.wg.await();
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Runnable getNextTask(boolean block) {
|
||||||
|
Runnable job = this.jobQueue.poll();
|
||||||
|
|
||||||
|
if (job == null && block) {
|
||||||
|
synchronized (BatchExecutor.this.jobNotifier) {
|
||||||
|
try {
|
||||||
|
BatchExecutor.this.jobNotifier.wait();
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processTask(Runnable job) {
|
||||||
|
try {
|
||||||
|
job.run();
|
||||||
|
} finally {
|
||||||
|
BatchExecutor.this.wg.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the "optimal" number of threads to be used for chunk build tasks. This will always return at least one
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
private static int getOptimalThreadCount() {
|
||||||
|
return Mth.clamp(Math.max(getMaxThreadCount() / 3, getMaxThreadCount() - 6), 1, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getMaxThreadCount() {
|
||||||
|
return Runtime.getRuntime().availableProcessors();
|
||||||
|
}
|
||||||
|
private class WorkerRunnable implements Runnable {
|
||||||
|
|
||||||
|
private final AtomicBoolean running = BatchExecutor.this.running;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Run until the chunk builder shuts down
|
||||||
|
while (this.running.get()) {
|
||||||
|
Runnable job = BatchExecutor.this.getNextTask(true);
|
||||||
|
|
||||||
|
if (job == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
processTask(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.jozufozu.flywheel.backend.instancing;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class ImmediateExecutor implements TaskEngine {
|
||||||
|
|
||||||
|
public static final ImmediateExecutor INSTANCE = new ImmediateExecutor();
|
||||||
|
|
||||||
|
private ImmediateExecutor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submit(@NotNull Runnable command) {
|
||||||
|
command.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncPoint() {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,15 +29,20 @@ public class InstanceWorld {
|
||||||
protected final InstanceManager<Entity> entityInstanceManager;
|
protected final InstanceManager<Entity> entityInstanceManager;
|
||||||
protected final InstanceManager<BlockEntity> tileEntityInstanceManager;
|
protected final InstanceManager<BlockEntity> tileEntityInstanceManager;
|
||||||
|
|
||||||
|
protected final BatchExecutor executor;
|
||||||
|
|
||||||
public InstanceWorld() {
|
public InstanceWorld() {
|
||||||
|
|
||||||
|
this.executor = new BatchExecutor();
|
||||||
|
this.executor.startWorkers();
|
||||||
|
|
||||||
FlwEngine engine = Backend.getInstance()
|
FlwEngine engine = Backend.getInstance()
|
||||||
.getEngine();
|
.getEngine();
|
||||||
|
|
||||||
switch (engine) {
|
switch (engine) {
|
||||||
case GL33 -> {
|
case GL33 -> {
|
||||||
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
||||||
.build();
|
.build(this.executor);
|
||||||
|
|
||||||
entityInstanceManager = new EntityInstanceManager(manager);
|
entityInstanceManager = new EntityInstanceManager(manager);
|
||||||
tileEntityInstanceManager = new TileInstanceManager(manager);
|
tileEntityInstanceManager = new TileInstanceManager(manager);
|
||||||
|
@ -47,7 +52,7 @@ public class InstanceWorld {
|
||||||
this.engine = manager;
|
this.engine = manager;
|
||||||
}
|
}
|
||||||
case BATCHING -> {
|
case BATCHING -> {
|
||||||
this.engine = new BatchingEngine();
|
this.engine = new BatchingEngine(this.executor);
|
||||||
entityInstanceManager = new EntityInstanceManager(this.engine);
|
entityInstanceManager = new EntityInstanceManager(this.engine);
|
||||||
tileEntityInstanceManager = new TileInstanceManager(this.engine);
|
tileEntityInstanceManager = new TileInstanceManager(this.engine);
|
||||||
}
|
}
|
||||||
|
@ -67,6 +72,7 @@ public class InstanceWorld {
|
||||||
* Free all acquired resources and invalidate this instance world.
|
* Free all acquired resources and invalidate this instance world.
|
||||||
*/
|
*/
|
||||||
public void delete() {
|
public void delete() {
|
||||||
|
this.executor.stopWorkers();
|
||||||
engine.delete();
|
engine.delete();
|
||||||
entityInstanceManager.detachLightListeners();
|
entityInstanceManager.detachLightListeners();
|
||||||
tileEntityInstanceManager.detachLightListeners();
|
tileEntityInstanceManager.detachLightListeners();
|
||||||
|
|
|
@ -21,7 +21,5 @@ public interface RenderDispatcher {
|
||||||
*/
|
*/
|
||||||
void beginFrame(Camera info);
|
void beginFrame(Camera info);
|
||||||
|
|
||||||
default void delete() {
|
void delete();
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.jozufozu.flywheel.backend.instancing;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface TaskEngine {
|
||||||
|
void submit(@NotNull Runnable command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for all running jobs to finish.
|
||||||
|
*/
|
||||||
|
void syncPoint();
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.instancing.batching;
|
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public class BatchExecutor implements Executor {
|
|
||||||
private final Executor internal;
|
|
||||||
private final WaitGroup wg;
|
|
||||||
|
|
||||||
public BatchExecutor(Executor internal) {
|
|
||||||
this.internal = internal;
|
|
||||||
|
|
||||||
wg = new WaitGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(@NotNull Runnable command) {
|
|
||||||
wg.add(1);
|
|
||||||
internal.execute(() -> {
|
|
||||||
// wrapper function to decrement the wait group
|
|
||||||
try {
|
|
||||||
command.run();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
} finally {
|
|
||||||
wg.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void await() throws InterruptedException {
|
|
||||||
wg.await();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,11 +2,11 @@ package com.jozufozu.flywheel.backend.instancing.batching;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.InstanceData;
|
import com.jozufozu.flywheel.api.InstanceData;
|
||||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.backend.model.DirectBufferBuilder;
|
import com.jozufozu.flywheel.backend.model.DirectBufferBuilder;
|
||||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
@ -31,7 +31,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
||||||
return (BatchedMaterial<D>) materials.computeIfAbsent(spec, BatchedMaterial::new);
|
return (BatchedMaterial<D>) materials.computeIfAbsent(spec, BatchedMaterial::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(PoseStack stack, MultiBufferSource source, Executor pool) {
|
public void render(PoseStack stack, MultiBufferSource source, TaskEngine pool) {
|
||||||
VertexConsumer buffer = source.getBuffer(state);
|
VertexConsumer buffer = source.getBuffer(state);
|
||||||
|
|
||||||
if (buffer instanceof DirectBufferBuilder direct) {
|
if (buffer instanceof DirectBufferBuilder direct) {
|
||||||
|
@ -41,7 +41,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderParallel(PoseStack stack, Executor pool, DirectBufferBuilder direct) {
|
private void renderParallel(PoseStack stack, TaskEngine pool, DirectBufferBuilder direct) {
|
||||||
int vertexCount = calculateNeededVertices();
|
int vertexCount = calculateNeededVertices();
|
||||||
DirectVertexConsumer consumer = direct.intoDirectConsumer(vertexCount);
|
DirectVertexConsumer consumer = direct.intoDirectConsumer(vertexCount);
|
||||||
FormatContext context = new FormatContext(consumer.hasOverlay());
|
FormatContext context = new FormatContext(consumer.hasOverlay());
|
||||||
|
|
|
@ -3,11 +3,10 @@ package com.jozufozu.flywheel.backend.instancing.batching;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
@ -20,19 +19,16 @@ import net.minecraft.core.Vec3i;
|
||||||
|
|
||||||
public class BatchingEngine implements Engine {
|
public class BatchingEngine implements Engine {
|
||||||
|
|
||||||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
|
||||||
|
|
||||||
protected final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
|
protected final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
|
||||||
|
protected final TaskEngine taskEngine;
|
||||||
|
|
||||||
private final BatchExecutor pool;
|
public BatchingEngine(TaskEngine taskEngine) {
|
||||||
|
|
||||||
public BatchingEngine() {
|
|
||||||
this.layers = new EnumMap<>(RenderLayer.class);
|
this.layers = new EnumMap<>(RenderLayer.class);
|
||||||
for (RenderLayer value : RenderLayer.values()) {
|
for (RenderLayer value : RenderLayer.values()) {
|
||||||
layers.put(value, new HashMap<>());
|
layers.put(value, new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
pool = new BatchExecutor(Executors.newWorkStealingPool(ForkJoinPool.getCommonPoolParallelism()));
|
this.taskEngine = taskEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,7 +38,7 @@ public class BatchingEngine implements Engine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vec3i getOriginCoordinate() {
|
public Vec3i getOriginCoordinate() {
|
||||||
return originCoordinate;
|
return BlockPos.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,22 +49,25 @@ public class BatchingEngine implements Engine {
|
||||||
|
|
||||||
stack.translate(-event.camX, -event.camY, -event.camZ);
|
stack.translate(-event.camX, -event.camY, -event.camZ);
|
||||||
|
|
||||||
|
taskEngine.syncPoint();
|
||||||
|
|
||||||
for (Map.Entry<RenderType, BatchedMaterialGroup> entry : layers.get(event.getLayer()).entrySet()) {
|
for (Map.Entry<RenderType, BatchedMaterialGroup> entry : layers.get(event.getLayer()).entrySet()) {
|
||||||
BatchedMaterialGroup group = entry.getValue();
|
BatchedMaterialGroup group = entry.getValue();
|
||||||
|
|
||||||
group.render(stack, buffers, pool);
|
group.render(stack, buffers, taskEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
taskEngine.syncPoint();
|
||||||
pool.await();
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.popPose();
|
stack.popPose();
|
||||||
|
|
||||||
event.buffers.bufferSource().endBatch();
|
event.buffers.bufferSource().endBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beginFrame(Camera info) {
|
public void beginFrame(Camera info) {
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package com.jozufozu.flywheel.backend.instancing.batching;
|
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.InstanceData;
|
import com.jozufozu.flywheel.api.InstanceData;
|
||||||
import com.jozufozu.flywheel.api.struct.BatchingTransformer;
|
import com.jozufozu.flywheel.api.struct.BatchingTransformer;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
import com.jozufozu.flywheel.core.model.Model;
|
||||||
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
||||||
|
@ -32,7 +31,7 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void submitTasks(PoseStack stack, Executor pool, DirectVertexConsumer consumer) {
|
void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
|
||||||
int instances = numInstances();
|
int instances = numInstances();
|
||||||
|
|
||||||
while (instances > 0) {
|
while (instances > 0) {
|
||||||
|
@ -44,7 +43,7 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||||
|
|
||||||
DirectVertexConsumer sub = consumer.split(verts);
|
DirectVertexConsumer sub = consumer.split(verts);
|
||||||
|
|
||||||
pool.execute(() -> drawRange(stack, sub, start, end));
|
pool.submit(() -> drawRange(stack, sub, start, end));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +81,6 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||||
anyToRemove = false;
|
anyToRemove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (context.usesOverlay()) {
|
if (context.usesOverlay()) {
|
||||||
defaultParams.overlay();
|
defaultParams.overlay();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import java.util.stream.Stream;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.ImmediateExecutor;
|
||||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||||
|
@ -33,6 +35,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||||
|
|
||||||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
protected BlockPos originCoordinate = BlockPos.ZERO;
|
||||||
|
|
||||||
|
protected final TaskEngine taskEngine;
|
||||||
protected final WorldContext<P> context;
|
protected final WorldContext<P> context;
|
||||||
protected final GroupFactory<P> groupFactory;
|
protected final GroupFactory<P> groupFactory;
|
||||||
protected final boolean ignoreOriginCoordinate;
|
protected final boolean ignoreOriginCoordinate;
|
||||||
|
@ -41,15 +44,16 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||||
|
|
||||||
private final WeakHashSet<OriginShiftListener> listeners;
|
private final WeakHashSet<OriginShiftListener> listeners;
|
||||||
|
|
||||||
public InstancingEngine(WorldContext<P> context) {
|
public InstancingEngine(WorldContext<P> context, TaskEngine taskEngine) {
|
||||||
this(context, InstancedMaterialGroup::new, false);
|
this(taskEngine, context, InstancedMaterialGroup::new, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <P extends WorldProgram> Builder<P> builder(WorldContext<P> context) {
|
public static <P extends WorldProgram> Builder<P> builder(WorldContext<P> context) {
|
||||||
return new Builder<>(context);
|
return new Builder<>(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstancingEngine(WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
public InstancingEngine(TaskEngine taskEngine, WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
||||||
|
this.taskEngine = taskEngine;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
|
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
|
||||||
|
|
||||||
|
@ -200,7 +204,11 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
public InstancingEngine<P> build() {
|
public InstancingEngine<P> build() {
|
||||||
return new InstancingEngine<>(context, groupFactory, ignoreOriginCoordinate);
|
return build(ImmediateExecutor.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InstancingEngine<P> build(TaskEngine taskEngine) {
|
||||||
|
return new InstancingEngine<>(taskEngine, context, groupFactory, ignoreOriginCoordinate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ public class ModelTransformer {
|
||||||
modelMat.multiply(params.model);
|
modelMat.multiply(params.model);
|
||||||
|
|
||||||
Matrix3f normalMat;
|
Matrix3f normalMat;
|
||||||
|
|
||||||
if (params.fullNormalTransform) {
|
if (params.fullNormalTransform) {
|
||||||
normalMat = input.last().normal().copy();
|
normalMat = input.last().normal().copy();
|
||||||
normalMat.mul(params.normal);
|
normalMat.mul(params.normal);
|
||||||
|
|
Loading…
Reference in a new issue