[Mesa-dev] [PATCH 08/10] anv: Use DRM sync objects to back fences whenever possible
Jason Ekstrand
jason at jlekstrand.net
Thu Aug 24 17:39:54 UTC 2017
On Thu, Aug 24, 2017 at 10:20 AM, Lionel Landwerlin <
lionel.g.landwerlin at intel.com> wrote:
> On 08/08/17 23:45, Jason Ekstrand wrote:
>
>> In order to implement VK_KHR_external_fence, we need to back our fences
>> with something that's shareable. Since the kernel wait interface for
>> sync objects already supports waiting for multiple fences in one go, it
>> makes anv_WaitForFences much simpler if we only have one type of fence.
>> ---
>> src/intel/vulkan/anv_batch_chain.c | 8 +++
>> src/intel/vulkan/anv_device.c | 2 +
>> src/intel/vulkan/anv_private.h | 4 ++
>> src/intel/vulkan/anv_queue.c | 132 ++++++++++++++++++++++++++++++
>> ++++---
>> 4 files changed, 136 insertions(+), 10 deletions(-)
>>
>> diff --git a/src/intel/vulkan/anv_batch_chain.c
>> b/src/intel/vulkan/anv_batch_chain.c
>> index 5d876e4..15082b5 100644
>> --- a/src/intel/vulkan/anv_batch_chain.c
>> +++ b/src/intel/vulkan/anv_batch_chain.c
>> @@ -1556,6 +1556,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,
>> return result;
>> break;
>> + case ANV_FENCE_TYPE_SYNCOBJ:
>> + result = anv_execbuf_add_syncobj(&execbuf, impl->syncobj,
>> + I915_EXEC_FENCE_SIGNAL,
>> + &device->alloc);
>> + if (result != VK_SUCCESS)
>> + return result;
>> + break;
>> +
>> default:
>> unreachable("Invalid fence type");
>> }
>> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.
>> c
>> index a6d5215..2e0fa19 100644
>> --- a/src/intel/vulkan/anv_device.c
>> +++ b/src/intel/vulkan/anv_device.c
>> @@ -339,6 +339,8 @@ anv_physical_device_init(struct anv_physical_device
>> *device,
>> 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);
>> device->has_syncobj = anv_gem_get_param(fd,
>> I915_PARAM_HAS_EXEC_FENCE_ARRAY);
>> + device->has_syncobj_wait = device->has_syncobj &&
>> + anv_gem_supports_syncobj_wait(fd);
>> bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);
>> diff --git a/src/intel/vulkan/anv_private.h
>> b/src/intel/vulkan/anv_private.h
>> index 2f89d3f..430652d 100644
>> --- a/src/intel/vulkan/anv_private.h
>> +++ b/src/intel/vulkan/anv_private.h
>> @@ -654,6 +654,7 @@ struct anv_physical_device {
>> bool has_exec_async;
>> bool has_exec_fence;
>> bool has_syncobj;
>> + bool has_syncobj_wait;
>> uint32_t eu_total;
>> uint32_t subslice_total;
>> @@ -1755,6 +1756,9 @@ struct anv_fence_impl {
>> struct anv_bo bo;
>> enum anv_bo_fence_state state;
>> } bo;
>> +
>> + /** DRM syncobj handle for syncobj-based fences */
>> + uint32_t syncobj;
>> };
>> };
>> diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
>> index 7348e15..8e45bb2 100644
>> --- a/src/intel/vulkan/anv_queue.c
>> +++ b/src/intel/vulkan/anv_queue.c
>> @@ -271,17 +271,25 @@ VkResult anv_CreateFence(
>> if (fence == NULL)
>> return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
>> - fence->permanent.type = ANV_FENCE_TYPE_BO;
>> + if (device->instance->physicalDevice.has_syncobj_wait) {
>> + fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
>> - VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool,
>> - &fence->permanent.bo.bo, 4096);
>> - if (result != VK_SUCCESS)
>> - return result;
>> -
>> - if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
>> - fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
>> + fence->permanent.syncobj = anv_gem_syncobj_create(device);
>> + if (!fence->permanent.syncobj)
>> + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
>>
>
> Don't you need to do something when the fence is created with the signaled
> bit with drm syncobj?
> I didn't see anything in the spec that would make this illegal so I assume
> we have to handle it.
>
Hrm... Yes, I think we do. Unfortunately, that's going to require
additional kernel API. :( Thanks for catching that, I'll work on it today.
--Jason
> } else {
>> - fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
>> + fence->permanent.type = ANV_FENCE_TYPE_BO;
>> +
>> + VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool,
>> + &fence->permanent.bo.bo,
>> 4096);
>> + if (result != VK_SUCCESS)
>> + return result;
>> +
>> + if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
>> + fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
>> + } else {
>> + fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
>> + }
>> }
>> *pFence = anv_fence_to_handle(fence);
>> @@ -301,6 +309,10 @@ anv_fence_impl_cleanup(struct anv_device *device,
>> case ANV_FENCE_TYPE_BO:
>> anv_bo_pool_free(&device->batch_bo_pool, &impl->bo.bo);
>> return;
>> +
>> + case ANV_FENCE_TYPE_SYNCOBJ:
>> + anv_gem_syncobj_destroy(device, impl->syncobj);
>> + return;
>> }
>> unreachable("Invalid fence type");
>> @@ -328,6 +340,8 @@ VkResult anv_ResetFences(
>> uint32_t fenceCount,
>> const VkFence* pFences)
>> {
>> + ANV_FROM_HANDLE(anv_device, device, _device);
>> +
>> for (uint32_t i = 0; i < fenceCount; i++) {
>> ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
>> @@ -339,6 +353,10 @@ VkResult anv_ResetFences(
>> impl->bo.state = ANV_BO_FENCE_STATE_RESET;
>> break;
>> + case ANV_FENCE_TYPE_SYNCOBJ:
>> + anv_gem_syncobj_reset(device, impl->syncobj);
>> + break;
>> +
>> default:
>> unreachable("Invalid fence type");
>> }
>> @@ -384,6 +402,22 @@ VkResult anv_GetFenceStatus(
>> unreachable("Invalid fence status");
>> }
>> + case ANV_FENCE_TYPE_SYNCOBJ: {
>> + int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);
>> + if (ret == -1) {
>> + if (errno == ETIME) {
>> + return VK_NOT_READY;
>> + } else {
>> + /* We don't know the real error. */
>> + device->lost = true;
>> + return vk_errorf(VK_ERROR_DEVICE_LOST,
>> + "drm_syncobj_wait failed: %m");
>> + }
>> + } else {
>> + return VK_SUCCESS;
>> + }
>> + }
>> +
>> default:
>> unreachable("Invalid fence type");
>> }
>> @@ -392,6 +426,78 @@ VkResult anv_GetFenceStatus(
>> #define NSEC_PER_SEC 1000000000
>> #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
>> +static uint64_t
>> +gettime_ns(void)
>> +{
>> + struct timespec current;
>> + clock_gettime(CLOCK_MONOTONIC, ¤t);
>> + return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
>> +}
>> +
>> +static VkResult
>> +anv_wait_for_syncobj_fences(struct anv_device *device,
>> + uint32_t fenceCount,
>> + const VkFence *pFences,
>> + bool waitAll,
>> + uint64_t _timeout)
>> +{
>> + uint32_t *syncobjs = vk_zalloc(&device->alloc,
>> + sizeof(*syncobjs) * fenceCount, 8,
>> + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
>> + if (!syncobjs)
>> + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
>> +
>> + for (uint32_t i = 0; i < fenceCount; i++) {
>> + ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
>> + assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
>> +
>> + struct anv_fence_impl *impl =
>> + fence->temporary.type != ANV_FENCE_TYPE_NONE ?
>> + &fence->temporary : &fence->permanent;
>> +
>> + assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
>> + syncobjs[i] = impl->syncobj;
>> + }
>> +
>> + int64_t abs_timeout_ns = 0;
>> + if (_timeout > 0) {
>> + uint64_t current_ns = gettime_ns();
>> +
>> + /* Add but saturate to INT32_MAX */
>> + if (current_ns + _timeout < current_ns)
>> + abs_timeout_ns = INT64_MAX;
>> + else if (current_ns + _timeout > INT64_MAX)
>> + abs_timeout_ns = INT64_MAX;
>> + else
>> + abs_timeout_ns = current_ns + _timeout;
>> + }
>> +
>> + /* The gem_syncobj_wait ioctl may return early due to an inherent
>> + * limitation in the way it computes timeouts. Loop until we've
>> actually
>> + * passed the timeout.
>> + */
>> + int ret;
>> + do {
>> + ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
>> + abs_timeout_ns, waitAll);
>> + } while (ret == -1 && errno == ETIME && gettime_ns() <
>> abs_timeout_ns);
>> +
>> + vk_free(&device->alloc, syncobjs);
>> +
>> + if (ret == -1) {
>> + if (errno == ETIME) {
>> + return VK_TIMEOUT;
>> + } else {
>> + /* We don't know the real error. */
>> + device->lost = true;
>> + return vk_errorf(VK_ERROR_DEVICE_LOST,
>> + "drm_syncobj_wait failed: %m");
>> + }
>> + } else {
>> + return VK_SUCCESS;
>> + }
>> +}
>> +
>> static VkResult
>> anv_wait_for_bo_fences(struct anv_device *device,
>> uint32_t fenceCount,
>> @@ -546,7 +652,13 @@ VkResult anv_WaitForFences(
>> if (unlikely(device->lost))
>> return VK_ERROR_DEVICE_LOST;
>> - return anv_wait_for_bo_fences(device, fenceCount, pFences, waitAll,
>> timeout);
>> + if (device->instance->physicalDevice.has_syncobj_wait) {
>> + return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
>> + waitAll, timeout);
>> + } else {
>> + return anv_wait_for_bo_fences(device, fenceCount, pFences,
>> + waitAll, timeout);
>> + }
>> }
>> // Queue semaphore functions
>>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170824/82f42360/attachment-0001.html>
More information about the mesa-dev
mailing list