Refactor instance validation layers selection

This commit is contained in:
Florian RICHER 2025-05-20 18:46:16 +02:00
parent 9f713edf62
commit c09b04dc81
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
2 changed files with 106 additions and 60 deletions

View file

@ -6,6 +6,8 @@ import org.lwjgl.system.*;
import org.lwjgl.vulkan.*;
import org.tinylog.Logger;
import fr.mrdev023.vulkan_java.vk.utils.InstanceValidationLayersSelector;
import java.nio.*;
import java.util.*;
@ -42,23 +44,16 @@ public class Instance {
.apiVersion(VK_API_VERSION_1_1);
// Validation layers
List<String> validationLayers = getSupportedValidationLayers();
int numValidationLayers = validationLayers.size();
boolean supportsValidation = validate;
if (validate && numValidationLayers == 0) {
supportsValidation = false;
Logger.warn(
"Request validation but no supported validation layers found. Falling back to no validation");
}
Logger.debug("Validation: {}", supportsValidation);
var validationLayers = new InstanceValidationLayersSelector()
.withValidationLayers(validate)
.selectValidationLayers();
// Set required layers
PointerBuffer requiredLayers = null;
if (supportsValidation) {
requiredLayers = stack.mallocPointer(numValidationLayers);
for (int i = 0; i < numValidationLayers; i++) {
Logger.debug("Using validation layer [{}]", validationLayers.get(i));
requiredLayers.put(i, stack.ASCII(validationLayers.get(i)));
if (!validationLayers.isEmpty()) {
requiredLayers = stack.mallocPointer(validationLayers.size());
for (String layer : validationLayers) {
requiredLayers.put(stack.ASCII(layer));
}
}
@ -74,7 +69,7 @@ public class Instance {
boolean usePortability = instanceExtensions.contains(PORTABILITY_EXTENSION) &&
VulkanUtils.getOS() == VulkanUtils.OSType.MACOS;
if (supportsValidation) {
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);
@ -93,7 +88,7 @@ public class Instance {
requiredExtensions.flip();
long extension = MemoryUtil.NULL;
if (supportsValidation) {
if (!validationLayers.isEmpty()) {
debugUtils = createDebugCallBack();
extension = debugUtils.address();
}
@ -114,7 +109,7 @@ public class Instance {
vkInstance = new VkInstance(pInstance.get(0), instanceInfo);
vkDebugHandle = VK_NULL_HANDLE;
if (supportsValidation) {
if (!validationLayers.isEmpty()) {
LongBuffer longBuff = stack.mallocLong(1);
vkCheck(vkCreateDebugUtilsMessengerEXT(vkInstance, debugUtils, null, longBuff),
"Error creating debug utils");
@ -177,49 +172,6 @@ public class Instance {
return instanceExtensions;
}
private List<String> getSupportedValidationLayers() {
try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer numLayersArr = stack.callocInt(1);
vkEnumerateInstanceLayerProperties(numLayersArr, null);
int numLayers = numLayersArr.get(0);
Logger.debug("Instance supports [{}] layers", numLayers);
VkLayerProperties.Buffer propsBuf = VkLayerProperties.calloc(numLayers, stack);
vkEnumerateInstanceLayerProperties(numLayersArr, propsBuf);
List<String> supportedLayers = new ArrayList<>();
for (int i = 0; i < numLayers; i++) {
VkLayerProperties props = propsBuf.get(i);
String layerName = props.layerNameString();
supportedLayers.add(layerName);
Logger.debug("Supported layer [{}]", layerName);
}
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();
}
}
public VkInstance getVkInstance() {
return vkInstance;
}

View file

@ -0,0 +1,94 @@
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);
}
}
}