Vertex Rendering!
This commit is contained in:
parent
852336e188
commit
2f626ba00f
20 changed files with 450 additions and 25 deletions
|
|
@ -2,7 +2,10 @@ package net.halbear.Terrain4J.EngineCore.Display;
|
|||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelsCache;
|
||||
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.Fence;
|
||||
|
|
@ -17,12 +20,15 @@ import org.lwjgl.vulkan.VkSemaphoreSubmitInfo;
|
|||
import org.tinylog.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.lwjgl.vulkan.VK13.VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
|
||||
import static org.lwjgl.vulkan.VK13.VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
||||
public class Render {
|
||||
|
||||
private final ModelsCache modelsCache;
|
||||
|
||||
private final CommandBuffer[] CommandBuffers;
|
||||
private final CommandPool[] CommandPools;
|
||||
private final Fence[] Fences;
|
||||
|
|
@ -55,6 +61,14 @@ public class Render {
|
|||
RenderCompleteSemaphores[i] = new Semaphore(RendererContext);
|
||||
}
|
||||
sceneRender = new SceneRender(RendererContext);
|
||||
modelsCache = new ModelsCache();
|
||||
}
|
||||
|
||||
public void Initialise(InitData initData){
|
||||
List<ModelData> Models = initData.Models();
|
||||
Logger.debug("Loading {} models", Models.size());
|
||||
modelsCache.loadModels(RendererContext, Models, CommandPools[0], GraphicsQueue);
|
||||
Logger.debug("Loaded {} models", Models.size());
|
||||
}
|
||||
|
||||
private void RecordingStart(CommandPool commandPool, CommandBuffer commandBuffer){
|
||||
|
|
@ -69,7 +83,7 @@ public class Render {
|
|||
public void cleanup() {
|
||||
RendererContext.GetDevice().waitIdle();
|
||||
Logger.debug("Waiting Vulkan Context");
|
||||
sceneRender.cleanup();
|
||||
sceneRender.cleanup(RendererContext);
|
||||
Logger.debug("Dynamic Renderer Cleaned up");
|
||||
Arrays.asList(RenderCompleteSemaphores).forEach(i->i.cleanup(RendererContext));
|
||||
Logger.debug("Render Semaphores cleaned up");
|
||||
|
|
@ -82,6 +96,7 @@ public class Render {
|
|||
CommandPools[i].cleanup(RendererContext);
|
||||
}
|
||||
Logger.debug("Command pools cleaned up");
|
||||
modelsCache.CleanUp(RendererContext);
|
||||
RendererContext.cleanup();
|
||||
}
|
||||
public void render(EngineInstance engineInstance){
|
||||
|
|
@ -94,7 +109,7 @@ public class Render {
|
|||
if (ImageIndex < 0){
|
||||
return;
|
||||
}
|
||||
sceneRender.Render(RendererContext,CommandBuffer,ImageIndex);
|
||||
sceneRender.Render(RendererContext,CommandBuffer, modelsCache,ImageIndex);
|
||||
RecordingStop(CommandBuffer);
|
||||
Submit(CommandBuffer, CurrentFrame, ImageIndex);
|
||||
swapChain.PresentImage(PresentQueue, RenderCompleteSemaphores[ImageIndex],ImageIndex);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ public class EngineConfig {
|
|||
public static int FrameRate_WINDOW =0;
|
||||
public static int RENDERFRAMES =0;
|
||||
public static boolean VSYNC = false;
|
||||
public static boolean ShaderDebug = false;
|
||||
public static boolean RecompileShaders = false;
|
||||
private boolean vkValidated;
|
||||
private String PhysicalDeviceName;
|
||||
private int RequestedImages;
|
||||
|
|
@ -42,7 +44,12 @@ public class EngineConfig {
|
|||
public boolean GetVSYNC(){
|
||||
return VSYNC;
|
||||
}
|
||||
|
||||
public boolean DebugShaders(){
|
||||
return ShaderDebug;
|
||||
}
|
||||
public boolean RecompileShaders(){
|
||||
return RecompileShaders;
|
||||
}
|
||||
private EngineConfig() {
|
||||
var EngineConfigVar = new Properties();
|
||||
Path path = Paths.get("");
|
||||
|
|
@ -95,6 +102,8 @@ public class EngineConfig {
|
|||
VSYNC = Boolean.parseBoolean(EngineConfigVar.getOrDefault("vsync", true).toString());
|
||||
vkValidated = Boolean.parseBoolean(EngineConfigVar.getOrDefault("vkValidated", false).toString());
|
||||
RequestedImages = Integer.parseInt(EngineConfigVar.getOrDefault("RequestedImages", 3).toString());
|
||||
ShaderDebug =Boolean.parseBoolean(EngineConfigVar.getOrDefault("Debug_Shaders", false).toString());
|
||||
RecompileShaders =Boolean.parseBoolean(EngineConfigVar.getOrDefault("ShaderRecompiling", true).toString());
|
||||
Logger.debug("\n\nsuccessfully loaded configuration: \n{}\n\n",EngineConfigVar.toString());
|
||||
}
|
||||
else if(!ConfigFile.exists()){
|
||||
|
|
@ -112,6 +121,8 @@ public class EngineConfig {
|
|||
EngineConfigVar.setProperty("display_height","720");
|
||||
EngineConfigVar.setProperty("vsync","true");
|
||||
EngineConfigVar.setProperty("vkValidated","false");
|
||||
EngineConfigVar.setProperty("Debug_Shaders","false");
|
||||
EngineConfigVar.setProperty("ShaderRecompiling","true");
|
||||
EngineConfigVar.store(new FileWriter(path.toAbsolutePath().toString() + "/" + FILENAME), "created new properties file");
|
||||
Logger.debug("Wrote New Config File [{}]", ConfigFile.getAbsolutePath());
|
||||
} catch (IOException excp2) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package net.halbear.Terrain4J.EngineCore.Logic;
|
|||
|
||||
public interface GameLogic {
|
||||
void cleanup();
|
||||
void Initialise(EngineInstance engineInstance);
|
||||
InitData Initialise(EngineInstance engineInstance);
|
||||
void Input(EngineInstance engineInstance, long FrameDiffNanoSeconds);
|
||||
void Update(EngineInstance engineInstance, long FrameDiffNanoSeconds);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record InitData(List<ModelData> Models) {
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Logic;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Display.Window;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline.PipelineCache;
|
||||
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;
|
||||
|
|
@ -15,6 +16,7 @@ public class VulkanContext {
|
|||
private Surface surface;
|
||||
private final PhysicalDevice PhysDevice;
|
||||
private SwapChain swapChain;
|
||||
private final PipelineCache VkPipelineCache;
|
||||
|
||||
public VulkanContext(Window window){
|
||||
var EngineGlobals = EngineConfig.getInstance();
|
||||
|
|
@ -24,20 +26,21 @@ public class VulkanContext {
|
|||
surface = new Surface(Instance, PhysDevice, window);
|
||||
swapChain = new SwapChain(window, device, surface, EngineGlobals.GetRequestedImages(), EngineGlobals.GetVSYNC());
|
||||
VulkanLayersOpen+=5;
|
||||
VkPipelineCache = new PipelineCache(device);
|
||||
}
|
||||
|
||||
public void cleanup(){
|
||||
swapChain.cleanup(device);
|
||||
surface.cleanup(Instance);
|
||||
VkPipelineCache.CleanUp(device);
|
||||
device.cleanup();
|
||||
PhysDevice.cleanup();
|
||||
Instance.cleanup();
|
||||
Logger.debug("Render Thread Finished ending Vulkan Processes\nVulkan Layers Open:[{}]", VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen);
|
||||
VulkanLayersOpen--;
|
||||
}
|
||||
public SwapChain GetSwapChain(){
|
||||
return swapChain;
|
||||
}
|
||||
public PipelineCache GetVkPipelineCache(){return VkPipelineCache;}
|
||||
public SwapChain GetSwapChain(){return swapChain;}
|
||||
public Device GetDevice(){
|
||||
return device;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@ package net.halbear.Terrain4J.EngineCore.Main;
|
|||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.MeshData;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.VkModel.ModelData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GameCore implements GameLogic {
|
||||
@Override
|
||||
|
|
@ -10,8 +16,19 @@ public class GameCore implements GameLogic {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void Initialise(EngineInstance engineInstance) {
|
||||
|
||||
public InitData Initialise(EngineInstance engineInstance) {
|
||||
var ModelID = "TriangleModel";
|
||||
MeshData meshData = new MeshData("triangle-mesh", new float[]{
|
||||
-0.5f, -0.5f, 0.0f,
|
||||
0.0f, 0.5f, 0.0f,
|
||||
0.5f, -0.5f, 0.0f},
|
||||
new int[]{0, 1, 2});
|
||||
List<MeshData> MeshDataList = new ArrayList<>();
|
||||
MeshDataList.add(meshData);
|
||||
ModelData modelData = new ModelData(ModelID, MeshDataList);
|
||||
List<ModelData> models = new ArrayList<>();
|
||||
models.add(modelData);
|
||||
return new InitData(models);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Main;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Display.Window;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.*;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.MainThread;
|
||||
import net.halbear.Terrain4J.EngineCore.Threads.RenderThread;
|
||||
import org.tinylog.Logger;
|
||||
|
|
@ -24,9 +21,10 @@ public class PrimaryRuntime {
|
|||
|
||||
public PrimaryRuntime(String windowTitle, GameLogic appLogic) {
|
||||
window = new Window(windowTitle);
|
||||
InitData initData = appLogic.Initialise(engineInstance);
|
||||
engineInstance = new EngineInstance(window, new Scene(window));
|
||||
PrimaryThread = new MainThread(engineInstance, appLogic);
|
||||
DrawingThread = new RenderThread(window, engineInstance);
|
||||
DrawingThread = new RenderThread(window, engineInstance, initData);
|
||||
Thread.currentThread().setName("Terrain4J Primary Runtime Thread");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import net.halbear.Terrain4J.EngineCore.Display.Window;
|
|||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.GameLogic;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.Scene;
|
||||
import org.tinylog.Logger;
|
||||
|
|
@ -34,7 +35,6 @@ public class MainThread implements Runnable {
|
|||
}
|
||||
public MainThread(EngineInstance engineInstance, GameLogic appLogic){
|
||||
this.gameLogic = appLogic;
|
||||
gameLogic.Initialise(engineInstance);
|
||||
Logger.debug("Starting Main Thread");
|
||||
UpdateTickRateThreshold();
|
||||
mainThread = new Thread(this);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import net.halbear.Terrain4J.EngineCore.Display.Render;
|
|||
import net.halbear.Terrain4J.EngineCore.Display.Window;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineInstance;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.InitData;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
import net.halbear.Terrain4J.EngineCore.Main.PrimaryRuntime;
|
||||
import org.tinylog.Logger;
|
||||
|
|
@ -15,9 +16,10 @@ public class RenderThread implements Runnable {
|
|||
private final Render render;
|
||||
private Window window;
|
||||
|
||||
public RenderThread(Window window,EngineInstance engineInstance) {
|
||||
public RenderThread(Window window, EngineInstance engineInstance, InitData initData) {
|
||||
//this.window = window;
|
||||
render = new Render(engineInstance);
|
||||
render.Initialise(initData);
|
||||
renderThread = new Thread(this);
|
||||
renderThread.setName("Terrain4J Vulkan Render Thread");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
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;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.vulkan.*;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
import static org.lwjgl.vulkan.VK10.*;
|
||||
import static org.lwjgl.vulkan.VK13.VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
|
||||
public class Pipeline {
|
||||
private final long VulkanPipeline;
|
||||
private final long VulkanPipelineLayout;
|
||||
|
||||
public Pipeline(VulkanContext VkCtx, PipelineBuildInfo BuildInfo){
|
||||
Logger.debug("Creating Pipeline");
|
||||
Device device = VkCtx.GetDevice();
|
||||
try(var MemStack = MemoryStack.stackPush()){
|
||||
LongBuffer longPtr = MemStack.mallocLong(1);
|
||||
ByteBuffer main = MemStack.UTF8("main");
|
||||
ShaderModule[] ShaderModules = BuildInfo.GetShaderModules();
|
||||
int ModuleCount = ShaderModules.length;
|
||||
var ShaderStages = VkPipelineShaderStageCreateInfo.calloc(ModuleCount, MemStack);
|
||||
for(int i = 0; i < ModuleCount; i++){
|
||||
ShaderModule shaderModule = ShaderModules[i];
|
||||
ShaderStages.get(i)
|
||||
.sType$Default()
|
||||
.stage(shaderModule.GetShaderStage())
|
||||
.module(shaderModule.GetHandle())
|
||||
.pName(main);
|
||||
}
|
||||
|
||||
var AssemblyStateCreateInfo = VkPipelineInputAssemblyStateCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
|
||||
var ViewportCreateStateInfo = VkPipelineViewportStateCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.viewportCount(1)
|
||||
.scissorCount(1);
|
||||
var RasterizationStateCreateInfo = VkPipelineRasterizationStateCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.polygonMode(VK_POLYGON_MODE_FILL)
|
||||
.cullMode(VK_CULL_MODE_NONE)
|
||||
.frontFace(VK_FRONT_FACE_CLOCKWISE)
|
||||
.lineWidth(1.0f);
|
||||
var MultisampleStateCreateInfo = VkPipelineMultisampleStateCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.rasterizationSamples(VK_SAMPLE_COUNT_1_BIT);
|
||||
VkPipelineDynamicStateCreateInfo VulkanPipelineDynamicStateCreateInfo = VkPipelineDynamicStateCreateInfo.calloc(MemStack)
|
||||
.sType(VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO)
|
||||
.pDynamicStates(MemStack.ints(
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR
|
||||
));
|
||||
var BlendAttributeState = VkPipelineColorBlendAttachmentState.calloc(1,MemStack)
|
||||
.colorWriteMask(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)
|
||||
.blendEnable(false);
|
||||
var ColourBlendState = VkPipelineColorBlendStateCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.pAttachments(BlendAttributeState);
|
||||
IntBuffer ColourFormats = MemStack.mallocInt(1);
|
||||
ColourFormats.put(0,BuildInfo.GetColourFormat());
|
||||
var RendererCreateInfo = VkPipelineRenderingCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.colorAttachmentCount(1)
|
||||
.pColorAttachmentFormats(ColourFormats);
|
||||
var PipelineLayoutCreateInfoPtr = VkPipelineLayoutCreateInfo.calloc(MemStack)
|
||||
.sType$Default();
|
||||
VulkanUtils.vkCheck(vkCreatePipelineLayout(device.FetchVulkanDevice(), PipelineLayoutCreateInfoPtr,null,longPtr)
|
||||
,"Unable to create new pipeline layout");
|
||||
VulkanPipelineLayout = longPtr.get(0);
|
||||
|
||||
var PipelineCreateInfo = VkGraphicsPipelineCreateInfo.calloc(1,MemStack)
|
||||
.sType$Default()
|
||||
.renderPass(VK_NULL_HANDLE)
|
||||
.pStages(ShaderStages)
|
||||
.pVertexInputState(BuildInfo.GetVertexInputStateCreateInfo())
|
||||
.pInputAssemblyState(AssemblyStateCreateInfo)
|
||||
.pViewportState(ViewportCreateStateInfo)
|
||||
.pRasterizationState(RasterizationStateCreateInfo)
|
||||
.pColorBlendState(ColourBlendState)
|
||||
.pMultisampleState(MultisampleStateCreateInfo)
|
||||
.pDynamicState(VulkanPipelineDynamicStateCreateInfo)
|
||||
.layout(VulkanPipelineLayout)
|
||||
.pNext(RendererCreateInfo);
|
||||
VulkanUtils.vkCheck(vkCreateGraphicsPipelines(device.FetchVulkanDevice(),
|
||||
VkCtx.GetVkPipelineCache().GetVkPipelineCache(), PipelineCreateInfo,
|
||||
null, longPtr),"Could not create new pipeline");
|
||||
VulkanPipeline = longPtr.get(0);
|
||||
}
|
||||
}
|
||||
public long GetVulkanPipeline(){return VulkanPipeline;}
|
||||
public long GetVulkanPipelineLayout(){return VulkanPipelineLayout;}
|
||||
public void CleanUp(VulkanContext VkCtx){
|
||||
Logger.debug("destroying Pipeline");
|
||||
VkDevice vkDevice = VkCtx.GetDevice().FetchVulkanDevice();
|
||||
vkDestroyPipelineLayout(vkDevice,VulkanPipelineLayout,null);
|
||||
vkDestroyPipeline(vkDevice,VulkanPipeline,null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader.ShaderModule;
|
||||
import org.lwjgl.vulkan.VkPipelineVertexInputStateCreateInfo;
|
||||
|
||||
public class PipelineBuildInfo {
|
||||
private final int ColourFormat;
|
||||
private final ShaderModule[] ShaderModules;
|
||||
private final VkPipelineVertexInputStateCreateInfo VertexInput;
|
||||
public PipelineBuildInfo(ShaderModule[] shaderModules, VkPipelineVertexInputStateCreateInfo VertexInput, int ColourFormat){
|
||||
this.ColourFormat = ColourFormat;
|
||||
this.ShaderModules = shaderModules;
|
||||
this.VertexInput = VertexInput;
|
||||
}
|
||||
public int GetColourFormat(){return ColourFormat;}
|
||||
public ShaderModule[] GetShaderModules(){return ShaderModules;}
|
||||
public VkPipelineVertexInputStateCreateInfo GetVertexInputStateCreateInfo(){return VertexInput;}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Pipeline;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Device;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.vulkan.VkPipelineCacheCreateInfo;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
import static org.lwjgl.vulkan.VK13.vkCreatePipelineCache;
|
||||
import static org.lwjgl.vulkan.VK13.vkDestroyPipelineCache;
|
||||
|
||||
public class PipelineCache {
|
||||
private final long VulkanPipelineCache;
|
||||
public PipelineCache(Device device){
|
||||
Logger.debug("Creating new Vk Pipeline Cache");
|
||||
try(var MemStack = MemoryStack.stackPush()){
|
||||
var PipelineCacheCreateInfo = VkPipelineCacheCreateInfo.calloc(MemStack).sType$Default();
|
||||
LongBuffer longPtr = MemStack.mallocLong(1);
|
||||
VulkanUtils.vkCheck(vkCreatePipelineCache(device.FetchVulkanDevice(), PipelineCacheCreateInfo
|
||||
,null, longPtr),"Error Creating New Pipeline Cache");
|
||||
VulkanPipelineCache = longPtr.get(0);
|
||||
}
|
||||
}
|
||||
public void CleanUp(Device device){
|
||||
Logger.debug("Destroying Vulkan Pipeline Cache");
|
||||
vkDestroyPipelineCache(device.FetchVulkanDevice(), VulkanPipelineCache, null);
|
||||
}
|
||||
public long GetVkPipelineCache(){return VulkanPipelineCache;}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import org.lwjgl.util.shaderc.Shaderc;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class ShaderCompiler {
|
||||
private ShaderCompiler(){}
|
||||
|
||||
public static byte[] CompileShader(String ShaderCode, int ShaderType, boolean HLSLshader){
|
||||
long Compiler = 0;
|
||||
long Options = 0;
|
||||
byte[] CompiledShader;
|
||||
try{
|
||||
Compiler = Shaderc.shaderc_compiler_initialize();
|
||||
Options = Shaderc.shaderc_compile_options_initialize();
|
||||
if(EngineConfig.getInstance().DebugShaders()){
|
||||
Shaderc.shaderc_compile_options_set_generate_debug_info(Options);
|
||||
Shaderc.shaderc_compile_options_set_optimization_level(Options,0);
|
||||
}
|
||||
Shaderc.shaderc_compile_options_set_source_language(Options, HLSLshader ? Shaderc.shaderc_source_language_hlsl : Shaderc.shaderc_source_language_glsl);
|
||||
long CompilationResult = Shaderc.shaderc_compile_into_spv(
|
||||
Compiler,
|
||||
ShaderCode,
|
||||
ShaderType,
|
||||
HLSLshader ? "shader.hlsl" : "shader.glsl",
|
||||
"main",
|
||||
Options
|
||||
);
|
||||
if(Shaderc.shaderc_result_get_compilation_status(CompilationResult) !=
|
||||
Shaderc.shaderc_compilation_status_success){
|
||||
throw new RuntimeException("Failed to Compile Shader: " + Shaderc.shaderc_result_get_error_message(CompilationResult));
|
||||
}
|
||||
ByteBuffer buffer = Shaderc.shaderc_result_get_bytes(CompilationResult);
|
||||
assert buffer != null;
|
||||
CompiledShader = new byte[buffer.remaining()];
|
||||
buffer.get(CompiledShader);
|
||||
} finally{
|
||||
Shaderc.shaderc_compile_options_release(Options);
|
||||
Shaderc.shaderc_compiler_release(Compiler);
|
||||
}
|
||||
return CompiledShader;
|
||||
}
|
||||
|
||||
public static void CompileGLSLShaderOnChange(String ShaderFile, int ShaderType){
|
||||
byte[] CompiledShader;
|
||||
try{
|
||||
var glslFile = new File(ShaderFile);
|
||||
var spvFile = new File(ShaderFile + ".spv");
|
||||
if(!spvFile.exists() || glslFile.lastModified() > spvFile.lastModified()){
|
||||
Logger.debug("Compiling new [{}] shader from [{}] source",spvFile.getPath(),glslFile.getPath());
|
||||
var ShaderCode = new String(Files.readAllBytes(glslFile.toPath()));
|
||||
CompiledShader = CompileShader(ShaderCode, ShaderType, false);
|
||||
Files.write(spvFile.toPath(), CompiledShader);
|
||||
} else{
|
||||
Logger.debug("Loading Compiled Shader [{}]",spvFile.getPath());
|
||||
}
|
||||
} catch(IOException exception){
|
||||
Logger.error(exception);
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package net.halbear.Terrain4J.EngineCore.Vulkan.Rendering.Shader;
|
||||
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.vulkan.VkShaderModuleCreateInfo;
|
||||
import static org.lwjgl.vulkan.VK13.vkCreateShaderModule;
|
||||
import static org.lwjgl.vulkan.VK13.vkDestroyShaderModule;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.file.Files;
|
||||
|
||||
|
||||
public class ShaderModule {
|
||||
private final long Handle;
|
||||
private final int ShaderStage;
|
||||
|
||||
public ShaderModule(VulkanContext VkCtx, int ShaderStage, String ShaderSPVFile){
|
||||
try{
|
||||
byte[] Contents = Files.readAllBytes(new File(ShaderSPVFile).toPath());
|
||||
Handle = CreateShaderModule(VkCtx, Contents);
|
||||
this.ShaderStage = ShaderStage;
|
||||
} catch(IOException exception){
|
||||
Logger.error("Cannot Read Shader Files",exception);
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static long CreateShaderModule(VulkanContext VkCtx, byte[] Code){
|
||||
try(var MemStack = MemoryStack.stackPush()){
|
||||
ByteBuffer CodePointer = MemStack.malloc(Code.length).put(0,Code);
|
||||
var ShaderModuleCreateInfo = VkShaderModuleCreateInfo.calloc(MemStack)
|
||||
.sType$Default()
|
||||
.pCode(CodePointer);
|
||||
LongBuffer LongPoiner = MemStack.mallocLong(1);
|
||||
VulkanUtils.vkCheck(vkCreateShaderModule(VkCtx.GetDevice().FetchVulkanDevice(), ShaderModuleCreateInfo, null, LongPoiner),"Failed to create a new Shader Module");
|
||||
return LongPoiner.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanUp(VulkanContext VkCtx){
|
||||
vkDestroyShaderModule(VkCtx.GetDevice().FetchVulkanDevice(), Handle, null);
|
||||
}
|
||||
|
||||
public long GetHandle(){return Handle;}
|
||||
public int GetShaderStage(){return ShaderStage;}
|
||||
}
|
||||
|
|
@ -3,12 +3,23 @@ package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen;
|
|||
import net.halbear.Terrain4J.EngineCore.Display.Render;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.EngineConfig;
|
||||
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
|
||||
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.PipelineCache;
|
||||
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.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.VulkanUtils;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.util.shaderc.Shaderc;
|
||||
import org.lwjgl.vulkan.*;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import java.nio.LongBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.lwjgl.vulkan.KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
|
@ -25,12 +36,40 @@ public class SceneRender { //dynamic rendering;
|
|||
private boolean Rb = false;
|
||||
private boolean Gb = true;
|
||||
private boolean Bb = false;
|
||||
|
||||
private static final String FRAGMENT_SHADER_FILE_GLSL = "resources/shaders/scene_fragment.glsl";
|
||||
private static final String FRAGMENT_SHADER_FILE_SPV = FRAGMENT_SHADER_FILE_GLSL + ".spv";
|
||||
private static final String VERTEX_SHADER_FILE_GLSL = "resources/shaders/scene_vertex.glsl";
|
||||
private static final String VERTEX_SHADER_FILE_SPV = VERTEX_SHADER_FILE_GLSL + ".spv";
|
||||
private final Pipeline VkPipeline;
|
||||
|
||||
public SceneRender(VulkanContext vulkanContext){
|
||||
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);
|
||||
}
|
||||
|
||||
ShaderModule[] shaderModules = SceneRender.CreateShaderModules(vulkanContext);
|
||||
VkPipeline = CreatePipeline(vulkanContext, shaderModules);
|
||||
Arrays.asList(shaderModules).forEach(shaderModule -> shaderModule.CleanUp(vulkanContext));
|
||||
}
|
||||
private static ShaderModule[] CreateShaderModules(VulkanContext VkCtx){
|
||||
if(EngineConfig.getInstance().RecompileShaders()){
|
||||
ShaderCompiler.CompileGLSLShaderOnChange(VERTEX_SHADER_FILE_GLSL, Shaderc.shaderc_glsl_vertex_shader);
|
||||
ShaderCompiler.CompileGLSLShaderOnChange(FRAGMENT_SHADER_FILE_GLSL, Shaderc.shaderc_fragment_shader);
|
||||
}
|
||||
return new ShaderModule[]{
|
||||
new ShaderModule(VkCtx, VK_SHADER_STAGE_VERTEX_BIT, VERTEX_SHADER_FILE_SPV),
|
||||
new ShaderModule(VkCtx, VK_SHADER_STAGE_FRAGMENT_BIT, FRAGMENT_SHADER_FILE_SPV)
|
||||
};
|
||||
}
|
||||
private static Pipeline CreatePipeline(VulkanContext VkCtx, ShaderModule[] ShaderModules){
|
||||
var vertexBufferStructure = new VertexBufferStructure();
|
||||
var BuildInfo = new PipelineBuildInfo(ShaderModules,vertexBufferStructure.getVertexInput(),
|
||||
VkCtx.GetSurface().GetSurfaceFormat().ImageFormat());
|
||||
var pipeline = new Pipeline(VkCtx, BuildInfo);
|
||||
vertexBufferStructure.cleanup();
|
||||
return pipeline;
|
||||
}
|
||||
public void UpdateColours(VulkanContext vulkanContext){
|
||||
if (Gb){
|
||||
if (G < 1.0f && Math.random() <0.5) G+=0.0005f;
|
||||
|
|
@ -58,7 +97,7 @@ public class SceneRender { //dynamic rendering;
|
|||
RenderInfo = CreateRenderInfo(vulkanContext, AttachmentInfoColour);
|
||||
}
|
||||
|
||||
public void Render(VulkanContext vulkanContext, CommandBuffer commandBuffer, int ImageIndex){
|
||||
public void Render(VulkanContext vulkanContext, CommandBuffer commandBuffer,ModelsCache modelsCache, int ImageIndex){
|
||||
UpdateColours(vulkanContext);
|
||||
try(var MemStack = MemoryStack.stackPush()){
|
||||
SwapChain swapChain = vulkanContext.GetSwapChain();
|
||||
|
|
@ -70,6 +109,35 @@ public class SceneRender { //dynamic rendering;
|
|||
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_ACCESS_2_NONE, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
vkCmdBeginRendering(CommandHandle, RenderInfo[ImageIndex]);
|
||||
vkCmdBindPipeline(CommandHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, VkPipeline.GetVulkanPipeline());
|
||||
|
||||
VkExtent2D swapChainExtent = swapChain.GetSwapChainExtent();
|
||||
int width = swapChainExtent.width();
|
||||
int height = swapChainExtent.height();
|
||||
var Viewport = VkViewport.calloc(1,MemStack)
|
||||
.x(0)
|
||||
.y(height)
|
||||
.height(-height)
|
||||
.width(width)
|
||||
.minDepth(0.0F)
|
||||
.maxDepth(1.0F);
|
||||
vkCmdSetViewport(CommandHandle, 0, Viewport);
|
||||
var Scissor = VkRect2D.calloc(1,MemStack)
|
||||
.extent(it -> it.width(width).height(height))
|
||||
.offset(it->it.x(0).y(0));
|
||||
vkCmdSetScissor(CommandHandle, 0, Scissor);
|
||||
|
||||
LongBuffer offsets = MemStack.mallocLong(1).put(0,0L);
|
||||
LongBuffer vertexBuffer = MemStack.mallocLong(1);
|
||||
var VulkanModels = modelsCache.GetModelMap().values();
|
||||
for(VulkanModel VkModel : VulkanModels){
|
||||
for(VulkanMesh mesh : VkModel.GetVkMeshList()){
|
||||
vertexBuffer.put(0,mesh.VerticesBuffer().GetBuffer());
|
||||
vkCmdBindVertexBuffers(CommandHandle,0,vertexBuffer,offsets);
|
||||
vkCmdBindIndexBuffer(CommandHandle,mesh.IndicesBuffer().GetBuffer(),0,VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(CommandHandle,mesh.IndicesCount(),1,0,0,0);
|
||||
}
|
||||
}
|
||||
vkCmdEndRendering(CommandHandle);
|
||||
|
||||
VulkanUtils.ImageBarrier(MemStack, CommandHandle, SwapChainImage,
|
||||
|
|
@ -113,9 +181,11 @@ public class SceneRender { //dynamic rendering;
|
|||
}
|
||||
return result;
|
||||
}
|
||||
public void cleanup(){
|
||||
public void cleanup(VulkanContext VkCtx){
|
||||
VkPipeline.CleanUp(VkCtx);
|
||||
Arrays.asList(RenderInfo).forEach(VkRenderingInfo::free);
|
||||
Arrays.asList(AttachmentInfoColour).forEach(VkRenderingAttachmentInfo.Buffer::free);
|
||||
ClearValueColour.free();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue