/* * 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 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) { } }