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