what if minecraft ran on the GPU exclusively? glad you asked! because now it can

This commit is contained in:
Halbear 2026-09-15 20:49:24 +01:00
parent fa7bf893e7
commit bf9af81f38
41 changed files with 2433 additions and 34 deletions

View file

@ -5,6 +5,8 @@ import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.SkyBox;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelChunkGenerator;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiRenderer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.GUI.GuiTexture;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Lighting.LightRenderer;
@ -28,6 +30,8 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.SwapChain.SwapChainRender;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBufferSubmitInfo;
import org.lwjgl.vulkan.VkExtent2D;
@ -179,6 +183,8 @@ public class VulkanRenderer implements Renderer {
spriteRenderer.CompileSprites(RendererContext,modelsCache, textureCache);
spriteRenderer.LoadMaterials(RendererContext,materialsCache,textureCache);
GuiRender.LoadTextures(RendererContext,initData.GuiTextures(),textureCache);
VoxelWorldManager.Init(RendererContext);
// VoxelWorldManager.GenerateChunks(new Vector3i(0,0,0), new Vector3i(16,0,16));
}
public GuiRenderer GetGUIRenderer(){return GuiRender;}
@ -196,6 +202,9 @@ public class VulkanRenderer implements Renderer {
public void cleanup() {
RendererContext.GetDevice().waitIdle();
Logger.debug("Waiting Vulkan Context");
VoxelWorldManager.Cleanup(RendererContext);
sceneRender.cleanup(RendererContext);
if(ssaoRenderer != null)ssaoRenderer.cleanup(RendererContext);
if(ssrRender != null)ssrRender.cleanup(RendererContext);
@ -239,7 +248,7 @@ public class VulkanRenderer implements Renderer {
public static volatile boolean Debug = false;
public static volatile DebugRenderMode debugMode = DebugRenderMode.Albedo;
Vector3f CamPos = new Vector3f();
public void DeferredRender(EngineInstance engineInstance){
SwapChain swapChain = RendererContext.GetSwapChain();
WaitForFence(CurrentFrame);
@ -247,9 +256,8 @@ public class VulkanRenderer implements Renderer {
var CommandPool = CommandPools[CurrentFrame];
var CommandBuffer = CommandBuffers[CurrentFrame];
RecordingStart(CommandPool, CommandBuffer);
VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer);
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
boolean RenderShadows = ShadowRenderer.AllowShadowRendering() && EngineConfig.getInstance().RenderShadows();
if(RenderShadows) {shadowRender.render(engineInstance, RendererContext, CommandBuffer, modelsCache, materialsCache, CurrentFrame); }
@ -289,9 +297,8 @@ public class VulkanRenderer implements Renderer {
resize(engineInstance);
return;
}
RecordingStart(CommandPool, CommandBuffer);
VoxelWorldManager.RecordGeneration(RendererContext,CommandBuffer);
sceneRender.Render(engineInstance,RendererContext,CommandBuffer, modelsCache,materialsCache,CurrentFrame);
PostProcessor.Render(RendererContext,CommandBuffer,sceneRender.GetAttachmentColour());
spriteRenderer.Render(engineInstance,RendererContext,CommandBuffer,PostProcessor.GetAttachment(),modelsCache,CurrentFrame);

View file

@ -29,6 +29,8 @@ import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.Noise2D;
import net.halbear.Terrain4J.EngineCore.Main.Util.Maths.PermutationArray;
import net.halbear.Terrain4J.EngineCore.Profiling.CPUMonitor;
import net.halbear.Terrain4J.EngineCore.Profiling.GPUProfiler;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelChunkGenerator;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ServerSideNetworkUtils;
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
@ -36,13 +38,11 @@ import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPass
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialData;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelData;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.Forward.ForwardSceneRender;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.Vector3i;
import org.joml.*;
import org.lwjgl.openal.AL11;
import org.tinylog.Logger;
import java.lang.Math;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -51,7 +51,7 @@ import static org.lwjgl.glfw.GLFW.*;
public class GameCore implements GameLogic {
private static final float MOUSE_SENSITIVITY = 0.1f;
private static final float MOVEMENT_SPEED = 0.01f;
private static final float MOVEMENT_SPEED = 0.1f;
public static boolean LoadingLevel = false;
private Vector2f LastMousePos = new Vector2f(0,0);
@ -161,6 +161,9 @@ public class GameCore implements GameLogic {
}
boolean createOfflinePlayer = !PrimaryRuntime.IsServer && !ClientSideNetworkUtils.Connected;
MaterialData VoxelMat = new MaterialData("VoxelTerrain","resources/EngineResources/Texture/test_cube.png","","",new Vector4f(1,1,1,1),
0,0,"",new Vector4f(),"",0,"",1,new Vector4f(),1.0f,0);
materials.add(VoxelMat);
materials.addAll(MelonaMat);
materials.addAll(CollisionVisualisationMat);
materials.addAll(MelonaMaterial);
@ -283,11 +286,11 @@ public class GameCore implements GameLogic {
permutation.GeneratePermutationArray(5783904701859L);
for(int x = -1; x < 2; x++){
for(int y = -1; y < 2; y++){
GenerateChunk(new Vector3i(x, 0, y), 16);
//GenerateChunk(new Vector3i(x, 0, y), 16);
}
}
for(int i = 0; i < 20; i++){
SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1));
//SpawnNewActor(engineInstance, new Vector3f(-5 + (float)Math.random() * 10,10 + (float)Math.random() * 10, -5 + (float)Math.random() * 10), new Vector3f(0, 0, 0), new Vector3f(1, 1, 1));
}
Settings.textBuffer.set(ClientSideNetworkUtils.ServerIP);
Settings.UsernameBuffer.set("Player");
@ -651,10 +654,20 @@ public class GameCore implements GameLogic {
FetchingMetrics = false;
return imGuiIO.getWantCaptureKeyboard();
}
Vector3f CamPos = new Vector3f();
@Override
public void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds) {
if(!PrimaryRuntime.IsServer && !RenderThread.Headless) {
CamPos.set(engineInstance.scene().GetCamera().GetPosition());
Vector3i ChunkPos = new Vector3i((int)Math.floor(CamPos.x/ (float) VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.y/ (float)VoxelChunkGenerator.CHUNK_SIZE),(int)Math.floor(CamPos.z/ (float)VoxelChunkGenerator.CHUNK_SIZE));
if(ChunkPos.x != VoxelWorldManager.LastPosition.x || ChunkPos.y != VoxelWorldManager.LastPosition.y || ChunkPos.z != VoxelWorldManager.LastPosition.z) {
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(5, 3, 5));
VoxelWorldManager.UnloadFarChunks(ChunkPos, 10);
} else {
VoxelWorldManager.GenerateChunks(ChunkPos, new Vector3i(24,10,24));
VoxelWorldManager.UnloadFarChunks(ChunkPos, 48);
}
for (int i = 0; i < VisualisedCollisionActor3D.CollisionVisuals.size(); i++) {
VisualisedCollisionActor3D.CollisionVisuals.get(i).Update();
}

View file

@ -0,0 +1,330 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil.ComputePipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.ModelsCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.joml.Matrix4f;
import org.joml.Vector3i;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.shaderc.Shaderc;
import org.lwjgl.vulkan.*;
import org.tinylog.Logger;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import static net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.BufferBarrier;
import static org.lwjgl.system.MemoryUtil.memFree;
import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK10.VK_PIPELINE_BIND_POINT_COMPUTE;
import static org.lwjgl.vulkan.VK10.VK_SHADER_STAGE_COMPUTE_BIT;
import static org.lwjgl.vulkan.VK10.vkCmdDispatch;
import static org.lwjgl.vulkan.VK10.vkCmdPushConstants;
import static org.lwjgl.vulkan.VK13.*;
public class ComputeVoxelTerrain {
public static final int CHUNK_SIZE = 16;
public static final int LOCAL_SIZE = 4;
public static final int DISPATCH_SIZE = CHUNK_SIZE / LOCAL_SIZE;
public static final int CHUNK_PUSH_CONSTANT_SIZE = Integer.BYTES * 4;
private static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
private static final int MAX_FACES = VOXEL_COUNT * 6;
private static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * 16;
private static final int MAX_VERTICES = MAX_VISIBLE_FACES_PER_CHUNK * 4;
private static final int MAX_INDICES = MAX_VISIBLE_FACES_PER_CHUNK * 6;
private static final int FLOATS_PER_VERTEX = 14;
private static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES;
private static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES;
private static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES;
private final String DESCRIPTOR_ID_MESH;
private final String DESCRIPTOR_ID_RESET;
private final String DESCRIPTOR_ID_VOXEL;
private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGeneration.glsl";
private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGeneration.glsl";
private static final String VOXEL_RESET_GLSL = "resources/EngineResources/VoxelComputeShaders/resetVoxelDraw.glsl";
private static final String MESH_GENERATION_SPV = MESH_GENERATION_GLSL + ".spv";
private static final String VOXEL_GENERATION_SPV = VOXEL_GENERATION_GLSL + ".spv";
private static final String VOXEL_RESET_SPV = VOXEL_RESET_GLSL + ".spv";
private final VulkanBuffer VoxelData;
private final VulkanBuffer VertexBuffer;
private final VulkanBuffer IndexBuffer;
private final VulkanBuffer DrawCommand;
private final VulkanBuffer Counters;
private final DescriptorSetLayout voxelGenerationLayout;
private final DescriptorSetLayout resetLayout;
private final DescriptorSetLayout meshGenerationLayout;
private final Pipeline voxelGeneration;
private final Pipeline voxelReset;
private final Pipeline meshGeneration;
private final ByteBuffer graphicsPushConstants;
private final int chunkX;
private final int chunkY;
private final int chunkZ;
private boolean generated;
public ComputeVoxelTerrain(VulkanContext VkCtx, int chunkX, int chunkY, int chunkZ) {
this.chunkX = chunkX;
this.chunkY = chunkY;
this.chunkZ = chunkZ;
this.generated = false;
DESCRIPTOR_ID_MESH = "DESC_ID_MESH_" + chunkX + "_" + chunkY + "_" + chunkZ;
DESCRIPTOR_ID_RESET = "DESC_ID_RESET_" + chunkX + "_" + chunkY + "_" + chunkZ;
DESCRIPTOR_ID_VOXEL = "DESC_ID_VOXEL_" + chunkX + "_" + chunkY + "_" + chunkZ;
long voxelBufferSize = (long) VOXEL_COUNT * Integer.BYTES;
long vertexBufferSize = (long) MAX_VERTICES * VERTEX_SIZE_BYTES;
long indexBufferSize = (long) MAX_INDICES * Integer.BYTES;
VoxelData = new VulkanBuffer(VkCtx,voxelBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
VertexBuffer = new VulkanBuffer( VkCtx, vertexBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
IndexBuffer = new VulkanBuffer(VkCtx,indexBufferSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
DrawCommand = new VulkanBuffer(VkCtx,DRAW_INDEXED_INDIRECT_COMMAND_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
Counters = new VulkanBuffer(VkCtx,COUNTER_BUFFER_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,
VK_SHADER_STAGE_COMPUTE_BIT ) });
resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,
VK_SHADER_STAGE_COMPUTE_BIT ),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,
VK_SHADER_STAGE_COMPUTE_BIT ) });
meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,
1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,
1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,2,
1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,3,
1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4,
1,VK_SHADER_STAGE_COMPUTE_BIT),});
createDescriptorSets(VkCtx);
PushConstantsRange[] chunkPushConstants = new PushConstantsRange[]{
new PushConstantsRange(
VK_SHADER_STAGE_COMPUTE_BIT,
0,
CHUNK_PUSH_CONSTANT_SIZE
)
};
ShaderModule resetShader = createComputeShader(VkCtx, VOXEL_RESET_GLSL, VOXEL_RESET_SPV);
ShaderModule voxelShader = createComputeShader(VkCtx, VOXEL_GENERATION_GLSL, VOXEL_GENERATION_SPV);
ShaderModule meshShader = createComputeShader(VkCtx, MESH_GENERATION_GLSL, MESH_GENERATION_SPV);
voxelReset = new ComputePipeline( VkCtx, resetShader,new DescriptorSetLayout[]{resetLayout},
new PushConstantsRange[0]);
voxelGeneration = new ComputePipeline( VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout},
chunkPushConstants );
meshGeneration = new ComputePipeline(VkCtx, meshShader,new DescriptorSetLayout[]{meshGenerationLayout},
chunkPushConstants );
resetShader.CleanUp(VkCtx);
voxelShader.CleanUp(VkCtx);
meshShader.CleanUp(VkCtx);
graphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc(VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE);
}
private static ShaderModule createComputeShader(VulkanContext VkCtx, String glslPath, String spvPath) {
if (EngineConfig.getInstance().RecompileShaders()) {
ShaderCompiler.CompileGLSLShaderOnChange(glslPath, Shaderc.shaderc_glsl_compute_shader);
}
return new ShaderModule(VkCtx, VK_SHADER_STAGE_COMPUTE_BIT, spvPath, null);
}
private void createDescriptorSets(VulkanContext VkCtx) {
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
Device device = VkCtx.GetDevice();
DescriptorSet resetSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_RESET, resetLayout);
resetSet.SetBuffer(device, DrawCommand, DrawCommand.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
resetSet.SetBuffer(device, Counters, Counters.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
DescriptorSet voxelSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_VOXEL, voxelGenerationLayout);
voxelSet.SetBuffer(device, VoxelData, VoxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESCRIPTOR_ID_MESH, meshGenerationLayout);
meshSet.SetBuffer(device, VoxelData, VoxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, VertexBuffer, VertexBuffer.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, IndexBuffer, IndexBuffer.GetRequestedSize(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, DrawCommand, DrawCommand.GetRequestedSize(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, Counters, Counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
}
public void RecordGeneration(VulkanContext VkCtx, CommandBuffer commandBuffer) {
if (generated) {
return;
}
try (MemoryStack MemStack = MemoryStack.stackPush()) {
VkCommandBuffer CommandBuffer = commandBuffer.GetVulkanCommandBuffer();
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
ByteBuffer chunkPushBuffer = MemStack.malloc(CHUNK_PUSH_CONSTANT_SIZE);
chunkPushBuffer.putInt(0, chunkX);
chunkPushBuffer.putInt(4, chunkY);
chunkPushBuffer.putInt(8, chunkZ);
chunkPushBuffer.putInt(12, 0);
LongBuffer resetDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_RESET).GetVkDescriptorSet());
LongBuffer voxelDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_VOXEL).GetVkDescriptorSet());
LongBuffer meshDescriptorSet = MemStack.longs(allocator.GetDescriptorSet(DESCRIPTOR_ID_MESH).GetVkDescriptorSet());
vkCmdBindPipeline(CommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE,voxelReset.GetVulkanPipeline());
vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelReset.GetVulkanPipelineLayout(),0,resetDescriptorSet,null);
vkCmdDispatch(CommandBuffer, 1, 1, 1);
VulkanUtils.BufferBarriers(MemStack, CommandBuffer,
new long[]{DrawCommand.GetBuffer(),Counters.GetBuffer()},
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT);
vkCmdBindPipeline(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelGeneration.GetVulkanPipeline());
vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,voxelGeneration.GetVulkanPipelineLayout(),0, voxelDescriptorSet,null);
vkCmdPushConstants(CommandBuffer,voxelGeneration.GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0,chunkPushBuffer);
vkCmdDispatch(CommandBuffer, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
BufferBarrier(MemStack, CommandBuffer, VoxelData.GetBuffer(),
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_SHADER_READ_BIT);
vkCmdBindPipeline(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,meshGeneration.GetVulkanPipeline());
vkCmdBindDescriptorSets(CommandBuffer,VK_PIPELINE_BIND_POINT_COMPUTE,meshGeneration.GetVulkanPipelineLayout(),0, meshDescriptorSet,null);
vkCmdPushConstants(CommandBuffer, meshGeneration.GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0,chunkPushBuffer);
vkCmdDispatch(CommandBuffer, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
VulkanUtils.BufferBarriers(MemStack, CommandBuffer,
new long[]{VertexBuffer.GetBuffer(),
IndexBuffer.GetBuffer(),
DrawCommand.GetBuffer()},
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_2_INDEX_READ_BIT | VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT);
generated = true;
}
}
public void RecordRender(VkCommandBuffer CommandBuffer, Pipeline graphicsPipeline,Matrix4f modelMatrix, int materialIndex) {
try (MemoryStack stack = MemoryStack.stackPush()) {
modelMatrix.get(0, graphicsPushConstants);
graphicsPushConstants.putInt(VulkanUtils.MATRIX4X4_SIZE, materialIndex);
// Logger.debug("Rendering Chunk {}:{}:{}",chunkX,chunkY,chunkZ);
vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT,0, graphicsPushConstants.slice(0, VulkanUtils.MATRIX4X4_SIZE));
vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_FRAGMENT_BIT,VulkanUtils.MATRIX4X4_SIZE, graphicsPushConstants.slice(VulkanUtils.MATRIX4X4_SIZE, VulkanUtils.INT_SIZE));
LongBuffer vertexBuffers = stack.longs(VertexBuffer.GetBuffer());
LongBuffer offsets = stack.longs(0L);
vkCmdBindVertexBuffers(CommandBuffer, 0, vertexBuffers, offsets);
vkCmdBindIndexBuffer(CommandBuffer, IndexBuffer.GetBuffer(), 0, VK_INDEX_TYPE_UINT32);
//vkCmdDrawIndexed(CommandBuffer,MAX_INDICES,1,0,0,0);
vkCmdDrawIndexedIndirect(CommandBuffer,DrawCommand.GetBuffer(),0,1,DRAW_INDEXED_INDIRECT_COMMAND_SIZE);
}
}
public VulkanBuffer GetVoxelDataBuffer() {
return VoxelData;
}
public VulkanBuffer GetVertexBuffer() {
return VertexBuffer;
}
public VulkanBuffer GetIndexBuffer() {
return IndexBuffer;
}
public VulkanBuffer GetDrawCommandBuffer() {
return DrawCommand;
}
public VulkanBuffer GetCountersBuffer() {
return Counters;
}
public boolean IsGenerated() {
return generated;
}
public void MarkDirty() {
generated = false;
}
public Vector3i GetPosition(){
return new Vector3i(chunkX,chunkY,chunkZ);
}
public void cleanup(VulkanContext VkCtx) {
voxelGeneration.CleanUp(VkCtx);
voxelReset.CleanUp(VkCtx);
meshGeneration.CleanUp(VkCtx);
voxelGenerationLayout.CleanUp(VkCtx);
resetLayout.CleanUp(VkCtx);
meshGenerationLayout.CleanUp(VkCtx);
VoxelData.cleanup(VkCtx);
VertexBuffer.cleanup(VkCtx);
IndexBuffer.cleanup(VkCtx);
DrawCommand.cleanup(VkCtx);
Counters.cleanup(VkCtx);
org.lwjgl.system.MemoryUtil.memFree(graphicsPushConstants);
}
public void recordComputeCommandBuffer(VkCommandBuffer cmd, long computePipeline, long pipelineLayout,
long descriptorSet, int chunkX, int chunkY, int chunkZ) {
try (MemoryStack MemStack = MemoryStack.stackPush()) {
ByteBuffer pushConstants = MemStack.malloc(CHUNK_PUSH_CONSTANT_SIZE);
pushConstants.putInt(0, chunkX);
pushConstants.putInt(4, chunkY);
pushConstants.putInt(8, chunkZ);
pushConstants.putInt(12, 0);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
vkCmdBindDescriptorSets(cmd,VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout,
0,MemStack.longs(descriptorSet),null);
vkCmdPushConstants(cmd,pipelineLayout,VK_SHADER_STAGE_COMPUTE_BIT,0,pushConstants);
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
}
}
}

