working on colour rendering

This commit is contained in:
Harrison Corlett 2026-01-26 14:56:23 +00:00
parent 2486270c96
commit 4e606e094a
8 changed files with 192 additions and 15 deletions

View file

@ -13,6 +13,7 @@ import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBufferSubmitInfo; import org.lwjgl.vulkan.VkCommandBufferSubmitInfo;
import org.lwjgl.vulkan.VkSemaphoreSubmitInfo; import org.lwjgl.vulkan.VkSemaphoreSubmitInfo;
import org.tinylog.Logger;
import javax.swing.*; import javax.swing.*;
import java.util.Arrays; import java.util.Arrays;
@ -53,7 +54,7 @@ public class Render {
for(int i = 0; i < SwapChainImageCount; i++){ for(int i = 0; i < SwapChainImageCount; i++){
RenderCompleteSemaphores[i] = new Semaphore(RendererContext); RenderCompleteSemaphores[i] = new Semaphore(RendererContext);
} }
sceneRender = new SceneRender(); sceneRender = new SceneRender(RendererContext);
} }
private void RecordingStart(CommandPool commandPool, CommandBuffer commandBuffer){ private void RecordingStart(CommandPool commandPool, CommandBuffer commandBuffer){
@ -66,7 +67,7 @@ public class Render {
} }
public void cleanup() { public void cleanup() {
RendererContext.WaitIdle(); RendererContext.GetDevice().waitIdle();
sceneRender.cleanup(); sceneRender.cleanup();
Arrays.asList(RenderCompleteSemaphores).forEach(i->i.cleanup(RendererContext)); Arrays.asList(RenderCompleteSemaphores).forEach(i->i.cleanup(RendererContext));
Arrays.asList(PresentCompleteSemaphores).forEach(i->i.cleanup(RendererContext)); Arrays.asList(PresentCompleteSemaphores).forEach(i->i.cleanup(RendererContext));
@ -87,7 +88,7 @@ public class Render {
if (ImageIndex < 0){ if (ImageIndex < 0){
return; return;
} }
sceneRender.render(RendererContext,CommandBuffer,ImageIndex); sceneRender.Render(RendererContext,CommandBuffer,ImageIndex);
RecordingStop(CommandBuffer); RecordingStop(CommandBuffer);
Submit(CommandBuffer, CurrentFrame, ImageIndex); Submit(CommandBuffer, CurrentFrame, ImageIndex);
swapChain.PresentImage(PresentQueue, RenderCompleteSemaphores[ImageIndex],ImageIndex); swapChain.PresentImage(PresentQueue, RenderCompleteSemaphores[ImageIndex],ImageIndex);

View file

@ -95,7 +95,9 @@ public class PrimaryRuntime {
if (ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > -1) { if (ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > -1) {
Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]", ThreadsOpen, VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen); Logger.debug("Waiting to close Primary Thread, making sure vulkan has shut down properly first and Engine Threads are closed\nThreads Open:[{}]\nVulkan Layers Open:[{}]", ThreadsOpen, VulkanContext.VulkanLayersOpen < 0 ? "All processes closed and vulkan instance removed" : VulkanContext.VulkanLayersOpen);
while ((ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > 0) && VulkanContext.VulkanLayersOpen > -1 && !CanClose) { while ((ThreadsOpen > 0 || VulkanContext.VulkanLayersOpen > 0) && VulkanContext.VulkanLayersOpen > -1 && !CanClose) {
if (!DrawingThread.FetchRenderThread().isAlive() && !PrimaryThread.FetchMainThread().isAlive() && ThreadsOpen >0){
break;
}
} }
} }
Logger.debug("Closing Primary Thread, Thread: [{}]",Thread.currentThread().toString()); Logger.debug("Closing Primary Thread, Thread: [{}]",Thread.currentThread().toString());

View file

@ -4,10 +4,7 @@ import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils; import net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkDevice; import org.lwjgl.vulkan.*;
import org.lwjgl.vulkan.VkDeviceCreateInfo;
import org.lwjgl.vulkan.VkDeviceQueueCreateInfo;
import org.lwjgl.vulkan.VkExtensionProperties;
import org.tinylog.Logger; import org.tinylog.Logger;
import java.awt.*; import java.awt.*;
@ -39,11 +36,21 @@ public class Device {
.queueFamilyIndex(i) .queueFamilyIndex(i)
.pQueuePriorities(Priorities); .pQueuePriorities(Priorities);
} }
var features13 = VkPhysicalDeviceVulkan13Features.calloc(MemStack)
.sType$Default()
.dynamicRendering(true)
.synchronization2(true);
var features2 = VkPhysicalDeviceFeatures2.calloc(MemStack).sType$Default();
features2.pNext(features13.address());
var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack) var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack)
.sType$Default() .sType$Default()
.pNext(features2.address())
.ppEnabledExtensionNames(RequiredExtensions) .ppEnabledExtensionNames(RequiredExtensions)
.pQueueCreateInfos(QueueCreationInfoBuffer); .pQueueCreateInfos(QueueCreationInfoBuffer);
PointerBuffer pp = MemStack.mallocPointer(1); PointerBuffer pp = MemStack.mallocPointer(1);
vkCheck(vkCreateDevice(PhysDevice.GetPhysicalDevice(), DeviceCreateInfo, null, pp), "Failed to create device"); vkCheck(vkCreateDevice(PhysDevice.GetPhysicalDevice(), DeviceCreateInfo, null, pp), "Failed to create device");
VulkanDevice = new VkDevice(pp.get(0), PhysDevice.GetPhysicalDevice(), DeviceCreateInfo); VulkanDevice = new VkDevice(pp.get(0), PhysDevice.GetPhysicalDevice(), DeviceCreateInfo);
} }

View file

@ -7,6 +7,8 @@ import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.*; import org.lwjgl.vulkan.*;
import org.tinylog.Logger; import org.tinylog.Logger;
import java.nio.IntBuffer;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck; import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK13.*; import static org.lwjgl.vulkan.VK13.*;
@ -55,7 +57,24 @@ public class Queue {
super(vulkanContext, GetPresentQueueFamilyIndex(vulkanContext), QueueIndex); super(vulkanContext, GetPresentQueueFamilyIndex(vulkanContext), QueueIndex);
} }
private static int GetPresentQueueFamilyIndex(VulkanContext vulkanContext){ private static int GetPresentQueueFamilyIndex(VulkanContext vulkanContext){
return -1; int Index = -1;
try(var MemStack = MemoryStack.stackPush()){
var QueuePropertiesBuffer = vulkanContext.GetPhysicalDevice().GetQueueFamilyProperties();
int QueueFamilyCount = QueuePropertiesBuffer.capacity();
IntBuffer intBuffer = MemStack.mallocInt(1);
for(int i = 0; i < QueueFamilyCount; i++){
KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(vulkanContext.GetPhysicalDevice().GetPhysicalDevice(), i, vulkanContext.GetSurface().GetVkSurface(), intBuffer);
boolean SupportsPresentation = intBuffer.get(0) == VK_TRUE;
if(SupportsPresentation){
Index = i;
break;
}
}
}
if (Index < 0){
throw new RuntimeException("Could Not Present Image Queue Family Index");
}
return Index;
} }
} }

View file

@ -53,6 +53,7 @@ public class ImageView {
public long GetVulkanImageView(){ public long GetVulkanImageView(){
return VulkanImageView; return VulkanImageView;
} }
public long GetVulkanImage(){return VulkanImage;}
public static class ImageViewData{ public static class ImageViewData{
private int AspectMask; private int AspectMask;

View file

@ -1,7 +1,87 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen; package net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DisplayToScreen;
public class SceneRender { import net.halbear.Terrain4J.EngineCore.Display.Render;
public SceneRender(){ import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
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.vulkan.*;
import java.util.Arrays;
import static org.lwjgl.vulkan.KHRSwapchain.VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
import static org.lwjgl.vulkan.KHRSynchronization2.VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
import static org.lwjgl.vulkan.KHRSynchronization2.VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR;
import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK13.*;
public class SceneRender { //dynamic rendering;
private final VkClearValue ClearValueColour;
private VkRenderingAttachmentInfo.Buffer[] AttachmentInfoColour;
private VkRenderingInfo[] RenderInfo;
public SceneRender(VulkanContext vulkanContext){
ClearValueColour = VkClearValue.calloc().color(c->c.float32(0,0.5f).float32(1,0.7f).float32(2,0.9f).float32(3,1.0f));
AttachmentInfoColour = CreateColourAttachmentsInfo(vulkanContext,ClearValueColour);
RenderInfo = CreateRenderInfo(vulkanContext, AttachmentInfoColour);
}
public void Render(VulkanContext vulkanContext, CommandBuffer commandBuffer, int ImageIndex){
try(var MemStack = MemoryStack.stackPush()){
SwapChain swapChain = vulkanContext.GetSwapChain();
long SwapChainImage = swapChain.GetVulkanImageView(ImageIndex).GetVulkanImage();
VkCommandBuffer CommandHandle = commandBuffer.GetVulkanCommandBuffer();
VulkanUtils.ImageBarrier(MemStack, CommandHandle, SwapChainImage,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
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]);
vkCmdEndRendering(CommandHandle);
VulkanUtils.ImageBarrier(MemStack, CommandHandle, SwapChainImage,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_2_NONE,
VK_IMAGE_ASPECT_COLOR_BIT);
}
}
private static VkRenderingInfo[] CreateRenderInfo(VulkanContext vulkanContext, VkRenderingAttachmentInfo.Buffer[] ColourAttachments){
SwapChain swapChain = vulkanContext.GetSwapChain();
int ImageCount = swapChain.GetImageCount();
var Result = new VkRenderingInfo[ImageCount];
try(var MemStack = MemoryStack.stackPush()){
VkExtent2D Extent = swapChain.GetSwapChainExtent();
var RenderArea = VkRect2D.calloc(MemStack).extent(Extent);
for(int i = 0; i < ImageCount; i++){
var RenderInfo = VkRenderingInfo.calloc()
.sType$Default()
.renderArea(RenderArea)
.layerCount(1)
.pColorAttachments(ColourAttachments[i]);
Result[i] = RenderInfo;
}
}
return Result;
}
private static VkRenderingAttachmentInfo.Buffer[] CreateColourAttachmentsInfo(VulkanContext vulkanContext, VkClearValue CLearValue){
SwapChain swapChain = vulkanContext.GetSwapChain();
int ImageCount = swapChain.GetImageCount();
var result = new VkRenderingAttachmentInfo.Buffer[ImageCount];
for(int i = 0; i < ImageCount; i++){
var Attachments = VkRenderingAttachmentInfo.calloc(1)
.sType$Default()
.imageView(swapChain.GetVulkanImageView(i).GetVulkanImageView())
.imageLayout(VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR)
.loadOp(VK_ATTACHMENT_LOAD_OP_CLEAR)
.clearValue(CLearValue);
result[i] = Attachments;
}
return result;
}
public void cleanup(){
Arrays.asList(RenderInfo).forEach(VkRenderingInfo::free);
Arrays.asList(AttachmentInfoColour).forEach(VkRenderingAttachmentInfo.Buffer::free);
ClearValueColour.free();
} }
} }

View file

@ -4,7 +4,9 @@ import net.halbear.Terrain4J.EngineCore.Display.Window;
import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext; import net.halbear.Terrain4J.EngineCore.Logic.VulkanContext;
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.GPUSynchronisation.Semaphore; import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.GPUSynchronisation.Semaphore;
import net.halbear.Terrain4J.EngineCore.Vulkan.Structure.DeviceLayers.Queues.Queue;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.vulkan.*; import org.lwjgl.vulkan.*;
import org.tinylog.Logger; import org.tinylog.Logger;
@ -13,8 +15,7 @@ import java.nio.LongBuffer;
import java.util.Arrays; import java.util.Arrays;
import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck; import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck;
import static org.lwjgl.vulkan.VK10.VK_IMAGE_ASPECT_COLOR_BIT; import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK10.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
public class SwapChain { public class SwapChain {
private final ImageView[] ImageViewArray; private final ImageView[] ImageViewArray;
@ -100,7 +101,41 @@ public class SwapChain {
} }
public int FetchNextImage(Device device, Semaphore ImageFetchSemaphore){ public int FetchNextImage(Device device, Semaphore ImageFetchSemaphore){
return 0; //testing smth with the git rq int ImageIndex;
try(var MemStack = MemoryStack.stackPush()){
IntBuffer IntPointer = MemStack.mallocInt(1);
int Error = KHRSwapchain.vkAcquireNextImageKHR(device.FetchVulkanDevice(), VulkanSwapChain, ~0L, ImageFetchSemaphore.GetSemaphore(), MemoryUtil.NULL, IntPointer);
if (Error == KHRSwapchain.VK_ERROR_OUT_OF_DATE_KHR){
return -1;
}
else if (Error == KHRSwapchain.VK_SUBOPTIMAL_KHR){
Logger.warn("Suboptimal surface properties match, not fatal");
} else if (Error != VK_SUCCESS){
throw new RuntimeException("Failed to fetch next image in the swapchain: " + Error);
}
ImageIndex = IntPointer.get(0);
}
return ImageIndex;
}
public boolean PresentImage(Queue queue,Semaphore RenderCompleteSemaphores, int ImageIndex){
boolean resize = false;
try(var MemStack = MemoryStack.stackPush()){
VkPresentInfoKHR Present = VkPresentInfoKHR.calloc(MemStack)
.sType$Default()
.pWaitSemaphores(MemStack.longs(RenderCompleteSemaphores.GetSemaphore()))
.swapchainCount(1)
.pSwapchains(MemStack.longs(VulkanSwapChain))
.pImageIndices(MemStack.ints(ImageIndex));
int Error = KHRSwapchain.vkQueuePresentKHR(queue.GetVulkanQueue(), Present);
if (Error == KHRSwapchain.VK_ERROR_OUT_OF_DATE_KHR){
resize = true;
} else if (Error == KHRSwapchain.VK_SUBOPTIMAL_KHR){
Logger.warn("Suboptimal surface properties match, not fatal");
} else if (Error != VK_SUCCESS){
throw new RuntimeException("failed to present KHR: " + Error);
}
}
return resize;
} }
public void cleanup(Device device){ public void cleanup(Device device){

View file

@ -1,8 +1,16 @@
package net.halbear.Terrain4J.EngineCore.Vulkan.Util; package net.halbear.Terrain4J.EngineCore.Vulkan.Util;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkCommandBuffer;
import org.lwjgl.vulkan.VkDependencyInfo;
import org.lwjgl.vulkan.VkImageMemoryBarrier;
import org.lwjgl.vulkan.VkImageMemoryBarrier2;
import org.tinylog.Logger;
import java.util.Locale; import java.util.Locale;
import static org.lwjgl.vulkan.VK10.*; import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK13.vkCmdPipelineBarrier2;
public class VulkanUtils { public class VulkanUtils {
public static final int MAX_IN_FLIGHT = 2; public static final int MAX_IN_FLIGHT = 2;
@ -21,7 +29,31 @@ public class VulkanUtils {
} }
return result; return result;
} }
public static void ImageBarrier(MemoryStack MemStack, VkCommandBuffer CommandHandle, long Image, int OldLayout,
int NewLayout, long SrcStage, long DstStage, long SrcAccess, long DstAccess,
int AspectMask){
var ImageBarrier = VkImageMemoryBarrier2.calloc(1, MemStack)
.sType$Default()
.oldLayout(OldLayout)
.newLayout(NewLayout)
.srcStageMask(SrcStage)
.dstStageMask(DstStage)
.srcAccessMask(SrcAccess)
.dstAccessMask(DstAccess)
.srcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.dstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.subresourceRange(it -> it
.aspectMask(AspectMask)
.baseMipLevel(0)
.levelCount(VK_REMAINING_MIP_LEVELS)
.baseArrayLayer(0)
.layerCount(VK_REMAINING_ARRAY_LAYERS))
.image(Image);
VkDependencyInfo DependencyInfo = VkDependencyInfo.calloc(MemStack)
.sType$Default()
.pImageMemoryBarriers(ImageBarrier);
vkCmdPipelineBarrier2(CommandHandle, DependencyInfo);
}
public static void vkCheck(int Error, String ErrorMessage) { public static void vkCheck(int Error, String ErrorMessage) {
if (Error != VK_SUCCESS) { if (Error != VK_SUCCESS) {
String ErrorCode = switch (Error) { String ErrorCode = switch (Error) {