1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2014 Broadcom 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21b8e80941Smrg * IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg/** @file vc4_fence.c 25b8e80941Smrg * 26b8e80941Smrg * Seqno-based fence management. 27b8e80941Smrg * 28b8e80941Smrg * We have two mechanisms for waiting in our kernel API: You can wait on a BO 29b8e80941Smrg * to have all rendering to from any process to be completed, or wait on a 30b8e80941Smrg * seqno for that particular seqno to be passed. The fence API we're 31b8e80941Smrg * implementing is based on waiting for all rendering in the context to have 32b8e80941Smrg * completed (with no reference to what other processes might be doing with 33b8e80941Smrg * the same BOs), so we can just use the seqno of the last rendering we'd 34b8e80941Smrg * fired off as our fence marker. 35b8e80941Smrg */ 36b8e80941Smrg 37b8e80941Smrg#include <libsync.h> 38b8e80941Smrg#include <fcntl.h> 39b8e80941Smrg 40b8e80941Smrg#include "util/u_inlines.h" 41b8e80941Smrg 42b8e80941Smrg#include "vc4_screen.h" 43b8e80941Smrg#include "vc4_context.h" 44b8e80941Smrg#include "vc4_bufmgr.h" 45b8e80941Smrg 46b8e80941Smrgstruct vc4_fence { 47b8e80941Smrg struct pipe_reference reference; 48b8e80941Smrg uint64_t seqno; 49b8e80941Smrg int fd; 50b8e80941Smrg}; 51b8e80941Smrg 52b8e80941Smrgstatic inline struct vc4_fence * 53b8e80941Smrgvc4_fence(struct pipe_fence_handle *pfence) 54b8e80941Smrg{ 55b8e80941Smrg return (struct vc4_fence *)pfence; 56b8e80941Smrg} 57b8e80941Smrg 58b8e80941Smrgstatic void 59b8e80941Smrgvc4_fence_reference(struct pipe_screen *pscreen, 60b8e80941Smrg struct pipe_fence_handle **pp, 61b8e80941Smrg struct pipe_fence_handle *pf) 62b8e80941Smrg{ 63b8e80941Smrg struct vc4_fence **p = (struct vc4_fence **)pp; 64b8e80941Smrg struct vc4_fence *f = vc4_fence(pf); 65b8e80941Smrg struct vc4_fence *old = *p; 66b8e80941Smrg 67b8e80941Smrg if (pipe_reference(&(*p)->reference, &f->reference)) { 68b8e80941Smrg if (old->fd >= 0) 69b8e80941Smrg close(old->fd); 70b8e80941Smrg free(old); 71b8e80941Smrg } 72b8e80941Smrg *p = f; 73b8e80941Smrg} 74b8e80941Smrg 75b8e80941Smrgstatic boolean 76b8e80941Smrgvc4_fence_finish(struct pipe_screen *pscreen, 77b8e80941Smrg struct pipe_context *ctx, 78b8e80941Smrg struct pipe_fence_handle *pf, 79b8e80941Smrg uint64_t timeout_ns) 80b8e80941Smrg{ 81b8e80941Smrg struct vc4_screen *screen = vc4_screen(pscreen); 82b8e80941Smrg struct vc4_fence *f = vc4_fence(pf); 83b8e80941Smrg 84b8e80941Smrg if (f->fd >= 0) 85b8e80941Smrg return sync_wait(f->fd, timeout_ns / 1000000) == 0; 86b8e80941Smrg 87b8e80941Smrg return vc4_wait_seqno(screen, f->seqno, timeout_ns, "fence wait"); 88b8e80941Smrg} 89b8e80941Smrg 90b8e80941Smrgstruct vc4_fence * 91b8e80941Smrgvc4_fence_create(struct vc4_screen *screen, uint64_t seqno, int fd) 92b8e80941Smrg{ 93b8e80941Smrg struct vc4_fence *f = calloc(1, sizeof(*f)); 94b8e80941Smrg 95b8e80941Smrg if (!f) 96b8e80941Smrg return NULL; 97b8e80941Smrg 98b8e80941Smrg pipe_reference_init(&f->reference, 1); 99b8e80941Smrg f->seqno = seqno; 100b8e80941Smrg f->fd = fd; 101b8e80941Smrg 102b8e80941Smrg return f; 103b8e80941Smrg} 104b8e80941Smrg 105b8e80941Smrgstatic void 106b8e80941Smrgvc4_fence_create_fd(struct pipe_context *pctx, struct pipe_fence_handle **pf, 107b8e80941Smrg int fd, enum pipe_fd_type type) 108b8e80941Smrg{ 109b8e80941Smrg struct vc4_context *vc4 = vc4_context(pctx); 110b8e80941Smrg struct vc4_fence **fence = (struct vc4_fence **)pf; 111b8e80941Smrg 112b8e80941Smrg assert(type == PIPE_FD_TYPE_NATIVE_SYNC); 113b8e80941Smrg *fence = vc4_fence_create(vc4->screen, vc4->last_emit_seqno, 114b8e80941Smrg fcntl(fd, F_DUPFD_CLOEXEC, 3)); 115b8e80941Smrg} 116b8e80941Smrg 117b8e80941Smrgstatic void 118b8e80941Smrgvc4_fence_server_sync(struct pipe_context *pctx, 119b8e80941Smrg struct pipe_fence_handle *pfence) 120b8e80941Smrg{ 121b8e80941Smrg struct vc4_context *vc4 = vc4_context(pctx); 122b8e80941Smrg struct vc4_fence *fence = vc4_fence(pfence); 123b8e80941Smrg 124b8e80941Smrg if (fence->fd >= 0) 125b8e80941Smrg sync_accumulate("vc4", &vc4->in_fence_fd, fence->fd); 126b8e80941Smrg} 127b8e80941Smrg 128b8e80941Smrgstatic int 129b8e80941Smrgvc4_fence_get_fd(struct pipe_screen *screen, struct pipe_fence_handle *pfence) 130b8e80941Smrg{ 131b8e80941Smrg struct vc4_fence *fence = vc4_fence(pfence); 132b8e80941Smrg 133b8e80941Smrg return fcntl(fence->fd, F_DUPFD_CLOEXEC, 3); 134b8e80941Smrg} 135b8e80941Smrg 136b8e80941Smrgint 137b8e80941Smrgvc4_fence_context_init(struct vc4_context *vc4) 138b8e80941Smrg{ 139b8e80941Smrg vc4->base.create_fence_fd = vc4_fence_create_fd; 140b8e80941Smrg vc4->base.fence_server_sync = vc4_fence_server_sync; 141b8e80941Smrg vc4->in_fence_fd = -1; 142b8e80941Smrg 143b8e80941Smrg /* Since we initialize the in_fence_fd to -1 (no wait necessary), 144b8e80941Smrg * we also need to initialize our in_syncobj as signaled. 145b8e80941Smrg */ 146b8e80941Smrg if (vc4->screen->has_syncobj) { 147b8e80941Smrg return drmSyncobjCreate(vc4->fd, DRM_SYNCOBJ_CREATE_SIGNALED, 148b8e80941Smrg &vc4->in_syncobj); 149b8e80941Smrg } else { 150b8e80941Smrg return 0; 151b8e80941Smrg } 152b8e80941Smrg} 153b8e80941Smrg 154b8e80941Smrgvoid 155b8e80941Smrgvc4_fence_screen_init(struct vc4_screen *screen) 156b8e80941Smrg{ 157b8e80941Smrg screen->base.fence_reference = vc4_fence_reference; 158b8e80941Smrg screen->base.fence_finish = vc4_fence_finish; 159b8e80941Smrg screen->base.fence_get_fd = vc4_fence_get_fd; 160b8e80941Smrg} 161