From: Jordan Justen Date: Sun, 24 Mar 2019 08:00:37 +0000 (-0700) Subject: anv: Support multiple engines with DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT X-Git-Tag: upstream/21.2.3~8816 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4656be70dd75adce5481394ddfc14edf31c068d8;p=platform%2Fupstream%2Fmesa.git anv: Support multiple engines with DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT v2 (Jason Ekstrand): - Separate the anv_gem interface from anv_queue internals - Rework on top of the new anv_queue_family stuff Signed-off-by: Jordan Justen Reviewed-by: Jason Ekstrand Reviewed-by: Lionel Landwerlin Part-of: --- diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index 566a249..d904633 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -299,14 +299,37 @@ anv_physical_device_free_disk_cache(struct anv_physical_device *device) static void anv_physical_device_init_queue_families(struct anv_physical_device *pdevice) { - pdevice->queue.family_count = 1; - pdevice->queue.families[0] = (struct anv_queue_family) { - .queueFlags = VK_QUEUE_GRAPHICS_BIT | - VK_QUEUE_COMPUTE_BIT | - VK_QUEUE_TRANSFER_BIT, - .queueCount = 1, - .engine_class = I915_ENGINE_CLASS_RENDER, - }; + uint32_t family_count = 0; + + if (pdevice->engine_info) { + int render_count = anv_gem_count_engines(pdevice->engine_info, + I915_ENGINE_CLASS_RENDER); + if (render_count > 0) { + pdevice->queue.families[family_count++] = (struct anv_queue_family) { + .queueFlags = VK_QUEUE_GRAPHICS_BIT | + VK_QUEUE_COMPUTE_BIT | + VK_QUEUE_TRANSFER_BIT, + .queueCount = render_count, + .engine_class = I915_ENGINE_CLASS_RENDER, + }; + } + /* Increase count below when other families are added as a reminder to + * increase the ANV_MAX_QUEUE_FAMILIES value. + */ + STATIC_ASSERT(ANV_MAX_QUEUE_FAMILIES >= 1); + } else { + /* Default to a single render queue */ + pdevice->queue.families[family_count++] = (struct anv_queue_family) { + .queueFlags = VK_QUEUE_GRAPHICS_BIT | + VK_QUEUE_COMPUTE_BIT | + VK_QUEUE_TRANSFER_BIT, + .queueCount = 1, + .engine_class = I915_ENGINE_CLASS_RENDER, + }; + family_count = 1; + } + assert(family_count <= ANV_MAX_QUEUE_FAMILIES); + pdevice->queue.family_count = family_count; } static VkResult @@ -2864,7 +2887,35 @@ VkResult anv_CreateDevice( goto fail_device; } - device->context_id = anv_gem_create_context(device); + uint32_t num_queues = 0; + for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) + num_queues += pCreateInfo->pQueueCreateInfos[i].queueCount; + + if (device->physical->engine_info) { + /* The kernel API supports at most 64 engines */ + assert(num_queues <= 64); + uint16_t engine_classes[64]; + int engine_count = 0; + for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { + const VkDeviceQueueCreateInfo *queueCreateInfo = + &pCreateInfo->pQueueCreateInfos[i]; + + assert(queueCreateInfo->queueFamilyIndex < + physical_device->queue.family_count); + struct anv_queue_family *queue_family = + &physical_device->queue.families[queueCreateInfo->queueFamilyIndex]; + + for (uint32_t j = 0; j < queueCreateInfo->queueCount; j++) + engine_classes[engine_count++] = queue_family->engine_class; + } + device->context_id = + anv_gem_create_context_engines(device, + physical_device->engine_info, + engine_count, engine_classes); + } else { + assert(num_queues == 1); + device->context_id = anv_gem_create_context(device); + } if (device->context_id == -1) { result = vk_error(VK_ERROR_INITIALIZATION_FAILED); goto fail_fd; @@ -2872,10 +2923,6 @@ VkResult anv_CreateDevice( device->has_thread_submit = physical_device->has_thread_submit; - uint32_t num_queues = 0; - for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) - num_queues += pCreateInfo->pQueueCreateInfos[i].queueCount; - device->queues = vk_zalloc(&device->vk.alloc, num_queues * sizeof(*device->queues), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); @@ -2890,8 +2937,15 @@ VkResult anv_CreateDevice( &pCreateInfo->pQueueCreateInfos[i]; for (uint32_t j = 0; j < queueCreateInfo->queueCount; j++) { + /* When using legacy contexts, we use I915_EXEC_RENDER but, with + * engine-based contexts, the bottom 6 bits of exec_flags are used + * for the engine ID. + */ + uint32_t exec_flags = device->physical->engine_info ? + device->queue_count : I915_EXEC_RENDER; + result = anv_queue_init(device, &device->queues[device->queue_count], - I915_EXEC_RENDER, queueCreateInfo); + exec_flags, queueCreateInfo); if (result != VK_SUCCESS) goto fail_queues; diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c index b7b2d14..e6a6cc1 100644 --- a/src/intel/vulkan/anv_gem.c +++ b/src/intel/vulkan/anv_gem.c @@ -375,6 +375,90 @@ anv_gem_create_context(struct anv_device *device) } int +anv_gem_create_context_engines(struct anv_device *device, + const struct drm_i915_query_engine_info *info, + int num_engines, uint16_t *engine_classes) +{ + const size_t engine_inst_sz = 2 * sizeof(__u16); /* 1 class, 1 instance */ + const size_t engines_param_size = + sizeof(__u64) /* extensions */ + num_engines * engine_inst_sz; + + void *engines_param = malloc(engines_param_size); + assert(engines_param); + *(__u64*)engines_param = 0; + __u16 *class_inst_ptr = (__u16*)(((__u64*)engines_param) + 1); + + /* For each type of drm_i915_gem_engine_class of interest, we keep track of + * the previous engine instance used. + */ + int last_engine_idx[] = { + [I915_ENGINE_CLASS_RENDER] = -1, + }; + + int i915_engine_counts[] = { + [I915_ENGINE_CLASS_RENDER] = + anv_gem_count_engines(info, I915_ENGINE_CLASS_RENDER), + }; + + /* For each queue, we look for the next instance that matches the class we + * need. + */ + for (int i = 0; i < num_engines; i++) { + uint16_t engine_class = engine_classes[i]; + if (i915_engine_counts[engine_class] <= 0) { + free(engines_param); + return -1; + } + + /* Run through the engines reported by the kernel looking for the next + * matching instance. We loop in case we want to create multiple + * contexts on an engine instance. + */ + int engine_instance = -1; + for (int i = 0; i < info->num_engines; i++) { + int *idx = &last_engine_idx[engine_class]; + if (++(*idx) >= info->num_engines) + *idx = 0; + if (info->engines[*idx].engine.engine_class == engine_class) { + engine_instance = info->engines[*idx].engine.engine_instance; + break; + } + } + if (engine_instance < 0) { + free(engines_param); + return -1; + } + + *class_inst_ptr++ = engine_class; + *class_inst_ptr++ = engine_instance; + } + + assert((uintptr_t)engines_param + engines_param_size == + (uintptr_t)class_inst_ptr); + + struct drm_i915_gem_context_create_ext_setparam set_engines = { + .base = { + .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + }, + .param = { + .param = I915_CONTEXT_PARAM_ENGINES, + .value = (uintptr_t)engines_param, + .size = engines_param_size, + } + }; + struct drm_i915_gem_context_create_ext create = { + .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + .extensions = (uintptr_t)&set_engines, + }; + int ret = gen_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create); + free(engines_param); + if (ret == -1) + return -1; + + return create.ctx_id; +} + +int anv_gem_destroy_context(struct anv_device *device, int context) { struct drm_i915_gem_context_destroy destroy = { diff --git a/src/intel/vulkan/anv_gem_stubs.c b/src/intel/vulkan/anv_gem_stubs.c index b41e963..10e5741 100644 --- a/src/intel/vulkan/anv_gem_stubs.c +++ b/src/intel/vulkan/anv_gem_stubs.c @@ -252,6 +252,15 @@ anv_i915_query(int fd, uint64_t query_id, void *buffer, unreachable("Unused"); } +int +anv_gem_create_context_engines(struct anv_device *device, + const struct drm_i915_query_engine_info *info, + int num_engines, + uint16_t *engine_classes) +{ + unreachable("Unused"); +} + struct drm_i915_query_engine_info * anv_gem_get_engine_info(int fd) { diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 3d5020d..f25ca1a 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1619,6 +1619,10 @@ int anv_gem_execbuffer(struct anv_device *device, int anv_gem_set_tiling(struct anv_device *device, uint32_t gem_handle, uint32_t stride, uint32_t tiling); int anv_gem_create_context(struct anv_device *device); +int anv_gem_create_context_engines(struct anv_device *device, + const struct drm_i915_query_engine_info *info, + int num_engines, + uint16_t *engine_classes); bool anv_gem_has_context_priority(int fd); int anv_gem_destroy_context(struct anv_device *device, int context); int anv_gem_set_context_param(int fd, int context, uint32_t param,