View file

@ -0,0 +1,6 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import org.joml.Vector3i;
public record RenderChunk(Vector3i position, int slot,long vertexOffsetBytes, long indexOffsetBytes,int maxIndexCount,long indirectCommandOffsetBytes) {
}

View file

@ -0,0 +1,182 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil.ComputePipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.*;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
import org.lwjgl.util.shaderc.Shaderc;
import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
import static org.lwjgl.vulkan.VK13.*;
public class SharedVoxelTerrainResources {
public static final int CHUNK_SIZE = 16;
public static final int VOXEL_COUNT = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
public static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES;
public static final int COUNTER_BUFFER_SIZE = 2 * Integer.BYTES;
public static final int TERRAIN_GENERATION_PUSH_CONSTANT_SIZE = Integer.BYTES * 8;
/*Push constants:
int chunkX
int chunkY
int chunkZ
int slot
uint vertexFloatOffset
uint indexOffset
uint indirectCommandOffset
uint padding */
private static final String DESC_ID_VOXEL_GENERATION = "VOXEL_SHARED_DESC_GENERATION";
private static final String DESC_ID_RESET = "VOXEL_SHARED_DESC_RESET";
private static final String DESC_ID_MESH = "VOXEL_SHARED_DESC_MESH";
private static final String MESH_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/meshGenerationShared.glsl";
private static final String VOXEL_GENERATION_GLSL = "resources/EngineResources/VoxelComputeShaders/voxelGenerationShared.glsl";
private static final String VOXEL_RESET_GLSL = "resources/EngineResources/VoxelComputeShaders/resetVoxelDrawShared.glsl";
private static final String MESH_GENERATION_SPV = MESH_GENERATION_GLSL + ".spv";
private static final String VOXEL_GENERATION_SPV = VOXEL_GENERATION_GLSL + ".spv";
private static final String VOXEL_RESET_SPV = VOXEL_RESET_GLSL + ".spv";
private final VoxelMeshPool meshPool;
private final VulkanBuffer voxelData;
private final VulkanBuffer counters;
private final DescriptorSetLayout voxelGenerationLayout;
private final DescriptorSetLayout resetLayout;
private final DescriptorSetLayout meshGenerationLayout;
private final Pipeline voxelGenerationPipeline;
private final Pipeline resetPipeline;
private final Pipeline meshGenerationPipeline;
public SharedVoxelTerrainResources(VulkanContext VkCtx, int maxResidentChunks) {
meshPool = new VoxelMeshPool(VkCtx, maxResidentChunks);
voxelData = new VulkanBuffer(VkCtx, (long) VOXEL_COUNT * Integer.BYTES,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
counters = new VulkanBuffer( VkCtx,COUNTER_BUFFER_SIZE,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0 );
voxelGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT)
});
resetLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,VK_SHADER_STAGE_COMPUTE_BIT)
});
meshGenerationLayout = new DescriptorSetLayout(VkCtx, new DescriptorSetLayout.LayoutInformation[]{
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,0,1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,1,1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,2,1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,3,1,VK_SHADER_STAGE_COMPUTE_BIT),
new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,4,1,VK_SHADER_STAGE_COMPUTE_BIT)
});
createDescriptorSets(VkCtx);
PushConstantsRange[] generationPushConstants = new PushConstantsRange[]{
new PushConstantsRange(VK_SHADER_STAGE_COMPUTE_BIT,0, TERRAIN_GENERATION_PUSH_CONSTANT_SIZE)
};
ShaderModule resetShader = createComputeShader(VkCtx, VOXEL_RESET_GLSL, VOXEL_RESET_SPV);
ShaderModule voxelShader = createComputeShader(VkCtx, VOXEL_GENERATION_GLSL, VOXEL_GENERATION_SPV);
ShaderModule meshShader = createComputeShader(VkCtx, MESH_GENERATION_GLSL, MESH_GENERATION_SPV);
resetPipeline = new ComputePipeline(VkCtx,resetShader,new DescriptorSetLayout[]{resetLayout},generationPushConstants);
voxelGenerationPipeline = new ComputePipeline(VkCtx,voxelShader, new DescriptorSetLayout[]{voxelGenerationLayout},generationPushConstants);
meshGenerationPipeline = new ComputePipeline( VkCtx,meshShader, new DescriptorSetLayout[]{meshGenerationLayout},generationPushConstants );
resetShader.CleanUp(VkCtx);
voxelShader.CleanUp(VkCtx);
meshShader.CleanUp(VkCtx);
}
private static ShaderModule createComputeShader(VulkanContext VkCtx, String glslPath, String spvPath) {
if (EngineConfig.getInstance().RecompileShaders()) {
ShaderCompiler.CompileGLSLShaderOnChange(glslPath, Shaderc.shaderc_glsl_compute_shader);
}
return new ShaderModule(VkCtx, VK_SHADER_STAGE_COMPUTE_BIT, spvPath, null);
}
private void createDescriptorSets(VulkanContext VkCtx) {
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
Device device = VkCtx.GetDevice();
DescriptorSet resetSet = allocator.AddDescriptorSet(device, DESC_ID_RESET, resetLayout);
resetSet.SetBuffer(device, meshPool.indirectPool(), meshPool.indirectPool().GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
resetSet.SetBuffer(device, counters, counters.GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
DescriptorSet voxelSet = allocator.AddDescriptorSet(device, DESC_ID_VOXEL_GENERATION, voxelGenerationLayout);
voxelSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
DescriptorSet meshSet = allocator.AddDescriptorSet(device, DESC_ID_MESH, meshGenerationLayout);
meshSet.SetBuffer(device, voxelData, voxelData.GetRequestedSize(), 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, meshPool.vertexPool(), meshPool.vertexPool().GetRequestedSize(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, meshPool.indexPool(), meshPool.indexPool().GetRequestedSize(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, meshPool.indirectPool(), meshPool.indirectPool().GetRequestedSize(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
meshSet.SetBuffer(device, counters, counters.GetRequestedSize(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
}
public VoxelMeshPool meshPool() {
return meshPool;
}
public VulkanBuffer voxelData() {
return voxelData;
}
public VulkanBuffer counters() {
return counters;
}
public Pipeline voxelGenerationPipeline() {
return voxelGenerationPipeline;
}
public Pipeline resetPipeline() {
return resetPipeline;
}
public Pipeline meshGenerationPipeline() {
return meshGenerationPipeline;
}
public String voxelGenerationDescriptorId() {
return DESC_ID_VOXEL_GENERATION;
}
public String resetDescriptorId() {
return DESC_ID_RESET;
}
public String meshDescriptorId() {
return DESC_ID_MESH;
}
public void cleanup(VulkanContext VkCtx) {
resetPipeline.CleanUp(VkCtx);
voxelGenerationPipeline.CleanUp(VkCtx);
meshGenerationPipeline.CleanUp(VkCtx);
resetLayout.CleanUp(VkCtx);
voxelGenerationLayout.CleanUp(VkCtx);
meshGenerationLayout.CleanUp(VkCtx);
voxelData.cleanup(VkCtx);
counters.cleanup(VkCtx);
meshPool.cleanup(VkCtx);
}
}

View file

@ -0,0 +1,121 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.DescriptorAllocator;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBuffer;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import static org.lwjgl.vulkan.VK13.*;
public class VoxelChunkGenerator {
public static final int CHUNK_SIZE = 16;
public static final int LOCAL_SIZE = 4;
public static final int DISPATCH_SIZE = CHUNK_SIZE / LOCAL_SIZE;
private final SharedVoxelTerrainResources resources;
public VoxelChunkGenerator(SharedVoxelTerrainResources resources) {
this.resources = resources;
}
public void recordGenerateChunk(VulkanContext VkCtx,CommandBuffer commandBuffer, RenderChunk chunk) {
try (MemoryStack stack = MemoryStack.stackPush()) {
VkCommandBuffer cmd = commandBuffer.GetVulkanCommandBuffer();
DescriptorAllocator allocator = VkCtx.GetDescriptorAllocator();
ByteBuffer pushConstants = stack.malloc(SharedVoxelTerrainResources.TERRAIN_GENERATION_PUSH_CONSTANT_SIZE);
int vertexFloatOffset = (int) (chunk.vertexOffsetBytes() / Float.BYTES);
int indexOffset = (int) (chunk.indexOffsetBytes() / Integer.BYTES);
int indirectCommandIndex = (int) (chunk.indirectCommandOffsetBytes() / VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE);
pushConstants.putInt(0, chunk.position().x);
pushConstants.putInt(4, chunk.position().y);
pushConstants.putInt(8, chunk.position().z);
pushConstants.putInt(12, chunk.slot());
pushConstants.putInt(16, vertexFloatOffset);
pushConstants.putInt(20, indexOffset);
pushConstants.putInt(24, indirectCommandIndex);
pushConstants.putInt(28, 0);
LongBuffer resetDescriptorSet = stack.longs(
allocator.GetDescriptorSet(resources.resetDescriptorId()).GetVkDescriptorSet()
);
LongBuffer voxelDescriptorSet = stack.longs(
allocator.GetDescriptorSet(resources.voxelGenerationDescriptorId()).GetVkDescriptorSet()
);
LongBuffer meshDescriptorSet = stack.longs(
allocator.GetDescriptorSet(resources.meshDescriptorId()).GetVkDescriptorSet()
);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipeline());
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.resetPipeline().GetVulkanPipelineLayout(),0, resetDescriptorSet,null );
vkCmdPushConstants( cmd, resources.resetPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
vkCmdDispatch(cmd, 1, 1, 1);
VulkanUtils.BufferBarriers(stack, cmd,
new long[]{
resources.meshPool().indirectPoolHandle(),
resources.counters().GetBuffer()
},
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.voxelGenerationPipeline().GetVulkanPipeline());
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.voxelGenerationPipeline().GetVulkanPipelineLayout(),0, voxelDescriptorSet,null );
vkCmdPushConstants( cmd, resources.voxelGenerationPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
VulkanUtils.BufferBarrier(stack, cmd,resources.voxelData().GetBuffer(),
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT
);
vkCmdBindPipeline(cmd,VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipeline() );
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE,resources.meshGenerationPipeline().GetVulkanPipelineLayout(),0, meshDescriptorSet,null );
vkCmdPushConstants( cmd, resources.meshGenerationPipeline().GetVulkanPipelineLayout(),VK_SHADER_STAGE_COMPUTE_BIT,0, pushConstants );
vkCmdDispatch(cmd, DISPATCH_SIZE, DISPATCH_SIZE, DISPATCH_SIZE);
VulkanUtils.BufferBarriers(stack, cmd,
new long[]{
resources.voxelData().GetBuffer(),
resources.counters().GetBuffer(),
resources.meshPool().vertexPoolHandle(),
resources.meshPool().indexPoolHandle(),
resources.meshPool().indirectPoolHandle()
},
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
VK_ACCESS_2_SHADER_WRITE_BIT,
VK_ACCESS_2_SHADER_READ_BIT |
VK_ACCESS_2_SHADER_WRITE_BIT |
VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT |
VK_ACCESS_2_INDEX_READ_BIT |
VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT
);
}
}
}

View file

@ -0,0 +1,7 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
public enum VoxelChunkVisibility {
EMPTY_AIR,
FULLY_SOLID_UNDERGROUND,
SURFACE
}

View file

@ -0,0 +1,126 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanBuffer;
import org.joml.Vector3i;
import java.util.ArrayDeque;
import java.util.Queue;
import static org.lwjgl.util.vma.Vma.VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
import static org.lwjgl.vulkan.VK13.*;
public class VoxelMeshPool{
public static final int CHUNK_SIZE = 16;
public static final int FLOATS_PER_VERTEX = 14;
public static final int VERTEX_SIZE_BYTES = FLOATS_PER_VERTEX * Float.BYTES;
public static final int MAX_VISIBLE_FACES_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * 12;
public static final int MAX_VERTICES_PER_CHUNK = MAX_VISIBLE_FACES_PER_CHUNK * 4;
public static final int MAX_INDICES_PER_CHUNK = MAX_VISIBLE_FACES_PER_CHUNK * 6;
public static final int INDEX_SIZE_BYTES = Integer.BYTES;
public static final int DRAW_INDEXED_INDIRECT_COMMAND_SIZE = 5 * Integer.BYTES;
private final int maxChunks;
private final long vertexSlotSizeBytes;
private final long indexSlotSizeBytes;
private final long indirectSlotSizeBytes;
private final VulkanBuffer vertexPool;
private final VulkanBuffer indexPool;
private final VulkanBuffer indirectPool;
private final Queue<Integer> freeSlots = new ArrayDeque<>();
public VoxelMeshPool(VulkanContext VkCtx, int maxChunks) {
this.maxChunks = maxChunks;
this.vertexSlotSizeBytes = (long) MAX_VERTICES_PER_CHUNK * VERTEX_SIZE_BYTES;
this.indexSlotSizeBytes = (long) MAX_INDICES_PER_CHUNK * INDEX_SIZE_BYTES;
this.indirectSlotSizeBytes = DRAW_INDEXED_INDIRECT_COMMAND_SIZE;
long vertexPoolSize = vertexSlotSizeBytes * maxChunks;
long indexPoolSize = indexSlotSizeBytes * maxChunks;
long indirectPoolSize = indirectSlotSizeBytes * maxChunks;
vertexPool = new VulkanBuffer(VkCtx,vertexPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
indexPool = new VulkanBuffer(VkCtx,indexPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
indirectPool = new VulkanBuffer(VkCtx,indirectPoolSize,VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE,0,0);
for (int i = 0; i < maxChunks; i++) {
freeSlots.add(i);
}
}
public RenderChunk allocate(Vector3i position) {
Integer slot = freeSlots.poll();
if (slot == null) {
return null;
}
return new RenderChunk(new Vector3i(position),slot, vertexOffsetBytes(slot),indexOffsetBytes(slot),MAX_INDICES_PER_CHUNK,indirectCommandOffsetBytes(slot));
}
public void free(RenderChunk chunk) {
freeSlots.add(chunk.slot());
}
public long vertexOffsetBytes(int slot) {
return vertexSlotSizeBytes * slot;
}
public long indexOffsetBytes(int slot) {
return indexSlotSizeBytes * slot;
}
public long indirectCommandOffsetBytes(int slot) {
return indirectSlotSizeBytes * slot;
}
public VulkanBuffer vertexPool() {
return vertexPool;
}
public VulkanBuffer indexPool() {
return indexPool;
}
public VulkanBuffer indirectPool() {
return indirectPool;
}
public long vertexPoolHandle() {
return vertexPool.GetBuffer();
}
public long indexPoolHandle() {
return indexPool.GetBuffer();
}
public long indirectPoolHandle() {
return indirectPool.GetBuffer();
}
public int maxChunks() {
return maxChunks;
}
public int freeSlotCount() {
return freeSlots.size();
}
public void cleanup(VulkanContext VkCtx) {
vertexPool.cleanup(VkCtx);
indexPool.cleanup(VkCtx);
indirectPool.cleanup(VkCtx);
}
}

View file

@ -0,0 +1,113 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
public final class VoxelTerrainHeightSampler {
private VoxelTerrainHeightSampler() {
}
private static double fract(double value) {
return value - Math.floor(value);
}
private static double mix(double a, double b, double t) {
return a * (1.0 - t) + b * t;
}
private static double rand(double x, double z) {
return fract(Math.sin(x * 12.9898 + z * 78.233) * 43758.5453123);
}
private static double valueNoise(double x, double z) {
double ix = Math.floor(x);
double iz = Math.floor(z);
double fx = fract(x);
double fz = fract(z);
double a = rand(ix, iz);
double b = rand(ix + 1.0, iz);
double c = rand(ix, iz + 1.0);
double d = rand(ix + 1.0, iz + 1.0);
double ux = fx * fx * (3.0 - 2.0 * fx);
double uz = fz * fz * (3.0 - 2.0 * fz);
return mix(mix(a, b, ux), mix(c, d, ux), uz);
}
public static double terrainHeight(double worldX, double worldZ) {
return valueNoise(worldX * 0.005, worldZ * 0.005) * 100.0
+ valueNoise(worldX * 0.01, worldZ * 0.01) * 10.0
+ valueNoise(worldX * 0.1, worldZ * 0.1) * 5.0
+ valueNoise(worldX, worldZ) * 0.5;
}
public static double minHeightForChunkXZ(int chunkX, int chunkZ, int chunkSize) {
double min = Double.POSITIVE_INFINITY;
int worldMinX = chunkX * chunkSize;
int worldMinZ = chunkZ * chunkSize;
int worldMaxX = worldMinX + chunkSize - 1;
int worldMaxZ = worldMinZ + chunkSize - 1;
int samplesPerAxis = 5;
for (int sx = 0; sx < samplesPerAxis; sx++) {
for (int sz = 0; sz < samplesPerAxis; sz++) {
double tx = sx / (double) (samplesPerAxis - 1);
double tz = sz / (double) (samplesPerAxis - 1);
double x = mix(worldMinX, worldMaxX, tx);
double z = mix(worldMinZ, worldMaxZ, tz);
min = Math.min(min, terrainHeight(x, z));
}
}
return min;
}
public static double maxHeightForChunkXZ(int chunkX, int chunkZ, int chunkSize) {
double max = Double.NEGATIVE_INFINITY;
int worldMinX = chunkX * chunkSize;
int worldMinZ = chunkZ * chunkSize;
int worldMaxX = worldMinX + chunkSize - 1;
int worldMaxZ = worldMinZ + chunkSize - 1;
int samplesPerAxis = 5;
for (int sx = 0; sx < samplesPerAxis; sx++) {
for (int sz = 0; sz < samplesPerAxis; sz++) {
double tx = sx / (double) (samplesPerAxis - 1);
double tz = sz / (double) (samplesPerAxis - 1);
double x = mix(worldMinX, worldMaxX, tx);
double z = mix(worldMinZ, worldMaxZ, tz);
max = Math.max(max, terrainHeight(x, z));
}
}
return max;
}
public static VoxelChunkVisibility classifyChunk(int chunkX, int chunkY, int chunkZ, int chunkSize) {
int chunkMinY = chunkY * chunkSize;
int chunkMaxY = chunkMinY + chunkSize - 1;
double minHeight = minHeightForChunkXZ(chunkX, chunkZ, chunkSize);
double maxHeight = maxHeightForChunkXZ(chunkX, chunkZ, chunkSize);
double safetyPadding = 32.0;
if (chunkMinY > maxHeight + safetyPadding) {
return VoxelChunkVisibility.EMPTY_AIR;
}
if (chunkMaxY < minHeight - safetyPadding) {
return VoxelChunkVisibility.FULLY_SOLID_UNDERGROUND;
}
return VoxelChunkVisibility.SURFACE;
}
}

View file

@ -0,0 +1,274 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.VkModel.MaterialsCache;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.CommandBuffer;
import org.joml.Matrix4f;
import org.joml.Vector3i;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBuffer;
import org.tinylog.Logger;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import static org.lwjgl.vulkan.VK13.*;
public class VoxelWorldManager {
private static final int MAX_RESIDENT_CHUNKS = 512 * 24;
private static final int MAX_CHUNK_GENERATIONS_PER_FRAME = 32;
private static final ConcurrentLinkedQueue<Vector3i> RequestedChunks = new ConcurrentLinkedQueue<>();
private static final ConcurrentHashMap<Vector3i, RenderChunk> RenderChunks = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Vector3i, Boolean> KnownChunks = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<Vector3i, VoxelChunkVisibility> CulledChunks = new ConcurrentHashMap<>();
private static SharedVoxelTerrainResources Resources;
private static VoxelChunkGenerator Generator;
private static ByteBuffer GraphicsPushConstants;
public static void Init(VulkanContext VkCtx) {
if (Resources != null) {
return;
}
Resources = new SharedVoxelTerrainResources(VkCtx, MAX_RESIDENT_CHUNKS);
Generator = new VoxelChunkGenerator(Resources);
GraphicsPushConstants = org.lwjgl.system.MemoryUtil.memAlloc(
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE +
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE
);
}
public static void GenerateChunk(Vector3i Position) {
Vector3i key = new Vector3i(Position);
if (KnownChunks.containsKey(key)) {
return;
}
RequestedChunks.add(key);
KnownChunks.put(key, true);
}
public static int GenerationOffset = 0;
public static Vector3i LastPosition = new Vector3i(0, 0, 0);
static int IterationX = 0;
static Vector3i ChunkPos = new Vector3i(0, 0, 0);
static Vector3i ChunkPos2 = new Vector3i(0, 0, 0);
public static void GenerateChunks(Vector3i Position, Vector3i Radius) {
int ChunkX = Position.x;
int ChunkY = Position.y;
int ChunkY2 = Position.y;
int ChunkZ = Position.z;
for (int Ry = 0; Ry <= Radius.y; Ry++)
{
for (int Rx = -IterationX; Rx <= IterationX; Rx++)
{
for (int Rz = -IterationX; Rz <= IterationX; Rz++)
{
ChunkX = Position.x + Rx;
ChunkY = Position.y + Ry;
ChunkY2 = Position.y - Ry;
ChunkZ = Position.z + Rz;
if (Rx == -IterationX || Rz == -IterationX || Rx == IterationX || Rz == IterationX)
{
GenerateChunk(ChunkPos.set(ChunkX, ChunkY, ChunkZ));
GenerateChunk(ChunkPos2.set(ChunkX, ChunkY2, ChunkZ));
}
}
}
}
IterationX++;
if (IterationX > Radius.x || Position.x != LastPosition.x || Position.y != LastPosition.y || Position.z != LastPosition.z)
{
IterationX = 0;
}
LastPosition.set(Position);
}
public static void RecordGeneration(VulkanContext VkCtx, CommandBuffer commandBuffer) {
if (Resources == null) {
Init(VkCtx);
}
int generatedThisFrame = 0;
while (!RequestedChunks.isEmpty() && generatedThisFrame < MAX_CHUNK_GENERATIONS_PER_FRAME) {
Vector3i position = RequestedChunks.poll();
if (position == null) {
break;
}
// VoxelChunkVisibility visibility = VoxelTerrainHeightSampler.classifyChunk(
// position.x,
// position.y,
// position.z,
// VoxelChunkGenerator.CHUNK_SIZE
// );
//
// if (visibility != VoxelChunkVisibility.SURFACE) {
// CulledChunks.put(new Vector3i(position), visibility);
// continue;
// }
RenderChunk renderChunk = Resources.meshPool().allocate(position);
if (renderChunk == null) {
Logger.warn("Voxel mesh pool full. Could not allocate chunk {}", position);
RequestedChunks.add(position);
break;
}
Generator.recordGenerateChunk(VkCtx, commandBuffer, renderChunk);
RenderChunks.put(new Vector3i(position), renderChunk);
generatedThisFrame++;
}
}
public static void RecordRender(VkCommandBuffer CommandBuffer,Pipeline graphicsPipeline, MaterialsCache materialsCache) {
if (Resources == null) {
return;
}
int terrainMaterialIndex = materialsCache.GetPosition("VoxelTerrain");
if (terrainMaterialIndex < 0) {
terrainMaterialIndex = 0;
}
try (MemoryStack stack = MemoryStack.stackPush()) {
Matrix4f identity = new Matrix4f().identity();
identity.get(0, GraphicsPushConstants);
GraphicsPushConstants.putInt(
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE,
terrainMaterialIndex
);
vkCmdPushConstants(CommandBuffer, graphicsPipeline.GetVulkanPipelineLayout(),VK_SHADER_STAGE_VERTEX_BIT,
0,GraphicsPushConstants.slice(
0,
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE));
vkCmdPushConstants(CommandBuffer,graphicsPipeline.GetVulkanPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT,
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE,
GraphicsPushConstants.slice(
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.MATRIX4X4_SIZE,
net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils.INT_SIZE ) );
LongBuffer vertexBuffers = stack.longs(Resources.meshPool().vertexPoolHandle());
LongBuffer offsets = stack.longs(0L);
vkCmdBindVertexBuffers(CommandBuffer, 0, vertexBuffers, offsets);
vkCmdBindIndexBuffer(CommandBuffer, Resources.meshPool().indexPoolHandle(), 0, VK_INDEX_TYPE_UINT32);
RenderChunks.forEach((position, chunk) -> vkCmdDrawIndexedIndirect(CommandBuffer,Resources.meshPool().indirectPoolHandle(),
chunk.indirectCommandOffsetBytes(), 1,VoxelMeshPool.DRAW_INDEXED_INDIRECT_COMMAND_SIZE));
}
}
public static void UnloadFarChunks(Vector3i centerChunk, int unloadRadius) {
int maxDistSq = unloadRadius * unloadRadius;
RenderChunks.entrySet().removeIf(entry -> {
Vector3i pos = entry.getKey();
int dx = pos.x - centerChunk.x;
int dy = pos.y - centerChunk.y;
int dz = pos.z - centerChunk.z;
int distSq = dx * dx + dy * dy + dz * dz;
if (distSq > maxDistSq) {
RenderChunk chunk = entry.getValue();
Resources.meshPool().free(chunk);
KnownChunks.remove(pos);
return true;
}
return false;
});
CulledChunks.entrySet().removeIf(entry -> {
Vector3i pos = entry.getKey();
int dx = pos.x - centerChunk.x;
int dy = pos.y - centerChunk.y;
int dz = pos.z - centerChunk.z;
int distSq = dx * dx + dy * dy + dz * dz;
if (distSq > maxDistSq) {
KnownChunks.remove(pos);
return true;
}
return false;
});
RequestedChunks.removeIf(pos -> {
int dx = pos.x - centerChunk.x;
int dy = pos.y - centerChunk.y;
int dz = pos.z - centerChunk.z;
int distSq = dx * dx + dy * dy + dz * dz;
if (distSq > maxDistSq) {
KnownChunks.remove(pos);
return true;
}
return false;
});
}
public static int GetRenderableChunkCount() {
return RenderChunks.size();
}
public static int GetCulledChunkCount() {
return CulledChunks.size();
}
public static int GetRequestedChunkCount() {
return RequestedChunks.size();
}
public static int GetFreeMeshSlots() {
if (Resources == null) {
return 0;
}
return Resources.meshPool().freeSlotCount();
}
public static void Cleanup(VulkanContext VkCtx) {
if (Resources != null) {
Resources.cleanup(VkCtx);
Resources = null;
}
if (GraphicsPushConstants != null) {
org.lwjgl.system.MemoryUtil.memFree(GraphicsPushConstants);
GraphicsPushConstants = null;
}
RequestedChunks.clear();
RenderChunks.clear();
KnownChunks.clear();
}
}

View file

@ -0,0 +1,94 @@
package net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VulkanUtil;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.PushConstantsRange;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.DescriptorSetLayout;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Shader.ShaderModule;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.*;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
import static org.lwjgl.vulkan.VK10.*;
public class ComputePipeline implements Pipeline {
private final long VulkanPipeline;
private final long VulkanPipelineLayout;
public ComputePipeline(VulkanContext VkCtx,ShaderModule shaderModule, DescriptorSetLayout[] descriptorSetLayouts,PushConstantsRange[] pushConstantsRanges) {
Device device = VkCtx.GetDevice();
try (MemoryStack stack = MemoryStack.stackPush()) {
LongBuffer pPipelineLayout = stack.mallocLong(1);
LongBuffer pPipeline = stack.mallocLong(1);
int layoutCount = descriptorSetLayouts != null ? descriptorSetLayouts.length : 0;
LongBuffer setLayouts = stack.mallocLong(layoutCount);
for (int i = 0; i < layoutCount; i++) {
setLayouts.put(i, descriptorSetLayouts[i].GetVkDescriptorLayout());
}
VkPushConstantRange.Buffer pushRanges = null;
int pushRangeCount = pushConstantsRanges != null ? pushConstantsRanges.length : 0;
if (pushRangeCount > 0) {
pushRanges = VkPushConstantRange.calloc(pushRangeCount, stack);
for (int i = 0; i < pushRangeCount; i++) {
PushConstantsRange range = pushConstantsRanges[i];
pushRanges.get(i)
.stageFlags(range.Stage())
.offset(range.Offset())
.size(range.Size());
}
}
VkPipelineLayoutCreateInfo layoutInfo = VkPipelineLayoutCreateInfo.calloc(stack)
.sType$Default()
.pSetLayouts(setLayouts)
.pPushConstantRanges(pushRanges);
VulkanUtils.vkCheck(
vkCreatePipelineLayout(device.FetchVulkanDevice(), layoutInfo, null, pPipelineLayout),
"Unable to create compute pipeline layout"
);
VulkanPipelineLayout = pPipelineLayout.get(0);
ByteBuffer main = stack.UTF8("main");
VkPipelineShaderStageCreateInfo shaderStage = VkPipelineShaderStageCreateInfo.calloc(stack)
.sType$Default()
.stage(VK_SHADER_STAGE_COMPUTE_BIT)
.module(shaderModule.GetHandle())
.pName(main);
VkComputePipelineCreateInfo.Buffer pipelineInfo = VkComputePipelineCreateInfo.calloc(1, stack)
.sType$Default()
.stage(shaderStage)
.layout(VulkanPipelineLayout);
VulkanUtils.vkCheck(vkCreateComputePipelines(device.FetchVulkanDevice(),VkCtx.GetVkPipelineCache().GetVkPipelineCache(),
pipelineInfo,null,pPipeline),"Unable to create compute pipeline" );
VulkanPipeline = pPipeline.get(0);
}
}
@Override
public long GetVulkanPipeline() {
return VulkanPipeline;
}
@Override
public long GetVulkanPipelineLayout() {
return VulkanPipelineLayout;
}
@Override
public void CleanUp(VulkanContext VkCtx) {
VkDevice device = VkCtx.GetDevice().FetchVulkanDevice();
vkDestroyPipeline(device, VulkanPipeline, null);
vkDestroyPipelineLayout(device, VulkanPipelineLayout, null);
}
}

View file

@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement;
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer;
import net.halbear.Terrain4J.EngineCore.ServerNetworking.ClientSideNetworkUtils;
@ -379,6 +380,8 @@ public class DeferredSceneRender implements SceneRenderer {//dynamic rendering
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache);
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());
skyboxViewMatrix.m30(0.0f);

View file

@ -7,6 +7,7 @@ import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3DElement;
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.RenderPasses.DeferredRendering.DeferredSceneRender;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.ImageView;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Structure.DisplayToScreen.SceneRenderer;
@ -363,6 +364,7 @@ public class ForwardSceneRender implements SceneRenderer {//dynamic rendering
.put(3,descriptorAllocator.GetDescriptorSet(DESCRIPTOR_ID_TEXT).GetVkDescriptorSet());
vkCmdBindDescriptorSets(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, DualPassRendering ? VkPipelineOpaque.GetVulkanPipelineLayout() : VkPipeline.GetVulkanPipelineLayout(),0,DescriptorSets,null);
RenderActors(engineInstance, CommandHandle, modelsCache, materialsCache, false);
VoxelWorldManager.RecordRender(CommandHandle, DualPassRendering ? VkPipelineOpaque : VkPipeline,materialsCache);
Matrix4f skyboxViewMatrix = new Matrix4f().identity();
skyboxViewMatrix.set(engineInstance.scene().GetCamera().GetViewMatrix());

View file

@ -6,6 +6,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor.Actor3D;
import net.halbear.Terrain4J.EngineCore.Main.Scene.IScene;
import net.halbear.Terrain4J.EngineCore.Main.Scene.SceneLightingManager;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Computing.VoxelTerrainGeneration.VoxelWorldManager;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.DefaultPipeline;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.Attachment;
import net.halbear.Terrain4J.EngineCore.RenderingAPI.Vulkan.Rendering.Pipeline.Images.ITexture;
@ -393,7 +394,7 @@ public class ShadowRenderer {
vkCmdDrawIndexed(cmdHandle, vulkanMesh.IndicesCount(), 1, 0, 0, 0);
}
}
VoxelWorldManager.RecordRender(cmdHandle,pipeline,materialsCache);
vkCmdEndRendering(cmdHandle);
}
}

View file

@ -47,6 +47,7 @@ public class DescriptorSet {
.sType$Default()
.dstSet(VkDescriptorSet)
.dstBinding(Binding)
.dstArrayElement(0)
.descriptorType(Type)
.descriptorCount(1)
.pBufferInfo(BufferInfo);

View file

@ -206,6 +206,50 @@ public class VulkanUtils {
}
return result;
}
public static void BufferBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long BufferHandle,
long SrcStage,long DstStage,long SrcAccess,long DstAccess){
var BufferBarrier = VkBufferMemoryBarrier2.calloc(1, MemStack)
.sType$Default()
.srcStageMask(SrcStage)
.dstStageMask(DstStage)
.srcAccessMask(SrcAccess)
.dstAccessMask(DstAccess)
.srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.buffer(BufferHandle)
.offset(0)
.size(VK_WHOLE_SIZE);
VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack)
.sType$Default()
.pBufferMemoryBarriers(BufferBarrier);
vkCmdPipelineBarrier2(CommandHandle, DependencyInfo);
}
public static void BufferBarriers(MemoryStack MemStack,VkCommandBuffer CommandHandle,long[] Buffers,
long SrcStage,long DstStage,long SrcAccess,long DstAccess ){
var BufferBarriers = VkBufferMemoryBarrier2.calloc(Buffers.length, MemStack);
for (int i = 0; i < Buffers.length; i++) {
BufferBarriers.get(i)
.sType$Default()
.srcStageMask(SrcStage)
.dstStageMask(DstStage)
.srcAccessMask(SrcAccess)
.dstAccessMask(DstAccess)
.srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.buffer(Buffers[i])
.offset(0)
.size(VK_WHOLE_SIZE);
}
VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack)
.sType$Default()
.pBufferMemoryBarriers(BufferBarriers);
vkCmdPipelineBarrier2(CommandHandle, DependencyInfo);
}
public static void ImageBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long Image, int OldLayout,
int NewLayout, long SrcStage, long DstStage, long SrcAccess, long DstAccess,
int AspectMask){