From 3667e4b03b8f91a573a1f5b4c55ee1177b986dd1 Mon Sep 17 00:00:00 2001 From: knokko Date: Sun, 31 Dec 2023 00:30:38 +0100 Subject: [PATCH] Add support for video coding queue families --- .../boiler/builder/BoilerDeviceBuilder.java | 28 ++-- .../queue/MinimalQueueFamilyMapper.java | 65 ++++++--- .../builder/queue/QueueFamilyAllocation.java | 4 + .../builder/queue/QueueFamilyMapper.java | 8 +- .../builder/queue/QueueFamilyMapping.java | 39 +++-- .../knokko/boiler/queue/QueueFamilies.java | 4 +- .../boiler/queue/TestMinimalQueueMapper.java | 134 +++++++++++++++--- 7 files changed, 224 insertions(+), 58 deletions(-) create mode 100644 src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyAllocation.java diff --git a/src/main/java/com/github/knokko/boiler/builder/BoilerDeviceBuilder.java b/src/main/java/com/github/knokko/boiler/builder/BoilerDeviceBuilder.java index d8c544f..4f82d3a 100644 --- a/src/main/java/com/github/knokko/boiler/builder/BoilerDeviceBuilder.java +++ b/src/main/java/com/github/knokko/boiler/builder/BoilerDeviceBuilder.java @@ -156,15 +156,23 @@ static Result createDevice(BoilerBuilder builder, BoilerInstanceBuilder.Result i } else queueFamilyPresentSupport[familyIndex] = true; } - var queueFamilyMapping = builder.queueFamilyMapper.mapQueueFamilies(pQueueFamilies, queueFamilyPresentSupport); + var queueFamilyMapping = builder.queueFamilyMapper.mapQueueFamilies( + pQueueFamilies, enabledExtensions, queueFamilyPresentSupport + ); queueFamilyMapping.validate(); var uniqueQueueFamilies = new HashMap(); // Do presentFamily first so that it will be overwritten by the others if the queue family is shared uniqueQueueFamilies.put(queueFamilyMapping.presentFamilyIndex(), new float[] { 1f }); - uniqueQueueFamilies.put(queueFamilyMapping.graphicsFamilyIndex(), queueFamilyMapping.graphicsPriorities()); - uniqueQueueFamilies.put(queueFamilyMapping.computeFamilyIndex(), queueFamilyMapping.computePriorities()); - uniqueQueueFamilies.put(queueFamilyMapping.transferFamilyIndex(), queueFamilyMapping.transferPriorities()); + uniqueQueueFamilies.put(queueFamilyMapping.graphics().index(), queueFamilyMapping.graphics().priorities()); + uniqueQueueFamilies.put(queueFamilyMapping.compute().index(), queueFamilyMapping.compute().priorities()); + uniqueQueueFamilies.put(queueFamilyMapping.transfer().index(), queueFamilyMapping.transfer().priorities()); + if (queueFamilyMapping.videoEncode() != null) { + uniqueQueueFamilies.put(queueFamilyMapping.videoEncode().index(), queueFamilyMapping.videoEncode().priorities()); + } + if (queueFamilyMapping.videoDecode() != null) { + uniqueQueueFamilies.put(queueFamilyMapping.videoDecode().index(), queueFamilyMapping.videoDecode().priorities()); + } var pQueueCreateInfos = VkDeviceQueueCreateInfo.calloc(uniqueQueueFamilies.size(), stack); int ciQueueIndex = 0; @@ -200,11 +208,15 @@ static Result createDevice(BoilerBuilder builder, BoilerInstanceBuilder.Result i queueFamilyMap.put(entry.getKey(), getQueueFamily(stack, vkDevice, entry.getKey(), entry.getValue().length)); } + int videoEncodeIndex = queueFamilyMapping.videoEncode() != null ? queueFamilyMapping.videoEncode().index() : -1; + int videoDecodeIndex = queueFamilyMapping.videoDecode() != null ? queueFamilyMapping.videoDecode().index() : -1; queueFamilies = new QueueFamilies( - queueFamilyMap.get(queueFamilyMapping.graphicsFamilyIndex()), - queueFamilyMap.get(queueFamilyMapping.computeFamilyIndex()), - queueFamilyMap.get(queueFamilyMapping.transferFamilyIndex()), - queueFamilyMap.get(queueFamilyMapping.presentFamilyIndex()) + queueFamilyMap.get(queueFamilyMapping.graphics().index()), + queueFamilyMap.get(queueFamilyMapping.compute().index()), + queueFamilyMap.get(queueFamilyMapping.transfer().index()), + queueFamilyMap.get(queueFamilyMapping.presentFamilyIndex()), + queueFamilyMap.get(videoEncodeIndex), + queueFamilyMap.get(videoDecodeIndex) ); var vmaVulkanFunctions = VmaVulkanFunctions.calloc(stack); diff --git a/src/main/java/com/github/knokko/boiler/builder/queue/MinimalQueueFamilyMapper.java b/src/main/java/com/github/knokko/boiler/builder/queue/MinimalQueueFamilyMapper.java index 8fa9001..5cebb87 100644 --- a/src/main/java/com/github/knokko/boiler/builder/queue/MinimalQueueFamilyMapper.java +++ b/src/main/java/com/github/knokko/boiler/builder/queue/MinimalQueueFamilyMapper.java @@ -2,17 +2,49 @@ import org.lwjgl.vulkan.VkQueueFamilyProperties; +import java.util.Set; + +import static org.lwjgl.vulkan.KHRVideoDecodeQueue.VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME; +import static org.lwjgl.vulkan.KHRVideoDecodeQueue.VK_QUEUE_VIDEO_DECODE_BIT_KHR; +import static org.lwjgl.vulkan.KHRVideoEncodeQueue.VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME; +import static org.lwjgl.vulkan.KHRVideoEncodeQueue.VK_QUEUE_VIDEO_ENCODE_BIT_KHR; import static org.lwjgl.vulkan.VK10.VK_QUEUE_COMPUTE_BIT; import static org.lwjgl.vulkan.VK10.VK_QUEUE_GRAPHICS_BIT; public class MinimalQueueFamilyMapper implements QueueFamilyMapper { @Override - public QueueFamilyMapping mapQueueFamilies(VkQueueFamilyProperties.Buffer queueFamilies, boolean[] presentSupport) { + public QueueFamilyMapping mapQueueFamilies( + VkQueueFamilyProperties.Buffer queueFamilies, + Set deviceExtensions, + boolean[] presentSupport + ) { float[] priorities = { 1f }; - int graphicsFamilyIndex = -1; - int computeFamilyIndex = -1; - int presentFamilyIndex = -1; + + boolean shouldTryEncode = deviceExtensions.contains(VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME); + boolean shouldTryDecode = deviceExtensions.contains(VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME); + int encodeIndex = -1; + int decodeIndex = -1; + for (int familyIndex = 0; familyIndex < queueFamilies.limit(); familyIndex++) { + int queueFlags = queueFamilies.get(familyIndex).queueFlags(); + boolean hasEncode = shouldTryEncode && (queueFlags & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) != 0; + boolean hasDecode = shouldTryDecode && (queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) != 0; + if (hasEncode && hasDecode) { + encodeIndex = familyIndex; + decodeIndex = familyIndex; + break; + } + + if (encodeIndex == -1 && hasEncode) encodeIndex = familyIndex; + if (decodeIndex == -1 && hasDecode) decodeIndex = familyIndex; + } + + var videoEncode = encodeIndex != -1 ? new QueueFamilyAllocation(encodeIndex, priorities) : null; + var videoDecode = decodeIndex != -1 ? new QueueFamilyAllocation(decodeIndex, priorities) : null; + + int graphicsIndex = -1; + int computeIndex = -1; + int presentIndex = -1; for (int familyIndex = 0; familyIndex < queueFamilies.limit(); familyIndex++) { int queueFlags = queueFamilies.get(familyIndex).queueFlags(); @@ -21,26 +53,27 @@ public QueueFamilyMapping mapQueueFamilies(VkQueueFamilyProperties.Buffer queueF boolean hasPresent = presentSupport[familyIndex]; if (hasGraphics && hasCompute && hasPresent) { - return new QueueFamilyMapping( - familyIndex, priorities, familyIndex, priorities, familyIndex, priorities, familyIndex - ); + var allocation = new QueueFamilyAllocation(familyIndex, priorities); + return new QueueFamilyMapping(allocation, allocation, allocation, videoEncode, videoDecode, familyIndex); } - if (graphicsFamilyIndex == -1 && hasGraphics) graphicsFamilyIndex = familyIndex; - if (computeFamilyIndex == -1 && hasCompute) computeFamilyIndex = familyIndex; + if (graphicsIndex == -1 && hasGraphics) graphicsIndex = familyIndex; + if (computeIndex == -1 && hasCompute) computeIndex = familyIndex; if (hasGraphics && hasCompute) { - graphicsFamilyIndex = familyIndex; - computeFamilyIndex = familyIndex; + graphicsIndex = familyIndex; + computeIndex = familyIndex; } - if (presentFamilyIndex == -1 && hasPresent) presentFamilyIndex = familyIndex; - if ((hasGraphics || hasCompute) && hasPresent) presentFamilyIndex = familyIndex; + if (presentIndex == -1 && hasPresent) presentIndex = familyIndex; + if ((hasGraphics || hasCompute) && hasPresent) presentIndex = familyIndex; } + return new QueueFamilyMapping( - graphicsFamilyIndex, priorities, - computeFamilyIndex, priorities, - graphicsFamilyIndex, priorities, presentFamilyIndex + new QueueFamilyAllocation(graphicsIndex, priorities), + new QueueFamilyAllocation(computeIndex, priorities), + new QueueFamilyAllocation(graphicsIndex, priorities), + videoEncode, videoDecode, presentIndex ); } } diff --git a/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyAllocation.java b/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyAllocation.java new file mode 100644 index 0000000..1b38024 --- /dev/null +++ b/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyAllocation.java @@ -0,0 +1,4 @@ +package com.github.knokko.boiler.builder.queue; + +public record QueueFamilyAllocation(int index, float[] priorities) { +} diff --git a/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapper.java b/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapper.java index ec633d3..5c8554f 100644 --- a/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapper.java +++ b/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapper.java @@ -2,8 +2,14 @@ import org.lwjgl.vulkan.VkQueueFamilyProperties; +import java.util.Set; + @FunctionalInterface public interface QueueFamilyMapper { - QueueFamilyMapping mapQueueFamilies(VkQueueFamilyProperties.Buffer queueFamilies, boolean[] presentSupport); + QueueFamilyMapping mapQueueFamilies( + VkQueueFamilyProperties.Buffer queueFamilies, + Set deviceExtensions, + boolean[] presentSupport + ); } diff --git a/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapping.java b/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapping.java index 2038df8..3b078d2 100644 --- a/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapping.java +++ b/src/main/java/com/github/knokko/boiler/builder/queue/QueueFamilyMapping.java @@ -3,26 +3,45 @@ import java.util.Arrays; public record QueueFamilyMapping( - int graphicsFamilyIndex, float[] graphicsPriorities, - int computeFamilyIndex, float[] computePriorities, - int transferFamilyIndex, float[] transferPriorities, + QueueFamilyAllocation graphics, + QueueFamilyAllocation compute, + QueueFamilyAllocation transfer, + QueueFamilyAllocation videoEncode, + QueueFamilyAllocation videoDecode, int presentFamilyIndex ) { public void validate() throws IllegalStateException { - validateFamilyPriorities(graphicsFamilyIndex, computeFamilyIndex, graphicsPriorities, computePriorities, "graphics", "compute"); - validateFamilyPriorities(graphicsFamilyIndex, transferFamilyIndex, graphicsPriorities, transferPriorities, "graphics", "transfer"); - validateFamilyPriorities(computeFamilyIndex, transferFamilyIndex, computePriorities, transferPriorities, "compute", "transfer"); + validateFamilyPriorities(graphics, compute, "graphics", "compute"); + validateFamilyPriorities(graphics, transfer, "graphics", "transfer"); + validateFamilyPriorities(compute, transfer, "compute", "transfer"); + if (videoEncode != null) { + validateFamilyPriorities(graphics, videoEncode, "graphics", "videoEncode"); + validateFamilyPriorities(compute, videoEncode, "compute", "videoEncode"); + validateFamilyPriorities(transfer, videoEncode, "transfer", "videoEncode"); + } + if (videoDecode != null) { + validateFamilyPriorities(graphics, videoDecode, "graphics", "videoDecode"); + validateFamilyPriorities(compute, videoDecode, "compute", "videoDecode"); + validateFamilyPriorities(transfer, videoDecode, "transfer", "videoDecode"); + } + if (videoEncode != null && videoDecode != null) { + validateFamilyPriorities(videoEncode, videoDecode, "videoEncode", "videoDecode"); + } } private void validateFamilyPriorities( - int index1, int index2, float[] priorities1, float[] priorities2, String name1, String name2 + QueueFamilyAllocation allocation1, QueueFamilyAllocation allocation2, String name1, String name2 ) throws IllegalStateException { - if (priorities1 == null || priorities2 == null) throw new IllegalStateException("Priorities are null"); - if (index1 == index2 && !Arrays.equals(priorities1, priorities2)) { + if (allocation1.priorities() == null || allocation2.priorities() == null) { + throw new IllegalStateException("Priorities are null"); + } + if (allocation1.index() == allocation2.index() && + !Arrays.equals(allocation1.priorities(), allocation2.priorities())) { throw new IllegalStateException(String.format( "%sIndex == %sIndex (%d), but %sPriorities (%s) != %sPriorities(%s)", - name1, name2, index1, name1, Arrays.toString(priorities1), name2, Arrays.toString(priorities2) + name1, name2, allocation1.index(), name1, Arrays.toString(allocation1.priorities()), + name2, Arrays.toString(allocation2.priorities()) )); } } diff --git a/src/main/java/com/github/knokko/boiler/queue/QueueFamilies.java b/src/main/java/com/github/knokko/boiler/queue/QueueFamilies.java index db59039..de5871a 100644 --- a/src/main/java/com/github/knokko/boiler/queue/QueueFamilies.java +++ b/src/main/java/com/github/knokko/boiler/queue/QueueFamilies.java @@ -1,5 +1,7 @@ package com.github.knokko.boiler.queue; public record QueueFamilies( - QueueFamily graphics, QueueFamily compute, QueueFamily transfer, QueueFamily present + QueueFamily graphics, QueueFamily compute, + QueueFamily transfer, QueueFamily present, + QueueFamily videoEncode, QueueFamily videoDecode ) { } diff --git a/src/test/java/com/github/knokko/boiler/queue/TestMinimalQueueMapper.java b/src/test/java/com/github/knokko/boiler/queue/TestMinimalQueueMapper.java index 3a31e64..d0c2ebf 100644 --- a/src/test/java/com/github/knokko/boiler/queue/TestMinimalQueueMapper.java +++ b/src/test/java/com/github/knokko/boiler/queue/TestMinimalQueueMapper.java @@ -4,14 +4,26 @@ import org.junit.jupiter.api.Test; import org.lwjgl.vulkan.VkQueueFamilyProperties; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.HashSet; +import java.util.Set; + +import static com.github.knokko.boiler.util.CollectionHelper.createSet; +import static org.junit.jupiter.api.Assertions.*; import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.system.MemoryUtil.memPutInt; +import static org.lwjgl.vulkan.KHRVideoDecodeQueue.VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME; +import static org.lwjgl.vulkan.KHRVideoDecodeQueue.VK_QUEUE_VIDEO_DECODE_BIT_KHR; +import static org.lwjgl.vulkan.KHRVideoEncodeQueue.VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME; +import static org.lwjgl.vulkan.KHRVideoEncodeQueue.VK_QUEUE_VIDEO_ENCODE_BIT_KHR; import static org.lwjgl.vulkan.VK10.*; public class TestMinimalQueueMapper { + private static final Set VIDEO_EXTENSIONS = createSet( + VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, + VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME + ); + @Test public void testAllCombined() { try (var stack = stackPush()) { @@ -19,7 +31,7 @@ public void testAllCombined() { memPutInt(pQueueFamilies.get(0).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_GRAPHICS_BIT); memPutInt( pQueueFamilies.get(1).address() + VkQueueFamilyProperties.QUEUEFLAGS, - VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_VIDEO_DECODE_BIT_KHR ); memPutInt( pQueueFamilies.get(2).address() + VkQueueFamilyProperties.QUEUEFLAGS, @@ -28,36 +40,50 @@ public void testAllCombined() { boolean[] presentSupport = { true, true, false }; - var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies(pQueueFamilies, presentSupport); + var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies( + pQueueFamilies, VIDEO_EXTENSIONS, presentSupport + ); mapping.validate(); - assertEquals(1, mapping.graphicsFamilyIndex()); - assertEquals(1, mapping.computeFamilyIndex()); - assertEquals(1, mapping.transferFamilyIndex()); + assertEquals(1, mapping.graphics().index()); + assertEquals(1, mapping.compute().index()); + assertEquals(1, mapping.transfer().index()); assertEquals(1, mapping.presentFamilyIndex()); - assertArrayEquals(new float[] { 1f }, mapping.graphicsPriorities()); + assertNull(mapping.videoEncode()); + assertEquals(1, mapping.videoDecode().index()); + assertArrayEquals(new float[] { 1f }, mapping.graphics().priorities()); } } @Test public void testAllDistinct() { try (var stack = stackPush()) { - var pQueueFamilies = VkQueueFamilyProperties.calloc(3, stack); + var pQueueFamilies = VkQueueFamilyProperties.calloc(4, stack); memPutInt(pQueueFamilies.get(0).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_GRAPHICS_BIT); memPutInt( pQueueFamilies.get(1).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT ); memPutInt(pQueueFamilies.get(2).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_TRANSFER_BIT); + memPutInt(pQueueFamilies.get(3).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_VIDEO_ENCODE_BIT_KHR); - boolean[] presentSupport = { false, false, true }; + boolean[] presentSupport = { false, false, true, true }; - var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies(pQueueFamilies, presentSupport); + var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies( + pQueueFamilies, VIDEO_EXTENSIONS, presentSupport + ); mapping.validate(); - assertEquals(0, mapping.graphicsFamilyIndex()); - assertEquals(1, mapping.computeFamilyIndex()); - assertEquals(0, mapping.transferFamilyIndex()); + assertEquals(0, mapping.graphics().index()); + assertEquals(1, mapping.compute().index()); + assertEquals(0, mapping.transfer().index()); assertEquals(2, mapping.presentFamilyIndex()); - for (var priorities : new float[][] { mapping.graphicsPriorities(), mapping.computePriorities(), mapping.transferPriorities() }) { + assertEquals(3, mapping.videoEncode().index()); + assertNull(mapping.videoDecode()); + for (var priorities : new float[][] { + mapping.graphics().priorities(), + mapping.compute().priorities(), + mapping.transfer().priorities(), + mapping.videoEncode().priorities() + }) { assertArrayEquals(new float[] { 1f }, priorities); } } @@ -66,7 +92,7 @@ public void testAllDistinct() { @Test public void testPartiallyCombined() { try (var stack = stackPush()) { - var pQueueFamilies = VkQueueFamilyProperties.calloc(4, stack); + var pQueueFamilies = VkQueueFamilyProperties.calloc(5, stack); memPutInt(pQueueFamilies.get(0).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_GRAPHICS_BIT); memPutInt( pQueueFamilies.get(1).address() + VkQueueFamilyProperties.QUEUEFLAGS, @@ -77,18 +103,82 @@ public void testPartiallyCombined() { VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT ); memPutInt(pQueueFamilies.get(3).address() + VkQueueFamilyProperties.QUEUEFLAGS, VK_QUEUE_TRANSFER_BIT); + memPutInt( + pQueueFamilies.get(4).address() + VkQueueFamilyProperties.QUEUEFLAGS, + VK_QUEUE_VIDEO_ENCODE_BIT_KHR | VK_QUEUE_VIDEO_DECODE_BIT_KHR + ); - boolean[] presentSupport = { true, false, false, true }; + boolean[] presentSupport = { true, false, false, true, false }; - var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies(pQueueFamilies, presentSupport); + var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies( + pQueueFamilies, VIDEO_EXTENSIONS, presentSupport + ); mapping.validate(); - assertEquals(2, mapping.graphicsFamilyIndex()); - assertEquals(2, mapping.computeFamilyIndex()); - assertEquals(2, mapping.transferFamilyIndex()); + assertEquals(2, mapping.graphics().index()); + assertEquals(2, mapping.compute().index()); + assertEquals(2, mapping.transfer().index()); assertEquals(0, mapping.presentFamilyIndex()); - for (var priorities : new float[][] { mapping.graphicsPriorities(), mapping.computePriorities(), mapping.transferPriorities() }) { + assertEquals(4, mapping.videoEncode().index()); + assertEquals(4, mapping.videoDecode().index()); + for (var priorities : new float[][] { + mapping.graphics().priorities(), + mapping.compute().priorities(), + mapping.transfer().priorities(), + mapping.videoEncode().priorities(), + mapping.videoDecode().priorities() + }) { assertArrayEquals(new float[] { 1f }, priorities); } } } + + @Test + public void testIgnoreVideoQueueFamiliesWhenExtensionsAreNotEnabled() { + try (var stack = stackPush()) { + var pQueueFamilies = VkQueueFamilyProperties.calloc(2, stack); + memPutInt( + pQueueFamilies.get(0).address() + VkQueueFamilyProperties.QUEUEFLAGS, + VK_QUEUE_VIDEO_ENCODE_BIT_KHR | VK_QUEUE_VIDEO_DECODE_BIT_KHR + ); + memPutInt( + pQueueFamilies.get(1).address() + VkQueueFamilyProperties.QUEUEFLAGS, + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT + ); + + boolean[] presentSupport = { true, true }; + + var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies( + pQueueFamilies, new HashSet<>(), presentSupport + ); + mapping.validate(); + assertEquals(1, mapping.graphics().index()); + assertEquals(1, mapping.compute().index()); + assertEquals(1, mapping.transfer().index()); + assertNull(mapping.videoDecode()); + assertNull(mapping.videoEncode()); + } + } + + @Test + public void testWithoutAnyVideoFamilies() { + try (var stack = stackPush()) { + var pQueueFamilies = VkQueueFamilyProperties.calloc(1, stack); + memPutInt( + pQueueFamilies.get(0).address() + VkQueueFamilyProperties.QUEUEFLAGS, + VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT + ); + + boolean[] presentSupport = { true }; + + var mapping = new MinimalQueueFamilyMapper().mapQueueFamilies( + pQueueFamilies, VIDEO_EXTENSIONS, presentSupport + ); + mapping.validate(); + assertEquals(0, mapping.graphics().index()); + assertEquals(0, mapping.compute().index()); + assertEquals(0, mapping.transfer().index()); + assertNull(mapping.videoDecode()); + assertNull(mapping.videoEncode()); + } + } }