Cleanup Error logging + Polish OpenGL Error/Warning/Message handling

This commit is contained in:
tom lee
2022-02-27 17:01:03 +08:00
parent 7db3789bc2
commit e6f8c0d65f
8 changed files with 411 additions and 74 deletions
@@ -274,8 +274,7 @@ public class LodDimensionFileHandler
}
catch (IOException ioEx)
{
ApiShared.LOGGER.error("LOD file read error. Unable to read xz compressed file [" + file + "] error [" + ioEx.getMessage() + "]: ");
ioEx.printStackTrace();
ApiShared.LOGGER.error("LOD file read error. Unable to read xz compressed file [" + file + "]: ",ioEx);
region.addLevelContainer(new VerticalLevelContainer(tempDetailLevel));
}
}// for each detail level
@@ -301,8 +300,7 @@ public class LodDimensionFileHandler
try {
file.createNewFile();
} catch (IOException e) {
ApiShared.LOGGER.error("LOD file write error. Unable to create parent directory for [" + file + "] error [" + e.getMessage() + "]: ");
e.printStackTrace();
ApiShared.LOGGER.error("LOD file write error. Unable to create parent directory for [" + file + "]: ", e);
return;
}
try (FileOutputStream fileOutStream = new FileOutputStream(file))
@@ -318,8 +316,7 @@ public class LodDimensionFileHandler
}
catch (IOException e)
{
ApiShared.LOGGER.error("LOD file write error. Unable to write to temp file [" + file + "] error [" + e.getMessage() + "]: ");
e.printStackTrace();
ApiShared.LOGGER.error("LOD file write error. Unable to write to temp file [" + file + "]: ", e);
}
}
@@ -395,8 +392,7 @@ public class LodDimensionFileHandler
if (!worked)
ApiShared.LOGGER.error("File writing timed out! File data may not be saved correctly and may cause corruptions!!!");
} catch (InterruptedException e) {
ApiShared.LOGGER.error("File writing wait is interrupted! File data may not be saved correctly and may cause corruptions!!!");
e.printStackTrace();
ApiShared.LOGGER.error("File writing wait is interrupted! File data may not be saved correctly and may cause corruptions!!!: ", e);
} finally {
fileWritingThreadPool = Executors.newSingleThreadExecutor(new LodThreadFactory(this.getClass().getSimpleName(), Thread.NORM_PRIORITY+1));
}
@@ -449,7 +445,7 @@ public class LodDimensionFileHandler
}
catch (Exception e)
{
e.printStackTrace();
ApiShared.LOGGER.error("Lod: UNCAUGHT exception when saving region "+r.getRegionPos()+": ", e);
} finally {
r.isWriting.decrementAndGet();
}
@@ -560,8 +556,7 @@ public class LodDimensionFileHandler
}
catch (IOException e)
{
ApiShared.LOGGER.error("LOD file write error. Unable to write to temp file [" + tempFile + "] error [" + e.getMessage() + "]: ");
e.printStackTrace();
ApiShared.LOGGER.error("LOD file write error. Unable to write to temp file [" + tempFile + "]: ", e);
continue;
}
@@ -569,8 +564,7 @@ public class LodDimensionFileHandler
try {
Files.move(tempFile.toPath(), oldFile.toPath(), StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
ApiShared.LOGGER.error("LOD file write error. Unable to update file [" + oldFile + "] error [" + e.getMessage() + "]: ");
e.printStackTrace();
ApiShared.LOGGER.error("LOD file write error. Unable to update file [" + oldFile + "]: ", e);
}
}
}
@@ -124,26 +124,20 @@ public class LodVertexBuffer implements AutoCloseable
_destroy();
_create(useBuffStorage);
}
try {
switch (uploadMethod) {
case AUTO:
throw new IllegalArgumentException("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
case BUFFER_STORAGE:
_uploadBufferStorage(bb);
break;
case DATA:
_uploadData(bb);
break;
case SUB_DATA:
_uploadSubData(bb, maxExpensionSize);
break;
default:
throw new IllegalArgumentException("Invalid GpuUploadMethod enum");
}
} catch (IllegalArgumentException e) {
throw e;
} catch (Exception e) {
ApiShared.LOGGER.error("vboUpload failed: ", e);
switch (uploadMethod) {
case AUTO:
throw new IllegalArgumentException("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
case BUFFER_STORAGE:
_uploadBufferStorage(bb);
break;
case DATA:
_uploadData(bb);
break;
case SUB_DATA:
_uploadSubData(bb, maxExpensionSize);
break;
default:
throw new IllegalArgumentException("Invalid GpuUploadMethod enum");
}
}
@@ -6,6 +6,7 @@ import java.util.concurrent.TimeUnit;
import org.lwjgl.opengl.GL32;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.builders.bufferBuilding.LodBufferBuilderFactory;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.objects.opengl.LodQuadBuilder.BufferFiller;
@@ -96,7 +97,13 @@ public class SimpleRenderBuffer extends RenderBuffer
ByteBuffer bb = iter.next();
LodVertexBuffer vbo = getOrMakeVbo(i++, method.useBufferStorage);
int size = bb.limit() - bb.position();
vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, FULL_SIZED_BUFFERS);
try {
vbo.uploadBuffer(bb, size/LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, FULL_SIZED_BUFFERS);
} catch (Exception e) {
vbos[i-1] = null;
vbo.close();
ApiShared.LOGGER.error("Failed to upload buffer: ", e);
}
if (BPerNS<=0) continue;
// upload buffers over an extended period of time
// to hopefully prevent stuttering.
@@ -19,9 +19,7 @@
package com.seibel.lod.core.render;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -37,10 +35,10 @@ import org.lwjgl.opengl.GLUtil;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.seibel.lod.core.ModInfo;
import com.seibel.lod.core.api.ClientApi;
import com.seibel.lod.core.enums.config.GpuUploadMethod;
import com.seibel.lod.core.enums.rendering.DebugMode;
import com.seibel.lod.core.enums.rendering.GLProxyContext;
import com.seibel.lod.core.util.GLMessage;
import com.seibel.lod.core.util.GLMessageOutputStream;
import com.seibel.lod.core.util.SingletonHandler;
import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton;
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
@@ -65,6 +63,12 @@ import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftWrapper;
public class GLProxy
{
private static final IMinecraftWrapper MC = SingletonHandler.get(IMinecraftWrapper.class);
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
@@ -103,6 +107,9 @@ public class GLProxy
private final GpuUploadMethod preferredUploadMethod;
public final GLMessage.Builder lodBuilderDebugMessageBuilder;
public final GLMessage.Builder proxyWorkerDebugMessageBuilder;
private String getFailedVersionInfo(GLCapabilities c) {
@@ -150,6 +157,31 @@ public class GLProxy
"4.6: " + c.OpenGL46 + "\n";
}
private static void logMessage(GLMessage msg) {
GLMessage.Severity s = msg.severity;
if (msg.type == GLMessage.Type.ERROR ||
msg.type == GLMessage.Type.UNDEFINED_BEHAVIOR) {
ApiShared.LOGGER.error("GL ERROR {} from {}: {}", msg.id, msg.source, msg.message);
throw new RuntimeException("GL ERROR: "+msg.toString());
}
RuntimeException e = new RuntimeException("GL MESSAGE: "+msg.toString());
switch (s) {
case HIGH:
ApiShared.LOGGER.error(e);
break;
case MEDIUM:
ApiShared.LOGGER.warn(e);
break;
case LOW:
ApiShared.LOGGER.info(e);
break;
case NOTIFICATION:
ApiShared.LOGGER.debug(e);
break;
}
}
/**
* @throws IllegalStateException
@@ -158,9 +190,35 @@ public class GLProxy
*/
private GLProxy()
{
lodBuilderDebugMessageBuilder = new GLMessage.Builder(
(type) -> {
if (type == GLMessage.Type.POP_GROUP) return false;
if (type == GLMessage.Type.PUSH_GROUP) return false;
if (type == GLMessage.Type.MARKER) return false;
// if (type == GLMessage.Type.PERFORMANCE) return false;
return true;
}
,(severity) -> {
if (severity == GLMessage.Severity.NOTIFICATION) return false;
return true;
},null
);
proxyWorkerDebugMessageBuilder = new GLMessage.Builder(
(type) -> {
if (type == GLMessage.Type.POP_GROUP) return false;
if (type == GLMessage.Type.PUSH_GROUP) return false;
if (type == GLMessage.Type.MARKER) return false;
// if (type == GLMessage.Type.PERFORMANCE) return false;
return true;
}
,(severity) -> {
if (severity == GLMessage.Severity.NOTIFICATION) return false;
return true;
},null
);
// boolean enableDebugLogging = CONFIG.client().advanced().debugging().getDebugMode() == DebugMode.SHOW_DETAIL;
boolean enableDebugLogging = true;
// this must be created on minecraft's render context to work correctly
ApiShared.LOGGER.info("Creating " + GLProxy.class.getSimpleName() + "... If this is the last message you see in the log there must have been a OpenGL error.");
@@ -194,6 +252,8 @@ public class GLProxy
}
ApiShared.LOGGER.info("minecraftGlCapabilities:\n"+getVersionInfo(minecraftGlCapabilities));
GLFW.glfwMakeContextCurrent(0L);
// context creation setup
GLFW.glfwDefaultWindowHints();
// make the context window invisible
@@ -203,17 +263,34 @@ public class GLProxy
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
// GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 5);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
// create the LodBuilder context
lodBuilderGlContext = GLFW.glfwCreateWindow(64, 48, "LOD Builder Window", 0L, minecraftGlContext);
if (lodBuilderGlContext == 0) {
ApiShared.LOGGER.error("ERROR: Failed to create GLFW context for OpenGL 3.2 with"
+ " Forward Compat Core Profile! Your OS may have not been able to support it!");
throw new UnsupportedOperationException("Forward Compat Core Profile 3.2 creation failure");
}
GLFW.glfwMakeContextCurrent(lodBuilderGlContext);
lodBuilderGlCapabilities = GL.createCapabilities();
ApiShared.LOGGER.info("lodBuilderGlCapabilities:\n"+getVersionInfo(lodBuilderGlCapabilities));
GLFW.glfwMakeContextCurrent(0L);
// create the proxyWorker's context
proxyWorkerGlContext = GLFW.glfwCreateWindow(64, 48, "LOD proxy worker Window", 0L, minecraftGlContext);
if (proxyWorkerGlContext == 0) {
ApiShared.LOGGER.error("ERROR: Failed to create GLFW context for OpenGL 3.2 with"
+ " Forward Compat Core Profile! Your OS may have not been able to support it!");
throw new UnsupportedOperationException("Forward Compat Core Profile 3.2 creation failure");
}
GLFW.glfwMakeContextCurrent(proxyWorkerGlContext);
proxyWorkerGlCapabilities = GL.createCapabilities();
ApiShared.LOGGER.info("proxyWorkerGlCapabilities:\n"+getVersionInfo(lodBuilderGlCapabilities));
GLFW.glfwMakeContextCurrent(0L);
// Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after
VertexAttributeBufferBindingSupported = minecraftGlCapabilities.glBindVertexBuffer != 0L; // Nullptr
@@ -228,22 +305,10 @@ public class GLProxy
//==================================//
setGlContext(GLProxyContext.LOD_BUILDER);
// TODO: Enable this but disable INFO logging
File proxyLog = new File("OpenGL-Lod-ProxyContext.log");
try {
proxyLog.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (enableDebugLogging)
try {
GLUtil.setupDebugMessageCallback(new PrintStream(proxyLog));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream((msg) -> {
logMessage(msg);
}, lodBuilderDebugMessageBuilder), true));
// get specific capabilities
// Check if we can use the Buffer Storage, which is available in GL4.4 or after
@@ -270,20 +335,10 @@ public class GLProxy
ApiShared.LOGGER.info("GPU Vendor [" + vendor + "], Preferred upload method is [" + preferredUploadMethod + "].");
setGlContext(GLProxyContext.PROXY_WORKER);
File workerLog = new File("OpenGL-Lod-WorkerContext.log");
try {
workerLog.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (enableDebugLogging)
try {
GLUtil.setupDebugMessageCallback(new PrintStream(workerLog));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream((msg) -> {
logMessage(msg);
}, proxyWorkerDebugMessageBuilder), true));
//==========//
// clean up //
@@ -0,0 +1,46 @@
package com.seibel.lod.core.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.function.Consumer;
public final class ComsumerOutputStream extends OutputStream
{
final Consumer<String> func;
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public ComsumerOutputStream(Consumer<String> func) {
this.func = func;
}
@Override
public void write(int b)
{
buffer.write(b);
}
@Override
public void write(byte[] b) throws IOException {
buffer.write(b);
}
@Override
public void write(byte[] b,
int off,
int len) {
buffer.write(b, off, len);
}
@Override
public void flush()
{
String str = buffer.toString();
buffer.reset();
func.accept(str);
}
@Override
public void close() throws IOException
{
buffer.close();
}
}
@@ -21,9 +21,6 @@ package com.seibel.lod.core.util;
import java.util.Arrays;
import com.seibel.lod.core.api.ApiShared;
import com.seibel.lod.core.enums.config.DistanceGenerationMode;
/**
*
@@ -196,11 +193,13 @@ public class DataPointUtil
}
private static SpamReducedLogger warnLogger = new SpamReducedLogger(1);
public static byte getGenerationMode(long dataPoint)
{
byte genMode = (byte) ((dataPoint >>> GEN_TYPE_SHIFT) & GEN_TYPE_MASK);
if (doesItExist(dataPoint) && genMode==0) {
ApiShared.LOGGER.warn("Existing datapoint with genMode 0 detected! This is invalid in DataPoint version 10!"
if (warnLogger.canMaybeLog() && doesItExist(dataPoint) && genMode==0) {
warnLogger.warnInc("Existing datapoint with genMode 0 detected! This is invalid in DataPoint version 10!"
+ " This may be caused by old data that has not been updated correctly.");
return 1;
}
@@ -0,0 +1,198 @@
package com.seibel.lod.core.util;
import java.util.HashMap;
import java.util.function.Function;
public final class GLMessage {
static final String HEADER = "[LWJGL] OpenGL debug message";
public final GLMessage.Type type;
public final GLMessage.Severity severity;
public final GLMessage.Source source;
public final String id;
public final String message;
GLMessage(GLMessage.Type t, GLMessage.Severity s, GLMessage.Source sr, String id, String ms) {
this.type = t;
this.source = sr;
this.severity = s;
this.id = id;
this.message = ms;
}
@Override
public String toString() {
return "[level:"+severity+", type:"+type+", source:"+source+", id:"+id+", msg:{"+message+"}]";
}
public enum Type {
ERROR,
DEPRECATED_BEHAVIOR,
UNDEFINED_BEHAVIOR,
PORTABILITY,
PERFORMANCE,
MARKER,
PUSH_GROUP,
POP_GROUP,
OTHER;
public final String str;
private Type() {
str = super.toString().toUpperCase();
}
@Override
public final String toString() {
return str;
}
static final HashMap<String, GLMessage.Type> toEnum;
static {
toEnum = new HashMap<String, GLMessage.Type>();
for (GLMessage.Type t : Type.values()) {
toEnum.put(t.str, t);
}
}
public final static GLMessage.Type get(String str) {
return toEnum.get(str);
}
}
public enum Source {
API,
WINDOW_SYSTEM,
SHADER_COMPILER,
THIRD_PARTY,
APPLICATION,
OTHER;
public final String str;
private Source() {
str = super.toString().toUpperCase();
}
static final HashMap<String, GLMessage.Source> toEnum;
static {
toEnum = new HashMap<String, GLMessage.Source>();
for (GLMessage.Source t : Source.values()) {
toEnum.put(t.str, t);
}
}
public final static GLMessage.Source get(String str) {
return toEnum.get(str);
}
}
public enum Severity {
HIGH, MEDIUM, LOW, NOTIFICATION;
public final String str;
private Severity() {
str = super.toString().toUpperCase();
}
static final HashMap<String, GLMessage.Severity> toEnum;
static {
toEnum = new HashMap<String, GLMessage.Severity>();
for (GLMessage.Severity t : Severity.values()) {
toEnum.put(t.str, t);
}
}
public final static GLMessage.Severity get(String str) {
return toEnum.get(str);
}
}
public static class Builder {
GLMessage.Type type;
GLMessage.Severity severity;
GLMessage.Source source;
Function<Type, Boolean> typeFilter;
Function<Severity, Boolean> severityFilter;
Function<Source, Boolean> sourceFilter;
String id;
String message;
int stage = 0;
public Builder() {
this(null, null, null);
}
public Builder(
Function<Type, Boolean> typeFilter,
Function<Severity, Boolean> severityFilter,
Function<Source, Boolean> sourceFilter) {
this.typeFilter = typeFilter;
this.severityFilter = severityFilter;
this.sourceFilter = sourceFilter;
}
public GLMessage add(String str) {
str = str.strip();
if (str.isEmpty()) return null;
boolean b = runStage(str);
if (b && stage >= 16) {
stage = 0;
return new GLMessage(type, severity, source, id, message);
} else {
return null;
}
}
public void setTypeFilter(Function<Type, Boolean> typeFilter) {
this.typeFilter = typeFilter;
}
public void setSeverityFilter(Function<Severity, Boolean> severityFilter) {
this.severityFilter = severityFilter;
}
public void setSourceFilter(Function<Source, Boolean> sourceFilter) {
this.sourceFilter = sourceFilter;
}
private boolean runStage(String str) {
switch (stage) {
case 0:
return checkAndIncStage(str, GLMessage.HEADER);
case 1:
return checkAndIncStage(str, "ID");
case 2:
return checkAndIncStage(str, ":");
case 3:
id = str;
stage++;
return true;
case 4:
return checkAndIncStage(str, "Source");
case 5:
return checkAndIncStage(str, ":");
case 6:
source = Source.get(str);
if (sourceFilter!=null && !sourceFilter.apply(source)) stage = -1;
stage++;
return true;
case 7:
return checkAndIncStage(str, "Type");
case 8:
return checkAndIncStage(str, ":");
case 9:
type = Type.get(str);
if (typeFilter!=null && !typeFilter.apply(type)) stage = -1;
stage++;
return true;
case 10:
return checkAndIncStage(str, "Severity");
case 11:
return checkAndIncStage(str, ":");
case 12:
severity = Severity.get(str);
if (severityFilter!=null && !severityFilter.apply(severity)) stage = -1;
stage++;
return true;
case 13:
return checkAndIncStage(str, "Message");
case 14:
return checkAndIncStage(str, ":");
case 15:
message = str;
stage++;
return true;
default: return false;
}
}
private boolean checkAndIncStage(String str, String comp) {
boolean result = str.equals(comp);
if (result) stage++;
return result;
}
};
}
@@ -0,0 +1,44 @@
package com.seibel.lod.core.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.function.Consumer;
public final class GLMessageOutputStream extends OutputStream
{
final Consumer<GLMessage> func;
final GLMessage.Builder builder;
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public GLMessageOutputStream(Consumer<GLMessage> func, GLMessage.Builder builder)
{
this.func = func;
this.builder = builder;
}
@Override
public void write(int b)
{
buffer.write(b);
if (b=='\n') flush();
}
@Override
public void flush()
{
String str = buffer.toString();
GLMessage msg = builder.add(str);
if (msg != null) func.accept(msg);
buffer.reset();
}
@Override
public void close() throws IOException
{
flush();
buffer.close();
}
}