[Mesa-dev] [PATCH 08/10] anv: Use DRM sync objects to back fences whenever possible
Jason Ekstrand
jason at jlekstrand.net
Thu Aug 24 18:02:54 UTC 2017
On Thu, Aug 24, 2017 at 10:39 AM, Jason Ekstrand <jason at jlekstrand.net>
wrote:
> 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.
>
Correction: This won't require more kernel API. I can fire off a dummy
execbuf to trigger the fence in the create function. It's just going to
require more kernel API to do cleanly.
--Jason
>
> --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/edff77d1/attachment-0001.html>
More information about the mesa-dev
mailing list