Start work on the Device Interface Layer, the layers go

Instance -> PhysicalDevice -> Device
This commit is contained in:
Harrison Corlett 2026-01-16 14:30:23 +00:00
parent 9f4c78aae2
commit d8653120d2
2 changed files with 168 additions and 5 deletions

View file

@ -1,4 +1,44 @@
package net.halbear.Terrain4J.EngineCore.VulkanDeviceManagement; 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 { 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);
}
}
}

View file

@ -3,34 +3,99 @@ package net.halbear.Terrain4J.EngineCore.VulkanDeviceManagement;
import net.halbear.Terrain4J.EngineCore.Display.VulkanInstance; import net.halbear.Terrain4J.EngineCore.Display.VulkanInstance;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VkPhysicalDevice; import org.lwjgl.vulkan.*;
import org.tinylog.Logger;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.sql.Array;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
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.vkEnumeratePhysicalDevices; import static org.lwjgl.vulkan.VK10.*;
import static org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceProperties2;
import static org.lwjgl.vulkan.VK11.vkGetPhysicalDeviceQueueFamilyProperties2;
public class PhysicalDevice { 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<String> REQUIRED_EXTENSIONS;
static{
REQUIRED_EXTENSIONS = new HashSet<>();
REQUIRED_EXTENSIONS.add(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
private PhysicalDevice(VkPhysicalDevice VulkanPhysicalDevice){ 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){ public static PhysicalDevice createPhysicalDevice(VulkanInstance instance, String PreferredDeviceName){
Logger.debug("selecting physical devices");
PhysicalDevice result = null; PhysicalDevice result = null;
try (var MemStack = MemoryStack.stackPush()){ try (var MemStack = MemoryStack.stackPush()){
PointerBuffer PointerPhyiscalDevices = getPhysicalDevices(instance, MemStack); PointerBuffer PointerPhyiscalDevices = getPhysicalDevices(instance, MemStack);
int DeviceCount = PointerPhyiscalDevices.capacity(); int DeviceCount = PointerPhyiscalDevices.capacity();
var physDevices = new ArrayList<PhysicalDevice>(); var PhysicalDevices = new ArrayList<PhysicalDevice>();
for(int i = 0; i < DeviceCount; i++){ for(int i = 0; i < DeviceCount; i++){
var vkPhysicalDevice = new VkPhysicalDevice(PointerPhyiscalDevices.get(i),instance.getVkInstance()); var vkPhysicalDevice = new VkPhysicalDevice(PointerPhyiscalDevices.get(i),instance.getVkInstance());
var PhysDevice = new PhysicalDevice(vkPhysicalDevice); 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);
} }
} }
return null; 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 result;
} }
public static PointerBuffer getPhysicalDevices(VulkanInstance instance, MemoryStack MemStack){ public static PointerBuffer getPhysicalDevices(VulkanInstance instance, MemoryStack MemStack){
@ -38,8 +103,66 @@ public class PhysicalDevice {
IntBuffer intBuffer = MemStack.mallocInt(1); IntBuffer intBuffer = MemStack.mallocInt(1);
vkCheck(vkEnumeratePhysicalDevices(instance.getVkInstance(),intBuffer,null),"Failed to fetch physical device count"); vkCheck(vkEnumeratePhysicalDevices(instance.getVkInstance(),intBuffer,null),"Failed to fetch physical device count");
int DeviceCount = intBuffer.get(0); int DeviceCount = intBuffer.get(0);
Logger.debug("Detected Physical Device Count: {}",DeviceCount);
PointerPhysicalDevices = MemStack.mallocPointer(DeviceCount); PointerPhysicalDevices = MemStack.mallocPointer(DeviceCount);
vkCheck(vkEnumeratePhysicalDevices(instance.getVkInstance(),intBuffer,PointerPhysicalDevices),"Failed to fetch physical devices"); vkCheck(vkEnumeratePhysicalDevices(instance.getVkInstance(),intBuffer,PointerPhysicalDevices),"Failed to fetch physical devices");
return PointerPhysicalDevices; 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<String> 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;
}
} }