Housekeeping

- Update dependencies, forge version
- Bump LICENCE year
- Use fma in MatrixUtil and VertexTransformations
- Remove some dead variables from TransformCall
- Use onSpinWait in WaitGroup#await
- Do not allow adding negative numbers to a WaitGroup
- Thin abstraction for TaskNotifier
- Clean up WorkerThread task polling
This commit is contained in:
Jozufozu 2023-05-21 15:24:33 -07:00
parent 37ecedb97a
commit 3da51885d1
10 changed files with 60 additions and 58 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) 2021 Jozufozu Copyright (c) 2021-2023 Jozufozu
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the

View file

@ -146,8 +146,8 @@ dependencies {
// switch to implementation for debugging // switch to implementation for debugging
compileOnly fg.deobf("maven.modrinth:starlight-forge:1.0.2+1.18.2") compileOnly fg.deobf("maven.modrinth:starlight-forge:1.0.2+1.18.2")
compileOnly fg.deobf("maven.modrinth:rubidium:0.5.3a") compileOnly fg.deobf("maven.modrinth:rubidium:0.5.6")
compileOnly fg.deobf("maven.modrinth:oculus:1.18.2-1.2.5a") compileOnly fg.deobf("maven.modrinth:oculus:1.18.2-1.5.2")
// https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497 // https://discord.com/channels/313125603924639766/725850371834118214/910619168821354497
// Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings

View file

@ -5,12 +5,12 @@ org.gradle.daemon = false
mod_version = 1.0.0-alpha mod_version = 1.0.0-alpha
artifact_minecraft_version = 1.18.2 artifact_minecraft_version = 1.18.2
minecraft_version = 1.18.2 minecraft_version=1.18.2
forge_version = 40.1.68 forge_version=40.2.4
# build dependency versions # build dependency versions
forgegradle_version = 5.1.53 forgegradle_version=5.1.+
mixingradle_version = 0.7-SNAPSHOT mixingradle_version=0.7-SNAPSHOT
mixin_version = 0.8.5 mixin_version = 0.8.5
librarian_version = 1.+ librarian_version = 1.+
cursegradle_version = 1.4.0 cursegradle_version = 1.4.0

View file

@ -20,11 +20,7 @@ import com.mojang.math.Matrix4f;
public class TransformCall<I extends Instance> { public class TransformCall<I extends Instance> {
private final CPUInstancer<I> instancer; private final CPUInstancer<I> instancer;
private final Material material;
private final BatchedMeshPool.BufferedMesh mesh;
private final int meshVertexCount; private final int meshVertexCount;
private final int meshByteSize;
private final InstanceVertexTransformer<I> instanceVertexTransformer; private final InstanceVertexTransformer<I> instanceVertexTransformer;
private final MaterialVertexTransformer materialVertexTransformer; private final MaterialVertexTransformer materialVertexTransformer;
private final InstanceBoundingSphereTransformer<I> boundingSphereTransformer; private final InstanceBoundingSphereTransformer<I> boundingSphereTransformer;
@ -34,15 +30,12 @@ public class TransformCall<I extends Instance> {
public TransformCall(CPUInstancer<I> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) { public TransformCall(CPUInstancer<I> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
this.instancer = instancer; this.instancer = instancer;
this.material = material;
this.mesh = mesh;
instanceVertexTransformer = instancer.type.getVertexTransformer(); instanceVertexTransformer = instancer.type.getVertexTransformer();
boundingSphereTransformer = instancer.type.getBoundingSphereTransformer(); boundingSphereTransformer = instancer.type.getBoundingSphereTransformer();
materialVertexTransformer = material.getVertexTransformer(); materialVertexTransformer = material.getVertexTransformer();
meshVertexCount = mesh.getVertexCount(); meshVertexCount = mesh.getVertexCount();
meshByteSize = mesh.size();
boundingSphere = mesh.mesh.getBoundingSphere(); boundingSphere = mesh.mesh.getBoundingSphere();
drawPlan = RunOnAllWithContextPlan.of(instancer::getAll, (instance, ctx) -> { drawPlan = RunOnAllWithContextPlan.of(instancer::getAll, (instance, ctx) -> {

View file

@ -9,11 +9,11 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.ThreadGroupNotifier;
import com.jozufozu.flywheel.lib.task.WaitGroup; import com.jozufozu.flywheel.lib.task.WaitGroup;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
@ -37,7 +37,7 @@ public class ParallelTaskExecutor implements TaskExecutor {
private final Deque<Runnable> taskQueue = new ConcurrentLinkedDeque<>(); private final Deque<Runnable> taskQueue = new ConcurrentLinkedDeque<>();
private final Queue<Runnable> mainThreadQueue = new ConcurrentLinkedQueue<>(); private final Queue<Runnable> mainThreadQueue = new ConcurrentLinkedQueue<>();
private final Object taskNotifier = new Object(); private final ThreadGroupNotifier taskNotifier = new ThreadGroupNotifier();
private final WaitGroup waitGroup = new WaitGroup(); private final WaitGroup waitGroup = new WaitGroup();
public ParallelTaskExecutor(String name) { public ParallelTaskExecutor(String name) {
@ -114,9 +114,7 @@ public class ParallelTaskExecutor implements TaskExecutor {
waitGroup.add(); waitGroup.add();
taskQueue.add(task); taskQueue.add(task);
synchronized (taskNotifier) { taskNotifier.postNotification();
taskNotifier.notifyAll();
}
} }
@Override @Override
@ -148,8 +146,8 @@ public class ParallelTaskExecutor implements TaskExecutor {
} else { } else {
// then wait for the other threads to finish. // then wait for the other threads to finish.
waitGroup.await(); waitGroup.await();
// at this point there will be no more tasks in the queue, but // at this point we know taskQueue is empty,
// one of the worker threads may have submitted a main thread task. // but one of the worker threads may have submitted a main thread task.
if (mainThreadQueue.isEmpty()) { if (mainThreadQueue.isEmpty()) {
// if they didn't, we're done. // if they didn't, we're done.
break; break;
@ -170,23 +168,6 @@ public class ParallelTaskExecutor implements TaskExecutor {
mainThreadQueue.clear(); mainThreadQueue.clear();
} }
@Nullable
private Runnable getNextTask() {
Runnable task = taskQueue.pollFirst();
if (task == null) {
synchronized (taskNotifier) {
try {
taskNotifier.wait();
} catch (InterruptedException e) {
//
}
}
}
return task;
}
private void processTask(Runnable task) { private void processTask(Runnable task) {
try { try {
task.run(); task.run();
@ -226,9 +207,11 @@ public class ParallelTaskExecutor implements TaskExecutor {
public void run() { public void run() {
// Run until the executor shuts down // Run until the executor shuts down
while (ParallelTaskExecutor.this.running.get()) { while (ParallelTaskExecutor.this.running.get()) {
Runnable task = getNextTask(); Runnable task = taskQueue.pollFirst();
if (task == null) { if (task == null) {
// Nothing to do, time to sleep.
taskNotifier.awaitNotification();
continue; continue;
} }

View file

@ -1,7 +1,10 @@
package com.jozufozu.flywheel.lib.math; package com.jozufozu.flywheel.lib.math;
import static org.joml.Math.fma;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.joml.Math;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.mixin.matrix.Matrix3fAccessor; import com.jozufozu.flywheel.mixin.matrix.Matrix3fAccessor;
@ -12,32 +15,32 @@ import com.mojang.math.Matrix4f;
public final class MatrixUtil { public final class MatrixUtil {
public static float transformPositionX(Matrix4f matrix, float x, float y, float z) { public static float transformPositionX(Matrix4f matrix, float x, float y, float z) {
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
return (m.flywheel$m00() * x) + (m.flywheel$m01() * y) + (m.flywheel$m02() * z) + m.flywheel$m03(); return fma(m.flywheel$m00(), x, fma(m.flywheel$m01(), y, fma(m.flywheel$m02(), z, m.flywheel$m03())));
} }
public static float transformPositionY(Matrix4f matrix, float x, float y, float z) { public static float transformPositionY(Matrix4f matrix, float x, float y, float z) {
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
return (m.flywheel$m10() * x) + (m.flywheel$m11() * y) + (m.flywheel$m12() * z) + m.flywheel$m13(); return fma(m.flywheel$m10(), x, fma(m.flywheel$m11(), y, fma(m.flywheel$m12(), z, m.flywheel$m13())));
} }
public static float transformPositionZ(Matrix4f matrix, float x, float y, float z) { public static float transformPositionZ(Matrix4f matrix, float x, float y, float z) {
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix; Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
return (m.flywheel$m20() * x) + (m.flywheel$m21() * y) + (m.flywheel$m22() * z) + m.flywheel$m23(); return fma(m.flywheel$m20(), x, fma(m.flywheel$m21(), y, fma(m.flywheel$m22(), z, m.flywheel$m23())));
} }
public static float transformNormalX(Matrix3f matrix, float x, float y, float z) { public static float transformNormalX(Matrix3f matrix, float x, float y, float z) {
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
return (m.flywheel$m00() * x) + (m.flywheel$m01() * y) + (m.flywheel$m02() * z); return fma(m.flywheel$m00(), x, fma(m.flywheel$m01(), y, m.flywheel$m02() * z));
} }
public static float transformNormalY(Matrix3f matrix, float x, float y, float z) { public static float transformNormalY(Matrix3f matrix, float x, float y, float z) {
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
return (m.flywheel$m10() * x) + (m.flywheel$m11() * y) + (m.flywheel$m12() * z); return fma(m.flywheel$m10(), x, fma(m.flywheel$m11(), y, m.flywheel$m12() * z));
} }
public static float transformNormalZ(Matrix3f matrix, float x, float y, float z) { public static float transformNormalZ(Matrix3f matrix, float x, float y, float z) {
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix; Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
return (m.flywheel$m20() * x) + (m.flywheel$m21() * y) + (m.flywheel$m22() * z); return fma(m.flywheel$m20(), x, fma(m.flywheel$m21(), y, m.flywheel$m22() * z));
} }
public static void write(Matrix4f matrix, ByteBuffer buf) { public static void write(Matrix4f matrix, ByteBuffer buf) {

View file

@ -0,0 +1,19 @@
package com.jozufozu.flywheel.lib.task;
/**
* Thin wrapper around Java's built-in object synchronization primitives.
*/
public class ThreadGroupNotifier {
public synchronized void awaitNotification() {
try {
this.wait();
} catch (InterruptedException e) {
// we don't care if we're interrupted, just continue.
}
}
public synchronized void postNotification() {
this.notifyAll();
}
}

View file

@ -4,6 +4,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import com.google.common.base.Preconditions;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
public class WaitGroup { public class WaitGroup {
@ -16,6 +17,7 @@ public class WaitGroup {
} }
public void add(int i) { public void add(int i) {
Preconditions.checkArgument(i >= 0, "Cannot add a negative number of tasks to a WaitGroup!");
if (i == 0) { if (i == 0) {
return; return;
} }
@ -31,17 +33,9 @@ public class WaitGroup {
public void await() { public void await() {
// TODO: comprehensive performance tracking for tasks // TODO: comprehensive performance tracking for tasks
long start = System.nanoTime();
int count = 0;
while (counter.get() > 0) { while (counter.get() > 0) {
// spin in place to avoid sleeping the main thread // spin in place to avoid sleeping the main thread
count++; Thread.onSpinWait();
}
long end = System.nanoTime();
long elapsed = end - start;
if (elapsed > 1000000) { // > 1ms
// LOGGER.debug("Waited " + StringUtil.formatTime(elapsed) + ", looped " + count + " times");
} }
} }

View file

@ -1,5 +1,8 @@
package com.jozufozu.flywheel.lib.vertex; package com.jozufozu.flywheel.lib.vertex;
import static org.joml.Math.fma;
import static org.joml.Math.invsqrt;
import com.jozufozu.flywheel.api.vertex.MutableVertexList; import com.jozufozu.flywheel.api.vertex.MutableVertexList;
import com.jozufozu.flywheel.lib.math.MatrixUtil; import com.jozufozu.flywheel.lib.math.MatrixUtil;
import com.mojang.math.Matrix3f; import com.mojang.math.Matrix3f;
@ -22,9 +25,9 @@ public final class VertexTransformations {
float tnx = MatrixUtil.transformNormalX(matrix, nx, ny, nz); float tnx = MatrixUtil.transformNormalX(matrix, nx, ny, nz);
float tny = MatrixUtil.transformNormalY(matrix, nx, ny, nz); float tny = MatrixUtil.transformNormalY(matrix, nx, ny, nz);
float tnz = MatrixUtil.transformNormalZ(matrix, nx, ny, nz); float tnz = MatrixUtil.transformNormalZ(matrix, nx, ny, nz);
float sqrLength = tnx * tnx + tny * tny + tnz * tnz; float sqrLength = fma(tnx, tnx, fma(tny, tny, tnz * tnz));
if (sqrLength != 0) { if (sqrLength != 0) {
float f = 1 / (float) Math.sqrt(sqrLength); float f = invsqrt(sqrLength);
tnx *= f; tnx *= f;
tny *= f; tny *= f;
tnz *= f; tnz *= f;

View file

@ -1,6 +1,7 @@
package com.jozufozu.flywheel.lib.task; package com.jozufozu.flywheel.lib.task;
import org.junit.jupiter.api.Assertions; import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class WaitGroupTest { public class WaitGroupTest {
@ -9,6 +10,12 @@ public class WaitGroupTest {
WaitGroup wg = new WaitGroup(); WaitGroup wg = new WaitGroup();
wg.add(); wg.add();
wg.done(); wg.done();
Assertions.assertThrows(IllegalStateException.class, wg::done); assertThrows(IllegalStateException.class, wg::done);
}
@Test
public void testAddNegative() {
WaitGroup wg = new WaitGroup();
assertThrows(IllegalArgumentException.class, () -> wg.add(-1));
} }
} }