This commit is contained in:
mcrcortex
2025-05-13 17:26:49 +10:00
parent 0028e5ec8f
commit 3ade56c582
9 changed files with 149 additions and 52 deletions

View File

@@ -1,11 +1,13 @@
package me.cortex.voxy.client.core;
import com.mojang.blaze3d.opengl.GlConst;
import com.mojang.blaze3d.opengl.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import me.cortex.voxy.client.TimingStatistics;
import me.cortex.voxy.client.config.VoxyConfig;
import me.cortex.voxy.client.core.gl.Capabilities;
import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.gl.GlTexture;
import me.cortex.voxy.client.core.model.ModelBakerySubsystem;
import me.cortex.voxy.client.core.rendering.ChunkBoundRenderer;
import me.cortex.voxy.client.core.rendering.RenderDistanceTracker;
@@ -42,6 +44,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.opengl.GL30C.GL_DRAW_FRAMEBUFFER_BINDING;
import static org.lwjgl.opengl.GL30C.glBindFramebuffer;
import static org.lwjgl.opengl.GL33.glBindSampler;
public class VoxyRenderSystem {
private final RenderService renderer;
@@ -217,11 +220,27 @@ public class VoxyRenderSystem {
TimingStatistics.postDynamic.stop();
glBindFramebuffer(GlConst.GL_FRAMEBUFFER, oldFB);
{//Reset state manager stuffs
GlStateManager._glBindVertexArray(0);//Clear binding
GlStateManager._activeTexture(GlConst.GL_TEXTURE0);
GlStateManager._bindTexture(0);
glBindSampler(0, 0);
GlStateManager._activeTexture(GlConst.GL_TEXTURE1);
GlStateManager._bindTexture(0);
glBindSampler(1, 0);
GlStateManager._activeTexture(GlConst.GL_TEXTURE2);
GlStateManager._bindTexture(0);
glBindSampler(2, 0);
}
TimingStatistics.all.stop();
}
public void addDebugInfo(List<String> debug) {
debug.add("GlBuffer, Count/Size (mb): " + GlBuffer.getCount() + "/" + (GlBuffer.getTotalSize()/1_000_000));
debug.add("Buf/Tex [#/Mb]: [" + GlBuffer.getCount() + "/" + (GlBuffer.getTotalSize()/1_000_000) + "],[" + GlTexture.getCount() + "/" + (GlTexture.getEstimatedTotalSize()/1_000_000)+"]");
this.renderer.addDebugData(debug);
{
TimingStatistics.update();

View File

@@ -7,6 +7,7 @@ import org.lwjgl.opengl.GL20C;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL32.glGetInteger64;
import static org.lwjgl.opengl.GL43C.GL_MAX_SHADER_STORAGE_BLOCK_SIZE;
import static org.lwjgl.opengl.NVXGPUMemoryInfo.*;
public class Capabilities {
@@ -16,9 +17,13 @@ public class Capabilities {
public final boolean INT64_t;
public final long ssboMaxSize;
public final boolean isMesa;
public final boolean canQueryGpuMemory;
public final long totalDedicatedMemory;//Bytes, dedicated memory
public final long totalDynamicMemory;//Bytes, total allocation memory - dedicated memory
public Capabilities() {
var cap = GL.getCapabilities();
this.meshShaders = cap.GL_NV_mesh_shader && cap.GL_NV_representative_fragment_test;
this.canQueryGpuMemory = cap.GL_NVX_gpu_memory_info;
//this.INT64_t = cap.GL_ARB_gpu_shader_int64 || cap.GL_AMD_gpu_shader_int64;
//The only reliable way to test for int64 support is to try compile a shader
this.INT64_t = testShaderCompilesOk(ShaderType.COMPUTE, """
@@ -33,6 +38,14 @@ public class Capabilities {
this.ssboMaxSize = glGetInteger64(GL_MAX_SHADER_STORAGE_BLOCK_SIZE);
this.isMesa = glGetString(GL_VERSION).toLowerCase().contains("mesa");
if (this.canQueryGpuMemory) {
this.totalDedicatedMemory = glGetInteger64(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX)*1024;//Since its in Kb
this.totalDynamicMemory = (glGetInteger64(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX)*1024) - this.totalDedicatedMemory;//Since its in Kb
} else {
this.totalDedicatedMemory = -1;
this.totalDynamicMemory = -1;
}
}
public static void init() {
@@ -47,4 +60,13 @@ public class Capabilities {
return result == GL20C.GL_TRUE;
}
public long getFreeDedicatedGpuMemory() {
if (!this.canQueryGpuMemory) {
throw new IllegalStateException("Cannot query gpu memory, missing extension");
}
return glGetInteger64(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX)*1024;//Since its in Kb
}
//TODO: add gpu eviction tracking
}

View File

@@ -4,8 +4,9 @@ import me.cortex.voxy.common.util.TrackedObject;
import static org.lwjgl.opengl.ARBFramebufferObject.glDeleteFramebuffers;
import static org.lwjgl.opengl.ARBFramebufferObject.glGenFramebuffers;
import static org.lwjgl.opengl.GL11.GL_RGBA8;
import static org.lwjgl.opengl.GL11C.*;
import static org.lwjgl.opengl.GL30C.glGetIntegeri;
import static org.lwjgl.opengl.GL30.GL_DEPTH24_STENCIL8;
import static org.lwjgl.opengl.GL45C.*;
public class GlTexture extends TrackedObject {
@@ -14,7 +15,12 @@ public class GlTexture extends TrackedObject {
private int format;
private int width;
private int height;
private int layers;
private int levels;
private boolean hasAllocated;
private static int COUNT;
private static long ESTIMATED_TOTAL_SIZE;
public GlTexture() {
this(GL_TEXTURE_2D);
}
@@ -22,6 +28,7 @@ public class GlTexture extends TrackedObject {
public GlTexture(int type) {
this.id = glCreateTextures(type);
this.type = type;
COUNT++;
}
private GlTexture(int type, boolean useGenTypes) {
@@ -31,22 +38,30 @@ public class GlTexture extends TrackedObject {
this.id = glCreateTextures(type);
}
this.type = type;
COUNT++;
}
public GlTexture store(int format, int levels, int width, int height) {
if (this.hasAllocated) {
throw new IllegalStateException("Texture already allocated");
}
this.hasAllocated = true;
this.format = format;
if (this.type == GL_TEXTURE_2D) {
glTextureStorage2D(this.id, levels, format, width, height);
this.width = width;
this.height = height;
this.layers = layers;
this.levels = levels;
} else {
throw new IllegalStateException("Unknown texture type");
}
ESTIMATED_TOTAL_SIZE += this.getEstimatedSize();
return this;
}
public GlTexture createView() {
this.assertAllocated();
var view = new GlTexture(this.type, true);
glTextureView(view.id, this.type, this.id, this.format, 0, 1, 0, 1);
return view;
@@ -54,23 +69,63 @@ public class GlTexture extends TrackedObject {
@Override
public void free() {
if (this.hasAllocated) {
ESTIMATED_TOTAL_SIZE -= this.getEstimatedSize();
}
COUNT--;
this.hasAllocated = false;
super.free0();
glDeleteTextures(this.id);
}
public GlTexture name(String name) {
this.assertAllocated();
return GlDebug.name(name, this);
}
public int getWidth() {
this.assertAllocated();
return this.width;
}
public int getHeight() {
this.assertAllocated();
return this.height;
}
public int getLayers() {
return this.layers;
public int getLevels() {
this.assertAllocated();
return this.levels;
}
private long getEstimatedSize() {
this.assertAllocated();
long elemSize = switch (this.format) {
case GL_RGBA8, GL_DEPTH24_STENCIL8 -> 4;
case GL_DEPTH_COMPONENT24 -> 4;//TODO: check this is right????
default -> throw new IllegalStateException("Unknown element size");
};
long size = 0;
for (int lvl = 0; lvl < this.levels; lvl++) {
size += Math.max((((long)this.width)>>lvl), 1) * Math.max((((long)this.height)>>lvl), 1) * elemSize;
}
return size;
}
public void assertAllocated() {
if (!this.hasAllocated) {
throw new IllegalStateException("Texture not yet allocated");
}
}
public static int getCount() {
return COUNT;
}
public static long getEstimatedTotalSize() {
return ESTIMATED_TOTAL_SIZE;
}
}

View File

@@ -1,18 +1,14 @@
package me.cortex.voxy.client.core.gl.shader;
import com.mojang.blaze3d.opengl.GlConst;
import com.mojang.blaze3d.opengl.GlStateManager;
import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.gl.GlDebug;
import me.cortex.voxy.client.core.gl.GlTexture;
import me.cortex.voxy.common.util.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.lwjgl.opengl.ARBDirectStateAccess.glBindTextureUnit;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL30.glBindBufferBase;
import static org.lwjgl.opengl.GL30.glBindBufferRange;
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
@@ -117,8 +113,6 @@ public class AutoBindingShader extends Shader {
for (var binding : this.textureBindings) {
if (binding.texture != null) {
binding.texture.assertNotFreed();
GlStateManager._activeTexture(GlConst.GL_TEXTURE0+binding.unit);
GlStateManager._bindTexture(0);
glBindTextureUnit(binding.unit, binding.texture.id);
}
if (binding.sampler != -1) {

View File

@@ -1,10 +1,5 @@
package me.cortex.voxy.client.core.model.bakery;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.opengl.GlConst;
import com.mojang.blaze3d.opengl.GlStateManager;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.platform.DepthTestFunction;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
import com.mojang.blaze3d.vertex.VertexFormat;
@@ -12,22 +7,14 @@ import me.cortex.voxy.client.core.gl.GlBuffer;
import me.cortex.voxy.client.core.gl.GlVertexArray;
import me.cortex.voxy.client.core.gl.shader.Shader;
import me.cortex.voxy.client.core.gl.shader.ShaderType;
import me.cortex.voxy.client.core.rendering.util.SharedIndexBuffer;
import me.cortex.voxy.client.core.rendering.util.UploadStream;
import me.cortex.voxy.common.util.UnsafeUtil;
import net.minecraft.client.gl.*;
import net.minecraft.client.gl.GlGpuBuffer;
import net.minecraft.client.render.BuiltBuffer;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.util.Identifier;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.ARBVertexArrayObject.glBindVertexArray;
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
import static org.lwjgl.opengl.GL33.glBindSampler;
import static org.lwjgl.opengl.GL43.glBindVertexBuffer;
import static org.lwjgl.opengl.GL45.*;
public class BudgetBufferRenderer {
@@ -82,9 +69,6 @@ public class BudgetBufferRenderer {
throw new IllegalStateException();
}
GlStateManager._activeTexture(GlConst.GL_TEXTURE0);
GlStateManager._bindTexture(0);
quadCount = quads;
long size = quads * 4L * STRIDE;
@@ -101,6 +85,7 @@ public class BudgetBufferRenderer {
bakeryShader.bind();
VA.bind();
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
glBindSampler(0, 0);
glBindTextureUnit(0, texId);
}

View File

@@ -21,8 +21,7 @@ import net.minecraft.world.chunk.light.LightingProvider;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import static org.lwjgl.opengl.ARBShaderImageLoadStore.GL_FRAMEBUFFER_BARRIER_BIT;
import static org.lwjgl.opengl.ARBShaderImageLoadStore.glMemoryBarrier;
import static org.lwjgl.opengl.ARBShaderImageLoadStore.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14C.glBlendFuncSeparate;
import static org.lwjgl.opengl.GL30.*;
@@ -268,7 +267,7 @@ public class ModelTextureBakery {
glDisable(GL_BLEND);
//Finish and download
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT|GL_TEXTURE_UPDATE_BARRIER_BIT|GL_PIXEL_BUFFER_BARRIER_BIT|GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);//Am not sure if barriers are right
this.capture.emitToStream(streamBuffer, streamOffset);
glBindFramebuffer(GL_FRAMEBUFFER, this.capture.framebuffer.id);

View File

@@ -39,15 +39,27 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
private final WorldEngine world;
private static long getGeometryBufferSize() {
long geometryCapacity = Math.min((1L<<(64-Long.numberOfLeadingZeros(Capabilities.INSTANCE.ssboMaxSize-1)))<<1, 1L<<32)-1024/*(1L<<32)-1024*/;
//Limit to available dedicated memory if possible
if (Capabilities.INSTANCE.canQueryGpuMemory) {
//512mb less than avalible,
long limit = Capabilities.INSTANCE.getFreeDedicatedGpuMemory() - 512*1024*1024;
// Give a minimum of 512 mb requirement
limit = Math.max(512*1024*1024, limit);
geometryCapacity = Math.min(geometryCapacity, limit);
}
//geometryCapacity = 1<<24;
return geometryCapacity;
}
@SuppressWarnings("unchecked")
public RenderService(WorldEngine world, ServiceThreadPool serviceThreadPool) {
this.world = world;
this.modelService = new ModelBakerySubsystem(world.getMapper());
//Max geometry: 1 gb
long geometryCapacity = Math.min((1L<<(64-Long.numberOfLeadingZeros(Capabilities.INSTANCE.ssboMaxSize-1)))<<1, 1L<<32)-1024/*(1L<<32)-1024*/;
//geometryCapacity = 1<<24;
long geometryCapacity = getGeometryBufferSize();
this.geometryData = (Q) new BasicSectionGeometryData(1<<20, geometryCapacity);
//Max sections: ~500k
@@ -102,7 +114,6 @@ public class RenderService<T extends AbstractSectionRenderer<J, Q>, J extends Vi
this.sectionRenderer.renderOpaque(viewport, depthBoundTexture);
//NOTE: need to do the upload and download tick here, after the section renderer renders the world, to ensure "stable"
// sections

View File

@@ -130,21 +130,21 @@ public class AsyncNodeManager {
private void run() {
if (this.workCounter.get() == 0) {
LockSupport.park();
if (this.workCounter.get() == 0) {//No work
if (this.workCounter.get() == 0 || !this.running) {//No work
return;
}
//This is a funny thing, wait a bit, this allows for better batching, but this thread is independent of everything else so waiting a bit should be mostly ok
try {
Thread.sleep(25);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (!this.running) {
return;
}
//This is a funny thing, wait a bit, this allows for better batching, but this thread is independent of everything else so waiting a bit should be mostly ok
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
int workDone = 0;
@@ -370,8 +370,14 @@ public class AsyncNodeManager {
int val = iter.nextInt();
int placeId = results.geometryIdUpdateMap.putIfAbsent(val, results.geometryIdUpdateMap.size());
placeId = placeId==-1?results.geometryIdUpdateMap.size()-1:placeId;
if (512<=placeId) {
throw new IllegalStateException("Outside range of allowed updates");
if (results.geometryIdUpdateData.size<=placeId*32L) {
//We need to expand the buffer :(
var old = results.geometryIdUpdateData;
var newBuffer = new MemoryBuffer((long) (old.size*1.5));
Logger.info("Expanding geometry update buffer to " + newBuffer.size);
old.cpyTo(newBuffer.address);
old.free();
results.geometryIdUpdateData = newBuffer;
}
//Write updated data
this.geometryManager.writeMetadata(val, placeId*32L + results.geometryIdUpdateData.address);
@@ -388,8 +394,14 @@ public class AsyncNodeManager {
int val = iter.nextInt();
int placeId = results.nodeIdUpdateMap.putIfAbsent(val, results.nodeIdUpdateMap.size());
placeId = placeId==-1?results.nodeIdUpdateMap.size()-1:placeId;
if (1024<=placeId) {
throw new IllegalStateException("Outside range of allowed updates");
if (results.nodeIdUpdateData.size<=placeId*16L) {
//We need to expand the buffer :(
var old = results.nodeIdUpdateData;
var newBuffer = new MemoryBuffer((long) (old.size*1.5));
Logger.info("Expanding node update buffer to " + newBuffer.size);
old.cpyTo(newBuffer.address);
old.free();
results.nodeIdUpdateData = newBuffer;
}
//Write updated data
this.manager.writeNode(val, placeId*16L + results.nodeIdUpdateData.address);
@@ -633,7 +645,7 @@ public class AsyncNodeManager {
//Node id updates + size
private final Int2IntOpenHashMap nodeIdUpdateMap = new Int2IntOpenHashMap();//node id to update data location
private final MemoryBuffer nodeIdUpdateData = new MemoryBuffer(8192*2);//capacity for 1024 entries, TODO: ADD RESIZE
private MemoryBuffer nodeIdUpdateData = new MemoryBuffer(8192*2);//capacity for 1024 entries, TODO: ADD RESIZE
private int currentMaxNodeId;// the id of the ending of the node ids
//TLN add/rem
@@ -643,7 +655,7 @@ public class AsyncNodeManager {
private int geometrySectionCount;
private final Int2ObjectOpenHashMap<MemoryBuffer> geometryUploads = new Int2ObjectOpenHashMap<>();
private final Int2IntOpenHashMap geometryIdUpdateMap = new Int2IntOpenHashMap();//geometry id to update data location
private final MemoryBuffer geometryIdUpdateData = new MemoryBuffer(8192*2);//capacity for 512 entries, TODO: ADD RESIZE
private MemoryBuffer geometryIdUpdateData = new MemoryBuffer(8192*2);//capacity for 512 entries, TODO: ADD RESIZE
public SyncResults() {

View File

@@ -7,7 +7,7 @@ out vec4 colour;
void main() {
colour = texture(tex, texCoord);
if (colour.a < 0.0001f && ((metadata&1u)!=0)) {
if (colour.a < 0.001f && ((metadata&1u)!=0)) {
discard;
}
}