Merge branch 'main' of https://gitlab.com/jeseibel/distant-horizons-core into refactor/remove-tcp-connection

This commit is contained in:
s809
2024-06-09 21:18:08 +05:00
16 changed files with 141 additions and 499 deletions
@@ -1,14 +1,41 @@
package com.seibel.distanthorizons.api.enums.config;
import com.seibel.distanthorizons.coreapi.ModInfo;
/**
* AUTO, <br>
* STABLE, <br>
* NIGHTLY, <br><br>
*
* @since API 2.0.0
* @version 2024-4-6
* @since API 2.1.0
* @version 2024-6-8
*/
public enum EDhApiUpdateBranch
{
AUTO,
STABLE,
NIGHTLY
NIGHTLY;
/**
* If the updateBranch value is {@link EDhApiUpdateBranch#AUTO}
* this method will convert it either to {@link EDhApiUpdateBranch#STABLE} or {@link EDhApiUpdateBranch#NIGHTLY}
* based on this jar's state. <Br><br>
*
* If updateBranch is {@link EDhApiUpdateBranch#STABLE} or {@link EDhApiUpdateBranch#NIGHTLY}
* it just returns.
*/
public static EDhApiUpdateBranch convertAutoToStableOrNightly(EDhApiUpdateBranch updateBranch)
{
if (updateBranch != EDhApiUpdateBranch.AUTO)
{
return updateBranch;
}
else
{
return ModInfo.IS_DEV_BUILD ? EDhApiUpdateBranch.NIGHTLY : EDhApiUpdateBranch.STABLE;
}
}
}
@@ -42,7 +42,7 @@ public final class ModInfo
public static final String NAME = "DistantHorizons";
/** Human-readable version of NAME */
public static final String READABLE_NAME = "Distant Horizons";
public static final String VERSION = "2.0.4-a-dev";
public static final String VERSION = "2.1.1-a-dev";
/** Returns true if the current build is an unstable developer build, false otherwise. */
public static boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
@@ -1118,16 +1118,6 @@ public class Config
+ "")
.build();
public static ConfigEntry<Boolean> gpuUploadAsync = new ConfigEntry.Builder<Boolean>()
.set(true)
.comment(""
+ "If true geometry data will be uploaded on a DH controlled thread, reducing FPS stuttering. \n"
+ "If false uploading will be done on Minecraft's main rendering thread. \n"
+ "\n"
+ "Setting this to false may reduce crashes or corrupted geometry on systems with an AMD GPU when Sodium is installed.\n"
+ "")
.build();
}
public static class AutoUpdater
@@ -1147,11 +1137,12 @@ public class Config
.build();
public static ConfigEntry<EDhApiUpdateBranch> updateBranch = new ConfigEntry.Builder<EDhApiUpdateBranch>()
.set(
ModInfo.IS_DEV_BUILD ? EDhApiUpdateBranch.NIGHTLY : EDhApiUpdateBranch.STABLE // If it's already a nightly build, then download the nightly build ofc
)
.set(EDhApiUpdateBranch.AUTO)
.comment(""
+ " If DH should use the nightly (provided by Gitlab), or stable (provided by Modrinth) build")
+ "If DH should use the nightly (provided by Gitlab), or stable (provided by Modrinth) build. \n"
+ "If ["+EDhApiUpdateBranch.AUTO+"] is selected DH will update to new stable releases if the current jar is a stable jar \n"
+ "and will update to new nightly builds if the current jar is a nightly jar (IE the version number ends in '-dev')."
+ "")
.build();
}
@@ -271,7 +271,11 @@ public class ConfigFileHandling
if (SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class).isDedicatedServer() && entry.getServersideShortName() == null)
return;
nightConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n ");
String comment = entry.getComment().replaceAll("\n", "\n ").trim();
// the new line makes it easier to read and separate configs
// the space makes sure the first word of a comment isn't directly in line with the "#"
comment = "\n " + comment;
nightConfig.setComment(entry.getNameWCategory(), comment);
}
@@ -393,4 +397,4 @@ public class ConfigFileHandling
}
}
*/
}
}
@@ -82,8 +82,7 @@ public class OpenGLConfigScreen extends AbstractScreen
private void createBuffer()
{
GLProxy.getInstance().recordOpenGlCall(() -> sharedContextBuffer = createTextingBuffer());
GLProxy.ensureAllGLJobCompleted();
sharedContextBuffer = createTextingBuffer();
sameContextBuffer = createTextingBuffer();
}
@@ -22,7 +22,6 @@ package com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.EGLProxyContext;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
@@ -92,58 +91,36 @@ public class ColumnRenderBuffer implements AutoCloseable
LodUtil.assertTrue(Thread.currentThread().getName().startsWith(ThreadUtil.THREAD_NAME_PREFIX), "Buffer uploading needs to be done on a DH thread to prevent locking up any MC threads.");
// the async is relative to MC's render thread
boolean uploadAsync = Config.Client.Advanced.GpuBuffers.gpuUploadAsync.get();
if (uploadAsync)
// upload on MC's render thread
CompletableFuture<Void> uploadFuture = new CompletableFuture<>();
minecraftClient.executeOnRenderThread(() ->
{
// upload here on a DH thread
GLProxy glProxy = GLProxy.getInstance();
EGLProxyContext oldContext = glProxy.getGlContext();
glProxy.setGlContext(EGLProxyContext.LOD_BUILDER);
try
{
this.uploadBuffersUsingUploadMethod(builder, gpuUploadMethod);
uploadFuture.complete(null);
}
finally
catch (InterruptedException e)
{
glProxy.setGlContext(oldContext);
throw new CompletionException(e);
}
}
else
});
try
{
// upload on MC's render thread
CompletableFuture<Void> uploadFuture = new CompletableFuture<>();
minecraftClient.executeOnRenderThread(() ->
{
try
{
this.uploadBuffersUsingUploadMethod(builder, gpuUploadMethod);
uploadFuture.complete(null);
}
catch (InterruptedException e)
{
throw new CompletionException(e);
}
});
try
{
// wait for the upload to finish
uploadFuture.get(1000, TimeUnit.MILLISECONDS);
}
catch (ExecutionException e)
{
LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e);
}
catch (TimeoutException e)
{
// timeouts can be ignored because it generally means the
// MC Render thread executor was closed
//LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e);
}
// wait for the upload to finish
uploadFuture.get(5_000, TimeUnit.MILLISECONDS);
}
catch (ExecutionException e)
{
LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e);
}
catch (TimeoutException e)
{
// timeouts can be ignored because it generally means the
// MC Render thread executor was closed
//LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e);
}
}
private void uploadBuffersUsingUploadMethod(LodQuadBuilder builder, EDhApiGpuUploadMethod gpuUploadMethod) throws InterruptedException
@@ -403,7 +380,7 @@ public class ColumnRenderBuffer implements AutoCloseable
{
if (buffer != null)
{
buffer.destroy(false);
buffer.destroyAsync();
}
}
@@ -411,7 +388,7 @@ public class ColumnRenderBuffer implements AutoCloseable
{
if (buffer != null)
{
buffer.destroy(false);
buffer.destroyAsync();
}
}
});
@@ -1,44 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.enums;
/**
* Minecraft, <br>
* Lod_Builder, <br>
* Proxy_Worker, <br>
* None <br>
*
* @author James Seibel
* @version 10-1-2021
*/
public enum EGLProxyContext
{
/** Minecraft's render thread */
MINECRAFT,
/** The context we send buffers to the GPU on */
LOD_BUILDER,
/** A context that can be used for miscellaneous tasks, owned by the GLProxy */
PROXY_WORKER,
/** used to un-bind threads */
NONE,
}
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.core.jar.updater;
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.JarUtils;
@@ -83,15 +84,8 @@ public class SelfUpdater
boolean returnValue = false;
try
{
switch (Config.Client.Advanced.AutoUpdater.updateBranch.get())
{
case STABLE:
returnValue = onStableStart();
break;
case NIGHTLY:
returnValue = onNightlyStart();
break;
};
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
returnValue = (updateBranch == EDhApiUpdateBranch.STABLE) ? onStableStart() : onNightlyStart();
}
catch (Exception e) // Shouldn't be needed, but just in case
{
@@ -19,22 +19,17 @@
package com.seibel.distanthorizons.core.render.glObject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
import com.seibel.distanthorizons.api.enums.config.EDhApiGlProfileMode;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.EGLProxyContext;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ReflectionUtil;
import com.seibel.distanthorizons.core.util.objects.GLMessage;
import com.seibel.distanthorizons.core.util.objects.GLMessageOutputStream;
import com.seibel.distanthorizons.core.util.objects.Pair;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.coreapi.util.StringUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
@@ -48,9 +43,6 @@ import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* A singleton that holds references to different openGL contexts
@@ -74,34 +66,13 @@ public class GLProxy
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
() -> Config.Client.Advanced.Logging.logRendererGLEvent.get());
/** newest version first */
private static final ArrayList<Pair<Integer, Integer>> SUPPORTED_GL_VERSIONS = new ArrayList<>(
Arrays.asList(
new Pair<>(4,6), new Pair<>(4,5), new Pair<>(4,4), new Pair<>(4,3), new Pair<>(4,2), new Pair<>(4,1), new Pair<>(4,0),
new Pair<>(3,3), new Pair<>(3,2)
));
private static GLProxy instance = null;
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
private final ConcurrentLinkedQueue<Runnable> renderThreadRunnableQueue = new ConcurrentLinkedQueue<>();
private ConcurrentLinkedQueue<Runnable> renderThreadRunnableQueue = new ConcurrentLinkedQueue<>();
/** Minecraft's GLFW window */
public final long minecraftGlContext;
/** Minecraft's GL capabilities */
public final GLCapabilities minecraftGlCapabilities;
/** the LodBuilder's GLFW window */
public final long lodBuilderGlContext;
/** the LodBuilder's GL capabilities */
public final GLCapabilities lodBuilderGlCapabilities;
/** the proxyWorker's GLFW window */
public final long proxyWorkerGlContext;
/** the proxyWorker's GL capabilities */
public final GLCapabilities proxyWorkerGlCapabilities;
public final GLCapabilities glCapabilities;
public boolean namedObjectSupported = false; // ~OpenGL 4.5 (UNUSED CURRENTLY)
public boolean bufferStorageSupported = false; // ~OpenGL 4.4
@@ -110,8 +81,6 @@ public class GLProxy
private final EDhApiGpuUploadMethod preferredUploadMethod;
public final GLMessage.Builder vanillaDebugMessageBuilder = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER;
public final GLMessage.Builder lodBuilderDebugMessageBuilder = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER;
public final GLMessage.Builder proxyWorkerDebugMessageBuilder = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER;
@@ -139,14 +108,13 @@ public class GLProxy
// get Minecraft's GL context //
//============================//
// get Minecraft's context
this.minecraftGlContext = GLFW.glfwGetCurrentContext();
this.minecraftGlCapabilities = GL.getCapabilities();
// get Minecraft's capabilities
this.glCapabilities = GL.getCapabilities();
// crash the game if the GPU doesn't support OpenGL 3.2
if (!this.minecraftGlCapabilities.OpenGL32)
if (!this.glCapabilities.OpenGL32)
{
String supportedVersionInfo = this.getFailedVersionInfo(this.minecraftGlCapabilities);
String supportedVersionInfo = this.getFailedVersionInfo(this.glCapabilities);
// See full requirement at above.
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GLProxy.class.getSimpleName()
@@ -154,7 +122,7 @@ public class GLProxy
"Additional info:\n" + supportedVersionInfo;
MC.crashMinecraft(errorMessage, new UnsupportedOperationException("Distant Horizon OpenGL requirements not met"));
}
GL_LOGGER.info("minecraftGlCapabilities:\n" + this.versionInfoToString(this.minecraftGlCapabilities));
GL_LOGGER.info("minecraftGlCapabilities:\n" + this.versionInfoToString(this.glCapabilities));
if (Config.Client.Advanced.Debugging.OpenGl.overrideVanillaGLLogger.get())
{
@@ -163,155 +131,20 @@ public class GLProxy
//================================//
// create the lod builder context //
//================================//
String contextCreateErrorMessage = "";
long potentialLodBuilderGlContext = 0;
GLCapabilities potentialLodBuilderGlCapabilities = null;
int majorGlVersion = Config.Client.Advanced.Debugging.OpenGl.glContextMajorVersion.get();
int minorGlVersion = Config.Client.Advanced.Debugging.OpenGl.glContextMinorVersion.get();
ArrayList<Pair<Integer, Integer>> glVersions = new ArrayList<>();
if (majorGlVersion != 0)
{
glVersions.add(new Pair<>(majorGlVersion, minorGlVersion));
}
else
{
glVersions.addAll(SUPPORTED_GL_VERSIONS);
}
for (Pair<Integer, Integer> supportedGlVersion : glVersions)
{
int glMajorVersion = supportedGlVersion.first;
int glMinorVersion = supportedGlVersion.second;
GL_LOGGER.info("Attempting to create a context with GL version: ["+glMajorVersion+"."+glMinorVersion+"]");
GLFW.glfwMakeContextCurrent(0L);
// context creation setup
GLFW.glfwDefaultWindowHints();
// make the context window invisible
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
boolean debugContextEnabled = Config.Client.Advanced.Debugging.OpenGl.enableGlDebugContext.get();
boolean forwardCompatEnabled = Config.Client.Advanced.Debugging.OpenGl.enableGlForwardCompatibilityMode.get();
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, glMajorVersion);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, glMinorVersion);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_DEBUG_CONTEXT, debugContextEnabled ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, forwardCompatEnabled ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
int profileModeInt;
EDhApiGlProfileMode profileModeEnum = Config.Client.Advanced.Debugging.OpenGl.glProfileMode.get();
switch (profileModeEnum)
{
case CORE:
profileModeInt = GLFW.GLFW_OPENGL_CORE_PROFILE;
break;
case COMPAT:
profileModeInt = GLFW.GLFW_OPENGL_COMPAT_PROFILE;
break;
default:
case ANY:
profileModeInt = GLFW.GLFW_OPENGL_ANY_PROFILE;
break;
}
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, profileModeInt);
contextCreateErrorMessage =
"Failed to create OpenGL GLFW context for OpenGL Version: [" + glMajorVersion + "." + glMinorVersion + "] \n" +
"with Debugging: [" + (debugContextEnabled ? "Enabled" : "Disabled") + "], \n" +
"Forward Compatibility: [" + (true ? "Enabled" : "Disabled") + "], \n" +
"and Profile: [" + profileModeEnum.name() + "]. ";
// try creating the Lod Builder context
potentialLodBuilderGlContext = GLFW.glfwCreateWindow(64, 64, "LOD Builder Window", 0L, this.minecraftGlContext);
if (potentialLodBuilderGlContext == 0)
{
GL_LOGGER.info(contextCreateErrorMessage);
GL_LOGGER.debug("Minecraft GL Capabilities:\n [\n" + ReflectionUtil.getAllFieldValuesAsString(this.minecraftGlCapabilities) + "\n]\n");
continue;
}
// create the window
GLFW.glfwMakeContextCurrent(potentialLodBuilderGlContext);
GL_LOGGER.info("Successfully created a context with GL version: ["+glMajorVersion+"."+glMinorVersion+"]");
// set and log the capabilities
potentialLodBuilderGlCapabilities = GL.createCapabilities();
GL_LOGGER.info("lodBuilderGlCapabilities:\n" + this.versionInfoToString(potentialLodBuilderGlCapabilities));
// override the GL logger
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream(GLProxy::logMessage, this.lodBuilderDebugMessageBuilder), true));
// clear the context for the next stage
GLFW.glfwMakeContextCurrent(0L);
break;
}
if (potentialLodBuilderGlContext == 0)
{
// no context was created
throw new UnsupportedOperationException("ERROR: Unable to create a GL Context using any of the supported GL versions: ["+ StringUtil.join(",", SUPPORTED_GL_VERSIONS) +"]");
}
this.lodBuilderGlContext = potentialLodBuilderGlContext;
this.lodBuilderGlCapabilities = potentialLodBuilderGlCapabilities;
//=================================//
// create the proxy worker context //
//=================================//
// create the proxyWorker's context
this.proxyWorkerGlContext = GLFW.glfwCreateWindow(64, 48, "LOD proxy worker Window", 0L, this.minecraftGlContext);
if (this.proxyWorkerGlContext == 0)
{
GL_LOGGER.error(contextCreateErrorMessage +
"\n Your OS and GPU Driver may have not support this combination.");
GL_LOGGER.error("Minecraft GL Capabilities:\n [\n"+ReflectionUtil.getAllFieldValuesAsString(this.minecraftGlCapabilities)+"\n]\n");
throw new UnsupportedOperationException("Forward Compat Core Profile 3.2 creation failure");
}
// create the window
GLFW.glfwMakeContextCurrent(this.proxyWorkerGlContext);
// set and log the capabilities
this.proxyWorkerGlCapabilities = GL.createCapabilities();
GL_LOGGER.info("proxyWorkerGlCapabilities:\n" + this.versionInfoToString(this.lodBuilderGlCapabilities));
// override the GL logger
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream(GLProxy::logMessage, this.proxyWorkerDebugMessageBuilder), true));
// clear the context for the next stage
GLFW.glfwMakeContextCurrent(0L);
//======================//
// get GPU capabilities //
//======================//
// get capabilities from a context we use
this.setGlContext(EGLProxyContext.LOD_BUILDER);
// Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after
this.VertexAttributeBufferBindingSupported = this.minecraftGlCapabilities.glBindVertexBuffer != 0L; // Nullptr
this.VertexAttributeBufferBindingSupported = this.glCapabilities.glBindVertexBuffer != 0L; // Nullptr
// UNUSED currently
// Check if we can use the named version of all calls, which is available in GL4.5 or after
this.namedObjectSupported = this.minecraftGlCapabilities.glNamedBufferData != 0L; //Nullptr
this.namedObjectSupported = this.glCapabilities.glNamedBufferData != 0L; //Nullptr
// get specific capabilities
// Check if we can use the Buffer Storage, which is available in GL4.4 or after
this.bufferStorageSupported = this.minecraftGlCapabilities.glBufferStorage != 0L && this.lodBuilderGlCapabilities.glBufferStorage != 0L; // Nullptr
this.bufferStorageSupported = this.glCapabilities.glBufferStorage != 0L; // Nullptr
if (!this.bufferStorageSupported)
{
GL_LOGGER.warn("This GPU doesn't support Buffer Storage (OpenGL 4.4), falling back to using other methods.");
@@ -337,99 +170,12 @@ public class GLProxy
// clean up //
//==========//
// Since this is created on the render thread, make sure the Minecraft context is used in the end
this.setGlContext(EGLProxyContext.MINECRAFT);
// GLProxy creation success
GL_LOGGER.info(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
}
//==================//
// context handling //
//==================//
/**
* A wrapper function to make switching contexts easier. <br>
* Does nothing if the calling thread is already using newContext.
*/
public void setGlContext(EGLProxyContext newContext)
{
EGLProxyContext currentContext = this.getGlContext();
// we don't have to change the context, we are already there.
if (currentContext == newContext)
return;
long contextPointer;
GLCapabilities newGlCapabilities = null;
// get the pointer(s) for this context
switch (newContext)
{
case LOD_BUILDER:
contextPointer = this.lodBuilderGlContext;
newGlCapabilities = this.lodBuilderGlCapabilities;
break;
case MINECRAFT:
contextPointer = this.minecraftGlContext;
newGlCapabilities = this.minecraftGlCapabilities;
break;
case PROXY_WORKER:
contextPointer = this.proxyWorkerGlContext;
newGlCapabilities = this.proxyWorkerGlCapabilities;
break;
default: // default should never happen, it is just here to make the compiler happy
case NONE:
// 0L is equivalent to null
contextPointer = 0L;
break;
}
GLFW.glfwMakeContextCurrent(contextPointer);
GL.setCapabilities(newGlCapabilities);
}
/** Returns this thread's OpenGL context. */
public EGLProxyContext getGlContext()
{
long currentContext = GLFW.glfwGetCurrentContext();
if (currentContext == this.lodBuilderGlContext)
{
return EGLProxyContext.LOD_BUILDER;
}
else if (currentContext == this.minecraftGlContext)
{
return EGLProxyContext.MINECRAFT;
}
else if (currentContext == this.proxyWorkerGlContext)
{
return EGLProxyContext.PROXY_WORKER;
}
else if (currentContext == 0L)
{
return EGLProxyContext.NONE;
}
else
{
// hopefully this shouldn't happen
throw new IllegalStateException(Thread.currentThread().getName() +
" has a unknown OpenGl context: [" + currentContext + "]. "
+ "Minecraft context [" + this.minecraftGlContext + "], "
+ "LodBuilder context [" + this.lodBuilderGlContext + "], "
+ "ProxyWorker context [" + this.proxyWorkerGlContext + "], "
+ "no context [0].");
}
}
//=========//
// getters //
//=========//
@@ -457,33 +203,27 @@ public class GLProxy
return method == EDhApiGpuUploadMethod.AUTO ? this.preferredUploadMethod : method;
}
public boolean runningOnRenderThread()
{
long currentContext = GLFW.glfwGetCurrentContext();
return currentContext != 0L; // if the context isn't null, it's the MC context
}
//=========================//
// Worker Thread Runnables //
//=========================//
/**
* Asynchronously calls the given runnable on proxy's OpenGL context.
* Useful for creating/destroying OpenGL objects in a thread
* that doesn't normally have access to a OpenGL context. <br>
* No rendering can be done through this method.
*/
public void recordOpenGlCall(Runnable renderCall)
public void queueRunningOnRenderThread(Runnable renderCall)
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
this.workerThread.execute(() -> this.runOpenGlCall(renderCall, stackTrace, true));
this.renderThreadRunnableQueue.add(() -> this.runOpenGlCall(renderCall, stackTrace));
}
private void runOpenGlCall(Runnable renderCall, StackTraceElement[] stackTrace, boolean useProxyWorkerContext)
private void runOpenGlCall(Runnable renderCall, StackTraceElement[] stackTrace)
{
try
{
// set up the context if requested...
if (useProxyWorkerContext)
{
this.setGlContext(EGLProxyContext.PROXY_WORKER);
}
// ...run the actual code...
renderCall.run();
}
@@ -493,67 +233,28 @@ public class GLProxy
error.setStackTrace(stackTrace);
GL_LOGGER.error(Thread.currentThread().getName() + " ran into a issue: ", error);
}
finally
{
// ...and make sure the context is released when the thread finishes
if (useProxyWorkerContext)
{
this.setGlContext(EGLProxyContext.NONE);
}
}
}
public static void ensureAllGLJobCompleted()
{
if (!hasInstance())
{
return;
}
LOGGER.info("Blocking until GL jobs finished...");
try
{
instance.workerThread.shutdown();
boolean worked = instance.workerThread.awaitTermination(30, TimeUnit.SECONDS);
if (!worked)
{
LOGGER.error("GLWorkerThread shutdown timed out! Game may crash on exit due to cleanup failure!");
}
}
catch (InterruptedException e)
{
LOGGER.error("GLWorkerThread shutdown is interrupted! Game may crash on exit due to cleanup failure!");
e.printStackTrace();
}
finally
{
instance.workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
}
LOGGER.info("All GL jobs finished!");
}
//=========================//
// Render Thread Runnables //
//=========================//
public void queueRunningOnRenderThread(Runnable renderCall)
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
this.renderThreadRunnableQueue.add(() -> this.runOpenGlCall(renderCall, stackTrace, false));
}
/**
/**
* Doesn't do any thread/GL Context validation.
* Running this outside of the render thread may cause crashes or other issues.
*/
public void runRenderThreadTasks()
{
long startTime = System.nanoTime();
Runnable runnable = this.renderThreadRunnableQueue.poll();
while(runnable != null)
{
long currentTime = System.nanoTime();
long runDuration = currentTime - startTime;
// only try running for 4ms at a time to (hopefully) prevent random lag spikes
if (runDuration > 4_000_000)
{
break;
}
runnable.run();
runnable = this.renderThreadRunnableQueue.poll();
}
@@ -20,7 +20,6 @@
package com.seibel.distanthorizons.core.render.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.core.enums.EGLProxyContext;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.util.LodUtil;
@@ -94,9 +93,9 @@ public class GLBuffer implements AutoCloseable
protected void create(boolean asBufferStorage)
{
if (GLProxy.getInstance().getGlContext() == EGLProxyContext.NONE)
if (!GLProxy.getInstance().runningOnRenderThread())
{
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside a OpenGL context.");
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
}
this.id = GL32.glGenBuffers();
@@ -109,7 +108,7 @@ public class GLBuffer implements AutoCloseable
}
protected void destroy(boolean async)
protected void destroyAsync()
{
if (this.id == 0)
{
@@ -117,40 +116,33 @@ public class GLBuffer implements AutoCloseable
return;
}
destroyBufferId(async, this.id);
destroyBufferIdAsync(this.id);
this.id = 0;
this.size = 0;
}
private static void destroyBufferId(boolean async, int id)
private static void destroyBufferIdAsync(int id)
{
EGLProxyContext glContext = GLProxy.getInstance().getGlContext();
if (async
&& glContext != EGLProxyContext.PROXY_WORKER
&& glContext != EGLProxyContext.MINECRAFT)
{
GLProxy.getInstance().queueRunningOnRenderThread(() -> destroyBufferId(false, id));
}
else
{
// remove the phantom references
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
GLProxy.getInstance().queueRunningOnRenderThread(() ->
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
// destroy the buffer if it exists,
// the buffer may not exist if the destroy method is called twice
if (GL32.glIsBuffer(id))
{
GL32.glDeleteBuffers(id);
bufferCount.decrementAndGet();
// remove the phantom references
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
//LOGGER.info("destroyed buffer ["+id+"], remaining: ["+BUFFER_ID_TO_PHANTOM.size()+"]");
}
}
// destroy the buffer if it exists,
// the buffer may not exist if the destroy method is called twice
if (GL32.glIsBuffer(id))
{
GL32.glDeleteBuffers(id);
bufferCount.decrementAndGet();
//LOGGER.info("destroyed buffer ["+id+"], remaining: ["+BUFFER_ID_TO_PHANTOM.size()+"]");
}
});
}
@@ -205,7 +197,7 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
int bbSize = bb.limit() - bb.position();
this.destroy(true);
this.destroyAsync();
this.create(true);
this.bind();
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, bufferStorageHint);
@@ -293,7 +285,7 @@ public class GLBuffer implements AutoCloseable
//===========//
@Override
public void close() { this.destroy(true); }
public void close() { this.destroyAsync(); }
@Override
public String toString()
@@ -319,7 +311,7 @@ public class GLBuffer implements AutoCloseable
{
// recreate if the buffer storage type changed
this.bind();
this.destroy(true);
this.destroyAsync();
this.create(uploadMethod.useBufferStorage);
this.bind();
}
@@ -362,7 +354,7 @@ public class GLBuffer implements AutoCloseable
if (PHANTOM_TO_BUFFER_ID.containsKey(phantomRef))
{
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
destroyBufferId(true, id);
destroyBufferIdAsync(id);
}
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
@@ -35,7 +35,7 @@ public class GLElementBuffer extends GLBuffer
* bigger than the upload payload
*/
protected int indicesCount = 0;
public int getIndicesCount() { return indicesCount; }
public int getIndicesCount() { return this.indicesCount; }
protected int type = GL32.GL_UNSIGNED_INT;
public int getType() { return type; }
@@ -45,10 +45,10 @@ public class GLElementBuffer extends GLBuffer
}
@Override
public void destroy(boolean async)
public void destroyAsync()
{
super.destroy(async);
indicesCount = 0;
super.destroyAsync();
this.indicesCount = 0;
}
@Override
@@ -39,7 +39,7 @@ public class GLVertexBuffer extends GLBuffer
* bigger than the upload payload
*/
protected int vertexCount = 0;
public int getVertexCount() { return vertexCount; }
public int getVertexCount() { return this.vertexCount; }
// FIXME: This setter is needed for premapping buffer to manually set the vertexCount. Fix this.
public void setVertexCount(int vertexCount) { this.vertexCount = vertexCount; }
@@ -52,9 +52,9 @@ public class GLVertexBuffer extends GLBuffer
@Override
public void destroy(boolean async)
public void destroyAsync()
{
super.destroy(async);
super.destroyAsync();
this.vertexCount = 0;
}
@@ -849,7 +849,7 @@ public class LodRenderer
}
if (this.quadIBO != null)
this.quadIBO.destroy(false);
this.quadIBO.destroyAsync();
// Delete framebuffer, color texture, and depth texture
if (this.framebuffer != null && !this.usingMcFrameBuffer)
@@ -97,8 +97,7 @@ public class TestRenderer
private void createBuffer()
{
GLProxy.getInstance().recordOpenGlCall(() -> sharedContextBuffer = createTextingBuffer());
GLProxy.ensureAllGLJobCompleted();
sharedContextBuffer = createTextingBuffer();
sameContextBuffer = createTextingBuffer();
}
@@ -68,8 +68,8 @@ public class DhDataOutputStream extends DataOutputStream
ResettableArrayCache arrayCache = LZMA_RESETTABLE_ARRAY_CACHE_GETTER.get();
arrayCache.reset();
// Note: if the LZMA2Options are changed the array cache may need to be re-tested.
// the array cache was specifically tested and tuned for LZMA preset 4
return new XZOutputStream(stream, new LZMA2Options(4),
// the array cache was specifically tested and tuned for LZMA preset 3/4
return new XZOutputStream(stream, new LZMA2Options(3),
XZ.CHECK_CRC64, arrayCache);
default:
@@ -941,6 +941,8 @@
"Stable",
"distanthorizons.config.enum.EDhApiUpdateBranch.NIGHTLY":
"Nightly",
"distanthorizons.config.enum.EDhApiUpdateBranch.AUTO":
"Auto",
"distanthorizons.config.enum.EDhApiGrassSideRendering.AS_GRASS":
"As Grass",