From d8653120d2679e247538ab211445c15e9db822c2 Mon Sep 17 00:00:00 2001 From: Halbear Date: Fri, 16 Jan 2026 14:30:23 +0000 Subject: [PATCH] Start work on the Device Interface Layer, the layers go Instance -> PhysicalDevice -> Device --- .../VulkanDeviceManagement/Device.java | 40 ++++++ .../PhysicalDevice.java | 133 +++++++++++++++++- 2 files changed, 168 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/Device.java b/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/Device.java index 6e9fdd9..5fa586c 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/Device.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/Device.java @@ -1,4 +1,44 @@ package net.halbear.Terrain4J.EngineCore.VulkanDeviceManagement; +import org.lwjgl.PointerBuffer; +import org.lwjgl.system.MemoryStack; +import org.lwjgl.vulkan.VkDevice; +import org.lwjgl.vulkan.VkDeviceCreateInfo; +import org.lwjgl.vulkan.VkDeviceQueueCreateInfo; +import org.tinylog.Logger; + +import java.nio.FloatBuffer; + +import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck; +import static org.lwjgl.vulkan.VK10.vkCreateDevice; + public class Device { + VkDevice VulkanDevice; + + public Device(PhysicalDevice PhysDevice){ + PointerBuffer RequiredExtensions = null; // to be finished later + + Logger.debug("Creating Device Interface Layer"); + try (var MemStack = MemoryStack.stackPush()) { + var QueuePropertyBuffer = PhysDevice.GetQueueFamilyProperties(); + int QueueFamilyCount = QueuePropertyBuffer.capacity(); + var QueueCreationInfoBuffer = VkDeviceQueueCreateInfo.calloc(QueueFamilyCount, MemStack); + for(int i = 0; i < QueueFamilyCount; i++){ + FloatBuffer Priorities = MemStack.callocFloat(QueuePropertyBuffer.get(i).queueCount()); + QueueCreationInfoBuffer.get(i) + .sType$Default() + .queueFamilyIndex(i) + .pQueuePriorities(Priorities); + } + var DeviceCreateInfo = VkDeviceCreateInfo.calloc(MemStack) + .sType$Default() + .ppEnabledExtensionNames(RequiredExtensions) + .pQueueCreateInfos(QueueCreationInfoBuffer); + PointerBuffer pp = MemStack.mallocPointer(1); + vkCheck(vkCreateDevice(PhysDevice.GetPhysicalDevice(), DeviceCreateInfo, null, pp), "Failed to create device"); + VulkanDevice = new VkDevice(pp.get(0), PhysDevice.GetPhysicalDevice(), DeviceCreateInfo); + } + } } + + diff --git a/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/PhysicalDevice.java b/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/PhysicalDevice.java index cadf93e..ca42218 100644 --- a/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/PhysicalDevice.java +++ b/src/main/java/net/halbear/Terrain4J/EngineCore/VulkanDeviceManagement/PhysicalDevice.java @@ -3,34 +3,99 @@ package net.halbear.Terrain4J.EngineCore.VulkanDeviceManagement; import net.halbear.Terrain4J.EngineCore.Display.VulkanInstance; import org.lwjgl.PointerBuffer; import org.lwjgl.system.MemoryStack; -import org.lwjgl.vulkan.VkPhysicalDevice; +import org.lwjgl.vulkan.*; +import org.tinylog.Logger; import java.nio.IntBuffer; -import java.sql.Array; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; import static net.halbear.Terrain4J.EngineCore.Vulkan.Util.VulkanUtils.vkCheck; -import static org.lwjgl.vulkan.VK10.vkEnumeratePhysicalDevices; +import static org.lwjgl.vulkan.VK10.*; +import static org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceProperties2; +import static org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceQueueFamilyProperties2; public class PhysicalDevice { + private final VkExtensionProperties.Buffer vkDeviceExtensions; + private final VkPhysicalDeviceMemoryProperties vkMemoryProperties; + private final VkPhysicalDevice vkPhysicalDevice; + private final VkPhysicalDeviceFeatures vkPhysicalDeviceFeatures; + private final VkPhysicalDeviceProperties2 vkPhysicalDeviceProperties; + private final VkQueueFamilyProperties.Buffer vkQueueFamilyProperties; + + protected static final Set REQUIRED_EXTENSIONS; + + static{ + REQUIRED_EXTENSIONS = new HashSet<>(); + REQUIRED_EXTENSIONS.add(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME); + } private PhysicalDevice(VkPhysicalDevice VulkanPhysicalDevice){ + try(var MemStack = MemoryStack.stackPush()){ + this.vkPhysicalDevice = VulkanPhysicalDevice; + IntBuffer intBuffer = MemStack.mallocInt(1); + vkPhysicalDeviceProperties = VkPhysicalDeviceProperties2.calloc().sType$Default(); + vkGetPhysicalDeviceProperties2(vkPhysicalDevice, vkPhysicalDeviceProperties); + vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String)null, intBuffer, null), "Failed to get extension property count"); + vkDeviceExtensions = VkExtensionProperties.calloc(intBuffer.get(0)); + vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String)null, intBuffer, vkDeviceExtensions), "Failed to get extension property"); + + vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, intBuffer, null); + vkQueueFamilyProperties = VkQueueFamilyProperties.calloc(intBuffer.get(0)); + vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, intBuffer, vkQueueFamilyProperties); + + vkPhysicalDeviceFeatures = VkPhysicalDeviceFeatures.calloc(); + vkGetPhysicalDeviceFeatures(vkPhysicalDevice, vkPhysicalDeviceFeatures); + + vkMemoryProperties = VkPhysicalDeviceMemoryProperties.calloc(); + vkGetPhysicalDeviceMemoryProperties(vkPhysicalDevice, vkMemoryProperties); + } } public static PhysicalDevice createPhysicalDevice(VulkanInstance instance, String PreferredDeviceName){ + Logger.debug("selecting physical devices"); PhysicalDevice result = null; try (var MemStack = MemoryStack.stackPush()){ PointerBuffer PointerPhyiscalDevices = getPhysicalDevices(instance, MemStack); int DeviceCount = PointerPhyiscalDevices.capacity(); - var physDevices = new ArrayList(); + var PhysicalDevices = new ArrayList(); for(int i = 0; i < DeviceCount; i++){ var vkPhysicalDevice = new VkPhysicalDevice(PointerPhyiscalDevices.get(i),instance.getVkInstance()); var PhysDevice = new PhysicalDevice(vkPhysicalDevice); + + String DeviceName = PhysDevice.FetchDeviceName(); + if(!PhysDevice.HasGraphicsQueueFamily()){ + Logger.debug("Device [{}] does not support graphics queue family",DeviceName); + PhysDevice.cleanup(); + continue; + } + + if(!PhysDevice.SupportsExtensions(REQUIRED_EXTENSIONS)){ + Logger.debug("Device [{}] does not support some required extensions",DeviceName); + PhysDevice.cleanup(); + continue; + } + if(PreferredDeviceName != null && PreferredDeviceName.equals(DeviceName)){ + result = PhysDevice; + break; + } + if(PhysDevice.vkPhysicalDeviceProperties.properties().deviceType() == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU){ + PhysicalDevices.addFirst(PhysDevice); + } else{ + PhysicalDevices.add(PhysDevice); + } } + result = result == null && !PhysicalDevices.isEmpty() ? PhysicalDevices.removeFirst() : result; + PhysicalDevices.forEach(PhysicalDevice::cleanup); + if (result == null){ + throw new RuntimeException("No Graphics Driver Found!"); + } + Logger.debug("Selected Graphics Driver: [{}]", result.FetchDeviceName()); } - return null; + return result; } public static PointerBuffer getPhysicalDevices(VulkanInstance instance, MemoryStack MemStack){ @@ -38,8 +103,66 @@ public class PhysicalDevice { IntBuffer intBuffer = MemStack.mallocInt(1); vkCheck(vkEnumeratePhysicalDevices(instance.getVkInstance(),intBuffer,null),"Failed to fetch physical device count"); int DeviceCount = intBuffer.get(0); + Logger.debug("Detected Physical Device Count: {}",DeviceCount); PointerPhysicalDevices = MemStack.mallocPointer(DeviceCount); vkCheck(vkEnumeratePhysicalDevices(instance.getVkInstance(),intBuffer,PointerPhysicalDevices),"Failed to fetch physical devices"); return PointerPhysicalDevices; } + //Display Drivers have specific queues for specific tasks organised into "families", this makes sure the gpu can push queues that process graphics + private boolean HasGraphicsQueueFamily(){ + boolean CanHanldeGraphicsQueues = false; + int FamilyCount = vkQueueFamilyProperties != null ? vkQueueFamilyProperties.capacity() : 0; + for(int i = 0; i < FamilyCount; i ++){ + VkQueueFamilyProperties FamilyProperties = vkQueueFamilyProperties.get(i); + if((FamilyProperties.queueFlags() & VK_QUEUE_GRAPHICS_BIT) != 0){ + CanHanldeGraphicsQueues = true; + break; + } + } + return CanHanldeGraphicsQueues; + } + + public boolean SupportsExtensions(Set Extensions){ + var ExtensionsClone = new HashSet<>(Extensions); + int ExtensionCount = vkDeviceExtensions != null ? vkDeviceExtensions.capacity() : 0; + for(int i = 0; i < ExtensionCount; i++){ + String ExtensionName = vkDeviceExtensions.get(i).extensionNameString(); + ExtensionsClone.remove(ExtensionName); + } + + boolean AllSupported = ExtensionsClone.isEmpty(); + if (!AllSupported){ + Logger.debug("A detected [{}] number of extensions are not compatible with the device [{}]",ExtensionsClone.iterator().next(), FetchDeviceName()); + } + return AllSupported; + } + + public void cleanup(){ + Logger.debug("freeing physical device [{}]", FetchDeviceName()); + vkMemoryProperties.free(); + vkPhysicalDeviceFeatures.free(); + vkQueueFamilyProperties.free(); + vkDeviceExtensions.free(); + vkPhysicalDeviceProperties.free(); + } + + public String FetchDeviceName(){ + return vkPhysicalDeviceProperties.properties().deviceNameString(); + } + public VkPhysicalDeviceMemoryProperties GetMemoryProperties(){ + return vkMemoryProperties; + } + + public VkPhysicalDevice GetPhysicalDevice(){ + return vkPhysicalDevice; + } + public VkPhysicalDeviceFeatures GetPhysicalDeviceFeatures(){ + return vkPhysicalDeviceFeatures; + } + public VkPhysicalDeviceProperties2 GetPhysicalDeviceProperties(){ + return vkPhysicalDeviceProperties; + } + public VkQueueFamilyProperties.Buffer GetQueueFamilyProperties(){ + return vkQueueFamilyProperties; + } }