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 <assert.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <stdbool.h>
28 #include <stddef.h>
29 #include <stdint.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <vulkan/vulkan.h>
33
34 #include "fw-api/pvr_rogue_fwif.h"
35 #include "fw-api/pvr_rogue_fwif_rf.h"
36 #include "pvr_private.h"
37 #include "pvr_srv.h"
38 #include "pvr_srv_bo.h"
39 #include "pvr_srv_bridge.h"
40 #include "pvr_srv_job_common.h"
41 #include "pvr_srv_job_render.h"
42 #include "pvr_srv_sync.h"
43 #include "pvr_types.h"
44 #include "pvr_winsys.h"
45 #include "util/libsync.h"
46 #include "util/log.h"
47 #include "util/macros.h"
48 #include "vk_alloc.h"
49 #include "vk_log.h"
50 #include "vk_util.h"
51
52 struct pvr_srv_winsys_free_list {
53 struct pvr_winsys_free_list base;
54
55 void *handle;
56
57 struct pvr_srv_winsys_free_list *parent;
58 };
59
60 #define to_pvr_srv_winsys_free_list(free_list) \
61 container_of(free_list, struct pvr_srv_winsys_free_list, base)
62
63 struct pvr_srv_winsys_rt_dataset {
64 struct pvr_winsys_rt_dataset base;
65
66 struct {
67 void *handle;
68 struct pvr_srv_sync_prim *sync_prim;
69 } rt_datas[ROGUE_FWIF_NUM_RTDATAS];
70 };
71
72 #define to_pvr_srv_winsys_rt_dataset(rt_dataset) \
73 container_of(rt_dataset, struct pvr_srv_winsys_rt_dataset, base)
74
75 struct pvr_srv_winsys_render_ctx {
76 struct pvr_winsys_render_ctx base;
77
78 /* Handle to kernel context. */
79 void *handle;
80
81 int timeline_geom;
82 int timeline_frag;
83 };
84
85 #define to_pvr_srv_winsys_render_ctx(ctx) \
86 container_of(ctx, struct pvr_srv_winsys_render_ctx, base)
87
pvr_srv_winsys_free_list_create(struct pvr_winsys * ws,struct pvr_winsys_vma * 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 * parent_free_list,struct pvr_winsys_free_list ** const free_list_out)88 VkResult pvr_srv_winsys_free_list_create(
89 struct pvr_winsys *ws,
90 struct pvr_winsys_vma *free_list_vma,
91 uint32_t initial_num_pages,
92 uint32_t max_num_pages,
93 uint32_t grow_num_pages,
94 uint32_t grow_threshold,
95 struct pvr_winsys_free_list *parent_free_list,
96 struct pvr_winsys_free_list **const free_list_out)
97 {
98 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
99 struct pvr_srv_winsys_bo *srv_free_list_bo =
100 to_pvr_srv_winsys_bo(free_list_vma->bo);
101 struct pvr_srv_winsys_free_list *srv_free_list;
102 void *parent_handle;
103 VkResult result;
104
105 srv_free_list = vk_zalloc(srv_ws->alloc,
106 sizeof(*srv_free_list),
107 8,
108 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
109 if (!srv_free_list)
110 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
111
112 if (parent_free_list) {
113 srv_free_list->parent = to_pvr_srv_winsys_free_list(parent_free_list);
114 parent_handle = srv_free_list->parent->handle;
115 } else {
116 srv_free_list->parent = NULL;
117 parent_handle = NULL;
118 }
119
120 result = pvr_srv_rgx_create_free_list(srv_ws->render_fd,
121 srv_ws->server_memctx_data,
122 max_num_pages,
123 initial_num_pages,
124 grow_num_pages,
125 grow_threshold,
126 parent_handle,
127 #if defined(DEBUG)
128 PVR_SRV_TRUE /* free_list_check */,
129 #else
130 PVR_SRV_FALSE /* free_list_check */,
131 #endif
132 free_list_vma->dev_addr,
133 srv_free_list_bo->pmr,
134 0 /* pmr_offset */,
135 &srv_free_list->handle);
136 if (result != VK_SUCCESS)
137 goto err_vk_free_srv_free_list;
138
139 srv_free_list->base.ws = ws;
140
141 *free_list_out = &srv_free_list->base;
142
143 return VK_SUCCESS;
144
145 err_vk_free_srv_free_list:
146 vk_free(srv_ws->alloc, srv_free_list);
147
148 return result;
149 }
150
pvr_srv_winsys_free_list_destroy(struct pvr_winsys_free_list * free_list)151 void pvr_srv_winsys_free_list_destroy(struct pvr_winsys_free_list *free_list)
152 {
153 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(free_list->ws);
154 struct pvr_srv_winsys_free_list *srv_free_list =
155 to_pvr_srv_winsys_free_list(free_list);
156
157 pvr_srv_rgx_destroy_free_list(srv_ws->render_fd, srv_free_list->handle);
158 vk_free(srv_ws->alloc, srv_free_list);
159 }
160
pvr_srv_render_target_dataset_create(struct pvr_winsys * ws,const struct pvr_winsys_rt_dataset_create_info * create_info,struct pvr_winsys_rt_dataset ** const rt_dataset_out)161 VkResult pvr_srv_render_target_dataset_create(
162 struct pvr_winsys *ws,
163 const struct pvr_winsys_rt_dataset_create_info *create_info,
164 struct pvr_winsys_rt_dataset **const rt_dataset_out)
165 {
166 const pvr_dev_addr_t macrotile_addrs[ROGUE_FWIF_NUM_RTDATAS] = {
167 [0] = create_info->rt_datas[0].macrotile_array_dev_addr,
168 [1] = create_info->rt_datas[1].macrotile_array_dev_addr,
169 };
170 const pvr_dev_addr_t pm_mlist_addrs[ROGUE_FWIF_NUM_RTDATAS] = {
171 [0] = create_info->rt_datas[0].pm_mlist_dev_addr,
172 [1] = create_info->rt_datas[1].pm_mlist_dev_addr,
173 };
174 const pvr_dev_addr_t rgn_header_addrs[ROGUE_FWIF_NUM_RTDATAS] = {
175 [0] = create_info->rt_datas[0].rgn_header_dev_addr,
176 [1] = create_info->rt_datas[1].rgn_header_dev_addr,
177 };
178
179 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
180 struct pvr_srv_winsys_free_list *srv_local_free_list =
181 to_pvr_srv_winsys_free_list(create_info->local_free_list);
182 void *free_lists[ROGUE_FW_MAX_FREELISTS] = { NULL };
183 struct pvr_srv_winsys_rt_dataset *srv_rt_dataset;
184 void *handles[ROGUE_FWIF_NUM_RTDATAS];
185 VkResult result;
186
187 free_lists[ROGUE_FW_LOCAL_FREELIST] = srv_local_free_list->handle;
188
189 if (srv_local_free_list->parent) {
190 free_lists[ROGUE_FW_GLOBAL_FREELIST] =
191 srv_local_free_list->parent->handle;
192 }
193
194 srv_rt_dataset = vk_zalloc(srv_ws->alloc,
195 sizeof(*srv_rt_dataset),
196 8,
197 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
198 if (!srv_rt_dataset)
199 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
200
201 /* If greater than 1 we'll have to pass in an array. For now just passing in
202 * the reference.
203 */
204 STATIC_ASSERT(ROGUE_FWIF_NUM_GEOMDATAS == 1);
205 /* If not 2 the arrays used in the bridge call will require updating. */
206 STATIC_ASSERT(ROGUE_FWIF_NUM_RTDATAS == 2);
207
208 result = pvr_srv_rgx_create_hwrt_dataset(
209 srv_ws->render_fd,
210 create_info->ppp_multi_sample_ctl_y_flipped,
211 create_info->ppp_multi_sample_ctl,
212 macrotile_addrs,
213 pm_mlist_addrs,
214 &create_info->rtc_dev_addr,
215 rgn_header_addrs,
216 &create_info->tpc_dev_addr,
217 &create_info->vheap_table_dev_addr,
218 free_lists,
219 create_info->isp_merge_lower_x,
220 create_info->isp_merge_lower_y,
221 create_info->isp_merge_scale_x,
222 create_info->isp_merge_scale_y,
223 create_info->isp_merge_upper_x,
224 create_info->isp_merge_upper_y,
225 create_info->isp_mtile_size,
226 create_info->mtile_stride,
227 create_info->ppp_screen,
228 create_info->rgn_header_size,
229 create_info->te_aa,
230 create_info->te_mtile1,
231 create_info->te_mtile2,
232 create_info->te_screen,
233 create_info->tpc_size,
234 create_info->tpc_stride,
235 create_info->max_rts,
236 handles);
237 if (result != VK_SUCCESS)
238 goto err_vk_free_srv_rt_dataset;
239
240 srv_rt_dataset->rt_datas[0].handle = handles[0];
241 srv_rt_dataset->rt_datas[1].handle = handles[1];
242
243 for (uint32_t i = 0; i < ARRAY_SIZE(srv_rt_dataset->rt_datas); i++) {
244 srv_rt_dataset->rt_datas[i].sync_prim = pvr_srv_sync_prim_alloc(srv_ws);
245 if (!srv_rt_dataset->rt_datas[i].sync_prim)
246 goto err_srv_sync_prim_free;
247 }
248
249 srv_rt_dataset->base.ws = ws;
250
251 *rt_dataset_out = &srv_rt_dataset->base;
252
253 return VK_SUCCESS;
254
255 err_srv_sync_prim_free:
256 for (uint32_t i = 0; i < ARRAY_SIZE(srv_rt_dataset->rt_datas); i++) {
257 pvr_srv_sync_prim_free(srv_rt_dataset->rt_datas[i].sync_prim);
258
259 if (srv_rt_dataset->rt_datas[i].handle) {
260 pvr_srv_rgx_destroy_hwrt_dataset(srv_ws->render_fd,
261 srv_rt_dataset->rt_datas[i].handle);
262 }
263 }
264
265 err_vk_free_srv_rt_dataset:
266 vk_free(srv_ws->alloc, srv_rt_dataset);
267
268 return result;
269 }
270
pvr_srv_render_target_dataset_destroy(struct pvr_winsys_rt_dataset * rt_dataset)271 void pvr_srv_render_target_dataset_destroy(
272 struct pvr_winsys_rt_dataset *rt_dataset)
273 {
274 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(rt_dataset->ws);
275 struct pvr_srv_winsys_rt_dataset *srv_rt_dataset =
276 to_pvr_srv_winsys_rt_dataset(rt_dataset);
277
278 for (uint32_t i = 0; i < ARRAY_SIZE(srv_rt_dataset->rt_datas); i++) {
279 pvr_srv_sync_prim_free(srv_rt_dataset->rt_datas[i].sync_prim);
280
281 if (srv_rt_dataset->rt_datas[i].handle) {
282 pvr_srv_rgx_destroy_hwrt_dataset(srv_ws->render_fd,
283 srv_rt_dataset->rt_datas[i].handle);
284 }
285 }
286
287 vk_free(srv_ws->alloc, srv_rt_dataset);
288 }
289
pvr_srv_render_ctx_fw_static_state_init(struct pvr_winsys_render_ctx_create_info * create_info,struct rogue_fwif_static_rendercontext_state * static_state)290 static void pvr_srv_render_ctx_fw_static_state_init(
291 struct pvr_winsys_render_ctx_create_info *create_info,
292 struct rogue_fwif_static_rendercontext_state *static_state)
293 {
294 struct pvr_winsys_render_ctx_static_state *ws_static_state =
295 &create_info->static_state;
296 struct rogue_fwif_ta_regs_cswitch *regs =
297 &static_state->ctx_switch_geom_regs[0];
298
299 memset(static_state, 0, sizeof(*static_state));
300
301 regs->vdm_context_state_base_addr = ws_static_state->vdm_ctx_state_base_addr;
302 regs->ta_context_state_base_addr = ws_static_state->geom_ctx_state_base_addr;
303
304 STATIC_ASSERT(ARRAY_SIZE(regs->ta_state) ==
305 ARRAY_SIZE(ws_static_state->geom_state));
306 for (uint32_t i = 0; i < ARRAY_SIZE(ws_static_state->geom_state); i++) {
307 regs->ta_state[i].vdm_context_store_task0 =
308 ws_static_state->geom_state[i].vdm_ctx_store_task0;
309 regs->ta_state[i].vdm_context_store_task1 =
310 ws_static_state->geom_state[i].vdm_ctx_store_task1;
311 regs->ta_state[i].vdm_context_store_task2 =
312 ws_static_state->geom_state[i].vdm_ctx_store_task2;
313
314 regs->ta_state[i].vdm_context_resume_task0 =
315 ws_static_state->geom_state[i].vdm_ctx_resume_task0;
316 regs->ta_state[i].vdm_context_resume_task1 =
317 ws_static_state->geom_state[i].vdm_ctx_resume_task1;
318 regs->ta_state[i].vdm_context_resume_task2 =
319 ws_static_state->geom_state[i].vdm_ctx_resume_task2;
320 }
321 }
322
pvr_srv_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)323 VkResult pvr_srv_winsys_render_ctx_create(
324 struct pvr_winsys *ws,
325 struct pvr_winsys_render_ctx_create_info *create_info,
326 struct pvr_winsys_render_ctx **const ctx_out)
327 {
328 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
329 struct rogue_fwif_rf_cmd reset_cmd = { 0 };
330
331 struct rogue_fwif_static_rendercontext_state static_state;
332 struct pvr_srv_winsys_render_ctx *srv_ctx;
333 const uint32_t call_stack_depth = 1U;
334 VkResult result;
335
336 srv_ctx = vk_zalloc(srv_ws->alloc,
337 sizeof(*srv_ctx),
338 8,
339 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
340 if (!srv_ctx)
341 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
342
343 result = pvr_srv_create_timeline(srv_ws->render_fd, &srv_ctx->timeline_geom);
344 if (result != VK_SUCCESS)
345 goto err_free_srv_ctx;
346
347 result = pvr_srv_create_timeline(srv_ws->render_fd, &srv_ctx->timeline_frag);
348 if (result != VK_SUCCESS)
349 goto err_close_timeline_geom;
350
351 pvr_srv_render_ctx_fw_static_state_init(create_info, &static_state);
352
353 /* TODO: Add support for reset framework. Currently we subtract
354 * reset_cmd.regs size from reset_cmd size to only pass empty flags field.
355 */
356 result = pvr_srv_rgx_create_render_context(
357 srv_ws->render_fd,
358 pvr_srv_from_winsys_priority(create_info->priority),
359 create_info->vdm_callstack_addr,
360 call_stack_depth,
361 sizeof(reset_cmd) - sizeof(reset_cmd.regs),
362 (uint8_t *)&reset_cmd,
363 srv_ws->server_memctx_data,
364 sizeof(static_state),
365 (uint8_t *)&static_state,
366 0,
367 RGX_CONTEXT_FLAG_DISABLESLR,
368 0,
369 UINT_MAX,
370 UINT_MAX,
371 &srv_ctx->handle);
372 if (result != VK_SUCCESS)
373 goto err_close_timeline_frag;
374
375 srv_ctx->base.ws = ws;
376
377 *ctx_out = &srv_ctx->base;
378
379 return VK_SUCCESS;
380
381 err_close_timeline_frag:
382 close(srv_ctx->timeline_frag);
383
384 err_close_timeline_geom:
385 close(srv_ctx->timeline_geom);
386
387 err_free_srv_ctx:
388 vk_free(srv_ws->alloc, srv_ctx);
389
390 return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
391 }
392
pvr_srv_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx * ctx)393 void pvr_srv_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx *ctx)
394 {
395 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
396 struct pvr_srv_winsys_render_ctx *srv_ctx =
397 to_pvr_srv_winsys_render_ctx(ctx);
398
399 pvr_srv_rgx_destroy_render_context(srv_ws->render_fd, srv_ctx->handle);
400 close(srv_ctx->timeline_frag);
401 close(srv_ctx->timeline_geom);
402 vk_free(srv_ws->alloc, srv_ctx);
403 }
404
pvr_srv_geometry_cmd_init(const struct pvr_winsys_render_submit_info * submit_info,const struct pvr_srv_sync_prim * sync_prim,struct rogue_fwif_cmd_ta * cmd)405 static void pvr_srv_geometry_cmd_init(
406 const struct pvr_winsys_render_submit_info *submit_info,
407 const struct pvr_srv_sync_prim *sync_prim,
408 struct rogue_fwif_cmd_ta *cmd)
409 {
410 const struct pvr_winsys_geometry_state *state = &submit_info->geometry;
411 struct rogue_fwif_ta_regs *fw_regs = &cmd->geom_regs;
412
413 memset(cmd, 0, sizeof(*cmd));
414
415 cmd->cmd_shared.cmn.frame_num = submit_info->frame_num;
416
417 fw_regs->vdm_ctrl_stream_base = state->regs.vdm_ctrl_stream_base;
418 fw_regs->tpu_border_colour_table = state->regs.tpu_border_colour_table;
419 fw_regs->ppp_ctrl = state->regs.ppp_ctrl;
420 fw_regs->te_psg = state->regs.te_psg;
421 fw_regs->tpu = state->regs.tpu;
422 fw_regs->vdm_context_resume_task0_size =
423 state->regs.vdm_ctx_resume_task0_size;
424
425 assert(state->regs.pds_ctrl >> 32U == 0U);
426 fw_regs->pds_ctrl = (uint32_t)state->regs.pds_ctrl;
427
428 if (state->flags & PVR_WINSYS_GEOM_FLAG_FIRST_GEOMETRY)
429 cmd->flags |= ROGUE_FWIF_TAFLAGS_FIRSTKICK;
430
431 if (state->flags & PVR_WINSYS_GEOM_FLAG_LAST_GEOMETRY)
432 cmd->flags |= ROGUE_FWIF_TAFLAGS_LASTKICK;
433
434 if (state->flags & PVR_WINSYS_GEOM_FLAG_SINGLE_CORE)
435 cmd->flags |= ROGUE_FWIF_TAFLAGS_SINGLE_CORE;
436
437 cmd->partial_render_ta_3d_fence.ufo_addr.addr =
438 pvr_srv_sync_prim_get_fw_addr(sync_prim);
439 cmd->partial_render_ta_3d_fence.value = sync_prim->value;
440 }
441
pvr_srv_fragment_cmd_init(const struct pvr_winsys_render_submit_info * submit_info,struct rogue_fwif_cmd_3d * cmd)442 static void pvr_srv_fragment_cmd_init(
443 const struct pvr_winsys_render_submit_info *submit_info,
444 struct rogue_fwif_cmd_3d *cmd)
445 {
446 const struct pvr_winsys_fragment_state *state = &submit_info->fragment;
447 struct rogue_fwif_3d_regs *fw_regs = &cmd->regs;
448
449 memset(cmd, 0, sizeof(*cmd));
450
451 cmd->cmd_shared.cmn.frame_num = submit_info->frame_num;
452
453 fw_regs->usc_pixel_output_ctrl = state->regs.usc_pixel_output_ctrl;
454 fw_regs->isp_bgobjdepth = state->regs.isp_bgobjdepth;
455 fw_regs->isp_bgobjvals = state->regs.isp_bgobjvals;
456 fw_regs->isp_aa = state->regs.isp_aa;
457 fw_regs->isp_ctl = state->regs.isp_ctl;
458 fw_regs->tpu = state->regs.tpu;
459 fw_regs->event_pixel_pds_info = state->regs.event_pixel_pds_info;
460 fw_regs->pixel_phantom = state->regs.pixel_phantom;
461 fw_regs->event_pixel_pds_data = state->regs.event_pixel_pds_data;
462 fw_regs->isp_scissor_base = state->regs.isp_scissor_base;
463 fw_regs->isp_dbias_base = state->regs.isp_dbias_base;
464 fw_regs->isp_oclqry_base = state->regs.isp_oclqry_base;
465 fw_regs->isp_zlsctl = state->regs.isp_zlsctl;
466 fw_regs->isp_zload_store_base = state->regs.isp_zload_store_base;
467 fw_regs->isp_stencil_load_store_base =
468 state->regs.isp_stencil_load_store_base;
469 fw_regs->isp_zls_pixels = state->regs.isp_zls_pixels;
470
471 STATIC_ASSERT(ARRAY_SIZE(fw_regs->pbe_word) ==
472 ARRAY_SIZE(state->regs.pbe_word));
473
474 STATIC_ASSERT(ARRAY_SIZE(fw_regs->pbe_word[0]) <=
475 ARRAY_SIZE(state->regs.pbe_word[0]));
476
477 #if !defined(NDEBUG)
478 /* Depending on the hardware we might have more PBE words than the firmware
479 * accepts so check that the extra words are 0.
480 */
481 if (ARRAY_SIZE(fw_regs->pbe_word[0]) < ARRAY_SIZE(state->regs.pbe_word[0])) {
482 /* For each color attachment. */
483 for (uint32_t i = 0; i < ARRAY_SIZE(state->regs.pbe_word); i++) {
484 /* For each extra PBE word not used by the firmware. */
485 for (uint32_t j = ARRAY_SIZE(fw_regs->pbe_word[0]);
486 j < ARRAY_SIZE(state->regs.pbe_word[0]);
487 j++) {
488 assert(state->regs.pbe_word[i][j] == 0);
489 }
490 }
491 }
492 #endif
493
494 memcpy(fw_regs->pbe_word, state->regs.pbe_word, sizeof(fw_regs->pbe_word));
495
496 fw_regs->tpu_border_colour_table = state->regs.tpu_border_colour_table;
497
498 STATIC_ASSERT(ARRAY_SIZE(fw_regs->pds_bgnd) ==
499 ARRAY_SIZE(state->regs.pds_bgnd));
500 typed_memcpy(fw_regs->pds_bgnd,
501 state->regs.pds_bgnd,
502 ARRAY_SIZE(fw_regs->pds_bgnd));
503
504 STATIC_ASSERT(ARRAY_SIZE(fw_regs->pds_pr_bgnd) ==
505 ARRAY_SIZE(state->regs.pds_pr_bgnd));
506 typed_memcpy(fw_regs->pds_pr_bgnd,
507 state->regs.pds_pr_bgnd,
508 ARRAY_SIZE(fw_regs->pds_pr_bgnd));
509
510 if (state->flags & PVR_WINSYS_FRAG_FLAG_DEPTH_BUFFER_PRESENT)
511 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_DEPTHBUFFER;
512
513 if (state->flags & PVR_WINSYS_FRAG_FLAG_STENCIL_BUFFER_PRESENT)
514 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_STENCILBUFFER;
515
516 if (state->flags & PVR_WINSYS_FRAG_FLAG_PREVENT_CDM_OVERLAP)
517 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_PREVENT_CDM_OVERLAP;
518
519 if (state->flags & PVR_WINSYS_FRAG_FLAG_SINGLE_CORE)
520 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_SINGLE_CORE;
521
522 cmd->zls_stride = state->zls_stride;
523 cmd->sls_stride = state->sls_stride;
524 }
525
pvr_srv_winsys_render_submit(const struct pvr_winsys_render_ctx * ctx,const struct pvr_winsys_render_submit_info * submit_info,struct vk_sync * signal_sync_geom,struct vk_sync * signal_sync_frag)526 VkResult pvr_srv_winsys_render_submit(
527 const struct pvr_winsys_render_ctx *ctx,
528 const struct pvr_winsys_render_submit_info *submit_info,
529 struct vk_sync *signal_sync_geom,
530 struct vk_sync *signal_sync_frag)
531 {
532 const struct pvr_srv_winsys_rt_dataset *srv_rt_dataset =
533 to_pvr_srv_winsys_rt_dataset(submit_info->rt_dataset);
534 struct pvr_srv_sync_prim *sync_prim =
535 srv_rt_dataset->rt_datas[submit_info->rt_data_idx].sync_prim;
536 void *rt_data_handle =
537 srv_rt_dataset->rt_datas[submit_info->rt_data_idx].handle;
538 const struct pvr_srv_winsys_render_ctx *srv_ctx =
539 to_pvr_srv_winsys_render_ctx(ctx);
540 const struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
541
542 uint32_t sync_pmr_flags[PVR_SRV_SYNC_MAX] = { 0U };
543 void *sync_pmrs[PVR_SRV_SYNC_MAX] = { NULL };
544 uint32_t sync_pmr_count;
545
546 struct pvr_srv_sync *srv_signal_sync_geom;
547 struct pvr_srv_sync *srv_signal_sync_frag;
548
549 struct rogue_fwif_cmd_ta geom_cmd;
550 struct rogue_fwif_cmd_3d frag_cmd;
551
552 int in_frag_fd = -1;
553 int in_geom_fd = -1;
554 int fence_frag;
555 int fence_geom;
556
557 VkResult result;
558
559 pvr_srv_geometry_cmd_init(submit_info, sync_prim, &geom_cmd);
560 pvr_srv_fragment_cmd_init(submit_info, &frag_cmd);
561
562 for (uint32_t i = 0U; i < submit_info->wait_count; i++) {
563 struct pvr_srv_sync *srv_wait_sync = to_srv_sync(submit_info->waits[i]);
564 int ret;
565
566 if (!submit_info->waits[i] || srv_wait_sync->fd < 0)
567 continue;
568
569 if (submit_info->stage_flags[i] & PVR_PIPELINE_STAGE_GEOM_BIT) {
570 ret = sync_accumulate("", &in_geom_fd, srv_wait_sync->fd);
571 if (ret) {
572 result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
573 goto err_close_in_fds;
574 }
575
576 submit_info->stage_flags[i] &= ~PVR_PIPELINE_STAGE_GEOM_BIT;
577 }
578
579 if (submit_info->stage_flags[i] & PVR_PIPELINE_STAGE_FRAG_BIT) {
580 ret = sync_accumulate("", &in_frag_fd, srv_wait_sync->fd);
581 if (ret) {
582 result = vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
583 goto err_close_in_fds;
584 }
585
586 submit_info->stage_flags[i] &= ~PVR_PIPELINE_STAGE_FRAG_BIT;
587 }
588 }
589
590 if (submit_info->bo_count <= ARRAY_SIZE(sync_pmrs)) {
591 sync_pmr_count = submit_info->bo_count;
592 } else {
593 mesa_logw("Too many bos to synchronize access to (ignoring %zu bos)\n",
594 submit_info->bo_count - ARRAY_SIZE(sync_pmrs));
595 sync_pmr_count = ARRAY_SIZE(sync_pmrs);
596 }
597
598 STATIC_ASSERT(ARRAY_SIZE(sync_pmrs) == ARRAY_SIZE(sync_pmr_flags));
599 assert(sync_pmr_count <= ARRAY_SIZE(sync_pmrs));
600 for (uint32_t i = 0; i < sync_pmr_count; i++) {
601 const struct pvr_winsys_job_bo *job_bo = &submit_info->bos[i];
602 const struct pvr_srv_winsys_bo *srv_bo = to_pvr_srv_winsys_bo(job_bo->bo);
603
604 sync_pmrs[i] = srv_bo->pmr;
605
606 if (job_bo->flags & PVR_WINSYS_JOB_BO_FLAG_WRITE)
607 sync_pmr_flags[i] = PVR_BUFFER_FLAG_WRITE;
608 else
609 sync_pmr_flags[i] = PVR_BUFFER_FLAG_READ;
610 }
611
612 /* The 1.14 PowerVR Services KM driver doesn't add a sync dependency to the
613 * fragment phase on the geometry phase for us. This makes it
614 * necessary to use a sync prim for this purpose. This requires that we pass
615 * in the same sync prim information for the geometry phase update and the
616 * PR fence. We update the sync prim value here as this is the value the
617 * sync prim will get updated to once the geometry phase has completed and
618 * the value the PR or fragment phase will be fenced on.
619 */
620 sync_prim->value++;
621
622 do {
623 result = pvr_srv_rgx_kick_render2(srv_ws->render_fd,
624 srv_ctx->handle,
625 0,
626 NULL,
627 NULL,
628 NULL,
629 1,
630 &sync_prim->srv_ws->sync_block_handle,
631 &sync_prim->offset,
632 &sync_prim->value,
633 0,
634 NULL,
635 NULL,
636 NULL,
637 sync_prim->srv_ws->sync_block_handle,
638 sync_prim->offset,
639 sync_prim->value,
640 in_geom_fd,
641 srv_ctx->timeline_geom,
642 &fence_geom,
643 "GEOM",
644 in_frag_fd,
645 srv_ctx->timeline_frag,
646 &fence_frag,
647 "FRAG",
648 sizeof(geom_cmd),
649 (uint8_t *)&geom_cmd,
650 /* Currently no support for PRs. */
651 0,
652 /* Currently no support for PRs. */
653 NULL,
654 sizeof(frag_cmd),
655 (uint8_t *)&frag_cmd,
656 submit_info->job_num,
657 /* Always kick the TA. */
658 true,
659 /* Always kick a PR. */
660 true,
661 submit_info->run_frag,
662 false,
663 0,
664 rt_data_handle,
665 /* Currently no support for PRs. */
666 NULL,
667 /* Currently no support for PRs. */
668 NULL,
669 sync_pmr_count,
670 sync_pmr_count ? sync_pmr_flags : NULL,
671 sync_pmr_count ? sync_pmrs : NULL,
672 0,
673 0,
674 0,
675 0,
676 0);
677 } while (result == VK_NOT_READY);
678
679 if (result != VK_SUCCESS)
680 goto err_close_in_fds;
681
682 if (signal_sync_geom) {
683 srv_signal_sync_geom = to_srv_sync(signal_sync_geom);
684 pvr_srv_set_sync_payload(srv_signal_sync_geom, fence_geom);
685 } else if (fence_geom != -1) {
686 close(fence_geom);
687 }
688
689 if (signal_sync_frag) {
690 srv_signal_sync_frag = to_srv_sync(signal_sync_frag);
691 pvr_srv_set_sync_payload(srv_signal_sync_frag, fence_frag);
692 } else if (fence_frag != -1) {
693 close(fence_frag);
694 }
695
696 return VK_SUCCESS;
697
698 err_close_in_fds:
699 if (in_geom_fd >= 0)
700 close(in_geom_fd);
701
702 if (in_frag_fd >= 0)
703 close(in_frag_fd);
704
705 return result;
706 }
707