VkInstance: Refactor Validation and Extensions selection
This commit is contained in:
parent
c09b04dc81
commit
9ecf98a26d
4 changed files with 315 additions and 167 deletions
|
@ -1,19 +1,17 @@
|
||||||
package fr.mrdev023.vulkan_java.vk;
|
package fr.mrdev023.vulkan_java.vk;
|
||||||
|
|
||||||
import org.lwjgl.PointerBuffer;
|
import org.lwjgl.PointerBuffer;
|
||||||
import org.lwjgl.glfw.GLFWVulkan;
|
|
||||||
import org.lwjgl.system.*;
|
import org.lwjgl.system.*;
|
||||||
import org.lwjgl.vulkan.*;
|
import org.lwjgl.vulkan.*;
|
||||||
import org.tinylog.Logger;
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
import fr.mrdev023.vulkan_java.vk.utils.InstanceValidationLayersSelector;
|
import fr.mrdev023.vulkan_java.vk.utils.InstanceExtensions;
|
||||||
|
import fr.mrdev023.vulkan_java.vk.utils.InstanceValidationLayers;
|
||||||
|
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
|
import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
|
||||||
import static org.lwjgl.vulkan.EXTDebugUtils.*;
|
import static org.lwjgl.vulkan.EXTDebugUtils.*;
|
||||||
import static org.lwjgl.vulkan.KHRPortabilityEnumeration.VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
|
||||||
import static org.lwjgl.vulkan.VK11.*;
|
import static org.lwjgl.vulkan.VK11.*;
|
||||||
|
|
||||||
public class Instance {
|
public class Instance {
|
||||||
|
@ -23,7 +21,6 @@ public class Instance {
|
||||||
public static final int MESSAGE_TYPE_BITMASK = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
public static final int MESSAGE_TYPE_BITMASK = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||||
private static final String PORTABILITY_EXTENSION = "VK_KHR_portability_enumeration";
|
|
||||||
|
|
||||||
private final VkInstance vkInstance;
|
private final VkInstance vkInstance;
|
||||||
|
|
||||||
|
@ -31,7 +28,6 @@ public class Instance {
|
||||||
private long vkDebugHandle;
|
private long vkDebugHandle;
|
||||||
|
|
||||||
public Instance(boolean validate) throws VulkanError {
|
public Instance(boolean validate) throws VulkanError {
|
||||||
Logger.debug("Creating Vulkan instance");
|
|
||||||
try (MemoryStack stack = MemoryStack.stackPush()) {
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
// Create application information
|
// Create application information
|
||||||
ByteBuffer appShortName = stack.UTF8("VulkanBook");
|
ByteBuffer appShortName = stack.UTF8("VulkanBook");
|
||||||
|
@ -43,52 +39,19 @@ public class Instance {
|
||||||
.engineVersion(0)
|
.engineVersion(0)
|
||||||
.apiVersion(VK_API_VERSION_1_1);
|
.apiVersion(VK_API_VERSION_1_1);
|
||||||
|
|
||||||
// Validation layers
|
InstanceValidationLayers validationLayers = new InstanceValidationLayers.Selector()
|
||||||
var validationLayers = new InstanceValidationLayersSelector()
|
.includeValidationLayers(validate)
|
||||||
.withValidationLayers(validate)
|
|
||||||
.selectValidationLayers();
|
.selectValidationLayers();
|
||||||
|
|
||||||
// Set required layers
|
InstanceExtensions instanceExtensions = new InstanceExtensions.Selector()
|
||||||
PointerBuffer requiredLayers = null;
|
.withValidationLayers(validationLayers)
|
||||||
if (!validationLayers.isEmpty()) {
|
.selectInstanceExtensions();
|
||||||
requiredLayers = stack.mallocPointer(validationLayers.size());
|
|
||||||
for (String layer : validationLayers) {
|
|
||||||
requiredLayers.put(stack.ASCII(layer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> instanceExtensions = getInstanceExtensions();
|
PointerBuffer instanceExtensionsBuffer = instanceExtensions.writeToStack(stack);
|
||||||
|
PointerBuffer validationLayersBuffer = validationLayers.writeToStack(stack);
|
||||||
// GLFW Extension
|
|
||||||
PointerBuffer glfwExtensions = GLFWVulkan.glfwGetRequiredInstanceExtensions();
|
|
||||||
if (glfwExtensions == null) {
|
|
||||||
throw new RuntimeException("Failed to find the GLFW platform surface extensions");
|
|
||||||
}
|
|
||||||
|
|
||||||
PointerBuffer requiredExtensions;
|
|
||||||
|
|
||||||
boolean usePortability = instanceExtensions.contains(PORTABILITY_EXTENSION) &&
|
|
||||||
VulkanUtils.getOS() == VulkanUtils.OSType.MACOS;
|
|
||||||
if (!validationLayers.isEmpty()) {
|
|
||||||
ByteBuffer vkDebugUtilsExtension = stack.UTF8(EXTDebugUtils.VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
||||||
int numExtensions = usePortability ? glfwExtensions.remaining() + 2 : glfwExtensions.remaining() + 1;
|
|
||||||
requiredExtensions = stack.mallocPointer(numExtensions);
|
|
||||||
requiredExtensions.put(glfwExtensions).put(vkDebugUtilsExtension);
|
|
||||||
if (usePortability) {
|
|
||||||
requiredExtensions.put(stack.UTF8(PORTABILITY_EXTENSION));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int numExtensions = usePortability ? glfwExtensions.remaining() + 1 : glfwExtensions.remaining();
|
|
||||||
requiredExtensions = stack.mallocPointer(numExtensions);
|
|
||||||
requiredExtensions.put(glfwExtensions);
|
|
||||||
if (usePortability) {
|
|
||||||
requiredExtensions.put(stack.UTF8(KHRPortabilitySubset.VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requiredExtensions.flip();
|
|
||||||
|
|
||||||
long extension = MemoryUtil.NULL;
|
long extension = MemoryUtil.NULL;
|
||||||
if (!validationLayers.isEmpty()) {
|
if (validationLayers.hasValidationLayers()) {
|
||||||
debugUtils = createDebugCallBack();
|
debugUtils = createDebugCallBack();
|
||||||
extension = debugUtils.address();
|
extension = debugUtils.address();
|
||||||
}
|
}
|
||||||
|
@ -98,24 +61,23 @@ public class Instance {
|
||||||
.sType(VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)
|
.sType(VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)
|
||||||
.pNext(extension)
|
.pNext(extension)
|
||||||
.pApplicationInfo(appInfo)
|
.pApplicationInfo(appInfo)
|
||||||
.ppEnabledLayerNames(requiredLayers)
|
.ppEnabledLayerNames(validationLayersBuffer)
|
||||||
.ppEnabledExtensionNames(requiredExtensions);
|
.ppEnabledExtensionNames(instanceExtensionsBuffer);
|
||||||
if (usePortability) {
|
instanceExtensions.writeInstanceCreateInfoFlags(instanceInfo);
|
||||||
instanceInfo.flags(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
PointerBuffer pInstance = stack.mallocPointer(1);
|
PointerBuffer pInstance = stack.mallocPointer(1);
|
||||||
vkCheck(vkCreateInstance(instanceInfo, null, pInstance), "Error creating instance");
|
vkCheck(vkCreateInstance(instanceInfo, null, pInstance), "Error creating instance");
|
||||||
vkInstance = new VkInstance(pInstance.get(0), instanceInfo);
|
vkInstance = new VkInstance(pInstance.get(0), instanceInfo);
|
||||||
|
|
||||||
vkDebugHandle = VK_NULL_HANDLE;
|
vkDebugHandle = VK_NULL_HANDLE;
|
||||||
if (!validationLayers.isEmpty()) {
|
if (validationLayers.hasValidationLayers()) {
|
||||||
LongBuffer longBuff = stack.mallocLong(1);
|
LongBuffer longBuff = stack.mallocLong(1);
|
||||||
vkCheck(vkCreateDebugUtilsMessengerEXT(vkInstance, debugUtils, null, longBuff),
|
vkCheck(vkCreateDebugUtilsMessengerEXT(vkInstance, debugUtils, null, longBuff),
|
||||||
"Error creating debug utils");
|
"Error creating debug utils");
|
||||||
vkDebugHandle = longBuff.get(0);
|
vkDebugHandle = longBuff.get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Logger.debug("Vulkan instance created");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VkDebugUtilsMessengerCreateInfoEXT createDebugCallBack() {
|
private static VkDebugUtilsMessengerCreateInfoEXT createDebugCallBack() {
|
||||||
|
@ -152,26 +114,6 @@ public class Instance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getInstanceExtensions() {
|
|
||||||
Set<String> instanceExtensions = new HashSet<>();
|
|
||||||
try (MemoryStack stack = MemoryStack.stackPush()) {
|
|
||||||
IntBuffer numExtensionsBuf = stack.callocInt(1);
|
|
||||||
vkEnumerateInstanceExtensionProperties((String) null, numExtensionsBuf, null);
|
|
||||||
int numExtensions = numExtensionsBuf.get(0);
|
|
||||||
Logger.debug("Instance supports [{}] extensions", numExtensions);
|
|
||||||
|
|
||||||
VkExtensionProperties.Buffer instanceExtensionsProps = VkExtensionProperties.calloc(numExtensions, stack);
|
|
||||||
vkEnumerateInstanceExtensionProperties((String) null, numExtensionsBuf, instanceExtensionsProps);
|
|
||||||
for (int i = 0; i < numExtensions; i++) {
|
|
||||||
VkExtensionProperties props = instanceExtensionsProps.get(i);
|
|
||||||
String extensionName = props.extensionNameString();
|
|
||||||
instanceExtensions.add(extensionName);
|
|
||||||
Logger.debug("Supported instance extension [{}]", extensionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instanceExtensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VkInstance getVkInstance() {
|
public VkInstance getVkInstance() {
|
||||||
return vkInstance;
|
return vkInstance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
package fr.mrdev023.vulkan_java.vk.utils;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.lwjgl.PointerBuffer;
|
||||||
|
import org.lwjgl.glfw.GLFWVulkan;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.vulkan.EXTDebugUtils;
|
||||||
|
import org.lwjgl.vulkan.KHRPortabilityEnumeration;
|
||||||
|
import org.lwjgl.vulkan.VK10;
|
||||||
|
import org.lwjgl.vulkan.VkExtensionProperties;
|
||||||
|
import org.lwjgl.vulkan.VkInstanceCreateInfo;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @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) {
|
||||||
|
this.instanceExtensions = instanceExtensions;
|
||||||
|
this.glfwRequiredExtensions = glfwRequiredExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasInstanceExtensions() {
|
||||||
|
return !instanceExtensions.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getInstanceExtensions() {
|
||||||
|
return instanceExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointerBuffer writeToStack(MemoryStack stack) {
|
||||||
|
int numExtensions = instanceExtensions.size() + glfwRequiredExtensions.remaining();
|
||||||
|
PointerBuffer requiredExtensions = stack.mallocPointer(numExtensions);
|
||||||
|
|
||||||
|
requiredExtensions.put(glfwRequiredExtensions);
|
||||||
|
for (String extension : instanceExtensions) {
|
||||||
|
requiredExtensions.put(stack.UTF8(extension));
|
||||||
|
}
|
||||||
|
requiredExtensions.flip();
|
||||||
|
|
||||||
|
return requiredExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeInstanceCreateInfoFlags(VkInstanceCreateInfo instanceInfo) {
|
||||||
|
if (instanceExtensions.contains(KHRPortabilityEnumeration.VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) {
|
||||||
|
instanceInfo.flags(KHRPortabilityEnumeration.VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to automatically select the instance extensions
|
||||||
|
*
|
||||||
|
* <h5>Specification</h5>
|
||||||
|
* <ul>
|
||||||
|
* <li>Get the GLFW required extensions to create the Window Surface</li>
|
||||||
|
* <li>Get the portability extensions if the OS needs it</li>
|
||||||
|
* <li>Add Debug Utils extension if validation layers are enabled</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h5>See Also</h5>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #selectInstanceExtensions()}</li>
|
||||||
|
* <li>{@link #withValidationLayers(InstanceValidationLayers)}</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static class Selector {
|
||||||
|
private InstanceValidationLayers validationLayers;
|
||||||
|
|
||||||
|
public Selector withValidationLayers(InstanceValidationLayers validationLayers) {
|
||||||
|
this.validationLayers = validationLayers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the instance extensions.
|
||||||
|
*
|
||||||
|
* @return the set of instance extensions
|
||||||
|
*/
|
||||||
|
public InstanceExtensions selectInstanceExtensions() {
|
||||||
|
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> portabilityExtensions = getPortabilityExtensions(instanceExtensions);
|
||||||
|
log("Portability extensions used", portabilityExtensions);
|
||||||
|
|
||||||
|
Set<String> selectedExtensions = new HashSet<>();
|
||||||
|
selectedExtensions.addAll(portabilityExtensions);
|
||||||
|
|
||||||
|
if (validationLayers != null && validationLayers.hasValidationLayers()) {
|
||||||
|
selectedExtensions.add(EXTDebugUtils.VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
log("Selected instance extensions", selectedExtensions);
|
||||||
|
|
||||||
|
return new InstanceExtensions(selectedExtensions, glfwExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getInstanceExtensions() {
|
||||||
|
Set<String> instanceExtensions = new HashSet<>();
|
||||||
|
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
IntBuffer numExtensionsBuf = stack.callocInt(1);
|
||||||
|
VK10.vkEnumerateInstanceExtensionProperties((String) null, numExtensionsBuf, null);
|
||||||
|
int numExtensions = numExtensionsBuf.get(0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
String extensionName = props.extensionNameString();
|
||||||
|
instanceExtensions.add(extensionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instanceExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getPortabilityExtensions(Set<String> instanceExtensions) {
|
||||||
|
Set<String> portabilityExtensions = new HashSet<>();
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
portabilityExtensions.add(KHRPortabilityEnumeration.VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return portabilityExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String title, Set<String> layers) {
|
||||||
|
Logger.debug("{} ({})", title, layers.size());
|
||||||
|
for (String layer : layers) {
|
||||||
|
Logger.debug(" - {}", layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
package fr.mrdev023.vulkan_java.vk.utils;
|
||||||
|
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.lwjgl.PointerBuffer;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.vulkan.VK10;
|
||||||
|
import org.lwjgl.vulkan.VkLayerProperties;
|
||||||
|
import org.tinylog.Logger;
|
||||||
|
|
||||||
|
public class InstanceValidationLayers {
|
||||||
|
private Set<String> validationLayers;
|
||||||
|
|
||||||
|
private InstanceValidationLayers(Set<String> validationLayers) {
|
||||||
|
this.validationLayers = validationLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasValidationLayers() {
|
||||||
|
return !validationLayers.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getValidationLayers() {
|
||||||
|
return validationLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointerBuffer writeToStack(MemoryStack stack) {
|
||||||
|
if (validationLayers.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerBuffer requiredLayers = stack.mallocPointer(validationLayers.size());
|
||||||
|
for (String layer : validationLayers) {
|
||||||
|
requiredLayers.put(stack.UTF8(layer));
|
||||||
|
}
|
||||||
|
requiredLayers.flip();
|
||||||
|
|
||||||
|
return requiredLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to select the validation layers and create an InstanceValidationLayers object.
|
||||||
|
*
|
||||||
|
* <h5>Specification</h5>
|
||||||
|
* <ul>
|
||||||
|
* <li>Include the validation layers if the user wants them</li>
|
||||||
|
* <li>Select the validation layers from the supported validation layers</li>
|
||||||
|
* <li>Return an InstanceValidationLayers object with the selected validation layers</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h5>See Also</h5>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #includeValidationLayers(boolean)}</li>
|
||||||
|
* <li>{@link #selectValidationLayers()}</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static class Selector {
|
||||||
|
private boolean includeValidationLayers = false;
|
||||||
|
|
||||||
|
public Selector includeValidationLayers(boolean includeValidationLayers) {
|
||||||
|
this.includeValidationLayers = includeValidationLayers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the validation layers.
|
||||||
|
*
|
||||||
|
* @return the set of validation layers
|
||||||
|
*/
|
||||||
|
public InstanceValidationLayers selectValidationLayers() {
|
||||||
|
var supportedLayers = getSupportedValidationLayers();
|
||||||
|
log("Supported validation layers", supportedLayers);
|
||||||
|
|
||||||
|
Set<String> layersToUse = includeValidationLayers
|
||||||
|
? selectValidationLayersFromSupportedLayers(supportedLayers)
|
||||||
|
: Collections.emptySet();
|
||||||
|
log("Selected validation layers", layersToUse);
|
||||||
|
|
||||||
|
if (layersToUse.isEmpty() && includeValidationLayers) {
|
||||||
|
Logger.warn("Request validation but no supported validation layers found. Falling back to no validation");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InstanceValidationLayers(layersToUse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getSupportedValidationLayers() {
|
||||||
|
Set<String> supportedLayers = new HashSet<>();
|
||||||
|
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
// Get the number of supported validation layers by the current vulkan instance
|
||||||
|
IntBuffer numLayersArr = stack.callocInt(1);
|
||||||
|
VK10.vkEnumerateInstanceLayerProperties(numLayersArr, null);
|
||||||
|
int numLayers = numLayersArr.get(0);
|
||||||
|
|
||||||
|
// Get the supported validation layers by the current vulkan instance
|
||||||
|
VkLayerProperties.Buffer propsBuf = VkLayerProperties.calloc(numLayers, stack);
|
||||||
|
VK10.vkEnumerateInstanceLayerProperties(numLayersArr, propsBuf);
|
||||||
|
|
||||||
|
// Convert the supported validation layers to a list of strings
|
||||||
|
for (int i = 0; i < numLayers; i++) {
|
||||||
|
VkLayerProperties props = propsBuf.get(i);
|
||||||
|
String layerName = props.layerNameString();
|
||||||
|
supportedLayers.add(layerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return supportedLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> selectValidationLayersFromSupportedLayers(Set<String> supportedLayers) {
|
||||||
|
Set<String> layersToUse = new HashSet<>();
|
||||||
|
|
||||||
|
// Main validation layer
|
||||||
|
if (supportedLayers.contains("VK_LAYER_KHRONOS_validation")) {
|
||||||
|
layersToUse.add("VK_LAYER_KHRONOS_validation");
|
||||||
|
return layersToUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback 1
|
||||||
|
if (supportedLayers.contains("VK_LAYER_LUNARG_standard_validation")) {
|
||||||
|
layersToUse.add("VK_LAYER_LUNARG_standard_validation");
|
||||||
|
return layersToUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback 2 (set)
|
||||||
|
Set<String> requestedLayers = new HashSet<>();
|
||||||
|
requestedLayers.add("VK_LAYER_GOOGLE_threading");
|
||||||
|
requestedLayers.add("VK_LAYER_LUNARG_parameter_validation");
|
||||||
|
requestedLayers.add("VK_LAYER_LUNARG_object_tracker");
|
||||||
|
requestedLayers.add("VK_LAYER_LUNARG_core_validation");
|
||||||
|
requestedLayers.add("VK_LAYER_GOOGLE_unique_objects");
|
||||||
|
|
||||||
|
return requestedLayers.stream().filter(supportedLayers::contains).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String title, Set<String> layers) {
|
||||||
|
Logger.debug("{} ({})", title, layers.size());
|
||||||
|
for (String layer : layers) {
|
||||||
|
Logger.debug(" - {}", layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,94 +0,0 @@
|
||||||
package fr.mrdev023.vulkan_java.vk.utils;
|
|
||||||
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.lwjgl.system.MemoryStack;
|
|
||||||
import org.lwjgl.vulkan.VK10;
|
|
||||||
import org.lwjgl.vulkan.VkLayerProperties;
|
|
||||||
import org.tinylog.Logger;
|
|
||||||
|
|
||||||
public class InstanceValidationLayersSelector {
|
|
||||||
private boolean withValidationLayers = false;
|
|
||||||
|
|
||||||
public InstanceValidationLayersSelector withValidationLayers(boolean withValidationLayers) {
|
|
||||||
this.withValidationLayers = withValidationLayers;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> selectValidationLayers() {
|
|
||||||
if (!withValidationLayers) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
var supportedLayers = getSupportedValidationLayers();
|
|
||||||
log("Supported validation layers", supportedLayers);
|
|
||||||
|
|
||||||
var layersToUse = selectValidationLayersFromSupportedLayers(supportedLayers);
|
|
||||||
log("Selected validation layers", layersToUse);
|
|
||||||
|
|
||||||
if (layersToUse.isEmpty() && withValidationLayers) {
|
|
||||||
Logger.warn("Request validation but no supported validation layers found. Falling back to no validation");
|
|
||||||
}
|
|
||||||
|
|
||||||
return layersToUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getSupportedValidationLayers() {
|
|
||||||
try (MemoryStack stack = MemoryStack.stackPush()) {
|
|
||||||
// Get the number of supported validation layers by the current vulkan instance
|
|
||||||
IntBuffer numLayersArr = stack.callocInt(1);
|
|
||||||
VK10.vkEnumerateInstanceLayerProperties(numLayersArr, null);
|
|
||||||
int numLayers = numLayersArr.get(0);
|
|
||||||
|
|
||||||
// Get the supported validation layers by the current vulkan instance
|
|
||||||
VkLayerProperties.Buffer propsBuf = VkLayerProperties.calloc(numLayers, stack);
|
|
||||||
VK10.vkEnumerateInstanceLayerProperties(numLayersArr, propsBuf);
|
|
||||||
|
|
||||||
// Convert the supported validation layers to a list of strings
|
|
||||||
List<String> supportedLayers = new ArrayList<>();
|
|
||||||
for (int i = 0; i < numLayers; i++) {
|
|
||||||
VkLayerProperties props = propsBuf.get(i);
|
|
||||||
String layerName = props.layerNameString();
|
|
||||||
supportedLayers.add(layerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return supportedLayers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> selectValidationLayersFromSupportedLayers(List<String> supportedLayers) {
|
|
||||||
List<String> layersToUse = new ArrayList<>();
|
|
||||||
|
|
||||||
// Main validation layer
|
|
||||||
if (supportedLayers.contains("VK_LAYER_KHRONOS_validation")) {
|
|
||||||
layersToUse.add("VK_LAYER_KHRONOS_validation");
|
|
||||||
return layersToUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback 1
|
|
||||||
if (supportedLayers.contains("VK_LAYER_LUNARG_standard_validation")) {
|
|
||||||
layersToUse.add("VK_LAYER_LUNARG_standard_validation");
|
|
||||||
return layersToUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback 2 (set)
|
|
||||||
List<String> requestedLayers = new ArrayList<>();
|
|
||||||
requestedLayers.add("VK_LAYER_GOOGLE_threading");
|
|
||||||
requestedLayers.add("VK_LAYER_LUNARG_parameter_validation");
|
|
||||||
requestedLayers.add("VK_LAYER_LUNARG_object_tracker");
|
|
||||||
requestedLayers.add("VK_LAYER_LUNARG_core_validation");
|
|
||||||
requestedLayers.add("VK_LAYER_GOOGLE_unique_objects");
|
|
||||||
|
|
||||||
return requestedLayers.stream().filter(supportedLayers::contains).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void log(String title, List<String> layers) {
|
|
||||||
Logger.debug("{} ({})", title, layers.size());
|
|
||||||
for (String layer : layers) {
|
|
||||||
Logger.debug(" - {}", layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue