The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

c/util: Implement wait_image in comp_swapchain

authored by

Christoph Haag and committed by
Jakob Bornecrantz
351dd9b9 cd37974c

+180 -1
+6
src/xrt/auxiliary/util/u_trace_marker.h
··· 127 127 #define SINK_TRACE_BEGIN(IDENT) U_TRACE_BEGIN_COLOR(sink, IDENT, 0xffa500) 128 128 #define SINK_TRACE_END(IDENT) U_TRACE_END(sink, IDENT) 129 129 130 + #define SWAPCHAIN_TRACE_MARKER() U_TRACE_FUNC_COLOR(sc, 0x007700) 131 + #define SWAPCHAIN_TRACE_IDENT(IDENT) U_TRACE_IDENT_COLOR(sc, IDENT, 0x007700) 132 + #define SWAPCHAIN_TRACE_BEGIN(IDENT) U_TRACE_BEGIN_COLOR(sc, IDENT, 0x007700) 133 + #define SWAPCHAIN_TRACE_END(IDENT) U_TRACE_END(sc, IDENT) 134 + 130 135 #define TRACK_TRACE_MARKER() U_TRACE_FUNC_COLOR(track, 0xff0000) 131 136 #define TRACK_TRACE_IDENT(IDENT) U_TRACE_IDENT_COLOR(track, IDENT, 0xff0000) 132 137 #define TRACK_TRACE_BEGIN(IDENT) U_TRACE_BEGIN_COLOR(track, IDENT, 0xff0000) ··· 324 329 C(oxr, "st/oxr") /* OpenXR State Tracker calls */ \ 325 330 C(sink, "sink") /* Sink/frameserver calls */ \ 326 331 C(comp, "comp") /* Compositor calls */ \ 332 + C(sc, "sc") /* Swapchain calls */ \ 327 333 C(track, "track") /* Tracking calls */ \ 328 334 C(timing, "timing") /* Timing calls */ 329 335
+165 -1
src/xrt/compositor/util/comp_swapchain.c
··· 12 12 13 13 #include "util/u_misc.h" 14 14 #include "util/u_handles.h" 15 + #include "util/u_trace_marker.h" 15 16 16 17 #include "util/comp_swapchain.h" 17 18 #include "vk/vk_cmd_pool.h" ··· 19 20 #include <stdio.h> 20 21 #include <stdlib.h> 21 22 #include <inttypes.h> 23 + #include <errno.h> 22 24 23 25 24 26 /* ··· 53 55 } 54 56 55 57 static xrt_result_t 58 + swapchain_inc_image_use(struct xrt_swapchain *xsc, uint32_t index) 59 + { 60 + struct comp_swapchain *sc = comp_swapchain(xsc); 61 + 62 + SWAPCHAIN_TRACE_BEGIN(swapchain_inc_image_use); 63 + 64 + VK_TRACE(sc->vk, "%p INC_IMAGE %d (use %d)", (void *)sc, index, sc->images[index].use_count); 65 + 66 + os_mutex_lock(&sc->images[index].use_mutex); 67 + sc->images[index].use_count++; 68 + os_mutex_unlock(&sc->images[index].use_mutex); 69 + 70 + SWAPCHAIN_TRACE_END(swapchain_inc_image_use); 71 + 72 + return XRT_SUCCESS; 73 + } 74 + 75 + static xrt_result_t 76 + swapchain_dec_image_use(struct xrt_swapchain *xsc, uint32_t index) 77 + { 78 + struct comp_swapchain *sc = comp_swapchain(xsc); 79 + 80 + SWAPCHAIN_TRACE_BEGIN(swapchain_dec_image_use); 81 + 82 + VK_TRACE(sc->vk, "%p DEC_IMAGE %d (use %d)", (void *)sc, index, sc->images[index].use_count); 83 + 84 + os_mutex_lock(&sc->images[index].use_mutex); 85 + 86 + assert(sc->images[index].use_count > 0 && "use count already 0"); 87 + 88 + sc->images[index].use_count--; 89 + if (sc->images[index].use_count == 0) { 90 + os_mutex_unlock(&sc->images[index].use_mutex); 91 + pthread_cond_broadcast(&sc->images[index].use_cond); 92 + } 93 + 94 + os_mutex_unlock(&sc->images[index].use_mutex); 95 + 96 + SWAPCHAIN_TRACE_END(swapchain_dec_image_use); 97 + 98 + return XRT_SUCCESS; 99 + } 100 + 101 + static xrt_result_t 56 102 swapchain_wait_image(struct xrt_swapchain *xsc, uint64_t timeout_ns, uint32_t index) 57 103 { 58 104 struct comp_swapchain *sc = comp_swapchain(xsc); 59 105 60 - VK_TRACE(sc->vk, "WAIT_IMAGE"); 106 + SWAPCHAIN_TRACE_BEGIN(swapchain_wait_image); 107 + 108 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d (use %d)", (void *)sc, index, sc->images[index].use_count); 109 + 110 + os_mutex_lock(&sc->images[index].use_mutex); 111 + 112 + if (sc->images[index].use_count == 0) { 113 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d: NO WAIT", (void *)sc, index); 114 + os_mutex_unlock(&sc->images[index].use_mutex); 115 + SWAPCHAIN_TRACE_END(swapchain_wait_image); 116 + return XRT_SUCCESS; 117 + } 118 + 119 + // on windows pthread_cond_timedwait can not be used with monotonic time 120 + uint64_t start_wait_rt = os_realtime_get_ns(); 121 + 122 + uint64_t end_wait_rt; 123 + // don't wrap on big or indefinite timeout 124 + if (start_wait_rt > UINT64_MAX - timeout_ns) { 125 + end_wait_rt = UINT64_MAX; 126 + } else { 127 + end_wait_rt = start_wait_rt + timeout_ns; 128 + } 129 + 130 + struct timespec spec; 131 + os_ns_to_timespec(end_wait_rt, &spec); 132 + 133 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d (use %d) start wait at: %" PRIu64 " (timeout at %" PRIu64 ")", (void *)sc, 134 + index, sc->images[index].use_count, start_wait_rt, end_wait_rt); 135 + 136 + int ret; 137 + while (sc->images[index].use_count > 0) { 138 + // use pthread_cond_timedwait to implement timeout behavior 139 + ret = pthread_cond_timedwait(&sc->images[index].use_cond, &sc->images[index].use_mutex.mutex, &spec); 140 + 141 + uint64_t now_rt = os_realtime_get_ns(); 142 + double diff = time_ns_to_ms_f(now_rt - start_wait_rt); 143 + 144 + if (ret == 0) { 145 + 146 + if (sc->images[index].use_count == 0) { 147 + // image became available within timeout limits 148 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d: success at %" PRIu64 " after %fms", (void *)sc, 149 + index, now_rt, diff); 150 + os_mutex_unlock(&sc->images[index].use_mutex); 151 + SWAPCHAIN_TRACE_END(swapchain_wait_image); 152 + return XRT_SUCCESS; 153 + } else { 154 + // cond got signaled but image is still in use, continue waiting 155 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d: woken at %" PRIu64 " after %fms but still (%d use)", 156 + (void *)sc, index, now_rt, diff, sc->images[index].use_count); 157 + continue; 158 + } 159 + 160 + } else if (ret == ETIMEDOUT) { 161 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d (use %d): timeout at %" PRIu64 " after %fms", (void *)sc, 162 + index, sc->images[index].use_count, now_rt, diff); 163 + 164 + if (now_rt >= end_wait_rt) { 165 + // image did not become available within timeout limits 166 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d (use %d): timeout (%" PRIu64 " > %" PRIu64 ")", 167 + (void *)sc, index, sc->images[index].use_count, now_rt, end_wait_rt); 168 + os_mutex_unlock(&sc->images[index].use_mutex); 169 + SWAPCHAIN_TRACE_END(swapchain_wait_image); 170 + return XRT_TIMEOUT; 171 + 172 + } else { 173 + // spurious cond wakeup 174 + VK_TRACE(sc->vk, 175 + "%p WAIT_IMAGE %d (use %d): spurious timeout at %" PRIu64 " (%fms to timeout)", 176 + (void *)sc, index, sc->images[index].use_count, now_rt, 177 + time_ns_to_ms_f(end_wait_rt - now_rt)); 178 + continue; 179 + } 180 + 181 + } else { 182 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d: condition variable error %d", (void *)sc, index, ret); 183 + os_mutex_unlock(&sc->images[index].use_mutex); 184 + SWAPCHAIN_TRACE_END(swapchain_wait_image); 185 + return XRT_ERROR_VULKAN; 186 + } 187 + } 188 + 189 + VK_TRACE(sc->vk, "%p WAIT_IMAGE %d: became available before spurious wakeup %d", (void *)sc, index, ret); 190 + 191 + os_mutex_unlock(&sc->images[index].use_mutex); 192 + SWAPCHAIN_TRACE_END(swapchain_wait_image); 193 + 61 194 return XRT_SUCCESS; 62 195 } 63 196 ··· 99 232 { 100 233 sc->base.base.destroy = swapchain_destroy; 101 234 sc->base.base.acquire_image = swapchain_acquire_image; 235 + sc->base.base.inc_image_use = swapchain_inc_image_use; 236 + sc->base.base.dec_image_use = swapchain_dec_image_use; 102 237 sc->base.base.wait_image = swapchain_wait_image; 103 238 sc->base.base.release_image = swapchain_release_image; 104 239 sc->base.base.image_count = image_count; ··· 228 363 //! @todo Propegate error 229 364 VK_ERROR(vk, "Failed to barrier images"); 230 365 } 366 + 367 + for (uint32_t i = 0; i < image_count; i++) { 368 + 369 + ret = pthread_cond_init(&sc->images[i].use_cond, NULL); 370 + if (ret) { 371 + VK_ERROR(sc->vk, "Failed to init image use cond: %d", ret); 372 + continue; 373 + } 374 + 375 + ret = os_mutex_init(&sc->images[i].use_mutex); 376 + if (ret) { 377 + VK_ERROR(sc->vk, "Failed to init image use mutex: %d", ret); 378 + continue; 379 + } 380 + 381 + sc->images[i].use_count = 0; 382 + } 231 383 } 232 384 233 385 static void ··· 379 531 struct vk_bundle *vk = sc->vk; 380 532 381 533 VK_TRACE(vk, "REALLY DESTROY"); 534 + 535 + for (uint32_t i = 0; i < sc->base.base.image_count; i++) { 536 + // compositor ensures to garbage collect after gpu work finished 537 + if (sc->images[i].use_count != 0) { 538 + VK_ERROR(vk, "swapchain destroy while image %d use count %d", i, sc->images[i].use_count); 539 + assert(false); 540 + continue; // leaking better than crashing? 541 + } 542 + 543 + os_mutex_destroy(&sc->images[i].use_mutex); 544 + pthread_cond_destroy(&sc->images[i].use_cond); 545 + } 382 546 383 547 for (uint32_t i = 0; i < sc->base.base.image_count; i++) { 384 548 image_cleanup(vk, &sc->images[i]);
+9
src/xrt/compositor/util/comp_swapchain.h
··· 64 64 } views; 65 65 //! The number of array slices in a texture, 1 == regular 2D texture. 66 66 size_t array_size; 67 + 68 + //! A usage counter, similar to a reference counter. 69 + uint32_t use_count; 70 + 71 + //! A condition variable per swapchain image that is notified when @ref use_count count reaches 0. 72 + pthread_cond_t use_cond; 73 + 74 + //! A mutex per swapchain image that is used with @ref use_cond. 75 + struct os_mutex use_mutex; 67 76 }; 68 77 69 78 /*!