This commit is contained in:
Florian RICHER 2025-05-24 16:25:10 +02:00
parent 0e181376b4
commit 3749af2c5c
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
20 changed files with 385 additions and 378 deletions

View file

@ -1,25 +1,30 @@
package fr.mrdev023.vulkan_java.vk;
import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
import static org.lwjgl.vulkan.VK10.VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
import static org.lwjgl.vulkan.VK10.vkCreateDevice;
import static org.lwjgl.vulkan.VK10.vkDestroyDevice;
import static org.lwjgl.vulkan.VK10.vkDeviceWaitIdle;
import java.util.Optional;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.*;
import org.lwjgl.vulkan.VkDevice;
import org.lwjgl.vulkan.VkDeviceCreateInfo;
import org.lwjgl.vulkan.VkPhysicalDeviceFeatures;
import org.tinylog.Logger;
import fr.mrdev023.vulkan_java.vk.utils.SuitablePhysicalDeviceFinder;
import java.nio.*;
import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
import static org.lwjgl.vulkan.VK11.*;
public class Device {
private final PhysicalDevice physicalDevice;
private final VkDevice vkDevice;
private final Queue.PresentQueue presentQueue;
private final Queue.GraphicsQueue graphicsQueue;
private final Queue.ComputeQueue computeQueue;
private final Queue.TransferQueue transferQueue;
private final Optional<Queue> presentQueue;
private final Optional<Queue> graphicsQueue;
private final Optional<Queue> computeQueue;
private final Optional<Queue> transferQueue;
public Device(SuitablePhysicalDeviceFinder.MatchResult physicalDeviceMatch) throws VulkanError {
this.physicalDevice = physicalDeviceMatch.physicalDevice;
@ -36,17 +41,9 @@ public class Device {
VkPhysicalDeviceFeatures features = VkPhysicalDeviceFeatures.calloc(stack);
// Enable all the queue families
VkQueueFamilyProperties.Buffer queuePropsBuff = physicalDevice.getVkQueueFamilyProps();
int numQueuesFamilies = queuePropsBuff.capacity();
VkDeviceQueueCreateInfo.Buffer queueCreationInfoBuf = VkDeviceQueueCreateInfo.calloc(numQueuesFamilies,
stack);
for (int i = 0; i < numQueuesFamilies; i++) {
FloatBuffer priorities = stack.callocFloat(queuePropsBuff.get(i).queueCount());
queueCreationInfoBuf.get(i)
.sType(VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO)
.queueFamilyIndex(i)
.pQueuePriorities(priorities);
}
var queueFamilyIndices = physicalDeviceMatch.validatorResult.queueFamilyIndices.orElseThrow();
var queuesCreator = new QueuesCreator(queueFamilyIndices);
var queueCreationInfoBuf = queuesCreator.createQueueCreateInfos(stack, physicalDevice);
VkDeviceCreateInfo deviceCreateInfo = VkDeviceCreateInfo.calloc(stack)
.sType(VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO)
@ -59,16 +56,14 @@ public class Device {
"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);
presentQueue = null;
graphicsQueue = null;
computeQueue = null;
transferQueue = null;
graphicsQueue = queueFamilyIndices.getGraphicsQueueFamilyIndex()
.flatMap(queueFamilyIndex -> Optional.of(queuesCreator.createQueue(this, queueFamilyIndex)));
presentQueue = queueFamilyIndices.getPresentQueueFamilyIndex()
.flatMap(queueFamilyIndex -> Optional.of(queuesCreator.createQueue(this, queueFamilyIndex)));
computeQueue = queueFamilyIndices.getComputeQueueFamilyIndex()
.flatMap(queueFamilyIndex -> Optional.of(queuesCreator.createQueue(this, queueFamilyIndex)));
transferQueue = queueFamilyIndices.getTransferQueueFamilyIndex()
.flatMap(queueFamilyIndex -> Optional.of(queuesCreator.createQueue(this, queueFamilyIndex)));
}
Logger.debug("Vulkan device created");
@ -91,19 +86,19 @@ public class Device {
vkDeviceWaitIdle(vkDevice);
}
public Queue.PresentQueue getPresentQueue() {
public Optional<Queue> getPresentQueue() {
return presentQueue;
}
public Queue.GraphicsQueue getGraphicsQueue() {
public Optional<Queue> getGraphicsQueue() {
return graphicsQueue;
}
public Queue.ComputeQueue getComputeQueue() {
public Optional<Queue> getComputeQueue() {
return computeQueue;
}
public Queue.TransferQueue getTransferQueue() {
public Optional<Queue> getTransferQueue() {
return transferQueue;
}
}

View file

@ -21,27 +21,15 @@ public class PhysicalDevice {
private final VkQueueFamilyProperties.Buffer vkQueueFamilyProps;
private PhysicalDevice(VkPhysicalDevice vkPhysicalDevice) throws VulkanError {
this.vkPhysicalDevice = vkPhysicalDevice;
try (MemoryStack stack = MemoryStack.stackPush()) {
this.vkPhysicalDevice = vkPhysicalDevice;
IntBuffer intBuffer = stack.mallocInt(1);
// Get device properties
vkPhysicalDeviceProperties = VkPhysicalDeviceProperties.calloc();
vkGetPhysicalDeviceProperties(vkPhysicalDevice, vkPhysicalDeviceProperties);
// Get device extensions
vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String) null, intBuffer, null),
"Failed to get number of device extension properties");
vkDeviceExtensions = VkExtensionProperties.calloc(intBuffer.get(0));
vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String) null, intBuffer,
vkDeviceExtensions),
"Failed to get extension properties");
// Get Queue family properties
vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, intBuffer, null);
vkQueueFamilyProps = VkQueueFamilyProperties.calloc(intBuffer.get(0));
vkGetPhysicalDeviceQueueFamilyProperties(vkPhysicalDevice, intBuffer, vkQueueFamilyProps);
vkDeviceExtensions = getVulkanPhysicalDeviceExtensions(stack, vkPhysicalDevice);
vkQueueFamilyProps = getVulkanQueueFamilyProperties(stack, vkPhysicalDevice);
vkPhysicalDeviceFeatures = VkPhysicalDeviceFeatures.calloc();
vkGetPhysicalDeviceFeatures(vkPhysicalDevice, vkPhysicalDeviceFeatures);
@ -113,4 +101,31 @@ public class PhysicalDevice {
public VkExtensionProperties.Buffer getVkDeviceExtensions() {
return vkDeviceExtensions;
}
private static VkExtensionProperties.Buffer getVulkanPhysicalDeviceExtensions(MemoryStack stack,
VkPhysicalDevice physicalDevice)
throws VulkanError {
IntBuffer numExtensions = stack.mallocInt(1);
vkCheck(vkEnumerateDeviceExtensionProperties(physicalDevice, (String) null, numExtensions, null),
"Failed to get number of device extension properties");
VkExtensionProperties.Buffer deviceExtensions = VkExtensionProperties.calloc(numExtensions.get(0));
vkCheck(vkEnumerateDeviceExtensionProperties(physicalDevice, (String) null, numExtensions,
deviceExtensions),
"Failed to get extension properties");
return deviceExtensions;
}
private static VkQueueFamilyProperties.Buffer getVulkanQueueFamilyProperties(MemoryStack stack,
VkPhysicalDevice physicalDevice)
throws VulkanError {
IntBuffer numQueueFamilies = stack.mallocInt(1);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, numQueueFamilies, null);
VkQueueFamilyProperties.Buffer queueFamilyProps = VkQueueFamilyProperties.calloc(numQueueFamilies.get(0));
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, numQueueFamilies, queueFamilyProps);
return queueFamilyProps;
}
}

View file

@ -29,28 +29,4 @@ public class Queue {
public void waitIdle() {
vkQueueWaitIdle(vkQueue);
}
public static class GraphicsQueue extends Queue {
public GraphicsQueue(Device device, int queueFamilyIndex, int queueIndex) {
super(device, queueFamilyIndex, queueIndex);
}
}
public static class PresentQueue extends Queue {
public PresentQueue(Device device, int queueFamilyIndex, int queueIndex) {
super(device, queueFamilyIndex, queueIndex);
}
}
public static class ComputeQueue extends Queue {
public ComputeQueue(Device device, int queueFamilyIndex, int queueIndex) {
super(device, queueFamilyIndex, queueIndex);
}
}
public static class TransferQueue extends Queue {
public TransferQueue(Device device, int queueFamilyIndex, int queueIndex) {
super(device, queueFamilyIndex, queueIndex);
}
}
}

View file

@ -0,0 +1,67 @@
package fr.mrdev023.vulkan_java.vk;
import java.util.HashMap;
import java.util.Optional;
public class QueueFamilyIndices {
private final Optional<Integer> graphicsQueueFamilyIndex;
private final Optional<Integer> computeQueueFamilyIndex;
private final Optional<Integer> transferQueueFamilyIndex;
private final Optional<Integer> presentQueueFamilyIndex;
public QueueFamilyIndices(Optional<Integer> graphicsQueueFamilyIndex, Optional<Integer> computeQueueFamilyIndex,
Optional<Integer> transferQueueFamilyIndex, Optional<Integer> presentQueueFamilyIndex) {
this.graphicsQueueFamilyIndex = graphicsQueueFamilyIndex;
this.computeQueueFamilyIndex = computeQueueFamilyIndex;
this.transferQueueFamilyIndex = transferQueueFamilyIndex;
this.presentQueueFamilyIndex = presentQueueFamilyIndex;
}
public Optional<Integer> getGraphicsQueueFamilyIndex() {
return graphicsQueueFamilyIndex;
}
public Optional<Integer> getComputeQueueFamilyIndex() {
return computeQueueFamilyIndex;
}
public Optional<Integer> getTransferQueueFamilyIndex() {
return transferQueueFamilyIndex;
}
public Optional<Integer> getPresentQueueFamilyIndex() {
return presentQueueFamilyIndex;
}
public static class Builder {
private Optional<Integer> graphicsQueueFamilyIndex;
private Optional<Integer> computeQueueFamilyIndex;
private Optional<Integer> transferQueueFamilyIndex;
private Optional<Integer> presentQueueFamilyIndex;
public Builder withGraphicsQueueFamilyIndex(int graphicsQueueFamilyIndex) {
this.graphicsQueueFamilyIndex = Optional.of(graphicsQueueFamilyIndex);
return this;
}
public Builder withComputeQueueFamilyIndex(int computeQueueFamilyIndex) {
this.computeQueueFamilyIndex = Optional.of(computeQueueFamilyIndex);
return this;
}
public Builder withTransferQueueFamilyIndex(int transferQueueFamilyIndex) {
this.transferQueueFamilyIndex = Optional.of(transferQueueFamilyIndex);
return this;
}
public Builder withPresentQueueFamilyIndex(int presentQueueFamilyIndex) {
this.presentQueueFamilyIndex = Optional.of(presentQueueFamilyIndex);
return this;
}
public QueueFamilyIndices build() {
return new QueueFamilyIndices(graphicsQueueFamilyIndex, computeQueueFamilyIndex, transferQueueFamilyIndex,
presentQueueFamilyIndex);
}
}
}

