Compare commits

..

33 Commits

Author SHA1 Message Date
James Seibel 91f9ef3f4b remove dev from the version number 2026-04-24 06:51:09 -05:00
James Seibel d52a3abb14 Add a rough build all parallel batch script 2026-04-23 20:38:51 -05:00
James Seibel 16370b0b6e ignore parallel build folders 2026-04-23 20:38:23 -05:00
James Seibel bfa60b48cf Fix iris transparent blending 2026-04-23 17:54:41 -05:00
James Seibel 50518bfe21 Fix "fog" rendering when underwater with Iris 2026-04-23 17:39:46 -05:00
James Seibel 80e4467829 Fix near clip plane to close with shaders 2026-04-23 17:09:27 -05:00
James Seibel 396315bd05 Fix GC rarely deleting in use GL buffers 2026-04-23 16:57:17 -05:00
James Seibel 7a0fec2c2f Maybe fix a buffer deletion issue? 2026-04-23 07:44:33 -05:00
James Seibel 4afaaa7b12 up api version 6.0.0 -> 6.1.0 2026-04-23 07:42:31 -05:00
James Seibel b057041467 Add more locking and volatile buffer ID checks 2026-04-23 07:16:31 -05:00
James Seibel 33e6ce6376 potential nvidia null VBO pointer crash fix 2026-04-22 22:33:17 -05:00
James Seibel 118ef39c30 Fix flashing when moving over root node boundaries 2026-04-22 18:36:13 -05:00
James Seibel 1013e1c824 Merge branch 'main' of gitlab.com:distant-horizons-team/distant-horizons 2026-04-22 17:15:09 -05:00
James Seibel b0e924c7fe Fix nvidia driver crash 2026-04-22 17:14:50 -05:00
James Seibel 1777acd1d4 remove unused var in ThreadWorldGenParams 2026-04-22 16:54:41 -05:00
s809 8276a862f8 Clean up received payload buffer check a bit 2026-04-23 00:26:37 +05:00
James Seibel 4329acf91d Try fixing rare null pointer in render 2026-04-22 07:51:11 -05:00
James Seibel 72f83b40f7 Fix quad tree unit tests 2026-04-22 07:41:56 -05:00
James Seibel a33eb30a53 fix rare race condition preventing world gen 2026-04-21 22:20:14 -05:00
James Seibel d3e96f50a8 Maybe fix native GL crash due to buffer free 2 2026-04-21 21:40:33 -05:00
James Seibel 3aefeb98b4 Maybe fix native GL crash due to buffer free 2026-04-21 21:37:14 -05:00
James Seibel 3553ff8e60 handle a weird double start issue 2026-04-21 21:25:44 -05:00
James Seibel 945a2c0c5a Fix garbage collector warning not using config 2026-04-21 19:59:23 -05:00
James Seibel 8c7974e216 Improve node out-of-bound logic
This fixes some overlapping rendering issues, fixes LOD generating outside of render distance, and fixes low-detail LODs flashing when moving into previously-explored LODs
2026-04-21 19:50:30 -05:00
James Seibel 37756cd759 Try fixing LOD flashing/stuck low details 2026-04-21 07:48:46 -05:00
James Seibel c60cc4f013 Merge branch 'main' into 'main'
Remove broken TerraFirmaCraft compatibility code

