Working on complex models and texture loading
This commit is contained in:
parent
6d6d9f42be
commit
c2aa4ec895
27 changed files with 780 additions and 59 deletions
|
|
@ -1,9 +1,33 @@
|
|||
#version 450
|
||||
|
||||
const int MAX_TEXTURES = 100;
|
||||
|
||||
layout(location = 0) in vec2 inTextCoords;
|
||||
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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,17 @@ layout(location = 0) in vec3 inPos;
|
|||
layout(location = 1) in vec2 intTextCoords;
|
||||
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;
|
||||
} push_constants;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ public class EngineConfig {
|
|||
private String PhysicalDeviceName;
|
||||
private int RequestedImages;
|
||||
private String IconPath = "/WindowResources/Icon/";
|
||||
private String DefaultTexturePath = "/EngineResources/Texture/DefaultTexture.png";
|
||||
private String IconName = "ProgramIcon.png";
|
||||
private float FOV = 60f;
|
||||
private float zFarPlane;
|
||||
|
|
@ -62,7 +63,6 @@ public class EngineConfig {
|
|||
boolean SuccessfulLoad = false;
|
||||
try(InputStream stream = new FileInputStream(path.toAbsolutePath().toString() + "/" + FILENAME)){
|
||||
try {
|
||||
|
||||
EngineConfigVar.load(stream);
|
||||
SuccessfulLoad = true;
|
||||
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()));
|
||||
zNearPlane = (Float.parseFloat(EngineConfigVar.getOrDefault("z_near_plane", 1.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());
|
||||
}
|
||||
else if(!ConfigFile.exists()){
|
||||
|
|
@ -142,6 +143,7 @@ public class EngineConfig {
|
|||
EngineConfigVar.setProperty("field_of_view","60");
|
||||
EngineConfigVar.setProperty("z_near_plane","1");
|
||||
EngineConfigVar.setProperty("z_far_plane","100");
|
||||
EngineConfigVar.setProperty("DefaultTexturePath",DefaultTexturePath);
|
||||
EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file");
|
||||
Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath());
|
||||
} catch (IOException excp2) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic;
|
||||
|
||||
public interface GameLogic {
|
||||
public interface GameLogic {
|
||||
void cleanup();
|
||||
InitData Initialise(EngineInstance engineInstance);
|
||||
void Input(EngineInstance engineInstance, long FrameDiffNanoSeconds);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package net.halbear.Terrain4J.EngineCore.Logic.Rendering;
|
|||
import net.halbear.Terrain4J.EngineCore.Display.Window;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
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.PhysicalDevice;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen.Surface;
|
||||
|
|
@ -18,6 +19,7 @@ public class VulkanContext {
|
|||
private final PhysicalDevice PhysDevice;
|
||||
private SwapChain swapChain;
|
||||
private final PipelineCache VkPipelineCache;
|
||||
private final DescriptorAllocator descriptorAllocator;
|
||||
|
||||
public VulkanContext(Window window){
|
||||
var EngineGlobals = EngineConfig.getInstance();
|
||||
|
|
@ -28,6 +30,7 @@ public class VulkanContext {
|
|||
swapChain = new SwapChain(window, device, surface, EngineGlobals.GetRequestedImages(), EngineGlobals.GetVSYNC());
|
||||
VulkanLayersOpen+=5;
|
||||
VkPipelineCache = new PipelineCache(device);
|
||||
descriptorAllocator = new DescriptorAllocator(PhysDevice, device);
|
||||
}
|
||||
public void Resize(Window window){
|
||||
swapChain.cleanup(device);
|
||||
|
|
@ -37,6 +40,7 @@ public class VulkanContext {
|
|||
swapChain = new SwapChain(window, device, surface, EngCfg.GetRequestedImages(),EngCfg.GetVSYNC());
|
||||
}
|
||||
public void cleanup(){
|
||||
descriptorAllocator.CleanUp(device);
|
||||
swapChain.cleanup(device);
|
||||
surface.cleanup(Instance);
|
||||
VkPipelineCache.CleanUp(device);
|
||||
|
|
@ -57,4 +61,5 @@ public class VulkanContext {
|
|||
public Surface GetSurface(){
|
||||
return surface;
|
||||
}
|
||||
public DescriptorAllocator GetDescriptorAllocator(){return descriptorAllocator;}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class Attachment {
|
|||
DepthAttachment = true;
|
||||
}
|
||||
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;}
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ public class Texture {
|
|||
|
||||
CreateStgBuffer(VkCtx, imageSrc.data());
|
||||
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)
|
||||
.format(ImageFormat);
|
||||
.Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
|
||||
.Format(ImageFormat);
|
||||
image = new Image(VkCtx, ImageData);
|
||||
var ImageViewData = new ImageView.ImageViewData().format(image.GetFormat())
|
||||
.aspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
var ImageViewData = new ImageView.ImageViewData().Format(image.GetFormat())
|
||||
.AspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
imageView = new ImageView(VkCtx.GetDevice(), image.getVulkanImage(), ImageViewData, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
|
||||
|
||||
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.Structure.DeviceLayers.Device;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
|
||||
|
|
@ -99,8 +100,17 @@ public class Pipeline {
|
|||
.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)
|
||||
.sType$Default()
|
||||
.pSetLayouts(ppLayout)
|
||||
.pPushConstantRanges(VkPushConstRangeBuffer);
|
||||
|
||||
VulkanUtils.vkCheck(vkCreatePipelineLayout(device.FetchVulkanDevice(), PipelineLayoutCreateInfoPtr,null,longPtr)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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 org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo;
|
||||
import org.lwjgl.vulkan.VkPushConstantRange;
|
||||
|
|
@ -12,6 +13,7 @@ public class PipelineBuildInfo {
|
|||
private final VkPipelineVertexInputStateCreateInfo VertexInput;
|
||||
private int DepthFormat;
|
||||
private PushConstantsRange[] PushConstRanges;
|
||||
private DescriptorSetLayout[] DescriptorSetLayouts;
|
||||
|
||||
public PipelineBuildInfo(ShaderModule[] shaderModules, VkPipelineVertexInputStateCreateInfo VertexInput, int ColourFormat){
|
||||
this.ColourFormat = ColourFormat;
|
||||
|
|
@ -20,6 +22,13 @@ public class PipelineBuildInfo {
|
|||
DepthFormat = VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
|
||||
public DescriptorSetLayout[] GetDescriptorSetLayouts(){return DescriptorSetLayouts;}
|
||||
|
||||
public PipelineBuildInfo SetDescriptorSetLayouts(DescriptorSetLayout[] descriptorSetLayouts){
|
||||
this.DescriptorSetLayouts = descriptorSetLayouts;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PipelineBuildInfo SetDepthFormat(int DepthFormat){
|
||||
this.DepthFormat = DepthFormat;
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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){}
|
||||
}
|
||||
|
|
@ -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;}
|
||||
}
|
||||
|
|
@ -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){}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
|
||||
|
||||
public record TextureSamplerInfo(int AddressMode, int BorderColour, int MipLevels,boolean Anisotropy) {
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,10 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanBuffer;
|
|||
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
|
||||
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.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -25,41 +29,45 @@ public class ModelsCache {
|
|||
}
|
||||
|
||||
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();
|
||||
try {
|
||||
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);
|
||||
for (ModelData modelData : Models) {
|
||||
VulkanModel VKModel = new VulkanModel(modelData.ID());
|
||||
ModelsMap.put(VKModel.GetID(), VKModel);
|
||||
|
||||
DataInputStream VertexInput = new DataInputStream(new BufferedInputStream(
|
||||
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(IndicesBuffers.SrcBuffer());
|
||||
VerticesBuffers.RecordTransferCommand(Command);
|
||||
IndicesBuffers.RecordTransferCommand(Command);
|
||||
VulkanMesh VkMesh = new VulkanMesh(meshData.ID(), VerticesBuffers.DstBuffer(), IndicesBuffers.DstBuffer(),
|
||||
meshData.IndexSize() / VulkanUtils.INT_SIZE, meshData.MaterialID());
|
||||
VKModel.GetVkMeshList().add(VkMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Command.EndRecording();
|
||||
Command.SubmitAndWait(VkCtx,queue);
|
||||
Command.cleanup(VkCtx,commandPool);
|
||||
|
||||
StagingBufferList.forEach(b -> b.cleanup(VkCtx));
|
||||
} catch (Exception exception){
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static TransferBuffer CreateVerticesBuffer(VulkanContext VkCtx, MeshData meshData){
|
||||
float[] Positions = meshData.Positions();
|
||||
float[] TextureCoords = meshData.textureCoords();
|
||||
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;
|
||||
private static TransferBuffer CreateVerticesBuffer(VulkanContext VkCtx, MeshData meshData, DataInputStream VertexStream) throws IOException {
|
||||
|
||||
int BufferSize = meshData.VertexSize();
|
||||
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,
|
||||
|
|
@ -67,32 +75,30 @@ public class ModelsCache {
|
|||
|
||||
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;
|
||||
int StartTexCoordPos = Row * 2;
|
||||
data.put(Positions[StartPos]);
|
||||
data.put(Positions[StartPos+1]);
|
||||
data.put(Positions[StartPos+2]);
|
||||
data.put(TextureCoords[StartTexCoordPos]);
|
||||
data.put(TextureCoords[StartTexCoordPos + 1]);
|
||||
|
||||
int ValuesToRead = meshData.VertexSize()/VulkanUtils.FLOAT_SIZE;
|
||||
while(ValuesToRead > 0){
|
||||
data.put(VertexStream.readFloat());
|
||||
ValuesToRead--;
|
||||
}
|
||||
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;
|
||||
|
||||
private static TransferBuffer CreateIndicesBuffer(VulkanContext VkCtx, MeshData meshData, DataInputStream IndexStream) throws IOException{
|
||||
int BufferSize = meshData.IndexSize();
|
||||
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);
|
||||
|
||||
int ValuesToRead = meshData.IndexSize()/VulkanUtils.INT_SIZE;
|
||||
while(ValuesToRead > 0){
|
||||
data.put(IndexStream.readInt());
|
||||
ValuesToRead--;
|
||||
}
|
||||
SrcBuffer.UnMapMemory(VkCtx);
|
||||
return new TransferBuffer(SrcBuffer,DstBuffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel;
|
||||
|
||||
public record VulkanMaterial(String ID) {
|
||||
}
|
||||
|
|
@ -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.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){
|
||||
VerticesBuffer.cleanup(VkCtx);
|
||||
IndicesBuffer.cleanup(VkCtx);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import static org.lwjgl.vulkan.VK13.*;
|
|||
|
||||
public class Device {
|
||||
private final VkDevice VulkanDevice;
|
||||
private final boolean SamplesAnisotropy;
|
||||
|
||||
public Device(PhysicalDevice PhysDevice){
|
||||
Logger.debug("Creating Device Interface Layer");
|
||||
|
|
@ -41,6 +42,13 @@ public class Device {
|
|||
.dynamicRendering(true)
|
||||
.synchronization2(true);
|
||||
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());
|
||||
|
||||
var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack)
|
||||
|
|
@ -109,6 +117,8 @@ public class Device {
|
|||
VulkanContext.VulkanLayersOpen--;
|
||||
}
|
||||
|
||||
public boolean SamplesAnisotropy(){return SamplesAnisotropy;}
|
||||
|
||||
public VkDevice FetchVulkanDevice()
|
||||
{
|
||||
return VulkanDevice;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@ public class ImageView {
|
|||
private final int MipLevels;
|
||||
private final long VulkanImage;
|
||||
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.MipLevels = imageViewData.MipLevels;
|
||||
this.VulkanImage = vulkanImage;
|
||||
this.DepthImage = DepthImage;
|
||||
try(var MemStack = MemoryStack.stackPush()){
|
||||
LongBuffer LongPointer = MemStack.mallocLong(1);
|
||||
var ViewCreateInfo = VkImageViewCreateInfo.calloc(MemStack)
|
||||
|
|
@ -54,6 +56,7 @@ public class ImageView {
|
|||
return VulkanImageView;
|
||||
}
|
||||
public long GetVulkanImage(){return VulkanImage;}
|
||||
public boolean IsDepthImage(){return DepthImage;}
|
||||
|
||||
public static class ImageViewData{
|
||||
private int AspectMask;
|
||||
|
|
|
|||
|
|
@ -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.EngineInstance;
|
||||
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.Scene;
|
||||
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.PipelineBuildInfo;
|
||||
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.ShaderModule;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.*;
|
||||
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.VulkanMesh;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.VulkanModel;
|
||||
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 org.joml.Matrix4f;
|
||||
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.*;
|
||||
|
||||
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 final VkClearValue ClearValueDepth;
|
||||
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));
|
||||
AttachmentInfoColour = CreateColourAttachmentsInfo(vulkanContext,ClearValueColour);
|
||||
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);
|
||||
VkPipeline = CreatePipeline(vulkanContext, shaderModules);
|
||||
VkPipeline = CreatePipeline(vulkanContext, shaderModules, new DescriptorSetLayout[]{
|
||||
descriptorLayoutVertexUniform, descriptorLayoutFragStorage, descriptorLayoutFragStorage
|
||||
});
|
||||
//Continue Here
|
||||
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public class SwapChain {
|
|||
var ReturnResult = new ImageView[ImageCount];
|
||||
var ImageViewData = new ImageView.ImageViewData().Format(Format).AspectMask(VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public class VulkanUtils {
|
|||
public static final int FLOAT_SIZE = 4;
|
||||
public static final int INT_SIZE = 4;
|
||||
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){
|
||||
int result = -1;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ vkValidated=true
|
|||
vsync=false
|
||||
#Vsync images
|
||||
RequestedImages=3
|
||||
DefaultTexturePath=/EngineResources/Texture/DefaultTexture.png
|
||||
#This is the name of the GPU you want the engine to use
|
||||
PhysicalDeviceName=
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue