418 lines
15 KiB
Java
418 lines
15 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.mojang.logging.LogUtils
|
|
* it.unimi.dsi.fastutil.ints.IntConsumer
|
|
* org.joml.Matrix4f
|
|
* org.joml.Matrix4fStack
|
|
* org.jspecify.annotations.Nullable
|
|
* org.lwjgl.glfw.GLFW
|
|
* org.lwjgl.glfw.GLFWErrorCallbackI
|
|
* org.lwjgl.system.MemoryUtil
|
|
* org.slf4j.Logger
|
|
*/
|
|
package com.mojang.blaze3d.systems;
|
|
|
|
import com.mojang.blaze3d.ProjectionType;
|
|
import com.mojang.blaze3d.TracyFrameCapture;
|
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
|
import com.mojang.blaze3d.buffers.GpuFence;
|
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
|
import com.mojang.blaze3d.opengl.GlDevice;
|
|
import com.mojang.blaze3d.platform.GLX;
|
|
import com.mojang.blaze3d.platform.Window;
|
|
import com.mojang.blaze3d.shaders.ShaderSource;
|
|
import com.mojang.blaze3d.systems.GpuDevice;
|
|
import com.mojang.blaze3d.systems.RenderPass;
|
|
import com.mojang.blaze3d.systems.SamplerCache;
|
|
import com.mojang.blaze3d.systems.ScissorState;
|
|
import com.mojang.blaze3d.textures.GpuTextureView;
|
|
import com.mojang.blaze3d.vertex.Tesselator;
|
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
|
import com.mojang.logging.LogUtils;
|
|
import it.unimi.dsi.fastutil.ints.IntConsumer;
|
|
import java.nio.Buffer;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Locale;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.renderer.DynamicUniforms;
|
|
import net.minecraft.util.ArrayListDeque;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.TimeSource;
|
|
import net.minecraft.util.Util;
|
|
import org.joml.Matrix4f;
|
|
import org.joml.Matrix4fStack;
|
|
import org.jspecify.annotations.Nullable;
|
|
import org.lwjgl.glfw.GLFW;
|
|
import org.lwjgl.glfw.GLFWErrorCallbackI;
|
|
import org.lwjgl.system.MemoryUtil;
|
|
import org.slf4j.Logger;
|
|
|
|
public class RenderSystem {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
public static final int MINIMUM_ATLAS_TEXTURE_SIZE = 1024;
|
|
public static final int PROJECTION_MATRIX_UBO_SIZE = new Std140SizeCalculator().putMat4f().get();
|
|
private static @Nullable Thread renderThread;
|
|
private static @Nullable GpuDevice DEVICE;
|
|
private static double lastDrawTime;
|
|
private static final AutoStorageIndexBuffer sharedSequential;
|
|
private static final AutoStorageIndexBuffer sharedSequentialQuad;
|
|
private static final AutoStorageIndexBuffer sharedSequentialLines;
|
|
private static ProjectionType projectionType;
|
|
private static ProjectionType savedProjectionType;
|
|
private static final Matrix4fStack modelViewStack;
|
|
private static @Nullable GpuBufferSlice shaderFog;
|
|
private static @Nullable GpuBufferSlice shaderLightDirections;
|
|
private static @Nullable GpuBufferSlice projectionMatrixBuffer;
|
|
private static @Nullable GpuBufferSlice savedProjectionMatrixBuffer;
|
|
private static String apiDescription;
|
|
private static final AtomicLong pollEventsWaitStart;
|
|
private static final AtomicBoolean pollingEvents;
|
|
private static final ArrayListDeque<GpuAsyncTask> PENDING_FENCES;
|
|
public static @Nullable GpuTextureView outputColorTextureOverride;
|
|
public static @Nullable GpuTextureView outputDepthTextureOverride;
|
|
private static @Nullable GpuBuffer globalSettingsUniform;
|
|
private static @Nullable DynamicUniforms dynamicUniforms;
|
|
private static final ScissorState scissorStateForRenderTypeDraws;
|
|
private static SamplerCache samplerCache;
|
|
|
|
public static SamplerCache getSamplerCache() {
|
|
return samplerCache;
|
|
}
|
|
|
|
public static void initRenderThread() {
|
|
if (renderThread != null) {
|
|
throw new IllegalStateException("Could not initialize render thread");
|
|
}
|
|
renderThread = Thread.currentThread();
|
|
}
|
|
|
|
public static boolean isOnRenderThread() {
|
|
return Thread.currentThread() == renderThread;
|
|
}
|
|
|
|
public static void assertOnRenderThread() {
|
|
if (!RenderSystem.isOnRenderThread()) {
|
|
throw RenderSystem.constructThreadException();
|
|
}
|
|
}
|
|
|
|
private static IllegalStateException constructThreadException() {
|
|
return new IllegalStateException("Rendersystem called from wrong thread");
|
|
}
|
|
|
|
private static void pollEvents() {
|
|
pollEventsWaitStart.set(Util.getMillis());
|
|
pollingEvents.set(true);
|
|
GLFW.glfwPollEvents();
|
|
pollingEvents.set(false);
|
|
}
|
|
|
|
public static boolean isFrozenAtPollEvents() {
|
|
return pollingEvents.get() && Util.getMillis() - pollEventsWaitStart.get() > 200L;
|
|
}
|
|
|
|
public static void flipFrame(Window window, @Nullable TracyFrameCapture tracyFrameCapture) {
|
|
RenderSystem.pollEvents();
|
|
Tesselator.getInstance().clear();
|
|
GLFW.glfwSwapBuffers((long)window.handle());
|
|
if (tracyFrameCapture != null) {
|
|
tracyFrameCapture.endFrame();
|
|
}
|
|
dynamicUniforms.reset();
|
|
Minecraft.getInstance().levelRenderer.endFrame();
|
|
RenderSystem.pollEvents();
|
|
}
|
|
|
|
public static void limitDisplayFPS(int framerateLimit) {
|
|
double targetTime = lastDrawTime + 1.0 / (double)framerateLimit;
|
|
double drawTime = GLFW.glfwGetTime();
|
|
while (drawTime < targetTime) {
|
|
GLFW.glfwWaitEventsTimeout((double)(targetTime - drawTime));
|
|
drawTime = GLFW.glfwGetTime();
|
|
}
|
|
lastDrawTime = drawTime;
|
|
}
|
|
|
|
public static void setShaderFog(GpuBufferSlice fog) {
|
|
shaderFog = fog;
|
|
}
|
|
|
|
public static @Nullable GpuBufferSlice getShaderFog() {
|
|
return shaderFog;
|
|
}
|
|
|
|
public static void setShaderLights(GpuBufferSlice buffer) {
|
|
shaderLightDirections = buffer;
|
|
}
|
|
|
|
public static @Nullable GpuBufferSlice getShaderLights() {
|
|
return shaderLightDirections;
|
|
}
|
|
|
|
public static void enableScissorForRenderTypeDraws(int x, int y, int width, int height) {
|
|
scissorStateForRenderTypeDraws.enable(x, y, width, height);
|
|
}
|
|
|
|
public static void disableScissorForRenderTypeDraws() {
|
|
scissorStateForRenderTypeDraws.disable();
|
|
}
|
|
|
|
public static ScissorState getScissorStateForRenderTypeDraws() {
|
|
return scissorStateForRenderTypeDraws;
|
|
}
|
|
|
|
public static String getBackendDescription() {
|
|
return String.format(Locale.ROOT, "LWJGL version %s", GLX._getLWJGLVersion());
|
|
}
|
|
|
|
public static String getApiDescription() {
|
|
return apiDescription;
|
|
}
|
|
|
|
public static TimeSource.NanoTimeSource initBackendSystem() {
|
|
return GLX._initGlfw()::getAsLong;
|
|
}
|
|
|
|
public static void initRenderer(long windowHandle, int logVerbosity, boolean synchronousLogs, ShaderSource shaderSource, boolean wantsDebugLabels) {
|
|
DEVICE = new GlDevice(windowHandle, logVerbosity, synchronousLogs, shaderSource, wantsDebugLabels);
|
|
apiDescription = RenderSystem.getDevice().getImplementationInformation();
|
|
dynamicUniforms = new DynamicUniforms();
|
|
samplerCache.initialize();
|
|
}
|
|
|
|
public static void setErrorCallback(GLFWErrorCallbackI onFullscreenError) {
|
|
GLX._setGlfwErrorCallback(onFullscreenError);
|
|
}
|
|
|
|
public static void setupDefaultState() {
|
|
modelViewStack.clear();
|
|
}
|
|
|
|
public static void setProjectionMatrix(GpuBufferSlice projectionMatrixBuffer, ProjectionType type) {
|
|
RenderSystem.assertOnRenderThread();
|
|
RenderSystem.projectionMatrixBuffer = projectionMatrixBuffer;
|
|
projectionType = type;
|
|
}
|
|
|
|
public static void backupProjectionMatrix() {
|
|
RenderSystem.assertOnRenderThread();
|
|
savedProjectionMatrixBuffer = projectionMatrixBuffer;
|
|
savedProjectionType = projectionType;
|
|
}
|
|
|
|
public static void restoreProjectionMatrix() {
|
|
RenderSystem.assertOnRenderThread();
|
|
projectionMatrixBuffer = savedProjectionMatrixBuffer;
|
|
projectionType = savedProjectionType;
|
|
}
|
|
|
|
public static @Nullable GpuBufferSlice getProjectionMatrixBuffer() {
|
|
RenderSystem.assertOnRenderThread();
|
|
return projectionMatrixBuffer;
|
|
}
|
|
|
|
public static Matrix4f getModelViewMatrix() {
|
|
RenderSystem.assertOnRenderThread();
|
|
return modelViewStack;
|
|
}
|
|
|
|
public static Matrix4fStack getModelViewStack() {
|
|
RenderSystem.assertOnRenderThread();
|
|
return modelViewStack;
|
|
}
|
|
|
|
public static AutoStorageIndexBuffer getSequentialBuffer(VertexFormat.Mode primitiveMode) {
|
|
RenderSystem.assertOnRenderThread();
|
|
return switch (primitiveMode) {
|
|
case VertexFormat.Mode.QUADS -> sharedSequentialQuad;
|
|
case VertexFormat.Mode.LINES -> sharedSequentialLines;
|
|
default -> sharedSequential;
|
|
};
|
|
}
|
|
|
|
public static void setGlobalSettingsUniform(GpuBuffer buffer) {
|
|
globalSettingsUniform = buffer;
|
|
}
|
|
|
|
public static @Nullable GpuBuffer getGlobalSettingsUniform() {
|
|
return globalSettingsUniform;
|
|
}
|
|
|
|
public static ProjectionType getProjectionType() {
|
|
RenderSystem.assertOnRenderThread();
|
|
return projectionType;
|
|
}
|
|
|
|
public static void queueFencedTask(Runnable task) {
|
|
PENDING_FENCES.addLast(new GpuAsyncTask(task, RenderSystem.getDevice().createCommandEncoder().createFence()));
|
|
}
|
|
|
|
public static void executePendingTasks() {
|
|
GpuAsyncTask task = PENDING_FENCES.peekFirst();
|
|
while (task != null) {
|
|
if (task.fence.awaitCompletion(0L)) {
|
|
try {
|
|
task.callback.run();
|
|
}
|
|
finally {
|
|
task.fence.close();
|
|
}
|
|
PENDING_FENCES.removeFirst();
|
|
task = PENDING_FENCES.peekFirst();
|
|
continue;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
public static GpuDevice getDevice() {
|
|
if (DEVICE == null) {
|
|
throw new IllegalStateException("Can't getDevice() before it was initialized");
|
|
}
|
|
return DEVICE;
|
|
}
|
|
|
|
public static @Nullable GpuDevice tryGetDevice() {
|
|
return DEVICE;
|
|
}
|
|
|
|
public static DynamicUniforms getDynamicUniforms() {
|
|
if (dynamicUniforms == null) {
|
|
throw new IllegalStateException("Can't getDynamicUniforms() before device was initialized");
|
|
}
|
|
return dynamicUniforms;
|
|
}
|
|
|
|
public static void bindDefaultUniforms(RenderPass renderPass) {
|
|
GpuBufferSlice shaderLights;
|
|
GpuBuffer globalUniform;
|
|
GpuBufferSlice fog;
|
|
GpuBufferSlice projectionMatrix = RenderSystem.getProjectionMatrixBuffer();
|
|
if (projectionMatrix != null) {
|
|
renderPass.setUniform("Projection", projectionMatrix);
|
|
}
|
|
if ((fog = RenderSystem.getShaderFog()) != null) {
|
|
renderPass.setUniform("Fog", fog);
|
|
}
|
|
if ((globalUniform = RenderSystem.getGlobalSettingsUniform()) != null) {
|
|
renderPass.setUniform("Globals", globalUniform);
|
|
}
|
|
if ((shaderLights = RenderSystem.getShaderLights()) != null) {
|
|
renderPass.setUniform("Lighting", shaderLights);
|
|
}
|
|
}
|
|
|
|
static {
|
|
lastDrawTime = Double.MIN_VALUE;
|
|
sharedSequential = new AutoStorageIndexBuffer(1, 1, java.util.function.IntConsumer::accept);
|
|
sharedSequentialQuad = new AutoStorageIndexBuffer(4, 6, (c, i) -> {
|
|
c.accept(i);
|
|
c.accept(i + 1);
|
|
c.accept(i + 2);
|
|
c.accept(i + 2);
|
|
c.accept(i + 3);
|
|
c.accept(i);
|
|
});
|
|
sharedSequentialLines = new AutoStorageIndexBuffer(4, 6, (c, i) -> {
|
|
c.accept(i);
|
|
c.accept(i + 1);
|
|
c.accept(i + 2);
|
|
c.accept(i + 3);
|
|
c.accept(i + 2);
|
|
c.accept(i + 1);
|
|
});
|
|
projectionType = ProjectionType.PERSPECTIVE;
|
|
savedProjectionType = ProjectionType.PERSPECTIVE;
|
|
modelViewStack = new Matrix4fStack(16);
|
|
shaderFog = null;
|
|
apiDescription = "Unknown";
|
|
pollEventsWaitStart = new AtomicLong();
|
|
pollingEvents = new AtomicBoolean(false);
|
|
PENDING_FENCES = new ArrayListDeque();
|
|
scissorStateForRenderTypeDraws = new ScissorState();
|
|
samplerCache = new SamplerCache();
|
|
}
|
|
|
|
public static final class AutoStorageIndexBuffer {
|
|
private final int vertexStride;
|
|
private final int indexStride;
|
|
private final IndexGenerator generator;
|
|
private @Nullable GpuBuffer buffer;
|
|
private VertexFormat.IndexType type = VertexFormat.IndexType.SHORT;
|
|
private int indexCount;
|
|
|
|
private AutoStorageIndexBuffer(int vertexStride, int indexStride, IndexGenerator generator) {
|
|
this.vertexStride = vertexStride;
|
|
this.indexStride = indexStride;
|
|
this.generator = generator;
|
|
}
|
|
|
|
public boolean hasStorage(int indexCount) {
|
|
return indexCount <= this.indexCount;
|
|
}
|
|
|
|
public GpuBuffer getBuffer(int indexCount) {
|
|
this.ensureStorage(indexCount);
|
|
return this.buffer;
|
|
}
|
|
|
|
/*
|
|
* WARNING - Removed try catching itself - possible behaviour change.
|
|
*/
|
|
private void ensureStorage(int indexCount) {
|
|
if (this.hasStorage(indexCount)) {
|
|
return;
|
|
}
|
|
indexCount = Mth.roundToward(indexCount * 2, this.indexStride);
|
|
LOGGER.debug("Growing IndexBuffer: Old limit {}, new limit {}.", (Object)this.indexCount, (Object)indexCount);
|
|
int primitiveCount = indexCount / this.indexStride;
|
|
int vertexCount = primitiveCount * this.vertexStride;
|
|
VertexFormat.IndexType type = VertexFormat.IndexType.least(vertexCount);
|
|
int bufferSize = Mth.roundToward(indexCount * type.bytes, 4);
|
|
ByteBuffer data = MemoryUtil.memAlloc((int)bufferSize);
|
|
try {
|
|
this.type = type;
|
|
IntConsumer intConsumer = this.intConsumer(data);
|
|
for (int ii = 0; ii < indexCount; ii += this.indexStride) {
|
|
this.generator.accept(intConsumer, ii * this.vertexStride / this.indexStride);
|
|
}
|
|
data.flip();
|
|
if (this.buffer != null) {
|
|
this.buffer.close();
|
|
}
|
|
this.buffer = RenderSystem.getDevice().createBuffer(() -> "Auto Storage index buffer", 64, data);
|
|
}
|
|
finally {
|
|
MemoryUtil.memFree((Buffer)data);
|
|
}
|
|
this.indexCount = indexCount;
|
|
}
|
|
|
|
private IntConsumer intConsumer(ByteBuffer buffer) {
|
|
switch (this.type) {
|
|
case SHORT: {
|
|
return value -> buffer.putShort((short)value);
|
|
}
|
|
}
|
|
return buffer::putInt;
|
|
}
|
|
|
|
public VertexFormat.IndexType type() {
|
|
return this.type;
|
|
}
|
|
|
|
private static interface IndexGenerator {
|
|
public void accept(IntConsumer var1, int var2);
|
|
}
|
|
}
|
|
|
|
record GpuAsyncTask(Runnable callback, GpuFence fence) {
|
|
}
|
|
}
|
|
|