View file

@ -0,0 +1,76 @@
package fr.mrdev023.vulkan_java.vk;
import java.nio.FloatBuffer;
import java.util.HashMap;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkDeviceQueueCreateInfo;
public class QueuesCreator {
private final HashMap<Integer, Integer> families;
private HashMap<Integer, Integer> counters;
public QueuesCreator(QueueFamilyIndices queueFamilyIndices) {
this.families = createFamilies(queueFamilyIndices);
this.counters = new HashMap<>();
for (var family : families.keySet()) {
counters.put(family, 0);
}
}
public VkDeviceQueueCreateInfo.Buffer createQueueCreateInfos(MemoryStack stack,
PhysicalDevice physicalDevice) {
VkDeviceQueueCreateInfo.Buffer queueCreationInfoBuf = VkDeviceQueueCreateInfo.calloc(families.size(),
stack);
int i = 0;
for (var familyIndex : families.keySet()) {
FloatBuffer priorities = stack.callocFloat(families.get(familyIndex));
queueCreationInfoBuf.get(i)
.sType(VK10.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO)
.queueFamilyIndex(familyIndex)
.pQueuePriorities(priorities);
i++;
}
return queueCreationInfoBuf;
}
public Queue createQueue(Device device, int queueFamilyIndex) {
var queueIndex = getNextAvailableQueueIndexForFamilyIndex(queueFamilyIndex);
return new Queue(device, queueFamilyIndex, queueIndex);
}
private int getNextAvailableQueueIndexForFamilyIndex(int queueFamilyIndex) {
var max = families.getOrDefault(queueFamilyIndex, 0);
var current = counters.getOrDefault(queueFamilyIndex, 0);
if (current >= max) {
throw new RuntimeException("No more queues available for family " + queueFamilyIndex);
}
counters.put(queueFamilyIndex, current + 1);
return current + 1;
}
private HashMap<Integer, Integer> createFamilies(QueueFamilyIndices queueFamilyIndices) {
var families = new HashMap<Integer, Integer>();
if (queueFamilyIndices.getGraphicsQueueFamilyIndex().isPresent()) {
var familyIndex = queueFamilyIndices.getGraphicsQueueFamilyIndex().get();
families.put(familyIndex, families.getOrDefault(familyIndex, 0) + 1);
}
if (queueFamilyIndices.getComputeQueueFamilyIndex().isPresent()) {
var familyIndex = queueFamilyIndices.getComputeQueueFamilyIndex().get();
families.put(familyIndex, families.getOrDefault(familyIndex, 0) + 1);
}
if (queueFamilyIndices.getTransferQueueFamilyIndex().isPresent()) {
var familyIndex = queueFamilyIndices.getTransferQueueFamilyIndex().get();
families.put(familyIndex, families.getOrDefault(familyIndex, 0) + 1);
}
if (queueFamilyIndices.getPresentQueueFamilyIndex().isPresent()) {
var familyIndex = queueFamilyIndices.getPresentQueueFamilyIndex().get();
families.put(familyIndex, families.getOrDefault(familyIndex, 0) + 1);
}
return families;
}
}

View file

@ -1,8 +1,6 @@
package fr.mrdev023.vulkan_java.vk;
import fr.mrdev023.vulkan_java.vk.compatibilities.validators.PhysicalDeviceCompatibilityValidator;
import fr.mrdev023.vulkan_java.vk.utils.SuitablePhysicalDeviceFinder;
import fr.mrdev023.vulkan_java.window.Display;
import static org.lwjgl.glfw.GLFWVulkan.glfwVulkanSupported;
import java.util.Optional;
import java.util.Set;
@ -12,7 +10,9 @@ import org.lwjgl.vulkan.KHRPortabilitySubset;
import org.lwjgl.vulkan.KHRSwapchain;
import org.lwjgl.vulkan.VK10;
import static org.lwjgl.glfw.GLFWVulkan.glfwVulkanSupported;
import fr.mrdev023.vulkan_java.vk.utils.SuitablePhysicalDeviceFinder;
import fr.mrdev023.vulkan_java.vk.validators.PhysicalDeviceCompatibilityValidator;
import fr.mrdev023.vulkan_java.window.Display;
public class Vulkan {

View file

@ -1,26 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.requirements;
import java.util.Optional;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkQueueFamilyProperties;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
public class ComputeQueueRequirement implements IQueueFamilyRequirement {
@Override
public boolean isFamilySuitable(PhysicalDevice physicalDevice, VkQueueFamilyProperties queueFamilyProperties, int queueFamilyIndex) {
return (queueFamilyProperties.queueFlags() & VK10.VK_QUEUE_COMPUTE_BIT) != 0;
}
@Override
public String getName() {
return "Compute Queue";
}
@Override
public Optional<Integer> getQueueFlag() {
return Optional.of(VK10.VK_QUEUE_COMPUTE_BIT);
}
}

View file

@ -1,26 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.requirements;
import java.util.Optional;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkQueueFamilyProperties;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
public class GraphicsQueueRequirement implements IQueueFamilyRequirement {
@Override
public boolean isFamilySuitable(PhysicalDevice physicalDevice, VkQueueFamilyProperties queueFamilyProperties, int queueFamilyIndex) {
return (queueFamilyProperties.queueFlags() & VK10.VK_QUEUE_GRAPHICS_BIT) != 0;
}
@Override
public String getName() {
return "Graphics Queue";
}
@Override
public Optional<Integer> getQueueFlag() {
return Optional.of(VK10.VK_QUEUE_GRAPHICS_BIT);
}
}

View file

@ -1,13 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.requirements;
import java.util.Optional;
import org.lwjgl.vulkan.VkQueueFamilyProperties;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
public interface IQueueFamilyRequirement {
boolean isFamilySuitable(PhysicalDevice physicalDevice, VkQueueFamilyProperties queueFamilyProperties, int queueFamilyIndex);
String getName();
Optional<Integer> getQueueFlag();
}

View file

@ -1,40 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.requirements;
import java.nio.IntBuffer;
import java.util.Optional;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.KHRSurface;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkQueueFamilyProperties;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.Surface;
public class SurfacePresentQueueRequirement implements IQueueFamilyRequirement {
private final Surface surface;
public SurfacePresentQueueRequirement(Surface surface) {
this.surface = surface;
}
@Override
public boolean isFamilySuitable(PhysicalDevice physicalDevice, VkQueueFamilyProperties queueFamilyProperties, int queueFamilyIndex) {
try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer presentSupport = stack.ints(VK10.VK_FALSE);
KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.getVkPhysicalDevice(), queueFamilyIndex, surface.getVkSurface(), presentSupport);
return presentSupport.get(0) == VK10.VK_TRUE;
}
}
@Override
public String getName() {
return "Surface Present Queue";
}
@Override
public Optional<Integer> getQueueFlag() {
return Optional.empty();
}
}

View file

@ -1,26 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.requirements;
import java.util.Optional;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkQueueFamilyProperties;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
public class TransferQueueRequirement implements IQueueFamilyRequirement {
@Override
public boolean isFamilySuitable(PhysicalDevice physicalDevice, VkQueueFamilyProperties queueFamilyProperties, int queueFamilyIndex) {
return (queueFamilyProperties.queueFlags() & VK10.VK_QUEUE_TRANSFER_BIT) != 0;
}
@Override
public String getName() {
return "Transfer Queue";
}
@Override
public Optional<Integer> getQueueFlag() {
return Optional.of(VK10.VK_QUEUE_TRANSFER_BIT);
}
}

View file

@ -1,77 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.validators;
import java.util.ArrayList;
import java.util.Optional;
import java.util.Set;
import org.lwjgl.vulkan.VK10;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.Surface;
import fr.mrdev023.vulkan_java.vk.compatibilities.requirements.ComputeQueueRequirement;
import fr.mrdev023.vulkan_java.vk.compatibilities.requirements.GraphicsQueueRequirement;
import fr.mrdev023.vulkan_java.vk.compatibilities.requirements.IQueueFamilyRequirement;
import fr.mrdev023.vulkan_java.vk.compatibilities.requirements.SurfacePresentQueueRequirement;
import fr.mrdev023.vulkan_java.vk.compatibilities.requirements.TransferQueueRequirement;
public class PhysicalDeviceCompatibilityValidator {
private int requiredQueueFlags;
private Set<String> requiredExtensions;
private final Optional<Surface> surface;
public PhysicalDeviceCompatibilityValidator(int requiredQueueFlags, Set<String> requiredExtensions, Optional<Surface> surface) {
this.requiredQueueFlags = requiredQueueFlags;
this.requiredExtensions = requiredExtensions;
this.surface = surface;
}
public Result validate(PhysicalDevice physicalDevice) {
var queueFamilyRequirementsResult = validateQueueFamilyRequirements(physicalDevice);
var deviceExtensionsResult = validateDeviceExtensions(physicalDevice);
return new Result(queueFamilyRequirementsResult, deviceExtensionsResult);
}
private QueueFamilyRequirementsValidator.Result validateQueueFamilyRequirements(PhysicalDevice physicalDevice) {
var queueFamilyRequirements = new ArrayList<IQueueFamilyRequirement>();
if ((requiredQueueFlags & VK10.VK_QUEUE_GRAPHICS_BIT) != 0) {
queueFamilyRequirements.add(new GraphicsQueueRequirement());
}
if ((requiredQueueFlags & VK10.VK_QUEUE_COMPUTE_BIT) != 0) {
queueFamilyRequirements.add(new ComputeQueueRequirement());
}
if ((requiredQueueFlags & VK10.VK_QUEUE_TRANSFER_BIT) != 0) {
queueFamilyRequirements.add(new TransferQueueRequirement());
}
if (surface.isPresent()) {
queueFamilyRequirements.add(new SurfacePresentQueueRequirement(surface.get()));
}
var queueFamilyRequirementsValidator = new QueueFamilyRequirementsValidator(queueFamilyRequirements);
var result = queueFamilyRequirementsValidator.validate(physicalDevice);
return result;
}
private DeviceExtensionsValidator.Result validateDeviceExtensions(PhysicalDevice physicalDevice) {
var deviceExtensionsValidator = new DeviceExtensionsValidator(requiredExtensions);
var result = deviceExtensionsValidator.validate(physicalDevice);
return result;
}
public static class Result {
public final boolean isSuitable;
public final QueueFamilyRequirementsValidator.Result queueFamilyRequirementsResult;
public final DeviceExtensionsValidator.Result deviceExtensionsResult;
public Result(QueueFamilyRequirementsValidator.Result queueFamilyRequirementsResult, DeviceExtensionsValidator.Result deviceExtensionsResult) {
this.isSuitable = queueFamilyRequirementsResult.isSuitable && deviceExtensionsResult.isSuitable;
this.queueFamilyRequirementsResult = queueFamilyRequirementsResult;
this.deviceExtensionsResult = deviceExtensionsResult;
}
}
}

View file

