diff --git a/res/org/lwjgl/demo/opengl/shader/downsampling/downsample.cs.glsl b/res/org/lwjgl/demo/opengl/shader/downsampling/downsample.cs.glsl index 76fde7e8..ee2a8429 100644 --- a/res/org/lwjgl/demo/opengl/shader/downsampling/downsample.cs.glsl +++ b/res/org/lwjgl/demo/opengl/shader/downsampling/downsample.cs.glsl @@ -6,7 +6,7 @@ #extension GL_KHR_shader_subgroup_shuffle : require layout(location=0) uniform sampler2D baseImage; -layout(binding=0, rgba16f) uniform writeonly restrict image2D mips[3]; +layout(binding=0, rgba16f) uniform writeonly restrict image2D mips[5]; /* * The assumption here is that each subgroup item maps to its corresponding local workgroup item @@ -30,6 +30,8 @@ int unpack(int x) { return x; } +shared vec4 sm[4][4]; + void main(void) { ivec2 ts = textureSize(baseImage, 0); @@ -78,4 +80,31 @@ void main(void) { t = (t + h + v + d) * vec4(0.25); if ((gl_SubgroupInvocationID & 15) == 0) imageStore(mips[2], i/ivec2(4), t); + + // compute mip 4 using shared memory + /* + * For mip 4 we essentially have 8x8 work items. + */ + ivec2 smc = l / ivec2(4); + ivec2 smi = (smc + ivec2(1)) & ivec2(1); + if ((l.x & 3) == 0 && (l.y & 3) == 0) + sm[smc.x][smc.y] = t; + barrier(); + if ((l.x & 7) == 0 && (l.y & 7) == 0) { + t = (sm[smc.x][smc.y] + sm[smi.x][smc.y] + sm[smc.x][smi.y] + sm[smi.x][smi.y]) * 0.25; + imageStore(mips[3], i/ivec2(8), t); + } + + // compute mip 5 also using shared memory + /* + * For mip 5 we have 16x16 work items. + */ + smc = l / ivec2(8); + if ((l.x & 7) == 0 && (l.y & 7) == 0) + sm[smc.x][smc.y] = t; + barrier(); + if (l.x == 0 && l.y == 0) { + t = (sm[0][0] + sm[1][0] + sm[0][1] + sm[1][1]) * 0.25; + imageStore(mips[4], i/ivec2(16), t); + } } diff --git a/src/org/lwjgl/demo/opengl/shader/DownsamplingDemo.java b/src/org/lwjgl/demo/opengl/shader/DownsamplingDemo.java index d0d99853..8409d668 100644 --- a/src/org/lwjgl/demo/opengl/shader/DownsamplingDemo.java +++ b/src/org/lwjgl/demo/opengl/shader/DownsamplingDemo.java @@ -14,6 +14,7 @@ import java.nio.ByteBuffer; import java.nio.IntBuffer; +import org.joml.Random; import org.lwjgl.demo.opengl.util.DemoUtils; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GLCapabilities; @@ -25,6 +26,7 @@ /** * Computes 3 mip levels of a texture using only a single compute shader dispatch * and GL_KHR_shader_subgroup. + * Then uses shared memory for mips 4 and 5. * * @author Kai Burjack */ @@ -97,8 +99,9 @@ private static void createComputeProgram() throws IOException { computeProgram = program; } + private static final Random rnd = new Random(1L); private static byte v(int i) { - return i % 8 == 0 ? (byte) 255 : (byte) 0; + return (byte) (rnd.nextFloat() * 255); } private static void createTextures() { @@ -108,12 +111,14 @@ private static void createTextures() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexStorage2D(GL_TEXTURE_2D, 4, GL_RGBA16F, width, height); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6); + glTexStorage2D(GL_TEXTURE_2D, 6, GL_RGBA16F, width, height); ByteBuffer pixels = MemoryUtil.memAlloc(width * height * 4); // fill the first level of the texture with some pattern for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) - pixels.put(v(x)).put(v(y)).put((byte) 127).put((byte) 255); + pixels.put(v(x)).put(v(y)).put(v(x)).put((byte) 255); pixels.flip(); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); MemoryUtil.memFree(pixels); @@ -125,10 +130,12 @@ private static void downsample() { // read mip level 0 glBindTexture(GL_TEXTURE_2D, texture); - // write mip levels 1-3 + // write mip levels 1-4 glBindImageTexture(0, texture, 1, false, 0, GL_WRITE_ONLY, GL_RGBA16F); glBindImageTexture(1, texture, 2, false, 0, GL_WRITE_ONLY, GL_RGBA16F); glBindImageTexture(2, texture, 3, false, 0, GL_WRITE_ONLY, GL_RGBA16F); + glBindImageTexture(3, texture, 4, false, 0, GL_WRITE_ONLY, GL_RGBA16F); + glBindImageTexture(4, texture, 5, false, 0, GL_WRITE_ONLY, GL_RGBA16F); int texelsPerWorkItem = 2; int numGroupsX = (int) ceil((double) width / texelsPerWorkItem / 16); @@ -142,12 +149,14 @@ private static void downsample() { glBindImageTexture(0, 0, 1, false, 0, GL_WRITE_ONLY, GL_RGBA16F); glBindImageTexture(1, 0, 2, false, 0, GL_WRITE_ONLY, GL_RGBA16F); glBindImageTexture(2, 0, 3, false, 0, GL_WRITE_ONLY, GL_RGBA16F); + glBindImageTexture(3, 0, 3, false, 0, GL_WRITE_ONLY, GL_RGBA16F); + glBindImageTexture(4, 0, 3, false, 0, GL_WRITE_ONLY, GL_RGBA16F); glUseProgram(0); } private static void present() { glClear(GL_COLOR_BUFFER_BIT); - glViewport(0, 0, width/(1< supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -198,7 +204,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_1)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); @@ -344,6 +350,20 @@ private static DeviceAndQueueFamilies selectBestPhysicalDevice() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkDevice createDevice(List requiredExtensions) { List supportedDeviceExtensions = enumerateSupportedDeviceExtensions(); for (String requiredExtension : requiredExtensions) { diff --git a/src/org/lwjgl/demo/vulkan/raytracing/HybridMagicaVoxel.java b/src/org/lwjgl/demo/vulkan/raytracing/HybridMagicaVoxel.java index bce9a869..127b0009 100644 --- a/src/org/lwjgl/demo/vulkan/raytracing/HybridMagicaVoxel.java +++ b/src/org/lwjgl/demo/vulkan/raytracing/HybridMagicaVoxel.java @@ -6,6 +6,7 @@ import static java.lang.ClassLoader.getSystemResourceAsStream; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static org.joml.Math.*; import static org.lwjgl.demo.vulkan.VKUtil.*; @@ -277,6 +278,20 @@ private static List enumerateSupportedInstanceExtensions() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkInstance createInstance(PointerBuffer requiredExtensions) { List supportedInstanceExtensions = enumerateSupportedInstanceExtensions(); try (MemoryStack stack = stackPush()) { @@ -287,9 +302,14 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { } ppEnabledExtensionNames = pointers(stack, requiredExtensions, stack.UTF8(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)); } - PointerBuffer enabledLayers = null; + PointerBuffer ppEnabledLayerNames = null; if (DEBUG) { - enabledLayers = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + List supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -298,7 +318,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_2)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); diff --git a/src/org/lwjgl/demo/vulkan/raytracing/ReflectiveMagicaVoxel.java b/src/org/lwjgl/demo/vulkan/raytracing/ReflectiveMagicaVoxel.java index 18789f62..1a4c07ea 100644 --- a/src/org/lwjgl/demo/vulkan/raytracing/ReflectiveMagicaVoxel.java +++ b/src/org/lwjgl/demo/vulkan/raytracing/ReflectiveMagicaVoxel.java @@ -6,6 +6,7 @@ import static java.lang.ClassLoader.getSystemResourceAsStream; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static org.joml.Math.*; import static org.lwjgl.demo.vulkan.VKUtil.*; @@ -273,9 +274,14 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { } ppEnabledExtensionNames = pointers(stack, requiredExtensions, stack.UTF8(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)); } - PointerBuffer enabledLayers = null; + PointerBuffer ppEnabledLayerNames = null; if (DEBUG) { - enabledLayers = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + List supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -284,7 +290,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_1)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); @@ -475,6 +481,20 @@ private static DeviceAndQueueFamilies selectPhysicalDevice() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkDevice createDevice(List requiredExtensions) { List supportedDeviceExtensions = enumerateSupportedDeviceExtensions(); for (String requiredExtension : requiredExtensions) { diff --git a/src/org/lwjgl/demo/vulkan/raytracing/SdfBricks.java b/src/org/lwjgl/demo/vulkan/raytracing/SdfBricks.java index 04723c4c..f3d5a4c7 100644 --- a/src/org/lwjgl/demo/vulkan/raytracing/SdfBricks.java +++ b/src/org/lwjgl/demo/vulkan/raytracing/SdfBricks.java @@ -6,6 +6,7 @@ import static java.lang.ClassLoader.getSystemResourceAsStream; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static org.joml.Math.*; import static org.lwjgl.demo.vulkan.VKUtil.*; @@ -271,9 +272,14 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { } ppEnabledExtensionNames = pointers(stack, requiredExtensions, stack.UTF8(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)); } - PointerBuffer enabledLayers = null; + PointerBuffer ppEnabledLayerNames = null; if (DEBUG) { - enabledLayers = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + List supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -282,7 +288,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_1)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); @@ -471,6 +477,20 @@ private static DeviceAndQueueFamilies selectPhysicalDevice() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkDevice createDevice(List requiredExtensions) { List supportedDeviceExtensions = enumerateSupportedDeviceExtensions(); for (String requiredExtension : requiredExtensions) { @@ -989,7 +1009,7 @@ private static VoxelField buildVoxelField() throws IOException { Vector3i min = new Vector3i(Integer.MAX_VALUE); Vector3i max = new Vector3i(Integer.MIN_VALUE); byte[] field = new byte[(256 + 2) * (256 + 2) * (256 + 2)]; - try (InputStream is = getSystemResourceAsStream("org/lwjgl/demo/models/mikelovesrobots_mmmm/scene_house5.vox"); + try (InputStream is = getSystemResourceAsStream("voxelmodel/vox/monument/monu2.vox"); BufferedInputStream bis = new BufferedInputStream(is)) { new MagicaVoxelLoader().read(bis, new MagicaVoxelLoader.Callback() { public void voxel(int x, int y, int z, byte c) { @@ -1022,8 +1042,8 @@ private static Geometry createGeometry() throws IOException { int[] num = {0}; new GreedyVoxels(voxelField.ny, voxelField.py, voxelField.w, voxelField.d, new GreedyVoxels.Callback() { public void voxel(int x0, int y0, int z0, int w, int h, int d, int v) { - aabbs.putFloat(x0).putFloat(y0).putFloat(z0); - aabbs.putFloat(x0+w).putFloat(y0+h+0.1f).putFloat(z0+d); + aabbs.putFloat(x0*8).putFloat(y0*9.6f).putFloat(z0*8); + aabbs.putFloat((x0+w)*8).putFloat((y0+h)*9.6f+1.8f).putFloat((z0+d)*8); num[0]++; } }).merge(voxelField.field); diff --git a/src/org/lwjgl/demo/vulkan/raytracing/SimpleSphere.java b/src/org/lwjgl/demo/vulkan/raytracing/SimpleSphere.java index 2e32ef58..973065ce 100644 --- a/src/org/lwjgl/demo/vulkan/raytracing/SimpleSphere.java +++ b/src/org/lwjgl/demo/vulkan/raytracing/SimpleSphere.java @@ -5,6 +5,7 @@ package org.lwjgl.demo.vulkan.raytracing; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static java.util.stream.IntStream.range; import static org.joml.Math.*; @@ -245,9 +246,14 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { } ppEnabledExtensionNames = pointers(stack, requiredExtensions, stack.UTF8(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)); } - PointerBuffer enabledLayers = null; + PointerBuffer ppEnabledLayerNames = null; if (DEBUG) { - enabledLayers = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + List supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -256,7 +262,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_1)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); @@ -438,6 +444,20 @@ private static DeviceAndQueueFamilies selectPhysicalDevice() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkDevice createDevice(List requiredExtensions) { List supportedDeviceExtensions = enumerateSupportedDeviceExtensions(); for (String requiredExtension : requiredExtensions) { diff --git a/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangle.java b/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangle.java index f373320a..a681fd7f 100644 --- a/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangle.java +++ b/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangle.java @@ -5,6 +5,7 @@ package org.lwjgl.demo.vulkan.raytracing; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static java.util.stream.IntStream.range; import static org.joml.Math.*; @@ -244,9 +245,14 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { } ppEnabledExtensionNames = pointers(stack, requiredExtensions, stack.UTF8(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)); } - PointerBuffer enabledLayers = null; + PointerBuffer ppEnabledLayerNames = null; if (DEBUG) { - enabledLayers = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + List supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -255,7 +261,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_1)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); @@ -439,6 +445,20 @@ private static DeviceAndQueueFamilies selectPhysicalDevice() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkDevice createDevice(List requiredExtensions) { List supportedDeviceExtensions = enumerateSupportedDeviceExtensions(); for (String requiredExtension : requiredExtensions) { diff --git a/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangleRayQuery.java b/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangleRayQuery.java index af35d75a..3bcebe44 100644 --- a/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangleRayQuery.java +++ b/src/org/lwjgl/demo/vulkan/raytracing/SimpleTriangleRayQuery.java @@ -5,6 +5,7 @@ package org.lwjgl.demo.vulkan.raytracing; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import static java.util.stream.IntStream.range; import static org.joml.Math.*; @@ -240,9 +241,14 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { } ppEnabledExtensionNames = pointers(stack, requiredExtensions, stack.UTF8(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)); } - PointerBuffer enabledLayers = null; + PointerBuffer ppEnabledLayerNames = null; if (DEBUG) { - enabledLayers = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + List supportedLayers = enumerateSupportedInstanceLayers(); + if (!supportedLayers.contains("VK_LAYER_KHRONOS_validation")) { + System.err.println("DEBUG requested but layer VK_LAYER_KHRONOS_validation is unavailable. Install the Vulkan SDK for your platform. Vulkan debug layer will not be used."); + } else { + ppEnabledLayerNames = stack.pointers(stack.UTF8("VK_LAYER_KHRONOS_validation")); + } } VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo .calloc(stack) @@ -251,7 +257,7 @@ private static VkInstance createInstance(PointerBuffer requiredExtensions) { .calloc(stack) .sType$Default() .apiVersion(VK_API_VERSION_1_1)) - .ppEnabledLayerNames(enabledLayers) + .ppEnabledLayerNames(ppEnabledLayerNames) .ppEnabledExtensionNames(ppEnabledExtensionNames); PointerBuffer pInstance = stack.mallocPointer(1); _CHECK_(vkCreateInstance(pCreateInfo, null, pInstance), "Failed to create VkInstance"); @@ -430,6 +436,20 @@ private static DeviceAndQueueFamilies selectPhysicalDevice() { } } + private static final List enumerateSupportedInstanceLayers() { + try (MemoryStack stack = stackPush()) { + IntBuffer pPropertyCount = stack.mallocInt(1); + vkEnumerateInstanceLayerProperties(pPropertyCount, null); + int count = pPropertyCount.get(0); + if (count > 0) { + VkLayerProperties.Buffer pProperties = VkLayerProperties.malloc(count, stack); + vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties); + return pProperties.stream().map(VkLayerProperties::layerNameString).collect(toList()); + } + } + return emptyList(); + } + private static VkDevice createDevice(List requiredExtensions) { List supportedDeviceExtensions = enumerateSupportedDeviceExtensions(); for (String requiredExtension : requiredExtensions) {