1/* 2 * Copyright (C) 2017-2019 Lima Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24#include <stdlib.h> 25#include <string.h> 26 27#include "xf86drm.h" 28#include "libsync.h" 29#include "drm-uapi/lima_drm.h" 30 31#include "util/ralloc.h" 32#include "util/u_dynarray.h" 33#include "util/os_time.h" 34 35#include "lima_screen.h" 36#include "lima_context.h" 37#include "lima_submit.h" 38#include "lima_bo.h" 39#include "lima_util.h" 40 41struct lima_submit { 42 struct lima_screen *screen; 43 uint32_t pipe; 44 uint32_t ctx; 45 46 int in_sync_fd; 47 uint32_t in_sync; 48 uint32_t out_sync; 49 50 struct util_dynarray gem_bos; 51 struct util_dynarray bos; 52}; 53 54 55#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) 56 57struct lima_submit *lima_submit_create(struct lima_context *ctx, uint32_t pipe) 58{ 59 struct lima_submit *s; 60 61 s = rzalloc(ctx, struct lima_submit); 62 if (!s) 63 return NULL; 64 65 s->screen = lima_screen(ctx->base.screen); 66 s->pipe = pipe; 67 s->ctx = ctx->id; 68 s->in_sync_fd = -1; 69 70 int err = drmSyncobjCreate(s->screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED, 71 &s->out_sync); 72 if (err) 73 goto err_out0; 74 75 err = drmSyncobjCreate(s->screen->fd, DRM_SYNCOBJ_CREATE_SIGNALED, 76 &s->in_sync); 77 if (err) 78 goto err_out1; 79 80 util_dynarray_init(&s->gem_bos, s); 81 82 return s; 83 84err_out1: 85 drmSyncobjDestroy(s->screen->fd, s->out_sync); 86err_out0: 87 ralloc_free(s); 88 return NULL; 89} 90 91void lima_submit_free(struct lima_submit *submit) 92{ 93 if (submit->in_sync_fd >= 0) 94 close(submit->in_sync_fd); 95 drmSyncobjDestroy(submit->screen->fd, submit->in_sync); 96 drmSyncobjDestroy(submit->screen->fd, submit->out_sync); 97} 98 99bool lima_submit_add_bo(struct lima_submit *submit, struct lima_bo *bo, uint32_t flags) 100{ 101 util_dynarray_foreach(&submit->gem_bos, struct drm_lima_gem_submit_bo, gem_bo) { 102 if (bo->handle == gem_bo->handle) { 103 gem_bo->flags |= flags; 104 return true; 105 } 106 } 107 108 struct drm_lima_gem_submit_bo *submit_bo = 109 util_dynarray_grow(&submit->gem_bos, sizeof(*submit_bo)); 110 submit_bo->handle = bo->handle; 111 submit_bo->flags = flags; 112 113 struct lima_bo **jbo = util_dynarray_grow(&submit->bos, sizeof(*jbo)); 114 *jbo = bo; 115 116 /* prevent bo from being freed when submit start */ 117 lima_bo_reference(bo); 118 119 return true; 120} 121 122bool lima_submit_start(struct lima_submit *submit, void *frame, uint32_t size) 123{ 124 struct drm_lima_gem_submit req = { 125 .ctx = submit->ctx, 126 .pipe = submit->pipe, 127 .nr_bos = submit->gem_bos.size / sizeof(struct drm_lima_gem_submit_bo), 128 .bos = VOID2U64(util_dynarray_begin(&submit->gem_bos)), 129 .frame = VOID2U64(frame), 130 .frame_size = size, 131 }; 132 133 if (submit->in_sync_fd >= 0) { 134 int err = drmSyncobjImportSyncFile(submit->screen->fd, submit->in_sync, 135 submit->in_sync_fd); 136 if (err) 137 return false; 138 139 req.in_sync[0] = submit->in_sync; 140 close(submit->in_sync_fd); 141 submit->in_sync_fd = -1; 142 } 143 144 bool ret = drmIoctl(submit->screen->fd, DRM_IOCTL_LIMA_GEM_SUBMIT, &req) == 0; 145 146 util_dynarray_foreach(&submit->bos, struct lima_bo *, bo) { 147 lima_bo_free(*bo); 148 } 149 150 util_dynarray_clear(&submit->gem_bos); 151 util_dynarray_clear(&submit->bos); 152 return ret; 153} 154 155bool lima_submit_wait(struct lima_submit *submit, uint64_t timeout_ns) 156{ 157 int64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns); 158 159 return !drmSyncobjWait(submit->screen->fd, &submit->out_sync, 1, abs_timeout, 0, NULL); 160} 161 162bool lima_submit_has_bo(struct lima_submit *submit, struct lima_bo *bo, bool all) 163{ 164 util_dynarray_foreach(&submit->gem_bos, struct drm_lima_gem_submit_bo, gem_bo) { 165 if (bo->handle == gem_bo->handle) { 166 if (all) 167 return true; 168 else 169 return gem_bo->flags & LIMA_SUBMIT_BO_WRITE; 170 } 171 } 172 173 return false; 174} 175 176bool lima_submit_add_in_sync(struct lima_submit *submit, int fd) 177{ 178 return !sync_accumulate("lima", &submit->in_sync_fd, fd); 179} 180 181bool lima_submit_get_out_sync(struct lima_submit *submit, int *fd) 182{ 183 return !drmSyncobjExportSyncFile(submit->screen->fd, submit->out_sync, fd); 184} 185