@ -1,70 +0,0 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.validators;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.compatibilities.requirements.IQueueFamilyRequirement;
public class QueueFamilyRequirementsValidator {
private List<IQueueFamilyRequirement> requirements;
public QueueFamilyRequirementsValidator(List<IQueueFamilyRequirement> requirements) {
this.requirements = requirements;
}
/**
* Validate the queue family requirements of the physical device.
*
* <i>Note: This method return a Result to adapt the requirements to the
* physical device properties after the validation.</i>
*
* @param physicalDevice The physical device to validate the requirements for.
* @return A result object containing the validation results and whether the
* physical device is suitable.
*/
public Result validate(PhysicalDevice physicalDevice) {
var vkQueueFamilyProps = physicalDevice.getVkQueueFamilyProps();
HashMap<IQueueFamilyRequirement, Optional<Integer>> result = requirements.stream()
.collect(Collectors.toMap(
requirement -> requirement,
requirement -> Optional.empty(),
(a, b) -> a,
HashMap::new));
for (int i = 0; i < vkQueueFamilyProps.capacity(); i++) {
var vkQueueFamilyProp = vkQueueFamilyProps.get(i);
for (var requirement : requirements) {
if (result.get(requirement).isPresent()) {
continue;
}
if (requirement.isFamilySuitable(physicalDevice, vkQueueFamilyProp, i)) {
result.put(requirement, Optional.of(i));
}
}
if (result.values().stream().allMatch(Optional::isPresent)) {
break;
}
}
boolean isSuitable = result.values().stream().allMatch(Optional::isPresent);
return new Result(result, isSuitable);
}
public static class Result {
public final HashMap<IQueueFamilyRequirement, Optional<Integer>> queueFamilyIndices;
public final boolean isSuitable;
public Result(HashMap<IQueueFamilyRequirement, Optional<Integer>> queueFamilyIndices, boolean isSuitable) {
this.queueFamilyIndices = queueFamilyIndices;
this.isSuitable = isSuitable;
}
}
}

View file

