diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EDhApiGpuUploadMethod.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EDhApiGpuUploadMethod.java index df4c4a767..8b6b737f8 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EDhApiGpuUploadMethod.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EDhApiGpuUploadMethod.java @@ -23,13 +23,12 @@ package com.seibel.distanthorizons.api.enums.config; * AUTO,
* BUFFER_STORAGE,
* SUB_DATA,
- * BUFFER_MAPPING,
* DATA
* * @author Leetom * @author James Seibel * @version 2024-4-6 - * @since API 2.0.0 + * @since API 3.0.0 */ public enum EDhApiGpuUploadMethod { @@ -49,7 +48,10 @@ public enum EDhApiGpuUploadMethod * May end up storing buffers in System memory.
* Fast rending if in GPU memory, slow if in system memory,
* but won't stutter when uploading. + * + * @deprecated not currently supported */ + @Deprecated BUFFER_MAPPING(true, false), /** Fast rendering but may stutter when uploading. */ diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/IDhApiConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/IDhApiConfig.java index a0f81b499..fd7a5b8b4 100644 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/IDhApiConfig.java +++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/IDhApiConfig.java @@ -36,7 +36,6 @@ public interface IDhApiConfig IDhApiWorldGenerationConfig worldGenerator(); IDhApiMultiplayerConfig multiplayer(); IDhApiMultiThreadingConfig multiThreading(); - IDhApiGpuBuffersConfig gpuBuffers(); // note: DON'T add the Auto Updater to this API. We only want the user's to have the ability to control when things are downloaded to their machines. //IDhApiLoggingConfig logging(); // TODO implement IDhApiDebuggingConfig debugging(); diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGpuBuffersConfig.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGpuBuffersConfig.java deleted file mode 100644 index 4b0433f7a..000000000 --- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/config/client/IDhApiGpuBuffersConfig.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.api.interfaces.config.client; - -import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; -import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigGroup; -import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; - -/** - * Distant Horizons' OpenGL buffer configuration. - * - * @author James Seibel - * @version 2023-6-14 - * @since API 1.0.0 - */ -public interface IDhApiGpuBuffersConfig extends IDhApiConfigGroup -{ - - /** Defines how geometry data is uploaded to the GPU. */ - IDhApiConfigValue gpuUploadMethod(); - - /** - * Defines how long we should wait after uploading one - * Megabyte of geometry data to the GPU before uploading - * the next Megabyte of data.
- * This can be set to a non-zero number to reduce stuttering caused by - * uploading buffers to the GPU. - */ - IDhApiConfigValue gpuUploadPerMegabyteInMilliseconds(); - -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/DhApiConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/DhApiConfig.java index 5197f7b46..1abbf6d32 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/DhApiConfig.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/DhApiConfig.java @@ -42,8 +42,6 @@ public class DhApiConfig implements IDhApiConfig @Override public IDhApiMultiThreadingConfig multiThreading() { return DhApiMultiThreadingConfig.INSTANCE; } @Override - public IDhApiGpuBuffersConfig gpuBuffers() { return DhApiGpuBuffersConfig.INSTANCE; } - @Override public IDhApiDebuggingConfig debugging() { return DhApiDebuggingConfig.INSTANCE; } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGpuBuffersConfig.java b/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGpuBuffersConfig.java deleted file mode 100644 index 22f4852b0..000000000 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/external/methods/config/client/DhApiGpuBuffersConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.core.api.external.methods.config.client; - -import com.seibel.distanthorizons.api.interfaces.config.IDhApiConfigValue; -import com.seibel.distanthorizons.api.interfaces.config.client.IDhApiGpuBuffersConfig; -import com.seibel.distanthorizons.api.objects.config.DhApiConfigValue; -import com.seibel.distanthorizons.core.config.Config; -import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod; - -public class DhApiGpuBuffersConfig implements IDhApiGpuBuffersConfig -{ - public static DhApiGpuBuffersConfig INSTANCE = new DhApiGpuBuffersConfig(); - - private DhApiGpuBuffersConfig() { } - - - - public IDhApiConfigValue gpuUploadMethod() - { return new DhApiConfigValue<>(Config.Client.Advanced.GpuBuffers.gpuUploadMethod); } - - public IDhApiConfigValue gpuUploadPerMegabyteInMilliseconds() - { return new DhApiConfigValue<>(Config.Client.Advanced.GpuBuffers.gpuUploadPerMegabyteInMilliseconds); } - -} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index b6c2448dd..463ebcbea 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -125,7 +125,6 @@ public class Config public static ConfigCategory multiplayer = new ConfigCategory.Builder().set(Multiplayer.class).build(); public static ConfigCategory lodBuilding = new ConfigCategory.Builder().set(LodBuilding.class).build(); public static ConfigCategory multiThreading = new ConfigCategory.Builder().set(MultiThreading.class).build(); - public static ConfigCategory buffers = new ConfigCategory.Builder().set(GpuBuffers.class).build(); public static ConfigCategory autoUpdater = new ConfigCategory.Builder().set(AutoUpdater.class).build(); public static ConfigCategory logging = new ConfigCategory.Builder().set(Logging.class).build(); @@ -1072,53 +1071,6 @@ public class Config } - public static class GpuBuffers - { - public static ConfigEntry gpuUploadMethod = new ConfigEntry.Builder() - .set(EDhApiGpuUploadMethod.AUTO) - .comment("" - + "What method should be used to upload geometry to the GPU? \n" - + "\n" - + EDhApiGpuUploadMethod.AUTO + ": Picks the best option based on the GPU you have. \n" - + "\n" - + EDhApiGpuUploadMethod.BUFFER_STORAGE + ": Default if OpenGL 4.5 is supported. \n" - + " Fast rendering, no stuttering. \n" - + "\n" - + EDhApiGpuUploadMethod.SUB_DATA + ": Backup option for NVIDIA. \n" - + " Fast rendering but may stutter when uploading. \n" - + "\n" - + EDhApiGpuUploadMethod.BUFFER_MAPPING + ": Slow rendering but won't stutter when uploading. \n" - + " Generally the best option for integrated GPUs. \n" - + " Default option for AMD/Intel if OpenGL 4.5 isn't supported. \n" - + " May end up storing buffers in System memory. \n" - + " Fast rendering if in GPU memory, slow if in system memory, \n" - + " but won't stutter when uploading. \n" - + "\n" - + EDhApiGpuUploadMethod.DATA + ": Fast rendering but will stutter when uploading. \n" - + " Backup option for AMD/Intel. \n" - + " Fast rendering but may stutter when uploading. \n" - + "\n" - + "If you don't see any difference when changing these settings, \n" - + "or the world looks corrupted: restart your game." - + "") - .build(); - - public static ConfigEntry gpuUploadPerMegabyteInMilliseconds = new ConfigEntry.Builder() - .setMinDefaultMax(0, 0, 50) - .comment("" - + "How long should a buffer wait per Megabyte of data uploaded? \n" - + "Helpful resource for frame times: https://fpstoms.com \n" - + "\n" - + "Longer times may reduce stuttering but will make LODs \n" - + "transition and load slower. Change this to [0] for no timeout. \n" - + "\n" - + "NOTE:\n" - + "Before changing this config, try changing the \"GPU Upload method\" first. \n" - + "") - .build(); - - } - public static class AutoUpdater { public static ConfigEntry enableAutoUpdater = new ConfigEntry.Builder() diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java index 6b6807787..833e0cf8b 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/ColumnRenderBuffer.java @@ -36,7 +36,7 @@ import org.apache.logging.log4j.Logger; import org.lwjgl.system.MemoryUtil; import java.nio.ByteBuffer; -import java.util.Iterator; +import java.util.ArrayList; import java.util.concurrent.*; /** @@ -101,7 +101,7 @@ public class ColumnRenderBuffer implements AutoCloseable { try { - this.uploadBuffersUsingUploadMethod(builder, gpuUploadMethod); + this.uploadBuffers(builder, gpuUploadMethod); uploadFuture.complete(null); } catch (InterruptedException e) @@ -127,72 +127,46 @@ public class ColumnRenderBuffer implements AutoCloseable //LOGGER.warn("Error uploading builder ["+builder+"] synchronously. Error: "+e.getMessage(), e); } } - private void uploadBuffersUsingUploadMethod(LodQuadBuilder builder, EDhApiGpuUploadMethod gpuUploadMethod) throws InterruptedException + private void uploadBuffers(LodQuadBuilder builder, EDhApiGpuUploadMethod method) throws InterruptedException { - if (gpuUploadMethod.useEarlyMapping) - { - this.uploadBuffersMapped(builder, gpuUploadMethod); - } - else - { - this.uploadBuffersDirect(builder, gpuUploadMethod); - } + // uploading mapped buffers used to be done here, + // however due to a memory leak and complication with the previous code, + // now we only allow direct uploading. + // (There's also insufficient data to state whether mapped buffers are necessary + // for DH to upload without stuttering the main thread) + + this.vbos = makeAndUploadBuffers(builder, method, this.vbos, builder.makeOpaqueVertexBuffers()); + this.vbosTransparent = makeAndUploadBuffers(builder, method, this.vbosTransparent, builder.makeTransparentVertexBuffers()); this.buffersUploaded = true; } - - - - private void uploadBuffersMapped(LodQuadBuilder builder, EDhApiGpuUploadMethod method) + /** This resizes and returns the vbo array if necessary based on the amount of data needed for this area. */ + private static GLVertexBuffer[] makeAndUploadBuffers(LodQuadBuilder builder, EDhApiGpuUploadMethod method, GLVertexBuffer[] vbos, ArrayList buffers) throws InterruptedException { - // opaque vbos // - - this.vbos = resizeBuffer(this.vbos, builder.getCurrentNeededOpaqueVertexBufferCount()); - for (int i = 0; i < this.vbos.length; i++) + try { - if (this.vbos[i] == null) + vbos = resizeBuffer(vbos, buffers.size()); + uploadBuffersDirect(vbos, buffers, method); + } + finally + { + // all the buffers must be manually freed to prevent memory leaks + if (buffers != null) { - this.vbos[i] = new GLVertexBuffer(method.useBufferStorage); + for (ByteBuffer buffer : buffers) + { + MemoryUtil.memFree(buffer); + } } } - LodQuadBuilder.BufferFiller func = builder.makeOpaqueBufferFiller(method); - for (GLVertexBuffer vbo : this.vbos) - { - func.fill(vbo); - } - - // transparent vbos // - - this.vbosTransparent = resizeBuffer(this.vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount()); - for (int i = 0; i < this.vbosTransparent.length; i++) - { - if (this.vbosTransparent[i] == null) - { - this.vbosTransparent[i] = new GLVertexBuffer(method.useBufferStorage); - } - } - LodQuadBuilder.BufferFiller transparentFillerFunc = builder.makeTransparentBufferFiller(method); - for (GLVertexBuffer vbo : this.vbosTransparent) - { - transparentFillerFunc.fill(vbo); - } + // return the array in case it was resized + return vbos; } - - private void uploadBuffersDirect(LodQuadBuilder builder, EDhApiGpuUploadMethod method) throws InterruptedException + private static void uploadBuffersDirect(GLVertexBuffer[] vbos, ArrayList byteBuffers, EDhApiGpuUploadMethod method) throws InterruptedException { - this.vbos = resizeBuffer(this.vbos, builder.getCurrentNeededOpaqueVertexBufferCount()); - uploadBuffersDirect(this.vbos, builder.makeOpaqueVertexBuffers(), method); - - this.vbosTransparent = resizeBuffer(this.vbosTransparent, builder.getCurrentNeededTransparentVertexBufferCount()); - uploadBuffersDirect(this.vbosTransparent, builder.makeTransparentVertexBuffers(), method); - } - private static void uploadBuffersDirect(GLVertexBuffer[] vbos, Iterator iter, EDhApiGpuUploadMethod method) throws InterruptedException - { - long remainingMS = 0; - long MBPerMS = Config.Client.Advanced.GpuBuffers.gpuUploadPerMegabyteInMilliseconds.get(); int vboIndex = 0; - while (iter.hasNext()) + for (int i = 0; i < byteBuffers.size(); i++) { if (vboIndex >= vbos.length) { @@ -208,41 +182,19 @@ public class ColumnRenderBuffer implements AutoCloseable GLVertexBuffer vbo = vbos[vboIndex]; - ByteBuffer bb = iter.next(); - int size = bb.limit() - bb.position(); + ByteBuffer buffer = byteBuffers.get(i); + int size = buffer.limit() - buffer.position(); try { vbo.bind(); - vbo.uploadBuffer(bb, size / LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, FULL_SIZED_BUFFER); + vbo.uploadBuffer(buffer, size / LodUtil.LOD_VERTEX_FORMAT.getByteSize(), method, FULL_SIZED_BUFFER); } catch (Exception e) { vbos[vboIndex] = null; vbo.close(); LOGGER.error("Failed to upload buffer: ", e); - } - finally - { - MemoryUtil.memFree(bb); - } - - - if (MBPerMS > 0) - { - // upload buffers over an extended period of time - // to hopefully prevent stuttering. - remainingMS += size * MBPerMS; - if (remainingMS >= TimeUnit.NANOSECONDS.convert(1000 / 60, TimeUnit.MILLISECONDS)) - { - if (remainingMS > MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS) - { - remainingMS = MAX_BUFFER_UPLOAD_TIMEOUT_NANOSECONDS; - } - - Thread.sleep(remainingMS / 1000000, (int) (remainingMS % 1000000)); - remainingMS = 0; - } } vboIndex++; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java index 12e2daf01..89cbcfec3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/render/bufferBuilding/LodQuadBuilder.java @@ -206,10 +206,124 @@ public class LodQuadBuilder + //=================// + // data finalizing // + //=================// + + /** runs any final data cleanup, merging, etc. */ + public void finalizeData() { this.mergeQuads(); } + + /** Uses Greedy meshing to merge this builder's Quads. */ + public void mergeQuads() + { + long mergeCount = 0; // can be used for debugging + long preQuadsCount = this.getCurrentOpaqueQuadsCount() + this.getCurrentTransparentQuadsCount(); + if (preQuadsCount <= 1) + { + return; + } + + for (int directionIndex = 0; directionIndex < 6; directionIndex++) + { + mergeCount += mergeQuadsInternal(this.opaqueQuads, directionIndex, BufferMergeDirectionEnum.EastWest); + if (this.doTransparency) + { + mergeCount += mergeQuadsInternal(this.transparentQuads, directionIndex, BufferMergeDirectionEnum.EastWest); + } + + + // only run the second merge if the face is the top or bottom + if (directionIndex == EDhDirection.UP.ordinal() || directionIndex == EDhDirection.DOWN.ordinal()) + { + mergeCount += mergeQuadsInternal(this.opaqueQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown); + if (this.doTransparency) + { + mergeCount += mergeQuadsInternal(this.transparentQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown); + } + } + } + + //long postQuadsCount = this.getCurrentOpaqueQuadsCount() + this.getCurrentTransparentQuadsCount(); + //LOGGER.trace("Merged "+mergeCount+"/"+preQuadsCount+"("+(mergeCount / (double) preQuadsCount)+") quads"); + } + + /** Merges all of this builder's quads for the given directionIndex (up, down, left, etc.) in the given direction */ + private static long mergeQuadsInternal(ArrayList[] list, int directionIndex, BufferMergeDirectionEnum mergeDirection) + { + if (list[directionIndex].size() <= 1) + return 0; + + list[directionIndex].sort((objOne, objTwo) -> objOne.compare(objTwo, mergeDirection)); + + long mergeCount = 0; + ListIterator iter = list[directionIndex].listIterator(); + BufferQuad currentQuad = iter.next(); + while (iter.hasNext()) + { + BufferQuad nextQuad = iter.next(); + + if (currentQuad.tryMerge(nextQuad, mergeDirection)) + { + // merge successful, attempt to merge the next quad + mergeCount++; + iter.set(null); + } + else + { + // merge fail, move on to the next quad + currentQuad = nextQuad; + } + } + list[directionIndex].removeIf(Objects::isNull); + return mergeCount; + } + + + //==============// - // add vertices // + // buffer setup // //==============// + public ArrayList makeOpaqueVertexBuffers() { return this.makeVertexBuffers(this.opaqueQuads); } + public ArrayList makeTransparentVertexBuffers() { return this.makeVertexBuffers(this.transparentQuads); } + private ArrayList makeVertexBuffers(ArrayList[] quadList) + { + ArrayList byteBufferList = new ArrayList<>(3); + + ByteBuffer buffer = null; + for (int directionIndex = 0; directionIndex < 6; directionIndex++) + { + // ignore empty directions + if (quadList[directionIndex].isEmpty()) + { + continue; + } + + // put all the quads in this direction into the buffer + for (int quadIndex = 0; quadIndex < quadList[directionIndex].size(); quadIndex++) + { + // if this is the first iteration or the buffer is full, + // create a new buffer + if (buffer == null || !buffer.hasRemaining()) + { + buffer = MemoryUtil.memAlloc(ColumnRenderBuffer.FULL_SIZED_BUFFER); + byteBufferList.add(buffer); + } + + this.putQuad(buffer, quadList[directionIndex].get(quadIndex)); + } + } + + // rewind all the buffers so they can be read from + for (int i = 0; i < byteBufferList.size(); i++) + { + buffer = byteBufferList.get(i); + buffer.limit(buffer.position()); + buffer.rewind(); + } + + return byteBufferList; + } private void putQuad(ByteBuffer bb, BufferQuad quad) { int[][] quadBase = DIRECTION_VERTEX_IBO_QUAD[quad.direction.ordinal()]; @@ -267,10 +381,10 @@ public class LodQuadBuilder if (quad.direction.getAxis().isHorizontal() || quad.direction == EDhDirection.DOWN) { if (this.grassSideRenderingMode == EDhApiGrassSideRendering.AS_DIRT - // if we want the color to fade, only apply the dirt color to the bottom vertices - || (this.grassSideRenderingMode == EDhApiGrassSideRendering.FADE_TO_DIRT && quadBase[i][1] == 0) - // always render the bottom as dirt - || quad.direction == EDhDirection.DOWN) + // if we want the color to fade, only apply the dirt color to the bottom vertices + || (this.grassSideRenderingMode == EDhApiGrassSideRendering.FADE_TO_DIRT && quadBase[i][1] == 0) + // always render the bottom as dirt + || quad.direction == EDhDirection.DOWN) { // for horizontal and bottom faces of grass blocks, use the dirt color to // prevent green cliff walls @@ -278,7 +392,7 @@ public class LodQuadBuilder color = ColorUtil.applyShade(color, MC.getShade(quad.direction)); } } - } + } } } @@ -292,7 +406,6 @@ public class LodQuadBuilder mx, my, mz); } } - private void putVertex(ByteBuffer bb, short x, short y, short z, int color, byte normalIndex, byte irisBlockMaterialId, byte skylight, byte blocklight, int mx, int my, int mz) { skylight %= 16; @@ -333,387 +446,6 @@ public class LodQuadBuilder - //=================// - // data finalizing // - //=================// - - /** runs any final data cleanup, merging, etc. */ - public void finalizeData() { this.mergeQuads(); } - - /** Uses Greedy meshing to merge this builder's Quads. */ - public void mergeQuads() - { - long mergeCount = 0; - long preQuadsCount = this.getCurrentOpaqueQuadsCount() + this.getCurrentTransparentQuadsCount(); - if (preQuadsCount <= 1) - { - return; - } - - for (int directionIndex = 0; directionIndex < 6; directionIndex++) - { - mergeCount += mergeQuadsInternal(this.opaqueQuads, directionIndex, BufferMergeDirectionEnum.EastWest); - if (this.doTransparency) - { - mergeCount += mergeQuadsInternal(this.transparentQuads, directionIndex, BufferMergeDirectionEnum.EastWest); - } - - - // only run the second merge if the face is the top or bottom - if (directionIndex == EDhDirection.UP.ordinal() || directionIndex == EDhDirection.DOWN.ordinal()) - { - mergeCount += mergeQuadsInternal(this.opaqueQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown); - if (this.doTransparency) - { - mergeCount += mergeQuadsInternal(this.transparentQuads, directionIndex, BufferMergeDirectionEnum.NorthSouthOrUpDown); - } - } - } - - long postQuadsCount = this.getCurrentOpaqueQuadsCount() + this.getCurrentTransparentQuadsCount(); - LOGGER.debug("Merged "+mergeCount+"/"+preQuadsCount+"("+(mergeCount / (double) preQuadsCount)+") quads"); - } - - /** Merges all of this builder's quads for the given directionIndex (up, down, left, etc.) in the given direction */ - private static long mergeQuadsInternal(ArrayList[] list, int directionIndex, BufferMergeDirectionEnum mergeDirection) - { - if (list[directionIndex].size() <= 1) - return 0; - - list[directionIndex].sort((objOne, objTwo) -> objOne.compare(objTwo, mergeDirection)); - - long mergeCount = 0; - ListIterator iter = list[directionIndex].listIterator(); - BufferQuad currentQuad = iter.next(); - while (iter.hasNext()) - { - BufferQuad nextQuad = iter.next(); - - if (currentQuad.tryMerge(nextQuad, mergeDirection)) - { - // merge successful, attempt to merge the next quad - mergeCount++; - iter.set(null); - } - else - { - // merge fail, move on to the next quad - currentQuad = nextQuad; - } - } - list[directionIndex].removeIf(Objects::isNull); - return mergeCount; - } - - - - //==============// - // buffer setup // - //==============// - - public Iterator makeOpaqueVertexBuffers() - { - return new Iterator() - { - final ByteBuffer bb = MemoryUtil.memAlloc(ColumnRenderBuffer.FULL_SIZED_BUFFER); - int dir = this.skipEmpty(0); - int quad = 0; - - private int skipEmpty(int d) - { - while (d < 6 && opaqueQuads[d].isEmpty()) - { - d++; - } - return d; - } - - @Override - public boolean hasNext() - { - return dir < 6; - } - - @Override - public ByteBuffer next() - { - if (dir >= 6) - { - return null; - } - bb.clear(); - bb.limit(ColumnRenderBuffer.FULL_SIZED_BUFFER); - while (bb.hasRemaining() && dir < 6) - { - writeData(); - } - bb.limit(bb.position()); - bb.rewind(); - return bb; - } - - private void writeData() - { - int i = quad; - for (; i < opaqueQuads[dir].size(); i++) - { - if (!bb.hasRemaining()) - { - break; - } - putQuad(bb, opaqueQuads[dir].get(i)); - } - - if (i >= opaqueQuads[dir].size()) - { - quad = 0; - dir++; - dir = skipEmpty(dir); - } - else - { - quad = i; - } - } - }; - } - - public Iterator makeTransparentVertexBuffers() - { - return new Iterator() - { - final ByteBuffer bb = MemoryUtil.memAlloc(ColumnRenderBuffer.FULL_SIZED_BUFFER); - int directionIndex = this.skipEmptyDirectionIndices(0); - int quad = 0; - - private int skipEmptyDirectionIndices(int directionIndex) - { - while (directionIndex < 6 && - (LodQuadBuilder.this.transparentQuads[directionIndex] == null - || LodQuadBuilder.this.transparentQuads[directionIndex].isEmpty())) - { - directionIndex++; - } - - return directionIndex; - } - - @Override - public boolean hasNext() { return this.directionIndex < 6; } - - @Override - public ByteBuffer next() - { - if (this.directionIndex >= 6) - { - return null; - } - - this.bb.clear(); - this.bb.limit(ColumnRenderBuffer.FULL_SIZED_BUFFER); - while (this.bb.hasRemaining() && this.directionIndex < 6) - { - this.writeData(); - } - this.bb.limit(this.bb.position()); - this.bb.rewind(); - return this.bb; - } - - private void writeData() - { - int i = this.quad; - for (; i < LodQuadBuilder.this.transparentQuads[this.directionIndex].size(); i++) - { - if (!this.bb.hasRemaining()) - { - break; - } - putQuad(this.bb, LodQuadBuilder.this.transparentQuads[this.directionIndex].get(i)); - } - - if (i >= LodQuadBuilder.this.transparentQuads[this.directionIndex].size()) - { - this.quad = 0; - this.directionIndex++; - this.directionIndex = this.skipEmptyDirectionIndices(this.directionIndex); - } - else - { - this.quad = i; - } - } - }; - } - public interface BufferFiller - { - /** If true: more data needs to be filled */ - boolean fill(GLVertexBuffer vbo); - - } - - public BufferFiller makeOpaqueBufferFiller(EDhApiGpuUploadMethod method) - { - return new BufferFiller() - { - int dir = 0; - int quad = 0; - - public boolean fill(GLVertexBuffer vbo) - { - if (dir >= 6) - { - vbo.setVertexCount(0); - return false; - } - - int numOfQuads = _countRemainingQuads(); - if (numOfQuads > ColumnRenderBuffer.MAX_QUADS_PER_BUFFER) - numOfQuads = ColumnRenderBuffer.MAX_QUADS_PER_BUFFER; - if (numOfQuads == 0) - { - vbo.setVertexCount(0); - return false; - } - ByteBuffer bb = vbo.mapBuffer(numOfQuads * ColumnRenderBuffer.QUADS_BYTE_SIZE, method, - ColumnRenderBuffer.FULL_SIZED_BUFFER); - if (bb == null) - throw new NullPointerException("mapBuffer returned null"); - bb.clear(); - bb.limit(numOfQuads * ColumnRenderBuffer.QUADS_BYTE_SIZE); - while (bb.hasRemaining() && dir < 6) - { - writeData(bb); - } - bb.rewind(); - vbo.unmapBuffer(); - vbo.setVertexCount(numOfQuads * 4); - return dir < 6; - } - - private int _countRemainingQuads() - { - int a = opaqueQuads[dir].size() - quad; - for (int i = dir + 1; i < opaqueQuads.length; i++) - { - a += opaqueQuads[i].size(); - } - return a; - } - - private void writeData(ByteBuffer bb) - { - int startQ = quad; - - int i = startQ; - for (i = startQ; i < opaqueQuads[dir].size(); i++) - { - if (!bb.hasRemaining()) - { - break; - } - putQuad(bb, opaqueQuads[dir].get(i)); - } - - if (i >= opaqueQuads[dir].size()) - { - quad = 0; - dir++; - while (dir < 6 && opaqueQuads[dir].isEmpty()) - { - dir++; - } - } - else - { - quad = i; - } - } - }; - } - - public BufferFiller makeTransparentBufferFiller(EDhApiGpuUploadMethod method) - { - return new BufferFiller() - { - int dir = 0; - int quad = 0; - - public boolean fill(GLVertexBuffer vbo) - { - if (dir >= 6) - { - vbo.setVertexCount(0); - return false; - } - - int numOfQuads = _countRemainingQuads(); - if (numOfQuads > ColumnRenderBuffer.MAX_QUADS_PER_BUFFER) - numOfQuads = ColumnRenderBuffer.MAX_QUADS_PER_BUFFER; - if (numOfQuads == 0) - { - vbo.setVertexCount(0); - return false; - } - ByteBuffer bb = vbo.mapBuffer(numOfQuads * ColumnRenderBuffer.QUADS_BYTE_SIZE, method, - ColumnRenderBuffer.FULL_SIZED_BUFFER); - if (bb == null) - throw new NullPointerException("mapBuffer returned null"); - bb.clear(); - bb.limit(numOfQuads * ColumnRenderBuffer.QUADS_BYTE_SIZE); - while (bb.hasRemaining() && dir < 6) - { - writeData(bb); - } - bb.rewind(); - vbo.unmapBuffer(); - vbo.setVertexCount(numOfQuads * 4); - return dir < 6; - } - - private int _countRemainingQuads() - { - int a = transparentQuads[dir].size() - quad; - for (int i = dir + 1; i < transparentQuads.length; i++) - { - a += transparentQuads[i].size(); - } - return a; - } - - private void writeData(ByteBuffer bb) - { - int startQ = quad; - - int i = startQ; - for (i = startQ; i < transparentQuads[dir].size(); i++) - { - if (!bb.hasRemaining()) - { - break; - } - putQuad(bb, transparentQuads[dir].get(i)); - } - - if (i >= transparentQuads[dir].size()) - { - quad = 0; - dir++; - while (dir < 6 && transparentQuads[dir].isEmpty()) - { - dir++; - } - } - else - { - quad = i; - } - } - }; - } - - - //=========// // getters // //=========// diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java index 4bbfbd6e8..c5556bd9d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java @@ -193,17 +193,7 @@ public class GLProxy return instance; } - public EDhApiGpuUploadMethod getGpuUploadMethod() - { - EDhApiGpuUploadMethod method = Config.Client.Advanced.GpuBuffers.gpuUploadMethod.get(); - if (!this.bufferStorageSupported && method == EDhApiGpuUploadMethod.BUFFER_STORAGE) - { - // if buffer storage isn't supported - // default to DATA since that is the most compatible - method = EDhApiGpuUploadMethod.DATA; - } - return method == EDhApiGpuUploadMethod.AUTO ? this.preferredUploadMethod : method; - } + public EDhApiGpuUploadMethod getGpuUploadMethod() { return this.preferredUploadMethod; } public boolean runningOnRenderThread() { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLBuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLBuffer.java index bdfee1f4b..c90ebc1c0 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLBuffer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLBuffer.java @@ -238,7 +238,7 @@ public class GLBuffer implements AutoCloseable // buffer mapping // //================// - public ByteBuffer mapBuffer(int targetSize, EDhApiGpuUploadMethod uploadMethod, int maxExpensionSize, int bufferHint, int mapFlags) + public ByteBuffer mapBuffer(int targetSize, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize, int bufferHint, int mapFlags) { LodUtil.assertTrue(targetSize != 0, "MapBuffer targetSize is 0"); LodUtil.assertTrue(uploadMethod.useEarlyMapping, "Upload method must be one that use early mappings in order to call mapBuffer"); @@ -252,7 +252,7 @@ public class GLBuffer implements AutoCloseable if (this.size < targetSize || this.size > targetSize * BUFFER_SHRINK_TRIGGER) { int newSize = (int) (targetSize * BUFFER_EXPANSION_MULTIPLIER); - if (newSize > maxExpensionSize) newSize = maxExpensionSize; + if (newSize > maxExpansionSize) newSize = maxExpansionSize; this.size = newSize; if (this.bufferStorage) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLVertexBuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLVertexBuffer.java index f3957ef56..5c5586e61 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLVertexBuffer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/buffer/GLVertexBuffer.java @@ -77,9 +77,9 @@ public class GLVertexBuffer extends GLBuffer this.vertexCount = vertCount; } - public ByteBuffer mapBuffer(int targetSize, EDhApiGpuUploadMethod uploadMethod, int maxExpensionSize) + public ByteBuffer mapBuffer(int targetSize, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize) { - return super.mapBuffer(targetSize, uploadMethod, maxExpensionSize, + return super.mapBuffer(targetSize, uploadMethod, maxExpansionSize, uploadMethod.useBufferStorage ? GL32.GL_MAP_WRITE_BIT : uploadMethod.useEarlyMapping ? GL32.GL_DYNAMIC_DRAW : GL32.GL_STATIC_DRAW, GL32.GL_MAP_WRITE_BIT | GL32.GL_MAP_UNSYNCHRONIZED_BIT | GL32.GL_MAP_INVALIDATE_BUFFER_BIT);