World and work stuff
This commit is contained in:
16
build.gradle
16
build.gradle
@@ -22,11 +22,23 @@ repositories {
|
||||
maven { url "https://maven.terraformersmc.com/releases/" }
|
||||
}
|
||||
|
||||
|
||||
def gitCommitHash = { ->
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine 'git', 'rev-parse', '--short', 'HEAD'
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
def buildtime = System.currentTimeSeconds()
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
inputs.properties("version": project.version, "commit": gitCommitHash, "buildtime": buildtime)
|
||||
|
||||
archivesBaseName = "voxy"
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
expand "commit": gitCommitHash, "version": project.version, "buildtime": buildtime
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,6 @@ import net.minecraft.client.world.ClientWorld;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Voxy implements ClientModInitializer {
|
||||
public static final String VERSION;
|
||||
|
||||
static {
|
||||
ModContainer mod = (ModContainer) FabricLoader.getInstance().getModContainer("voxy").orElseThrow(NullPointerException::new);
|
||||
VERSION = mod.getMetadata().getVersion().getFriendlyString();
|
||||
Serialization.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
|
||||
|
||||
@@ -11,6 +11,7 @@ import me.cortex.voxy.client.saver.ContextSelectionSystem;
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
import me.cortex.voxy.client.importers.WorldImporter;
|
||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.hud.ClientBossBar;
|
||||
import net.minecraft.client.render.Camera;
|
||||
@@ -150,7 +151,7 @@ public class VoxelCore {
|
||||
public void addDebugInfo(List<String> debug) {
|
||||
debug.add("");
|
||||
debug.add("");
|
||||
debug.add("Voxy Core: " + Voxy.VERSION);
|
||||
debug.add("Voxy Core: " + VoxyCommon.MOD_VERSION);
|
||||
/*
|
||||
debug.add("Ingest service tasks: " + this.world.ingestService.getTaskCount());
|
||||
debug.add("Saving service tasks: " + this.world.savingService.getTaskCount());
|
||||
|
||||
@@ -62,13 +62,17 @@ public class SectionUpdateRouter {
|
||||
public boolean unwatch(long position, int types) {
|
||||
var set = this.slices[getSliceIndex(position)];
|
||||
synchronized (set) {
|
||||
if (!set.containsKey(position)) {
|
||||
throw new IllegalStateException("Section pos not in map!! " + WorldEngine.pprintPos(position));
|
||||
}
|
||||
byte current = set.get(position);
|
||||
byte delta = (byte) (current&types);
|
||||
current &= (byte) ~types;
|
||||
if (current == 0) {
|
||||
set.remove(position);
|
||||
return true;
|
||||
}
|
||||
return delta!=0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,12 @@ package me.cortex.voxy.client.core.rendering.hierachical2;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import me.cortex.voxy.client.Voxy;
|
||||
import me.cortex.voxy.client.core.rendering.building.BuiltSection;
|
||||
import me.cortex.voxy.client.core.rendering.building.SectionUpdateRouter;
|
||||
import me.cortex.voxy.client.core.rendering.section.AbstractSectionGeometryManager;
|
||||
import me.cortex.voxy.client.core.util.ExpandingObjectAllocationList;
|
||||
import me.cortex.voxy.common.Logger;
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
import me.cortex.voxy.common.world.WorldSection;
|
||||
import me.jellysquid.mods.sodium.client.util.MathUtil;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
@@ -52,10 +50,16 @@ public class HierarchicalNodeManager {
|
||||
* * Technically an error state, as a leaf node should always have geometry (or marked as empty geometry data)
|
||||
*/
|
||||
|
||||
//WARNING! need to solve a section geometry which is empty having its geometry removed, cause its empty
|
||||
// so it wont send a request back cpu side
|
||||
|
||||
|
||||
//There are a few properties of the class that can be used for verification
|
||||
// a position cannot be both in a request and have an associated node, it must be none, in a request or a node
|
||||
// leaf nodes cannot have a childptr
|
||||
// updateRouter tracking child events should be the same set as activeSectionMap
|
||||
// any allocated indices in requests are not finished/are in flight
|
||||
// for all requests there must be an associated and valid node in the activeSectionMap
|
||||
// for all requests the parent node must exist and cannot be ID_TYPE_REQUEST
|
||||
// for all inner nodes, if there are no requests the children nodes must match the nodes childExistence bitset
|
||||
// if there is a request, it should be the delta to get from the old children to the new children
|
||||
// no node can have an empty childExistence (except for top level nodes)
|
||||
|
||||
private static final int NO_NODE = -1;
|
||||
|
||||
@@ -229,12 +233,82 @@ public class HierarchicalNodeManager {
|
||||
int type = (nodeId & ID_TYPE_MSK);
|
||||
nodeId &= ~ID_TYPE_MSK;
|
||||
if (type == ID_TYPE_REQUEST) {
|
||||
//Doesnt result in an invalidation as we must wait for geometry?
|
||||
//Doesnt result in an invalidation as we must wait for geometry to create a child
|
||||
this.requests.get(nodeId).putChildResult(getChildIdx(position), childExistence);
|
||||
} else if (type == ID_TYPE_LEAF || type == ID_TYPE_NONE || type == ID_TYPE_TOP) {
|
||||
//For all the types, if there is a request attatched, need to update the request data (and update the associated sections in the activeSectionMap)
|
||||
// if there isnt a current request, and there are nodes that got added, create a request
|
||||
//if any children dont exist anymore, need to delete them
|
||||
//ALSO: TODO: HERE: if a child is removed, need to remove it and all children accociated
|
||||
|
||||
//If its an inner node and doesnt have an inflight request, create an empty request, this will get autofilled by the following part
|
||||
if (type == ID_TYPE_NONE) {
|
||||
|
||||
}
|
||||
//If its a top level node, it needs a request? aswell
|
||||
|
||||
//If its a leaf node, its fine, dont need to create a request, only need to update the node msk
|
||||
|
||||
|
||||
if (this.nodeData.isNodeRequestInFlight(nodeId)) {
|
||||
int reqId = this.nodeData.getNodeRequest(nodeId);
|
||||
var request = this.requests.get(reqId);
|
||||
byte reqMsk = request.getMsk();
|
||||
if (reqMsk != childExistence) {
|
||||
//Only need to change if its not the same
|
||||
byte toRem = (byte) ((~childExistence)&reqMsk);
|
||||
if (toRem != 0) {
|
||||
//Remove nodes from the request
|
||||
for (int i = 0; i < 8; i++) {//TODO: swap out for numberOfTrailingZeros loop thing
|
||||
if ((toRem&(i<<1))==0) continue;
|
||||
int geometry = request.removeAndUnRequire(i);
|
||||
long cpos = makeChildPos(position, i);
|
||||
//Remove from update router and activeSectionMap
|
||||
int cid = this.activeSectionMap.remove(cpos);
|
||||
if ((cid&ID_TYPE_MSK)!=ID_TYPE_REQUEST || (cid&~ID_TYPE_MSK)!=reqId) {
|
||||
throw new IllegalStateException(WorldEngine.pprintPos(position)+" " + i + " " + cid + " " + reqId);
|
||||
}
|
||||
///Remove all from update router
|
||||
if (!this.updateRouter.unwatch(cpos, WorldEngine.UPDATE_FLAGS)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
//Release geometry if it had any
|
||||
if (geometry != -1) {
|
||||
this.geometryManager.removeSection(geometry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte toAdd = (byte) ((~reqMsk)&childExistence);
|
||||
|
||||
//This also needs to be with respect to the nodes current childexistance status as some sections are already watched/have nodes, dont change those
|
||||
toAdd &= (byte) ~this.nodeData.getNodeChildExistence(nodeId);
|
||||
|
||||
if (toAdd != 0) {
|
||||
//Add nodes to the request that dont exist in the node already
|
||||
for (int i = 0; i < 8; i++) {//TODO: swap out for numberOfTrailingZeros loop thing
|
||||
if ((toAdd & (i << 1)) == 0) continue;
|
||||
request.addChildRequirement(i);
|
||||
long cpos = makeChildPos(position, i);
|
||||
int prev = this.activeSectionMap.put(cpos, ID_TYPE_REQUEST|reqId);
|
||||
if (prev!=-1) {
|
||||
throw new IllegalStateException("Child is already mapped to a node id " + WorldEngine.pprintPos(cpos) + " " + reqId + " " + prev);
|
||||
}
|
||||
if (!this.updateRouter.watch(cpos, WorldEngine.UPDATE_FLAGS)) {
|
||||
throw new IllegalStateException("Couldn't watch chunk section");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (request.getMsk() != childExistence) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
//If the request is satisfied after changes, consume it
|
||||
if (request.isSatisfied()) {
|
||||
this.consumeFinishedNodeChildRequest(nodeId, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Need to update the node itself, only if the node has children does it need to update the child ptr information tho
|
||||
} else {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
@@ -252,41 +326,27 @@ public class HierarchicalNodeManager {
|
||||
int type = (nodeId & ID_TYPE_MSK);
|
||||
nodeId &= ~ID_TYPE_MSK;
|
||||
if (type == ID_TYPE_REQUEST) {
|
||||
this.requestDataUpdate(nodeId);
|
||||
} else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP) {
|
||||
//Not part of a request, just a node update,
|
||||
|
||||
//NOTE! be aware that if its an existance update and there is a request attached, need to check if the updated
|
||||
// request becomes finished!!
|
||||
var request = this.requests.get(nodeId);
|
||||
//Update for section part of a request, the request may be a leaf request update or an inner node update
|
||||
int child = getChildIdx(position);
|
||||
int prev = request.putChildResult(child, this.geometryManager.uploadSection(section));
|
||||
if (prev != -1) {
|
||||
this.geometryManager.removeSection(prev);
|
||||
}
|
||||
if (request.isSatisfied()) {
|
||||
this.consumeFinishedNodeChildRequest(nodeId, request);
|
||||
}
|
||||
} else if (type == ID_TYPE_NONE || type == ID_TYPE_TOP || type == ID_TYPE_LEAF) {
|
||||
//Update the node geometry, and enqueue if it changed
|
||||
if (this.updateNodeGeometry(nodeId, section) != 0) {//TODO: might need to mark the node as empty geometry or something
|
||||
this.nodeUpdates.add(nodeId);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Should not reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void requestDataUpdate(int nodeId) {
|
||||
var request = this.requests.get(nodeId);
|
||||
//Update for section part of a request, the request may be a leaf request update or an inner node update
|
||||
|
||||
|
||||
if (request.isSatisfied()) {
|
||||
this.processFinishedNodeChildRequest(nodeId, request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Process NodeChildRequest results
|
||||
private void processFinishedNodeChildRequest(int parent, NodeChildRequest request) {
|
||||
int children = this.nodeData.getChildPtr(parent);
|
||||
if (children != NO_NODE) {
|
||||
//There are children already part of this node, so need to reallocate all the children
|
||||
int count = Integer.bitCount(Byte.toUnsignedInt(this.nodeData.getNodeChildExistence(parent)));
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private int updateNodeGeometry(int node, BuiltSection geometry) {
|
||||
int previousGeometry = this.nodeData.getNodeGeometry(node);
|
||||
int newGeometry = EMPTY_GEOMETRY_ID;
|
||||
@@ -304,7 +364,6 @@ public class HierarchicalNodeManager {
|
||||
|
||||
if (previousGeometry != newGeometry) {
|
||||
this.nodeData.setNodeGeometry(node, newGeometry);
|
||||
this.nodeUpdates.add(node);
|
||||
}
|
||||
if (previousGeometry == newGeometry) {
|
||||
return 0;//No change
|
||||
@@ -315,6 +374,18 @@ public class HierarchicalNodeManager {
|
||||
}
|
||||
}
|
||||
|
||||
//Process NodeChildRequest results
|
||||
private void consumeFinishedNodeChildRequest(int nodeId, NodeChildRequest request) {
|
||||
int children = this.nodeData.getChildPtr(nodeId);
|
||||
if (children != NO_NODE) {
|
||||
//There are children already part of this node, so need to reallocate all the children
|
||||
int count = Integer.bitCount(Byte.toUnsignedInt(this.nodeData.getNodeChildExistence(nodeId)));
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================================================================================
|
||||
|
||||
private static int getChildIdx(long pos) {
|
||||
|
||||
@@ -23,12 +23,18 @@ public class HierarchicalOcclusionTraverser {
|
||||
|
||||
private final GlBuffer nodeBuffer;
|
||||
private final GlBuffer uniformBuffer = new GlBuffer(1024).zero();
|
||||
private final GlBuffer renderList = new GlBuffer(100_000 * 4 + 4).zero();//100k sections max to render
|
||||
private final GlBuffer renderList = new GlBuffer(100_000 * 4 + 4).zero();//100k sections max to render, TODO: Maybe move to render service or somewhere else
|
||||
|
||||
private final GlBuffer scratchBuffer = new GlBuffer(1024).zero();//Scratch utility buffer for small things to get the ordering right and memory overall
|
||||
//Scratch queues for node traversal
|
||||
private final GlBuffer scratchQueueA = new GlBuffer(10_000*4).zero();
|
||||
private final GlBuffer scratchQueueB = new GlBuffer(10_000*4).zero();
|
||||
|
||||
|
||||
|
||||
private final HiZBuffer hiZBuffer = new HiZBuffer();
|
||||
|
||||
|
||||
|
||||
public HierarchicalOcclusionTraverser(HierarchicalNodeManager nodeManager, int requestBufferCount) {
|
||||
this.nodeManager = nodeManager;
|
||||
this.requestBuffer = new GlBuffer(requestBufferCount*4L+1024).zero();//The 1024 is to assist with race condition issues
|
||||
@@ -40,7 +46,6 @@ public class HierarchicalOcclusionTraverser {
|
||||
|
||||
}
|
||||
|
||||
public static int HACKY_SECTION_COUNT = 0;
|
||||
public void doTraversal(Viewport<?> viewport, int depthBuffer) {
|
||||
//Compute the mip chain
|
||||
this.hiZBuffer.buildMipChain(depthBuffer, viewport.width, viewport.height);
|
||||
@@ -51,16 +56,7 @@ public class HierarchicalOcclusionTraverser {
|
||||
//Use a chain of glDispatchComputeIndirect (5 times) with alternating read/write buffers
|
||||
// TODO: swap to persistent gpu thread instead
|
||||
|
||||
if (HACKY_SECTION_COUNT != 0) {
|
||||
long uploadPtr = UploadStream.INSTANCE.upload(this.renderList, 0, HACKY_SECTION_COUNT*4L+4);
|
||||
|
||||
MemoryUtil.memPutInt(uploadPtr, HACKY_SECTION_COUNT);
|
||||
for (int i = 1; i < HACKY_SECTION_COUNT+1; i++) {
|
||||
MemoryUtil.memPutInt(uploadPtr + 4L * i, i - 1);
|
||||
}
|
||||
|
||||
UploadStream.INSTANCE.commit();
|
||||
}
|
||||
|
||||
this.downloadResetRequestQueue();
|
||||
}
|
||||
@@ -98,5 +94,6 @@ public class HierarchicalOcclusionTraverser {
|
||||
this.nodeBuffer.free();
|
||||
this.uniformBuffer.free();
|
||||
this.renderList.free();
|
||||
this.scratchBuffer.free();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,4 +78,8 @@ class NodeChildRequest {
|
||||
public long getPosition() {
|
||||
return this.nodePos;
|
||||
}
|
||||
|
||||
public byte getMsk() {
|
||||
return this.mask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,13 @@ public class Logger {
|
||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger("Voxy");
|
||||
|
||||
public static void logError(Object... args) {
|
||||
Throwable throwable = null;
|
||||
for (var i : args) {
|
||||
if (i instanceof Throwable) {
|
||||
throwable = (Throwable) i;
|
||||
}
|
||||
}
|
||||
var stackEntry = new Throwable().getStackTrace()[1];
|
||||
LOGGER.error("["+stackEntry.getClassName()+"]: "+ Stream.of(args).map(Object::toString).collect(Collectors.joining(" ")));
|
||||
LOGGER.error("["+stackEntry.getClassName()+"]: "+ Stream.of(args).map(Object::toString).collect(Collectors.joining(" ")), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package me.cortex.voxy.commonImpl;
|
||||
|
||||
public interface IGetWorldInterface {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package me.cortex.voxy.commonImpl;
|
||||
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
|
||||
public interface IVoxyWorldGetter {
|
||||
WorldEngine getWorldEngine();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package me.cortex.voxy.commonImpl;
|
||||
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
|
||||
public interface IVoxyWorldSetter {
|
||||
void setWorldEngine(WorldEngine engine);
|
||||
}
|
||||
29
src/main/java/me/cortex/voxy/commonImpl/VoxyCommon.java
Normal file
29
src/main/java/me/cortex/voxy/commonImpl/VoxyCommon.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package me.cortex.voxy.commonImpl;
|
||||
|
||||
import me.cortex.voxy.common.config.Serialization;
|
||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
|
||||
public class VoxyCommon implements ModInitializer {
|
||||
public static final String MOD_VERSION;
|
||||
public static final boolean IS_DEDICATED_SERVER;
|
||||
|
||||
static {
|
||||
ModContainer mod = (ModContainer) FabricLoader.getInstance().getModContainer("voxy").orElseThrow(NullPointerException::new);
|
||||
var version = mod.getMetadata().getVersion().getFriendlyString();
|
||||
var commit = mod.getMetadata().getCustomValue("commit").getAsString();
|
||||
MOD_VERSION = version+"-"+commit;
|
||||
IS_DEDICATED_SERVER = FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER;
|
||||
|
||||
Serialization.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
//this.serviceThreadPool = new ServiceThreadPool(VoxyConfig.CONFIG.serviceThreads);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package me.cortex.voxy.commonImpl;
|
||||
|
||||
public class VoxyWorldService {
|
||||
|
||||
}
|
||||
@@ -1,24 +1,51 @@
|
||||
package me.cortex.voxy.commonImpl.mixin.minecraft;
|
||||
|
||||
import me.cortex.voxy.client.Voxy;
|
||||
import me.cortex.voxy.common.Logger;
|
||||
import me.cortex.voxy.common.world.WorldEngine;
|
||||
import me.cortex.voxy.commonImpl.IVoxyWorldGetter;
|
||||
import me.cortex.voxy.commonImpl.IVoxyWorldSetter;
|
||||
import me.cortex.voxy.commonImpl.VoxyCommon;
|
||||
import net.minecraft.registry.DynamicRegistryManager;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import net.minecraft.world.MutableWorldProperties;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(World.class)
|
||||
public class MixinWorld {
|
||||
@Unique private WorldEngine voxyWorldEngine;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(World.class)
|
||||
public class MixinWorld implements IVoxyWorldGetter, IVoxyWorldSetter {
|
||||
@Unique private WorldEngine voxyWorld;
|
||||
|
||||
@Inject(method = "close", at = @At("HEAD"))
|
||||
private void closeVoxyWorld(CallbackInfo ci) {
|
||||
if (this.voxyWorldEngine != null) {
|
||||
try {this.voxyWorldEngine.shutdown();} catch (Exception e) {
|
||||
if (this.voxyWorld != null) {
|
||||
try {this.voxyWorld.shutdown();this.voxyWorld = null;} catch (Exception e) {
|
||||
Logger.logError("Failed to shutdown voxy world engine.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldEngine getWorldEngine() {
|
||||
return this.voxyWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorldEngine(WorldEngine engine) {
|
||||
if (this.voxyWorld != null) {
|
||||
throw new IllegalStateException("WorldEngine not null");
|
||||
}
|
||||
this.voxyWorld = engine;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#version 460 core
|
||||
|
||||
//TODO: make this better than a single thread
|
||||
layout(local_size_x=32, local_size_y=1) in;
|
||||
//TODO: increase local size
|
||||
#define LOCAL_SIZE_BITS 5
|
||||
#define LOCAL_SIZE_MSK ((1<<LOCAL_SIZE_BITS)-1)
|
||||
layout(local_size_x=(1<<LOCAL_SIZE_BITS), local_size_y=1) in;
|
||||
|
||||
#import <voxy:lod/hierarchical/binding_points.glsl>
|
||||
#line 7
|
||||
@@ -26,11 +28,6 @@ layout(binding = SCENE_UNIFORM_INDEX, std140) uniform SceneUniform {
|
||||
float decendSSS;
|
||||
};
|
||||
|
||||
layout(binding = NODE_QUEUE_INDEX, std430) restrict buffer NodeQueue {
|
||||
uint nodeQueueSize;
|
||||
uint[] nodeQueue;
|
||||
};
|
||||
|
||||
layout(binding = REQUEST_QUEUE_INDEX, std430) restrict buffer RequestQueue {
|
||||
uint requestQueueIndex;
|
||||
uint[] requestQueue;
|
||||
@@ -41,6 +38,11 @@ layout(binding = RENDER_QUEUE_INDEX, std430) restrict buffer RenderQueue {
|
||||
uint[] renderQueue;
|
||||
};
|
||||
|
||||
layout(binding = NODE_QUEUE_INDEX, std430) restrict buffer NodeQueue {
|
||||
uint nodeQueueSize;
|
||||
uint[] nodeQueue;
|
||||
};
|
||||
|
||||
layout(binding = NEXT_NODE_QUEUE_INDEX, std430) restrict buffer NextNodeQueue {
|
||||
uint nextNodeQueueIndex;
|
||||
uint[] nextNodeQueue;
|
||||
@@ -102,6 +104,7 @@ void enqueueChildren(in UnpackedNode node) {
|
||||
uint children = getChildCount(node);
|
||||
uint ptr = getChildPtr(node);
|
||||
uint widx = atomicAdd(nextNodeQueueIndex, children);
|
||||
|
||||
for (int i = 0; i < children; i++) {
|
||||
nextNodeQueue[widx+i] = ptr+i;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
"schemaVersion": 1,
|
||||
"id": "voxy",
|
||||
"version": "${version}",
|
||||
"custom": {
|
||||
"commit": "${commit}",
|
||||
"buildtime": "${buildtime}"
|
||||
},
|
||||
"name": "Voxy",
|
||||
"description": "Far distance rendering mod utilising LoDs",
|
||||
"authors": [
|
||||
@@ -21,6 +25,9 @@
|
||||
],
|
||||
"modmenu": [
|
||||
"me.cortex.voxy.client.config.VoxyConfigScreenFactory"
|
||||
],
|
||||
"main": [
|
||||
"me.cortex.voxy.commonImpl.VoxyCommon"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
|
||||
Reference in New Issue
Block a user