Fix Physical Device Queue selector
This commit is contained in:
parent
422b2825ad
commit
a9cf0cf4cf
5 changed files with 106 additions and 74 deletions
|
@ -5,6 +5,8 @@ import org.lwjgl.system.MemoryStack;
|
|||
import org.lwjgl.vulkan.*;
|
||||
import org.tinylog.Logger;
|
||||
|
||||
import fr.mrdev023.vulkan_java.vk.utils.SuitablePhysicalDeviceFinder;
|
||||
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -15,9 +17,12 @@ public class Device {
|
|||
|
||||
private final PhysicalDevice physicalDevice;
|
||||
private final VkDevice vkDevice;
|
||||
private final Queue.GraphicsQueue graphicsQueue;
|
||||
private final Queue.ComputeQueue computeQueue;
|
||||
private final Queue.TransferQueue transferQueue;
|
||||
|
||||
public Device(PhysicalDevice physicalDevice) throws VulkanError {
|
||||
this.physicalDevice = physicalDevice;
|
||||
public Device(SuitablePhysicalDeviceFinder.MatchResult physicalDeviceMatch) throws VulkanError {
|
||||
this.physicalDevice = physicalDeviceMatch.physicalDevice;
|
||||
|
||||
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||
// Define required extensions
|
||||
|
@ -60,6 +65,10 @@ public class Device {
|
|||
vkCheck(vkCreateDevice(physicalDevice.getVkPhysicalDevice(), deviceCreateInfo, null, pp),
|
||||
"Failed to create device");
|
||||
vkDevice = new VkDevice(pp.get(0), physicalDevice.getVkPhysicalDevice(), deviceCreateInfo);
|
||||
|
||||
graphicsQueue = new Queue.GraphicsQueue(this, physicalDeviceMatch.graphicsQueueFamilyIndex, 0);
|
||||
computeQueue = new Queue.ComputeQueue(this, physicalDeviceMatch.computeQueueFamilyIndex, 1);
|
||||
transferQueue = new Queue.TransferQueue(this, physicalDeviceMatch.transferQueueFamilyIndex, 2);
|
||||
}
|
||||
|
||||
Logger.debug("Vulkan device created");
|
||||
|
@ -111,4 +120,16 @@ public class Device {
|
|||
public void waitIdle() {
|
||||
vkDeviceWaitIdle(vkDevice);
|
||||
}
|
||||
|
||||
public Queue.GraphicsQueue getGraphicsQueue() {
|
||||
return graphicsQueue;
|
||||
}
|
||||
|
||||
public Queue.ComputeQueue getComputeQueue() {
|
||||
return computeQueue;
|
||||
}
|
||||
|
||||
public Queue.TransferQueue getTransferQueue() {
|
||||
return transferQueue;
|
||||
}
|
||||
}
|
|
@ -31,29 +31,20 @@ public class Queue {
|
|||
}
|
||||
|
||||
public static class GraphicsQueue extends Queue {
|
||||
|
||||
public GraphicsQueue(Device device, int queueIndex) {
|
||||
super(device, getGraphicsQueueFamilyIndex(device), queueIndex);
|
||||
}
|
||||
|
||||
private static int getGraphicsQueueFamilyIndex(Device device) {
|
||||
int index = -1;
|
||||
PhysicalDevice physicalDevice = device.getPhysicalDevice();
|
||||
VkQueueFamilyProperties.Buffer queuePropsBuff = physicalDevice.getVkQueueFamilyProps();
|
||||
int numQueuesFamilies = queuePropsBuff.capacity();
|
||||
for (int i = 0; i < numQueuesFamilies; i++) {
|
||||
VkQueueFamilyProperties props = queuePropsBuff.get(i);
|
||||
boolean graphicsQueue = (props.queueFlags() & VK_QUEUE_GRAPHICS_BIT) != 0;
|
||||
if (graphicsQueue) {
|
||||
index = i;
|
||||
break;
|
||||
public GraphicsQueue(Device device, int queueFamilyIndex, int queueIndex) {
|
||||
super(device, queueFamilyIndex, queueIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
throw new RuntimeException("Failed to get graphics Queue family index");
|
||||
public static class ComputeQueue extends Queue {
|
||||
public ComputeQueue(Device device, int queueFamilyIndex, int queueIndex) {
|
||||
super(device, queueFamilyIndex, queueIndex);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public static class TransferQueue extends Queue {
|
||||
public TransferQueue(Device device, int queueFamilyIndex, int queueIndex) {
|
||||
super(device, queueFamilyIndex, queueIndex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ public class Vulkan {
|
|||
private static PhysicalDevice physicalDevice;
|
||||
private static Device device;
|
||||
private static Surface surface;
|
||||
private static Queue.GraphicsQueue graphicsQueue;
|
||||
|
||||
public static void init() throws VulkanError {
|
||||
if (!glfwVulkanSupported()) {
|
||||
|
@ -38,8 +37,7 @@ public class Vulkan {
|
|||
}
|
||||
|
||||
physicalDevice = physicalDeviceMatch.physicalDevice;
|
||||
device = new Device(physicalDevice);
|
||||
graphicsQueue = new Queue.GraphicsQueue(device, 0);
|
||||
device = new Device(physicalDeviceMatch);
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
|
|
|
@ -17,17 +17,16 @@ import org.tinylog.Logger;
|
|||
import fr.mrdev023.vulkan_java.vk.VulkanUtils;
|
||||
|
||||
/**
|
||||
* This class is used to store the instance extensions to use to create the Vulkan instance.
|
||||
* This class is used to store the instance extensions to use to create the
|
||||
* Vulkan instance.
|
||||
*
|
||||
* @see InstanceExtensions.Selector to select the instance extensions
|
||||
*/
|
||||
public class InstanceExtensions {
|
||||
private Set<String> instanceExtensions;
|
||||
private PointerBuffer glfwRequiredExtensions;
|
||||
|
||||
private InstanceExtensions(Set<String> instanceExtensions, PointerBuffer glfwRequiredExtensions) {
|
||||
private InstanceExtensions(Set<String> instanceExtensions) {
|
||||
this.instanceExtensions = instanceExtensions;
|
||||
this.glfwRequiredExtensions = glfwRequiredExtensions;
|
||||
}
|
||||
|
||||
public boolean hasInstanceExtensions() {
|
||||
|
@ -39,10 +38,9 @@ public class InstanceExtensions {
|
|||
}
|
||||
|
||||
public PointerBuffer writeToStack(MemoryStack stack) {
|
||||
int numExtensions = instanceExtensions.size() + glfwRequiredExtensions.remaining();
|
||||
PointerBuffer requiredExtensions = stack.mallocPointer(numExtensions);
|
||||
int numExtensions = instanceExtensions.size();
|
||||
|
||||
requiredExtensions.put(glfwRequiredExtensions);
|
||||
PointerBuffer requiredExtensions = stack.mallocPointer(numExtensions);
|
||||
for (String extension : instanceExtensions) {
|
||||
requiredExtensions.put(stack.UTF8(extension));
|
||||
}
|
||||
|
@ -90,16 +88,11 @@ public class InstanceExtensions {
|
|||
Set<String> instanceExtensions = getInstanceExtensions();
|
||||
log("Supported instance extensions", instanceExtensions);
|
||||
|
||||
// GLFW Extension
|
||||
PointerBuffer glfwExtensions = GLFWVulkan.glfwGetRequiredInstanceExtensions();
|
||||
if (glfwExtensions == null) {
|
||||
throw new RuntimeException("Failed to find the GLFW platform surface extensions");
|
||||
}
|
||||
|
||||
Set<String> glfwExtensions = getGLFWRequiredExtensions();
|
||||
Set<String> portabilityExtensions = getPortabilityExtensions(instanceExtensions);
|
||||
log("Portability extensions used", portabilityExtensions);
|
||||
|
||||
Set<String> selectedExtensions = new HashSet<>();
|
||||
selectedExtensions.addAll(glfwExtensions);
|
||||
selectedExtensions.addAll(portabilityExtensions);
|
||||
|
||||
if (validationLayers != null && validationLayers.hasValidationLayers()) {
|
||||
|
@ -107,7 +100,7 @@ public class InstanceExtensions {
|
|||
}
|
||||
log("Selected instance extensions", selectedExtensions);
|
||||
|
||||
return new InstanceExtensions(selectedExtensions, glfwExtensions);
|
||||
return new InstanceExtensions(selectedExtensions);
|
||||
}
|
||||
|
||||
private Set<String> getInstanceExtensions() {
|
||||
|
@ -118,7 +111,8 @@ public class InstanceExtensions {
|
|||
VK10.vkEnumerateInstanceExtensionProperties((String) null, numExtensionsBuf, null);
|
||||
int numExtensions = numExtensionsBuf.get(0);
|
||||
|
||||
VkExtensionProperties.Buffer instanceExtensionsProps = VkExtensionProperties.calloc(numExtensions, stack);
|
||||
VkExtensionProperties.Buffer instanceExtensionsProps = VkExtensionProperties.calloc(numExtensions,
|
||||
stack);
|
||||
VK10.vkEnumerateInstanceExtensionProperties((String) null, numExtensionsBuf, instanceExtensionsProps);
|
||||
for (int i = 0; i < numExtensions; i++) {
|
||||
VkExtensionProperties props = instanceExtensionsProps.get(i);
|
||||
|
@ -135,8 +129,10 @@ public class InstanceExtensions {
|
|||
|
||||
var osType = VulkanUtils.getOS();
|
||||
if (osType == VulkanUtils.OSType.MACOS) {
|
||||
if (!instanceExtensions.contains(KHRPortabilityEnumeration.VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
|
||||
throw new RuntimeException("Vulkan instance does not support portability enumeration extension but it's required for MacOS");
|
||||
if (!instanceExtensions
|
||||
.contains(KHRPortabilityEnumeration.VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
|
||||
throw new RuntimeException(
|
||||
"Vulkan instance does not support portability enumeration extension but it's required for MacOS");
|
||||
}
|
||||
portabilityExtensions.add(KHRPortabilityEnumeration.VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||
}
|
||||
|
@ -144,6 +140,19 @@ public class InstanceExtensions {
|
|||
return portabilityExtensions;
|
||||
}
|
||||
|
||||
private Set<String> getGLFWRequiredExtensions() {
|
||||
PointerBuffer glfwExtensionsBuffer = GLFWVulkan.glfwGetRequiredInstanceExtensions();
|
||||
if (glfwExtensionsBuffer == null) {
|
||||
throw new RuntimeException("Failed to find the GLFW platform surface extensions");
|
||||
}
|
||||
|
||||
Set<String> glfwExtensions = new HashSet<>();
|
||||
for (int i = 0; i < glfwExtensionsBuffer.remaining(); i++) {
|
||||
glfwExtensions.add(glfwExtensionsBuffer.getStringUTF8(i));
|
||||
}
|
||||
return glfwExtensions;
|
||||
}
|
||||
|
||||
private void log(String title, Set<String> layers) {
|
||||
Logger.debug("{} ({})", title, layers.size());
|
||||
for (String layer : layers) {
|
||||
|
|
|
@ -35,37 +35,47 @@ public class SuitablePhysicalDeviceFinder {
|
|||
return matchedPhysicalDevices.stream().min(Comparator.comparingInt(MatchResult::getScore)).orElse(null);
|
||||
}
|
||||
|
||||
private static MatchResult checkPhysicalDevice(MemoryStack stack, PhysicalDevice physicalDevice, Criteria criteria) {
|
||||
private static MatchResult checkPhysicalDevice(MemoryStack stack, PhysicalDevice physicalDevice,
|
||||
Criteria criteria) {
|
||||
int graphicsQueueFamilyIndex = -1;
|
||||
int computeQueueFamilyIndex = -1;
|
||||
int transferQueueFamilyIndex = -1;
|
||||
boolean surfaceSupport = false;
|
||||
|
||||
|
||||
IntBuffer presentSupport = stack.ints(VK10.VK_FALSE);
|
||||
var vkQueueFamilyProps = physicalDevice.getVkQueueFamilyProps();
|
||||
for (int i = 0; i < vkQueueFamilyProps.capacity(); i++) {
|
||||
var vkQueueFamilyProp = vkQueueFamilyProps.get(i);
|
||||
|
||||
if ((vkQueueFamilyProp.queueFlags() & VK10.VK_QUEUE_GRAPHICS_BIT) != 0) {
|
||||
if (graphicsQueueFamilyIndex == -1 && (vkQueueFamilyProp.queueFlags() & VK10.VK_QUEUE_GRAPHICS_BIT) != 0) {
|
||||
graphicsQueueFamilyIndex = i;
|
||||
}
|
||||
|
||||
if ((vkQueueFamilyProp.queueFlags() & VK10.VK_QUEUE_COMPUTE_BIT) != 0) {
|
||||
if (computeQueueFamilyIndex == -1 && (vkQueueFamilyProp.queueFlags() & VK10.VK_QUEUE_COMPUTE_BIT) != 0) {
|
||||
computeQueueFamilyIndex = i;
|
||||
}
|
||||
|
||||
if ((vkQueueFamilyProp.queueFlags() & VK10.VK_QUEUE_TRANSFER_BIT) != 0) {
|
||||
if (transferQueueFamilyIndex == -1 && (vkQueueFamilyProp.queueFlags() & VK10.VK_QUEUE_TRANSFER_BIT) != 0) {
|
||||
transferQueueFamilyIndex = i;
|
||||
}
|
||||
|
||||
KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.getVkPhysicalDevice(), i, criteria.withSurfaceSupport.getVkSurface(), presentSupport);
|
||||
KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.getVkPhysicalDevice(), i,
|
||||
criteria.withSurfaceSupport.getVkSurface(), presentSupport);
|
||||
if (presentSupport.get(0) == VK10.VK_TRUE) {
|
||||
surfaceSupport = true;
|
||||
}
|
||||
|
||||
if ((!criteria.withGraphicsQueue || graphicsQueueFamilyIndex != -1) &&
|
||||
(!criteria.withComputeQueue || computeQueueFamilyIndex != -1) &&
|
||||
(!criteria.withTransferQueue || transferQueueFamilyIndex != -1) &&
|
||||
(criteria.withSurfaceSupport == null || surfaceSupport)) {
|
||||
// We found a suitable queue family, we can break the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new MatchResult(physicalDevice, graphicsQueueFamilyIndex, computeQueueFamilyIndex, transferQueueFamilyIndex, surfaceSupport);
|
||||
return new MatchResult(physicalDevice, graphicsQueueFamilyIndex, computeQueueFamilyIndex,
|
||||
transferQueueFamilyIndex, surfaceSupport);
|
||||
}
|
||||
|
||||
public static class MatchResult {
|
||||
|
@ -75,7 +85,8 @@ public class SuitablePhysicalDeviceFinder {
|
|||
public final int computeQueueFamilyIndex;
|
||||
public final int transferQueueFamilyIndex;
|
||||
|
||||
public MatchResult(PhysicalDevice physicalDevice, int graphicsQueueFamilyIndex, int computeQueueFamilyIndex, int transferQueueFamilyIndex, boolean surfaceSupport) {
|
||||
public MatchResult(PhysicalDevice physicalDevice, int graphicsQueueFamilyIndex, int computeQueueFamilyIndex,
|
||||
int transferQueueFamilyIndex, boolean surfaceSupport) {
|
||||
this.physicalDevice = physicalDevice;
|
||||
this.graphicsQueueFamilyIndex = graphicsQueueFamilyIndex;
|
||||
this.computeQueueFamilyIndex = computeQueueFamilyIndex;
|
||||
|
@ -101,7 +112,7 @@ public class SuitablePhysicalDeviceFinder {
|
|||
Logger.debug("\t\t[FAILED] Graphics queue is not supported");
|
||||
return false;
|
||||
} else {
|
||||
Logger.debug("\t\t[OK] Graphics queue is supported");
|
||||
Logger.debug("\t\t[OK] Graphics queue is supported (family index: {})", graphicsQueueFamilyIndex);
|
||||
}
|
||||
|
||||
if (!criteria.withComputeQueue) {
|
||||
|
@ -110,7 +121,7 @@ public class SuitablePhysicalDeviceFinder {
|
|||
Logger.debug("\t\t[FAILED] Compute queue is not supported");
|
||||
return false;
|
||||
} else {
|
||||
Logger.debug("\t\t[OK] Compute queue is supported");
|
||||
Logger.debug("\t\t[OK] Compute queue is supported (family index: {})", computeQueueFamilyIndex);
|
||||
}
|
||||
|
||||
if (!criteria.withTransferQueue) {
|
||||
|
@ -119,7 +130,7 @@ public class SuitablePhysicalDeviceFinder {
|
|||
Logger.debug("\t\t[FAILED] Transfer queue is not supported");
|
||||
return false;
|
||||
} else {
|
||||
Logger.debug("\t\t[OK] Transfer queue is supported");
|
||||
Logger.debug("\t\t[OK] Transfer queue is supported (family index: {})", transferQueueFamilyIndex);
|
||||
}
|
||||
|
||||
if (criteria.withSurfaceSupport == null) {
|
||||
|
@ -133,8 +144,10 @@ public class SuitablePhysicalDeviceFinder {
|
|||
|
||||
if (criteria.extensions == null) {
|
||||
Logger.debug("\t\t[SKIPPED] Required extensions is empty");
|
||||
} else if (physicalDevice.getVkDeviceExtensions().stream().allMatch(extension -> criteria.extensions.contains(extension.extensionNameString()))) {
|
||||
Logger.debug("\t\t[FAILED] Required extensions are not supported [{}]", String.join(", ", criteria.extensions));
|
||||
} else if (physicalDevice.getVkDeviceExtensions().stream()
|
||||
.allMatch(extension -> criteria.extensions.contains(extension.extensionNameString()))) {
|
||||
Logger.debug("\t\t[FAILED] Required extensions are not supported [{}]",
|
||||
String.join(", ", criteria.extensions));
|
||||
return false;
|
||||
} else {
|
||||
Logger.debug("\t\t[OK] Required extensions are supported [{}]", String.join(", ", criteria.extensions));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue