I'm stopping here for today and will resume tomorrow.
On Fri 14 Apr 2017, Jason Ekstrand wrote: > --- > src/intel/vulkan/anv_batch_chain.c | 96 > ++++++++++++++++++++++++++++++++++++-- > src/intel/vulkan/anv_device.c | 25 ++++++++++ > src/intel/vulkan/anv_gem.c | 36 ++++++++++++++ > src/intel/vulkan/anv_private.h | 24 +++++++--- > src/intel/vulkan/anv_queue.c | 73 +++++++++++++++++++++++++++-- > 5 files changed, 240 insertions(+), 14 deletions(-) > > diff --git a/src/intel/vulkan/anv_batch_chain.c > b/src/intel/vulkan/anv_batch_chain.c > index 0529f22..ec37c81 100644 > --- a/src/intel/vulkan/anv_batch_chain.c > +++ b/src/intel/vulkan/anv_batch_chain.c > @@ -1387,6 +1387,23 @@ setup_execbuf_for_cmd_buffer(struct anv_execbuf > *execbuf, > return VK_SUCCESS; > } > > +static void > +setup_empty_execbuf(struct anv_execbuf *execbuf, struct anv_device *device) > +{ > + anv_execbuf_add_bo(execbuf, &device->trivial_batch_bo, NULL, 0, > + &device->alloc); > + > + execbuf->execbuf = (struct drm_i915_gem_execbuffer2) { > + .buffers_ptr = (uintptr_t) execbuf->objects, > + .buffer_count = execbuf->bo_count, > + .batch_start_offset = 0, > + .batch_len = 8, /* GEN8_MI_BATCH_BUFFER_END and NOOP */ > + .flags = I915_EXEC_HANDLE_LUT | I915_EXEC_RENDER, > + .rsvd1 = device->context_id, > + .rsvd2 = 0, > + }; > +} > + > VkResult > anv_cmd_buffer_execbuf(struct anv_device *device, > struct anv_cmd_buffer *cmd_buffer, > @@ -1398,11 +1415,13 @@ anv_cmd_buffer_execbuf(struct anv_device *device, > struct anv_execbuf execbuf; > anv_execbuf_init(&execbuf); > > + int in_fence = -1; > VkResult result = VK_SUCCESS; > for (uint32_t i = 0; i < num_in_semaphores; i++) { > ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]); > - assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE); > - struct anv_semaphore_impl *impl = &semaphore->permanent; > + struct anv_semaphore_impl *impl = > + semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ? > + &semaphore->temporary : &semaphore->permanent; > > switch (impl->type) { > case ANV_SEMAPHORE_TYPE_BO: > @@ -1411,13 +1430,42 @@ anv_cmd_buffer_execbuf(struct anv_device *device, > if (result != VK_SUCCESS) > return result; > break; > + > + case ANV_SEMAPHORE_TYPE_SYNC_FILE: > + if (in_fence == -1) { > + in_fence = impl->fd; > + } else { > + int merge = anv_gem_sync_file_merge(device, in_fence, impl->fd); > + if (merge == -1) > + return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX); > + > + close(impl->fd); > + close(in_fence); > + in_fence = merge; > + } > + > + impl->fd = -1; > + break; > + > default: > break; > } > + > + /* Waiting on a semaphore with temporary state implicitly resets it > back > + * to the permanent state. > + */ > + if (semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE) { > + assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_SYNC_FILE); > + semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE; > + } > } > > + bool need_out_fence = false; > for (uint32_t i = 0; i < num_out_semaphores; i++) { > ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]); > + /* Out fences can't have temporary state because that would imply > + * that we imported a sync file and are trying to signal it. > + */ > assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE); > struct anv_semaphore_impl *impl = &semaphore->permanent; > > @@ -1428,17 +1476,55 @@ anv_cmd_buffer_execbuf(struct anv_device *device, > if (result != VK_SUCCESS) > return result; > break; > + > + case ANV_SEMAPHORE_TYPE_SYNC_FILE: > + need_out_fence = true; > + break; > + > default: > break; > } > } > > - result = setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer); > - if (result != VK_SUCCESS) > - return result; > + if (cmd_buffer) { > + result = setup_execbuf_for_cmd_buffer(&execbuf, cmd_buffer); > + if (result != VK_SUCCESS) > + return result; > + } else { > + setup_empty_execbuf(&execbuf, device); > + } > + > + if (in_fence != -1) { > + execbuf.execbuf.flags |= I915_EXEC_FENCE_IN; > + execbuf.execbuf.rsvd2 |= (uint32_t)in_fence; > + } > + > + if (need_out_fence) > + execbuf.execbuf.flags |= I915_EXEC_FENCE_OUT; > > result = anv_device_execbuf(device, &execbuf.execbuf, execbuf.bos); > > + /* Execbuf does not consume the in_fence. It's our job to close it. */ > + close(in_fence); > + > + if (result == VK_SUCCESS && need_out_fence) { > + int out_fence = execbuf.execbuf.rsvd2 >> 32; > + for (uint32_t i = 0; i < num_out_semaphores; i++) { > + ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]); > + /* Out fences can't have temporary state because that would imply > + * that we imported a sync file and are trying to signal it. > + */ > + assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE); > + struct anv_semaphore_impl *impl = &semaphore->permanent; > + > + if (impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE) { > + assert(impl->fd == -1); > + impl->fd = dup(out_fence); > + } > + } > + close(out_fence); > + } > + > anv_execbuf_finish(&execbuf, &device->alloc); > > return result; > diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c > index f6e77ab..2885bb6 100644 > --- a/src/intel/vulkan/anv_device.c > +++ b/src/intel/vulkan/anv_device.c > @@ -232,6 +232,7 @@ anv_physical_device_init(struct anv_physical_device > *device, > goto fail; > > device->has_exec_async = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_ASYNC); > + device->has_exec_fence = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE); > > bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X); > > @@ -993,6 +994,26 @@ anv_device_init_border_colors(struct anv_device *device) > border_colors); > } > > +static void > +anv_device_init_trivial_batch(struct anv_device *device) > +{ > + anv_bo_init_new(&device->trivial_batch_bo, device, 4096); > + void *map = anv_gem_mmap(device, device->trivial_batch_bo.gem_handle, > + 0, 4096, 0); > + > + struct anv_batch batch; > + batch.start = batch.next = map; > + batch.end = map + 4096; > + > + anv_batch_emit(&batch, GEN7_MI_BATCH_BUFFER_END, bbe); > + anv_batch_emit(&batch, GEN7_MI_NOOP, noop); > + > + if (!device->info.has_llc) > + anv_clflush_range(map, batch.next - map); > + > + anv_gem_munmap(map, device->trivial_batch_bo.size); > +} > + > VkResult anv_CreateDevice( > VkPhysicalDevice physicalDevice, > const VkDeviceCreateInfo* pCreateInfo, > @@ -1116,6 +1137,8 @@ VkResult anv_CreateDevice( > if (result != VK_SUCCESS) > goto fail_surface_state_pool; > > + anv_device_init_trivial_batch(device); > + > anv_scratch_pool_init(device, &device->scratch_pool); > > anv_queue_init(device, &device->queue); > @@ -1205,6 +1228,8 @@ void anv_DestroyDevice( > anv_gem_munmap(device->workaround_bo.map, device->workaround_bo.size); > anv_gem_close(device, device->workaround_bo.gem_handle); > > + anv_gem_close(device, device->trivial_batch_bo.gem_handle); > + > anv_state_pool_finish(&device->surface_state_pool); > anv_block_pool_finish(&device->surface_state_block_pool); > anv_state_pool_finish(&device->instruction_state_pool); > diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c > index 1392bf4..ffdc5a1 100644 > --- a/src/intel/vulkan/anv_gem.c > +++ b/src/intel/vulkan/anv_gem.c > @@ -22,6 +22,7 @@ > */ > > #include <sys/ioctl.h> > +#include <sys/types.h> > #include <sys/mman.h> > #include <string.h> > #include <errno.h> > @@ -400,3 +401,38 @@ anv_gem_fd_to_handle(struct anv_device *device, int fd) > > return args.handle; > } > + > +#ifndef SYNC_IOC_MAGIC > +/* duplicated from linux/sync_file.h to avoid build-time depnedency > + * on new (v4.7) kernel headers. Once distro's are mostly using > + * something newer than v4.7 drop this and #include <linux/sync_file.h> > + * instead. > + */ > +struct sync_merge_data { > + char name[32]; > + __s32 fd2; > + __s32 fence; > + __u32 flags; > + __u32 pad; > +}; > + > +#define SYNC_IOC_MAGIC '>' > +#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) > +#endif > + > +int > +anv_gem_sync_file_merge(struct anv_device *device, int fd1, int fd2) > +{ > + const char name[] = "anv merge fence"; > + struct sync_merge_data args = { > + .fd2 = fd2, > + .fence = -1, > + }; > + memcpy(args.name, name, sizeof(name)); > + > + int ret = anv_ioctl(fd1, SYNC_IOC_MERGE, &args); > + if (ret == -1) > + return -1; > + > + return args.fence; > +} > diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h > index 4a59cac..a083a07 100644 > --- a/src/intel/vulkan/anv_private.h > +++ b/src/intel/vulkan/anv_private.h > @@ -647,6 +647,7 @@ struct anv_physical_device { > struct isl_device isl_dev; > int cmd_parser_version; > bool has_exec_async; > + bool has_exec_fence; > > uint32_t eu_total; > uint32_t subslice_total; > @@ -733,6 +734,7 @@ struct anv_device { > struct anv_state_pool surface_state_pool; > > struct anv_bo workaround_bo; > + struct anv_bo trivial_batch_bo; > > struct anv_pipeline_cache blorp_shader_cache; > struct blorp_context blorp; > @@ -797,6 +799,7 @@ uint32_t anv_gem_fd_to_handle(struct anv_device *device, > int fd); > int anv_gem_set_caching(struct anv_device *device, uint32_t gem_handle, > uint32_t caching); > int anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle, > uint32_t read_domains, uint32_t write_domain); > +int anv_gem_sync_file_merge(struct anv_device *device, int fd1, int fd2); > > VkResult anv_bo_init_new(struct anv_bo *bo, struct anv_device *device, > uint64_t size); > > @@ -1714,17 +1717,26 @@ enum anv_semaphore_type { > ANV_SEMAPHORE_TYPE_NONE = 0, > ANV_SEMAPHORE_TYPE_DUMMY, > ANV_SEMAPHORE_TYPE_BO, > + ANV_SEMAPHORE_TYPE_SYNC_FILE, > }; > > struct anv_semaphore_impl { > enum anv_semaphore_type type; > > - /* A BO representing this semaphore when type == ANV_SEMAPHORE_TYPE_BO. > - * This BO will be added to the object list on any execbuf2 calls for > - * which this semaphore is used as a wait or signal fence. When used as > - * a signal fence, the EXEC_OBJECT_WRITE flag will be set. > - */ > - struct anv_bo *bo; > + union { > + /* A BO representing this semaphore when type == ANV_SEMAPHORE_TYPE_BO. > + * This BO will be added to the object list on any execbuf2 calls for > + * which this semaphore is used as a wait or signal fence. When used > as > + * a signal fence, the EXEC_OBJECT_WRITE flag will be set. > + */ > + struct anv_bo *bo; > + > + /* The sync file descriptor when type == AKV_SEMAPHORE_TYPE_SYNC_FILE. > + * If the semaphore is in the unsignaled state due to either just being > + * created or because it has been used for a wait, fd will be -1. > + */ > + int fd; > + }; > }; > > struct anv_semaphore { > diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c > index 980fd2d..e7c8ef5 100644 > --- a/src/intel/vulkan/anv_queue.c > +++ b/src/intel/vulkan/anv_queue.c > @@ -159,6 +159,23 @@ VkResult anv_QueueSubmit( > pthread_mutex_lock(&device->mutex); > > for (uint32_t i = 0; i < submitCount; i++) { > + if (pSubmits[i].commandBufferCount == 0) { > + /* If we don't have any command buffers, we need to submit a dummy > + * batch to give GEM something to wait on. We could, potentially, > + * come up with something more efficient but this shouldn't be a > + * common case. > + */ > + result = anv_cmd_buffer_execbuf(device, NULL, > + pSubmits[i].pWaitSemaphores, > + pSubmits[i].waitSemaphoreCount, > + pSubmits[i].pSignalSemaphores, > + pSubmits[i].signalSemaphoreCount); > + if (result != VK_SUCCESS) > + goto out; > + > + continue; > + } > + > for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) { > ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, > pSubmits[i].pCommandBuffers[j]); > @@ -554,6 +571,11 @@ VkResult anv_CreateSemaphore( > * EXEC_OBJECT_ASYNC bit set. > */ > semaphore->permanent.bo->flags &= ~EXEC_OBJECT_ASYNC; > + } else if (handleTypes & > VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX) { > + assert(handleTypes == > VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX); > + > + semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE; > + semaphore->permanent.fd = -1; > } else { > assert(!"Unknown handle type"); > vk_free2(&device->alloc, pAllocator, semaphore); > @@ -581,6 +603,10 @@ anv_semaphore_impl_cleanup(struct anv_device *device, > anv_bo_cache_release(device, &device->bo_cache, impl->bo); > break; > > + case ANV_SEMAPHORE_TYPE_SYNC_FILE: > + close(impl->fd); > + break; > + > default: > unreachable("Invalid semaphore type"); > } > @@ -608,6 +634,8 @@ void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHX( > const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo, > VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties) > { > + ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice); > + > switch (pExternalSemaphoreInfo->handleType) { > case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX: > pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; > @@ -616,13 +644,27 @@ void > anv_GetPhysicalDeviceExternalSemaphorePropertiesKHX( > pExternalSemaphoreProperties->externalSemaphoreFeatures = > VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX | > VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX; > + return; > + > + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX: > + if (device->has_exec_fence) { > + pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; > + pExternalSemaphoreProperties->compatibleHandleTypes = > + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX; > + pExternalSemaphoreProperties->externalSemaphoreFeatures = > + VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX | > + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX; > + return; > + } > break; > > default: > - pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; > - pExternalSemaphoreProperties->compatibleHandleTypes = 0; > - pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; > + break; > } > + > + pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; > + pExternalSemaphoreProperties->compatibleHandleTypes = 0; > + pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; > } > > VkResult anv_ImportSemaphoreFdKHX( > @@ -654,6 +696,14 @@ VkResult anv_ImportSemaphoreFdKHX( > return VK_SUCCESS; > } > > + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX: > + anv_semaphore_impl_cleanup(device, &semaphore->temporary); > + > + semaphore->temporary.type = ANV_SEMAPHORE_TYPE_SYNC_FILE; > + semaphore->temporary.fd = pImportSemaphoreFdInfo->fd; > + > + return VK_SUCCESS; > + > default: > return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX); > } > @@ -673,6 +723,23 @@ VkResult anv_GetSemaphoreFdKHX( > return anv_bo_cache_export(device, &device->bo_cache, > semaphore->permanent.bo, pFd); > > + case ANV_SEMAPHORE_TYPE_SYNC_FILE: > + /* There are two reasons why this could happen: > + * > + * 1) The user is trying to export without submitting something that > + * signals the semaphore. If this is the case, it's their bug so > + * what we return here doesn't matter. > + * > + * 2) The kernel didn't give us a file descriptor. The most likely > + * reason for this is running out of file descriptors. > + */ > + if (semaphore->permanent.fd < 0) > + return vk_error(VK_ERROR_TOO_MANY_OBJECTS); > + > + *pFd = semaphore->permanent.fd; > + semaphore->permanent.fd = -1; > + return VK_SUCCESS; > + > default: > return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX); > } > -- > 2.5.0.400.gff86faf > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev