1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 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 FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Rob Clark <robclark@freedesktop.org> 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include "util/os_file.h" 28bf215546Sopenharmony_ci#include "util/u_inlines.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include "freedreno_batch.h" 31bf215546Sopenharmony_ci#include "freedreno_context.h" 32bf215546Sopenharmony_ci#include "freedreno_fence.h" 33bf215546Sopenharmony_ci#include "freedreno_util.h" 34bf215546Sopenharmony_ci/* TODO: Use the interface drm/freedreno_drmif.h instead of calling directly */ 35bf215546Sopenharmony_ci#include <xf86drm.h> 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_cistatic bool 38bf215546Sopenharmony_cifence_flush(struct pipe_context *pctx, struct pipe_fence_handle *fence, 39bf215546Sopenharmony_ci uint64_t timeout) 40bf215546Sopenharmony_ci /* NOTE: in the !fence_is_signalled() case we may be called from non-driver 41bf215546Sopenharmony_ci * thread, but we don't call fd_batch_flush() in that case 42bf215546Sopenharmony_ci */ 43bf215546Sopenharmony_ci in_dt 44bf215546Sopenharmony_ci{ 45bf215546Sopenharmony_ci if (!util_queue_fence_is_signalled(&fence->ready)) { 46bf215546Sopenharmony_ci if (fence->tc_token) { 47bf215546Sopenharmony_ci threaded_context_flush(pctx, fence->tc_token, timeout == 0); 48bf215546Sopenharmony_ci } 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci if (!timeout) 51bf215546Sopenharmony_ci return false; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci if (timeout == PIPE_TIMEOUT_INFINITE) { 54bf215546Sopenharmony_ci util_queue_fence_wait(&fence->ready); 55bf215546Sopenharmony_ci } else { 56bf215546Sopenharmony_ci int64_t abs_timeout = os_time_get_absolute_timeout(timeout); 57bf215546Sopenharmony_ci if (!util_queue_fence_wait_timeout(&fence->ready, abs_timeout)) { 58bf215546Sopenharmony_ci return false; 59bf215546Sopenharmony_ci } 60bf215546Sopenharmony_ci } 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci util_queue_fence_wait(&fence->submit_fence.ready); 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci /* We've already waited for batch to be flushed and fence->batch 65bf215546Sopenharmony_ci * to be cleared: 66bf215546Sopenharmony_ci */ 67bf215546Sopenharmony_ci assert(!fence->batch); 68bf215546Sopenharmony_ci return true; 69bf215546Sopenharmony_ci } 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci if (fence->batch) 72bf215546Sopenharmony_ci fd_batch_flush(fence->batch); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci util_queue_fence_wait(&fence->submit_fence.ready); 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci assert(!fence->batch); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci return true; 79bf215546Sopenharmony_ci} 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_civoid 82bf215546Sopenharmony_cifd_fence_repopulate(struct pipe_fence_handle *fence, struct pipe_fence_handle *last_fence) 83bf215546Sopenharmony_ci{ 84bf215546Sopenharmony_ci if (last_fence->last_fence) 85bf215546Sopenharmony_ci fd_fence_repopulate(fence, last_fence->last_fence); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci /* The fence we are re-populating must not be an fd-fence (but last_fince 88bf215546Sopenharmony_ci * might have been) 89bf215546Sopenharmony_ci */ 90bf215546Sopenharmony_ci assert(!fence->submit_fence.use_fence_fd); 91bf215546Sopenharmony_ci assert(!last_fence->batch); 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci fd_fence_ref(&fence->last_fence, last_fence); 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci /* We have nothing to flush, so nothing will clear the batch reference 96bf215546Sopenharmony_ci * (which is normally done when the batch is flushed), so do it now: 97bf215546Sopenharmony_ci */ 98bf215546Sopenharmony_ci fd_fence_set_batch(fence, NULL); 99bf215546Sopenharmony_ci} 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_cistatic void 102bf215546Sopenharmony_cifd_fence_destroy(struct pipe_fence_handle *fence) 103bf215546Sopenharmony_ci{ 104bf215546Sopenharmony_ci fd_fence_ref(&fence->last_fence, NULL); 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci tc_unflushed_batch_token_reference(&fence->tc_token, NULL); 107bf215546Sopenharmony_ci if (fence->submit_fence.use_fence_fd) 108bf215546Sopenharmony_ci close(fence->submit_fence.fence_fd); 109bf215546Sopenharmony_ci if (fence->syncobj) 110bf215546Sopenharmony_ci drmSyncobjDestroy(fd_device_fd(fence->screen->dev), fence->syncobj); 111bf215546Sopenharmony_ci fd_pipe_del(fence->pipe); 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci /* TODO might be worth trying harder to avoid a potential stall here, 114bf215546Sopenharmony_ci * but that would require the submit somehow holding a reference to 115bf215546Sopenharmony_ci * the pipe_fence_handle.. and I'm not sure if it is a thing that is 116bf215546Sopenharmony_ci * likely to matter much. 117bf215546Sopenharmony_ci */ 118bf215546Sopenharmony_ci util_queue_fence_wait(&fence->submit_fence.ready); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci FREE(fence); 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_civoid 124bf215546Sopenharmony_cifd_fence_ref(struct pipe_fence_handle **ptr, struct pipe_fence_handle *pfence) 125bf215546Sopenharmony_ci{ 126bf215546Sopenharmony_ci if (pipe_reference(&(*ptr)->reference, &pfence->reference)) 127bf215546Sopenharmony_ci fd_fence_destroy(*ptr); 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci *ptr = pfence; 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_cibool 133bf215546Sopenharmony_cifd_fence_finish(struct pipe_screen *pscreen, struct pipe_context *pctx, 134bf215546Sopenharmony_ci struct pipe_fence_handle *fence, uint64_t timeout) 135bf215546Sopenharmony_ci{ 136bf215546Sopenharmony_ci /* Note: for TC deferred fence, pctx->flush() may not have been called 137bf215546Sopenharmony_ci * yet, so always do fence_flush() *first* before delegating to 138bf215546Sopenharmony_ci * fence->last_fence 139bf215546Sopenharmony_ci */ 140bf215546Sopenharmony_ci if (!fence_flush(pctx, fence, timeout)) 141bf215546Sopenharmony_ci return false; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci if (fence->last_fence) 144bf215546Sopenharmony_ci return fd_fence_finish(pscreen, pctx, fence->last_fence, timeout); 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci if (fence->last_fence) 147bf215546Sopenharmony_ci fence = fence->last_fence; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci if (fence->submit_fence.use_fence_fd) { 150bf215546Sopenharmony_ci int ret = sync_wait(fence->submit_fence.fence_fd, timeout / 1000000); 151bf215546Sopenharmony_ci return ret == 0; 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if (fd_pipe_wait_timeout(fence->pipe, &fence->submit_fence.fence, timeout)) 155bf215546Sopenharmony_ci return false; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci return true; 158bf215546Sopenharmony_ci} 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_cistatic struct pipe_fence_handle * 161bf215546Sopenharmony_cifence_create(struct fd_context *ctx, struct fd_batch *batch, int fence_fd, 162bf215546Sopenharmony_ci int syncobj) 163bf215546Sopenharmony_ci{ 164bf215546Sopenharmony_ci struct pipe_fence_handle *fence; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci fence = CALLOC_STRUCT(pipe_fence_handle); 167bf215546Sopenharmony_ci if (!fence) 168bf215546Sopenharmony_ci return NULL; 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci pipe_reference_init(&fence->reference, 1); 171bf215546Sopenharmony_ci util_queue_fence_init(&fence->ready); 172bf215546Sopenharmony_ci util_queue_fence_init(&fence->submit_fence.ready); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci fence->ctx = ctx; 175bf215546Sopenharmony_ci fd_fence_set_batch(fence, batch); 176bf215546Sopenharmony_ci fence->pipe = fd_pipe_ref(ctx->pipe); 177bf215546Sopenharmony_ci fence->screen = ctx->screen; 178bf215546Sopenharmony_ci fence->submit_fence.fence_fd = fence_fd; 179bf215546Sopenharmony_ci fence->submit_fence.use_fence_fd = (fence_fd != -1); 180bf215546Sopenharmony_ci fence->syncobj = syncobj; 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci return fence; 183bf215546Sopenharmony_ci} 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_civoid 186bf215546Sopenharmony_cifd_create_fence_fd(struct pipe_context *pctx, struct pipe_fence_handle **pfence, 187bf215546Sopenharmony_ci int fd, enum pipe_fd_type type) 188bf215546Sopenharmony_ci{ 189bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci switch (type) { 192bf215546Sopenharmony_ci case PIPE_FD_TYPE_NATIVE_SYNC: 193bf215546Sopenharmony_ci *pfence = 194bf215546Sopenharmony_ci fence_create(fd_context(pctx), NULL, os_dupfd_cloexec(fd), 0); 195bf215546Sopenharmony_ci break; 196bf215546Sopenharmony_ci case PIPE_FD_TYPE_SYNCOBJ: { 197bf215546Sopenharmony_ci int ret; 198bf215546Sopenharmony_ci uint32_t syncobj; 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci assert(ctx->screen->has_syncobj); 201bf215546Sopenharmony_ci ret = drmSyncobjFDToHandle(fd_device_fd(ctx->screen->dev), fd, &syncobj); 202bf215546Sopenharmony_ci if (!ret) 203bf215546Sopenharmony_ci close(fd); 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci *pfence = fence_create(fd_context(pctx), NULL, -1, syncobj); 206bf215546Sopenharmony_ci break; 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci default: 209bf215546Sopenharmony_ci unreachable("Unhandled fence type"); 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci} 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_civoid 214bf215546Sopenharmony_cifd_fence_server_sync(struct pipe_context *pctx, struct pipe_fence_handle *fence) 215bf215546Sopenharmony_ci{ 216bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci /* NOTE: we don't expect the combination of fence-fd + async-flush-fence, 219bf215546Sopenharmony_ci * so timeout==0 is ok here: 220bf215546Sopenharmony_ci */ 221bf215546Sopenharmony_ci fence_flush(pctx, fence, 0); 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci if (fence->last_fence) { 224bf215546Sopenharmony_ci fd_fence_server_sync(pctx, fence->last_fence); 225bf215546Sopenharmony_ci return; 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci /* if not an external fence, then nothing more to do without preemption: */ 229bf215546Sopenharmony_ci if (!fence->submit_fence.use_fence_fd) 230bf215546Sopenharmony_ci return; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci if (sync_accumulate("freedreno", &ctx->in_fence_fd, fence->submit_fence.fence_fd)) { 233bf215546Sopenharmony_ci /* error */ 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci} 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_civoid 238bf215546Sopenharmony_cifd_fence_server_signal(struct pipe_context *pctx, 239bf215546Sopenharmony_ci struct pipe_fence_handle *fence) 240bf215546Sopenharmony_ci{ 241bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci if (fence->syncobj) { 244bf215546Sopenharmony_ci drmSyncobjSignal(fd_device_fd(ctx->screen->dev), &fence->syncobj, 1); 245bf215546Sopenharmony_ci } 246bf215546Sopenharmony_ci} 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ciint 249bf215546Sopenharmony_cifd_fence_get_fd(struct pipe_screen *pscreen, struct pipe_fence_handle *fence) 250bf215546Sopenharmony_ci{ 251bf215546Sopenharmony_ci /* We don't expect deferred flush to be combined with fence-fd: */ 252bf215546Sopenharmony_ci assert(!fence->last_fence); 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci assert(fence->submit_fence.use_fence_fd); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci /* NOTE: in the deferred fence case, the pctx we want is the threaded-ctx 257bf215546Sopenharmony_ci * but if TC is not used, this will be null. Which is fine, we won't call 258bf215546Sopenharmony_ci * threaded_context_flush() in that case 259bf215546Sopenharmony_ci */ 260bf215546Sopenharmony_ci fence_flush(&fence->ctx->tc->base, fence, PIPE_TIMEOUT_INFINITE); 261bf215546Sopenharmony_ci return os_dupfd_cloexec(fence->submit_fence.fence_fd); 262bf215546Sopenharmony_ci} 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_cibool 265bf215546Sopenharmony_cifd_fence_is_fd(struct pipe_fence_handle *fence) 266bf215546Sopenharmony_ci{ 267bf215546Sopenharmony_ci return fence->submit_fence.use_fence_fd; 268bf215546Sopenharmony_ci} 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_cistruct pipe_fence_handle * 271bf215546Sopenharmony_cifd_fence_create(struct fd_batch *batch) 272bf215546Sopenharmony_ci{ 273bf215546Sopenharmony_ci return fence_create(batch->ctx, batch, -1, 0); 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_civoid 277bf215546Sopenharmony_cifd_fence_set_batch(struct pipe_fence_handle *fence, struct fd_batch *batch) 278bf215546Sopenharmony_ci{ 279bf215546Sopenharmony_ci if (batch) { 280bf215546Sopenharmony_ci assert(!fence->batch); 281bf215546Sopenharmony_ci fence->batch = batch; 282bf215546Sopenharmony_ci fd_batch_needs_flush(batch); 283bf215546Sopenharmony_ci } else { 284bf215546Sopenharmony_ci fence->batch = NULL; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci /* When the batch is dis-associated with the fence, we can signal TC 287bf215546Sopenharmony_ci * that the fence is flushed 288bf215546Sopenharmony_ci */ 289bf215546Sopenharmony_ci if (fence->needs_signal) { 290bf215546Sopenharmony_ci util_queue_fence_signal(&fence->ready); 291bf215546Sopenharmony_ci fence->needs_signal = false; 292bf215546Sopenharmony_ci } 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci} 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_cistruct pipe_fence_handle * 297bf215546Sopenharmony_cifd_fence_create_unflushed(struct pipe_context *pctx, 298bf215546Sopenharmony_ci struct tc_unflushed_batch_token *tc_token) 299bf215546Sopenharmony_ci{ 300bf215546Sopenharmony_ci struct pipe_fence_handle *fence = 301bf215546Sopenharmony_ci fence_create(fd_context(pctx), NULL, -1, 0); 302bf215546Sopenharmony_ci fence->needs_signal = true; 303bf215546Sopenharmony_ci util_queue_fence_reset(&fence->ready); 304bf215546Sopenharmony_ci tc_unflushed_batch_token_reference(&fence->tc_token, tc_token); 305bf215546Sopenharmony_ci return fence; 306bf215546Sopenharmony_ci} 307