Shaking things out

- Use JOML better where we can.
  - Inline MatrixUtil#store and #toJoml
  - FlwShaderUniforms keeps a scratch matrix around for mutating the
    viewProjection.
  - Directly store a Quaternion4f in OrientedInstance to avoid creating
    new objects in the batching transformers.
- Move FrameContext creation to a functor.
- We do need to check the renderDebug flag still :ioa:
- Make VisualUpdatePlan's internal plan not null.
- Remove ClientMainMixin :sad:
  - Forge's new earlywindow stuff means there's no opportunity for
    Flywheel the mod to inject renderdoc before the window is
    initialized.
  - The workaround for now is to breakpoint in FML's
    DisplayWindow#initialize and evaluate
    `System.loadLibrary("renderdoc")` manually.
This commit is contained in:
Jozufozu 2023-11-24 14:29:03 -08:00
parent 152688a09f
commit 9ac8aea347
14 changed files with 62 additions and 124 deletions

View file

@ -45,7 +45,6 @@ minecraft {
client {
property 'flw.dumpShaderSource', 'true'
property 'flw.loadRenderDoc', 'true'
property 'flw.debugMemorySafety', 'true'
}

View file

@ -140,10 +140,10 @@ public class Flywheel {
private static void addDebugInfo(CustomizeGuiOverlayEvent.DebugText event) {
Minecraft mc = Minecraft.getInstance();
// FIXME: do we need this check anymore?
// if (!mc.options.renderDebug) {
// return;
// }
if (!mc.options.renderDebug) {
return;
}
ArrayList<String> info = event.getRight();
info.add("");

View file

@ -2,9 +2,9 @@ package com.jozufozu.flywheel.backend.engine.batching;
import org.jetbrains.annotations.NotNull;
import org.joml.FrustumIntersection;
import org.joml.Matrix4f;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.lib.math.MatrixUtil;
import com.jozufozu.flywheel.lib.util.FlwUtil;
import com.mojang.blaze3d.vertex.PoseStack;
@ -20,9 +20,9 @@ public record BatchContext(FrustumIntersection frustum, ClientLevel level, PoseS
var stack = FlwUtil.copyPoseStack(context.stack());
stack.translate(origin.getX() - cameraPos.x, origin.getY() - cameraPos.y, origin.getZ() - cameraPos.z);
org.joml.Matrix4f proj = MatrixUtil.toJoml(context.viewProjection());
proj.translate((float) (origin.getX() - cameraPos.x), (float) (origin.getY() - cameraPos.y), (float) (origin.getZ() - cameraPos.z));
Matrix4f viewProjection = new Matrix4f(context.viewProjection());
viewProjection.translate((float) (origin.getX() - cameraPos.x), (float) (origin.getY() - cameraPos.y), (float) (origin.getZ() - cameraPos.z));
return new BatchContext(new FrustumIntersection(proj), context.level(), stack.last());
return new BatchContext(new FrustumIntersection(viewProjection), context.level(), stack.last());
}
}

View file

@ -1,6 +1,26 @@
package com.jozufozu.flywheel.impl.visualization;
import org.jetbrains.annotations.NotNull;
import org.joml.FrustumIntersection;
import org.joml.Matrix4f;
import com.jozufozu.flywheel.api.event.RenderContext;
import net.minecraft.core.Vec3i;
public record FrameContext(double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum, float partialTick) {
@NotNull
public static FrameContext create(RenderContext context, Vec3i renderOrigin, float partialTick) {
var cameraPos = context.camera()
.getPosition();
double cameraX = cameraPos.x;
double cameraY = cameraPos.y;
double cameraZ = cameraPos.z;
Matrix4f viewProjection = new Matrix4f(context.viewProjection());
viewProjection.translate((float) (renderOrigin.getX() - cameraX), (float) (renderOrigin.getY() - cameraY), (float) (renderOrigin.getZ() - cameraZ));
FrustumIntersection frustum = new FrustumIntersection(viewProjection);
return new FrameContext(cameraX, cameraY, cameraZ, frustum, partialTick);
}
}

View file

@ -1,7 +1,6 @@
package com.jozufozu.flywheel.impl.visualization;
import org.jetbrains.annotations.Nullable;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.backend.BackendManager;
import com.jozufozu.flywheel.api.backend.Engine;
@ -20,7 +19,6 @@ import com.jozufozu.flywheel.impl.task.FlwTaskExecutor;
import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager;
import com.jozufozu.flywheel.impl.visualization.manager.EffectVisualManager;
import com.jozufozu.flywheel.impl.visualization.manager.EntityVisualManager;
import com.jozufozu.flywheel.lib.math.MatrixUtil;
import com.jozufozu.flywheel.lib.task.Flag;
import com.jozufozu.flywheel.lib.task.NamedFlag;
import com.jozufozu.flywheel.lib.task.NestedPlan;
@ -213,18 +211,7 @@ public class VisualizationManagerImpl implements VisualizationManager {
if (engine.updateRenderOrigin(context.camera())) {
recreationPlan.execute(taskExecutor, partialTick, then);
} else {
Vec3i renderOrigin = engine.renderOrigin();
var cameraPos = context.camera()
.getPosition();
double cameraX = cameraPos.x;
double cameraY = cameraPos.y;
double cameraZ = cameraPos.z;
org.joml.Matrix4f proj = MatrixUtil.toJoml(context.viewProjection());
proj.translate((float) (renderOrigin.getX() - cameraX), (float) (renderOrigin.getY() - cameraY), (float) (renderOrigin.getZ() - cameraZ));
FrustumIntersection frustum = new FrustumIntersection(proj);
var frameContext = new FrameContext(cameraX, cameraY, cameraZ, frustum, partialTick);
var frameContext = FrameContext.create(context, engine.renderOrigin(), partialTick);
normalPlan.execute(taskExecutor, frameContext, then);
}

View file

@ -10,11 +10,12 @@ import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.NestedPlan;
import com.jozufozu.flywheel.lib.task.SimplyComposedPlan;
import com.jozufozu.flywheel.lib.task.UnitPlan;
public class VisualUpdatePlan<C> implements SimplyComposedPlan<C> {
private final Supplier<List<Plan<C>>> initializer;
@Nullable
private Plan<C> plan;
@NotNull
private Plan<C> plan = UnitPlan.of();
private boolean initialized = false;
private boolean needsSimplify = true;
@ -28,24 +29,15 @@ public class VisualUpdatePlan<C> implements SimplyComposedPlan<C> {
}
public void add(Plan<C> plan) {
if (this.plan == null) {
this.plan = plan;
} else {
this.plan = this.plan.and(plan);
}
this.plan = this.plan.and(plan);
needsSimplify = true;
}
@NotNull
private Plan<C> updatePlans() {
if (!initialized) {
Plan<C> mainPlan = new NestedPlan<>(initializer.get());
if (plan != null) {
plan = mainPlan.and(plan);
} else {
plan = mainPlan;
}
plan = mainPlan.and(plan);
plan = plan.simplify();
initialized = true;
} else if (needsSimplify) {
@ -57,7 +49,7 @@ public class VisualUpdatePlan<C> implements SimplyComposedPlan<C> {
}
public void clear() {
plan = null;
plan = UnitPlan.of();
initialized = false;
}
}

View file

@ -7,6 +7,7 @@ import com.jozufozu.flywheel.api.instance.InstanceHandle;
import com.jozufozu.flywheel.api.instance.InstanceType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
public class OrientedInstance extends ColoredLitInstance {
public float posX;
@ -15,10 +16,7 @@ public class OrientedInstance extends ColoredLitInstance {
public float pivotX = 0.5f;
public float pivotY = 0.5f;
public float pivotZ = 0.5f;
public float qX;
public float qY;
public float qZ;
public float qW = 1;
public final Quaternionf rotation = new Quaternionf();
public OrientedInstance(InstanceType<? extends OrientedInstance> type, InstanceHandle handle) {
super(type, handle);
@ -49,11 +47,11 @@ public class OrientedInstance extends ColoredLitInstance {
}
public OrientedInstance setPivot(Vector3f pos) {
return setPosition(pos.x(), pos.y(), pos.z());
return setPivot(pos.x(), pos.y(), pos.z());
}
public OrientedInstance setPivot(net.minecraft.world.phys.Vec3 pos) {
return setPosition((float) pos.x(), (float) pos.y(), (float) pos.z());
public OrientedInstance setPivot(Vec3 pos) {
return setPivot((float) pos.x(), (float) pos.y(), (float) pos.z());
}
public OrientedInstance setPivot(float x, float y, float z) {
@ -65,23 +63,19 @@ public class OrientedInstance extends ColoredLitInstance {
}
public OrientedInstance setRotation(Quaternionf q) {
return setRotation(q.x, q.y, q.z, q.w);
rotation.set(q);
setChanged();
return this;
}
public OrientedInstance setRotation(float x, float y, float z, float w) {
this.qX = x;
this.qY = y;
this.qZ = z;
this.qW = w;
rotation.set(x, y, z, w);
setChanged();
return this;
}
public OrientedInstance resetRotation() {
this.qX = 0;
this.qY = 0;
this.qZ = 0;
this.qW = 1;
rotation.identity();
setChanged();
return this;
}

View file

@ -48,15 +48,13 @@ public class OrientedType implements InstanceType<OrientedInstance> {
@Override
public InstanceVertexTransformer<OrientedInstance> getVertexTransformer() {
return (vertexList, instance) -> {
Quaternionf q = new Quaternionf(instance.qX, instance.qY, instance.qZ, instance.qW);
Matrix4f modelMatrix = new Matrix4f();
modelMatrix.translate(instance.posX + instance.pivotX, instance.posY + instance.pivotY, instance.posZ + instance.pivotZ);
modelMatrix.rotate(q);
modelMatrix.rotate(instance.rotation);
modelMatrix.translate(-instance.pivotX, -instance.pivotY, -instance.pivotZ);
Matrix3f normalMatrix = new Matrix3f();
normalMatrix.set(q);
normalMatrix.set(instance.rotation);
float r = RenderMath.uf(instance.r);
float g = RenderMath.uf(instance.g);
@ -81,7 +79,7 @@ public class OrientedType implements InstanceType<OrientedInstance> {
public InstanceBoundingSphereTransformer<OrientedInstance> getBoundingSphereTransformer() {
return (boundingSphere, instance) -> {
boundingSphere.sub(instance.pivotX, instance.pivotY, instance.pivotZ, 0);
boundingSphere.rotate(new Quaternionf(instance.qX, instance.qY, instance.qZ, instance.qW));
boundingSphere.rotate(instance.rotation);
boundingSphere.add(instance.posX + instance.pivotX, instance.posY + instance.pivotY, instance.posZ + instance.pivotZ, 0);
};
}

View file

@ -15,10 +15,10 @@ public class OrientedWriter extends ColoredLitWriter<OrientedInstance> {
MemoryUtil.memPutFloat(ptr + 20, instance.pivotX);
MemoryUtil.memPutFloat(ptr + 24, instance.pivotY);
MemoryUtil.memPutFloat(ptr + 28, instance.pivotZ);
MemoryUtil.memPutFloat(ptr + 32, instance.qX);
MemoryUtil.memPutFloat(ptr + 36, instance.qY);
MemoryUtil.memPutFloat(ptr + 40, instance.qZ);
MemoryUtil.memPutFloat(ptr + 44, instance.qW);
MemoryUtil.memPutFloat(ptr + 32, instance.rotation.x);
MemoryUtil.memPutFloat(ptr + 36, instance.rotation.y);
MemoryUtil.memPutFloat(ptr + 40, instance.rotation.z);
MemoryUtil.memPutFloat(ptr + 44, instance.rotation.w);
}
}

View file

@ -68,7 +68,7 @@ public class TransformedType implements InstanceType<TransformedInstance> {
return (boundingSphere, instance) -> {
var radius = boundingSphere.w;
boundingSphere.w = 1;
boundingSphere.mul(MatrixUtil.toJoml(instance.model));
boundingSphere.mul(instance.model);
boundingSphere.w = radius * MatrixUtil.extractScale(instance.model);
};
}

View file

@ -73,22 +73,6 @@ public final class MatrixUtil {
MemoryUtil.memPutFloat(ptr + 32, matrix.m22());
}
public static void store(Matrix4f matrix, Matrix4f jomlMatrix) {
jomlMatrix.set(matrix);
}
public static Matrix4f toJoml(Matrix4f matrix) {
return new Matrix4f(matrix);
}
public static void store(Matrix3f matrix, org.joml.Matrix3f jomlMatrix) {
jomlMatrix.set(matrix);
}
public static Matrix3f toJoml(Matrix3f matrix) {
return new Matrix3f(matrix);
}
/**
* Extracts the greatest scale factor across all axes from the given matrix.
*

View file

@ -49,6 +49,8 @@ public class FlwShaderUniforms implements ShaderUniforms {
private boolean dirty;
private final Matrix4f viewProjection = new Matrix4f();
public Active(long ptr) {
this.ptr = ptr;
MinecraftForge.EVENT_BUS.addListener(this);
@ -83,18 +85,20 @@ public class FlwShaderUniforms implements ShaderUniforms {
var camY = (float) (camera.y - renderOrigin.getY());
var camZ = (float) (camera.z - renderOrigin.getZ());
// don't want to mutate viewProjection
var vp = new Matrix4f(context.viewProjection());
vp.translate(-camX, -camY, -camZ);
viewProjection.set(context.viewProjection());
viewProjection.translate(-camX, -camY, -camZ);
MatrixUtil.writeUnsafe(vp, ptr + 32);
MatrixUtil.writeUnsafe(viewProjection, ptr + 32);
MemoryUtil.memPutFloat(ptr + 96, camX);
MemoryUtil.memPutFloat(ptr + 100, camY);
MemoryUtil.memPutFloat(ptr + 104, camZ);
MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment
MemoryUtil.memPutInt(ptr + 112, getConstantAmbientLightFlag(context));
updateFrustum(context, camX, camY, camZ);
if (!FRUSTUM_PAUSED || FRUSTUM_CAPTURE) {
MoreMath.writePackedFrustumPlanes(ptr + 128, viewProjection);
FRUSTUM_CAPTURE = false;
}
dirty = true;
}
@ -127,17 +131,5 @@ public class FlwShaderUniforms implements ShaderUniforms {
return true;
}
private void updateFrustum(RenderContext context, float camX, float camY, float camZ) {
if (FRUSTUM_PAUSED && !FRUSTUM_CAPTURE) {
return;
}
var projection = MatrixUtil.toJoml(context.viewProjection());
projection.translate(-camX, -camY, -camZ);
MoreMath.writePackedFrustumPlanes(ptr + 128, projection);
FRUSTUM_CAPTURE = false;
}
}
}

View file

@ -1,27 +0,0 @@
package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.main.Main;
@Mixin(Main.class)
public class ClientMainMixin {
@Inject(method = "main([Ljava/lang/String;)V", at = @At("HEAD"))
private static void flywheel$injectRenderDoc(CallbackInfo ci) {
// Only try to load RenderDoc if a system property is set to true.
if (System.getProperty("flw.loadRenderDoc") == null) {
return;
}
try {
System.loadLibrary("renderdoc");
} catch (Throwable ignored) {
// Oh well, we tried.
// On Windows, RenderDoc installs to "C:\Program Files\RenderDoc\"
System.err.println("Is RenderDoc in your PATH?");
}
}
}

View file

@ -8,7 +8,6 @@
"BlockEntityTypeMixin",
"BufferBuilderMixin",
"ClientLevelMixin",
"ClientMainMixin",
"EntityTypeMixin",
"FogUpdateMixin",
"GlStateManagerMixin",