Vulkan Models, Mesh, Model caching and synchronisation

This commit is contained in:
Harrison Corlett 2026-05-13 15:21:36 +01:00
parent 01b7d524ee
commit 1ff359487d
6 changed files with 165 additions and 0 deletions

View file

@ -0,0 +1,4 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
public record MeshData(String ID, float[] Positions, int[] Indices) {
}

View file

@ -0,0 +1,8 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
import java.util.List;
public record ModelData(String ID, List<MeshData> Meshes) {
}

View file

@ -0,0 +1,102 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandPool;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.TransferBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Queues.Queue;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryUtil;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.lwjgl.vulkan.VK10.*;
public class ModelsCache {
private final Map<String, VulkanModel> ModelsMap;
public ModelsCache(){
ModelsMap = new HashMap<>();
}
public void loadModels(VulkanContext VkCtx, List<ModelData> Models, CommandPool commandPool, Queue queue){
List<VulkanBuffer> StagingBufferList = new ArrayList<>();
var Command = new CommandBuffer(VkCtx, commandPool, true, true);
Command.BeginRecording();
for(ModelData modelData : Models){
VulkanModel VKModel = new VulkanModel(modelData.ID());
ModelsMap.put(VKModel.GetID(), VKModel);
for(MeshData meshData : modelData.Meshes()){
TransferBuffer VerticesBuffers = CreateVerticesBuffer(VkCtx,meshData);
TransferBuffer IndicesBuffers = CreateIndicesBuffer(VkCtx,meshData);
StagingBufferList.add(VerticesBuffers.SrcBuffer());
StagingBufferList.add(IndicesBuffers.SrcBuffer());
VerticesBuffers.RecordTransferCommand(Command);
IndicesBuffers.RecordTransferCommand(Command);
VulkanMesh VkMesh = new VulkanMesh(meshData.ID(), VerticesBuffers.DstBuffer(),IndicesBuffers.DstBuffer(),
meshData.Indices().length);
VKModel.GetVkMeshList().add(VkMesh);
}
}
Command.EndRecording();
Command.SubmitAndWait(VkCtx,queue);
Command.cleanup(VkCtx,commandPool);
StagingBufferList.forEach(b -> b.cleanup(VkCtx));
}
private static TransferBuffer CreateVerticesBuffer(VulkanContext VkCtx, MeshData meshData){
float[] Positions = meshData.Positions();
int ElementCount = Positions.length;
int BufferSize = ElementCount * VulkanUtils.FLOAT_SIZE;
var SrcBuffer = new VulkanBuffer(VkCtx,BufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
var DstBuffer = new VulkanBuffer(VkCtx, BufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
long MappedMemory = SrcBuffer.MapMemory(VkCtx);
FloatBuffer data = MemoryUtil.memFloatBuffer(MappedMemory, (int) SrcBuffer.GetRequestedSize());
int Rows = Positions.length / 3;
for(int Row = 0; Row < Rows; Row++){
int StartPos = Row * 3;
data.put(Positions[StartPos]);
data.put(Positions[StartPos+1]);
data.put(Positions[StartPos+2]);
}
SrcBuffer.UnMapMemory(VkCtx);
return new TransferBuffer(SrcBuffer,DstBuffer);
}
private static TransferBuffer CreateIndicesBuffer(VulkanContext VkCtx, MeshData meshData){
int[] Indices = meshData.Indices();
int IndexCount = Indices.length;
int BufferSize = IndexCount * VulkanUtils.INT_SIZE;
var SrcBuffer = new VulkanBuffer(VkCtx,BufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
var DstBuffer = new VulkanBuffer(VkCtx, BufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
long MappedMemory = SrcBuffer.MapMemory(VkCtx);
IntBuffer data = MemoryUtil.memIntBuffer(MappedMemory,(int) SrcBuffer.GetRequestedSize());
data.put(Indices);
SrcBuffer.UnMapMemory(VkCtx);
return new TransferBuffer(SrcBuffer,DstBuffer);
}
public VulkanModel GetModel(String modelName){
return ModelsMap.get(modelName);
}
public Map<String, VulkanModel> GetModelMap(){
return ModelsMap;
}
public void CleanUp(VulkanContext VkCtx){
ModelsMap.forEach((key,Value)->Value.CleanUp(VkCtx));
ModelsMap.clear();
}
}

View file

@ -0,0 +1,12 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
public record VulkanMesh(String ID, VulkanBuffer VerticesBuffer,VulkanBuffer IndicesBuffer,int IndicesCount) {
public void Cleanup(VulkanContext VkCtx){
VerticesBuffer.cleanup(VkCtx);
IndicesBuffer.cleanup(VkCtx);
}
}

View file

@ -0,0 +1,21 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
import java.util.ArrayList;
import java.util.List;
public class VulkanModel {
private final String ID;
private final List<VulkanMesh> VulkanMeshList;
public VulkanModel(String id){
this.ID = id;
VulkanMeshList = new ArrayList<>();
}
public void CleanUp(VulkanContext VkCtx){
VulkanMeshList.forEach(mesh -> mesh.Cleanup(VkCtx));
}
public String GetID(){return ID;}
public List<VulkanMesh> GetVkMeshList(){return this.VulkanMeshList;}
}

View file

@ -0,0 +1,18 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkBufferCopy;
import static org.lwjgl.vulkan.VK10.vkCmdCopyBuffer;
public record TransferBuffer(VulkanBuffer SrcBuffer, VulkanBuffer DstBuffer) {
public void RecordTransferCommand(CommandBuffer commandBuffer){
try(var MemStack = MemoryStack.stackPush()){
VkBufferCopy.Buffer CopyRegion = VkBufferCopy.calloc(1,MemStack)
.srcOffset(0).dstOffset(0).size(SrcBuffer.GetRequestedSize());
vkCmdCopyBuffer(commandBuffer.GetVulkanCommandBuffer(),SrcBuffer.GetBuffer(),DstBuffer.GetBuffer(),CopyRegion);
}
}
}