diff --git a/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java b/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java index 72066a1a..a4bba2bd 100644 --- a/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java +++ b/src/main/java/me/cortex/voxy/client/config/VoxyConfig.java @@ -3,6 +3,7 @@ package me.cortex.voxy.client.config; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import me.cortex.voxy.client.core.Capabilities; import me.cortex.voxy.client.saver.ContextSelectionSystem; import net.fabricmc.loader.api.FabricLoader; import org.lwjgl.opengl.GL; @@ -68,7 +69,6 @@ public class VoxyConfig { } public boolean useMeshShaders() { - var cap = GL.getCapabilities(); - return this.useMeshShaderIfPossible && cap.GL_NV_mesh_shader && cap.GL_NV_representative_fragment_test; + return this.useMeshShaderIfPossible && Capabilities.INSTANCE.meshShaders; } } diff --git a/src/main/java/me/cortex/voxy/client/core/Capabilities.java b/src/main/java/me/cortex/voxy/client/core/Capabilities.java new file mode 100644 index 00000000..87548163 --- /dev/null +++ b/src/main/java/me/cortex/voxy/client/core/Capabilities.java @@ -0,0 +1,16 @@ +package me.cortex.voxy.client.core; + +import org.lwjgl.opengl.GL; + +public class Capabilities { + + public static final Capabilities INSTANCE = new Capabilities(); + + public final boolean meshShaders; + public final boolean INT64_t; + public Capabilities() { + var cap = GL.getCapabilities(); + this.meshShaders = cap.GL_NV_mesh_shader && cap.GL_NV_representative_fragment_test; + this.INT64_t = cap.GL_ARB_gpu_shader_int64 || cap.GL_AMD_gpu_shader_int64; + } +} diff --git a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java index 2d442bff..dfd356fc 100644 --- a/src/main/java/me/cortex/voxy/client/core/VoxelCore.java +++ b/src/main/java/me/cortex/voxy/client/core/VoxelCore.java @@ -68,23 +68,12 @@ public class VoxelCore { //Trigger the shared index buffer loading SharedIndexBuffer.INSTANCE.id(); - if (true) { - this.renderer = new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); - System.out.println("Using Gl46MeshletFarWorldRendering"); - } else { - if (VoxyConfig.CONFIG.useMeshShaders()) { - this.renderer = new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); - System.out.println("Using NvMeshFarWorldRenderer"); - } else { - this.renderer = new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); - System.out.println("Using Gl46FarWorldRenderer"); - } - } + this.renderer = this.createRenderBackend(); this.viewportSelector = new ViewportSelector<>(this.renderer::createViewport); System.out.println("Renderer initialized"); this.renderTracker = new RenderTracker(this.world, this.renderer); - this.renderGen = new RenderGenerationService(this.world, this.renderer.getModelManager(), VoxyConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult); + this.renderGen = new RenderGenerationService(this.world, this.renderer.getModelManager(), VoxyConfig.CONFIG.renderThreads, this.renderTracker::processBuildResult, this.renderer.usesMeshlets()); this.world.setDirtyCallback(this.renderTracker::sectionUpdated); this.renderTracker.setRenderGen(this.renderGen); System.out.println("Render tracker and generator initialized"); @@ -130,6 +119,20 @@ public class VoxelCore { System.out.println("Voxy core initialized"); } + private AbstractFarWorldRenderer createRenderBackend() { + if (true) { + System.out.println("Using Gl46MeshletFarWorldRendering"); + return new Gl46MeshletsFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); + } else { + if (VoxyConfig.CONFIG.useMeshShaders()) { + System.out.println("Using NvMeshFarWorldRenderer"); + return new NvMeshFarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); + } else { + System.out.println("Using Gl46FarWorldRenderer"); + return new Gl46FarWorldRenderer(VoxyConfig.CONFIG.geometryBufferSize, VoxyConfig.CONFIG.maxSections); + } + } + } public void enqueueIngest(WorldChunk worldChunk) { diff --git a/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java b/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java index 977eb7e9..411bd876 100644 --- a/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java +++ b/src/main/java/me/cortex/voxy/client/core/rendering/AbstractFarWorldRenderer.java @@ -174,4 +174,8 @@ public abstract class AbstractFarWorldRenderer resultConsumer; private final BuiltSectionMeshCache meshCache = new BuiltSectionMeshCache(); + private final boolean emitMeshlets; - public RenderGenerationService(WorldEngine world, ModelManager modelManager, int workers, Consumer consumer) { + public RenderGenerationService(WorldEngine world, ModelManager modelManager, int workers, Consumer consumer, boolean emitMeshlets) { + this.emitMeshlets = emitMeshlets; this.world = world; this.modelManager = modelManager; this.resultConsumer = consumer; @@ -47,7 +49,7 @@ public class RenderGenerationService { //TODO: add a generated render data cache private void renderWorker() { //Thread local instance of the factory - var factory = new RenderDataFactory(this.world, this.modelManager); + var factory = new RenderDataFactory(this.world, this.modelManager, this.emitMeshlets); while (this.running) { this.taskCounter.acquireUninterruptibly(); if (!this.running) break; diff --git a/src/main/resources/assets/voxy/shaders/heriacial_selector/hierarchical_worker.comp b/src/main/resources/assets/voxy/shaders/heriacial_selector/hierarchical_worker.comp new file mode 100644 index 00000000..4aba598e --- /dev/null +++ b/src/main/resources/assets/voxy/shaders/heriacial_selector/hierarchical_worker.comp @@ -0,0 +1,32 @@ +#version 460 + +layout(local_size_x=8) + + + + +//NEW IDEAm use the depth buffer directly to compute the lod level needed to cover it + + + + +//Location in world space up to 2x2x2 block size resolution +#define OctNodeTask uint64_t + + + +//First 32 bits are the start of child +// next 16 bits are split into 8 pairs, each pair specifies the type of the subnode (air/empty, partial, full) + + + +//Tasks are of size uint64_t + + + +void main() { + while (true) { + barrier(); + + } +} \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/heriacial_selector/persistent_threads.comp b/src/main/resources/assets/voxy/shaders/heriacial_selector/persistent_threads.comp new file mode 100644 index 00000000..70d17993 --- /dev/null +++ b/src/main/resources/assets/voxy/shaders/heriacial_selector/persistent_threads.comp @@ -0,0 +1,37 @@ +#version 460 + +#define WAVE_SIZE 64 +layout(local_size_x=WAVE_SIZE) + +#define WorkTask + + +//or make the shape 4x2x4 which has a local size of 32 + + +//The work queue is a circular queue with collision detection and abortion +struct WorkQueueHeader { + uint queueSizeBits; + uint start; + uint end; + uint _padd; +}; + + +//Task is a uint32, + +//The idea is to use persistent threads + octree culling to recursivly find bottom level sections that satisfy a pixel density requirement +// given a matrix +void main() { + while (true) { + + } +} + + + +//Idea cull/recuse in a manor of 4x4x4 cube (64 bits), have an existance mask per section so that unnessasery computation isnt done on air subsections +// if a section is fully or partially visible and its aabb does not occupy 1 pixel (or a subset of some specified area/density) +// then enqueue that section as a job +// once a node has reached its tail ending, check if its loaded or not, if not, request it to be loaded +// note that the cpu side can discard sections if they are superceeded by a higher level lod load request etc diff --git a/src/main/resources/assets/voxy/shaders/heriacial_selector/traversal.comp b/src/main/resources/assets/voxy/shaders/heriacial_selector/traversal.comp new file mode 100644 index 00000000..efbc0d47 --- /dev/null +++ b/src/main/resources/assets/voxy/shaders/heriacial_selector/traversal.comp @@ -0,0 +1,24 @@ +#version 460 + +layout(local_size_x=32) + +//Works in multiple parts +// first is a downwards traversal from a base level that finds all the bottom level pixel detail AABBs +// task queue is firstly filled with large visible AABB's from rastered occlusion +// +// each node metadata contains the position in 3d space relative to the toplevel node +// an offset into the datapool for the child nodes, and union between (a bitmsk of if a child node is full, empty, or mixed (or unloaded)) +// and a pointer to render metadata for meshlets + + +//The overarching idea is to have meshlets be automatatically selected based on the resulting pixel size/density +// after 3d projection, we dont want subpixel triangles and we want to be able to automatically account for the +// perspective warp on the edges of the screen (e.g. high fov == higher density at the center of the screen) +// from this, the gpu can then (if they are not present) request meshlets be added and thereby automatic lod selection +// and dynamic building resulting in possibly O(fast) rendering +void main() { + while (true) { + barrier(); + + } +} \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshlet.glsl b/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshlet.glsl index fdcb3a3f..5b4d7b40 100644 --- a/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshlet.glsl +++ b/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshlet.glsl @@ -17,7 +17,7 @@ uint extractDetail(PosHeader pos64) { return uint(pos64>>60); } uvec3 extractMin(AABBHeader aabb) { - return uvec3(uint(aabb&0xFF),uint((aabb>>8)&0xFF),uint((aabb>>16)&0xFF)); + return uvec3(uint(uint(aabb)&0xFF),uint((uint(aabb)>>8)&0xFF),uint((uint(aabb)>>16)&0xFF)); } uvec3 extractMax(AABBHeader aabb) { return uvec3(uint((aabb>>24)&0xFF),uint((aabb>>32)&0xFF),uint((aabb>>40)&0xFF)); diff --git a/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshletculler.comp b/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshletculler.comp index d99868ca..1b1a74ac 100644 --- a/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshletculler.comp +++ b/src/main/resources/assets/voxy/shaders/lod/gl46mesh/meshletculler.comp @@ -16,14 +16,18 @@ vec3 proj(vec3 pos) { bool testHiZ(PosHeader secPos, AABBHeader aabb) { ivec3 section = extractPosition(secPos); uint detail = extractDetail(secPos); - ivec3 pos = (((section<>1)&1u)*-4.0); if ((flags&1u) == 1 && colour.a <= 0.25f) { - discard; + //discard; } //Conditional tinting, TODO: FIXME: REPLACE WITH MASK OR SOMETHING, like encode data into the top bit of alpha @@ -31,12 +31,11 @@ void main() { //outColour = vec4(uv + baseUV, 0, 1); - /* + uint hash = meshlet*1231421+123141; hash ^= hash>>16; hash = hash*1231421+123141; hash ^= hash>>16; - - outColour = vec4(float(hash&15u)/15, float((hash>>4)&15u)/15, float((hash>>8)&15u)/15, 1); - */ + hash = hash * 1827364925 + 123325621; + //outColour = vec4(float(hash&15u)/15, float((hash>>4)&15u)/15, float((hash>>8)&15u)/15, 1); } \ No newline at end of file diff --git a/src/main/resources/assets/voxy/shaders/lod/gl46mesh/quads.vert b/src/main/resources/assets/voxy/shaders/lod/gl46mesh/quads.vert index 8e0432b3..71cabf5c 100644 --- a/src/main/resources/assets/voxy/shaders/lod/gl46mesh/quads.vert +++ b/src/main/resources/assets/voxy/shaders/lod/gl46mesh/quads.vert @@ -84,6 +84,7 @@ void main() { uint lodLevel = extractDetail(meshletPosition); ivec3 sectionPos = extractPosition(meshletPosition); + //meshlet = (meshlet<<5)|(gl_VertexID>>2);