Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9bd7e2daf | |||
| 8ec4e235eb | |||
| b8a59d0ef6 | |||
| e500143781 | |||
| 406468b54c | |||
| 6857300ae2 | |||
| 6775ee23c3 | |||
| 44645943e2 | |||
| f385c4a56b | |||
| 0cf5e6d594 | |||
| 7b5b8da0d2 | |||
| 851f2ccd06 | |||
| 6c40389c07 | |||
| fada9e4cf6 | |||
| 06198fdbb8 | |||
| 3158eed5a3 | |||
| d2ff4a5806 |
+4
-1
@@ -9,12 +9,15 @@ package com.seibel.distanthorizons.api.interfaces.data;
|
||||
* @version 2024-7-14
|
||||
* @since API 3.0.0
|
||||
*/
|
||||
public interface IDhApiTerrainDataCache
|
||||
public interface IDhApiTerrainDataCache // TODO should this be AutoClosable?
|
||||
{
|
||||
/**
|
||||
* Removes any data that's currently stored in this cache.
|
||||
* This cane be done to free up memory or invalidate
|
||||
* the cache so fresh data can be pulled in.
|
||||
* <br><br>
|
||||
* This should be called before de-referencing this object
|
||||
* so DH can handle any necessary cleanup for internal objects.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
||||
@@ -38,7 +38,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.3.0-b";
|
||||
public static final String VERSION = "2.3.1-b";
|
||||
/** Returns true if the current build is an unstable developer build, false otherwise. */
|
||||
public static final boolean IS_DEV_BUILD = VERSION.toLowerCase().contains("dev");
|
||||
|
||||
|
||||
+18
-6
@@ -197,10 +197,10 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||
|
||||
|
||||
if (!(apiDataCache instanceof DhApiTerrainDataCache))
|
||||
// the data cache can be null, but must be our own implementation
|
||||
if (apiDataCache != null
|
||||
&& !(apiDataCache instanceof DhApiTerrainDataCache))
|
||||
{
|
||||
// custom level wrappers aren't supported,
|
||||
// the API user must get a level wrapper from our code somewhere
|
||||
return DhApiResult.createFail("Unsupported [" + IDhApiTerrainDataCache.class.getSimpleName() + "] implementation, only the core class [" + DhApiTerrainDataCache.class.getSimpleName() + "] is a valid parameter.");
|
||||
}
|
||||
DhApiTerrainDataCache dataCache = (DhApiTerrainDataCache) apiDataCache;
|
||||
@@ -226,10 +226,9 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
// get the data source //
|
||||
//=====================//
|
||||
|
||||
FullDataSourceV2 dataSource = null;
|
||||
try
|
||||
{
|
||||
FullDataSourceV2 dataSource = null;
|
||||
|
||||
// try using the cached data if possible
|
||||
if (dataCache != null)
|
||||
{
|
||||
@@ -244,7 +243,12 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
{
|
||||
return DhApiResult.createFail("Unable to find/generate any data at the " + DhSectionPos.class.getSimpleName() + " [" + DhSectionPos.toString(sectionPos) + "].");
|
||||
}
|
||||
dataCache.add(sectionPos, dataSource);
|
||||
|
||||
// save to the cache if present
|
||||
if (dataCache != null)
|
||||
{
|
||||
dataCache.add(sectionPos, dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -316,6 +320,14 @@ public class DhApiTerrainDataRepo implements IDhApiTerrainDataRepo
|
||||
LOGGER.error("Unexpected exception in getTerrainDataColumnArray. Error: [" + e.getMessage() + "]", e);
|
||||
return DhApiResult.createFail("Unexpected exception: [" + e.getMessage() + "].");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (dataCache == null
|
||||
&& dataSource != null)
|
||||
{
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1015,9 +1015,23 @@ public class Config
|
||||
public static class OpenGl
|
||||
{
|
||||
public static ConfigEntry<Boolean> overrideVanillaGLLogger = new ConfigEntry.Builder<Boolean>()
|
||||
.set(ModInfo.IS_DEV_BUILD)
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "Requires a reboot to change. \n"
|
||||
+ "Defines how OpenGL errors are handled. \n "
|
||||
+ "Requires rebooting Minecraft to change. \n"
|
||||
+ "Will catch OpenGL errors thrown by other mods. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> onlyLogGlErrorsOnce = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "If true each Open GL error will only be logged once. \n"
|
||||
+ "Enabling this may cause some error logs to be missed. \n"
|
||||
+ "Does nothing if overrideVanillaGLLogger is set to false. \n"
|
||||
+ " \n"
|
||||
+ "Generally this can be kept as 'true' to prevent log spam. \n"
|
||||
+ "However, Please set this to 'false' if a developer needs your log to debug a GL issue. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
@@ -1281,7 +1295,7 @@ public class Config
|
||||
|
||||
public static ConfigEntry<Integer> generationProgressDisplayIntervalInSeconds = new ConfigEntry.Builder<Integer>()
|
||||
.setChatCommandName("generation.logInterval")
|
||||
.setMinDefaultMax(1, 5, 60 * 60 * 4) // max = 4 hours
|
||||
.setMinDefaultMax(1, 2, 60 * 60 * 4) // max = 4 hours
|
||||
.comment(""
|
||||
+ "How often should the distant generator progress be displayed? \n"
|
||||
+ "")
|
||||
|
||||
@@ -258,7 +258,11 @@ public class ClientLevelModule implements Closeable, AbstractDataSourceHandler.I
|
||||
|
||||
public void clearRenderCache()
|
||||
{
|
||||
this.clientLevel.getClientLevelWrapper().clearBlockColorCache();
|
||||
IClientLevelWrapper clientLevelWrapper = this.clientLevel.getClientLevelWrapper();
|
||||
if (clientLevelWrapper != null)
|
||||
{
|
||||
clientLevelWrapper.clearBlockColorCache();
|
||||
}
|
||||
|
||||
ClientRenderState ClientRenderState = this.ClientRenderStateRef.get();
|
||||
if (ClientRenderState != null && ClientRenderState.quadtree != null)
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV
|
||||
import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataSourceProvider;
|
||||
import com.seibel.distanthorizons.core.file.structure.ISaveStructure;
|
||||
import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.SyncOnLoadRequestQueue;
|
||||
@@ -47,6 +48,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrap
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -63,6 +65,9 @@ import java.util.concurrent.TimeUnit;
|
||||
public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
protected static final ConfigBasedLogger NETWORK_LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Common.Logging.logNetworkEvent.get());
|
||||
|
||||
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
|
||||
public final ClientLevelModule clientside;
|
||||
@@ -159,7 +164,9 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
|
||||
|
||||
try (FullDataSourceV2DTO dataSourceDto = this.networkState.fullDataPayloadReceiver.decodeDataSourceAndReleaseBuffer(message.payload))
|
||||
{
|
||||
if (!message.isSameLevelAs(this.levelWrapper))
|
||||
boolean isSameLevel = message.isSameLevelAs(this.levelWrapper);
|
||||
NETWORK_LOGGER.debug("Buffer {} isSameLevel: {}", message.payload.dtoBufferId, isSameLevel);
|
||||
if (!isSameLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
@@ -107,6 +108,7 @@ public class DhClientServerLevel extends AbstractDhServerLevel implements IDhCli
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IClientLevelWrapper getClientLevelWrapper() { return MC_CLIENT.getWrappedClientLevel(); }
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IDhClientLevel extends IDhLevel
|
||||
{
|
||||
@@ -35,6 +36,7 @@ public interface IDhClientLevel extends IDhLevel
|
||||
|
||||
int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper block);
|
||||
|
||||
@Nullable
|
||||
IClientLevelWrapper getClientLevelWrapper();
|
||||
|
||||
/**
|
||||
|
||||
+6
-4
@@ -69,19 +69,21 @@ public class FullDataPayloadReceiver implements AutoCloseable
|
||||
});
|
||||
}
|
||||
|
||||
public FullDataSourceV2DTO decodeDataSourceAndReleaseBuffer(FullDataPayload msg)
|
||||
public FullDataSourceV2DTO decodeDataSourceAndReleaseBuffer(FullDataPayload payload)
|
||||
{
|
||||
CompositeByteBuf compositeByteBuffer = this.buffersById.get(msg.dtoBufferId);
|
||||
CompositeByteBuf compositeByteBuffer = this.buffersById.get(payload.dtoBufferId);
|
||||
LodUtil.assertTrue(compositeByteBuffer != null);
|
||||
|
||||
try
|
||||
{
|
||||
return INetworkObject.decodeToInstance(FullDataSourceV2DTO.CreateEmptyDataSourceForDecoding(), compositeByteBuffer);
|
||||
FullDataSourceV2DTO dataSourceDto = INetworkObject.decodeToInstance(FullDataSourceV2DTO.CreateEmptyDataSourceForDecoding(), compositeByteBuffer);
|
||||
LOGGER.debug("Buffer {} DTO: {}", payload.dtoBufferId, dataSourceDto);
|
||||
return dataSourceDto;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Releasing the buffer is handled by cache
|
||||
this.buffersById.remove(msg.dtoBufferId);
|
||||
this.buffersById.remove(payload.dtoBufferId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessage;
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessageOutputStream;
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||
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;
|
||||
@@ -38,31 +38,28 @@ import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.opengl.GLUtil;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* A singleton that holds references to different openGL contexts
|
||||
* and GPU capabilities.
|
||||
*
|
||||
* <p>
|
||||
* Helpful OpenGL resources:
|
||||
* <p>
|
||||
* https://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf <br>
|
||||
* https://learnopengl.com/Advanced-OpenGL/Advanced-Data <br>
|
||||
* https://www.slideshare.net/CassEveritt/approaching-zero-driver-overhead <br><br>
|
||||
*
|
||||
* https://gamedev.stackexchange.com/questions/91995/edit-vbo-data-or-create-a-new-one <br>
|
||||
* https://stackoverflow.com/questions/63509735/massive-performance-loss-with-glmapbuffer <br><br>
|
||||
*/
|
||||
public class GLProxy
|
||||
{
|
||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
public static final ConfigBasedLogger GL_LOGGER = new ConfigBasedLogger(LogManager.getLogger(GLProxy.class),
|
||||
() -> Config.Common.Logging.logRendererGLEvent.get());
|
||||
|
||||
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||
|
||||
|
||||
|
||||
private static GLProxy instance = null;
|
||||
|
||||
|
||||
@@ -79,7 +76,29 @@ public class GLProxy
|
||||
|
||||
private final EDhApiGpuUploadMethod preferredUploadMethod;
|
||||
|
||||
public final GLMessage.Builder vanillaDebugMessageBuilder = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER;
|
||||
public final GLMessageBuilder vanillaDebugMessageBuilder =
|
||||
new GLMessageBuilder(
|
||||
(type) ->
|
||||
{
|
||||
if (type == EGLMessageType.POP_GROUP)
|
||||
return false;
|
||||
else if (type == EGLMessageType.PUSH_GROUP)
|
||||
return false;
|
||||
else if (type == EGLMessageType.MARKER)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
(severity) ->
|
||||
{
|
||||
// notifications can generally be ignored (if they are logged at all)
|
||||
if (severity == EGLMessageSeverity.NOTIFICATION)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -258,6 +277,7 @@ public class GLProxy
|
||||
// logging //
|
||||
//=========//
|
||||
|
||||
/** this method is called on the render thread at the point of the GL Error */
|
||||
private static void logMessage(GLMessage msg)
|
||||
{
|
||||
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
|
||||
@@ -268,44 +288,56 @@ public class GLProxy
|
||||
|
||||
|
||||
|
||||
if (msg.type == GLMessage.EType.ERROR || msg.type == GLMessage.EType.UNDEFINED_BEHAVIOR)
|
||||
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
|
||||
String errorMessage = "GL ERROR [" + msg.id + "] from [" + msg.source + "]: [" + msg.message + "]"+(onlyLogOnce ? " this message will only be logged once" : "")+".";
|
||||
if (onlyLogOnce
|
||||
&& !LOGGED_GL_MESSAGES.add(errorMessage))
|
||||
{
|
||||
// this message has already been logged
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// create an exception so we get a stacktrace of where the message was triggered from
|
||||
RuntimeException exception = new RuntimeException(errorMessage);
|
||||
|
||||
if (msg.type == EGLMessageType.ERROR || msg.type == EGLMessageType.UNDEFINED_BEHAVIOR)
|
||||
{
|
||||
// critical error
|
||||
|
||||
GL_LOGGER.error("GL ERROR " + msg.id + " from " + msg.source + ": " + msg.message);
|
||||
GL_LOGGER.error(exception.getMessage(), exception);
|
||||
|
||||
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
|
||||
{
|
||||
throw new RuntimeException("GL ERROR: " + msg);
|
||||
// will probably crash the game,
|
||||
// good for quickly checking if there's a problem while preventing log spam
|
||||
throw exception;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-critical log
|
||||
|
||||
GLMessage.ESeverity severity = msg.severity;
|
||||
RuntimeException ex = new RuntimeException("GL MESSAGE: " + msg);
|
||||
|
||||
EGLMessageSeverity severity = msg.severity;
|
||||
if (severity == null)
|
||||
{
|
||||
// just in case the message was malformed
|
||||
severity = GLMessage.ESeverity.LOW;
|
||||
severity = EGLMessageSeverity.LOW;
|
||||
}
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
case HIGH:
|
||||
GL_LOGGER.error("{}", ex);
|
||||
GL_LOGGER.error(exception.getMessage(), exception);
|
||||
break;
|
||||
case MEDIUM:
|
||||
GL_LOGGER.warn("{}", ex);
|
||||
GL_LOGGER.warn(exception.getMessage(), exception);
|
||||
break;
|
||||
case LOW:
|
||||
GL_LOGGER.info("{}", ex);
|
||||
GL_LOGGER.info(exception.getMessage(), exception);
|
||||
break;
|
||||
case NOTIFICATION:
|
||||
GL_LOGGER.debug("{}", ex);
|
||||
GL_LOGGER.debug(exception.getMessage(), exception);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class GLState
|
||||
public int vao;
|
||||
public int vbo;
|
||||
public int ebo;
|
||||
public int[] fbo;
|
||||
public int fbo;
|
||||
public int texture2D;
|
||||
/** IE: GL_TEXTURE0, GL_TEXTURE1, etc. */
|
||||
public int activeTextureNumber;
|
||||
@@ -68,12 +68,7 @@ public class GLState
|
||||
|
||||
|
||||
|
||||
public GLState()
|
||||
{
|
||||
this.fbo = new int[FBO_MAX];
|
||||
|
||||
this.saveState();
|
||||
}
|
||||
public GLState() { this.saveState(); }
|
||||
|
||||
public void saveState()
|
||||
{
|
||||
@@ -82,7 +77,7 @@ public class GLState
|
||||
this.vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
||||
this.ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
||||
|
||||
GL32.glGetIntegerv(GL32.GL_FRAMEBUFFER_BINDING, this.fbo);
|
||||
this.fbo = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
|
||||
|
||||
this.texture2D = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||
this.activeTextureNumber = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
|
||||
@@ -101,9 +96,19 @@ public class GLState
|
||||
|
||||
GLMC.glActiveTexture(this.activeTextureNumber);
|
||||
|
||||
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
if (this.fbo != 0)
|
||||
{
|
||||
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
// attempting to get values from the default framebuffer can throw errors on Linux
|
||||
this.frameBufferTexture0 = 0;
|
||||
this.frameBufferTexture1 = 0;
|
||||
this.frameBufferDepthTexture = 0;
|
||||
}
|
||||
|
||||
this.blend = GL32.glIsEnabled(GL32.GL_BLEND);
|
||||
this.scissor = GL32.glIsEnabled(GL32.GL_SCISSOR_TEST);
|
||||
@@ -131,7 +136,7 @@ public class GLState
|
||||
public String toString()
|
||||
{
|
||||
return "GLState{" +
|
||||
"program=" + this.program + ", vao=" + this.vao + ", vbo=" + this.vbo + ", ebo=" + this.ebo + ", fbo=" + this.fbo[0] +
|
||||
"program=" + this.program + ", vao=" + this.vao + ", vbo=" + this.vbo + ", ebo=" + this.ebo + ", fbo=" + this.fbo +
|
||||
", text=" + GLEnums.getString(this.texture2D) + "@" + this.activeTextureNumber + ", text0=" + GLEnums.getString(this.texture0) +
|
||||
", FB text0=" + this.frameBufferTexture0 +
|
||||
", FB text1=" + this.frameBufferTexture1 +
|
||||
@@ -146,23 +151,18 @@ public class GLState
|
||||
'}';
|
||||
}
|
||||
|
||||
public void RestoreFrameBuffer()
|
||||
public void restore()
|
||||
{
|
||||
// explicitly unbinding the frame buffer is necessary to prevent GL_CLEAR calls from hitting the wrong buffer
|
||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, 0);
|
||||
boolean frameBufferSet = false;
|
||||
|
||||
for (int i = 0; i < FBO_MAX; i++)
|
||||
if (this.fbo != 0 && GL32.glIsFramebuffer(this.fbo))
|
||||
{
|
||||
int buffer = this.fbo[i];
|
||||
if (i > 0 && buffer == 0) break;
|
||||
|
||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, GL32.glIsFramebuffer(buffer) ? buffer : 0);
|
||||
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fbo);
|
||||
frameBufferSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void restore()
|
||||
{
|
||||
this.RestoreFrameBuffer();
|
||||
|
||||
|
||||
if (this.blend)
|
||||
{
|
||||
@@ -197,9 +197,13 @@ public class GLState
|
||||
GLMC.glActiveTexture(this.activeTextureNumber);
|
||||
GLMC.glBindTexture(GL32.glIsTexture(this.texture2D) ? this.texture2D : 0);
|
||||
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
|
||||
// attempting to set textures on the default frame buffer (ID 0) will throw errors
|
||||
if (frameBufferSet)
|
||||
{
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
|
||||
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
|
||||
}
|
||||
|
||||
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(this.vbo) ? this.vbo : 0);
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ public class GLBuffer implements AutoCloseable
|
||||
this.destroyAsync();
|
||||
this.create(true);
|
||||
this.bind();
|
||||
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, bufferStorageHint);
|
||||
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, 0);
|
||||
this.size = bbSize;
|
||||
}
|
||||
/** Requires the buffer to be bound */
|
||||
|
||||
+46
-27
@@ -32,15 +32,18 @@ import org.lwjgl.opengl.GL32;
|
||||
/**
|
||||
* This object holds a OpenGL reference to a shader
|
||||
* and allows for reading in and compiling a shader file.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-8-2021
|
||||
*/
|
||||
public class Shader
|
||||
{
|
||||
/** OpenGL shader ID */
|
||||
public final int id;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* Creates a shader with specified type.
|
||||
*
|
||||
@@ -51,51 +54,67 @@ public class Shader
|
||||
*/
|
||||
public Shader(int type, String path, boolean absoluteFilePath)
|
||||
{
|
||||
GLProxy.GL_LOGGER.info("Loading shader at " + path);
|
||||
GLProxy.GL_LOGGER.info("Loading shader at [" + path + "]");
|
||||
// Create an empty shader object
|
||||
id = GL32.glCreateShader(type);
|
||||
StringBuilder source = loadFile(path, absoluteFilePath, new StringBuilder());
|
||||
GL32.glShaderSource(id, source);
|
||||
this.id = GL32.glCreateShader(type);
|
||||
if (this.id == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Failed to create shader with type ["+type+"].");
|
||||
}
|
||||
|
||||
GL32.glCompileShader(id);
|
||||
StringBuilder source = loadFile(path, absoluteFilePath, new StringBuilder());
|
||||
GL32.glShaderSource(this.id, source);
|
||||
|
||||
GL32.glCompileShader(this.id);
|
||||
// check if the shader compiled
|
||||
int status = GL32.glGetShaderi(id, GL32.GL_COMPILE_STATUS);
|
||||
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
|
||||
if (status != GL32.GL_TRUE)
|
||||
{
|
||||
String message = "Shader compiler error. Details: " + GL32.glGetShaderInfoLog(id);
|
||||
free(); // important!
|
||||
String message = "Shader compiler error. Details: ["+GL32.glGetShaderInfoLog(this.id)+"].";
|
||||
this.free(); // important!
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
GLProxy.GL_LOGGER.info("Shader at " + path + " loaded sucessfully.");
|
||||
GLProxy.GL_LOGGER.info("Shader at " + path + " loaded successfully.");
|
||||
}
|
||||
|
||||
public Shader(int type, String sourceString)
|
||||
{
|
||||
GLProxy.GL_LOGGER.info("Loading shader with type: {}", type);
|
||||
GLProxy.GL_LOGGER.debug("Source:\n{}", sourceString);
|
||||
// Create an empty shader object
|
||||
id = GL32.glCreateShader(type);
|
||||
GL32.glShaderSource(id, sourceString);
|
||||
GLProxy.GL_LOGGER.info("Loading shader with type: ["+type+"]");
|
||||
GLProxy.GL_LOGGER.debug("Source: \n["+sourceString+"]");
|
||||
if (sourceString == null || sourceString.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("No shader source given.");
|
||||
}
|
||||
|
||||
GL32.glCompileShader(id);
|
||||
// Create an empty shader object
|
||||
this.id = GL32.glCreateShader(type);
|
||||
if (this.id == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Failed to create shader with type ["+type+"] and Source: \n["+sourceString+"].");
|
||||
}
|
||||
|
||||
GL32.glShaderSource(this.id, sourceString);
|
||||
GL32.glCompileShader(this.id);
|
||||
// check if the shader compiled
|
||||
int status = GL32.glGetShaderi(id, GL32.GL_COMPILE_STATUS);
|
||||
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
|
||||
if (status != GL32.GL_TRUE)
|
||||
{
|
||||
|
||||
String message = "Shader compiler error. Details: " + GL32.glGetShaderInfoLog(id);
|
||||
message += "\nSource:\n" + sourceString;
|
||||
free(); // important!
|
||||
String message = "Shader compiler error. Details: [" + GL32.glGetShaderInfoLog(this.id) + "]\n";
|
||||
message += "Source: \n[" + sourceString + "]";
|
||||
this.free(); // important!
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
GLProxy.GL_LOGGER.info("Shader loaded sucessfully.");
|
||||
}
|
||||
|
||||
// REMEMBER to always free the resource!
|
||||
public void free()
|
||||
{
|
||||
GL32.glDeleteShader(id);
|
||||
}
|
||||
|
||||
|
||||
//=========//
|
||||
// helpers //
|
||||
//=========//
|
||||
|
||||
public void free() { GL32.glDeleteShader(this.id); }
|
||||
|
||||
public static StringBuilder loadFile(String path, boolean absoluteFilePath, StringBuilder stringBuilder)
|
||||
{
|
||||
|
||||
@@ -454,7 +454,7 @@ public class FullDataSourceV2DTO
|
||||
{
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("levelMinY", this.levelMinY)
|
||||
.add("pos", this.pos)
|
||||
.add("pos", DhSectionPos.toString(this.pos))
|
||||
.add("dataChecksum", this.dataChecksum)
|
||||
.add("compressedDataByteArray length", this.compressedDataByteArray.size())
|
||||
.add("compressedColumnGenStepByteArray length", this.compressedColumnGenStepByteArray.size())
|
||||
|
||||
@@ -1,430 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 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.util.objects;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Handles parsing and creating string messages from OpenGL messages.
|
||||
*
|
||||
* @author Leetom
|
||||
* @version 2022-10-1
|
||||
*/
|
||||
public final class GLMessage
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
|
||||
static final String HEADER = "[LWJGL] OpenGL debug message";
|
||||
public final EType type;
|
||||
public final ESeverity severity;
|
||||
public final ESource source;
|
||||
public final String id;
|
||||
public final String message;
|
||||
|
||||
/** This is needed since gl callback will not have the correct class loader set, which causes issues. */
|
||||
static void initLoadClass()
|
||||
{
|
||||
Builder dummy = new Builder();
|
||||
dummy.add(GLMessage.HEADER);
|
||||
dummy.add("ID");
|
||||
dummy.add(":");
|
||||
dummy.add("dummyId");
|
||||
dummy.add("Source");
|
||||
dummy.add(":");
|
||||
dummy.add(ESource.API.name);
|
||||
dummy.add("Type");
|
||||
dummy.add(":");
|
||||
dummy.add(EType.OTHER.name);
|
||||
dummy.add("Severity");
|
||||
dummy.add(":");
|
||||
dummy.add(ESeverity.LOW.name);
|
||||
dummy.add("Message");
|
||||
dummy.add(":");
|
||||
dummy.add("dummyMessage");
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
initLoadClass();
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLMessage(EType type, ESeverity severity, ESource source, String id, String message)
|
||||
{
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
this.severity = severity;
|
||||
this.id = id;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return "[level:" + severity + ", type:" + type + ", source:" + source + ", id:" + id + ", msg:{" + message + "}]"; }
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// helper enums //
|
||||
//==============//
|
||||
|
||||
public enum EType
|
||||
{
|
||||
ERROR,
|
||||
DEPRECATED_BEHAVIOR,
|
||||
UNDEFINED_BEHAVIOR,
|
||||
PORTABILITY,
|
||||
PERFORMANCE,
|
||||
MARKER,
|
||||
PUSH_GROUP,
|
||||
POP_GROUP,
|
||||
OTHER;
|
||||
|
||||
|
||||
private static final HashMap<String, EType> ENUM_BY_NAME = new HashMap<>();
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
for (EType type : EType.values())
|
||||
{
|
||||
ENUM_BY_NAME.put(type.name, type);
|
||||
}
|
||||
}
|
||||
|
||||
EType() { name = super.toString().toUpperCase(); }
|
||||
|
||||
|
||||
@Override
|
||||
public final String toString() { return name; }
|
||||
|
||||
public static EType get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||
|
||||
}
|
||||
|
||||
public enum ESource
|
||||
{
|
||||
API,
|
||||
WINDOW_SYSTEM,
|
||||
SHADER_COMPILER,
|
||||
THIRD_PARTY,
|
||||
APPLICATION,
|
||||
OTHER;
|
||||
|
||||
|
||||
private static final HashMap<String, ESource> ENUM_BY_NAME = new HashMap<>();
|
||||
|
||||
public final String name;
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
for (ESource source : ESource.values())
|
||||
{
|
||||
ENUM_BY_NAME.put(source.name, source);
|
||||
}
|
||||
}
|
||||
|
||||
ESource() { name = super.toString().toUpperCase(); }
|
||||
|
||||
|
||||
@Override
|
||||
public final String toString() { return name; }
|
||||
|
||||
public static ESource get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||
|
||||
}
|
||||
|
||||
public enum ESeverity
|
||||
{
|
||||
HIGH,
|
||||
MEDIUM,
|
||||
LOW,
|
||||
NOTIFICATION;
|
||||
|
||||
|
||||
public final String name;
|
||||
|
||||
static final HashMap<String, ESeverity> ENUM_BY_NAME = new HashMap<>();
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
for (ESeverity severity : ESeverity.values())
|
||||
{
|
||||
ENUM_BY_NAME.put(severity.name, severity);
|
||||
}
|
||||
}
|
||||
|
||||
ESeverity() { name = super.toString().toUpperCase(); }
|
||||
|
||||
|
||||
@Override
|
||||
public final String toString() { return name; }
|
||||
|
||||
public static ESeverity get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* Expected message format: <br>
|
||||
* <code>
|
||||
* [LWJGL] OpenGL debug message <br>
|
||||
* ID: 0x20071 <br>
|
||||
* Source: API <br>
|
||||
* Type: OTHER <br>
|
||||
* Severity: NOTIFICATION <br>
|
||||
* Message: Buffer detailed info: Buffer object 1014084 (bound to ...
|
||||
* </code>
|
||||
*/
|
||||
public static class Builder
|
||||
{
|
||||
/** how many stages are present in the message parser */
|
||||
private static final int FINAL_PARSER_STAGE_INDEX = 15;
|
||||
|
||||
public static final Builder DEFAULT_MESSAGE_BUILDER =
|
||||
new Builder(
|
||||
(type) ->
|
||||
{ // type filter
|
||||
if (type == GLMessage.EType.POP_GROUP)
|
||||
return false;
|
||||
if (type == GLMessage.EType.PUSH_GROUP)
|
||||
return false;
|
||||
if (type == GLMessage.EType.MARKER)
|
||||
return false;
|
||||
// if (type == GLMessage.Type.PERFORMANCE) return false;
|
||||
return true;
|
||||
},
|
||||
(severity) ->
|
||||
{ // severity filter
|
||||
if (severity == GLMessage.ESeverity.NOTIFICATION)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
|
||||
private final StringBuilder inProgressMessageBuilder = new StringBuilder();
|
||||
|
||||
private EType type;
|
||||
private ESeverity severity;
|
||||
private ESource source;
|
||||
|
||||
/** if the function returns false the message will be allowed */
|
||||
private final Function<EType, Boolean> typeFilter;
|
||||
/** if the function returns false the message will be allowed */
|
||||
private final Function<ESeverity, Boolean> severityFilter;
|
||||
/** if the function returns false the message will be allowed */
|
||||
private final Function<ESource, Boolean> sourceFilter;
|
||||
|
||||
private String id;
|
||||
private String message;
|
||||
/** how far into the message parser this builder is */
|
||||
private int parserStage = 0;
|
||||
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
initLoadClass();
|
||||
}
|
||||
|
||||
public Builder() { this(null, null, null); }
|
||||
|
||||
public Builder(
|
||||
Function<EType, Boolean> typeFilter,
|
||||
Function<ESeverity, Boolean> severityFilter,
|
||||
Function<ESource, Boolean> sourceFilter)
|
||||
{
|
||||
this.typeFilter = typeFilter;
|
||||
this.severityFilter = severityFilter;
|
||||
this.sourceFilter = sourceFilter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given string to the message builder. <br> <br>
|
||||
*
|
||||
* Will log a warning if the string given wasn't expected
|
||||
* for the next stage of the OpenGL message format.<br> <br>
|
||||
*
|
||||
* @return null if the message isn't complete
|
||||
*/
|
||||
public GLMessage add(String str)
|
||||
{
|
||||
// TODO fix implementation for MC 1.20.2 and newer
|
||||
// please see the incomplete GLMessageTest for an example as to how the message formats differ
|
||||
if (true)
|
||||
return null;
|
||||
|
||||
str = str.trim();
|
||||
if (str.isEmpty())
|
||||
return null;
|
||||
|
||||
boolean parseSuccess = runNextParserStage(str);
|
||||
if (parseSuccess && parserStage > FINAL_PARSER_STAGE_INDEX)
|
||||
{
|
||||
this.parserStage = 0;
|
||||
GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
|
||||
if (doesMessagePassFilters(msg))
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
else if (!parseSuccess)
|
||||
{
|
||||
LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, parserStage);
|
||||
}
|
||||
|
||||
// the message isn't finished yet
|
||||
return null;
|
||||
|
||||
// TODO implement a method that works for both MC 1.20.2+ and 1.20.1-
|
||||
//if (str.equals(HEADER) && inProgressMessageBuilder.length() != 0)
|
||||
//{
|
||||
// boolean parseSuccess = runNextParserStage(str);
|
||||
// if (parseSuccess && parserStage > FINAL_PARSER_STAGE_INDEX)
|
||||
// {
|
||||
// this.parserStage = 0;
|
||||
// GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
|
||||
// if (doesMessagePassFilters(msg))
|
||||
// {
|
||||
// return msg;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// inProgressMessageBuilder.setLength(0);
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!parseSuccess)
|
||||
// {
|
||||
// LOGGER.warn("Failed to parse GLMessage line '{}' at stage {}", str, parserStage);
|
||||
// inProgressMessageBuilder.setLength(0);
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// inProgressMessageBuilder.append(str);
|
||||
// return null;
|
||||
//}
|
||||
}
|
||||
|
||||
private boolean doesMessagePassFilters(GLMessage msg)
|
||||
{
|
||||
if (this.sourceFilter != null && !this.sourceFilter.apply(msg.source))
|
||||
return false;
|
||||
else if (this.typeFilter != null && !this.typeFilter.apply(msg.type))
|
||||
return false;
|
||||
else if (this.severityFilter != null && !this.severityFilter.apply(msg.severity))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return true if the given string was expected next for the OpenGL message format */
|
||||
private boolean runNextParserStage(String str)
|
||||
{
|
||||
switch (this.parserStage)
|
||||
{
|
||||
case 0:
|
||||
return checkAndIncStage(str, GLMessage.HEADER);
|
||||
case 1:
|
||||
return checkAndIncStage(str, "ID");
|
||||
case 2:
|
||||
return checkAndIncStage(str, ":");
|
||||
case 3:
|
||||
this.id = str;
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 4:
|
||||
return checkAndIncStage(str, "Source");
|
||||
case 5:
|
||||
return checkAndIncStage(str, ":");
|
||||
case 6:
|
||||
this.source = ESource.get(str);
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 7:
|
||||
return checkAndIncStage(str, "Type");
|
||||
case 8:
|
||||
return checkAndIncStage(str, ":");
|
||||
case 9:
|
||||
this.type = EType.get(str);
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 10:
|
||||
return checkAndIncStage(str, "Severity");
|
||||
case 11:
|
||||
return checkAndIncStage(str, ":");
|
||||
case 12:
|
||||
this.severity = ESeverity.get(str);
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 13:
|
||||
return checkAndIncStage(str, "Message");
|
||||
case 14:
|
||||
return checkAndIncStage(str, ":");
|
||||
case 15:
|
||||
this.message = str;
|
||||
this.parserStage++;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true and increments the parserStage
|
||||
* if the given and expected strings are the same.
|
||||
*/
|
||||
private boolean checkAndIncStage(String givenString, String expectedString)
|
||||
{
|
||||
boolean equal = givenString.equals(expectedString);
|
||||
//boolean equal = givenString.contains(expectedString);
|
||||
if (equal)
|
||||
this.parserStage++;
|
||||
return equal;
|
||||
}
|
||||
|
||||
} // builder class
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 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.util.objects.GLMessages;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public enum EGLMessageSeverity
|
||||
{
|
||||
HIGH,
|
||||
MEDIUM,
|
||||
LOW,
|
||||
NOTIFICATION;
|
||||
|
||||
|
||||
public final String name;
|
||||
|
||||
static final HashMap<String, EGLMessageSeverity> ENUM_BY_NAME = new HashMap<>();
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
for (EGLMessageSeverity severity : EGLMessageSeverity.values())
|
||||
{
|
||||
ENUM_BY_NAME.put(severity.name, severity);
|
||||
}
|
||||
}
|
||||
|
||||
EGLMessageSeverity() { this.name = super.toString().toUpperCase(); }
|
||||
|
||||
|
||||
@Override
|
||||
public final String toString() { return this.name; }
|
||||
|
||||
public static EGLMessageSeverity get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 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.util.objects.GLMessages;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public enum EGLMessageSource
|
||||
{
|
||||
API,
|
||||
WINDOW_SYSTEM,
|
||||
SHADER_COMPILER,
|
||||
THIRD_PARTY,
|
||||
APPLICATION,
|
||||
OTHER;
|
||||
|
||||
|
||||
private static final HashMap<String, EGLMessageSource> ENUM_BY_NAME = new HashMap<>();
|
||||
|
||||
public final String name;
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
for (EGLMessageSource source : EGLMessageSource.values())
|
||||
{
|
||||
ENUM_BY_NAME.put(source.name, source);
|
||||
}
|
||||
}
|
||||
|
||||
EGLMessageSource() { this.name = super.toString().toUpperCase(); }
|
||||
|
||||
|
||||
@Override
|
||||
public final String toString() { return this.name; }
|
||||
|
||||
public static EGLMessageSource get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 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.util.objects.GLMessages;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public enum EGLMessageType
|
||||
{
|
||||
ERROR,
|
||||
DEPRECATED_BEHAVIOR,
|
||||
UNDEFINED_BEHAVIOR,
|
||||
PORTABILITY,
|
||||
PERFORMANCE,
|
||||
MARKER,
|
||||
PUSH_GROUP,
|
||||
POP_GROUP,
|
||||
OTHER;
|
||||
|
||||
|
||||
private static final HashMap<String, EGLMessageType> ENUM_BY_NAME = new HashMap<>();
|
||||
|
||||
public final String name;
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
for (EGLMessageType type : EGLMessageType.values())
|
||||
{
|
||||
ENUM_BY_NAME.put(type.name, type);
|
||||
}
|
||||
}
|
||||
|
||||
EGLMessageType() { this.name = super.toString().toUpperCase(); }
|
||||
|
||||
|
||||
@Override
|
||||
public final String toString() { return this.name; }
|
||||
|
||||
public static EGLMessageType get(String name) { return ENUM_BY_NAME.get(name.toUpperCase()); }
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 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.util.objects.GLMessages;
|
||||
|
||||
public final class GLMessage
|
||||
{
|
||||
static final String HEADER = "[LWJGL] OpenGL debug message";
|
||||
public final EGLMessageType type;
|
||||
public final EGLMessageSeverity severity;
|
||||
public final EGLMessageSource source;
|
||||
public final String id;
|
||||
public final String message;
|
||||
|
||||
|
||||
|
||||
GLMessage(EGLMessageType type, EGLMessageSeverity severity, EGLMessageSource source, String id, String message)
|
||||
{
|
||||
this.type = type;
|
||||
this.source = source;
|
||||
this.severity = severity;
|
||||
this.id = id;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "level: [" + this.severity + "], " +
|
||||
"type: [" + this.type + "], " +
|
||||
"source: [" + this.source + "], " +
|
||||
"id: [" + this.id + "], " +
|
||||
"msg: [" + this.message + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 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.util.objects.GLMessages;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/** Expected message formats can be found in GLMessageTest. */
|
||||
public class GLMessageBuilder
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
/** how many stages are present in the message parser */
|
||||
private static final int FINAL_LEGACY_PARSER_STAGE_INDEX = 15;
|
||||
private static final int FINAL_NEW_PARSER_STAGE_INDEX = 5;
|
||||
|
||||
|
||||
|
||||
private EGLMessageType type;
|
||||
private EGLMessageSeverity severity;
|
||||
private EGLMessageSource source;
|
||||
|
||||
/** if the function returns false the message will be allowed */
|
||||
private final Function<EGLMessageType, Boolean> typeFilter;
|
||||
/** if the function returns false the message will be allowed */
|
||||
private final Function<EGLMessageSeverity, Boolean> severityFilter;
|
||||
/** if the function returns false the message will be allowed */
|
||||
private final Function<EGLMessageSource, Boolean> sourceFilter;
|
||||
|
||||
private String id;
|
||||
private String message;
|
||||
/** how far into the message parser this builder is */
|
||||
private int parserStage = 0;
|
||||
|
||||
private boolean legacyMessage = true;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public GLMessageBuilder() { this(null, null, null); }
|
||||
|
||||
public GLMessageBuilder(
|
||||
Function<EGLMessageType, Boolean> typeFilter,
|
||||
Function<EGLMessageSeverity, Boolean> severityFilter,
|
||||
Function<EGLMessageSource, Boolean> sourceFilter)
|
||||
{
|
||||
this.typeFilter = typeFilter;
|
||||
this.severityFilter = severityFilter;
|
||||
this.sourceFilter = sourceFilter;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// message parsing //
|
||||
//=================//
|
||||
|
||||
/**
|
||||
* Adds the given string to the message builder. <br> <br>
|
||||
*
|
||||
* Will log a warning if the string given wasn't expected
|
||||
* for the next stage of the OpenGL message format.<br> <br>
|
||||
*
|
||||
* @return null if the message isn't complete
|
||||
*/
|
||||
public GLMessage add(String str)
|
||||
{
|
||||
str = str.trim();
|
||||
if (str.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean messageFinished = false;
|
||||
boolean parseSuccess = this.runNextParserStage(str);
|
||||
|
||||
|
||||
if (this.legacyMessage
|
||||
&& this.parserStage > FINAL_LEGACY_PARSER_STAGE_INDEX)
|
||||
{
|
||||
messageFinished = true;
|
||||
}
|
||||
else if (!this.legacyMessage
|
||||
&& this.parserStage > FINAL_NEW_PARSER_STAGE_INDEX)
|
||||
{
|
||||
messageFinished = true;
|
||||
}
|
||||
|
||||
|
||||
if (parseSuccess && messageFinished)
|
||||
{
|
||||
this.parserStage = 0;
|
||||
GLMessage msg = new GLMessage(this.type, this.severity, this.source, this.id, this.message);
|
||||
if (this.doesMessagePassFilters(msg))
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
else if (!parseSuccess && messageFinished)
|
||||
{
|
||||
LOGGER.warn("Failed to parse GLMessage line [" + str + "] at stage [" + this.parserStage + "]");
|
||||
}
|
||||
|
||||
// the message isn't finished yet
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean doesMessagePassFilters(GLMessage msg)
|
||||
{
|
||||
if (this.sourceFilter != null && !this.sourceFilter.apply(msg.source))
|
||||
return false;
|
||||
else if (this.typeFilter != null && !this.typeFilter.apply(msg.type))
|
||||
return false;
|
||||
else if (this.severityFilter != null && !this.severityFilter.apply(msg.severity))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return true if the given string was expected next for the OpenGL message format */
|
||||
private boolean runNextParserStage(String str)
|
||||
{
|
||||
if (this.parserStage == 0)
|
||||
{
|
||||
return this.checkExactAndIncStage(str, GLMessage.HEADER);
|
||||
}
|
||||
else if (this.parserStage == 1)
|
||||
{
|
||||
// legacy message only contains "ID" (not the colon)
|
||||
this.legacyMessage = !str.contains("ID: ");
|
||||
}
|
||||
|
||||
|
||||
if (this.legacyMessage)
|
||||
{
|
||||
return this.runNextLegacyParserStage(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.runNextNewParserStage(str);
|
||||
}
|
||||
}
|
||||
/** MC 1.20.2 and older */
|
||||
private boolean runNextLegacyParserStage(String str)
|
||||
{
|
||||
switch (this.parserStage)
|
||||
{
|
||||
case 0:
|
||||
throw new IllegalStateException("Parser should be past stage ["+this.parserStage+"], next stage is [1].");
|
||||
case 1:
|
||||
return this.checkExactAndIncStage(str, "ID");
|
||||
case 2:
|
||||
return this.checkExactAndIncStage(str, ":");
|
||||
case 3:
|
||||
this.id = str;
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 4:
|
||||
return this.checkExactAndIncStage(str, "Source");
|
||||
case 5:
|
||||
return this.checkExactAndIncStage(str, ":");
|
||||
case 6:
|
||||
this.source = EGLMessageSource.get(str);
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 7:
|
||||
return this.checkExactAndIncStage(str, "Type");
|
||||
case 8:
|
||||
return this.checkExactAndIncStage(str, ":");
|
||||
case 9:
|
||||
this.type = EGLMessageType.get(str);
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 10:
|
||||
return this.checkExactAndIncStage(str, "Severity");
|
||||
case 11:
|
||||
return this.checkExactAndIncStage(str, ":");
|
||||
case 12:
|
||||
this.severity = EGLMessageSeverity.get(str);
|
||||
this.parserStage++;
|
||||
return true;
|
||||
case 13:
|
||||
return this.checkExactAndIncStage(str, "Message");
|
||||
case 14:
|
||||
return this.checkExactAndIncStage(str, ":");
|
||||
case 15:
|
||||
this.message = str;
|
||||
this.parserStage++;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/** after MC 1.20.2 */
|
||||
private boolean runNextNewParserStage(String str)
|
||||
{
|
||||
switch (this.parserStage)
|
||||
{
|
||||
case 0:
|
||||
throw new IllegalStateException("Parser should be past stage [" + this.parserStage + "], next stage is [1].");
|
||||
case 1:
|
||||
String idPrefix = "ID: ";
|
||||
return this.checkPrefixAndRun(str, idPrefix,
|
||||
(line) ->
|
||||
{
|
||||
this.id = trySubstring(str, idPrefix.length());
|
||||
this.parserStage++;
|
||||
});
|
||||
case 2:
|
||||
String sourcePrefix = "Source: ";
|
||||
return this.checkPrefixAndRun(str, sourcePrefix,
|
||||
(line) ->
|
||||
{
|
||||
String sourceString = trySubstring(str, sourcePrefix.length());
|
||||
this.source = EGLMessageSource.get(sourceString);
|
||||
this.parserStage++;
|
||||
});
|
||||
case 3:
|
||||
String typePrefix = "Type: ";
|
||||
return this.checkPrefixAndRun(str, typePrefix,
|
||||
(line) ->
|
||||
{
|
||||
String sourceString = trySubstring(str, typePrefix.length());
|
||||
this.type = EGLMessageType.get(sourceString);
|
||||
this.parserStage++;
|
||||
});
|
||||
case 4:
|
||||
String severityPrefix = "Severity: ";
|
||||
return this.checkPrefixAndRun(str, severityPrefix,
|
||||
(line) ->
|
||||
{
|
||||
String sourceString = trySubstring(str, severityPrefix.length());
|
||||
this.severity = EGLMessageSeverity.get(sourceString);
|
||||
this.parserStage++;
|
||||
});
|
||||
case 5:
|
||||
String messagePrefix = "Message: ";
|
||||
return this.checkPrefixAndRun(str, messagePrefix,
|
||||
(line) ->
|
||||
{
|
||||
this.message = trySubstring(str, messagePrefix.length());
|
||||
this.parserStage++;
|
||||
});
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* Returns true and increments the parserStage
|
||||
* if the message and expected strings are the same.
|
||||
*/
|
||||
private boolean checkExactAndIncStage(String message, String expectedString)
|
||||
{
|
||||
boolean equal = message.equals(expectedString);
|
||||
if (equal)
|
||||
{
|
||||
this.parserStage++;
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true and increments the parserStage
|
||||
* if the message starts with the given prefix.
|
||||
*/
|
||||
private boolean checkPrefixAndRun(String message, String expectedPrefix, Consumer<String> successConsumer)
|
||||
{
|
||||
boolean equal = message.startsWith(expectedPrefix);
|
||||
if (equal)
|
||||
{
|
||||
successConsumer.accept(message);
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
/** returns "" if the string isn't long enough */
|
||||
private static String trySubstring(String string, int beginIndex)
|
||||
{
|
||||
if (beginIndex > string.length())
|
||||
{
|
||||
// prevent index-out-of-bounds errors
|
||||
// if the message isn't what we expected
|
||||
return "";
|
||||
}
|
||||
|
||||
return string.substring(beginIndex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+17
-11
@@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.core.util.objects;
|
||||
package com.seibel.distanthorizons.core.util.objects.GLMessages;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -27,12 +27,12 @@ import java.util.function.Consumer;
|
||||
public final class GLMessageOutputStream extends OutputStream
|
||||
{
|
||||
final Consumer<GLMessage> func;
|
||||
final GLMessage.Builder builder;
|
||||
final GLMessageBuilder builder;
|
||||
|
||||
|
||||
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
public GLMessageOutputStream(Consumer<GLMessage> func, GLMessage.Builder builder)
|
||||
public GLMessageOutputStream(Consumer<GLMessage> func, GLMessageBuilder builder)
|
||||
{
|
||||
this.func = func;
|
||||
this.builder = builder;
|
||||
@@ -41,24 +41,30 @@ public final class GLMessageOutputStream extends OutputStream
|
||||
@Override
|
||||
public void write(int b)
|
||||
{
|
||||
buffer.write(b);
|
||||
if (b == '\n') flush();
|
||||
this.buffer.write(b);
|
||||
if (b == '\n')
|
||||
{
|
||||
this.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush()
|
||||
{
|
||||
String str = buffer.toString();
|
||||
GLMessage msg = builder.add(str);
|
||||
if (msg != null) func.accept(msg);
|
||||
buffer.reset();
|
||||
String str = this.buffer.toString();
|
||||
GLMessage msg = this.builder.add(str);
|
||||
if (msg != null)
|
||||
{
|
||||
this.func.accept(msg);
|
||||
}
|
||||
this.buffer.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
flush();
|
||||
buffer.close();
|
||||
this.flush();
|
||||
this.buffer.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -477,7 +477,11 @@
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.overrideVanillaGLLogger":
|
||||
"Override Vanilla GL Logger",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.overrideVanillaGLLogger.@tooltip":
|
||||
"Defines how OpenGL errors are handled. \n Requires rebooting Minecraft to apply. \nMay incorrectly catch OpenGL errors thrown by other mods.",
|
||||
"Defines how OpenGL errors are handled. \nRequires rebooting Minecraft to change. \nWill catch OpenGL errors thrown by other mods.",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.onlyLogGlErrorsOnce":
|
||||
"Only Log GL Errors Once",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.onlyLogGlErrorsOnce.@tooltip":
|
||||
"If true each Open GL error will only be logged once. \nTEnabling this may cause some error logs to be missed. \nDoes nothing if overrideVanillaGLLogger is set to false. \n\nGenerally this can be kept as 'true' to prevent log spam. \nHowever, Please set this to 'false' if a developer needs your log to debug a GL issue. \n",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode":
|
||||
"OpenGL Error Handling Mode",
|
||||
"distanthorizons.config.client.advanced.debugging.openGl.glErrorHandlingMode.@tooltip":
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.sql.DatabaseUpdater;
|
||||
import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
|
||||
import com.seibel.distanthorizons.core.sql.repo.phantoms.AutoClosableTrackingWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
@@ -218,6 +219,12 @@ public class DhRepoSqliteTest
|
||||
@Test
|
||||
public void testRepoLeakDetection()
|
||||
{
|
||||
if (!AutoClosableTrackingWrapper.TRACK_WRAPPERS)
|
||||
{
|
||||
System.out.println("Skipping repo leak detection unit test. Leak tracking is disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
TestPrimaryKeyRepo primaryKeyRepo = null;
|
||||
try
|
||||
{
|
||||
@@ -298,7 +305,8 @@ public class DhRepoSqliteTest
|
||||
}
|
||||
}
|
||||
|
||||
//Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size()); // TODO fails when built for release due to tracking being disabled
|
||||
// TODO fails when built for release due to tracking being disabled
|
||||
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
||||
primaryKeyRepo.openClosables.clear();
|
||||
|
||||
|
||||
@@ -318,7 +326,7 @@ public class DhRepoSqliteTest
|
||||
}
|
||||
}
|
||||
|
||||
//Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
||||
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package tests;
|
||||
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessage;
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -28,66 +28,88 @@ import java.util.ArrayList;
|
||||
public class GLMessageTest
|
||||
{
|
||||
public static final String MESSAGE_ID = "0x20071";
|
||||
public static final GLMessage.ESource MESSAGE_SOURCE = GLMessage.ESource.API;
|
||||
public static final GLMessage.EType MESSAGE_TYPE = GLMessage.EType.OTHER;
|
||||
public static final GLMessage.ESeverity MESSAGE_SEVERITY = GLMessage.ESeverity.NOTIFICATION;
|
||||
public static final EGLMessageSource MESSAGE_SOURCE = EGLMessageSource.API;
|
||||
public static final EGLMessageType MESSAGE_TYPE = EGLMessageType.OTHER;
|
||||
public static final EGLMessageSeverity MESSAGE_SEVERITY = EGLMessageSeverity.NOTIFICATION;
|
||||
public static final String MESSAGE = "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations.";
|
||||
|
||||
|
||||
/** This is how debug messages were sent prior to Minecraft 1.20.2 */
|
||||
private static final String[] PRE_1_20_2_MESSAGE_ARRAY =
|
||||
private static final String[] OLD_MESSAGE_ARRAY =
|
||||
{
|
||||
"[LWJGL] OpenGL debug message"
|
||||
,"ID", ":", "0x20071"
|
||||
,"Source", ":", "API"
|
||||
,"Type", ":", "OTHER"
|
||||
,"Severity", ":", "NOTIFICATION"
|
||||
,"Message", ":", "Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations."
|
||||
,"ID", ":", MESSAGE_ID
|
||||
,"Source", ":", MESSAGE_SOURCE.name
|
||||
,"Type", ":", MESSAGE_TYPE.name
|
||||
,"Severity", ":", MESSAGE_SEVERITY.name
|
||||
,"Message", ":", MESSAGE
|
||||
|
||||
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
|
||||
//,"[LWJGL] OpenGL debug message"
|
||||
};
|
||||
|
||||
/** This is how debug messages were sent after (and including) Minecraft 1.20.2 */
|
||||
private static final String[] POST_1_20_2_MESSAGE_ARRAY =
|
||||
private static final String[] NEW_MESSAGE_ARRAY =
|
||||
{
|
||||
"[LWJGL] OpenGL debug message"
|
||||
,"ID: 0x20071"
|
||||
,"Source: API"
|
||||
,"Type: OTHER"
|
||||
,"Severity: NOTIFICATION"
|
||||
,"Message: Buffer detailed info: Buffer object 1014084 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW) will use VIDEO memory as\" \"the source for buffer object operations."
|
||||
|
||||
,"ID: " + MESSAGE_ID
|
||||
,"Source: " + MESSAGE_SOURCE.name
|
||||
,"Type: " + MESSAGE_TYPE.name
|
||||
,"Severity: " + MESSAGE_SEVERITY.name
|
||||
,"Message: " + MESSAGE
|
||||
|
||||
// optional addition to force the builder into noticing the message ended, shouldn't be necessary
|
||||
//,"[LWJGL] OpenGL debug message"
|
||||
};
|
||||
|
||||
public final GLMessageBuilder messageBuilder = new GLMessageBuilder(null, null, null);
|
||||
|
||||
|
||||
|
||||
//=======//
|
||||
// tests //
|
||||
//=======//
|
||||
|
||||
@Test
|
||||
public void preMc1_20_2()
|
||||
{
|
||||
ArrayList<GLMessage> messageList = new ArrayList<>();
|
||||
for (String str : PRE_1_20_2_MESSAGE_ARRAY)
|
||||
for (String str : OLD_MESSAGE_ARRAY)
|
||||
{
|
||||
GLMessage message = GLMessage.Builder.DEFAULT_MESSAGE_BUILDER.add(str);
|
||||
GLMessage message = this.messageBuilder.add(str);
|
||||
if (message != null)
|
||||
{
|
||||
messageList.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
//Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
|
||||
//testMessage(messageList.get(0));
|
||||
Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
|
||||
messageMatchesExpected(messageList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mc1_20_2()
|
||||
{
|
||||
// TODO
|
||||
ArrayList<GLMessage> messageList = new ArrayList<>();
|
||||
for (String str : NEW_MESSAGE_ARRAY)
|
||||
{
|
||||
GLMessage message = this.messageBuilder.add(str);
|
||||
if (message != null)
|
||||
{
|
||||
messageList.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertEquals("Incorrect message parse count.", 1, messageList.size());
|
||||
messageMatchesExpected(messageList.get(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
private static void messageMatchesExpected(GLMessage testMessage)
|
||||
{
|
||||
Assert.assertEquals(MESSAGE_ID, testMessage.id);
|
||||
@@ -97,4 +119,6 @@ public class GLMessageTest
|
||||
Assert.assertEquals(MESSAGE, testMessage.message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user