See merge request distant-horizons-team/distant-horizons!86
2026-04-21 11:59:12 +00:00
James Seibel 87cce2e33c Fix LODs loading outside render distance
Fixes !1233
2026-04-19 21:48:33 -05:00
James Seibel 40ada9c186 fix debug wireframe on blaze3D 2026-04-19 16:34:44 -05:00
James Seibel 55fb458266 Maybe reduce memory when using internal world gen 2026-04-19 16:29:27 -05:00
James Seibel 79d2466fa2 Revert "Auto-change rendering backend when Iris is present"
This reverts commit d750e489df.
2026-04-19 15:09:16 -05:00
s809 d750e489df Auto-change rendering backend when Iris is present 2026-04-19 12:57:23 +05:00
James Seibel a206e49b2b up version number 3.0.1 -> 3.0.2 2026-04-18 21:44:33 -05:00
Daniel e5536de44f Remove broken TerraFirmaCraft compatibility code 2025-12-23 19:27:48 -08:00
15 changed files with 292 additions and 115 deletions
+2
View File
@@ -25,6 +25,8 @@ hs_err_pid*
Merged/ Merged/
# Folder created by the buildAll scripts # Folder created by the buildAll scripts
buildAllJars/ buildAllJars/
_buildAllJars/
_buildWorkers/
relocate_natives/.venv/ relocate_natives/.venv/
relocate_natives/__pycache__/ relocate_natives/__pycache__/
+35
View File
@@ -0,0 +1,35 @@
@echo off & setlocal enabledelayedexpansion
echo ==================== Getting versions to build... ====================
mkdir _buildAllJars 2>nul
del _buildAllJars\* /Q 2>nul
set "ROOT=%~dp0"
set "WORK_DIR=%ROOT%_buildWorkers"
mkdir "%WORK_DIR%" 2>nul
REM get the number of versions to compile
set count=0
for %%f in (versionProperties\*) do set /a count+=1
echo ==================== Found %count% versions to build in parallel ====================
REM Launch a parallel job for each version
for %%f in (%ROOT%versionProperties\*) do (
set version=%%~nf
echo starting [!version!]...
start "Build !version!" cmd /c ""%ROOT%build_worker.bat" "!version!" "%ROOT%" "%WORK_DIR%" ""..\..\_buildAllJars"""
REM Minor timeout between launches so we can stop the build early if we only want
REM to test part of the script and to reduce startup load
timeout /t 3 /nobreak
REM 2>nul to supress a harmless warning that the for loop
REM "cannot find the drive specified"
) 2>nul
echo ==================== All builds started... Completed Jars will be in _buildAllJars ====================
endlocal
+41
View File
@@ -0,0 +1,41 @@
@echo off & setlocal enabledelayedexpansion
set "VERSION=%~1"
set "ROOT=%~2"
set "WORK_DIR=%~3"
set "WORKER=%WORK_DIR%\%VERSION%"
set "JAR_OUTPUT_DIR=%~4"
REM remove the ending "\" from the root folder, otherwise the final quote
REM in the robocopy command will be escaped and it won't run
if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%"
set "WORKER=%~3\%~1"
set "BUILT_JAR_DIR=%WORKER%\build\forgix"
echo ==================== [%VERSION%] Copying workspace ====================
mkdir "%WORKER%"
robocopy "%ROOT%" "%WORKER%" /E /XD "%WORKER%" "_buildWorkers" "buildAllJars" ".gradle" "build" ".git" ".idea" ".gitlab" "run" "testScripts" /NFL /NDL
echo ==================== [%VERSION%] Cleaning ====================
cd /d "%WORKER%"
call .\gradlew.bat clean
REM optional arg that can be added if we want to log the result to a file
REM >"%WORK_DIR%\build_%VERSION%.log" 2>&1
echo ==================== [%VERSION%] Assembling ====================
call .\gradlew.bat assemble -PmcVer="%VERSION%"
REM optional arg that can be added if we want to log the result to a file
REM >>"%WORK_DIR%\build_%VERSION%.log" 2>&1
echo ==================== [%VERSION%] Exporting ====================
mkdir "%JAR_OUTPUT_DIR%"
robocopy "%BUILT_JAR_DIR%" "%JAR_OUTPUT_DIR%" /NFL /NDL
echo ==================== [%VERSION%] Done ====================
endlocal
REM can be uncommented for debugging
REM pause
@@ -8,8 +8,8 @@ import com.seibel.distanthorizons.common.commands.CommandInitializer;
import com.seibel.distanthorizons.common.wrappers.DependencySetup; import com.seibel.distanthorizons.common.wrappers.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry; import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
import com.seibel.distanthorizons.core.Initializer;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler; import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler; import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
@@ -95,7 +95,8 @@ public abstract class AbstractModInitializer
// Client uses config for auto-updater, so it's initialized here instead of post-init stage // Client uses config for auto-updater, so it's initialized here instead of post-init stage
this.initConfig(); this.initConfig();
logModIncompatibilityWarnings(); // needs to be called after config loading logIncompatibilityWarnings(); // needs to be called after config loading
Initializer.postConfigInit();
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized."); LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
@@ -137,6 +138,7 @@ public abstract class AbstractModInitializer
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server; MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
this.initConfig(); this.initConfig();
Initializer.postConfigInit();
this.postInit(); this.postInit();
this.postServerInit(); this.postServerInit();
this.commandInitializer.onServerReady(); this.commandInitializer.onServerReady();
@@ -159,7 +161,7 @@ public abstract class AbstractModInitializer
private void startup() private void startup()
{ {
DependencySetup.createSharedBindings(); DependencySetup.createSharedBindings();
SharedApi.init(); Initializer.preConfigInit();
this.createInitialSharedBindings(); this.createInitialSharedBindings();
} }
@@ -261,9 +263,9 @@ public abstract class AbstractModInitializer
//==================================// //======================//
// mod partial compatibility checks // // compatibility checks //
//==================================// //======================//
//region //region
/** /**
@@ -272,7 +274,7 @@ public abstract class AbstractModInitializer
* This method will log (and display to chat if enabled) * This method will log (and display to chat if enabled)
* these warnings and potential fixes. * these warnings and potential fixes.
*/ */
private static void logModIncompatibilityWarnings() private static void logIncompatibilityWarnings()
{ {
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get(); boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class); IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
@@ -299,27 +299,27 @@ public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
// render // // render //
//try (RenderPass renderPass = commandEncoder.createRenderPass( try (RenderPass renderPass = commandEncoder.createRenderPass(
// this::getRenderPassName, this::getRenderPassName,
// BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
// /*optionalClearColorAsInt*/ OptionalInt.empty(), /*optionalClearColorAsInt*/ OptionalInt.empty(),
// BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
// /*optionalDepthValueAsDouble*/ OptionalDouble.empty())) /*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
//{ {
// // Bind instance data // // Bind instance data //
// renderPass.setUniform("uniformBlock", this.uniformBuffer); renderPass.setUniform("uniformBlock", this.uniformBuffer);
//
// renderPass.setPipeline(this.pipeline); renderPass.setPipeline(this.pipeline);
// renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT); renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT);
//
// renderPass.setVertexBuffer(0, this.boxVertexBuffer); renderPass.setVertexBuffer(0, this.boxVertexBuffer);
//
// renderPass.drawIndexed( renderPass.drawIndexed(
// /*indexStart*/ 0, /*indexStart*/ 0,
// /*firstIndex*/0, /*firstIndex*/0,
// /*indexCount*/BOX_OUTLINE_INDICES.length, /*indexCount*/BOX_OUTLINE_INDICES.length,
// /*instanceCount*/1); /*instanceCount*/1);
//} }
} }
private String getRenderPassName() { return "distantHorizons:McDebugRenderer"; } private String getRenderPassName() { return "distantHorizons:McDebugRenderer"; }
@@ -19,6 +19,7 @@ import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormat;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil; import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil; import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper; import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
@@ -267,6 +268,8 @@ public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
{ {
profiler.popPush("rendering"); profiler.popPush("rendering");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
// create a render pass // create a render pass
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass( try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
this::getRenderPassName, this::getRenderPassName,
@@ -10,7 +10,6 @@ import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer; import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer;
import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*; import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*;
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader; import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper; import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
@@ -22,7 +21,6 @@ import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
import com.seibel.distanthorizons.core.render.RenderParams; import com.seibel.distanthorizons.core.render.RenderParams;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer; import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
@@ -21,7 +21,6 @@ package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy; import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper; import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -39,6 +38,7 @@ import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.StampedLock;
public class GLBuffer implements AutoCloseable public class GLBuffer implements AutoCloseable
{ {
@@ -62,14 +62,24 @@ public class GLBuffer implements AutoCloseable
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup"); private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
protected int id; protected volatile int id = 0;
public final int getId() { return this.id; } public final int getId() { return this.id; }
protected int size = 0; protected int size = 0;
public int getSize() { return this.size; } public int getSize() { return this.size; }
protected boolean bufferStorage; protected boolean bufferStorage;
public final boolean isBufferStorage() { return this.bufferStorage; }
protected boolean isMapped = false; protected boolean isMapped = false;
/**
* Locking on the render thread isn't great, but is needed due to an inconsistent
* race condition where VBOs can be marked as deleted outside the render thread. <br><br>
*
* But, due to being a read-write lock the chance of freezing
* the render thread is very low
* and since this is a stamped lock, the optimistic read time is basically zero.
* (The optimistic lock time doesn't even appear in the profiler).
*/
public final StampedLock renderStampLock = new StampedLock();
//==============// //==============//
@@ -112,36 +122,73 @@ public class GLBuffer implements AutoCloseable
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread."); LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
} }
// destroy the old buffer if one is present
if (this.id != 0) // lock to prevent the render thread from accessing the buffer's ID
// while we are removing it
long writeStamp = renderStampLock.writeLock();
try
{ {
destroyBufferIdNow(this.id); int oldId = this.id;
this.id = GLMC.glGenBuffers();
// destroy the old buffer
// after the new one has been created
// to hopefully prevent a rare race conditions where the old ID
// is still used somewhere
if (oldId != 0)
{
// this ID doesn't need to be tracked anymore
tryRemoveBufferIdFromPhantom(oldId);
destroyBufferIdNow(oldId);
}
this.bufferStorage = asBufferStorage;
bufferCount.getAndIncrement();
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
}
finally
{
renderStampLock.unlock(writeStamp);
} }
this.id = GLMC.glGenBuffers();
this.bufferStorage = asBufferStorage;
bufferCount.getAndIncrement();
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
} }
protected void destroyAsync() protected void destroyAsync()
{ {
if (this.id == 0) // lock to prevent the render thread from accessing the buffer's ID
// while we are removing it
long writeStamp = renderStampLock.writeLock();
try
{ {
// the buffer has already been closed if (this.id == 0)
return; {
// the buffer has already been closed
return;
}
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
// remove the phantom tracking now so the phantom doesn't have the chance to
// get garbage collected before the render thread task runs
// (this can happen if MC is running at extremely low framerates like 1 fps via mods)
tryRemoveBufferIdFromPhantom(idToDelete);
// mark the old data is invalid before deleting to prevent a rare race condition
// where the queued on render thread task runs before the ID is cleared
this.id = 0;
this.size = 0;
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); });
}
finally
{
renderStampLock.unlock(writeStamp);
} }
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete); });
this.id = 0;
this.size = 0;
} }
private static void destroyBufferIdNow(int id) private static void destroyBufferIdNow(int id)
{ {
// only delete valid buffers // only delete valid buffers
@@ -151,20 +198,6 @@ public class GLBuffer implements AutoCloseable
return; return;
} }
// remove and clear the phantom reference if present
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
phantom.clear();
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
bufferCount.decrementAndGet(); bufferCount.decrementAndGet();
// destroy the buffer if it exists, // destroy the buffer if it exists,
@@ -178,6 +211,32 @@ public class GLBuffer implements AutoCloseable
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]"); LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]");
} }
} }
else
{
// shouldn't happen, but just in case
LOGGER.warn("Attempted to destroy a non buffer object with ID ["+id+"].");
}
}
/** should be called before {@link GLBuffer#destroyBufferIdNow} */
private static void tryRemoveBufferIdFromPhantom(int id)
{
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
{
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
phantom.clear();
PHANTOM_TO_BUFFER_ID.remove(phantom);
BUFFER_ID_TO_PHANTOM.remove(id);
}
else
{
LOGGER.warn("Unable to remove phantom GLBuffer with ID ["+id+"], buffer may have already been deleted.");
}
} }
//endregion //endregion
@@ -321,7 +380,6 @@ public class GLBuffer implements AutoCloseable
{ {
// recreate if the buffer storage type changed // recreate if the buffer storage type changed
this.bind(); this.bind();
destroyBufferIdNow(this.id);
this.destroyOldAndCreate(uploadMethod.useBufferStorage); this.destroyOldAndCreate(uploadMethod.useBufferStorage);
this.bind(); this.bind();
} }
@@ -289,6 +289,9 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
GLMC.disableBlend(); GLMC.disableBlend();
} }
// needs to be triggered after DH attempts to set the GL state so that Iris
// can override it as needed
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
@@ -311,6 +314,12 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++) for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
{ {
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex); LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
if (!bufferContainer.buffersUploaded)
{
// make sure we don't accidentally try
// rendering a buffer that is (or is going to be) freed
continue;
}
// set uniforms and fire events // set uniforms and fire events
{ {
@@ -335,25 +344,45 @@ public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiS
continue; continue;
} }
if (vbo.getVertexCount() == 0)
// for lock information please view the lock's javadocs
long vboReadStamp = vbo.renderStampLock.readLock();
long iboReadStamp = vbo.getQuadIBO().renderStampLock.readLock();
try
{ {
continue; // don't render empty sections
if (vbo.getVertexCount() == 0)
{
continue;
}
// don't render deleted VBOs (this will crash the driver/game)
if (vbo.getId() == 0
|| vbo.getQuadIBO().getId() == 0)
{
continue;
}
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
int indexCount = (int) (vbo.getVertexCount() * 1.5);
vbo.bind();
vbo.getQuadIBO().bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
GL32.glDrawElements(
GL32.GL_TRIANGLES,
indexCount,
vbo.getQuadIBO().getGlType(), 0);
vbo.unbind();
vbo.getQuadIBO().unbind();
}
finally
{
vbo.renderStampLock.unlock(vboReadStamp);
vbo.getQuadIBO().renderStampLock.unlock(iboReadStamp);
} }
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
int indexCount = (int)(vbo.getVertexCount() * 1.5);
vbo.bind();
vbo.getQuadIBO().bind();
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
GL32.glDrawElements(
GL32.GL_TRIANGLES,
indexCount,
vbo.getQuadIBO().getGlType(), 0);
vbo.unbind();
vbo.getQuadIBO().unbind();
} }
} }
} }
@@ -80,9 +80,20 @@ public class DependencySetup
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE); SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
} }
private static boolean renderingApiBindingsSet = false;
/** will be called from a DH thread, not the render thread */ /** will be called from a DH thread, not the render thread */
public static void setRenderingApiBindings() public synchronized static void setRenderingApiBindings()
{ {
// shouldn't happen, but there was a single report that this method was triggered twice
if (renderingApiBindingsSet)
{
LOGGER.warn("Rendering bindings already set, skipping. How did this happen?");
return;
}
renderingApiBindingsSet = true;
EDhApiRenderApi renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingApi.get(); EDhApiRenderApi renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
if (renderingApiEnum == EDhApiRenderApi.AUTO) if (renderingApiEnum == EDhApiRenderApi.AUTO)
{ {
@@ -154,22 +154,12 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
static static
{ {
boolean isTerraFirmaCraftPresent = false;
try
{
Class.forName("net.dries007.tfc.world.TFCChunkGenerator");
isTerraFirmaCraftPresent = true;
LOGGER.info("TerraFirmaCraft detected.");
}
catch (ClassNotFoundException ignore) { }
ImmutableMap.Builder<EDhApiWorldGenerationStep, Integer> builder = ImmutableMap.builder(); ImmutableMap.Builder<EDhApiWorldGenerationStep, Integer> builder = ImmutableMap.builder();
builder.put(EDhApiWorldGenerationStep.EMPTY, 1); builder.put(EDhApiWorldGenerationStep.EMPTY, 1);
builder.put(EDhApiWorldGenerationStep.STRUCTURE_START, 0); builder.put(EDhApiWorldGenerationStep.STRUCTURE_START, 0);
builder.put(EDhApiWorldGenerationStep.STRUCTURE_REFERENCE, 0); builder.put(EDhApiWorldGenerationStep.STRUCTURE_REFERENCE, 0);
builder.put(EDhApiWorldGenerationStep.BIOMES, isTerraFirmaCraftPresent ? 1 : 0); builder.put(EDhApiWorldGenerationStep.BIOMES, 0);
builder.put(EDhApiWorldGenerationStep.NOISE, isTerraFirmaCraftPresent ? 1 : 0); builder.put(EDhApiWorldGenerationStep.NOISE, 0);
builder.put(EDhApiWorldGenerationStep.SURFACE, 0); builder.put(EDhApiWorldGenerationStep.SURFACE, 0);
builder.put(EDhApiWorldGenerationStep.CARVERS, 0); builder.put(EDhApiWorldGenerationStep.CARVERS, 0);
builder.put(EDhApiWorldGenerationStep.LIQUID_CARVERS, 0); builder.put(EDhApiWorldGenerationStep.LIQUID_CARVERS, 0);
@@ -205,11 +195,6 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
LOGGER.info("TerraForge Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it."); LOGGER.info("TerraForge Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it.");
LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "]."); LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "].");
} }
else if (generator.getClass().toString().equals("class net.dries007.tfc.world.TFCChunkGenerator"))
{
LOGGER.info("TerraFirmaCraft Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it.");
LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "].");
}
else else
{ {
LOGGER.warn("Unknown Chunk Generator detected: [" + generator.getClass() + "], Distant Generation May Fail!"); LOGGER.warn("Unknown Chunk Generator detected: [" + generator.getClass() + "], Distant Generation May Fail!");
@@ -12,11 +12,9 @@ import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat; import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.DhServerLevel;
import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.ExceptionUtil;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.TimerUtil; import com.seibel.distanthorizons.core.util.TimerUtil;
@@ -195,12 +193,22 @@ public class InternalServerGenerator
} }
finally finally
{ {
ArrayList<CompletableFuture<Void>> releaseFutures = new ArrayList<>();
// release all chunks from the server to prevent out of memory issues // release all chunks from the server to prevent out of memory issues
Iterator<ChunkPos> chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0); Iterator<ChunkPos> chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0);
while (chunkPosIterator.hasNext()) while (chunkPosIterator.hasNext())
{ {
ChunkPos chunkPos = chunkPosIterator.next(); ChunkPos chunkPos = chunkPosIterator.next();
this.releaseChunkFromServer(this.params.mcServerLevel, this.params.dhServerLevel, chunkPos); releaseFutures.add(this.releaseChunkFromServerAsync(this.params.mcServerLevel, chunkPos));
}
// wait for all release futures to finish to prevent an issue where DH queues
// tickets faster than MC can clear them out
for (int i = 0; i < releaseFutures.size(); i++)
{
CompletableFuture<Void> releaseFuture = releaseFutures.get(i);
releaseFuture.join();
} }
} }
} }
@@ -286,8 +294,10 @@ public class InternalServerGenerator
* mitigates out of memory issues in the vanilla chunk system. <br> * mitigates out of memory issues in the vanilla chunk system. <br>
* See: https://github.com/pop4959/Chunky/pull/383 * See: https://github.com/pop4959/Chunky/pull/383
*/ */
private void releaseChunkFromServer(ServerLevel level, IDhServerLevel dhLevel, ChunkPos chunkPos) private CompletableFuture<Void> releaseChunkFromServerAsync(ServerLevel level, ChunkPos chunkPos)
{ {
CompletableFuture<Void> removeTicketFuture = new CompletableFuture<>();
level.getChunkSource().chunkMap.mainThreadExecutor.execute(() -> level.getChunkSource().chunkMap.mainThreadExecutor.execute(() ->
{ {
try try
@@ -323,9 +333,15 @@ public class InternalServerGenerator
} }
catch (Exception e) catch (Exception e)
{ {
LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e); LOGGER.warn("Failed to release chunk ["+chunkPos+"] back to internal server. Error: ["+e.getMessage()+"]", e);
}
finally
{
removeTicketFuture.complete(null);
} }
}); });
return removeTicketFuture;
} }
@@ -40,8 +40,6 @@ public final class ThreadWorldGenParams
public StructureCheck structCheck; public StructureCheck structCheck;
#endif #endif
boolean isValid = true;
// used for some older MC versions // used for some older MC versions
private static GlobalWorldGenParams previousGlobalWorldGenParams = null; private static GlobalWorldGenParams previousGlobalWorldGenParams = null;
@@ -55,7 +53,6 @@ public final class ThreadWorldGenParams
{ {
ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get(); ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get();
if (threadParam != null if (threadParam != null
&& threadParam.isValid
&& threadParam.level == globalParams.mcServerLevel) && threadParam.level == globalParams.mcServerLevel)
{ {
return threadParam; return threadParam;
+2 -2
View File
@@ -6,8 +6,8 @@ org.gradle.caching=true
# Mod Info # Mod Info
mod_name=DistantHorizons mod_name=DistantHorizons
api_name=DistantHorizonsApi api_name=DistantHorizonsApi
mod_version=3.0.1-b mod_version=3.0.2-b
api_version=6.0.0 api_version=6.1.0
maven_group=com.seibel.distanthorizons maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons mod_readable_name=Distant Horizons
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow. mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.