1 /*
2 * Copyright © 2021 Collabora Ltd.
3 *
4 * Derived from tu_device.c which is:
5 * Copyright © 2016 Red Hat.
6 * Copyright © 2016 Bas Nieuwenhuizen
7 * Copyright © 2015 Intel Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29 #include "genxml/gen_macros.h"
30
31 #include "decode.h"
32
33 #include "panvk_cs.h"
34 #include "panvk_private.h"
35
36 #include "vk_drm_syncobj.h"
37
38 static void
panvk_queue_submit_batch(struct panvk_queue * queue,struct panvk_batch * batch,uint32_t * bos,unsigned nr_bos,uint32_t * in_fences,unsigned nr_in_fences)39 panvk_queue_submit_batch(struct panvk_queue *queue, struct panvk_batch *batch,
40 uint32_t *bos, unsigned nr_bos, uint32_t *in_fences,
41 unsigned nr_in_fences)
42 {
43 const struct panvk_device *dev = queue->device;
44 unsigned debug = dev->physical_device->instance->debug_flags;
45 int ret;
46
47 /* Reset the batch if it's already been issued */
48 if (batch->issued) {
49 util_dynarray_foreach(&batch->jobs, void *, job)
50 memset((*job), 0, 4 * 4);
51
52 /* Reset the tiler before re-issuing the batch */
53 if (batch->tiler.descs.cpu) {
54 memcpy(batch->tiler.descs.cpu, batch->tiler.templ,
55 pan_size(TILER_CONTEXT) + pan_size(TILER_HEAP));
56 }
57 }
58
59 if (batch->jc.first_job) {
60 struct drm_panfrost_submit submit = {
61 .bo_handles = (uintptr_t)bos,
62 .bo_handle_count = nr_bos,
63 .in_syncs = (uintptr_t)in_fences,
64 .in_sync_count = nr_in_fences,
65 .out_sync = queue->sync,
66 .jc = batch->jc.first_job,
67 };
68
69 ret = drmIoctl(dev->vk.drm_fd, DRM_IOCTL_PANFROST_SUBMIT, &submit);
70 assert(!ret);
71
72 if (debug & (PANVK_DEBUG_TRACE | PANVK_DEBUG_SYNC)) {
73 ret = drmSyncobjWait(dev->vk.drm_fd, &submit.out_sync, 1, INT64_MAX, 0,
74 NULL);
75 assert(!ret);
76 }
77
78 if (debug & PANVK_DEBUG_TRACE) {
79 pandecode_jc(dev->debug.decode_ctx, batch->jc.first_job,
80 dev->physical_device->kmod.props.gpu_prod_id);
81 }
82
83 if (debug & PANVK_DEBUG_DUMP)
84 pandecode_dump_mappings(dev->debug.decode_ctx);
85 }
86
87 if (batch->fragment_job) {
88 struct drm_panfrost_submit submit = {
89 .bo_handles = (uintptr_t)bos,
90 .bo_handle_count = nr_bos,
91 .out_sync = queue->sync,
92 .jc = batch->fragment_job,
93 .requirements = PANFROST_JD_REQ_FS,
94 };
95
96 if (batch->jc.first_job) {
97 submit.in_syncs = (uintptr_t)(&queue->sync);
98 submit.in_sync_count = 1;
99 } else {
100 submit.in_syncs = (uintptr_t)in_fences;
101 submit.in_sync_count = nr_in_fences;
102 }
103
104 ret = drmIoctl(dev->vk.drm_fd, DRM_IOCTL_PANFROST_SUBMIT, &submit);
105 assert(!ret);
106 if (debug & (PANVK_DEBUG_TRACE | PANVK_DEBUG_SYNC)) {
107 ret = drmSyncobjWait(dev->vk.drm_fd, &submit.out_sync, 1, INT64_MAX, 0,
108 NULL);
109 assert(!ret);
110 }
111
112 if (debug & PANVK_DEBUG_TRACE)
113 pandecode_jc(dev->debug.decode_ctx, batch->fragment_job,
114 dev->physical_device->kmod.props.gpu_prod_id);
115
116 if (debug & PANVK_DEBUG_DUMP)
117 pandecode_dump_mappings(dev->debug.decode_ctx);
118 }
119
120 if (debug & PANVK_DEBUG_TRACE)
121 pandecode_next_frame(dev->debug.decode_ctx);
122
123 batch->issued = true;
124 }
125
126 static void
panvk_queue_transfer_sync(struct panvk_queue * queue,uint32_t syncobj)127 panvk_queue_transfer_sync(struct panvk_queue *queue, uint32_t syncobj)
128 {
129 struct panvk_device *dev = queue->device;
130 int ret;
131
132 struct drm_syncobj_handle handle = {
133 .handle = queue->sync,
134 .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
135 .fd = -1,
136 };
137
138 ret = drmIoctl(dev->vk.drm_fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
139 assert(!ret);
140 assert(handle.fd >= 0);
141
142 handle.handle = syncobj;
143 ret = drmIoctl(dev->vk.drm_fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &handle);
144 assert(!ret);
145
146 close(handle.fd);
147 }
148
149 static void
panvk_add_wait_event_syncobjs(struct panvk_batch * batch,uint32_t * in_fences,unsigned * nr_in_fences)150 panvk_add_wait_event_syncobjs(struct panvk_batch *batch, uint32_t *in_fences,
151 unsigned *nr_in_fences)
152 {
153 util_dynarray_foreach(&batch->event_ops, struct panvk_event_op, op) {
154 switch (op->type) {
155 case PANVK_EVENT_OP_SET:
156 /* Nothing to do yet */
157 break;
158 case PANVK_EVENT_OP_RESET:
159 /* Nothing to do yet */
160 break;
161 case PANVK_EVENT_OP_WAIT:
162 in_fences[(*nr_in_fences)++] = op->event->syncobj;
163 break;
164 default:
165 unreachable("bad panvk_event_op type\n");
166 }
167 }
168 }
169
170 static void
panvk_signal_event_syncobjs(struct panvk_queue * queue,struct panvk_batch * batch)171 panvk_signal_event_syncobjs(struct panvk_queue *queue,
172 struct panvk_batch *batch)
173 {
174 struct panvk_device *dev = queue->device;
175
176 util_dynarray_foreach(&batch->event_ops, struct panvk_event_op, op) {
177 switch (op->type) {
178 case PANVK_EVENT_OP_SET: {
179 panvk_queue_transfer_sync(queue, op->event->syncobj);
180 break;
181 }
182 case PANVK_EVENT_OP_RESET: {
183 struct panvk_event *event = op->event;
184
185 struct drm_syncobj_array objs = {
186 .handles = (uint64_t)(uintptr_t)&event->syncobj,
187 .count_handles = 1};
188
189 int ret = drmIoctl(dev->vk.drm_fd, DRM_IOCTL_SYNCOBJ_RESET, &objs);
190 assert(!ret);
191 break;
192 }
193 case PANVK_EVENT_OP_WAIT:
194 /* Nothing left to do */
195 break;
196 default:
197 unreachable("bad panvk_event_op type\n");
198 }
199 }
200 }
201
202 VkResult
panvk_per_arch(queue_submit)203 panvk_per_arch(queue_submit)(struct vk_queue *vk_queue,
204 struct vk_queue_submit *submit)
205 {
206 struct panvk_queue *queue = container_of(vk_queue, struct panvk_queue, vk);
207 struct panvk_device *dev = queue->device;
208
209 unsigned nr_semaphores = submit->wait_count + 1;
210 uint32_t semaphores[nr_semaphores];
211
212 semaphores[0] = queue->sync;
213 for (unsigned i = 0; i < submit->wait_count; i++) {
214 assert(vk_sync_type_is_drm_syncobj(submit->waits[i].sync->type));
215 struct vk_drm_syncobj *syncobj =
216 vk_sync_as_drm_syncobj(submit->waits[i].sync);
217
218 semaphores[i + 1] = syncobj->syncobj;
219 }
220
221 for (uint32_t j = 0; j < submit->command_buffer_count; ++j) {
222 struct panvk_cmd_buffer *cmdbuf =
223 container_of(submit->command_buffers[j], struct panvk_cmd_buffer, vk);
224
225 list_for_each_entry(struct panvk_batch, batch, &cmdbuf->batches, node) {
226 /* FIXME: should be done at the batch level */
227 unsigned nr_bos =
228 panvk_pool_num_bos(&cmdbuf->desc_pool) +
229 panvk_pool_num_bos(&cmdbuf->varying_pool) +
230 panvk_pool_num_bos(&cmdbuf->tls_pool) +
231 (batch->fb.info ? batch->fb.info->attachment_count : 0) +
232 (batch->blit.src ? 1 : 0) + (batch->blit.dst ? 1 : 0) +
233 (batch->jc.first_tiler ? 1 : 0) + 1;
234 unsigned bo_idx = 0;
235 uint32_t bos[nr_bos];
236
237 panvk_pool_get_bo_handles(&cmdbuf->desc_pool, &bos[bo_idx]);
238 bo_idx += panvk_pool_num_bos(&cmdbuf->desc_pool);
239
240 panvk_pool_get_bo_handles(&cmdbuf->varying_pool, &bos[bo_idx]);
241 bo_idx += panvk_pool_num_bos(&cmdbuf->varying_pool);
242
243 panvk_pool_get_bo_handles(&cmdbuf->tls_pool, &bos[bo_idx]);
244 bo_idx += panvk_pool_num_bos(&cmdbuf->tls_pool);
245
246 if (batch->fb.info) {
247 for (unsigned i = 0; i < batch->fb.info->attachment_count; i++) {
248 struct panvk_image_view *iview =
249 batch->fb.info->attachments[i].iview;
250 struct panvk_image *img =
251 container_of(iview->vk.image, struct panvk_image, vk);
252
253 bos[bo_idx++] = pan_kmod_bo_handle(img->bo);
254 }
255 }
256
257 if (batch->blit.src)
258 bos[bo_idx++] = pan_kmod_bo_handle(batch->blit.src);
259
260 if (batch->blit.dst)
261 bos[bo_idx++] = pan_kmod_bo_handle(batch->blit.dst);
262
263 if (batch->jc.first_tiler)
264 bos[bo_idx++] = pan_kmod_bo_handle(dev->tiler_heap->bo);
265
266 bos[bo_idx++] = pan_kmod_bo_handle(dev->sample_positions->bo);
267 assert(bo_idx == nr_bos);
268
269 /* Merge identical BO entries. */
270 for (unsigned x = 0; x < nr_bos; x++) {
271 for (unsigned y = x + 1; y < nr_bos;) {
272 if (bos[x] == bos[y])
273 bos[y] = bos[--nr_bos];
274 else
275 y++;
276 }
277 }
278
279 unsigned nr_in_fences = 0;
280 unsigned max_wait_event_syncobjs = util_dynarray_num_elements(
281 &batch->event_ops, struct panvk_event_op);
282 uint32_t in_fences[nr_semaphores + max_wait_event_syncobjs];
283 memcpy(in_fences, semaphores, nr_semaphores * sizeof(*in_fences));
284 nr_in_fences += nr_semaphores;
285
286 panvk_add_wait_event_syncobjs(batch, in_fences, &nr_in_fences);
287
288 panvk_queue_submit_batch(queue, batch, bos, nr_bos, in_fences,
289 nr_in_fences);
290
291 panvk_signal_event_syncobjs(queue, batch);
292 }
293 }
294
295 /* Transfer the out fence to signal semaphores */
296 for (unsigned i = 0; i < submit->signal_count; i++) {
297 assert(vk_sync_type_is_drm_syncobj(submit->signals[i].sync->type));
298 struct vk_drm_syncobj *syncobj =
299 vk_sync_as_drm_syncobj(submit->signals[i].sync);
300
301 panvk_queue_transfer_sync(queue, syncobj->syncobj);
302 }
303
304 return VK_SUCCESS;
305 }
306
307 VkResult
panvk_per_arch(CreateSampler)308 panvk_per_arch(CreateSampler)(VkDevice _device,
309 const VkSamplerCreateInfo *pCreateInfo,
310 const VkAllocationCallbacks *pAllocator,
311 VkSampler *pSampler)
312 {
313 VK_FROM_HANDLE(panvk_device, device, _device);
314 struct panvk_sampler *sampler;
315
316 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
317
318 sampler = vk_object_alloc(&device->vk, pAllocator, sizeof(*sampler),
319 VK_OBJECT_TYPE_SAMPLER);
320 if (!sampler)
321 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
322
323 STATIC_ASSERT(sizeof(sampler->desc) >= pan_size(SAMPLER));
324 panvk_per_arch(emit_sampler)(pCreateInfo, &sampler->desc);
325 *pSampler = panvk_sampler_to_handle(sampler);
326
327 return VK_SUCCESS;
328 }
329