1 /*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <vulkan/vulkan.h>
30 #include <xf86drm.h>
31
32 #include "drm-uapi/pvr_drm.h"
33 #include "pvr_drm.h"
34 #include "pvr_drm_bo.h"
35 #include "pvr_drm_job_common.h"
36 #include "pvr_drm_job_render.h"
37 #include "pvr_private.h"
38 #include "pvr_winsys.h"
39 #include "pvr_winsys_helper.h"
40 #include "util/macros.h"
41 #include "vk_alloc.h"
42 #include "vk_drm_syncobj.h"
43 #include "vk_log.h"
44 #include "vk_util.h"
45 #include "vk_sync.h"
46
47 #define PVR_DRM_FREE_LIST_LOCAL 0U
48 #define PVR_DRM_FREE_LIST_GLOBAL 1U
49 #define PVR_DRM_FREE_LIST_MAX 2U
50
51 struct pvr_drm_winsys_free_list {
52 struct pvr_winsys_free_list base;
53
54 uint32_t handle;
55
56 struct pvr_drm_winsys_free_list *parent;
57 };
58
59 #define to_pvr_drm_winsys_free_list(free_list) \
60 container_of(free_list, struct pvr_drm_winsys_free_list, base)
61
62 struct pvr_drm_winsys_rt_dataset {
63 struct pvr_winsys_rt_dataset base;
64 uint32_t handle;
65 };
66
67 #define to_pvr_drm_winsys_rt_dataset(rt_dataset) \
68 container_of(rt_dataset, struct pvr_drm_winsys_rt_dataset, base)
69
pvr_drm_winsys_free_list_create(struct pvr_winsys * const ws,struct pvr_winsys_vma * const free_list_vma,uint32_t initial_num_pages,uint32_t max_num_pages,uint32_t grow_num_pages,uint32_t grow_threshold,struct pvr_winsys_free_list * const parent_free_list,struct pvr_winsys_free_list ** const free_list_out)70 VkResult pvr_drm_winsys_free_list_create(
71 struct pvr_winsys *const ws,
72 struct pvr_winsys_vma *const free_list_vma,
73 uint32_t initial_num_pages,
74 uint32_t max_num_pages,
75 uint32_t grow_num_pages,
76 uint32_t grow_threshold,
77 struct pvr_winsys_free_list *const parent_free_list,
78 struct pvr_winsys_free_list **const free_list_out)
79 {
80 struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ws);
81 struct drm_pvr_ioctl_create_free_list_args free_list_args = {
82 .free_list_gpu_addr = free_list_vma->dev_addr.addr,
83 .initial_num_pages = initial_num_pages,
84 .max_num_pages = max_num_pages,
85 .grow_num_pages = grow_num_pages,
86 .grow_threshold = grow_threshold,
87 .vm_context_handle = drm_ws->vm_context,
88 };
89 struct pvr_drm_winsys_free_list *drm_free_list;
90 VkResult result;
91
92 drm_free_list = vk_zalloc(ws->alloc,
93 sizeof(*drm_free_list),
94 8,
95 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
96 if (!drm_free_list) {
97 result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
98 goto err_out;
99 }
100
101 drm_free_list->base.ws = ws;
102
103 if (parent_free_list)
104 drm_free_list->parent = to_pvr_drm_winsys_free_list(parent_free_list);
105
106 /* Returns VK_ERROR_INITIALIZATION_FAILED to match pvrsrv. */
107 result = pvr_ioctlf(ws->render_fd,
108 DRM_IOCTL_PVR_CREATE_FREE_LIST,
109 &free_list_args,
110 VK_ERROR_INITIALIZATION_FAILED,
111 "Failed to create free list");
112 if (result != VK_SUCCESS)
113 goto err_free_free_list;
114
115 drm_free_list->handle = free_list_args.handle;
116
117 *free_list_out = &drm_free_list->base;
118
119 return VK_SUCCESS;
120
121 err_free_free_list:
122 vk_free(ws->alloc, drm_free_list);
123
124 err_out:
125 return result;
126 }
127
pvr_drm_winsys_free_list_destroy(struct pvr_winsys_free_list * free_list)128 void pvr_drm_winsys_free_list_destroy(struct pvr_winsys_free_list *free_list)
129 {
130 struct pvr_drm_winsys_free_list *const drm_free_list =
131 to_pvr_drm_winsys_free_list(free_list);
132 struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(free_list->ws);
133 struct drm_pvr_ioctl_destroy_free_list_args args = {
134 .handle = drm_free_list->handle,
135 };
136
137 pvr_ioctlf(drm_ws->base.render_fd,
138 DRM_IOCTL_PVR_DESTROY_FREE_LIST,
139 &args,
140 VK_ERROR_UNKNOWN,
141 "Error destroying free list");
142
143 vk_free(drm_ws->base.alloc, free_list);
144 }
145
pvr_drm_render_ctx_static_state_init(struct pvr_winsys_render_ctx_create_info * create_info,uint8_t * stream_ptr_start,uint32_t * stream_len_ptr)146 static void pvr_drm_render_ctx_static_state_init(
147 struct pvr_winsys_render_ctx_create_info *create_info,
148 uint8_t *stream_ptr_start,
149 uint32_t *stream_len_ptr)
150 {
151 struct pvr_winsys_render_ctx_static_state *ws_static_state =
152 &create_info->static_state;
153 uint64_t *stream_ptr = (uint64_t *)stream_ptr_start;
154
155 /* Leave space for stream header. */
156 stream_ptr += pvr_cmd_length(KMD_STREAM_HDR) / 2;
157
158 *stream_ptr++ = ws_static_state->vdm_ctx_state_base_addr;
159 /* geom_reg_vdm_context_state_resume_addr is unused and zeroed. */
160 *stream_ptr++ = 0;
161 *stream_ptr++ = ws_static_state->geom_ctx_state_base_addr;
162
163 for (uint32_t i = 0; i < ARRAY_SIZE(ws_static_state->geom_state); i++) {
164 *stream_ptr++ = ws_static_state->geom_state[i].vdm_ctx_store_task0;
165 *stream_ptr++ = ws_static_state->geom_state[i].vdm_ctx_store_task1;
166 *stream_ptr++ = ws_static_state->geom_state[i].vdm_ctx_store_task2;
167 /* {store, resume}_task{3, 4} are unused and zeroed. */
168 *stream_ptr++ = 0;
169 *stream_ptr++ = 0;
170
171 *stream_ptr++ = ws_static_state->geom_state[i].vdm_ctx_resume_task0;
172 *stream_ptr++ = ws_static_state->geom_state[i].vdm_ctx_resume_task1;
173 *stream_ptr++ = ws_static_state->geom_state[i].vdm_ctx_resume_task2;
174 /* {store, resume}_task{3, 4} are unused and zeroed. */
175 *stream_ptr++ = 0;
176 *stream_ptr++ = 0;
177 }
178
179 *stream_len_ptr = ((uint8_t *)stream_ptr - stream_ptr_start);
180
181 pvr_csb_pack ((uint64_t *)stream_ptr_start, KMD_STREAM_HDR, value) {
182 value.length = *stream_len_ptr;
183 }
184 }
185
186 struct pvr_drm_winsys_render_ctx {
187 struct pvr_winsys_render_ctx base;
188
189 /* Handle to kernel context. */
190 uint32_t handle;
191
192 uint32_t geom_to_pr_syncobj;
193 };
194
195 #define to_pvr_drm_winsys_render_ctx(ctx) \
196 container_of(ctx, struct pvr_drm_winsys_render_ctx, base)
197
pvr_drm_winsys_render_ctx_create(struct pvr_winsys * ws,struct pvr_winsys_render_ctx_create_info * create_info,struct pvr_winsys_render_ctx ** const ctx_out)198 VkResult pvr_drm_winsys_render_ctx_create(
199 struct pvr_winsys *ws,
200 struct pvr_winsys_render_ctx_create_info *create_info,
201 struct pvr_winsys_render_ctx **const ctx_out)
202 {
203 uint8_t static_ctx_state_fw_stream[192];
204 struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ws);
205 struct drm_pvr_ioctl_create_context_args ctx_args = {
206 .type = DRM_PVR_CTX_TYPE_RENDER,
207 .priority = pvr_drm_from_winsys_priority(create_info->priority),
208 .static_context_state = (uint64_t)&static_ctx_state_fw_stream,
209 .callstack_addr = create_info->vdm_callstack_addr.addr,
210 .vm_context_handle = drm_ws->vm_context,
211 };
212
213 struct pvr_drm_winsys_render_ctx *drm_ctx;
214 uint32_t geom_to_pr_syncobj;
215 VkResult result;
216 int ret;
217
218 drm_ctx = vk_alloc(ws->alloc,
219 sizeof(*drm_ctx),
220 8,
221 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
222 if (!drm_ctx) {
223 result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
224 goto err_out;
225 }
226
227 ret = drmSyncobjCreate(ws->render_fd, 0, &geom_to_pr_syncobj);
228 if (ret < 0) {
229 result = vk_errorf(NULL,
230 VK_ERROR_OUT_OF_HOST_MEMORY,
231 "DRM_IOCTL_SYNCOBJ_CREATE failed: %s",
232 strerror(errno));
233 goto err_free_ctx;
234 }
235
236 pvr_drm_render_ctx_static_state_init(create_info,
237 static_ctx_state_fw_stream,
238 &ctx_args.static_context_state_len);
239
240 result = pvr_ioctlf(ws->render_fd,
241 DRM_IOCTL_PVR_CREATE_CONTEXT,
242 &ctx_args,
243 VK_ERROR_INITIALIZATION_FAILED,
244 "Failed to create render context");
245 if (result != VK_SUCCESS)
246 goto err_destroy_syncobj;
247
248 *drm_ctx = (struct pvr_drm_winsys_render_ctx) {
249 .base = {
250 .ws = ws,
251 },
252 .handle = ctx_args.handle,
253 .geom_to_pr_syncobj = geom_to_pr_syncobj,
254 };
255
256 *ctx_out = &drm_ctx->base;
257
258 return VK_SUCCESS;
259
260 err_destroy_syncobj:
261 ret = drmSyncobjDestroy(ws->render_fd, geom_to_pr_syncobj);
262 if (ret < 0) {
263 mesa_loge("DRM_IOCTL_SYNCOBJ_DESTROY failed: %s - leaking it",
264 strerror(errno));
265 }
266
267 err_free_ctx:
268 vk_free(ws->alloc, drm_ctx);
269
270 err_out:
271 return result;
272 }
273
pvr_drm_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx * ctx)274 void pvr_drm_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx *ctx)
275 {
276 struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ctx->ws);
277 struct pvr_drm_winsys_render_ctx *drm_ctx =
278 to_pvr_drm_winsys_render_ctx(ctx);
279 struct drm_pvr_ioctl_destroy_context_args args = {
280 .handle = drm_ctx->handle,
281 };
282 int ret;
283
284 ret = drmSyncobjDestroy(ctx->ws->render_fd, drm_ctx->geom_to_pr_syncobj);
285 if (ret < 0) {
286 mesa_loge("DRM_IOCTL_SYNCOBJ_DESTROY failed: %s - leaking it",
287 strerror(errno));
288 }
289
290 pvr_ioctlf(drm_ws->base.render_fd,
291 DRM_IOCTL_PVR_DESTROY_CONTEXT,
292 &args,
293 VK_ERROR_UNKNOWN,
294 "Error destroying render context");
295
296 vk_free(drm_ws->base.alloc, drm_ctx);
297 }
298
pvr_drm_render_target_dataset_create(struct pvr_winsys * const ws,const struct pvr_winsys_rt_dataset_create_info * const create_info,UNUSED const struct pvr_device_info * dev_info,struct pvr_winsys_rt_dataset ** const rt_dataset_out)299 VkResult pvr_drm_render_target_dataset_create(
300 struct pvr_winsys *const ws,
301 const struct pvr_winsys_rt_dataset_create_info *const create_info,
302 UNUSED const struct pvr_device_info *dev_info,
303 struct pvr_winsys_rt_dataset **const rt_dataset_out)
304 {
305 struct pvr_drm_winsys_free_list *drm_free_list =
306 to_pvr_drm_winsys_free_list(create_info->local_free_list);
307
308 /* 0 is just a placeholder. It doesn't indicate an invalid handle. */
309 uint32_t parent_free_list_handle =
310 drm_free_list->parent ? drm_free_list->parent->handle : 0;
311
312 struct drm_pvr_ioctl_create_hwrt_dataset_args args = {
313 .geom_data_args = {
314 .tpc_dev_addr = create_info->tpc_dev_addr.addr,
315 .tpc_size = create_info->tpc_size,
316 .tpc_stride = create_info->tpc_stride,
317 .vheap_table_dev_addr = create_info->vheap_table_dev_addr.addr,
318 .rtc_dev_addr = create_info->rtc_dev_addr.addr,
319 },
320
321 .rt_data_args = {
322 [0] = {
323 .pm_mlist_dev_addr =
324 create_info->rt_datas[0].pm_mlist_dev_addr.addr,
325 .macrotile_array_dev_addr =
326 create_info->rt_datas[0].macrotile_array_dev_addr.addr,
327 .region_header_dev_addr =
328 create_info->rt_datas[0].rgn_header_dev_addr.addr,
329 },
330 [1] = {
331 .pm_mlist_dev_addr =
332 create_info->rt_datas[1].pm_mlist_dev_addr.addr,
333 .macrotile_array_dev_addr =
334 create_info->rt_datas[1].macrotile_array_dev_addr.addr,
335 .region_header_dev_addr =
336 create_info->rt_datas[1].rgn_header_dev_addr.addr,
337 },
338 },
339
340 .free_list_handles = {
341 [PVR_DRM_FREE_LIST_LOCAL] = drm_free_list->handle,
342 [PVR_DRM_FREE_LIST_GLOBAL] = parent_free_list_handle,
343 },
344
345 .width = create_info->width,
346 .height = create_info->height,
347 .samples = create_info->samples,
348 .layers = create_info->layers,
349
350 .isp_merge_lower_x = create_info->isp_merge_lower_x,
351 .isp_merge_lower_y = create_info->isp_merge_lower_y,
352 .isp_merge_scale_x = create_info->isp_merge_scale_x,
353 .isp_merge_scale_y = create_info->isp_merge_scale_y,
354 .isp_merge_upper_x = create_info->isp_merge_upper_x,
355 .isp_merge_upper_y = create_info->isp_merge_upper_y,
356
357 .region_header_size = create_info->rgn_header_size,
358 };
359
360 struct pvr_drm_winsys_rt_dataset *drm_rt_dataset;
361 VkResult result;
362
363 STATIC_ASSERT(ARRAY_SIZE(args.rt_data_args) ==
364 ARRAY_SIZE(create_info->rt_datas));
365
366 drm_rt_dataset = vk_zalloc(ws->alloc,
367 sizeof(*drm_rt_dataset),
368 8,
369 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
370 if (!drm_rt_dataset) {
371 result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
372 goto err_out;
373 }
374
375 /* Returns VK_ERROR_INITIALIZATION_FAILED to match pvrsrv. */
376 result = pvr_ioctlf(ws->render_fd,
377 DRM_IOCTL_PVR_CREATE_HWRT_DATASET,
378 &args,
379 VK_ERROR_INITIALIZATION_FAILED,
380 "Failed to create render target dataset");
381 if (result != VK_SUCCESS)
382 goto err_free_dataset;
383
384 drm_rt_dataset->handle = args.handle;
385 drm_rt_dataset->base.ws = ws;
386
387 *rt_dataset_out = &drm_rt_dataset->base;
388
389 return VK_SUCCESS;
390
391 err_free_dataset:
392 vk_free(ws->alloc, drm_rt_dataset);
393
394 err_out:
395 return result;
396 }
397
pvr_drm_render_target_dataset_destroy(struct pvr_winsys_rt_dataset * const rt_dataset)398 void pvr_drm_render_target_dataset_destroy(
399 struct pvr_winsys_rt_dataset *const rt_dataset)
400 {
401 struct pvr_drm_winsys_rt_dataset *const drm_rt_dataset =
402 to_pvr_drm_winsys_rt_dataset(rt_dataset);
403 struct pvr_drm_winsys *const drm_ws = to_pvr_drm_winsys(rt_dataset->ws);
404 struct drm_pvr_ioctl_destroy_hwrt_dataset_args args = {
405 .handle = drm_rt_dataset->handle,
406 };
407
408 pvr_ioctlf(drm_ws->base.render_fd,
409 DRM_IOCTL_PVR_DESTROY_HWRT_DATASET,
410 &args,
411 VK_ERROR_UNKNOWN,
412 "Error destroying render target dataset");
413
414 vk_free(drm_ws->base.alloc, drm_rt_dataset);
415 }
416
pvr_winsys_geom_flags_to_drm(const struct pvr_winsys_geometry_state_flags * const ws_flags)417 static uint32_t pvr_winsys_geom_flags_to_drm(
418 const struct pvr_winsys_geometry_state_flags *const ws_flags)
419 {
420 uint32_t flags = 0U;
421
422 if (ws_flags->is_first_geometry)
423 flags |= DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST;
424
425 if (ws_flags->is_last_geometry)
426 flags |= DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST;
427
428 if (ws_flags->use_single_core)
429 flags |= DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE;
430
431 return flags;
432 }
433
pvr_winsys_frag_flags_to_drm(const struct pvr_winsys_fragment_state_flags * const ws_flags)434 static uint32_t pvr_winsys_frag_flags_to_drm(
435 const struct pvr_winsys_fragment_state_flags *const ws_flags)
436 {
437 uint32_t flags = 0U;
438
439 if (ws_flags->use_single_core)
440 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE;
441
442 if (ws_flags->has_depth_buffer)
443 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER;
444
445 if (ws_flags->has_stencil_buffer)
446 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER;
447
448 if (ws_flags->prevent_cdm_overlap)
449 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP;
450
451 if (ws_flags->get_vis_results)
452 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS;
453
454 if (ws_flags->has_spm_scratch_buffer)
455 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER;
456
457 if (ws_flags->disable_pixel_merging)
458 flags |= DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE;
459
460 return flags;
461 }
462
pvr_drm_winsys_render_submit(const struct pvr_winsys_render_ctx * ctx,const struct pvr_winsys_render_submit_info * submit_info,UNUSED const struct pvr_device_info * dev_info,struct vk_sync * signal_sync_geom,struct vk_sync * signal_sync_frag)463 VkResult pvr_drm_winsys_render_submit(
464 const struct pvr_winsys_render_ctx *ctx,
465 const struct pvr_winsys_render_submit_info *submit_info,
466 UNUSED const struct pvr_device_info *dev_info,
467 struct vk_sync *signal_sync_geom,
468 struct vk_sync *signal_sync_frag)
469
470 {
471 const struct pvr_drm_winsys *drm_ws = to_pvr_drm_winsys(ctx->ws);
472 const struct pvr_drm_winsys_render_ctx *drm_ctx =
473 to_pvr_drm_winsys_render_ctx(ctx);
474 const struct pvr_winsys_geometry_state *const geom_state =
475 &submit_info->geometry;
476 const struct pvr_winsys_fragment_state *const frag_state =
477 &submit_info->fragment;
478 const struct pvr_winsys_fragment_state *const pr_state =
479 &submit_info->fragment_pr;
480 const struct pvr_drm_winsys_rt_dataset *drm_rt_dataset =
481 to_pvr_drm_winsys_rt_dataset(submit_info->rt_dataset);
482
483 struct drm_pvr_sync_op geom_sync_ops[2], pr_sync_ops[1], frag_sync_ops[3];
484 unsigned num_geom_syncs = 0, num_pr_syncs = 0, num_frag_syncs = 0;
485 uint32_t geom_to_pr_syncobj;
486
487 struct drm_pvr_job jobs_args[3] = {
488 [0] = {
489 .type = DRM_PVR_JOB_TYPE_GEOMETRY,
490 .cmd_stream = (__u64)&geom_state->fw_stream[0],
491 .cmd_stream_len = geom_state->fw_stream_len,
492 .context_handle = drm_ctx->handle,
493 .flags = pvr_winsys_geom_flags_to_drm(&geom_state->flags),
494 .sync_ops = DRM_PVR_OBJ_ARRAY(0, geom_sync_ops),
495 .hwrt = {
496 .set_handle = drm_rt_dataset->handle,
497 .data_index = submit_info->rt_data_idx,
498 },
499 },
500 [1] = {
501 .type = DRM_PVR_JOB_TYPE_FRAGMENT,
502 .cmd_stream = (__u64)&pr_state->fw_stream[0],
503 .cmd_stream_len = pr_state->fw_stream_len,
504 .context_handle = drm_ctx->handle,
505 .flags = DRM_PVR_SUBMIT_JOB_FRAG_CMD_PARTIAL_RENDER |
506 pvr_winsys_frag_flags_to_drm(&pr_state->flags),
507 .sync_ops = DRM_PVR_OBJ_ARRAY(0, pr_sync_ops),
508 .hwrt = {
509 .set_handle = drm_rt_dataset->handle,
510 .data_index = submit_info->rt_data_idx,
511 },
512 }
513 };
514
515 struct drm_pvr_ioctl_submit_jobs_args args = {
516 .jobs = DRM_PVR_OBJ_ARRAY(2, jobs_args),
517 };
518
519 /* Geom syncs */
520
521 if (submit_info->geometry.wait) {
522 struct vk_sync *sync = submit_info->geometry.wait;
523
524 assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
525 geom_sync_ops[num_geom_syncs++] = (struct drm_pvr_sync_op){
526 .handle = vk_sync_as_drm_syncobj(sync)->syncobj,
527 .flags = DRM_PVR_SYNC_OP_FLAG_WAIT |
528 DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
529 .value = 0,
530 };
531 }
532
533 if (signal_sync_geom) {
534 assert(!(signal_sync_geom->flags & VK_SYNC_IS_TIMELINE));
535 geom_sync_ops[num_geom_syncs++] = (struct drm_pvr_sync_op){
536 .handle = vk_sync_as_drm_syncobj(signal_sync_geom)->syncobj,
537 .flags = DRM_PVR_SYNC_OP_FLAG_SIGNAL |
538 DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
539 .value = 0,
540 };
541 }
542
543 /* PR syncs */
544
545 if (signal_sync_geom) {
546 assert(!(signal_sync_geom->flags & VK_SYNC_IS_TIMELINE));
547 geom_to_pr_syncobj = vk_sync_as_drm_syncobj(signal_sync_geom)->syncobj;
548 } else {
549 geom_to_pr_syncobj = drm_ctx->geom_to_pr_syncobj;
550
551 geom_sync_ops[num_geom_syncs++] = (struct drm_pvr_sync_op){
552 .handle = geom_to_pr_syncobj,
553 .flags = DRM_PVR_SYNC_OP_FLAG_SIGNAL |
554 DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
555 .value = 0,
556 };
557 }
558
559 pr_sync_ops[num_pr_syncs++] = (struct drm_pvr_sync_op){
560 .handle = geom_to_pr_syncobj,
561 .flags = DRM_PVR_SYNC_OP_FLAG_WAIT |
562 DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
563 .value = 0,
564 };
565
566 /* Frag job */
567
568 if (submit_info->has_fragment_job) {
569 jobs_args[args.jobs.count++] = (struct drm_pvr_job) {
570 .type = DRM_PVR_JOB_TYPE_FRAGMENT,
571 .cmd_stream = (__u64)&frag_state->fw_stream[0],
572 .cmd_stream_len = frag_state->fw_stream_len,
573 .context_handle = drm_ctx->handle,
574 .flags = pvr_winsys_frag_flags_to_drm(&frag_state->flags),
575 .sync_ops = DRM_PVR_OBJ_ARRAY(0, frag_sync_ops),
576 .hwrt = {
577 .set_handle = drm_rt_dataset->handle,
578 .data_index = submit_info->rt_data_idx,
579 },
580 };
581
582 /* There's no need to setup a geom -> frag dependency here, as we always
583 * setup a geom -> pr dependency (a PR just being a frag job) and the KMD
584 * respects submission order for jobs of the same type.
585 *
586 * Note that, in the case where PRs aren't needed, because we didn't run
587 * out of PB space during the geometry phase, the PR job will still be
588 * scheduled after the geometry job, but no PRs will be performed, as
589 * they aren't needed.
590 */
591
592 if (submit_info->fragment.wait) {
593 struct vk_sync *sync = submit_info->fragment.wait;
594
595 assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
596 frag_sync_ops[num_frag_syncs++] = (struct drm_pvr_sync_op){
597 .handle = vk_sync_as_drm_syncobj(sync)->syncobj,
598 .flags = DRM_PVR_SYNC_OP_FLAG_WAIT |
599 DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
600 .value = 0,
601 };
602 }
603
604 if (signal_sync_frag) {
605 assert(!(signal_sync_frag->flags & VK_SYNC_IS_TIMELINE));
606 frag_sync_ops[num_frag_syncs++] = (struct drm_pvr_sync_op){
607 .handle = vk_sync_as_drm_syncobj(signal_sync_frag)->syncobj,
608 .flags = DRM_PVR_SYNC_OP_FLAG_SIGNAL |
609 DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ,
610 .value = 0,
611 };
612 }
613 }
614
615 jobs_args[0].sync_ops.count = num_geom_syncs;
616 jobs_args[1].sync_ops.count = num_pr_syncs;
617
618 if (submit_info->has_fragment_job)
619 jobs_args[2].sync_ops.count = num_frag_syncs;
620
621 /* Returns VK_ERROR_OUT_OF_DEVICE_MEMORY to match pvrsrv. */
622 return pvr_ioctlf(drm_ws->base.render_fd,
623 DRM_IOCTL_PVR_SUBMIT_JOBS,
624 &args,
625 VK_ERROR_OUT_OF_DEVICE_MEMORY,
626 "Failed to submit render job");
627 }
628