From 95bd36b90d59b444ddd458654c8fdd57f975e746 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Tue, 28 Mar 2023 10:58:22 -0700 Subject: [PATCH] TaskEngine and batching changes - Rename TaskEngine to TaskExecutor - Make TaskExecutor extend Executor - Simplify ParallelTaskExecutor - Move WorkGroup code to separate class - Fix CPUInstancers being updated too late - Do not unnecessarily clear memory when preparing DrawBuffer - Simplify BatchingDrawTracker and DrawBufferSet by storing RenderType in DrawBuffer - Move all additional Mojang matrix operations to MatrixUtil and expose fields using accessors - Remove Color - Remove WeakHashSet --- .../jozufozu/flywheel/backend/Backend.java | 8 +- .../backend/instancing/InstanceManager.java | 16 +- .../backend/instancing/InstanceWorld.java | 24 +- .../instancing/ParallelTaskEngine.java | 283 ---------------- .../instancing/ParallelTaskExecutor.java | 212 ++++++++++++ .../backend/instancing/RenderDispatcher.java | 4 +- .../backend/instancing/SerialTaskEngine.java | 26 -- .../instancing/SerialTaskExecutor.java | 23 ++ .../backend/instancing/TaskEngine.java | 14 - .../backend/instancing/TaskExecutor.java | 12 + .../backend/instancing/WorkGroup.java | 72 ++++ .../batching/BatchingDrawTracker.java | 83 ++--- .../instancing/batching/BatchingEngine.java | 17 +- .../batching/BatchingTransformManager.java | 2 +- .../instancing/batching/CPUInstancer.java | 2 +- .../instancing/batching/DrawBuffer.java | 11 +- .../instancing/batching/DrawBufferSet.java | 47 +-- .../instancing/batching/TransformCall.java | 14 +- .../instancing/batching/WaitGroup.java | 34 -- .../instancing/indirect/IndirectEngine.java | 11 +- .../instancing/InstancingDrawManager.java | 2 +- .../instancing/InstancingEngine.java | 11 +- .../jozufozu/flywheel/core/RenderContext.java | 4 +- .../jozufozu/flywheel/core/model/Mesh.java | 2 +- .../flywheel/core/structs/ColoredLitPart.java | 10 - .../transformed/TransformedWriter.java | 6 +- .../flywheel/core/uniform/ViewProvider.java | 4 +- .../flywheel/extension/Matrix3fExtension.java | 16 - .../flywheel/extension/Matrix4fExtension.java | 16 - .../flywheel/extension/MatrixWrite.java | 32 -- .../jozufozu/flywheel/light/LightUpdater.java | 15 +- .../light/WeakContainmentMultiMap.java | 10 +- .../flywheel/mixin/RenderTypeMixin.java | 2 +- .../mixin/matrix/Matrix3fAccessor.java | 36 ++ .../flywheel/mixin/matrix/Matrix3fMixin.java | 55 ---- .../mixin/matrix/Matrix4fAccessor.java | 57 ++++ .../flywheel/mixin/matrix/Matrix4fMixin.java | 80 ----- .../com/jozufozu/flywheel/util/Color.java | 309 ------------------ .../com/jozufozu/flywheel/util/FlwUtil.java | 7 + .../jozufozu/flywheel/util/MatrixUtil.java | 116 +++++++ .../jozufozu/flywheel/util/WeakHashSet.java | 122 ------- src/main/resources/flywheel.mixins.json | 4 +- 42 files changed, 665 insertions(+), 1166 deletions(-) delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskEngine.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskExecutor.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskEngine.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskExecutor.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/TaskEngine.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/TaskExecutor.java create mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/WorkGroup.java delete mode 100644 src/main/java/com/jozufozu/flywheel/backend/instancing/batching/WaitGroup.java delete mode 100644 src/main/java/com/jozufozu/flywheel/extension/Matrix3fExtension.java delete mode 100644 src/main/java/com/jozufozu/flywheel/extension/Matrix4fExtension.java delete mode 100644 src/main/java/com/jozufozu/flywheel/extension/MatrixWrite.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fAccessor.java delete mode 100644 src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fMixin.java create mode 100644 src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fAccessor.java delete mode 100644 src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fMixin.java delete mode 100644 src/main/java/com/jozufozu/flywheel/util/Color.java create mode 100644 src/main/java/com/jozufozu/flywheel/util/MatrixUtil.java delete mode 100644 src/main/java/com/jozufozu/flywheel/util/WeakHashSet.java diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 9aa80daa9..4f0a523ed 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import com.jozufozu.flywheel.api.FlywheelLevel; -import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine; +import com.jozufozu.flywheel.backend.instancing.ParallelTaskExecutor; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.BackendTypes; import com.mojang.logging.LogUtils; @@ -20,7 +20,7 @@ public class Backend { private static BackendType TYPE; - private static ParallelTaskEngine EXECUTOR; + private static ParallelTaskExecutor EXECUTOR; private static final Loader LOADER = new Loader(); @@ -35,9 +35,9 @@ public class Backend { * Get a thread pool for running Flywheel related work in parallel. * @return A global Flywheel thread pool. */ - public static ParallelTaskEngine getTaskEngine() { + public static ParallelTaskExecutor getTaskExecutor() { if (EXECUTOR == null) { - EXECUTOR = new ParallelTaskEngine("Flywheel"); + EXECUTOR = new ParallelTaskExecutor("Flywheel"); EXECUTOR.startWorkers(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 319fb9607..d8e88904a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -74,7 +74,7 @@ public abstract class InstanceManager { * Queued updates are processed. *

*/ - public void tick(TaskEngine taskEngine, double cameraX, double cameraY, double cameraZ) { + public void tick(TaskExecutor executor, double cameraX, double cameraY, double cameraZ) { tick.tick(); processQueuedUpdates(); @@ -84,7 +84,7 @@ public abstract class InstanceManager { int cZ = (int) cameraZ; var instances = getStorage().getInstancesForTicking(); - distributeWork(taskEngine, instances, instance -> tickInstance(instance, cX, cY, cZ)); + distributeWork(executor, instances, instance -> tickInstance(instance, cX, cY, cZ)); } protected void tickInstance(TickableInstance instance, int cX, int cY, int cZ) { @@ -106,7 +106,7 @@ public abstract class InstanceManager { instance.tick(); } - public void beginFrame(TaskEngine taskEngine, RenderContext context) { + public void beginFrame(TaskExecutor executor, RenderContext context) { frame.tick(); processQueuedAdditions(); @@ -118,22 +118,22 @@ public abstract class InstanceManager { FrustumIntersection culler = context.culler(); var instances = getStorage().getInstancesForUpdate(); - distributeWork(taskEngine, instances, instance -> updateInstance(instance, culler, cX, cY, cZ)); + distributeWork(executor, instances, instance -> updateInstance(instance, culler, cX, cY, cZ)); } - private static void distributeWork(TaskEngine taskEngine, List instances, Consumer action) { + private static void distributeWork(TaskExecutor executor, List instances, Consumer action) { final int size = instances.size(); - final int threadCount = taskEngine.getThreadCount(); + final int threadCount = executor.getThreadCount(); if (threadCount == 1) { - taskEngine.submit(() -> instances.forEach(action)); + executor.execute(() -> instances.forEach(action)); } else { final int stride = Math.max(size / (threadCount * 2), 1); for (int start = 0; start < size; start += stride) { int end = Math.min(start + stride, size); var sub = instances.subList(start, end); - taskEngine.submit(() -> sub.forEach(action)); + executor.execute(() -> sub.forEach(action)); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 621a5153e..c0b375c71 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -29,7 +29,7 @@ public class InstanceWorld implements AutoCloseable { protected final InstanceManager entities; protected final InstanceManager blockEntities; - public final ParallelTaskEngine taskEngine; + public final ParallelTaskExecutor taskExecutor; private final InstanceManager effects; public static InstanceWorld create(LevelAccessor level) { @@ -51,7 +51,7 @@ public class InstanceWorld implements AutoCloseable { this.entities = entities; this.blockEntities = blockEntities; this.effects = effects; - this.taskEngine = Backend.getTaskEngine(); + this.taskExecutor = Backend.getTaskExecutor(); } public InstanceManager getEntities() { @@ -87,15 +87,15 @@ public class InstanceWorld implements AutoCloseable { RenderContext context = event.getContext(); boolean shifted = engine.maintainOriginCoordinate(context.camera()); - taskEngine.syncPoint(); + taskExecutor.syncPoint(); if (!shifted) { - blockEntities.beginFrame(taskEngine, context); - entities.beginFrame(taskEngine, context); - effects.beginFrame(taskEngine, context); + blockEntities.beginFrame(taskExecutor, context); + entities.beginFrame(taskExecutor, context); + effects.beginFrame(taskExecutor, context); } - engine.beginFrame(taskEngine, context); + engine.beginFrame(taskExecutor, context); } /** @@ -117,17 +117,17 @@ public class InstanceWorld implements AutoCloseable { double y = renderViewEntity.getY(); double z = renderViewEntity.getZ(); - blockEntities.tick(taskEngine, x, y, z); - entities.tick(taskEngine, x, y, z); - effects.tick(taskEngine, x, y, z); + blockEntities.tick(taskExecutor, x, y, z); + entities.tick(taskExecutor, x, y, z); + effects.tick(taskExecutor, x, y, z); } /** * Draw all instances for the given stage. */ public void renderStage(RenderContext context, RenderStage stage) { - taskEngine.syncPoint(); - engine.renderStage(taskEngine, context, stage); + taskExecutor.syncPoint(); + engine.renderStage(taskExecutor, context, stage); } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskEngine.java deleted file mode 100644 index f929e6336..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskEngine.java +++ /dev/null @@ -1,283 +0,0 @@ -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 java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.Stream; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jozufozu.flywheel.Flywheel; -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 ParallelTaskEngine implements TaskEngine { - private static final Logger LOGGER = LoggerFactory.getLogger("BatchExecutor"); - - private final String name; - - /** - * If set to false, the engine will shut down. - */ - private final AtomicBoolean running = new AtomicBoolean(false); - private final WaitGroup wg = new WaitGroup(); - - private final Deque syncTasks = new ConcurrentLinkedDeque<>(); - private final Deque jobQueue = new ConcurrentLinkedDeque<>(); - private final List threads = new ArrayList<>(); - - private final Object jobNotifier = new Object(); - - private final int threadCount; - - public ParallelTaskEngine(String name) { - this.name = name; - threadCount = getOptimalThreadCount(); - } - - @Override - public int getThreadCount() { - return threadCount; - } - - public WorkGroupBuilder group(String name) { - return new WorkGroupBuilder(name); - } - - /** - * 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(), name + " " + 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 = this.jobQueue.pollLast()) != null) { - processTask(job); - } - - // and wait for any stragglers. - try { - this.wg.await(); - } catch (InterruptedException ignored) { - } - - while ((job = this.syncTasks.pollLast()) != null) { - job.run(); - } - } - - @Nullable - private Runnable getNextTask() { - Runnable job = this.jobQueue.pollFirst(); - - if (job == null) { - synchronized (ParallelTaskEngine.this.jobNotifier) { - try { - ParallelTaskEngine.this.jobNotifier.wait(); - } catch (InterruptedException ignored) { - } - } - } - - return job; - } - - // TODO: job context - private void processTask(Runnable job) { - try { - job.run(); - } catch (Exception e) { - Flywheel.LOGGER.error("Error running job", e); - } finally { - ParallelTaskEngine.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 = ParallelTaskEngine.this.running; - - @Override - public void run() { - // Run until the chunk builder shuts down - while (this.running.get()) { - Runnable job = ParallelTaskEngine.this.getNextTask(); - - if (job == null) { - continue; - } - - ParallelTaskEngine.this.processTask(job); - } - } - - } - - public class WorkGroupBuilder { - final String name; - - @Nullable - Runnable finalizer; - - Stream tasks; - - public WorkGroupBuilder(String name) { - this.name = name; - } - - public WorkGroupBuilder addTasks(Stream iterable, Consumer consumer) { - return addTasks(iterable.map(it -> () -> consumer.accept(it))); - } - - public WorkGroupBuilder addTasks(Stream tasks) { - if (this.tasks == null) { - this.tasks = tasks; - } else { - this.tasks = Stream.concat(this.tasks, tasks); - } - return this; - } - - public WorkGroupBuilder onComplete(Runnable runnable) { - this.finalizer = runnable; - return this; - } - - public void submit() { - if (this.tasks == null) { - return; - } - - WorkGroup workGroup = new WorkGroup(name, finalizer); - - tasks.map(task -> new WorkGroupTask(workGroup, task)).forEach(ParallelTaskEngine.this::submit); - } - - } - - private static class WorkGroupTask implements Runnable { - - private final WorkGroup parent; - private final Runnable wrapped; - - public WorkGroupTask(WorkGroup parent, Runnable wrapped) { - this.parent = parent; - this.wrapped = wrapped; - - this.parent.running.incrementAndGet(); - } - - @Override - public void run() { - this.wrapped.run(); - - this.parent.oneDown(); - } - } - - private class WorkGroup { - final String name; - - final Runnable finalizer; - - final AtomicInteger running = new AtomicInteger(0); - - public WorkGroup(String name, @Nullable Runnable finalizer) { - this.name = name; - this.finalizer = finalizer; - } - - public void oneDown() { - if (finalizer != null) { - if (running.decrementAndGet() == 0) { - ParallelTaskEngine.this.syncTasks.add(finalizer); - } - } - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskExecutor.java new file mode 100644 index 000000000..95c231000 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/ParallelTaskExecutor.java @@ -0,0 +1,212 @@ +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.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + +import com.jozufozu.flywheel.Flywheel; +import com.mojang.logging.LogUtils; + +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 +// https://stackoverflow.com/questions/29655531 +public class ParallelTaskExecutor implements TaskExecutor { + private static final Logger LOGGER = LogUtils.getLogger(); + + private final String name; + private final int threadCount; + + /** + * If set to false, the executor will shut down. + */ + private final AtomicBoolean running = new AtomicBoolean(false); + /** + * Synchronized via {@link #tasksCompletedNotifier}. + */ + private int incompleteTaskCounter = 0; + + private final List threads = new ArrayList<>(); + private final Deque taskQueue = new ConcurrentLinkedDeque<>(); + + private final Object taskNotifier = new Object(); + private final Object tasksCompletedNotifier = new Object(); + + public ParallelTaskExecutor(String name) { + this.name = name; + threadCount = getOptimalThreadCount(); + } + + @Override + public int getThreadCount() { + return threadCount; + } + + /** + * Spawns a number of work-stealing threads to process results in the task queue. If the executor is already + * running, this method does nothing and exits. + */ + public void startWorkers() { + if (running.getAndSet(true)) { + return; + } + + if (!threads.isEmpty()) { + throw new IllegalStateException("Threads are still alive while in the STOPPED state"); + } + + for (int i = 0; i < threadCount; i++) { + WorkerThread thread = new WorkerThread(name + " Task Executor #" + i); + thread.setPriority(Mth.clamp(Thread.NORM_PRIORITY - 2, Thread.MIN_PRIORITY, Thread.MAX_PRIORITY)); + thread.start(); + + threads.add(thread); + } + + LOGGER.info("Started {} worker threads", threads.size()); + } + + public void stopWorkers() { + if (!running.getAndSet(false)) { + return; + } + + if (threads.isEmpty()) { + throw new IllegalStateException("No threads are alive but the executor is in the RUNNING state"); + } + + LOGGER.info("Stopping worker threads"); + + // Notify all worker threads to wake up, where they will then terminate + synchronized (taskNotifier) { + taskNotifier.notifyAll(); + } + + // Wait for every remaining thread to terminate + for (Thread thread : threads) { + try { + thread.join(); + } catch (InterruptedException e) { + // + } + } + + threads.clear(); + taskQueue.clear(); + synchronized (tasksCompletedNotifier) { + incompleteTaskCounter = 0; + tasksCompletedNotifier.notifyAll(); + } + } + + @Override + public void execute(Runnable task) { + if (!running.get()) { + throw new IllegalStateException("Executor is stopped"); + } + + taskQueue.add(task); + + synchronized (tasksCompletedNotifier) { + incompleteTaskCounter++; + } + + synchronized (taskNotifier) { + taskNotifier.notify(); + } + } + + /** + * Wait for all running tasks to finish. + */ + @Override + public void syncPoint() { + Runnable task; + + // Finish everyone else's work... + while ((task = taskQueue.pollLast()) != null) { + processTask(task); + } + + // and wait for any stragglers. + synchronized (tasksCompletedNotifier) { + while (incompleteTaskCounter > 0) { + try { + tasksCompletedNotifier.wait(); + } catch (InterruptedException e) { + // + } + } + } + } + + @Nullable + private Runnable getNextTask() { + Runnable task = taskQueue.pollFirst(); + + if (task == null) { + synchronized (taskNotifier) { + try { + taskNotifier.wait(); + } catch (InterruptedException e) { + // + } + } + } + + return task; + } + + // TODO: task context + private void processTask(Runnable task) { + try { + task.run(); + } catch (Exception e) { + Flywheel.LOGGER.error("Error running task", e); + } finally { + synchronized (tasksCompletedNotifier) { + if (--incompleteTaskCounter == 0) { + tasksCompletedNotifier.notifyAll(); + } + } + } + } + + /** + * Returns the "optimal" number of threads to be used for 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 WorkerThread extends Thread { + private final AtomicBoolean running = ParallelTaskExecutor.this.running; + + public WorkerThread(String name) { + super(name); + } + + @Override + public void run() { + // Run until the executor shuts down + while (running.get()) { + Runnable task = getNextTask(); + + if (task == null) { + continue; + } + + processTask(task); + } + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java index d48d79670..610c9dc4d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/RenderDispatcher.java @@ -7,9 +7,9 @@ import net.minecraft.client.Camera; public interface RenderDispatcher { - void beginFrame(TaskEngine taskEngine, RenderContext context); + void beginFrame(TaskExecutor executor, RenderContext context); - void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage); + void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage); /** * Maintain the integer origin coordinate to be within a certain distance from the camera in all directions, diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskEngine.java deleted file mode 100644 index 1a6c8a9b6..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskEngine.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing; - -import org.jetbrains.annotations.NotNull; - -public class SerialTaskEngine implements TaskEngine { - - public static final SerialTaskEngine INSTANCE = new SerialTaskEngine(); - - private SerialTaskEngine() { - } - - @Override - public void submit(@NotNull Runnable command) { - command.run(); - } - - @Override - public void syncPoint() { - // noop - } - - @Override - public int getThreadCount() { - return 1; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskExecutor.java new file mode 100644 index 000000000..7a97d74ea --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/SerialTaskExecutor.java @@ -0,0 +1,23 @@ +package com.jozufozu.flywheel.backend.instancing; + +public class SerialTaskExecutor implements TaskExecutor { + public static final SerialTaskExecutor INSTANCE = new SerialTaskExecutor(); + + private SerialTaskExecutor() { + } + + @Override + public void execute(Runnable task) { + task.run(); + } + + @Override + public void syncPoint() { + // noop + } + + @Override + public int getThreadCount() { + return 1; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/TaskEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/TaskEngine.java deleted file mode 100644 index a38f5a5c2..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/TaskEngine.java +++ /dev/null @@ -1,14 +0,0 @@ -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(); - - int getThreadCount(); -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/TaskExecutor.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/TaskExecutor.java new file mode 100644 index 000000000..c341dab83 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/TaskExecutor.java @@ -0,0 +1,12 @@ +package com.jozufozu.flywheel.backend.instancing; + +import java.util.concurrent.Executor; + +public interface TaskExecutor extends Executor { + /** + * Wait for all running tasks to finish. + */ + void syncPoint(); + + int getThreadCount(); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/WorkGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/WorkGroup.java new file mode 100644 index 000000000..3ea1692c8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/WorkGroup.java @@ -0,0 +1,72 @@ +package com.jozufozu.flywheel.backend.instancing; + +import java.util.Iterator; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import org.jetbrains.annotations.Nullable; + +public class WorkGroup { + public static void run(Iterator tasks, Executor executor) { + tasks.forEachRemaining(executor::execute); + } + + public static void run(Iterator tasks, @Nullable Runnable finalizer, Executor executor) { + if (finalizer == null) { + run(tasks, executor); + return; + } + + AtomicInteger incompleteTaskCounter = new AtomicInteger(0); + tasks.forEachRemaining(task -> { + incompleteTaskCounter.incrementAndGet(); + executor.execute(() -> { + task.run(); + if (incompleteTaskCounter.decrementAndGet() == 0) { + executor.execute(finalizer); + } + }); + }); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + @Nullable + private Runnable finalizer; + private Stream tasks; + + public Builder() { + } + + public Builder addTasks(Stream iterable, Consumer consumer) { + return addTasks(iterable.map(it -> () -> consumer.accept(it))); + } + + public Builder addTasks(Stream tasks) { + if (this.tasks == null) { + this.tasks = tasks; + } else { + this.tasks = Stream.concat(this.tasks, tasks); + } + return this; + } + + public Builder onComplete(Runnable runnable) { + this.finalizer = runnable; + return this; + } + + public void execute(Executor executor) { + if (tasks == null) { + return; + } + + run(tasks.iterator(), finalizer, executor); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingDrawTracker.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingDrawTracker.java index a36dfc59a..329876a08 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingDrawTracker.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingDrawTracker.java @@ -1,7 +1,8 @@ package com.jozufozu.flywheel.backend.instancing.batching; +import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; +import java.util.Map; import java.util.Set; import com.jozufozu.flywheel.api.RenderStage; @@ -12,7 +13,15 @@ import com.mojang.blaze3d.vertex.BufferBuilder; import net.minecraft.client.renderer.RenderType; public class BatchingDrawTracker { - private final Set activeTypes = new HashSet<>(); + private static final RenderStage[] RENDER_STAGES = RenderStage.values(); + + private final Map> activeBuffers = new EnumMap<>(RenderStage.class); + { + for (RenderStage stage : RENDER_STAGES) { + activeBuffers.put(stage, new HashSet<>()); + } + } + private final BufferBuilder scratch; public BatchingDrawTracker() { @@ -22,22 +31,9 @@ public class BatchingDrawTracker { } public DrawBuffer getBuffer(RenderType renderType, RenderStage stage) { - return getBufferSet(renderType).getBuffer(stage); - } - - public DrawBufferSet getBufferSet(RenderType renderType) { - activeTypes.add(renderType); - return RenderTypeExtension.getDrawBufferSet(renderType); - } - - /** - * Draw and reset all DrawBuffers for the given RenderType. - * @param renderType The RenderType to draw. - */ - public void draw(RenderType renderType) { - _draw(renderType); - - activeTypes.remove(renderType); + DrawBuffer buffer = RenderTypeExtension.getDrawBufferSet(renderType).getBuffer(stage); + activeBuffers.get(stage).add(buffer); + return buffer; } /** @@ -45,59 +41,44 @@ public class BatchingDrawTracker { * @param stage The RenderStage to draw. */ public void draw(RenderStage stage) { - Iterator iterator = activeTypes.iterator(); - while (iterator.hasNext()) { - RenderType renderType = iterator.next(); - DrawBufferSet bufferSet = RenderTypeExtension.getDrawBufferSet(renderType); - DrawBuffer buffer = bufferSet.deactivateBuffer(stage); - if (buffer == null) { - continue; - } - if (bufferSet.getActiveStagesView().isEmpty()) { - iterator.remove(); - } - _draw(buffer, renderType); + Set buffers = activeBuffers.get(stage); + for (DrawBuffer buffer : buffers) { + _draw(buffer); + buffer.reset(); } + buffers.clear(); } /** * Draw and reset all active DrawBuffers. */ public void drawAll() { - for (RenderType renderType : activeTypes) { - _draw(renderType); - } - - activeTypes.clear(); - } - - private void _draw(RenderType renderType) { - DrawBufferSet bufferSet = RenderTypeExtension.getDrawBufferSet(renderType); - for (RenderStage stage : bufferSet.getActiveStagesView()) { - DrawBuffer buffer = bufferSet.deactivateBuffer(stage); - _draw(buffer, renderType); + for (Set buffers : activeBuffers.values()) { + for (DrawBuffer buffer : buffers) { + _draw(buffer); + buffer.reset(); + } + buffers.clear(); } } - private void _draw(DrawBuffer buffer, RenderType renderType) { + private void _draw(DrawBuffer buffer) { if (buffer.hasVertices()) { BufferBuilderExtension scratch = (BufferBuilderExtension) this.scratch; buffer.inject(scratch); - renderType.end(this.scratch, 0, 0, 0); + buffer.getRenderType().end(this.scratch, 0, 0, 0); } - - buffer.reset(); } /** * Reset all active DrawBuffers. */ public void reset() { - for (RenderType type : activeTypes) { - RenderTypeExtension.getDrawBufferSet(type) - .reset(); + for (Set buffers : activeBuffers.values()) { + for (DrawBuffer buffer : buffers) { + buffer.reset(); + } + buffers.clear(); } - - activeTypes.clear(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java index 84f1408be..88c47df7c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; -import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.instancing.TaskExecutor; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.util.FlwUtil; @@ -30,19 +30,19 @@ public class BatchingEngine implements Engine { } @Override - public void beginFrame(TaskEngine taskEngine, RenderContext context) { + public void beginFrame(TaskExecutor executor, RenderContext context) { transformManager.flush(); Vec3 cameraPos = context.camera().getPosition(); var stack = FlwUtil.copyPoseStack(context.stack()); stack.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z); - // TODO: async task engine barriers - taskEngine.syncPoint(); - submitTasks(taskEngine, stack.last(), context.level()); + // TODO: async task executor barriers + executor.syncPoint(); + submitTasks(executor, stack.last(), context.level()); } - public void submitTasks(TaskEngine taskEngine, PoseStack.Pose matrices, ClientLevel level) { + public void submitTasks(TaskExecutor executor, PoseStack.Pose matrices, ClientLevel level) { for (var transformSetEntry : transformManager.getTransformSetsView().entrySet()) { var stage = transformSetEntry.getKey(); var transformSet = transformSetEntry.getValue(); @@ -53,6 +53,7 @@ public class BatchingEngine implements Engine { int vertices = 0; for (var transformCall : transformCalls) { + transformCall.setup(); vertices += transformCall.getTotalVertexCount(); } @@ -65,7 +66,7 @@ public class BatchingEngine implements Engine { int startVertex = 0; for (var transformCall : transformCalls) { - transformCall.submitTasks(taskEngine, buffer, startVertex, matrices, level); + transformCall.submitTasks(executor, buffer, startVertex, matrices, level); startVertex += transformCall.getTotalVertexCount(); } } @@ -73,7 +74,7 @@ public class BatchingEngine implements Engine { } @Override - public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) { + public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) { drawTracker.draw(stage); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingTransformManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingTransformManager.java index 4540c2018..e93032f79 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingTransformManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingTransformManager.java @@ -99,7 +99,7 @@ public class BatchingTransformManager { public static class TransformSet implements Iterable>>> { public static final TransformSet EMPTY = new TransformSet(ImmutableListMultimap.of()); - final ListMultimap> transformCalls; + private final ListMultimap> transformCalls; public TransformSet(RenderStage renderStage) { transformCalls = ArrayListMultimap.create(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java index 1b4c764c3..e65deb393 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java @@ -10,7 +10,7 @@ public class CPUInstancer extends AbstractInstancer super(type); } - void setup() { + void update() { if (anyToRemove) { data.removeIf(InstancedPart::isRemoved); anyToRemove = false; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java index 4a5cc0621..914982d06 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBuffer.java @@ -11,6 +11,8 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.extension.BufferBuilderExtension; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.RenderType; + /** * A byte buffer that can be used to draw vertices through multiple {@link ReusableVertexList}s. * @@ -19,6 +21,7 @@ import com.mojang.blaze3d.vertex.VertexFormat; public class DrawBuffer { private static final List ALL = new ArrayList<>(); + private final RenderType renderType; private final VertexFormat format; private final int stride; private final VertexListProvider provider; @@ -29,7 +32,8 @@ public class DrawBuffer { private boolean prepared; private int vertexCount; - DrawBuffer(VertexFormat format, int stride, VertexListProvider provider) { + DrawBuffer(RenderType renderType, VertexFormat format, int stride, VertexListProvider provider) { + this.renderType = renderType; this.format = format; this.stride = stride; this.provider = provider; @@ -62,7 +66,6 @@ public class DrawBuffer { buffer = memory.asBuffer(); } - memory.clear(); prepared = true; } @@ -90,6 +93,10 @@ public class DrawBuffer { bufferBuilder.flywheel$injectForRender(buffer, format, vertexCount); } + public RenderType getRenderType() { + return renderType; + } + public VertexFormat getVertexFormat() { return format; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBufferSet.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBufferSet.java index 15b66b33d..56ccd328a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBufferSet.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/DrawBufferSet.java @@ -1,66 +1,33 @@ package com.jozufozu.flywheel.backend.instancing.batching; -import java.util.Collections; import java.util.EnumMap; -import java.util.EnumSet; import java.util.Map; -import java.util.Set; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.api.RenderStage; import com.jozufozu.flywheel.api.vertex.VertexListProvider; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.RenderType; + public class DrawBufferSet { + private final RenderType renderType; private final VertexFormat format; private final int stride; private final VertexListProvider provider; private final Map buffers = new EnumMap<>(RenderStage.class); - private final Set activeStages = EnumSet.noneOf(RenderStage.class); - private final Set activeStagesView = Collections.unmodifiableSet(activeStages); @ApiStatus.Internal - public DrawBufferSet(VertexFormat format) { - this.format = format; + public DrawBufferSet(RenderType renderType) { + this.renderType = renderType; + format = renderType.format(); stride = format.getVertexSize(); provider = VertexListProvider.get(format); } - public Set getActiveStagesView() { - return activeStagesView; - } - public DrawBuffer getBuffer(RenderStage stage) { - activeStages.add(stage); - return buffers.computeIfAbsent(stage, $ -> createBuffer()); - } - - @Nullable - public DrawBuffer deactivateBuffer(RenderStage stage) { - if (activeStages.remove(stage)) { - return buffers.get(stage); - } - return null; - } - - public void reset(RenderStage stage) { - if (activeStages.remove(stage)) { - buffers.get(stage).reset(); - } - } - - public void reset() { - for (RenderStage stage : activeStages) { - buffers.get(stage).reset(); - } - - activeStages.clear(); - } - - private DrawBuffer createBuffer() { - return new DrawBuffer(format, stride, provider); + return buffers.computeIfAbsent(stage, $ -> new DrawBuffer(renderType, format, stride, provider)); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformCall.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformCall.java index 2c0827707..b2cf9c3e3 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformCall.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/TransformCall.java @@ -7,7 +7,7 @@ import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.api.vertex.ReusableVertexList; -import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.instancing.TaskExecutor; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; @@ -37,9 +37,11 @@ public class TransformCall { return meshVertexCount * instancer.getInstanceCount(); } - void submitTasks(TaskEngine pool, DrawBuffer buffer, int startVertex, PoseStack.Pose matrices, ClientLevel level) { - instancer.setup(); + void setup() { + instancer.update(); + } + void submitTasks(TaskExecutor executor, DrawBuffer buffer, int startVertex, PoseStack.Pose matrices, ClientLevel level) { int instances = instancer.getInstanceCount(); while (instances > 0) { @@ -51,7 +53,7 @@ public class TransformCall { ReusableVertexList sub = buffer.slice(startVertex, vertexCount); startVertex += vertexCount; - pool.submit(() -> transformRange(sub, start, end, matrices, level)); + executor.execute(() -> transformRange(sub, start, end, matrices, level)); } } @@ -82,10 +84,10 @@ public class TransformCall { vertexList.ptr(anchorPtr); vertexList.vertexCount(totalVertexCount); material.getVertexTransformer().transform(vertexList, level); - applyPoseStack(vertexList, matrices); + applyMatrices(vertexList, matrices); } - private static void applyPoseStack(MutableVertexList vertexList, PoseStack.Pose matrices) { + private static void applyMatrices(MutableVertexList vertexList, PoseStack.Pose matrices) { Vector4f pos = new Vector4f(); Vector3f normal = new Vector3f(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/WaitGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/WaitGroup.java deleted file mode 100644 index a27f8cbdc..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/WaitGroup.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jozufozu.flywheel.backend.instancing.batching; - -import java.util.concurrent.atomic.AtomicInteger; - -// https://stackoverflow.com/questions/29655531 -public class WaitGroup { - - private final AtomicInteger counter = new AtomicInteger(0); - - public synchronized void add(int i) { - if (i == 0) { - return; - } - - if (i == 1) { - this.counter.incrementAndGet(); - } else { - this.counter.addAndGet(i); - } - } - - public synchronized void done() { - if (this.counter.decrementAndGet() == 0) { - this.notifyAll(); - } - } - - public synchronized void await() throws InterruptedException { - while (this.counter.get() > 0) { - this.wait(); - } - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java index 9c607c579..bca93b860 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectEngine.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.indirect; import java.util.Collections; import java.util.List; +import java.util.Set; import org.lwjgl.opengl.GL32; @@ -14,10 +15,10 @@ import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; -import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.instancing.TaskExecutor; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.model.Model; -import com.jozufozu.flywheel.util.WeakHashSet; +import com.jozufozu.flywheel.util.FlwUtil; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Camera; @@ -34,7 +35,7 @@ public class IndirectEngine implements Engine { /** * The set of instance managers that are attached to this engine. */ - private final WeakHashSet> instanceManagers = new WeakHashSet<>(); + private final Set> instanceManagers = FlwUtil.createWeakHashSet(); protected final ContextShader context; protected final int sqrMaxOriginDistance; @@ -52,14 +53,14 @@ public class IndirectEngine implements Engine { } @Override - public void beginFrame(TaskEngine taskEngine, RenderContext context) { + public void beginFrame(TaskExecutor executor, RenderContext context) { try (var restoreState = GlStateTracker.getRestoreState()) { drawManager.flush(); } } @Override - public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) { + public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) { try (var restoreState = GlStateTracker.getRestoreState()) { setup(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingDrawManager.java index c6fcf0310..06fdfa886 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingDrawManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingDrawManager.java @@ -99,7 +99,7 @@ public class InstancingDrawManager { public static final DrawSet EMPTY = new DrawSet(ImmutableListMultimap.of()); - final ListMultimap drawCalls; + private final ListMultimap drawCalls; public DrawSet(RenderStage renderStage) { drawCalls = ArrayListMultimap.create(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 99734c157..7eb5c16b6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.instancing; import java.util.Collections; import java.util.List; +import java.util.Set; import org.lwjgl.opengl.GL32; @@ -15,12 +16,12 @@ import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; -import com.jozufozu.flywheel.backend.instancing.TaskEngine; +import com.jozufozu.flywheel.backend.instancing.TaskExecutor; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.core.uniform.UniformBuffer; -import com.jozufozu.flywheel.util.WeakHashSet; +import com.jozufozu.flywheel.util.FlwUtil; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Camera; @@ -37,7 +38,7 @@ public class InstancingEngine implements Engine { /** * The set of instance managers that are attached to this engine. */ - private final WeakHashSet> instanceManagers = new WeakHashSet<>(); + private final Set> instanceManagers = FlwUtil.createWeakHashSet(); protected final ContextShader context; protected final int sqrMaxOriginDistance; @@ -55,14 +56,14 @@ public class InstancingEngine implements Engine { } @Override - public void beginFrame(TaskEngine taskEngine, RenderContext context) { + public void beginFrame(TaskExecutor executor, RenderContext context) { try (var restoreState = GlStateTracker.getRestoreState()) { drawManager.flush(); } } @Override - public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) { + public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) { var drawSet = drawManager.get(stage); if (drawSet.isEmpty()) { diff --git a/src/main/java/com/jozufozu/flywheel/core/RenderContext.java b/src/main/java/com/jozufozu/flywheel/core/RenderContext.java index 4664a052a..f6c99b41a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/RenderContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/RenderContext.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.core; import org.jetbrains.annotations.NotNull; -import com.jozufozu.flywheel.extension.Matrix4fExtension; +import com.jozufozu.flywheel.util.MatrixUtil; import com.jozufozu.flywheel.util.joml.FrustumIntersection; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Matrix4f; @@ -23,7 +23,7 @@ public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack } public static FrustumIntersection createCuller(Matrix4f viewProjection, float camX, float camY, float camZ) { - com.jozufozu.flywheel.util.joml.Matrix4f proj = Matrix4fExtension.clone(viewProjection); + com.jozufozu.flywheel.util.joml.Matrix4f proj = MatrixUtil.toJoml(viewProjection); proj.translate(camX, camY, camZ); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java index 12ee9e9cf..bfa7adb55 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java @@ -42,7 +42,7 @@ public interface Mesh { /** * Write this mesh into a vertex list. Vertices with index {@literal <}0 or {@literal >=}{@link #getVertexCount()} will not be - * modified. + * read or modified. * @param vertexList The vertex list to which data is written to. */ void write(MutableVertexList vertexList); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java index ca75d2f40..050b27d49 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java @@ -2,7 +2,6 @@ package com.jozufozu.flywheel.core.structs; import com.jozufozu.flywheel.api.instancer.InstancedPart; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.util.Color; import net.minecraft.client.renderer.LightTexture; @@ -39,15 +38,6 @@ public abstract class ColoredLitPart extends InstancedPart implements FlatLit { public static final TransformedWriter INSTANCE = new TransformedWriter(); @@ -9,8 +9,8 @@ public class TransformedWriter extends ColoredLitWriter { @Override public void write(final long ptr, final TransformedPart d) { super.write(ptr, d); - MatrixWrite.writeUnsafe(d.model, ptr + 8); - MatrixWrite.writeUnsafe(d.normal, ptr + 72); + MatrixUtil.writeUnsafe(d.model, ptr + 8); + MatrixUtil.writeUnsafe(d.normal, ptr + 72); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java index 89175710e..fb10e3fc3 100644 --- a/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/uniform/ViewProvider.java @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.event.BeginFrameEvent; -import com.jozufozu.flywheel.extension.MatrixWrite; +import com.jozufozu.flywheel.util.MatrixUtil; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.Vec3i; @@ -52,7 +52,7 @@ public class ViewProvider extends UniformProvider { var vp = context.viewProjection().copy(); vp.multiplyWithTranslation(-camX, -camY, -camZ); - MatrixWrite.writeUnsafe(vp, ptr); + MatrixUtil.writeUnsafe(vp, ptr); MemoryUtil.memPutFloat(ptr + 64, camX); MemoryUtil.memPutFloat(ptr + 68, camY); MemoryUtil.memPutFloat(ptr + 72, camZ); diff --git a/src/main/java/com/jozufozu/flywheel/extension/Matrix3fExtension.java b/src/main/java/com/jozufozu/flywheel/extension/Matrix3fExtension.java deleted file mode 100644 index ef8ce3cc6..000000000 --- a/src/main/java/com/jozufozu/flywheel/extension/Matrix3fExtension.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.jozufozu.flywheel.extension; - -import com.jozufozu.flywheel.util.joml.Matrix3f; - -public interface Matrix3fExtension { - - Matrix3f flywheel$store(Matrix3f matrix); - - static Matrix3f clone(com.mojang.math.Matrix3f moj) { - return ((Matrix3fExtension)(Object) moj).flywheel$store(new Matrix3f()); - } - - static void store(com.mojang.math.Matrix3f moj, Matrix3f joml) { - ((Matrix3fExtension)(Object) moj).flywheel$store(joml); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/extension/Matrix4fExtension.java b/src/main/java/com/jozufozu/flywheel/extension/Matrix4fExtension.java deleted file mode 100644 index ea77ca703..000000000 --- a/src/main/java/com/jozufozu/flywheel/extension/Matrix4fExtension.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.jozufozu.flywheel.extension; - -import com.jozufozu.flywheel.util.joml.Matrix4f; - -public interface Matrix4fExtension { - - Matrix4f flywheel$store(Matrix4f matrix); - - static Matrix4f clone(com.mojang.math.Matrix4f moj) { - return ((Matrix4fExtension)(Object) moj).flywheel$store(new Matrix4f()); - } - - static void store(com.mojang.math.Matrix4f moj, Matrix4f joml) { - ((Matrix4fExtension)(Object) moj).flywheel$store(joml); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/extension/MatrixWrite.java b/src/main/java/com/jozufozu/flywheel/extension/MatrixWrite.java deleted file mode 100644 index 15dead550..000000000 --- a/src/main/java/com/jozufozu/flywheel/extension/MatrixWrite.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.jozufozu.flywheel.extension; - -import java.nio.ByteBuffer; - -import com.mojang.math.Matrix3f; -import com.mojang.math.Matrix4f; - -/** - * @see com.jozufozu.flywheel.mixin.matrix.Matrix3fMixin - * @see com.jozufozu.flywheel.mixin.matrix.Matrix4fMixin - */ -public interface MatrixWrite { - - /** - * Write the contents of this object into sequential memory starting at the given address. - */ - void flywheel$writeUnsafe(long ptr); - - void flywheel$write(ByteBuffer buf); - - static void write(Matrix4f matrix, ByteBuffer buf) { - ((MatrixWrite) (Object) matrix).flywheel$write(buf); - } - - static void writeUnsafe(Matrix4f matrix, long ptr) { - ((MatrixWrite) (Object) matrix).flywheel$writeUnsafe(ptr); - } - - static void writeUnsafe(Matrix3f matrix, long ptr) { - ((MatrixWrite) (Object) matrix).flywheel$writeUnsafe(ptr); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java b/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java index 9cce9fd44..5a4998210 100644 --- a/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java +++ b/src/main/java/com/jozufozu/flywheel/light/LightUpdater.java @@ -6,8 +6,9 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Stream; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine; -import com.jozufozu.flywheel.util.WeakHashSet; +import com.jozufozu.flywheel.backend.instancing.ParallelTaskExecutor; +import com.jozufozu.flywheel.backend.instancing.WorkGroup; +import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.WorldAttached; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; @@ -27,7 +28,7 @@ import net.minecraft.world.level.LightLayer; public class LightUpdater { private static final WorldAttached LEVELS = new WorldAttached<>(LightUpdater::new); - private final ParallelTaskEngine taskEngine; + private final ParallelTaskExecutor taskExecutor; public static LightUpdater get(LevelAccessor level) { if (LightUpdated.receivesLightUpdates(level)) { @@ -41,12 +42,12 @@ public class LightUpdater { private final LevelAccessor level; - private final WeakHashSet tickingLightListeners = new WeakHashSet<>(); + private final Set tickingLightListeners = FlwUtil.createWeakHashSet(); private final WeakContainmentMultiMap sections = new WeakContainmentMultiMap<>(); private final WeakContainmentMultiMap chunks = new WeakContainmentMultiMap<>(); public LightUpdater(LevelAccessor level) { - taskEngine = Backend.getTaskEngine(); + taskExecutor = Backend.getTaskExecutor(); this.level = level; } @@ -66,14 +67,14 @@ public class LightUpdater { private void tickParallel() { Queue listeners = new ConcurrentLinkedQueue<>(); - taskEngine.group("LightUpdater") + WorkGroup.builder() .addTasks(tickingLightListeners.stream(), listener -> { if (listener.tickLightListener()) { listeners.add(listener); } }) .onComplete(() -> listeners.forEach(this::addListener)) - .submit(); + .execute(taskExecutor); } /** diff --git a/src/main/java/com/jozufozu/flywheel/light/WeakContainmentMultiMap.java b/src/main/java/com/jozufozu/flywheel/light/WeakContainmentMultiMap.java index ae6c5ea61..dcba34350 100644 --- a/src/main/java/com/jozufozu/flywheel/light/WeakContainmentMultiMap.java +++ b/src/main/java/com/jozufozu/flywheel/light/WeakContainmentMultiMap.java @@ -6,7 +6,7 @@ import java.util.Set; import java.util.WeakHashMap; import java.util.function.LongConsumer; -import com.jozufozu.flywheel.util.WeakHashSet; +import com.jozufozu.flywheel.util.FlwUtil; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -15,7 +15,7 @@ import it.unimi.dsi.fastutil.longs.LongSet; public class WeakContainmentMultiMap extends AbstractCollection { - private final Long2ObjectMap> forward; + private final Long2ObjectMap> forward; private final WeakHashMap reverse; public WeakContainmentMultiMap() { @@ -38,7 +38,7 @@ public class WeakContainmentMultiMap extends AbstractCollection { LongSet containmentSet = reverse.computeIfAbsent(listener, $ -> new LongRBTreeSet()); containmentSet.forEach((LongConsumer) l -> { - WeakHashSet listeners = forward.get(l); + Set listeners = forward.get(l); if (listeners != null) listeners.remove(listener); }); @@ -53,7 +53,7 @@ public class WeakContainmentMultiMap extends AbstractCollection { } public void put(long sectionPos, T listener) { - forward.computeIfAbsent(sectionPos, $ -> new WeakHashSet<>()).add(listener); + forward.computeIfAbsent(sectionPos, $ -> FlwUtil.createWeakHashSet()).add(listener); } @Override @@ -62,7 +62,7 @@ public class WeakContainmentMultiMap extends AbstractCollection { if (containmentSet != null) { containmentSet.forEach((LongConsumer) l -> { - WeakHashSet listeners = forward.get(l); + Set listeners = forward.get(l); if (listeners != null) listeners.remove(o); }); diff --git a/src/main/java/com/jozufozu/flywheel/mixin/RenderTypeMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/RenderTypeMixin.java index 09e380de1..da170f6f8 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/RenderTypeMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/RenderTypeMixin.java @@ -18,7 +18,7 @@ public class RenderTypeMixin implements RenderTypeExtension { @NotNull public DrawBufferSet flywheel$getDrawBufferSet() { if (flywheel$drawBufferSet == null) { - flywheel$drawBufferSet = new DrawBufferSet(((RenderType) (Object) this).format()); + flywheel$drawBufferSet = new DrawBufferSet((RenderType) (Object) this); } return flywheel$drawBufferSet; } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fAccessor.java b/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fAccessor.java new file mode 100644 index 000000000..cab5194df --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fAccessor.java @@ -0,0 +1,36 @@ +package com.jozufozu.flywheel.mixin.matrix; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import com.mojang.math.Matrix3f; + +@Mixin(Matrix3f.class) +public interface Matrix3fAccessor { + @Accessor("m00") + float flywheel$m00(); + + @Accessor("m01") + float flywheel$m01(); + + @Accessor("m02") + float flywheel$m02(); + + @Accessor("m10") + float flywheel$m10(); + + @Accessor("m11") + float flywheel$m11(); + + @Accessor("m12") + float flywheel$m12(); + + @Accessor("m20") + float flywheel$m20(); + + @Accessor("m21") + float flywheel$m21(); + + @Accessor("m22") + float flywheel$m22(); +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fMixin.java deleted file mode 100644 index 2690b8f99..000000000 --- a/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix3fMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.jozufozu.flywheel.mixin.matrix; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.jozufozu.flywheel.extension.Matrix3fExtension; -import com.jozufozu.flywheel.extension.MatrixWrite; -import com.mojang.math.Matrix3f; - -@Mixin(Matrix3f.class) -public abstract class Matrix3fMixin implements MatrixWrite, Matrix3fExtension { - @Shadow protected float m00; - @Shadow protected float m01; - @Shadow protected float m02; - @Shadow protected float m10; - @Shadow protected float m11; - @Shadow protected float m12; - @Shadow protected float m20; - @Shadow protected float m21; - @Shadow protected float m22; - - @Override - public void flywheel$writeUnsafe(long ptr) { - MemoryUtil.memPutFloat(ptr, m00); - MemoryUtil.memPutFloat(ptr + 4, m10); - MemoryUtil.memPutFloat(ptr + 8, m20); - MemoryUtil.memPutFloat(ptr + 12, m01); - MemoryUtil.memPutFloat(ptr + 16, m11); - MemoryUtil.memPutFloat(ptr + 20, m21); - MemoryUtil.memPutFloat(ptr + 24, m02); - MemoryUtil.memPutFloat(ptr + 28, m12); - MemoryUtil.memPutFloat(ptr + 32, m22); - } - - @Override - public void flywheel$write(ByteBuffer buffer) { - buffer.putFloat(m00); - buffer.putFloat(m10); - buffer.putFloat(m20); - buffer.putFloat(m01); - buffer.putFloat(m11); - buffer.putFloat(m21); - buffer.putFloat(m02); - buffer.putFloat(m12); - buffer.putFloat(m22); - } - - @Override - public com.jozufozu.flywheel.util.joml.Matrix3f flywheel$store(com.jozufozu.flywheel.util.joml.Matrix3f matrix) { - return matrix.set(m00, m10, m20, m01, m11, m21, m02, m12, m22); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fAccessor.java b/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fAccessor.java new file mode 100644 index 000000000..8da1c56f1 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fAccessor.java @@ -0,0 +1,57 @@ +package com.jozufozu.flywheel.mixin.matrix; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import com.mojang.math.Matrix4f; + +@Mixin(Matrix4f.class) +public interface Matrix4fAccessor { + @Accessor("m00") + float flywheel$m00(); + + @Accessor("m01") + float flywheel$m01(); + + @Accessor("m02") + float flywheel$m02(); + + @Accessor("m03") + float flywheel$m03(); + + @Accessor("m10") + float flywheel$m10(); + + @Accessor("m11") + float flywheel$m11(); + + @Accessor("m12") + float flywheel$m12(); + + @Accessor("m13") + float flywheel$m13(); + + @Accessor("m20") + float flywheel$m20(); + + @Accessor("m21") + float flywheel$m21(); + + @Accessor("m22") + float flywheel$m22(); + + @Accessor("m23") + float flywheel$m23(); + + @Accessor("m30") + float flywheel$m30(); + + @Accessor("m31") + float flywheel$m31(); + + @Accessor("m32") + float flywheel$m32(); + + @Accessor("m33") + float flywheel$m33(); +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fMixin.java deleted file mode 100644 index 542e71929..000000000 --- a/src/main/java/com/jozufozu/flywheel/mixin/matrix/Matrix4fMixin.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.jozufozu.flywheel.mixin.matrix; - -import java.nio.ByteBuffer; - -import org.lwjgl.system.MemoryUtil; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.jozufozu.flywheel.extension.Matrix4fExtension; -import com.jozufozu.flywheel.extension.MatrixWrite; -import com.mojang.math.Matrix4f; - -@Mixin(Matrix4f.class) -public abstract class Matrix4fMixin implements MatrixWrite, Matrix4fExtension { - @Shadow protected float m00; - @Shadow protected float m01; - @Shadow protected float m02; - @Shadow protected float m03; - @Shadow protected float m10; - @Shadow protected float m11; - @Shadow protected float m12; - @Shadow protected float m13; - @Shadow protected float m20; - @Shadow protected float m21; - @Shadow protected float m22; - @Shadow protected float m23; - @Shadow protected float m30; - @Shadow protected float m31; - @Shadow protected float m32; - @Shadow protected float m33; - - @Override - public void flywheel$writeUnsafe(long ptr) { - MemoryUtil.memPutFloat(ptr, m00); - MemoryUtil.memPutFloat(ptr + 4, m10); - MemoryUtil.memPutFloat(ptr + 8, m20); - MemoryUtil.memPutFloat(ptr + 12, m30); - MemoryUtil.memPutFloat(ptr + 16, m01); - MemoryUtil.memPutFloat(ptr + 20, m11); - MemoryUtil.memPutFloat(ptr + 24, m21); - MemoryUtil.memPutFloat(ptr + 28, m31); - MemoryUtil.memPutFloat(ptr + 32, m02); - MemoryUtil.memPutFloat(ptr + 36, m12); - MemoryUtil.memPutFloat(ptr + 40, m22); - MemoryUtil.memPutFloat(ptr + 44, m32); - MemoryUtil.memPutFloat(ptr + 48, m03); - MemoryUtil.memPutFloat(ptr + 52, m13); - MemoryUtil.memPutFloat(ptr + 56, m23); - MemoryUtil.memPutFloat(ptr + 60, m33); - } - - @Override - public void flywheel$write(ByteBuffer buf) { - buf.putFloat(m00); - buf.putFloat(m10); - buf.putFloat(m20); - buf.putFloat(m30); - buf.putFloat(m01); - buf.putFloat(m11); - buf.putFloat(m21); - buf.putFloat(m31); - buf.putFloat(m02); - buf.putFloat(m12); - buf.putFloat(m22); - buf.putFloat(m32); - buf.putFloat(m03); - buf.putFloat(m13); - buf.putFloat(m23); - buf.putFloat(m33); - } - - @Override - public com.jozufozu.flywheel.util.joml.Matrix4f flywheel$store(com.jozufozu.flywheel.util.joml.Matrix4f matrix) { - return matrix.set( - m00, m10, m20, m30, - m01, m11, m21, m31, - m02, m12, m22, m32, - m03, m13, m23, m33); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/util/Color.java b/src/main/java/com/jozufozu/flywheel/util/Color.java deleted file mode 100644 index e6824ec61..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/Color.java +++ /dev/null @@ -1,309 +0,0 @@ -package com.jozufozu.flywheel.util; - -import java.util.function.UnaryOperator; - -import org.jetbrains.annotations.NotNull; - -import com.google.common.hash.Hashing; -import com.mojang.math.Vector3f; - -import net.minecraft.util.Mth; -import net.minecraft.world.phys.Vec3; - -@SuppressWarnings("PointlessBitwiseExpression") -public class Color { - public final static Color TRANSPARENT_BLACK = new Color(0, 0, 0, 0).setImmutable(); - public final static Color BLACK = new Color(0, 0, 0).setImmutable(); - public final static Color WHITE = new Color(255, 255, 255).setImmutable(); - public final static Color RED = new Color(255, 0, 0).setImmutable(); - public final static Color GREEN = new Color(0, 255, 0).setImmutable(); - public final static Color SPRING_GREEN = new Color(0, 255, 187).setImmutable(); - - protected boolean mutable = true; - protected int value; - - public Color(int r, int g, int b) { - this(r, g, b, 0xff); - } - - public Color(int r, int g, int b, int a) { - value = ((a & 0xff) << 24) | - ((r & 0xff) << 16) | - ((g & 0xff) << 8) | - ((b & 0xff) << 0); - } - - public Color(float r, float g, float b, float a) { - this( - (int) (0.5 + 0xff * Mth.clamp(r, 0, 1)), - (int) (0.5 + 0xff * Mth.clamp(g, 0, 1)), - (int) (0.5 + 0xff * Mth.clamp(b, 0, 1)), - (int) (0.5 + 0xff * Mth.clamp(a, 0, 1)) - ); - } - - public Color(int rgba) { - value = rgba; - } - - public Color(int rgb, boolean hasAlpha) { - if (hasAlpha) { - value = rgb; - } else { - value = rgb | 0xff_000000; - } - } - - public Color copy() { - return copy(true); - } - - public Color copy(boolean mutable) { - if (mutable) - return new Color(value); - else - return new Color(value).setImmutable(); - } - - /** - * Mark this color as immutable. Attempting to mutate this color in the future - * will instead cause a copy to be created that can me modified. - */ - public Color setImmutable() { - this.mutable = false; - return this; - } - - /** - * @return the red component in the range 0-255. - * @see #getRGB - */ - public int getRed() { - return (getRGB() >> 16) & 0xff; - } - - /** - * @return the green component in the range 0-255. - * @see #getRGB - */ - public int getGreen() { - return (getRGB() >> 8) & 0xff; - } - - /** - * @return the blue component in the range 0-255. - * @see #getRGB - */ - public int getBlue() { - return (getRGB() >> 0) & 0xff; - } - - /** - * @return the alpha component in the range 0-255. - * @see #getRGB - */ - public int getAlpha() { - return (getRGB() >> 24) & 0xff; - } - - /** - * @return the red component in the range 0-1f. - */ - public float getRedAsFloat() { - return getRed() / 255f; - } - - /** - * @return the green component in the range 0-1f. - */ - public float getGreenAsFloat() { - return getGreen() / 255f; - } - - /** - * @return the blue component in the range 0-1f. - */ - public float getBlueAsFloat() { - return getBlue() / 255f; - } - - /** - * @return the alpha component in the range 0-1f. - */ - public float getAlphaAsFloat() { - return getAlpha() / 255f; - } - - /** - * Returns the RGB value representing this color - * (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue). - * @return the RGB value of the color - */ - public int getRGB() { - return value; - } - - public Vec3 asVector() { - return new Vec3(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat()); - } - - public Vector3f asVectorF() { - return new Vector3f(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat()); - } - - public Color setRed(int r) { - return ensureMutable().setRedUnchecked(r); - } - - public Color setGreen(int g) { - return ensureMutable().setGreenUnchecked(g); - } - - public Color setBlue(int b) { - return ensureMutable().setBlueUnchecked(b); - } - - public Color setAlpha(int a) { - return ensureMutable().setAlphaUnchecked(a); - } - - public Color setRed(float r) { - return ensureMutable().setRedUnchecked((int) (0xff * Mth.clamp(r, 0, 1))); - } - - public Color setGreen(float g) { - return ensureMutable().setGreenUnchecked((int) (0xff * Mth.clamp(g, 0, 1))); - } - - public Color setBlue(float b) { - return ensureMutable().setBlueUnchecked((int) (0xff * Mth.clamp(b, 0, 1))); - } - - public Color setAlpha(float a) { - return ensureMutable().setAlphaUnchecked((int) (0xff * Mth.clamp(a, 0, 1))); - } - - public Color scaleAlpha(float factor) { - return ensureMutable().setAlphaUnchecked((int) (getAlpha() * Mth.clamp(factor, 0, 1))); - } - - public Color mixWith(Color other, float weight) { - return ensureMutable() - .setRedUnchecked((int) (getRed() + (other.getRed() - getRed()) * weight)) - .setGreenUnchecked((int) (getGreen() + (other.getGreen() - getGreen()) * weight)) - .setBlueUnchecked((int) (getBlue() + (other.getBlue() - getBlue()) * weight)) - .setAlphaUnchecked((int) (getAlpha() + (other.getAlpha() - getAlpha()) * weight)); - } - - public Color darker() { - int a = getAlpha(); - return ensureMutable().mixWith(BLACK, .25f).setAlphaUnchecked(a); - } - - public Color brighter() { - int a = getAlpha(); - return ensureMutable().mixWith(WHITE, .25f).setAlphaUnchecked(a); - } - - public Color setValue(int value) { - return ensureMutable().setValueUnchecked(value); - } - - public Color modifyValue(UnaryOperator function) { - int newValue = function.apply(value); - if (newValue == value) - return this; - - return ensureMutable().setValueUnchecked(newValue); - } - - // ********* // - - protected Color ensureMutable() { - if (this.mutable) - return this; - - return new Color(this.value); - } - - protected Color setRedUnchecked(int r) { - this.value = (this.value & 0xff_00ffff) | ((r & 0xff) << 16); - return this; - } - - protected Color setGreenUnchecked(int g) { - this.value = (this.value & 0xff_ff00ff) | ((g & 0xff) << 8); - return this; - } - - protected Color setBlueUnchecked(int b) { - this.value = (this.value & 0xff_ffff00) | ((b & 0xff) << 0); - return this; - } - - protected Color setAlphaUnchecked(int a) { - this.value = (this.value & 0x00_ffffff) | ((a & 0xff) << 24); - return this; - } - - protected Color setValueUnchecked(int value) { - this.value = value; - return this; - } - - // ********* // - - public static Color mixColors(@NotNull Color c1, @NotNull Color c2, float w) { - return new Color( - (int) (c1.getRed() + (c2.getRed() - c1.getRed()) * w), - (int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * w), - (int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * w), - (int) (c1.getAlpha() + (c2.getAlpha() - c1.getAlpha()) * w) - ); - } - - public static int mixColors(int color1, int color2, float w) { - int a1 = (color1 >> 24); - int r1 = (color1 >> 16) & 0xFF; - int g1 = (color1 >> 8) & 0xFF; - int b1 = color1 & 0xFF; - int a2 = (color2 >> 24); - int r2 = (color2 >> 16) & 0xFF; - int g2 = (color2 >> 8) & 0xFF; - int b2 = color2 & 0xFF; - - return - ((int) (a1 + (a2 - a1) * w) << 24) + - ((int) (r1 + (r2 - r1) * w) << 16) + - ((int) (g1 + (g2 - g1) * w) << 8) + - ((int) (b1 + (b2 - b1) * w) << 0); - } - - public static Color rainbowColor(int timeStep) { - int localTimeStep = Math.abs(timeStep) % 1536; - int timeStepInPhase = localTimeStep % 256; - int phaseBlue = localTimeStep / 256; - int red = colorInPhase(phaseBlue + 4, timeStepInPhase); - int green = colorInPhase(phaseBlue + 2, timeStepInPhase); - int blue = colorInPhase(phaseBlue, timeStepInPhase); - return new Color(red, green, blue); - } - - private static int colorInPhase(int phase, int progress) { - phase = phase % 6; - if (phase <= 1) - return 0; - if (phase == 2) - return progress; - if (phase <= 4) - return 255; - else - return 255 - progress; - } - - public static Color generateFromLong(long l) { - return rainbowColor(Hashing.crc32().hashLong(l).asInt()) - .mixWith(WHITE, 0.5f); - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java index be55e6518..b40e70427 100644 --- a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java +++ b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java @@ -1,7 +1,10 @@ package com.jozufozu.flywheel.util; import java.util.Arrays; +import java.util.Collections; import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; import java.util.stream.Stream; import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor; @@ -81,4 +84,8 @@ public class FlwUtil { public static Stream mapValues(Map map) { return map.values().stream(); } + + public static Set createWeakHashSet() { + return Collections.newSetFromMap(new WeakHashMap<>()); + } } diff --git a/src/main/java/com/jozufozu/flywheel/util/MatrixUtil.java b/src/main/java/com/jozufozu/flywheel/util/MatrixUtil.java new file mode 100644 index 000000000..dbd1c7b12 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/MatrixUtil.java @@ -0,0 +1,116 @@ +package com.jozufozu.flywheel.util; + +import java.nio.ByteBuffer; + +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.mixin.matrix.Matrix3fAccessor; +import com.jozufozu.flywheel.mixin.matrix.Matrix4fAccessor; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; + +public class MatrixUtil { + public static void write(Matrix4f matrix, ByteBuffer buf) { + Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; + buf.putFloat(m.flywheel$m00()); + buf.putFloat(m.flywheel$m10()); + buf.putFloat(m.flywheel$m20()); + buf.putFloat(m.flywheel$m30()); + buf.putFloat(m.flywheel$m01()); + buf.putFloat(m.flywheel$m11()); + buf.putFloat(m.flywheel$m21()); + buf.putFloat(m.flywheel$m31()); + buf.putFloat(m.flywheel$m02()); + buf.putFloat(m.flywheel$m12()); + buf.putFloat(m.flywheel$m22()); + buf.putFloat(m.flywheel$m32()); + buf.putFloat(m.flywheel$m03()); + buf.putFloat(m.flywheel$m13()); + buf.putFloat(m.flywheel$m23()); + buf.putFloat(m.flywheel$m33()); + } + + public static void writeUnsafe(Matrix4f matrix, long ptr) { + Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; + MemoryUtil.memPutFloat(ptr, m.flywheel$m00()); + MemoryUtil.memPutFloat(ptr + 4, m.flywheel$m10()); + MemoryUtil.memPutFloat(ptr + 8, m.flywheel$m20()); + MemoryUtil.memPutFloat(ptr + 12, m.flywheel$m30()); + MemoryUtil.memPutFloat(ptr + 16, m.flywheel$m01()); + MemoryUtil.memPutFloat(ptr + 20, m.flywheel$m11()); + MemoryUtil.memPutFloat(ptr + 24, m.flywheel$m21()); + MemoryUtil.memPutFloat(ptr + 28, m.flywheel$m31()); + MemoryUtil.memPutFloat(ptr + 32, m.flywheel$m02()); + MemoryUtil.memPutFloat(ptr + 36, m.flywheel$m12()); + MemoryUtil.memPutFloat(ptr + 40, m.flywheel$m22()); + MemoryUtil.memPutFloat(ptr + 44, m.flywheel$m32()); + MemoryUtil.memPutFloat(ptr + 48, m.flywheel$m03()); + MemoryUtil.memPutFloat(ptr + 52, m.flywheel$m13()); + MemoryUtil.memPutFloat(ptr + 56, m.flywheel$m23()); + MemoryUtil.memPutFloat(ptr + 60, m.flywheel$m33()); + } + + public static void write(Matrix3f matrix, ByteBuffer buf) { + Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; + buf.putFloat(m.flywheel$m00()); + buf.putFloat(m.flywheel$m10()); + buf.putFloat(m.flywheel$m20()); + buf.putFloat(m.flywheel$m01()); + buf.putFloat(m.flywheel$m11()); + buf.putFloat(m.flywheel$m21()); + buf.putFloat(m.flywheel$m02()); + buf.putFloat(m.flywheel$m12()); + buf.putFloat(m.flywheel$m22()); + } + + public static void store(Matrix4f matrix, com.jozufozu.flywheel.util.joml.Matrix4f jomlMatrix) { + Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; + jomlMatrix.set( + m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m30(), + m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m31(), + m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22(), m.flywheel$m32(), + m.flywheel$m03(), m.flywheel$m13(), m.flywheel$m23(), m.flywheel$m33() + ); + } + + public static com.jozufozu.flywheel.util.joml.Matrix4f toJoml(Matrix4f matrix) { + Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; + return new com.jozufozu.flywheel.util.joml.Matrix4f( + m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m30(), + m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m31(), + m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22(), m.flywheel$m32(), + m.flywheel$m03(), m.flywheel$m13(), m.flywheel$m23(), m.flywheel$m33() + ); + } + + public static void writeUnsafe(Matrix3f matrix, long ptr) { + Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; + MemoryUtil.memPutFloat(ptr, m.flywheel$m00()); + MemoryUtil.memPutFloat(ptr + 4, m.flywheel$m10()); + MemoryUtil.memPutFloat(ptr + 8, m.flywheel$m20()); + MemoryUtil.memPutFloat(ptr + 12, m.flywheel$m01()); + MemoryUtil.memPutFloat(ptr + 16, m.flywheel$m11()); + MemoryUtil.memPutFloat(ptr + 20, m.flywheel$m21()); + MemoryUtil.memPutFloat(ptr + 24, m.flywheel$m02()); + MemoryUtil.memPutFloat(ptr + 28, m.flywheel$m12()); + MemoryUtil.memPutFloat(ptr + 32, m.flywheel$m22()); + } + + public static void store(Matrix3f matrix, com.jozufozu.flywheel.util.joml.Matrix3f jomlMatrix) { + Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; + jomlMatrix.set( + m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), + m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), + m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22() + ); + } + + public static com.jozufozu.flywheel.util.joml.Matrix3f toJoml(Matrix3f matrix) { + Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; + return new com.jozufozu.flywheel.util.joml.Matrix3f( + m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), + m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), + m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22() + ); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/WeakHashSet.java b/src/main/java/com/jozufozu/flywheel/util/WeakHashSet.java deleted file mode 100644 index 281aaf418..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/WeakHashSet.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.jozufozu.flywheel.util; - -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.WeakHashMap; - -import net.minecraft.util.Unit; - -public class WeakHashSet extends AbstractSet { - - WeakHashMap map; - - public WeakHashSet() { - map = new WeakHashMap<>(); - } - - /** - * Constructs a new set containing the elements in the specified - * collection. The HashMap is created with default load factor - * (0.75) and an initial capacity sufficient to contain the elements in - * the specified collection. - * - * @param c the collection whose elements are to be placed into this set - * @throws NullPointerException if the specified collection is null - */ - public WeakHashSet(Collection c) { - map = new WeakHashMap<>(Math.max((int) (c.size() / .75f) + 1, 16)); - addAll(c); - } - - /** - * Constructs a new, empty set; the backing HashMap instance has - * the specified initial capacity and the specified load factor. - * - * @param initialCapacity the initial capacity of the hash map - * @param loadFactor the load factor of the hash map - * @throws IllegalArgumentException if the initial capacity is less - * than zero, or if the load factor is nonpositive - */ - public WeakHashSet(int initialCapacity, float loadFactor) { - map = new WeakHashMap<>(initialCapacity, loadFactor); - } - - /** - * Constructs a new, empty set; the backing HashMap instance has - * the specified initial capacity and default load factor (0.75). - * - * @param initialCapacity the initial capacity of the hash table - * @throws IllegalArgumentException if the initial capacity is less - * than zero - */ - public WeakHashSet(int initialCapacity) { - map = new WeakHashMap<>(initialCapacity); - } - - @Override - public Iterator iterator() { - return map.keySet() - .iterator(); - } - - @Override - public int size() { - return map.size(); - } - - @Override - public boolean add(T t) { - return map.put(t, Unit.INSTANCE) == null; - } - - @Override - public boolean remove(Object o) { - return map.remove(o) != null; - } - - @Override - public boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return map.containsKey(o); - } - - @Override - public Object[] toArray() { - return map.keySet() - .toArray(); - } - - @Override - public boolean containsAll(Collection c) { - return stream().allMatch(map::containsKey); - } - - @Override - public boolean addAll(Collection c) { - boolean out = false; - for (T t : c) { - out |= add(t); - } - return out; - } - - @Override - public boolean retainAll(Collection c) { - return false; - } - - @Override - public boolean removeAll(Collection c) { - return false; - } - - @Override - public void clear() { - map.clear(); - } -} diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index e190d6a30..502c4882d 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -25,8 +25,8 @@ "VertexFormatMixin", "light.LightUpdateMixin", "light.NetworkLightUpdateMixin", - "matrix.Matrix3fMixin", - "matrix.Matrix4fMixin", + "matrix.Matrix3fAccessor", + "matrix.Matrix4fAccessor", "matrix.PoseStackMixin" ], "injectors": {