@ -1,6 +1,6 @@
package fr.mrdev023.vulkan_java.vk.loggers;
import fr.mrdev023.vulkan_java.vk.compatibilities.validators.DeviceExtensionsValidator;
import fr.mrdev023.vulkan_java.vk.validators.DeviceExtensionsValidator;
public class DeviceExtensionsResultLogger {
public static void log(DeviceExtensionsValidator.Result result) {

View file

@ -1,13 +1,13 @@
package fr.mrdev023.vulkan_java.vk.loggers;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.compatibilities.validators.PhysicalDeviceCompatibilityValidator;
import fr.mrdev023.vulkan_java.vk.validators.PhysicalDeviceCompatibilityValidator;
public class PhysicalDeviceCompatibilityLogger {
public static void log(PhysicalDevice physicalDevice, PhysicalDeviceCompatibilityValidator.Result result) {
ScopedLogger.pushScope("Physical device support (Is suitable: {})", result.isSuitable);
PhysicalDevicePropertiesLogger.log(physicalDevice);
QueueFamilyRequirementResultLogger.log(result.queueFamilyRequirementsResult);
QueueFamilyRequirementResultLogger.log(result.queueFamilyIndices);
DeviceExtensionsResultLogger.log(result.deviceExtensionsResult);
ScopedLogger.popScope();
}

View file

@ -1,17 +1,28 @@
package fr.mrdev023.vulkan_java.vk.loggers;
import fr.mrdev023.vulkan_java.vk.compatibilities.validators.QueueFamilyRequirementsValidator;
import java.util.Optional;
import fr.mrdev023.vulkan_java.vk.QueueFamilyIndices;
public class QueueFamilyRequirementResultLogger {
public static void log(QueueFamilyRequirementsValidator.Result result) {
ScopedLogger.pushScope("Queue Family Requirements (Is suitable: {})", result.isSuitable);
result.queueFamilyIndices.forEach((requirement, index) -> {
if (index.isPresent()) {
ScopedLogger.log("{}: [SUPPORTED]", requirement.getName());
} else {
ScopedLogger.log("{}: [UNSUPPORTED]", requirement.getName(), requirement.getQueueFlag().orElse(null));
}
});
public static void log(Optional<QueueFamilyIndices> queueFamilyIndices) {
ScopedLogger.pushScope("Queue Family Requirements (Is suitable: {})", queueFamilyIndices.isPresent());
logQueueFamilyResult("Graphics Queue",
queueFamilyIndices.flatMap(QueueFamilyIndices::getGraphicsQueueFamilyIndex));
logQueueFamilyResult("Compute Queue",
queueFamilyIndices.flatMap(QueueFamilyIndices::getComputeQueueFamilyIndex));
logQueueFamilyResult("Transfer Queue",
queueFamilyIndices.flatMap(QueueFamilyIndices::getTransferQueueFamilyIndex));
logQueueFamilyResult("Present Queue",
queueFamilyIndices.flatMap(QueueFamilyIndices::getPresentQueueFamilyIndex));
ScopedLogger.popScope();
}
private static void logQueueFamilyResult(String queueName, Optional<Integer> queueFamilyIndex) {
if (queueFamilyIndex.isPresent()) {
ScopedLogger.log("{}: [SUPPORTED] (Index: {})", queueName, queueFamilyIndex.get());
} else {
ScopedLogger.log("{}: [UNSUPPORTED]", queueName);
}
}
}

View file

@ -10,12 +10,13 @@ import org.lwjgl.vulkan.VK10;
import fr.mrdev023.vulkan_java.vk.Instance;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.VulkanError;
import fr.mrdev023.vulkan_java.vk.compatibilities.validators.PhysicalDeviceCompatibilityValidator;
import fr.mrdev023.vulkan_java.vk.loggers.PhysicalDeviceCompatibilityLogger;
import fr.mrdev023.vulkan_java.vk.validators.PhysicalDeviceCompatibilityValidator;
public class SuitablePhysicalDeviceFinder {
public static MatchResult findBestPhysicalDevice(Instance instance, PhysicalDeviceCompatibilityValidator validator) throws VulkanError {
public static MatchResult findBestPhysicalDevice(Instance instance, PhysicalDeviceCompatibilityValidator validator)
throws VulkanError {
List<MatchResult> matchedPhysicalDevices = new ArrayList<>();
try (MemoryStack stack = MemoryStack.stackPush()) {
@ -29,12 +30,13 @@ public class SuitablePhysicalDeviceFinder {
}
}
return matchedPhysicalDevices.stream().min(Comparator.comparingInt(matchResult -> getScore(matchResult))).orElse(null);
return matchedPhysicalDevices.stream().min(Comparator.comparingInt(matchResult -> getScore(matchResult)))
.orElse(null);
}
private static int getScore(MatchResult matchResult) {
int deviceType = matchResult.physicalDevice.getVkPhysicalDeviceProperties().deviceType();
return switch (deviceType) {
case VK10.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU -> 0;
case VK10.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU -> 1;
@ -42,7 +44,7 @@ public class SuitablePhysicalDeviceFinder {
case VK10.VK_PHYSICAL_DEVICE_TYPE_CPU -> 3;
case VK10.VK_PHYSICAL_DEVICE_TYPE_OTHER -> 4;
default -> 5;
};
};
}
public static class MatchResult {

View file

@ -1,4 +1,4 @@
package fr.mrdev023.vulkan_java.vk.compatibilities.validators;
package fr.mrdev023.vulkan_java.vk.validators;
import java.util.HashSet;
import java.util.Set;
@ -15,10 +15,12 @@ public class DeviceExtensionsValidator {
/**
* Validate the device extensions of the physical device.
*
* <i>Note: This method return a Result to adapt the extensions to the physical device properties after the validation.</i>
* <i>Note: This method return a Result to adapt the extensions to the physical
* device properties after the validation.</i>
*
* @param physicalDevice The physical device to validate the extensions for.
* @return A result object containing the validation results and whether the physical device is suitable.
* @return A result object containing the validation results and whether the
* physical device is suitable.
*/
public Result validate(PhysicalDevice physicalDevice) {
Set<String> matchingExtensions = new HashSet<>();

View file

@ -0,0 +1,54 @@
package fr.mrdev023.vulkan_java.vk.validators;
import java.util.Optional;
import java.util.Set;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.QueueFamilyIndices;
import fr.mrdev023.vulkan_java.vk.Surface;
public class PhysicalDeviceCompatibilityValidator {
private int requiredQueueFlags;
private Set<String> requiredExtensions;
private final Optional<Surface> surface;
public PhysicalDeviceCompatibilityValidator(int requiredQueueFlags, Set<String> requiredExtensions,
Optional<Surface> surface) {
this.requiredQueueFlags = requiredQueueFlags;
this.requiredExtensions = requiredExtensions;
this.surface = surface;
}
public Result validate(PhysicalDevice physicalDevice) {
var queueFamilyRequirementsResult = validateQueueFamilyRequirements(physicalDevice);
var deviceExtensionsResult = validateDeviceExtensions(physicalDevice);
return new Result(queueFamilyRequirementsResult, deviceExtensionsResult);
}
private Optional<QueueFamilyIndices> validateQueueFamilyRequirements(PhysicalDevice physicalDevice) {
var queueFamilyRequirementsValidator = new QueueFamilyRequirementsValidator(requiredQueueFlags, surface);
var result = queueFamilyRequirementsValidator.validate(physicalDevice);
return result;
}
private DeviceExtensionsValidator.Result validateDeviceExtensions(PhysicalDevice physicalDevice) {
var deviceExtensionsValidator = new DeviceExtensionsValidator(requiredExtensions);
var result = deviceExtensionsValidator.validate(physicalDevice);
return result;
}
public static class Result {
public final boolean isSuitable;
public final Optional<QueueFamilyIndices> queueFamilyIndices;
public final DeviceExtensionsValidator.Result deviceExtensionsResult;
public Result(Optional<QueueFamilyIndices> queueFamilyIndices,
DeviceExtensionsValidator.Result deviceExtensionsResult) {
this.isSuitable = queueFamilyIndices.isPresent() && deviceExtensionsResult.isSuitable;
this.queueFamilyIndices = queueFamilyIndices;
this.deviceExtensionsResult = deviceExtensionsResult;
}
}
}

View file

@ -0,0 +1,87 @@
package fr.mrdev023.vulkan_java.vk.validators;
import java.nio.IntBuffer;
import java.util.Optional;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.KHRSurface;
import org.lwjgl.vulkan.VK10;
import org.lwjgl.vulkan.VkQueueFamilyProperties;
import fr.mrdev023.vulkan_java.vk.PhysicalDevice;
import fr.mrdev023.vulkan_java.vk.QueueFamilyIndices;
import fr.mrdev023.vulkan_java.vk.Surface;
public class QueueFamilyRequirementsValidator {
private int requiredQueueFlags;
private Optional<Surface> surface;
public QueueFamilyRequirementsValidator(int requiredQueueFlags, Optional<Surface> surface) {
this.requiredQueueFlags = requiredQueueFlags;
this.surface = surface;
}
/**
* Validate the queue family requirements of the physical device.
*
* @param physicalDevice The physical device to validate the requirements for.
* @return The queue family indices if the requirements are met, otherwise an
* empty optional.
*/
public Optional<QueueFamilyIndices> validate(PhysicalDevice physicalDevice) {
var vkQueueFamilyProps = physicalDevice.getVkQueueFamilyProps();
var queueFamilyIndicesBuilder = new QueueFamilyIndices.Builder();
for (int i = 0; i < vkQueueFamilyProps.capacity(); i++) {
var vkQueueFamilyProp = vkQueueFamilyProps.get(i);
if (hasRequiredFlag(VK10.VK_QUEUE_GRAPHICS_BIT) && queueFlagIsSupported(vkQueueFamilyProp)) {
queueFamilyIndicesBuilder.withGraphicsQueueFamilyIndex(i);
requiredQueueFlags &= ~VK10.VK_QUEUE_GRAPHICS_BIT; // Consume the flag
}
if (hasRequiredFlag(VK10.VK_QUEUE_COMPUTE_BIT) && queueFlagIsSupported(vkQueueFamilyProp)) {
queueFamilyIndicesBuilder.withComputeQueueFamilyIndex(i);
requiredQueueFlags &= ~VK10.VK_QUEUE_COMPUTE_BIT; // Consume the flag
}
if (hasRequiredFlag(VK10.VK_QUEUE_TRANSFER_BIT) && queueFlagIsSupported(vkQueueFamilyProp)) {
queueFamilyIndicesBuilder.withTransferQueueFamilyIndex(i);
requiredQueueFlags &= ~VK10.VK_QUEUE_TRANSFER_BIT; // Consume the flag
}
if (surface.isPresent() && isSurfaceSupported(surface.get(), physicalDevice, i)) {
queueFamilyIndicesBuilder.withPresentQueueFamilyIndex(i);
surface = Optional.empty(); // Consume the surface
}
if (requiredQueueFlags == 0 && surface.isEmpty()) {
break;
}
}
if (requiredQueueFlags == 0 && surface.isEmpty()) {
return Optional.of(queueFamilyIndicesBuilder.build());
}
return Optional.empty();
}
private boolean queueFlagIsSupported(VkQueueFamilyProperties vkQueueFamilyProp) {
return (vkQueueFamilyProp.queueFlags() & requiredQueueFlags) != 0;
}
private boolean isSurfaceSupported(Surface surface, PhysicalDevice physicalDevice, int queueFamilyIndex) {
try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer presentSupport = stack.ints(VK10.VK_FALSE);
KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice.getVkPhysicalDevice(), queueFamilyIndex,
surface.getVkSurface(), presentSupport);
return presentSupport.get(0) == VK10.VK_TRUE;
}
}
private boolean hasRequiredFlag(int flag) {
return (requiredQueueFlags & flag) != 0;
}
}