As discussed in the Physical Device Enumeration section above, the
vkGetPhysicalDeviceQueueFamilyProperties
command is used to retrieve
details about the queue families and queues supported by a device.
Each index in the pQueueFamilyProperties
array returned by
vkGetPhysicalDeviceQueueFamilyProperties
describes a unique queue
family on that physical device.
These indices are used when creating queues, and they correspond directly
with the queueFamilyIndex
that is passed to the vkCreateDevice
command via the VkDeviceQueueCreateInfo
structure as described in the
Queue Creation section below.
Grouping of queue families within a physical device is implementation-dependent.
![]() | Note |
---|---|
The general expectation is that a physical device groups all queues of matching capabilities into a single family. However, this is a recommendation to implementations and it is possible that a physical device may return two separate queue families with the same capabilities. |
Once an application has identified a physical device with the queue(s) that it desires to use, it will create those queues in conjunction with a logical device. This is described in the following section.
Creating a logical device also creates the queues associated with that
device.
The queues to create are described by a set of VkDeviceQueueCreateInfo
structures that are passed to vkCreateDevice
in
pQueueCreateInfos
.
Queues are represented by VkQueue
handles:
VK_DEFINE_HANDLE(VkQueue)
The VkDeviceQueueCreateInfo
structure is defined as:
typedef struct VkDeviceQueueCreateInfo { VkStructureType sType; const void* pNext; VkDeviceQueueCreateFlags flags; uint32_t queueFamilyIndex; uint32_t queueCount; const float* pQueuePriorities; } VkDeviceQueueCreateInfo;
sType
is the type of this structure.
pNext
is NULL
or a pointer to an extension-specific structure.
flags
is reserved for future use.
queueFamilyIndex
is an unsigned integer indicating the index of
the queue family to create on this device.
This index corresponds to the index of an element of the
pQueueFamilyProperties
array that was returned by
vkGetPhysicalDeviceQueueFamilyProperties
.
queueCount
is an unsigned integer specifying the number of queues
to create in the queue family indicated by queueFamilyIndex
.
pQueuePriorities
is an array of queueCount
normalized
floating point values, specifying priorities of work that will be
submitted to each created queue.
See Queue Priority for more information.
To retrieve a handle to a VkQueue object, call:
void vkGetDeviceQueue( VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
device
is the logical device that owns the queue.
queueFamilyIndex
is the index of the queue family to which the
queue belongs.
queueIndex
is the index within this queue family of the queue to
retrieve.
pQueue
is a pointer to a VkQueue
object that will be filled
with the handle for the requested queue.
The queue family index is used in multiple places in Vulkan in order to tie operations to a specific family of queues.
When retrieving a handle to the queue via vkGetDeviceQueue
, the queue
family index is used to select which queue family to retrieve the
VkQueue
handle from as described in the previous section.
When creating a VkCommandPool
object (see
Command Pools), a queue family index is specified
in the VkCommandPoolCreateInfo
structure.
Command buffers from this pool can only be submitted on queues
corresponding to this queue family.
When creating VkImage
(see Images) and
VkBuffer
(see Buffers) resources, a set of queue
families is included in the VkImageCreateInfo
and
VkBufferCreateInfo
structures to specify the queue families that can
access the resource.
When inserting a VkBufferMemoryBarrier
or VkImageMemoryBarrier
(see Section 6.3, “Events”) a source and destination queue family index
is specified to allow the ownership of a buffer or image to be transferred
from one queue family to another.
See the Resource Sharing section for details.
Each queue is assigned a priority, as set in the
VkDeviceQueueCreateInfo
structures when creating the device.
The priority of each queue is a normalized floating point value between 0.0
and 1.0, which is then translated to a discrete priority level by the
implementation.
Higher values indicate a higher priority, with 0.0 being the lowest priority
and 1.0 being the highest.
Within the same device, queues with higher priority may be allotted more processing time than queues with lower priority. The implementation makes no guarantees with regards to ordering or scheduling among queues with the same priority, other than the constraints defined by explicit scheduling primitives. The implementation make no guarantees with regards to queues across different devices.
An implementation may allow a higher-priority queue to starve a
lower-priority queue on the same VkDevice
until the higher-priority
queue has no further commands to execute.
The relationship of queue priorities must not cause queues on one VkDevice
to starve queues on another VkDevice
.
No specific guarantees are made about higher priority queues receiving more processing time or better quality of service than lower priority queues.
Work is submitted to a queue via queue submission commands such as
vkQueueSubmit
.
Queue submission commands define a set of queue operations to be executed
by the underlying physical device, including synchronization with semaphores
and fences.
Submission commands take as parameters a target queue, zero or more batches of work, and an optional fence to signal upon completion. Each batch consists of three distinct parts:
Zero or more semaphores to wait on before execution of the rest of the batch.
Zero or more work items to execute.
Zero or more semaphores to signal upon completion of the work items.
If a fence is present in a queue submission, it describes a fence signal operation.
All work described by a queue submission command must be submitted to the queue before the command returns.
In Vulkan it is possible to sparsely bind memory to buffers and images as
described in the Sparse Resource chapter.
Sparse memory binding is a queue operation.
A queue whose flags include the VK_QUEUE_SPARSE_BINDING_BIT
must be
able to support the mapping of a virtual address to a physical address on
the device.
This causes an update to the page table mappings on the device.
This update must be synchronized on a queue to avoid corrupting page table
mappings during execution of graphics commands.
By binding the sparse memory resources on queues, all commands that are
dependent on the updated bindings are synchronized to only execute after the
binding is updated.
See the Synchronization and Cache Control chapter for
how this synchronization is accomplished.