1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2021 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "vk_sync_timeline.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <inttypes.h> 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "util/os_time.h" 29bf215546Sopenharmony_ci#include "util/timespec.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "vk_alloc.h" 32bf215546Sopenharmony_ci#include "vk_device.h" 33bf215546Sopenharmony_ci#include "vk_log.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_cistatic struct vk_sync_timeline * 36bf215546Sopenharmony_cito_vk_sync_timeline(struct vk_sync *sync) 37bf215546Sopenharmony_ci{ 38bf215546Sopenharmony_ci assert(sync->type->init == vk_sync_timeline_init); 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci return container_of(sync, struct vk_sync_timeline, sync); 41bf215546Sopenharmony_ci} 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_cistatic void 44bf215546Sopenharmony_civk_sync_timeline_type_validate(const struct vk_sync_timeline_type *ttype) 45bf215546Sopenharmony_ci{ 46bf215546Sopenharmony_ci ASSERTED const enum vk_sync_features req_features = 47bf215546Sopenharmony_ci VK_SYNC_FEATURE_BINARY | 48bf215546Sopenharmony_ci VK_SYNC_FEATURE_GPU_WAIT | 49bf215546Sopenharmony_ci VK_SYNC_FEATURE_GPU_MULTI_WAIT | 50bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_WAIT | 51bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_RESET; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci assert(!(req_features & ~ttype->point_sync_type->features)); 54bf215546Sopenharmony_ci} 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ciVkResult 57bf215546Sopenharmony_civk_sync_timeline_init(struct vk_device *device, 58bf215546Sopenharmony_ci struct vk_sync *sync, 59bf215546Sopenharmony_ci uint64_t initial_value) 60bf215546Sopenharmony_ci{ 61bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = to_vk_sync_timeline(sync); 62bf215546Sopenharmony_ci int ret; 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci ASSERTED const struct vk_sync_timeline_type *ttype = 65bf215546Sopenharmony_ci container_of(timeline->sync.type, struct vk_sync_timeline_type, sync); 66bf215546Sopenharmony_ci vk_sync_timeline_type_validate(ttype); 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci ret = mtx_init(&timeline->mutex, mtx_plain); 69bf215546Sopenharmony_ci if (ret != thrd_success) 70bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, "mtx_init failed"); 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci ret = cnd_init(&timeline->cond); 73bf215546Sopenharmony_ci if (ret != thrd_success) { 74bf215546Sopenharmony_ci mtx_destroy(&timeline->mutex); 75bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, "cnd_init failed"); 76bf215546Sopenharmony_ci } 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci timeline->highest_past = 79bf215546Sopenharmony_ci timeline->highest_pending = initial_value; 80bf215546Sopenharmony_ci list_inithead(&timeline->pending_points); 81bf215546Sopenharmony_ci list_inithead(&timeline->free_points); 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci return VK_SUCCESS; 84bf215546Sopenharmony_ci} 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_cistatic void 87bf215546Sopenharmony_civk_sync_timeline_finish(struct vk_device *device, 88bf215546Sopenharmony_ci struct vk_sync *sync) 89bf215546Sopenharmony_ci{ 90bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = to_vk_sync_timeline(sync); 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci list_for_each_entry_safe(struct vk_sync_timeline_point, point, 93bf215546Sopenharmony_ci &timeline->free_points, link) { 94bf215546Sopenharmony_ci list_del(&point->link); 95bf215546Sopenharmony_ci vk_sync_finish(device, &point->sync); 96bf215546Sopenharmony_ci vk_free(&device->alloc, point); 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci list_for_each_entry_safe(struct vk_sync_timeline_point, point, 99bf215546Sopenharmony_ci &timeline->pending_points, link) { 100bf215546Sopenharmony_ci list_del(&point->link); 101bf215546Sopenharmony_ci vk_sync_finish(device, &point->sync); 102bf215546Sopenharmony_ci vk_free(&device->alloc, point); 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci cnd_destroy(&timeline->cond); 106bf215546Sopenharmony_ci mtx_destroy(&timeline->mutex); 107bf215546Sopenharmony_ci} 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_cistatic struct vk_sync_timeline_point * 110bf215546Sopenharmony_civk_sync_timeline_first_point(struct vk_sync_timeline *timeline) 111bf215546Sopenharmony_ci{ 112bf215546Sopenharmony_ci struct vk_sync_timeline_point *point = 113bf215546Sopenharmony_ci list_first_entry(&timeline->pending_points, 114bf215546Sopenharmony_ci struct vk_sync_timeline_point, link); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci assert(point->value <= timeline->highest_pending); 117bf215546Sopenharmony_ci assert(point->value > timeline->highest_past); 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci return point; 120bf215546Sopenharmony_ci} 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_cistatic VkResult 123bf215546Sopenharmony_civk_sync_timeline_gc_locked(struct vk_device *device, 124bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 125bf215546Sopenharmony_ci bool drain); 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic VkResult 128bf215546Sopenharmony_civk_sync_timeline_alloc_point_locked(struct vk_device *device, 129bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 130bf215546Sopenharmony_ci uint64_t value, 131bf215546Sopenharmony_ci struct vk_sync_timeline_point **point_out) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci struct vk_sync_timeline_point *point; 134bf215546Sopenharmony_ci VkResult result; 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci result = vk_sync_timeline_gc_locked(device, timeline, false); 137bf215546Sopenharmony_ci if (unlikely(result != VK_SUCCESS)) 138bf215546Sopenharmony_ci return result; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci if (list_is_empty(&timeline->free_points)) { 141bf215546Sopenharmony_ci const struct vk_sync_timeline_type *ttype = 142bf215546Sopenharmony_ci container_of(timeline->sync.type, struct vk_sync_timeline_type, sync); 143bf215546Sopenharmony_ci const struct vk_sync_type *point_sync_type = ttype->point_sync_type; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci size_t size = offsetof(struct vk_sync_timeline_point, sync) + 146bf215546Sopenharmony_ci point_sync_type->size; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci point = vk_zalloc(&device->alloc, size, 8, 149bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 150bf215546Sopenharmony_ci if (!point) 151bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci point->timeline = timeline; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci result = vk_sync_init(device, &point->sync, point_sync_type, 156bf215546Sopenharmony_ci 0 /* flags */, 0 /* initial_value */); 157bf215546Sopenharmony_ci if (unlikely(result != VK_SUCCESS)) { 158bf215546Sopenharmony_ci vk_free(&device->alloc, point); 159bf215546Sopenharmony_ci return result; 160bf215546Sopenharmony_ci } 161bf215546Sopenharmony_ci } else { 162bf215546Sopenharmony_ci point = list_first_entry(&timeline->free_points, 163bf215546Sopenharmony_ci struct vk_sync_timeline_point, link); 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci if (point->sync.type->reset) { 166bf215546Sopenharmony_ci result = vk_sync_reset(device, &point->sync); 167bf215546Sopenharmony_ci if (unlikely(result != VK_SUCCESS)) 168bf215546Sopenharmony_ci return result; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci list_del(&point->link); 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci point->value = value; 175bf215546Sopenharmony_ci *point_out = point; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci return VK_SUCCESS; 178bf215546Sopenharmony_ci} 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ciVkResult 181bf215546Sopenharmony_civk_sync_timeline_alloc_point(struct vk_device *device, 182bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 183bf215546Sopenharmony_ci uint64_t value, 184bf215546Sopenharmony_ci struct vk_sync_timeline_point **point_out) 185bf215546Sopenharmony_ci{ 186bf215546Sopenharmony_ci VkResult result; 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 189bf215546Sopenharmony_ci result = vk_sync_timeline_alloc_point_locked(device, timeline, value, point_out); 190bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci return result; 193bf215546Sopenharmony_ci} 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_cistatic void 196bf215546Sopenharmony_civk_sync_timeline_point_free_locked(struct vk_sync_timeline *timeline, 197bf215546Sopenharmony_ci struct vk_sync_timeline_point *point) 198bf215546Sopenharmony_ci{ 199bf215546Sopenharmony_ci assert(point->refcount == 0 && !point->pending); 200bf215546Sopenharmony_ci list_add(&point->link, &timeline->free_points); 201bf215546Sopenharmony_ci} 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_civoid 204bf215546Sopenharmony_civk_sync_timeline_point_free(struct vk_device *device, 205bf215546Sopenharmony_ci struct vk_sync_timeline_point *point) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = point->timeline; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 210bf215546Sopenharmony_ci vk_sync_timeline_point_free_locked(timeline, point); 211bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 212bf215546Sopenharmony_ci} 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_cistatic void 215bf215546Sopenharmony_civk_sync_timeline_point_ref(struct vk_sync_timeline_point *point) 216bf215546Sopenharmony_ci{ 217bf215546Sopenharmony_ci point->refcount++; 218bf215546Sopenharmony_ci} 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_cistatic void 221bf215546Sopenharmony_civk_sync_timeline_point_unref(struct vk_sync_timeline *timeline, 222bf215546Sopenharmony_ci struct vk_sync_timeline_point *point) 223bf215546Sopenharmony_ci{ 224bf215546Sopenharmony_ci assert(point->refcount > 0); 225bf215546Sopenharmony_ci point->refcount--; 226bf215546Sopenharmony_ci if (point->refcount == 0 && !point->pending) 227bf215546Sopenharmony_ci vk_sync_timeline_point_free_locked(timeline, point); 228bf215546Sopenharmony_ci} 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_cistatic void 231bf215546Sopenharmony_civk_sync_timeline_point_complete(struct vk_sync_timeline *timeline, 232bf215546Sopenharmony_ci struct vk_sync_timeline_point *point) 233bf215546Sopenharmony_ci{ 234bf215546Sopenharmony_ci if (!point->pending) 235bf215546Sopenharmony_ci return; 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci assert(timeline->highest_past < point->value); 238bf215546Sopenharmony_ci timeline->highest_past = point->value; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci point->pending = false; 241bf215546Sopenharmony_ci list_del(&point->link); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci if (point->refcount == 0) 244bf215546Sopenharmony_ci vk_sync_timeline_point_free_locked(timeline, point); 245bf215546Sopenharmony_ci} 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_cistatic VkResult 248bf215546Sopenharmony_civk_sync_timeline_gc_locked(struct vk_device *device, 249bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 250bf215546Sopenharmony_ci bool drain) 251bf215546Sopenharmony_ci{ 252bf215546Sopenharmony_ci list_for_each_entry_safe(struct vk_sync_timeline_point, point, 253bf215546Sopenharmony_ci &timeline->pending_points, link) { 254bf215546Sopenharmony_ci /* timeline->higest_pending is only incremented once submission has 255bf215546Sopenharmony_ci * happened. If this point has a greater serial, it means the point 256bf215546Sopenharmony_ci * hasn't been submitted yet. 257bf215546Sopenharmony_ci */ 258bf215546Sopenharmony_ci if (point->value > timeline->highest_pending) 259bf215546Sopenharmony_ci return VK_SUCCESS; 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci /* If someone is waiting on this time point, consider it busy and don't 262bf215546Sopenharmony_ci * try to recycle it. There's a slim possibility that it's no longer 263bf215546Sopenharmony_ci * busy by the time we look at it but we would be recycling it out from 264bf215546Sopenharmony_ci * under a waiter and that can lead to weird races. 265bf215546Sopenharmony_ci * 266bf215546Sopenharmony_ci * We walk the list in-order so if this time point is still busy so is 267bf215546Sopenharmony_ci * every following time point 268bf215546Sopenharmony_ci */ 269bf215546Sopenharmony_ci assert(point->refcount >= 0); 270bf215546Sopenharmony_ci if (point->refcount > 0 && !drain) 271bf215546Sopenharmony_ci return VK_SUCCESS; 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci /* Garbage collect any signaled point. */ 274bf215546Sopenharmony_ci VkResult result = vk_sync_wait(device, &point->sync, 0, 275bf215546Sopenharmony_ci VK_SYNC_WAIT_COMPLETE, 276bf215546Sopenharmony_ci 0 /* abs_timeout_ns */); 277bf215546Sopenharmony_ci if (result == VK_TIMEOUT) { 278bf215546Sopenharmony_ci /* We walk the list in-order so if this time point is still busy so 279bf215546Sopenharmony_ci * is every following time point 280bf215546Sopenharmony_ci */ 281bf215546Sopenharmony_ci return VK_SUCCESS; 282bf215546Sopenharmony_ci } else if (result != VK_SUCCESS) { 283bf215546Sopenharmony_ci return result; 284bf215546Sopenharmony_ci } 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci vk_sync_timeline_point_complete(timeline, point); 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci return VK_SUCCESS; 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ciVkResult 293bf215546Sopenharmony_civk_sync_timeline_point_install(struct vk_device *device, 294bf215546Sopenharmony_ci struct vk_sync_timeline_point *point) 295bf215546Sopenharmony_ci{ 296bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = point->timeline; 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci assert(point->value > timeline->highest_pending); 301bf215546Sopenharmony_ci timeline->highest_pending = point->value; 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci assert(point->refcount == 0); 304bf215546Sopenharmony_ci point->pending = true; 305bf215546Sopenharmony_ci list_addtail(&point->link, &timeline->pending_points); 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci int ret = cnd_broadcast(&timeline->cond); 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci if (ret == thrd_error) 312bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, "cnd_broadcast failed"); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci return VK_SUCCESS; 315bf215546Sopenharmony_ci} 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_cistatic VkResult 318bf215546Sopenharmony_civk_sync_timeline_get_point_locked(struct vk_device *device, 319bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 320bf215546Sopenharmony_ci uint64_t wait_value, 321bf215546Sopenharmony_ci struct vk_sync_timeline_point **point_out) 322bf215546Sopenharmony_ci{ 323bf215546Sopenharmony_ci if (timeline->highest_past >= wait_value) { 324bf215546Sopenharmony_ci /* Nothing to wait on */ 325bf215546Sopenharmony_ci *point_out = NULL; 326bf215546Sopenharmony_ci return VK_SUCCESS; 327bf215546Sopenharmony_ci } 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci list_for_each_entry(struct vk_sync_timeline_point, point, 330bf215546Sopenharmony_ci &timeline->pending_points, link) { 331bf215546Sopenharmony_ci if (point->value >= wait_value) { 332bf215546Sopenharmony_ci vk_sync_timeline_point_ref(point); 333bf215546Sopenharmony_ci *point_out = point; 334bf215546Sopenharmony_ci return VK_SUCCESS; 335bf215546Sopenharmony_ci } 336bf215546Sopenharmony_ci } 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci return VK_NOT_READY; 339bf215546Sopenharmony_ci} 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ciVkResult 342bf215546Sopenharmony_civk_sync_timeline_get_point(struct vk_device *device, 343bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 344bf215546Sopenharmony_ci uint64_t wait_value, 345bf215546Sopenharmony_ci struct vk_sync_timeline_point **point_out) 346bf215546Sopenharmony_ci{ 347bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 348bf215546Sopenharmony_ci VkResult result = vk_sync_timeline_get_point_locked(device, timeline, 349bf215546Sopenharmony_ci wait_value, point_out); 350bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci return result; 353bf215546Sopenharmony_ci} 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_civoid 356bf215546Sopenharmony_civk_sync_timeline_point_release(struct vk_device *device, 357bf215546Sopenharmony_ci struct vk_sync_timeline_point *point) 358bf215546Sopenharmony_ci{ 359bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = point->timeline; 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 362bf215546Sopenharmony_ci vk_sync_timeline_point_unref(timeline, point); 363bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 364bf215546Sopenharmony_ci} 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_cistatic VkResult 367bf215546Sopenharmony_civk_sync_timeline_signal_locked(struct vk_device *device, 368bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 369bf215546Sopenharmony_ci uint64_t value) 370bf215546Sopenharmony_ci{ 371bf215546Sopenharmony_ci VkResult result = vk_sync_timeline_gc_locked(device, timeline, true); 372bf215546Sopenharmony_ci if (unlikely(result != VK_SUCCESS)) 373bf215546Sopenharmony_ci return result; 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci if (unlikely(value <= timeline->highest_past)) { 376bf215546Sopenharmony_ci return vk_device_set_lost(device, "Timeline values must only ever " 377bf215546Sopenharmony_ci "strictly increase."); 378bf215546Sopenharmony_ci } 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci assert(list_is_empty(&timeline->pending_points)); 381bf215546Sopenharmony_ci assert(timeline->highest_pending == timeline->highest_past); 382bf215546Sopenharmony_ci timeline->highest_pending = timeline->highest_past = value; 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci int ret = cnd_broadcast(&timeline->cond); 385bf215546Sopenharmony_ci if (ret == thrd_error) 386bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, "cnd_broadcast failed"); 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci return VK_SUCCESS; 389bf215546Sopenharmony_ci} 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_cistatic VkResult 392bf215546Sopenharmony_civk_sync_timeline_signal(struct vk_device *device, 393bf215546Sopenharmony_ci struct vk_sync *sync, 394bf215546Sopenharmony_ci uint64_t value) 395bf215546Sopenharmony_ci{ 396bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = to_vk_sync_timeline(sync); 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 399bf215546Sopenharmony_ci VkResult result = vk_sync_timeline_signal_locked(device, timeline, value); 400bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci return result; 403bf215546Sopenharmony_ci} 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_cistatic VkResult 406bf215546Sopenharmony_civk_sync_timeline_get_value(struct vk_device *device, 407bf215546Sopenharmony_ci struct vk_sync *sync, 408bf215546Sopenharmony_ci uint64_t *value) 409bf215546Sopenharmony_ci{ 410bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = to_vk_sync_timeline(sync); 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 413bf215546Sopenharmony_ci VkResult result = vk_sync_timeline_gc_locked(device, timeline, true); 414bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci if (result != VK_SUCCESS) 417bf215546Sopenharmony_ci return result; 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci *value = timeline->highest_past; 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci return VK_SUCCESS; 422bf215546Sopenharmony_ci} 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_cistatic VkResult 425bf215546Sopenharmony_civk_sync_timeline_wait_locked(struct vk_device *device, 426bf215546Sopenharmony_ci struct vk_sync_timeline *timeline, 427bf215546Sopenharmony_ci uint64_t wait_value, 428bf215546Sopenharmony_ci enum vk_sync_wait_flags wait_flags, 429bf215546Sopenharmony_ci uint64_t abs_timeout_ns) 430bf215546Sopenharmony_ci{ 431bf215546Sopenharmony_ci /* Wait on the queue_submit condition variable until the timeline has a 432bf215546Sopenharmony_ci * time point pending that's at least as high as wait_value. 433bf215546Sopenharmony_ci */ 434bf215546Sopenharmony_ci uint64_t now_ns = os_time_get_nano(); 435bf215546Sopenharmony_ci while (timeline->highest_pending < wait_value) { 436bf215546Sopenharmony_ci if (now_ns >= abs_timeout_ns) 437bf215546Sopenharmony_ci return VK_TIMEOUT; 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci int ret; 440bf215546Sopenharmony_ci if (abs_timeout_ns >= INT64_MAX) { 441bf215546Sopenharmony_ci /* Common infinite wait case */ 442bf215546Sopenharmony_ci ret = cnd_wait(&timeline->cond, &timeline->mutex); 443bf215546Sopenharmony_ci } else { 444bf215546Sopenharmony_ci /* This is really annoying. The C11 threads API uses CLOCK_REALTIME 445bf215546Sopenharmony_ci * while all our absolute timeouts are in CLOCK_MONOTONIC. Best 446bf215546Sopenharmony_ci * thing we can do is to convert and hope the system admin doesn't 447bf215546Sopenharmony_ci * change the time out from under us. 448bf215546Sopenharmony_ci */ 449bf215546Sopenharmony_ci uint64_t rel_timeout_ns = abs_timeout_ns - now_ns; 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci struct timespec now_ts, abs_timeout_ts; 452bf215546Sopenharmony_ci timespec_get(&now_ts, TIME_UTC); 453bf215546Sopenharmony_ci if (timespec_add_nsec(&abs_timeout_ts, &now_ts, rel_timeout_ns)) { 454bf215546Sopenharmony_ci /* Overflowed; may as well be infinite */ 455bf215546Sopenharmony_ci ret = cnd_wait(&timeline->cond, &timeline->mutex); 456bf215546Sopenharmony_ci } else { 457bf215546Sopenharmony_ci ret = cnd_timedwait(&timeline->cond, &timeline->mutex, 458bf215546Sopenharmony_ci &abs_timeout_ts); 459bf215546Sopenharmony_ci } 460bf215546Sopenharmony_ci } 461bf215546Sopenharmony_ci if (ret == thrd_error) 462bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, "cnd_timedwait failed"); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci /* We don't trust the timeout condition on cnd_timedwait() because of 465bf215546Sopenharmony_ci * the potential clock issues caused by using CLOCK_REALTIME. Instead, 466bf215546Sopenharmony_ci * update now_ns, go back to the top of the loop, and re-check. 467bf215546Sopenharmony_ci */ 468bf215546Sopenharmony_ci now_ns = os_time_get_nano(); 469bf215546Sopenharmony_ci } 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci if (wait_flags & VK_SYNC_WAIT_PENDING) 472bf215546Sopenharmony_ci return VK_SUCCESS; 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_ci VkResult result = vk_sync_timeline_gc_locked(device, timeline, false); 475bf215546Sopenharmony_ci if (result != VK_SUCCESS) 476bf215546Sopenharmony_ci return result; 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci while (timeline->highest_past < wait_value) { 479bf215546Sopenharmony_ci struct vk_sync_timeline_point *point = vk_sync_timeline_first_point(timeline); 480bf215546Sopenharmony_ci 481bf215546Sopenharmony_ci /* Drop the lock while we wait. */ 482bf215546Sopenharmony_ci vk_sync_timeline_point_ref(point); 483bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 484bf215546Sopenharmony_ci 485bf215546Sopenharmony_ci result = vk_sync_wait(device, &point->sync, 0, 486bf215546Sopenharmony_ci VK_SYNC_WAIT_COMPLETE, 487bf215546Sopenharmony_ci abs_timeout_ns); 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci /* Pick the mutex back up */ 490bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 491bf215546Sopenharmony_ci vk_sync_timeline_point_unref(timeline, point); 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */ 494bf215546Sopenharmony_ci if (result != VK_SUCCESS) 495bf215546Sopenharmony_ci return result; 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci vk_sync_timeline_point_complete(timeline, point); 498bf215546Sopenharmony_ci } 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci return VK_SUCCESS; 501bf215546Sopenharmony_ci} 502bf215546Sopenharmony_ci 503bf215546Sopenharmony_cistatic VkResult 504bf215546Sopenharmony_civk_sync_timeline_wait(struct vk_device *device, 505bf215546Sopenharmony_ci struct vk_sync *sync, 506bf215546Sopenharmony_ci uint64_t wait_value, 507bf215546Sopenharmony_ci enum vk_sync_wait_flags wait_flags, 508bf215546Sopenharmony_ci uint64_t abs_timeout_ns) 509bf215546Sopenharmony_ci{ 510bf215546Sopenharmony_ci struct vk_sync_timeline *timeline = to_vk_sync_timeline(sync); 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci mtx_lock(&timeline->mutex); 513bf215546Sopenharmony_ci VkResult result = vk_sync_timeline_wait_locked(device, timeline, 514bf215546Sopenharmony_ci wait_value, wait_flags, 515bf215546Sopenharmony_ci abs_timeout_ns); 516bf215546Sopenharmony_ci mtx_unlock(&timeline->mutex); 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_ci return result; 519bf215546Sopenharmony_ci} 520bf215546Sopenharmony_ci 521bf215546Sopenharmony_cistruct vk_sync_timeline_type 522bf215546Sopenharmony_civk_sync_timeline_get_type(const struct vk_sync_type *point_sync_type) 523bf215546Sopenharmony_ci{ 524bf215546Sopenharmony_ci return (struct vk_sync_timeline_type) { 525bf215546Sopenharmony_ci .sync = { 526bf215546Sopenharmony_ci .size = sizeof(struct vk_sync_timeline), 527bf215546Sopenharmony_ci .features = VK_SYNC_FEATURE_TIMELINE | 528bf215546Sopenharmony_ci VK_SYNC_FEATURE_GPU_WAIT | 529bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_WAIT | 530bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_SIGNAL | 531bf215546Sopenharmony_ci VK_SYNC_FEATURE_WAIT_ANY | 532bf215546Sopenharmony_ci VK_SYNC_FEATURE_WAIT_PENDING, 533bf215546Sopenharmony_ci .init = vk_sync_timeline_init, 534bf215546Sopenharmony_ci .finish = vk_sync_timeline_finish, 535bf215546Sopenharmony_ci .signal = vk_sync_timeline_signal, 536bf215546Sopenharmony_ci .get_value = vk_sync_timeline_get_value, 537bf215546Sopenharmony_ci .wait = vk_sync_timeline_wait, 538bf215546Sopenharmony_ci }, 539bf215546Sopenharmony_ci .point_sync_type = point_sync_type, 540bf215546Sopenharmony_ci }; 541bf215546Sopenharmony_ci} 542