<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Aug 24, 2017 at 10:39 AM, Jason Ekstrand <span dir="ltr"><<a href="mailto:jason@jlekstrand.net" target="_blank">jason@jlekstrand.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">On Thu, Aug 24, 2017 at 10:20 AM, Lionel Landwerlin <span dir="ltr"><<a href="mailto:lionel.g.landwerlin@intel.com" target="_blank">lionel.g.landwerlin@intel.com</a><wbr>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_-5540633037926366307HOEnZb"><div class="m_-5540633037926366307h5">On 08/08/17 23:45, Jason Ekstrand wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In order to implement VK_KHR_external_fence, we need to back our fences<br>
with something that's shareable. Since the kernel wait interface for<br>
sync objects already supports waiting for multiple fences in one go, it<br>
makes anv_WaitForFences much simpler if we only have one type of fence.<br>
---<br>
src/intel/vulkan/anv_batch_cha<wbr>in.c | 8 +++<br>
src/intel/vulkan/anv_device.c | 2 +<br>
src/intel/vulkan/anv_private.h<wbr> | 4 ++<br>
src/intel/vulkan/anv_queue.c | 132 ++++++++++++++++++++++++++++++<wbr>++++---<br>
4 files changed, 136 insertions(+), 10 deletions(-)<br>
<br>
diff --git a/src/intel/vulkan/anv_batch_c<wbr>hain.c b/src/intel/vulkan/anv_batch_c<wbr>hain.c<br>
index 5d876e4..15082b5 100644<br>
--- a/src/intel/vulkan/anv_batch_c<wbr>hain.c<br>
+++ b/src/intel/vulkan/anv_batch_c<wbr>hain.c<br>
@@ -1556,6 +1556,14 @@ anv_cmd_buffer_execbuf(struct anv_device *device,<br>
return result;<br>
break;<br>
+ case ANV_FENCE_TYPE_SYNCOBJ:<br>
+ result = anv_execbuf_add_syncobj(&execb<wbr>uf, impl->syncobj,<br>
+ I915_EXEC_FENCE_SIGNAL,<br>
+ &device->alloc);<br>
+ if (result != VK_SUCCESS)<br>
+ return result;<br>
+ break;<br>
+<br>
default:<br>
unreachable("Invalid fence type");<br>
}<br>
diff --git a/src/intel/vulkan/anv_device.<wbr>c b/src/intel/vulkan/anv_device.<wbr>c<br>
index a6d5215..2e0fa19 100644<br>
--- a/src/intel/vulkan/anv_device.<wbr>c<br>
+++ b/src/intel/vulkan/anv_device.<wbr>c<br>
@@ -339,6 +339,8 @@ anv_physical_device_init(struc<wbr>t anv_physical_device *device,<br>
device->has_exec_async = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_ASYNC);<br>
device->has_exec_fence = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE);<br>
device->has_syncobj = anv_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE_ARRA<wbr>Y);<br>
+ device->has_syncobj_wait = device->has_syncobj &&<br>
+ anv_gem_supports_syncobj_wait(<wbr>fd);<br>
bool swizzled = anv_gem_get_bit6_swizzle(fd, I915_TILING_X);<br>
diff --git a/src/intel/vulkan/anv_private<wbr>.h b/src/intel/vulkan/anv_private<wbr>.h<br>
index 2f89d3f..430652d 100644<br>
--- a/src/intel/vulkan/anv_private<wbr>.h<br>
+++ b/src/intel/vulkan/anv_private<wbr>.h<br>
@@ -654,6 +654,7 @@ struct anv_physical_device {<br>
bool has_exec_async;<br>
bool has_exec_fence;<br>
bool has_syncobj;<br>
+ bool has_syncobj_wait;<br>
uint32_t eu_total;<br>
uint32_t subslice_total;<br>
@@ -1755,6 +1756,9 @@ struct anv_fence_impl {<br>
struct anv_bo bo;<br>
enum anv_bo_fence_state state;<br>
} bo;<br>
+<br>
+ /** DRM syncobj handle for syncobj-based fences */<br>
+ uint32_t syncobj;<br>
};<br>
};<br>
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c<br>
index 7348e15..8e45bb2 100644<br>
--- a/src/intel/vulkan/anv_queue.c<br>
+++ b/src/intel/vulkan/anv_queue.c<br>
@@ -271,17 +271,25 @@ VkResult anv_CreateFence(<br>
if (fence == NULL)<br>
return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
- fence->permanent.type = ANV_FENCE_TYPE_BO;<br>
+ if (device->instance->physicalDev<wbr>ice.has_syncobj_wait) {<br>
+ fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;<br>
- VkResult result = anv_bo_pool_alloc(&device->bat<wbr>ch_bo_pool,<br>
- &fence-><a href="http://permanent.bo.bo" rel="noreferrer" target="_blank">permanent.bo.bo</a>, 4096);<br>
- if (result != VK_SUCCESS)<br>
- return result;<br>
-<br>
- if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {<br>
- fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;<br>
+ fence->permanent.syncobj = anv_gem_syncobj_create(device)<wbr>;<br>
+ if (!fence->permanent.syncobj)<br>
+ return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
</blockquote>
<br></div></div>
Don't you need to do something when the fence is created with the signaled bit with drm syncobj?<br>
I didn't see anything in the spec that would make this illegal so I assume we have to handle it.<br>
</blockquote><div><br></div></div></div><div>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.</div></div></div></div></blockquote><div><br></div><div>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.</div><div><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="HOEnZb"><font color="#888888"><div><br></div><div>--Jason<br></div></font></span><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_-5540633037926366307HOEnZb"><div class="m_-5540633037926366307h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
} else {<br>
- fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;<br>
+ fence->permanent.type = ANV_FENCE_TYPE_BO;<br>
+<br>
+ VkResult result = anv_bo_pool_alloc(&device->bat<wbr>ch_bo_pool,<br>
+ &fence-><a href="http://permanent.bo.bo" rel="noreferrer" target="_blank">permanent.bo.bo</a>, 4096);<br>
+ if (result != VK_SUCCESS)<br>
+ return result;<br>
+<br>
+ if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {<br>
+ fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;<br>
+ } else {<br>
+ fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;<br>
+ }<br>
}<br>
*pFence = anv_fence_to_handle(fence);<br>
@@ -301,6 +309,10 @@ anv_fence_impl_cleanup(struct anv_device *device,<br>
case ANV_FENCE_TYPE_BO:<br>
anv_bo_pool_free(&device->batc<wbr>h_bo_pool, &impl-><a href="http://bo.bo" rel="noreferrer" target="_blank">bo.bo</a>);<br>
return;<br>
+<br>
+ case ANV_FENCE_TYPE_SYNCOBJ:<br>
+ anv_gem_syncobj_destroy(device<wbr>, impl->syncobj);<br>
+ return;<br>
}<br>
unreachable("Invalid fence type");<br>
@@ -328,6 +340,8 @@ VkResult anv_ResetFences(<br>
uint32_t fenceCount,<br>
const VkFence* pFences)<br>
{<br>
+ ANV_FROM_HANDLE(anv_device, device, _device);<br>
+<br>
for (uint32_t i = 0; i < fenceCount; i++) {<br>
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);<br>
@@ -339,6 +353,10 @@ VkResult anv_ResetFences(<br>
impl->bo.state = ANV_BO_FENCE_STATE_RESET;<br>
break;<br>
+ case ANV_FENCE_TYPE_SYNCOBJ:<br>
+ anv_gem_syncobj_reset(device, impl->syncobj);<br>
+ break;<br>
+<br>
default:<br>
unreachable("Invalid fence type");<br>
}<br>
@@ -384,6 +402,22 @@ VkResult anv_GetFenceStatus(<br>
unreachable("Invalid fence status");<br>
}<br>
+ case ANV_FENCE_TYPE_SYNCOBJ: {<br>
+ int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);<br>
+ if (ret == -1) {<br>
+ if (errno == ETIME) {<br>
+ return VK_NOT_READY;<br>
+ } else {<br>
+ /* We don't know the real error. */<br>
+ device->lost = true;<br>
+ return vk_errorf(VK_ERROR_DEVICE_LOST<wbr>,<br>
+ "drm_syncobj_wait failed: %m");<br>
+ }<br>
+ } else {<br>
+ return VK_SUCCESS;<br>
+ }<br>
+ }<br>
+<br>
default:<br>
unreachable("Invalid fence type");<br>
}<br>
@@ -392,6 +426,78 @@ VkResult anv_GetFenceStatus(<br>
#define NSEC_PER_SEC 1000000000<br>
#define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)<br>
+static uint64_t<br>
+gettime_ns(void)<br>
+{<br>
+ struct timespec current;<br>
+ clock_gettime(CLOCK_MONOTONIC<wbr>, ¤t);<br>
+ return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;<br>
+}<br>
+<br>
+static VkResult<br>
+anv_wait_for_syncobj_fences(s<wbr>truct anv_device *device,<br>
+ uint32_t fenceCount,<br>
+ const VkFence *pFences,<br>
+ bool waitAll,<br>
+ uint64_t _timeout)<br>
+{<br>
+ uint32_t *syncobjs = vk_zalloc(&device->alloc,<br>
+ sizeof(*syncobjs) * fenceCount, 8,<br>
+ VK_SYSTEM_ALLOCATION_SCOPE_COM<wbr>MAND);<br>
+ if (!syncobjs)<br>
+ return vk_error(VK_ERROR_OUT_OF_HOST_<wbr>MEMORY);<br>
+<br>
+ for (uint32_t i = 0; i < fenceCount; i++) {<br>
+ ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);<br>
+ assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);<br>
+<br>
+ struct anv_fence_impl *impl =<br>
+ fence->temporary.type != ANV_FENCE_TYPE_NONE ?<br>
+ &fence->temporary : &fence->permanent;<br>
+<br>
+ assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);<br>
+ syncobjs[i] = impl->syncobj;<br>
+ }<br>
+<br>
+ int64_t abs_timeout_ns = 0;<br>
+ if (_timeout > 0) {<br>
+ uint64_t current_ns = gettime_ns();<br>
+<br>
+ /* Add but saturate to INT32_MAX */<br>
+ if (current_ns + _timeout < current_ns)<br>
+ abs_timeout_ns = INT64_MAX;<br>
+ else if (current_ns + _timeout > INT64_MAX)<br>
+ abs_timeout_ns = INT64_MAX;<br>
+ else<br>
+ abs_timeout_ns = current_ns + _timeout;<br>
+ }<br>
+<br>
+ /* The gem_syncobj_wait ioctl may return early due to an inherent<br>
+ * limitation in the way it computes timeouts. Loop until we've actually<br>
+ * passed the timeout.<br>
+ */<br>
+ int ret;<br>
+ do {<br>
+ ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,<br>
+ abs_timeout_ns, waitAll);<br>
+ } while (ret == -1 && errno == ETIME && gettime_ns() < abs_timeout_ns);<br>
+<br>
+ vk_free(&device->alloc, syncobjs);<br>
+<br>
+ if (ret == -1) {<br>
+ if (errno == ETIME) {<br>
+ return VK_TIMEOUT;<br>
+ } else {<br>
+ /* We don't know the real error. */<br>
+ device->lost = true;<br>
+ return vk_errorf(VK_ERROR_DEVICE_LOST<wbr>,<br>
+ "drm_syncobj_wait failed: %m");<br>
+ }<br>
+ } else {<br>
+ return VK_SUCCESS;<br>
+ }<br>
+}<br>
+<br>
static VkResult<br>
anv_wait_for_bo_fences(struct anv_device *device,<br>
uint32_t fenceCount,<br>
@@ -546,7 +652,13 @@ VkResult anv_WaitForFences(<br>
if (unlikely(device->lost))<br>
return VK_ERROR_DEVICE_LOST;<br>
- return anv_wait_for_bo_fences(device, fenceCount, pFences, waitAll, timeout);<br>
+ if (device->instance->physicalDev<wbr>ice.has_syncobj_wait) {<br>
+ return anv_wait_for_syncobj_fences(de<wbr>vice, fenceCount, pFences,<br>
+ waitAll, timeout);<br>
+ } else {<br>
+ return anv_wait_for_bo_fences(device, fenceCount, pFences,<br>
+ waitAll, timeout);<br>
+ }<br>
}<br>
// Queue semaphore functions<br>
</blockquote>
<br>
<br>
</div></div></blockquote></div></div></div><br></div></div>
</blockquote></div><br></div></div>