Working on complex models and texture loading

This commit is contained in:
Harrison Corlett 2026-06-04 15:29:59 +01:00
parent 6d6d9f42be
commit c2aa4ec895
27 changed files with 780 additions and 59 deletions

View file

@ -1,9 +1,33 @@
#version 450 #version 450
const int MAX_TEXTURES = 100;
layout(location = 0) in vec2 inTextCoords; layout(location = 0) in vec2 inTextCoords;
layout(location = 0) out vec4 outFragColor; layout(location = 0) out vec4 outFragColor;
struct Material{
vec4 diffuseColor;
uint hasTexture;
uint textureIdx;
uint padding[2];
};
layout(set = 1, binding = 0) readonly buffer MaterialUniform{
Material materials[];
} matUniform;
layout(set = 2, binding = 0) uniform sampler2D textSampler[MAX_TEXTURES];
layout(push_constant) uniform pc{
layout(offset = 64) uint materialIdx;
} push_constants;
void main() void main()
{ {
outFragColor = vec4(inTextCoords.x, inTextCoords.y, 0, 1); Material material = matUniform.materials[push_constants.materialIdx];
if(material.hasTexture == 1){
outFragColor = texture(textSampler[material.textureIdx],inTextCoords);
} else{
outFragColor = material.diffuseColor;
}
} }

View file

@ -4,13 +4,17 @@ layout(location = 0) in vec3 inPos;
layout(location = 1) in vec2 intTextCoords; layout(location = 1) in vec2 intTextCoords;
layout(location = 0) out vec2 outTextCoords; layout(location = 0) out vec2 outTextCoords;
layout(push_constant) uniform matrices{
mat4 projectionMatrix; layout(set = 0, binding = 0) uniform ProjUniform{
mat4 matrix;
} projUniform;
layout(push_constant) uniform pc{
mat4 modelMatrix; mat4 modelMatrix;
} push_constants; } push_constants;
void main() void main()
{ {
gl_Position = push_constants.projectionMatrix * push_constants.modelMatrix * vec4(inPos,1); gl_Position = projUniform.matrix * push_constants.modelMatrix * vec4(inPos,1);
outTextCoords = intTextCoords; outTextCoords = intTextCoords;
} }

View file

@ -44,6 +44,7 @@ public class EngineConfig {
private String PhysicalDeviceName; private String PhysicalDeviceName;
private int RequestedImages; private int RequestedImages;
private String IconPath = "/WindowResources/Icon/"; private String IconPath = "/WindowResources/Icon/";
private String DefaultTexturePath = "/EngineResources/Texture/DefaultTexture.png";
private String IconName = "ProgramIcon.png"; private String IconName = "ProgramIcon.png";
private float FOV = 60f; private float FOV = 60f;
private float zFarPlane; private float zFarPlane;
@ -62,7 +63,6 @@ public class EngineConfig {
boolean SuccessfulLoad = false; boolean SuccessfulLoad = false;
try(InputStream stream = new FileInputStream(path.toAbsolutePath().toString() + "/" + FILENAME)){ try(InputStream stream = new FileInputStream(path.toAbsolutePath().toString() + "/" + FILENAME)){
try { try {
EngineConfigVar.load(stream); EngineConfigVar.load(stream);
SuccessfulLoad = true; SuccessfulLoad = true;
Logger.debug("File [{}] read", FILENAME); Logger.debug("File [{}] read", FILENAME);
@ -116,6 +116,7 @@ public class EngineConfig {
FOV = (float)(DegToRad * Float.parseFloat(EngineConfigVar.getOrDefault("field_of_view", 60.0f).toString())); FOV = (float)(DegToRad * Float.parseFloat(EngineConfigVar.getOrDefault("field_of_view", 60.0f).toString()));
zNearPlane = (Float.parseFloat(EngineConfigVar.getOrDefault("z_near_plane", 1.0f).toString())); zNearPlane = (Float.parseFloat(EngineConfigVar.getOrDefault("z_near_plane", 1.0f).toString()));
zFarPlane = (Float.parseFloat(EngineConfigVar.getOrDefault("z_far_plane", 100.0f).toString())); zFarPlane = (Float.parseFloat(EngineConfigVar.getOrDefault("z_far_plane", 100.0f).toString()));
DefaultTexturePath = EngineConfigVar.getOrDefault("DefaultTexturePath","/EngineResources/Texture/DefaultTexture.png").toString();
Logger.debug("\n\nsuccessfully loaded configuration: \n{}\n\n",EngineConfigVar.toString()); Logger.debug("\n\nsuccessfully loaded configuration: \n{}\n\n",EngineConfigVar.toString());
} }
else if(!ConfigFile.exists()){ else if(!ConfigFile.exists()){
@ -142,6 +143,7 @@ public class EngineConfig {
EngineConfigVar.setProperty("field_of_view","60"); EngineConfigVar.setProperty("field_of_view","60");
EngineConfigVar.setProperty("z_near_plane","1"); EngineConfigVar.setProperty("z_near_plane","1");
EngineConfigVar.setProperty("z_far_plane","100"); EngineConfigVar.setProperty("z_far_plane","100");
EngineConfigVar.setProperty("DefaultTexturePath",DefaultTexturePath);
EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file"); EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file");
Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath()); Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath());
} catch (IOException excp2) { } catch (IOException excp2) {

View file

@ -3,6 +3,7 @@ package net.halbear.Terrain4J.EngineCore.Logic.Rendering;
import net.halbear.Terrain4J.EngineCore.Display.Window; import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineCache; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineCache;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorAllocator;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.PhysicalDevice; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.PhysicalDevice;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.Surface; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.Surface;
@ -18,6 +19,7 @@ public class VulkanContext {
private final PhysicalDevice PhysDevice; private final PhysicalDevice PhysDevice;
private SwapChain swapChain; private SwapChain swapChain;
private final PipelineCache VkPipelineCache; private final PipelineCache VkPipelineCache;
private final DescriptorAllocator descriptorAllocator;
public VulkanContext(Window window){ public VulkanContext(Window window){
var EngineGlobals = EngineConfig.getInstance(); var EngineGlobals = EngineConfig.getInstance();
@ -28,6 +30,7 @@ public class VulkanContext {
swapChain = new SwapChain(window, device, surface, EngineGlobals.GetRequestedImages(), EngineGlobals.GetVSYNC()); swapChain = new SwapChain(window, device, surface, EngineGlobals.GetRequestedImages(), EngineGlobals.GetVSYNC());
VulkanLayersOpen+=5; VulkanLayersOpen+=5;
VkPipelineCache = new PipelineCache(device); VkPipelineCache = new PipelineCache(device);
descriptorAllocator = new DescriptorAllocator(PhysDevice, device);
} }
public void Resize(Window window){ public void Resize(Window window){
swapChain.cleanup(device); swapChain.cleanup(device);
@ -37,6 +40,7 @@ public class VulkanContext {
swapChain = new SwapChain(window, device, surface, EngCfg.GetRequestedImages(),EngCfg.GetVSYNC()); swapChain = new SwapChain(window, device, surface, EngCfg.GetRequestedImages(),EngCfg.GetVSYNC());
} }
public void cleanup(){ public void cleanup(){
descriptorAllocator.CleanUp(device);
swapChain.cleanup(device); swapChain.cleanup(device);
surface.cleanup(Instance); surface.cleanup(Instance);
VkPipelineCache.CleanUp(device); VkPipelineCache.CleanUp(device);
@ -57,4 +61,5 @@ public class VulkanContext {
public Surface GetSurface(){ public Surface GetSurface(){
return surface; return surface;
} }
public DescriptorAllocator GetDescriptorAllocator(){return descriptorAllocator;}
} }

View file

@ -24,7 +24,7 @@ public class Attachment {
DepthAttachment = true; DepthAttachment = true;
} }
var ImageViewData = new ImageView.ImageViewData().Format(VkImage.GetFormat()).AspectMask(AspectMask); var ImageViewData = new ImageView.ImageViewData().Format(VkImage.GetFormat()).AspectMask(AspectMask);
VkImageView = new ImageView(VkCtx.GetDevice(), VkImage.getVulkanImage(), ImageViewData); VkImageView = new ImageView(VkCtx.GetDevice(), VkImage.getVulkanImage(), ImageViewData,false);
} }
public Image GetVkImage(){return VkImage;} public Image GetVkImage(){return VkImage;}

View file

@ -32,11 +32,11 @@ public class Texture {
CreateStgBuffer(VkCtx, imageSrc.data()); CreateStgBuffer(VkCtx, imageSrc.data());
var ImageData = new Image.ImageData().Width(Width).Height(Height) var ImageData = new Image.ImageData().Width(Width).Height(Height)
.usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) .Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
.format(ImageFormat); .Format(ImageFormat);
image = new Image(VkCtx, ImageData); image = new Image(VkCtx, ImageData);
var ImageViewData = new ImageView.ImageViewData().format(image.GetFormat()) var ImageViewData = new ImageView.ImageViewData().Format(image.GetFormat())
.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT); .AspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
imageView = new ImageView(VkCtx.GetDevice(), image.getVulkanImage(), ImageViewData, false); imageView = new ImageView(VkCtx.GetDevice(), image.getVulkanImage(), ImageViewData, false);
} }

View file

@ -0,0 +1,86 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.GraphUtils;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.IndexedLinkedHashMap;
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.Queues.Queue;
import org.tinylog.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.lwjgl.vulkan.VK10.VK_FORMAT_R8G8B8A8_SRGB;
public class TextureCache {
public static final int MAX_TEXTURES = 100;
private final IndexedLinkedHashMap<String, Texture> TextureMap;
public TextureCache(){
TextureMap = new IndexedLinkedHashMap<>();
}
public Texture AddTexture(VulkanContext VkCtx, String ID, ImageSrc imageSrc, int Format){
if(TextureMap.size() > MAX_TEXTURES){
throw new IllegalArgumentException("Texture Cache Is Full");
}
Texture newTexture = TextureMap.get(ID);
if(newTexture == null){
newTexture = new Texture(VkCtx, ID, imageSrc, Format);
TextureMap.put(ID, newTexture);
}
return newTexture;
}
public Texture AddTexture(VulkanContext VkCtx, String ID, String TexturePath, int Format) {
ImageSrc imageSrc = null;
Texture result = null;
try{
imageSrc = GraphUtils.LoadImage(TexturePath);
result = AddTexture(VkCtx, ID, imageSrc, Format);
} catch (IOException exception){
Logger.error("Could not load texture from patch [{}], exception: {}",TexturePath, exception);
} finally{
if(imageSrc != null){
GraphUtils.CleanImageData(imageSrc);
}
}
return result;
}
public void TransitionTexts(VulkanContext VkCtx, CommandPool CmdPool, Queue queue){
Logger.debug("Recording Texture Transition");
int TextureCount = TextureMap.size();
if(TextureCount < MAX_TEXTURES){
int PaddingTextCount = MAX_TEXTURES - TextureCount;
String DefaultTexturePath = EngineConfig.getInstance().GetDefaultTexturePath();
for(int i = 0; i < PaddingTextCount; i++){
AddTexture(VkCtx, UUID.randomUUID().toString(), DefaultTexturePath, VK_FORMAT_R8G8B8A8_SRGB);
}
}
var CommandBuffer = new CommandBuffer(VkCtx, CmdPool, true, true);
CommandBuffer.BeginRecording();
TextureMap.forEach((key,value)->value.RecordTextureTransition(CommandBuffer));
CommandBuffer.EndRecording();
CommandBuffer.SubmitAndWait(VkCtx, queue);
CommandBuffer.cleanup(VkCtx, CmdPool);
TextureMap.forEach((key,value)->value.CleanUpStgBuffer(VkCtx));
Logger.debug("Recorded Texture Transition");
}
public List<Texture> GetTextureList(){return new ArrayList<>(TextureMap.values());}
public int GetPosition(String ID){
int result = -1;
if(ID != null){
result = TextureMap.GetIndexOf(ID);
}
return result;
}
public void CleanUp(VulkanContext VkCtx){
TextureMap.forEach((k,t)->t.CleanUp(VkCtx));
TextureMap.clear();
}
}

View file

@ -0,0 +1,23 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class IndexedLinkedHashMap<K,V> extends LinkedHashMap<K,V> {
private final List<K> IndexList = new ArrayList<>();
public int GetIndexOf(K key){
return IndexList.indexOf(key);
}
public V GetValueAtIndex(int i){
return super.get(IndexList.get(i));
}
@Override
public V put(K key, V value){
if(!super.containsKey(key)) IndexList.add(key);
return super.put(key,value);
}
}

View file

@ -1,6 +1,7 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline; package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSetLayout;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils; import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
@ -99,8 +100,17 @@ public class Pipeline {
.size(pushConstantsRange.Size()); .size(pushConstantsRange.Size());
} }
} }
DescriptorSetLayout[] descriptorSetLayouts = BuildInfo.GetDescriptorSetLayouts();
int LayoutCount = descriptorSetLayouts != null ? descriptorSetLayouts.length : 0;
LongBuffer ppLayout = MemStack.mallocLong(LayoutCount);
for(int i = 0; i < LayoutCount; i++){
ppLayout.put(i, descriptorSetLayouts[i].GetVkDescriptorLayout());
}
var PipelineLayoutCreateInfoPtr = VkPipelineLayoutCreateInfo.calloc(MemStack) var PipelineLayoutCreateInfoPtr = VkPipelineLayoutCreateInfo.calloc(MemStack)
.sType$Default() .sType$Default()
.pSetLayouts(ppLayout)
.pPushConstantRanges(VkPushConstRangeBuffer); .pPushConstantRanges(VkPushConstRangeBuffer);
VulkanUtils.vkCheck(vkCreatePipelineLayout(device.FetchVulkanDevice(), PipelineLayoutCreateInfoPtr,null,longPtr) VulkanUtils.vkCheck(vkCreatePipelineLayout(device.FetchVulkanDevice(), PipelineLayoutCreateInfoPtr,null,longPtr)

View file

@ -1,5 +1,6 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline; package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.DescriptorSetLayout;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule;
import org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo; import org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo;
import org.lwjgl.vulkan.VkPushConstantRange; import org.lwjgl.vulkan.VkPushConstantRange;
@ -12,6 +13,7 @@ public class PipelineBuildInfo {
private final VkPipelineVertexInputStateCreateInfo VertexInput; private final VkPipelineVertexInputStateCreateInfo VertexInput;
private int DepthFormat; private int DepthFormat;
private PushConstantsRange[] PushConstRanges; private PushConstantsRange[] PushConstRanges;
private DescriptorSetLayout[] DescriptorSetLayouts;
public PipelineBuildInfo(ShaderModule[] shaderModules, VkPipelineVertexInputStateCreateInfo VertexInput, int ColourFormat){ public PipelineBuildInfo(ShaderModule[] shaderModules, VkPipelineVertexInputStateCreateInfo VertexInput, int ColourFormat){
this.ColourFormat = ColourFormat; this.ColourFormat = ColourFormat;
@ -20,6 +22,13 @@ public class PipelineBuildInfo {
DepthFormat = VK_FORMAT_UNDEFINED; DepthFormat = VK_FORMAT_UNDEFINED;
} }
public DescriptorSetLayout[] GetDescriptorSetLayouts(){return DescriptorSetLayouts;}
public PipelineBuildInfo SetDescriptorSetLayouts(DescriptorSetLayout[] descriptorSetLayouts){
this.DescriptorSetLayouts = descriptorSetLayouts;
return this;
}
public PipelineBuildInfo SetDepthFormat(int DepthFormat){ public PipelineBuildInfo SetDepthFormat(int DepthFormat){
this.DepthFormat = DepthFormat; this.DepthFormat = DepthFormat;
return this; return this;

View file

@ -0,0 +1,132 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.PhysicalDevice;
import org.lwjgl.vulkan.VkPhysicalDeviceFeatures2;
import org.lwjgl.vulkan.VkPhysicalDeviceLimits;
import org.tinylog.Logger;
import java.util.*;
import static org.lwjgl.vulkan.VK10.*;
public class DescriptorAllocator {
private final Map<Integer,Integer> DescriptorLimits;
private final List<DescriptorPoolInfo> DescriptorPoolList;
private final Map<String,DescriptorSetInfo> DescriptorSetInfoMap;
public DescriptorAllocator(PhysicalDevice physicalDevice, Device device){
Logger.debug("Creating Descriptor Allocator");
DescriptorPoolList = new ArrayList<>();
DescriptorLimits = CreateDescriptorLimits(physicalDevice);
DescriptorPoolList.add(CreateDescriptorPoolInformation(device, DescriptorLimits));
DescriptorSetInfoMap = new HashMap<>();
}
public synchronized DescriptorSet AddDescriptorSet(Device device, String ID, DescriptorSetLayout descriptorSetLayout){
return AddDescriptorSets(device, ID, 1, descriptorSetLayout)[0];
}
public synchronized DescriptorSet[] AddDescriptorSets(Device device, String ID, int count, DescriptorSetLayout descriptorSetLayout){
DescriptorPoolInfo TargetPool = null;
int PoolPosition = 0;
for(DescriptorPoolInfo descriptorPoolInfo : DescriptorPoolList){
for(DescriptorSetLayout.LayoutInformation LayoutInfo : descriptorSetLayout.GetLayoutInfos()){
int DescriptorType = LayoutInfo.DescriptorType();
Integer Available = descriptorPoolInfo.DescriptorCount.get(DescriptorType);
if(Available == null){
throw new RuntimeException("Unknown Type [" + DescriptorType + "]");
}
Integer MaxTotal = DescriptorLimits.get(DescriptorType);
if(count > MaxTotal){
throw new RuntimeException("Cannot Create More than ["+MaxTotal+"] for descriptor type [" + DescriptorType + "]");
}
if(Available < count){
TargetPool = null;
break;
} else{
TargetPool = descriptorPoolInfo;
}
}
PoolPosition++;
}
if(TargetPool == null){
TargetPool = CreateDescriptorPoolInformation(device, DescriptorLimits);
DescriptorPoolList.add(TargetPool);
PoolPosition++;
}
var Result = new DescriptorSet[count];
for(int i = 0; i < count; i++){
DescriptorSet descriptorSet = new DescriptorSet(device, TargetPool.descriptorPool(), descriptorSetLayout);
Result[i] = descriptorSet;
}
DescriptorSetInfoMap.put(ID, new DescriptorSetInfo(Result, PoolPosition));
for(DescriptorSetLayout.LayoutInformation LayoutInfo : descriptorSetLayout.GetLayoutInfos()){
int DescriptorType = LayoutInfo.DescriptorType();
TargetPool.DescriptorCount.put(DescriptorType,TargetPool.DescriptorCount.get(DescriptorType) - count);
}
return Result;
}
private static DescriptorPoolInfo CreateDescriptorPoolInformation(Device device, Map<Integer,Integer>DescriptorLimits){
Map<Integer,Integer> DescriptorCount = new HashMap<>();
List<DescriptorPool.DescriptorTypeCount> DescriptorTypeCounts = new ArrayList<>();
DescriptorLimits.forEach((key,value)->{
DescriptorCount.put(key,value);
DescriptorTypeCounts.add(new DescriptorPool.DescriptorTypeCount(key,value));
});
var DescriptorPool = new DescriptorPool(device, DescriptorTypeCounts);
return new DescriptorPoolInfo(DescriptorCount, DescriptorPool);
}
private static Map<Integer,Integer> CreateDescriptorLimits(PhysicalDevice physicalDevice){
var EngConfig = EngineConfig.getInstance();
int MaxDescriptors = EngConfig.GetMaxDescriptors();
VkPhysicalDeviceLimits limits = physicalDevice.GetPhysicalDeviceProperties().properties().limits();
Map<Integer, Integer> DescriptorLimits = new HashMap<>();
DescriptorLimits.put(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (int)Math.min(MaxDescriptors, Integer.toUnsignedLong(limits.maxDescriptorSetUniformBuffers())));
DescriptorLimits.put(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, (int)Math.min(MaxDescriptors, Integer.toUnsignedLong(limits.maxDescriptorSetSamplers())));
DescriptorLimits.put(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, (int)Math.min(MaxDescriptors, Integer.toUnsignedLong(limits.maxDescriptorSetStorageBuffers())));
return DescriptorLimits;
}
public synchronized void FreeDescriptorSet(Device device, String ID){
DescriptorSetInfo descriptorSetInfo = DescriptorSetInfoMap.get(ID);
if(descriptorSetInfo == null){
Logger.info("Descriptor Set of ID [{}} does not exist",ID);
return;
}
if(descriptorSetInfo.PoolPosition >= DescriptorPoolList.size()){
Logger.info("Could not locate a pool associated with Descriptor Set ID [{}]",ID);
return;
}
DescriptorPoolInfo descriptorPoolInfo = DescriptorPoolList.get(descriptorSetInfo.PoolPosition);
Arrays.asList(descriptorSetInfo.DescriptorSets()).forEach(descriptorSet ->
descriptorPoolInfo.descriptorPool.FreeDescriptorSet(device, descriptorSet.GetVkDescriptorSet()));
}
public synchronized DescriptorSet GetDescriptorSet(String ID, int Position){
DescriptorSet Result = null;
DescriptorSetInfo descriptorSetInfo = DescriptorSetInfoMap.get(ID);
if(descriptorSetInfo != null){
Result = descriptorSetInfo.DescriptorSets()[Position];
}
return Result;
}
public synchronized DescriptorSet GetDescriptorSet(String ID){
return GetDescriptorSet(ID, 0);
}
record DescriptorPoolInfo(Map<Integer,Integer>DescriptorCount, DescriptorPool descriptorPool){}
record DescriptorSetInfo(DescriptorSet[] DescriptorSets, int PoolPosition){}
public synchronized void CleanUp(Device device){
Logger.debug("Destroying Descriptor Allocator");
DescriptorSetInfoMap.clear();
DescriptorPoolList.forEach(descriptor -> descriptor.descriptorPool.CleanUp(device));
}
}

View file

@ -0,0 +1,60 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkDescriptorPoolCreateInfo;
import org.lwjgl.vulkan.VkDescriptorPoolSize;
import org.tinylog.Logger;
import java.nio.LongBuffer;
import java.util.List;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK10.*;
public class DescriptorPool {
private final long VkDescriptorPool;
private List<DescriptorTypeCount> DescriptorTypeCounts;
public DescriptorPool(Device device, List<DescriptorTypeCount> DescriptorTypeCounts){
Logger.debug("Creating Descriptor pool");
this.DescriptorTypeCounts = DescriptorTypeCounts;
try(var MemStack = MemoryStack.stackPush()){
int MaxSets = 0;
int TypeNum = DescriptorTypeCounts.size();
var TypeCounts = VkDescriptorPoolSize.calloc(TypeNum,MemStack);
for(int i = 0; i < TypeNum; i++){
MaxSets+= DescriptorTypeCounts.get(i).Count();
TypeCounts.get(i)
.type(DescriptorTypeCounts.get(i).DescriptorType())
.descriptorCount(DescriptorTypeCounts.get(i).Count());
}
var DescriptorPoolInfo = VkDescriptorPoolCreateInfo.calloc(MemStack)
.sType$Default()
.flags(VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT)
.pPoolSizes(TypeCounts)
.maxSets(MaxSets);
LongBuffer DescriptorPoolPointer = MemStack.mallocLong(1);
vkCheck(vkCreateDescriptorPool(device.FetchVulkanDevice(), DescriptorPoolInfo, null, DescriptorPoolPointer)
,"Failed to create descriptor pool");
VkDescriptorPool = DescriptorPoolPointer.get(0);
}
}
public void FreeDescriptorSet(Device device, Long VkDescriptorSet){
try(var MemStack = MemoryStack.stackPush()){
LongBuffer longBuffer = MemStack.mallocLong(1);
longBuffer.put(0,VkDescriptorSet);
vkCheck(vkFreeDescriptorSets(device.FetchVulkanDevice(), this.VkDescriptorPool, longBuffer),"Failed to free Descriptor Set");
}
}
public List<DescriptorTypeCount> GetDescriptorTypeCounts(){return DescriptorTypeCounts;}
public long GetVkDescriptorPool(){return VkDescriptorPool;}
public void CleanUp(Device device){
Logger.debug("Destroying Descriptor Pool");
vkDestroyDescriptorPool(device.FetchVulkanDevice(), VkDescriptorPool, null);
}
public record DescriptorTypeCount(int DescriptorType, int Count){}
}

View file

@ -0,0 +1,109 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.ImageView;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkDescriptorBufferInfo;
import org.lwjgl.vulkan.VkDescriptorImageInfo;
import org.lwjgl.vulkan.VkDescriptorSetAllocateInfo;
import org.lwjgl.vulkan.VkWriteDescriptorSet;
import java.nio.LongBuffer;
import java.util.List;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK10.*;
public class DescriptorSet {
protected long VkDescriptorSet;
public DescriptorSet(Device device,DescriptorPool descriptorPool, DescriptorSetLayout descriptorSetLayout){
try(var MemStack = MemoryStack.stackPush()){
LongBuffer DescriptorSetLayoutPointer = MemStack.mallocLong(1);
DescriptorSetLayoutPointer.put(0,descriptorSetLayout.GetVkDescriptorLayout());
var AllocInfo = VkDescriptorSetAllocateInfo.calloc(MemStack)
.sType$Default()
.descriptorPool(descriptorPool.GetVkDescriptorPool())
.pSetLayouts(DescriptorSetLayoutPointer);
LongBuffer DescriptorSetPointer = MemStack.mallocLong(1);
vkCheck(vkAllocateDescriptorSets(device.FetchVulkanDevice(), AllocInfo, DescriptorSetPointer)
,"Failed to create descriptor sets");
VkDescriptorSet = DescriptorSetPointer.get(0);
}
}
public void SetBuffer(Device device, VulkanBuffer VkBuffer, long Range, int Binding, int Type){
try(var MemStack = MemoryStack.stackPush()){
var BufferInfo = VkDescriptorBufferInfo.calloc(1,MemStack)
.buffer(VkBuffer.GetBuffer())
.offset(0)
.range(Range);
var DescriptorBuffer = VkWriteDescriptorSet.calloc(1,MemStack);
DescriptorBuffer.get(0)
.sType$Default()
.dstSet(VkDescriptorSet)
.dstBinding(Binding)
.descriptorCount(1)
.pBufferInfo(BufferInfo);
vkUpdateDescriptorSets(device.FetchVulkanDevice(),DescriptorBuffer,null);
}
}
public void SetImage(Device device, List<ImageView> imageViews, TextureSampler textureSampler, int BaseBinding){
try(var MemStack = MemoryStack.stackPush()){
int ImageCount = imageViews.size();
var DescriptorBuffer = VkWriteDescriptorSet.calloc(ImageCount,MemStack);
for(int i = 0; i < ImageCount; i++){
ImageView imageView = imageViews.get(i);
var ImageInfo = VkDescriptorImageInfo.calloc(1,MemStack)
.imageView(imageView.GetVulkanImageView())
.sampler(textureSampler.GetVkSampler());
if(imageView.IsDepthImage()){
ImageInfo.imageLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
} else{
ImageInfo.imageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
DescriptorBuffer.get(i)
.sType$Default()
.dstSet(VkDescriptorSet)
.dstBinding(BaseBinding + i)
.descriptorType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
.descriptorCount(1)
.pImageInfo(ImageInfo);
}
vkUpdateDescriptorSets(device.FetchVulkanDevice(),DescriptorBuffer,null);
}
}
public void SetImageArray(Device device, List<ImageView> imageViews, TextureSampler textureSampler, int BaseBinding){
try(var MemStack = MemoryStack.stackPush()){
int ImageCount = imageViews.size();
VkDescriptorImageInfo.Buffer imageInfos = VkDescriptorImageInfo.calloc(ImageCount,MemStack);
for(int i = 0; i < ImageCount; i++){
ImageView imageView = imageViews.get(i);
VkDescriptorImageInfo imageInfo = imageInfos.get(i);
imageInfo.imageView(imageView.GetVulkanImageView()).sampler(textureSampler.GetVkSampler());
if(imageView.IsDepthImage()){
imageInfo.imageLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
} else{
imageInfo.imageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
}
var DescriptorBuffer = VkWriteDescriptorSet.calloc(1,MemStack);
DescriptorBuffer.get(0)
.sType$Default()
.dstSet(VkDescriptorSet)
.dstBinding(BaseBinding)
.dstArrayElement(0)
.descriptorType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
.descriptorCount(ImageCount)
.pImageInfo(imageInfos);
vkUpdateDescriptorSets(device.FetchVulkanDevice(),DescriptorBuffer,null);
}
}
public long GetVkDescriptorSet(){return VkDescriptorSet;}
}

View file

@ -0,0 +1,53 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkDescriptorSetLayoutBinding;
import org.lwjgl.vulkan.VkDescriptorSetLayoutCreateInfo;
import org.tinylog.Logger;
import java.nio.LongBuffer;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK10.vkCreateDescriptorSetLayout;
import static org.lwjgl.vulkan.VK10.vkDestroyDescriptorSetLayout;
public class DescriptorSetLayout {
private final LayoutInformation[] LayoutInfos;
protected long VkDescriptorLayout;
public DescriptorSetLayout(VulkanContext VkCtx, LayoutInformation LayoutInfo){
this(VkCtx, new DescriptorSetLayout.LayoutInformation[]{LayoutInfo});
}
public DescriptorSetLayout(VulkanContext VkCtx, LayoutInformation[] LayoutInfos){
this.LayoutInfos = LayoutInfos;
try(var MemStack = MemoryStack.stackPush()){
int LayoutCount = LayoutInfos.length;
var LayoutBindings = VkDescriptorSetLayoutBinding.calloc(LayoutCount,MemStack);
for(int i = 0; i < LayoutCount; i++){
LayoutInformation LayoutInfo = LayoutInfos[i];
LayoutBindings.get(i)
.binding(LayoutInfo.Binding())
.descriptorType(LayoutInfo.DescriptorType())
.descriptorCount(LayoutInfo.DescriptorCount())
.stageFlags(LayoutInfo.Stage());
}
var VkLayoutInfo = VkDescriptorSetLayoutCreateInfo.calloc(MemStack)
.sType$Default()
.pBindings(LayoutBindings);
LongBuffer SetLayoutPointer = MemStack.mallocLong(1);
vkCheck(vkCreateDescriptorSetLayout(VkCtx.GetDevice().FetchVulkanDevice(), VkLayoutInfo,null,SetLayoutPointer),
"Failed to create Descriptor Set Layout");
VkDescriptorLayout = SetLayoutPointer.get(0);
}
}
public LayoutInformation GetLayoutInfo(){return GetLayoutInfos()[0];}
public LayoutInformation[] GetLayoutInfos(){return LayoutInfos;}
public long GetVkDescriptorLayout(){return VkDescriptorLayout;}
public void CleanUp(VulkanContext VkCtx){
Logger.debug("Destroying Descriptor Set Layout");
vkDestroyDescriptorSetLayout(VkCtx.GetDevice().FetchVulkanDevice(),VkDescriptorLayout,null);
}
public record LayoutInformation(int DescriptorType, int Binding, int DescriptorCount, int Stage){}
}

View file

@ -0,0 +1,49 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkSamplerCreateInfo;
import java.nio.LongBuffer;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK10.*;
public class TextureSampler {
private static final int MAX_ANISOTROPY = 16;
private final long VkSampler;
public TextureSampler(VulkanContext VkCtx, TextureSamplerInfo textureSamplerInfo){
try(var MemStack = MemoryStack.stackPush()){
var SamplerInfo = VkSamplerCreateInfo.calloc(MemStack)
.sType$Default()
.magFilter(VK_FILTER_NEAREST)
.minFilter(VK_FILTER_NEAREST)
.addressModeU(textureSamplerInfo.AddressMode())
.addressModeV(textureSamplerInfo.AddressMode())
.addressModeW(textureSamplerInfo.AddressMode())
.borderColor(textureSamplerInfo.BorderColour())
.unnormalizedCoordinates(false)
.compareEnable(false)
.compareOp(VK_COMPARE_OP_NEVER)
.mipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST)
.minLod(0.0f)
.maxLod(textureSamplerInfo.MipLevels())
.mipLodBias(0.0f);
if(textureSamplerInfo.Anisotrophy() && VkCtx.GetDevice().SamplesAnisotropy()){
SamplerInfo
.anisotropyEnable(true)
.maxAnisotropy(MAX_ANISOTROPY);
}
LongBuffer LongPointer = MemStack.mallocLong(1);
vkCheck(vkCreateSampler(VkCtx.GetDevice().FetchVulkanDevice(), SamplerInfo,null,LongPointer)
,"Failed to create sampler");
VkSampler = LongPointer.get(0);
}
}
public long GetVkSampler(){return VkSampler;}
public void CleanUp(VulkanContext VkCtx){
vkDestroySampler(VkCtx.GetDevice().FetchVulkanDevice(), VkSampler,null);
}
}

View file

@ -0,0 +1,4 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
public record TextureSamplerInfo(int AddressMode, int BorderColour, int MipLevels,boolean Anisotropy) {
}

View file

@ -0,0 +1,94 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.TextureCache;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.IndexedLinkedHashMap;
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 org.tinylog.Logger;
import org.w3c.dom.Text;
import java.nio.ByteBuffer;
import java.util.List;
import static org.lwjgl.vulkan.VK10.*;
public class MaterialsCache {
private static final int MATERIAL_SIZE = VulkanUtils.VEC4_SIZE + VulkanUtils.INT_SIZE * 4;
private final IndexedLinkedHashMap<String, VulkanMaterial> MaterialsMap;
private VulkanBuffer MaterialsBuffer;
public MaterialsCache(){
MaterialsMap = new IndexedLinkedHashMap<>();
}
//create staging buffer and GPU only accessibly buffer, add any located textures
public void LoadMaterials(VulkanContext VkCtx, List<MaterialData> Materials, TextureCache textureCache, CommandPool commandPool, Queue queue){
int MaterialCount = Materials.size();
int BufferSize = MATERIAL_SIZE * MaterialCount;
var SrcBuffer = new VulkanBuffer(VkCtx, BufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
MaterialsBuffer = new VulkanBuffer(VkCtx, BufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
var CmdBuffer = new CommandBuffer(VkCtx, commandPool, true, true);
CmdBuffer.BeginRecording();
TransferBuffer transferBuffer = new TransferBuffer(SrcBuffer,MaterialsBuffer);
long MappedMemory = SrcBuffer.MapMemory(VkCtx);
ByteBuffer data = MemoryUtil.memByteBuffer(MappedMemory, (int)SrcBuffer.GetRequestedSize());
int Offset = 0;
for(int i = 0; i < MaterialCount; i++){
var Material = Materials.get(i);
String TexturePath = Material.TexturePath();
boolean ValidTexture = TexturePath != null && !TexturePath.isEmpty();
if(ValidTexture){
textureCache.AddTexture(VkCtx, TexturePath, TexturePath, VK_FORMAT_R8G8B8A8_SRGB);
}
VulkanMaterial newMaterial = new VulkanMaterial(Material.ID());
MaterialsMap.put(newMaterial.ID(), newMaterial);
Material.DiffuseColour().get(Offset, data);
data.putInt(Offset + VulkanUtils.VEC4_SIZE, ValidTexture ? 1 : 0);
data.putInt(Offset + VulkanUtils.VEC4_SIZE + VulkanUtils.INT_SIZE, textureCache.GetPosition(TexturePath));
//pad data because the minimum size of data in the shader layout is a multiple of Vec4,
// compensate with 2 more bytes as we only need 6 currently
data.putInt(Offset + VulkanUtils.VEC4_SIZE + VulkanUtils.INT_SIZE * 2,0);
data.putInt(Offset + VulkanUtils.VEC4_SIZE + VulkanUtils.INT_SIZE * 3,0);
Offset += MATERIAL_SIZE;
}
SrcBuffer.UnMapMemory(VkCtx);
transferBuffer.RecordTransferCommand(CmdBuffer);
CmdBuffer.EndRecording();
CmdBuffer.SubmitAndWait(VkCtx,queue);
CmdBuffer.cleanup(VkCtx,commandPool);
transferBuffer.SrcBuffer().cleanup(VkCtx);
}
private void CleanUp(VulkanContext VkCtx){
if(MaterialsBuffer != null){
MaterialsBuffer.cleanup(VkCtx);
}
}
public VulkanMaterial GetMaterial(String ID){return MaterialsMap.get(ID);}
public VulkanBuffer GetMaterialsBuffer(){return MaterialsBuffer;}
public int GetPosition(String ID){
int result = -1;
if(ID != null){
result = MaterialsMap.GetIndexOf(ID);
} else{
Logger.warn("Missing Material [{}]",ID);
}
return result;
}
}

View file

@ -9,6 +9,10 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils; import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,41 +29,45 @@ public class ModelsCache {
} }
public void loadModels(VulkanContext VkCtx, List<ModelData> Models, CommandPool commandPool, Queue queue){ public void loadModels(VulkanContext VkCtx, List<ModelData> Models, CommandPool commandPool, Queue queue){
try {
List<VulkanBuffer> StagingBufferList = new ArrayList<>(); List<VulkanBuffer> StagingBufferList = new ArrayList<>();
var Command = new CommandBuffer(VkCtx, commandPool, true, true); var Command = new CommandBuffer(VkCtx, commandPool, true, true);
Command.BeginRecording(); Command.BeginRecording();
for(ModelData modelData : Models){ for (ModelData modelData : Models) {
VulkanModel VKModel = new VulkanModel(modelData.ID()); VulkanModel VKModel = new VulkanModel(modelData.ID());
ModelsMap.put(VKModel.GetID(), VKModel); ModelsMap.put(VKModel.GetID(), VKModel);
for(MeshData meshData : modelData.Meshes()){
TransferBuffer VerticesBuffers = CreateVerticesBuffer(VkCtx,meshData); DataInputStream VertexInput = new DataInputStream(new BufferedInputStream(
TransferBuffer IndicesBuffers = CreateIndicesBuffer(VkCtx,meshData); new FileInputStream(modelData.vertexPath())));
DataInputStream IndicesInput = new DataInputStream(new BufferedInputStream(
new FileInputStream(modelData.indexPath())));
for (MeshData meshData : modelData.Meshes()) {
TransferBuffer VerticesBuffers = CreateVerticesBuffer(VkCtx, meshData,VertexInput);
TransferBuffer IndicesBuffers = CreateIndicesBuffer(VkCtx, meshData,IndicesInput);
StagingBufferList.add(VerticesBuffers.SrcBuffer()); StagingBufferList.add(VerticesBuffers.SrcBuffer());
StagingBufferList.add(IndicesBuffers.SrcBuffer()); StagingBufferList.add(IndicesBuffers.SrcBuffer());
VerticesBuffers.RecordTransferCommand(Command); VerticesBuffers.RecordTransferCommand(Command);
IndicesBuffers.RecordTransferCommand(Command); IndicesBuffers.RecordTransferCommand(Command);
VulkanMesh VkMesh = new VulkanMesh(meshData.ID(), VerticesBuffers.DstBuffer(),IndicesBuffers.DstBuffer(), VulkanMesh VkMesh = new VulkanMesh(meshData.ID(), VerticesBuffers.DstBuffer(), IndicesBuffers.DstBuffer(),
meshData.Indices().length); meshData.IndexSize() / VulkanUtils.INT_SIZE, meshData.MaterialID());
VKModel.GetVkMeshList().add(VkMesh); VKModel.GetVkMeshList().add(VkMesh);
} }
} }
Command.EndRecording(); Command.EndRecording();
Command.SubmitAndWait(VkCtx,queue); Command.SubmitAndWait(VkCtx,queue);
Command.cleanup(VkCtx,commandPool); Command.cleanup(VkCtx,commandPool);
StagingBufferList.forEach(b -> b.cleanup(VkCtx)); StagingBufferList.forEach(b -> b.cleanup(VkCtx));
} catch (Exception exception){
throw new RuntimeException(exception);
}
} }
private static TransferBuffer CreateVerticesBuffer(VulkanContext VkCtx, MeshData meshData){ private static TransferBuffer CreateVerticesBuffer(VulkanContext VkCtx, MeshData meshData, DataInputStream VertexStream) throws IOException {
float[] Positions = meshData.Positions();
float[] TextureCoords = meshData.textureCoords(); int BufferSize = meshData.VertexSize();
if(TextureCoords == null || TextureCoords.length == 0){
TextureCoords = new float[(Positions.length/3) * 2];
}
int ElementCount = Positions.length + TextureCoords.length;
int BufferSize = ElementCount * VulkanUtils.FLOAT_SIZE;
var SrcBuffer = new VulkanBuffer(VkCtx,BufferSize, var SrcBuffer = new VulkanBuffer(VkCtx,BufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
var DstBuffer = new VulkanBuffer(VkCtx, BufferSize, var DstBuffer = new VulkanBuffer(VkCtx, BufferSize,
@ -67,32 +75,30 @@ public class ModelsCache {
long MappedMemory = SrcBuffer.MapMemory(VkCtx); long MappedMemory = SrcBuffer.MapMemory(VkCtx);
FloatBuffer data = MemoryUtil.memFloatBuffer(MappedMemory, (int) SrcBuffer.GetRequestedSize()); FloatBuffer data = MemoryUtil.memFloatBuffer(MappedMemory, (int) SrcBuffer.GetRequestedSize());
int Rows = Positions.length / 3;
for(int Row = 0; Row < Rows; Row++){ int ValuesToRead = meshData.VertexSize()/VulkanUtils.FLOAT_SIZE;
int StartPos = Row * 3; while(ValuesToRead > 0){
int StartTexCoordPos = Row * 2; data.put(VertexStream.readFloat());
data.put(Positions[StartPos]); ValuesToRead--;
data.put(Positions[StartPos+1]);
data.put(Positions[StartPos+2]);
data.put(TextureCoords[StartTexCoordPos]);
data.put(TextureCoords[StartTexCoordPos + 1]);
} }
SrcBuffer.UnMapMemory(VkCtx); SrcBuffer.UnMapMemory(VkCtx);
return new TransferBuffer(SrcBuffer,DstBuffer); return new TransferBuffer(SrcBuffer,DstBuffer);
} }
private static TransferBuffer CreateIndicesBuffer(VulkanContext VkCtx, MeshData meshData){ private static TransferBuffer CreateIndicesBuffer(VulkanContext VkCtx, MeshData meshData, DataInputStream IndexStream) throws IOException{
int[] Indices = meshData.Indices(); int BufferSize = meshData.IndexSize();
int IndexCount = Indices.length;
int BufferSize = IndexCount * VulkanUtils.INT_SIZE;
var SrcBuffer = new VulkanBuffer(VkCtx,BufferSize, var SrcBuffer = new VulkanBuffer(VkCtx,BufferSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
var DstBuffer = new VulkanBuffer(VkCtx, BufferSize, var DstBuffer = new VulkanBuffer(VkCtx, BufferSize,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
long MappedMemory = SrcBuffer.MapMemory(VkCtx); long MappedMemory = SrcBuffer.MapMemory(VkCtx);
IntBuffer data = MemoryUtil.memIntBuffer(MappedMemory,(int) SrcBuffer.GetRequestedSize()); IntBuffer data = MemoryUtil.memIntBuffer(MappedMemory,(int) SrcBuffer.GetRequestedSize());
data.put(Indices);
int ValuesToRead = meshData.IndexSize()/VulkanUtils.INT_SIZE;
while(ValuesToRead > 0){
data.put(IndexStream.readInt());
ValuesToRead--;
}
SrcBuffer.UnMapMemory(VkCtx); SrcBuffer.UnMapMemory(VkCtx);
return new TransferBuffer(SrcBuffer,DstBuffer); return new TransferBuffer(SrcBuffer,DstBuffer);
} }

View file

@ -0,0 +1,4 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
public record VulkanMaterial(String ID) {
}

View file

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

View file

@ -20,6 +20,7 @@ import static org.lwjgl.vulkan.VK13.*;
public class Device { public class Device {
private final VkDevice VulkanDevice; private final VkDevice VulkanDevice;
private final boolean SamplesAnisotropy;
public Device(PhysicalDevice PhysDevice){ public Device(PhysicalDevice PhysDevice){
Logger.debug("Creating Device Interface Layer"); Logger.debug("Creating Device Interface Layer");
@ -41,6 +42,13 @@ public class Device {
.dynamicRendering(true) .dynamicRendering(true)
.synchronization2(true); .synchronization2(true);
var features2 = VkPhysicalDeviceFeatures2.calloc(MemStack).sType$Default(); var features2 = VkPhysicalDeviceFeatures2.calloc(MemStack).sType$Default();
var features = features2.features();
VkPhysicalDeviceFeatures SupportedFeatures = PhysDevice.GetPhysicalDeviceFeatures();
SamplesAnisotropy = SupportedFeatures.samplerAnisotropy();
if(SamplesAnisotropy){
features.samplerAnisotropy(true);
}
features2.pNext(features13.address()); features2.pNext(features13.address());
var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack) var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack)
@ -109,6 +117,8 @@ public class Device {
VulkanContext.VulkanLayersOpen--; VulkanContext.VulkanLayersOpen--;
} }
public boolean SamplesAnisotropy(){return SamplesAnisotropy;}
public VkDevice FetchVulkanDevice() public VkDevice FetchVulkanDevice()
{ {
return VulkanDevice; return VulkanDevice;

View file

@ -16,11 +16,13 @@ public class ImageView {
private final int MipLevels; private final int MipLevels;
private final long VulkanImage; private final long VulkanImage;
private final long VulkanImageView; private final long VulkanImageView;
private final boolean DepthImage;
public ImageView(Device device, long vulkanImage, ImageViewData imageViewData){ public ImageView(Device device, long vulkanImage, ImageViewData imageViewData, boolean DepthImage){
this.AspectMask = imageViewData.AspectMask; this.AspectMask = imageViewData.AspectMask;
this.MipLevels = imageViewData.MipLevels; this.MipLevels = imageViewData.MipLevels;
this.VulkanImage = vulkanImage; this.VulkanImage = vulkanImage;
this.DepthImage = DepthImage;
try(var MemStack = MemoryStack.stackPush()){ try(var MemStack = MemoryStack.stackPush()){
LongBuffer LongPointer = MemStack.mallocLong(1); LongBuffer LongPointer = MemStack.mallocLong(1);
var ViewCreateInfo = VkImageViewCreateInfo.calloc(MemStack) var ViewCreateInfo = VkImageViewCreateInfo.calloc(MemStack)
@ -54,6 +56,7 @@ public class ImageView {
return VulkanImageView; return VulkanImageView;
} }
public long GetVulkanImage(){return VulkanImage;} public long GetVulkanImage(){return VulkanImage;}
public boolean IsDepthImage(){return DepthImage;}
public static class ImageViewData{ public static class ImageViewData{
private int AspectMask; private int AspectMask;

View file

@ -3,19 +3,22 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen;
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig; import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance; import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext; import net.halbear.Terrain4J.EngineCore.Logic.Rendering.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Main.GameCore;
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor; import net.halbear.Terrain4J.EngineCore.Main.Scene.Actor;
import net.halbear.Terrain4J.EngineCore.Main.Scene.Scene; import net.halbear.Terrain4J.EngineCore.Main.Scene.Scene;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.Attachment; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.Attachment;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Images.TextureCache;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Pipeline; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.Pipeline;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineBuildInfo; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineBuildInfo;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PushConstantsRange; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PushConstantsRange;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderCompiler; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.*;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VertexBufferStructure; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VertexBufferStructure;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelsCache; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelsCache;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanMesh; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanMesh;
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanModel; import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanModel;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.CommandBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils; import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
@ -33,6 +36,17 @@ import static org.lwjgl.vulkan.KHRSynchronization2.VK_IMAGE_LAYOUT_ATTACHMENT_OP
import static org.lwjgl.vulkan.VK13.*; import static org.lwjgl.vulkan.VK13.*;
public class SceneRender {//dynamic rendering public class SceneRender {//dynamic rendering
private static final String DESCRIPTOR_ID_MAT = "SCN_DESC_ID_MAT";
private static final String DESCRIPTOR_ID_PRJ = "SCN_DESC_ID_PRJ";
private static final String DESCRIPTOR_ID_TEXT = "SCN_DESC_ID_TEXT";
private static final int PUSH_CONSTANTS_SIZE = VulkanUtils.MATRIX4X4_SIZE + VulkanUtils.INT_SIZE;
private final VulkanBuffer BufferProjectionMatrix;
private final DescriptorSetLayout descriptorLayoutFragStorage;
private final DescriptorSetLayout descriptorLayoutTexture;
private final DescriptorSetLayout descriptorLayoutVertexUniform;
private final TextureSampler textureSampler;
private static final int DEPTH_FORMAT = VK_FORMAT_D16_UNORM; private static final int DEPTH_FORMAT = VK_FORMAT_D16_UNORM;
private final VkClearValue ClearValueDepth; private final VkClearValue ClearValueDepth;
private final ByteBuffer PushConstBuffer; private final ByteBuffer PushConstBuffer;
@ -63,9 +77,27 @@ public class SceneRender {//dynamic rendering
ClearValueColour = VkClearValue.calloc().color(c->c.float32(0,R).float32(1,G).float32(2,B).float32(3,1.0f)); ClearValueColour = VkClearValue.calloc().color(c->c.float32(0,R).float32(1,G).float32(2,B).float32(3,1.0f));
AttachmentInfoColour = CreateColourAttachmentsInfo(vulkanContext,ClearValueColour); AttachmentInfoColour = CreateColourAttachmentsInfo(vulkanContext,ClearValueColour);
RenderInfo = CreateRenderInfo(vulkanContext, AttachmentInfoColour, AttInfoDepth); RenderInfo = CreateRenderInfo(vulkanContext, AttachmentInfoColour, AttInfoDepth);
PushConstBuffer = MemoryUtil.memAlloc(VulkanUtils.MATRIX4X4_SIZE * 2); PushConstBuffer = (MemoryUtil.memAlloc(PUSH_CONSTANTS_SIZE));
descriptorLayoutVertexUniform = new DescriptorSetLayout(vulkanContext, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
0,1,VK_SHADER_STAGE_VERTEX_BIT));
BufferProjectionMatrix = VulkanUtils.CreateHostVisibleBuffer(vulkanContext, VulkanUtils.MATRIX4X4_SIZE,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, DESCRIPTOR_ID_PRJ, descriptorLayoutVertexUniform);
VulkanUtils.CopyMatrixToBuffer(vulkanContext, BufferProjectionMatrix, PrimaryRuntime.GetEngineInstance().scene().GetProjection().GetProjectionMatrix(),0);
descriptorLayoutFragStorage = new DescriptorSetLayout(vulkanContext, new DescriptorSetLayout.LayoutInformation(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
0,1,VK_SHADER_STAGE_FRAGMENT_BIT));
var textureSamplerInfo = new TextureSamplerInfo(VK_SAMPLER_ADDRESS_MODE_REPEAT,
VK_BORDER_COLOR_INT_OPAQUE_BLACK,1,true);
textureSampler = new TextureSampler(vulkanContext,textureSamplerInfo);
descriptorLayoutTexture = new DescriptorSetLayout(vulkanContext, new DescriptorSetLayout.LayoutInformation(
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, TextureCache.MAX_TEXTURES, VK_SHADER_STAGE_FRAGMENT_BIT
));
ShaderModule[] shaderModules = SceneRender.CreateShaderModules(vulkanContext); ShaderModule[] shaderModules = SceneRender.CreateShaderModules(vulkanContext);
VkPipeline = CreatePipeline(vulkanContext, shaderModules); VkPipeline = CreatePipeline(vulkanContext, shaderModules, new DescriptorSetLayout[]{
descriptorLayoutVertexUniform, descriptorLayoutFragStorage, descriptorLayoutFragStorage
});
//Continue Here
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext)); Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
} }

View file

@ -94,7 +94,7 @@ public class SwapChain {
var ReturnResult = new ImageView[ImageCount]; var ReturnResult = new ImageView[ImageCount];
var ImageViewData = new ImageView.ImageViewData().Format(Format).AspectMask(VK_IMAGE_ASPECT_COLOR_BIT); var ImageViewData = new ImageView.ImageViewData().Format(Format).AspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
for(int i = 0; i < ImageCount; i++){ for(int i = 0; i < ImageCount; i++){
ReturnResult[i] = new ImageView(device, SwapChainImages.get(i),ImageViewData); ReturnResult[i] = new ImageView(device, SwapChainImages.get(i),ImageViewData,false);
} }
return ReturnResult; return ReturnResult;
} }

View file

@ -15,6 +15,7 @@ public class VulkanUtils {
public static final int FLOAT_SIZE = 4; public static final int FLOAT_SIZE = 4;
public static final int INT_SIZE = 4; public static final int INT_SIZE = 4;
public static final int MATRIX4X4_SIZE = 16 * FLOAT_SIZE; public static final int MATRIX4X4_SIZE = 16 * FLOAT_SIZE;
public static final int VEC4_SIZE = 4 * FLOAT_SIZE;
public static int MemoryTypeFromProperties(VulkanContext vulkanContext, int TypeBits, int ReqMask){ public static int MemoryTypeFromProperties(VulkanContext vulkanContext, int TypeBits, int ReqMask){
int result = -1; int result = -1;

View file

@ -28,6 +28,7 @@ vkValidated=true
vsync=false vsync=false
#Vsync images #Vsync images
RequestedImages=3 RequestedImages=3
DefaultTexturePath=/EngineResources/Texture/DefaultTexture.png
#This is the name of the GPU you want the engine to use #This is the name of the GPU you want the engine to use
PhysicalDeviceName= PhysicalDeviceName=