Add a new extension VK_EXT_queue_global_priority, which allows the caller to elevate a queue's priority above all other queues in the system. This extension aims to provide a mechanism for compositors to have achieve a guaranteed quality of service, even when the hardware may be loaded by a game or application. --- docs/specs/VK_EXT_queue_global_priority.txt | 97 +++++++++++++++++++++++++++ include/vulkan/vk_ext_queue_global_priority.h | 72 ++++++++++++++++++++ src/amd/vulkan/radv_device.c | 31 ++++++++- src/amd/vulkan/radv_private.h | 12 ++++ src/amd/vulkan/radv_radeon_winsys.h | 8 ++- src/amd/vulkan/winsys/amdgpu/radv_amdgpu_cs.c | 20 +++++- 6 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 docs/specs/VK_EXT_queue_global_priority.txt create mode 100644 include/vulkan/vk_ext_queue_global_priority.h diff --git a/docs/specs/VK_EXT_queue_global_priority.txt b/docs/specs/VK_EXT_queue_global_priority.txt new file mode 100644 index 0000000..9a6a712 --- /dev/null +++ b/docs/specs/VK_EXT_queue_global_priority.txt @@ -0,0 +1,97 @@ +Name Strings + + VK_EXT_queue_global_priority + +Extension Type + + Queue Extension + +Registered Extension Number + + Draft + +Status + + Draft + +Version + + 0 (Early Draft) + +Last Modified Date + + See git log. + +IP Status + + No known IP claims. + +Dependencies + + This extension is written against the Vulkan 1.0.32 specification [1]. + +Contributors + + Andres Rodriguez, Valve Software <andresr at valvesoftware.com> + Pierre-Loup Griffais, Valve Software <pgriffais at valvesoftware.com> + +Contact + + Andres Rodriguez, Valve Software <andresr at valvesoftware.com> + +Overview + + In Vulkan 1.0.32 users can specify device-scope queue priorities. In + some cases it may be useful to extend this concept to a system-wide scope. + + This extension provides a mechanism for caller's to set their system-wide + priority. The default queue priority is VK_QUEUE_GLOBAL_PRIORITY_NORMAL. + + TODO: privileges required for priority escalation and note about system + resource starvation. + +New Object Types + + VkQueueGlobalPriorityEXT + VK_STRUCTURE_TYPE_QUEUE_GLOBAL_PRIORITY_EXT + +New Enum Constants + + None + +New Enums + + VkQueueGlobalPriority + VK_QUEUE_GLOBAL_PRIORITY_HIGH + VK_QUEUE_GLOBAL_PRIORITY_NORMAL + +New Structs + + typedef struct VkQueueGlobalPriorityEXT { + VkStructureType sType; + void* pNext; + VkQueueGlobalPriority priority; + } VkQueueGlobalPriorityEXT; + +New Functions + + None + +Description + + TODO + +Issues + + TODO + +References + + [1]: https://github.com/KhronosGroup/Vulkan-Docs/tree/v1.0-core-20161025 + +Version History + + See git log for full history. + + - Revision 1, 2017-01-01 (Andres Rodriguez) + - Initial draft diff --git a/include/vulkan/vk_ext_queue_global_priority.h b/include/vulkan/vk_ext_queue_global_priority.h new file mode 100644 index 0000000..01c7329 --- /dev/null +++ b/include/vulkan/vk_ext_queue_global_priority.h @@ -0,0 +1,72 @@ +/* + * Copyright 2017 Valve Software + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef VK_EXT_QUEUE_GLOBAL_PRIORITY_H_ +#define VK_EXT_QUEUE_GLOBAL_PRIORITY_H_ + +#include "vulkan.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Draft spec lives at <docs/specs/VK_EXT_queue_global_prioruity.txt>. + * + * TODO: Discuss with everyone who cares. + * TODO: Get a proper VkStructureType + * TODO: Finish spec + */ +#define VK_EXT_queue_global_priority +#define VK_EXT_queue_global_priotiry_SPEC_VERSION 0 /* experimental */ +#define VK_EXT_queue_global_priority_EXTENSION_NAME "VK_EXT_queue_global_priority" + +/** System-wide queue priority + * + * High priority queues may starve queues in other processes + */ +typedef enum VkQueueGlobalPriority { + VK_QUEUE_GLOBAL_PRIORITY_HIGH = 1, + VK_QUEUE_GLOBAL_PRIORITY_NORMAL = 2, + VK_QUEUE_GLOBAL_PRIORITY_BEGIN_RANGE = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_END_RANGE = VK_QUEUE_GLOBAL_PRIORITY_NORMAL, + VK_QUEUE_GLOBAL_PRIORITY_RANGE_SIZE = (VK_QUEUE_GLOBAL_PRIORITY_HIGH - VK_QUEUE_GLOBAL_PRIORITY_NORMAL + 1), + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM = 0x7FFFFFFF +} VkQueueGlobalPriority; + +/* Extends VkDeviceQueueCreateInfo. + * + * Used to set the global priority for the allocated queue + */ +typedef struct VkQueueGlobalPriorityEXT { + VkStructureType sType; + void* pNext; + VkQueueGlobalPriority priority; +} VkQueueGlobalPriorityEXT; + +#define VK_STRUCTURE_TYPE_QUEUE_GLOBAL_PRIORITY_EXT (VkStructureType)1000120001 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c index d9f9a2b..9880a5d 100644 --- a/src/amd/vulkan/radv_device.c +++ b/src/amd/vulkan/radv_device.c @@ -651,16 +651,41 @@ void radv_GetPhysicalDeviceMemoryProperties( }; } +static enum ctx_priority +radv_get_queue_global_priority(VkQueueGlobalPriorityEXT *pObj) +{ + switch(pObj->priority) { + case VK_QUEUE_GLOBAL_PRIORITY_HIGH: + return CTX_PRIORITY_HIGH; + default: + return CTX_PRIORITY_NORMAL; + } +} + static int radv_queue_init(struct radv_device *device, struct radv_queue *queue, - int queue_family_index, int idx) + int queue_family_index, int idx, const VkDeviceQueueCreateInfo *create_info) { queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC; queue->device = device; queue->queue_family_index = queue_family_index; queue->queue_idx = idx; + queue->priority = CTX_PRIORITY_NORMAL; + + radv_foreach_ext_obj(create_info, next_obj) { + switch (next_obj->sType) { + case VK_STRUCTURE_TYPE_QUEUE_GLOBAL_PRIORITY_EXT: + queue->priority = radv_get_queue_global_priority( + (VkQueueGlobalPriorityEXT*)next_obj); + break; + default: + radv_finishme("Unsupported queue extension VkStructureType %d\n", + next_obj->sType); + break; + } + } - queue->hw_ctx = device->ws->ctx_create(device->ws); + queue->hw_ctx = device->ws->ctx_create(device->ws, queue->priority); if (!queue->hw_ctx) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -731,7 +756,7 @@ VkResult radv_CreateDevice( device->queue_count[qfi] = queue_create->queueCount; for (unsigned q = 0; q < queue_create->queueCount; q++) { - result = radv_queue_init(device, &device->queues[qfi][q], qfi, q); + result = radv_queue_init(device, &device->queues[qfi][q], qfi, q, queue_create); if (result != VK_SUCCESS) goto fail; } diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h index d316f71..d79ef3a 100644 --- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -66,6 +66,7 @@ typedef uint32_t xcb_window_t; #include <vulkan/vulkan.h> #include <vulkan/vulkan_intel.h> +#include <vulkan/vk_ext_queue_global_priority.h> #include <vulkan/vk_icd.h> #include "radv_entrypoints.h" @@ -457,6 +458,7 @@ struct radv_queue { VK_LOADER_DATA _loader_data; struct radv_device * device; struct radeon_winsys_ctx *hw_ctx; + enum ctx_priority priority; int queue_family_index; int queue_idx; }; @@ -1325,4 +1327,14 @@ RADV_DEFINE_NONDISP_HANDLE_CASTS(radv_shader_module, VkShaderModule) return (const __VkType *) __radv_obj; \ } +/** + * Used to iterate over Vk structs that support extension types + * + * Iterate over the __obj->pNext list, keeping the current object in __varname + */ +#define radv_foreach_ext_obj(__obj, __varname) \ + /*Note: Any type with sType/pNext works here*/ \ + for ( VkSubmitInfo *__varname = (VkSubmitInfo*)__obj->pNext;\ + __varname != NULL;\ + __varname = (VkSubmitInfo*)__varname->pNext) #endif /* RADV_PRIVATE_H */ diff --git a/src/amd/vulkan/radv_radeon_winsys.h b/src/amd/vulkan/radv_radeon_winsys.h index 4b738b8..3218c87 100644 --- a/src/amd/vulkan/radv_radeon_winsys.h +++ b/src/amd/vulkan/radv_radeon_winsys.h @@ -64,6 +64,11 @@ enum ring_type { RING_LAST, }; +enum ctx_priority { + CTX_PRIORITY_HIGH = 0, + CTX_PRIORITY_NORMAL +}; + struct radeon_winsys_cs { unsigned cdw; /* Number of used dwords. */ unsigned max_dw; /* Maximum number of dwords. */ @@ -284,7 +289,8 @@ struct radeon_winsys { void (*buffer_set_metadata)(struct radeon_winsys_bo *bo, struct radeon_bo_metadata *md); - struct radeon_winsys_ctx *(*ctx_create)(struct radeon_winsys *ws); + struct radeon_winsys_ctx *(*ctx_create)(struct radeon_winsys *ws, + enum ctx_priority priority); void (*ctx_destroy)(struct radeon_winsys_ctx *ctx); bool (*ctx_wait_idle)(struct radeon_winsys_ctx *ctx, diff --git a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_cs.c b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_cs.c index b24aa99..585ccf4 100644 --- a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_cs.c +++ b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_cs.c @@ -775,15 +775,31 @@ static int radv_amdgpu_winsys_cs_submit(struct radeon_winsys_ctx *_ctx, return ret; } -static struct radeon_winsys_ctx *radv_amdgpu_ctx_create(struct radeon_winsys *_ws) +static uint32_t radv_to_amdgpu_priority(enum ctx_priority priority radv_priority) +{ + switch (radv_priority) { + case AMDGPU_CTX_PRIORITY_HIGH: + return AMDGPU_CTX_PRIORITY_HIGH; + case AMDGPU_CTX_PRIORITY_NORMAL: + return AMDGPU_CTX_PRIORITY_NORMAL; + default: + radv_loge("Invalid radv priority %d\n, defualting to normal", radv_priority); + return AMDGPU_CTX_PRIORITY_NORMAL; + } +} + +static struct radeon_winsys_ctx *radv_amdgpu_ctx_create(struct radeon_winsys *_ws, + enum ctx_priority priority) { struct radv_amdgpu_winsys *ws = radv_amdgpu_winsys(_ws); struct radv_amdgpu_ctx *ctx = CALLOC_STRUCT(radv_amdgpu_ctx); + uint32_t amdgpu_priority = radv_to_amdgpu_priority(priority); int r; if (!ctx) return NULL; - r = amdgpu_cs_ctx_create(ws->dev, &ctx->ctx); + + r = amdgpu_cs_ctx_create2(ws->dev, amdgpu_priority, &ctx->ctx); if (r) { fprintf(stderr, "amdgpu: radv_amdgpu_cs_ctx_create failed. (%i)\n", r); goto error_create; -- 2.9.3