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 <errno.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <stdbool.h>
29 #include <stddef.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <vulkan/vulkan.h>
34
35 #include "fw-api/pvr_rogue_fwif.h"
36 #include "fw-api/pvr_rogue_fwif_rf.h"
37 #include "pvr_csb.h"
38 #include "pvr_job_render.h"
39 #include "pvr_private.h"
40 #include "pvr_srv.h"
41 #include "pvr_srv_bo.h"
42 #include "pvr_srv_bridge.h"
43 #include "pvr_srv_job_common.h"
44 #include "pvr_srv_job_render.h"
45 #include "pvr_srv_sync.h"
46 #include "pvr_srv_sync_prim.h"
47 #include "pvr_types.h"
48 #include "pvr_winsys.h"
49 #include "util/compiler.h"
50 #include "util/log.h"
51 #include "util/macros.h"
52 #include "util/u_math.h"
53 #include "vk_alloc.h"
54 #include "vk_log.h"
55 #include "vk_util.h"
56
57 struct pvr_srv_winsys_free_list {
58 struct pvr_winsys_free_list base;
59
60 void *handle;
61
62 struct pvr_srv_winsys_free_list *parent;
63 };
64
65 #define to_pvr_srv_winsys_free_list(free_list) \
66 container_of(free_list, struct pvr_srv_winsys_free_list, base)
67
68 struct pvr_srv_winsys_rt_dataset {
69 struct pvr_winsys_rt_dataset base;
70
71 struct {
72 void *handle;
73 struct pvr_srv_sync_prim *sync_prim;
74 } rt_datas[ROGUE_FWIF_NUM_RTDATAS];
75 };
76
77 #define to_pvr_srv_winsys_rt_dataset(rt_dataset) \
78 container_of(rt_dataset, struct pvr_srv_winsys_rt_dataset, base)
79
80 struct pvr_srv_winsys_render_ctx {
81 struct pvr_winsys_render_ctx base;
82
83 /* Handle to kernel context. */
84 void *handle;
85
86 int timeline_geom;
87 int timeline_frag;
88 };
89
90 #define to_pvr_srv_winsys_render_ctx(ctx) \
91 container_of(ctx, struct pvr_srv_winsys_render_ctx, base)
92
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)93 VkResult pvr_srv_winsys_free_list_create(
94 struct pvr_winsys *ws,
95 struct pvr_winsys_vma *free_list_vma,
96 uint32_t initial_num_pages,
97 uint32_t max_num_pages,
98 uint32_t grow_num_pages,
99 uint32_t grow_threshold,
100 struct pvr_winsys_free_list *parent_free_list,
101 struct pvr_winsys_free_list **const free_list_out)
102 {
103 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
104 struct pvr_srv_winsys_bo *srv_free_list_bo =
105 to_pvr_srv_winsys_bo(free_list_vma->bo);
106 struct pvr_srv_winsys_free_list *srv_free_list;
107 void *parent_handle;
108 VkResult result;
109
110 srv_free_list = vk_zalloc(ws->alloc,
111 sizeof(*srv_free_list),
112 8,
113 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
114 if (!srv_free_list)
115 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
116
117 if (parent_free_list) {
118 srv_free_list->parent = to_pvr_srv_winsys_free_list(parent_free_list);
119 parent_handle = srv_free_list->parent->handle;
120 } else {
121 srv_free_list->parent = NULL;
122 parent_handle = NULL;
123 }
124
125 result = pvr_srv_rgx_create_free_list(ws->render_fd,
126 srv_ws->server_memctx_data,
127 max_num_pages,
128 initial_num_pages,
129 grow_num_pages,
130 grow_threshold,
131 parent_handle,
132 #if MESA_DEBUG
133 PVR_SRV_TRUE /* free_list_check */,
134 #else
135 PVR_SRV_FALSE /* free_list_check */,
136 #endif
137 free_list_vma->dev_addr,
138 srv_free_list_bo->pmr,
139 0 /* pmr_offset */,
140 &srv_free_list->handle);
141 if (result != VK_SUCCESS)
142 goto err_vk_free_srv_free_list;
143
144 srv_free_list->base.ws = ws;
145
146 *free_list_out = &srv_free_list->base;
147
148 return VK_SUCCESS;
149
150 err_vk_free_srv_free_list:
151 vk_free(ws->alloc, srv_free_list);
152
153 return result;
154 }
155
pvr_srv_winsys_free_list_destroy(struct pvr_winsys_free_list * free_list)156 void pvr_srv_winsys_free_list_destroy(struct pvr_winsys_free_list *free_list)
157 {
158 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(free_list->ws);
159 struct pvr_srv_winsys_free_list *srv_free_list =
160 to_pvr_srv_winsys_free_list(free_list);
161
162 pvr_srv_rgx_destroy_free_list(srv_ws->base.render_fd, srv_free_list->handle);
163 vk_free(srv_ws->base.alloc, srv_free_list);
164 }
165
pvr_rogue_get_cr_multisamplectl_val(uint32_t samples,bool y_flip)166 static uint64_t pvr_rogue_get_cr_multisamplectl_val(uint32_t samples,
167 bool y_flip)
168 {
169 static const struct {
170 uint8_t x[8];
171 uint8_t y[8];
172 } sample_positions[4] = {
173 /* 1 sample */
174 {
175 .x = { 8 },
176 .y = { 8 },
177 },
178 /* 2 samples */
179 {
180 .x = { 12, 4 },
181 .y = { 12, 4 },
182 },
183 /* 4 samples */
184 {
185 .x = { 6, 14, 2, 10 },
186 .y = { 2, 6, 10, 14 },
187 },
188 /* 8 samples */
189 {
190 .x = { 9, 7, 13, 5, 3, 1, 11, 15 },
191 .y = { 5, 11, 9, 3, 13, 7, 15, 1 },
192 },
193 };
194 uint64_t multisamplectl;
195 uint8_t idx;
196
197 idx = util_fast_log2(samples);
198 assert(idx < ARRAY_SIZE(sample_positions));
199
200 pvr_csb_pack (&multisamplectl, CR_PPP_MULTISAMPLECTL, value) {
201 switch (samples) {
202 case 8:
203 value.msaa_x7 = sample_positions[idx].x[7];
204 value.msaa_x6 = sample_positions[idx].x[6];
205 value.msaa_x5 = sample_positions[idx].x[5];
206 value.msaa_x4 = sample_positions[idx].x[4];
207
208 if (y_flip) {
209 value.msaa_y7 = 16U - sample_positions[idx].y[7];
210 value.msaa_y6 = 16U - sample_positions[idx].y[6];
211 value.msaa_y5 = 16U - sample_positions[idx].y[5];
212 value.msaa_y4 = 16U - sample_positions[idx].y[4];
213 } else {
214 value.msaa_y7 = sample_positions[idx].y[7];
215 value.msaa_y6 = sample_positions[idx].y[6];
216 value.msaa_y5 = sample_positions[idx].y[5];
217 value.msaa_y4 = sample_positions[idx].y[4];
218 }
219
220 FALLTHROUGH;
221 case 4:
222 value.msaa_x3 = sample_positions[idx].x[3];
223 value.msaa_x2 = sample_positions[idx].x[2];
224
225 if (y_flip) {
226 value.msaa_y3 = 16U - sample_positions[idx].y[3];
227 value.msaa_y2 = 16U - sample_positions[idx].y[2];
228 } else {
229 value.msaa_y3 = sample_positions[idx].y[3];
230 value.msaa_y2 = sample_positions[idx].y[2];
231 }
232
233 FALLTHROUGH;
234 case 2:
235 value.msaa_x1 = sample_positions[idx].x[1];
236
237 if (y_flip) {
238 value.msaa_y1 = 16U - sample_positions[idx].y[1];
239 } else {
240 value.msaa_y1 = sample_positions[idx].y[1];
241 }
242
243 FALLTHROUGH;
244 case 1:
245 value.msaa_x0 = sample_positions[idx].x[0];
246
247 if (y_flip) {
248 value.msaa_y0 = 16U - sample_positions[idx].y[0];
249 } else {
250 value.msaa_y0 = sample_positions[idx].y[0];
251 }
252
253 break;
254 default:
255 unreachable("Unsupported number of samples");
256 }
257 }
258
259 return multisamplectl;
260 }
261
262 static uint32_t
pvr_rogue_get_cr_isp_mtile_size_val(const struct pvr_device_info * dev_info,const struct pvr_rt_mtile_info * mtile_info,uint32_t samples)263 pvr_rogue_get_cr_isp_mtile_size_val(const struct pvr_device_info *dev_info,
264 const struct pvr_rt_mtile_info *mtile_info,
265 uint32_t samples)
266 {
267 uint32_t samples_per_pixel =
268 PVR_GET_FEATURE_VALUE(dev_info, isp_samples_per_pixel, 0);
269 uint32_t isp_mtile_size;
270
271 pvr_csb_pack (&isp_mtile_size, CR_ISP_MTILE_SIZE, value) {
272 value.x = mtile_info->mtile_x1;
273 value.y = mtile_info->mtile_y1;
274
275 if (samples_per_pixel == 1) {
276 if (samples >= 4)
277 value.x <<= 1;
278
279 if (samples >= 2)
280 value.y <<= 1;
281 } else if (samples_per_pixel == 2) {
282 if (samples >= 8)
283 value.x <<= 1;
284
285 if (samples >= 4)
286 value.y <<= 1;
287 } else if (samples_per_pixel == 4) {
288 if (samples >= 8)
289 value.y <<= 1;
290 } else {
291 assert(!"Unsupported ISP samples per pixel value");
292 }
293 }
294
295 return isp_mtile_size;
296 }
297
pvr_rogue_get_ppp_screen_val(uint32_t width,uint32_t height)298 static uint32_t pvr_rogue_get_ppp_screen_val(uint32_t width, uint32_t height)
299 {
300 uint32_t val;
301
302 pvr_csb_pack (&val, CR_PPP_SCREEN, state) {
303 state.pixxmax = width - 1;
304 state.pixymax = height - 1;
305 }
306
307 return val;
308 }
309
310 struct pvr_rogue_cr_te {
311 uint32_t aa;
312 uint32_t mtile1;
313 uint32_t mtile2;
314 uint32_t screen;
315 uint32_t mtile_stride;
316 };
317
pvr_rogue_ct_te_init(const struct pvr_device_info * dev_info,const struct pvr_rt_mtile_info * mtile_info,uint32_t samples,struct pvr_rogue_cr_te * const te_regs)318 static void pvr_rogue_ct_te_init(const struct pvr_device_info *dev_info,
319 const struct pvr_rt_mtile_info *mtile_info,
320 uint32_t samples,
321 struct pvr_rogue_cr_te *const te_regs)
322 {
323 uint32_t samples_per_pixel =
324 PVR_GET_FEATURE_VALUE(dev_info, isp_samples_per_pixel, 0);
325
326 pvr_csb_pack (&te_regs->aa, CR_TE_AA, value) {
327 if (samples_per_pixel == 1) {
328 if (samples >= 2)
329 value.y = true;
330 if (samples >= 4)
331 value.x = true;
332 } else if (samples_per_pixel == 2) {
333 if (samples >= 2)
334 value.x2 = true;
335 if (samples >= 4)
336 value.y = true;
337 if (samples >= 8)
338 value.x = true;
339 } else if (samples_per_pixel == 4) {
340 if (samples >= 2)
341 value.x2 = true;
342 if (samples >= 4)
343 value.y2 = true;
344 if (samples >= 8)
345 value.y = true;
346 } else {
347 assert(!"Unsupported ISP samples per pixel value");
348 }
349 }
350
351 pvr_csb_pack (&te_regs->mtile1, CR_TE_MTILE1, value) {
352 value.x1 = mtile_info->mtile_x1;
353 if (!PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
354 value.x2 = mtile_info->mtile_x2;
355 value.x3 = mtile_info->mtile_x3;
356 }
357 }
358
359 pvr_csb_pack (&te_regs->mtile2, CR_TE_MTILE2, value) {
360 value.y1 = mtile_info->mtile_y1;
361 if (!PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
362 value.y2 = mtile_info->mtile_y2;
363 value.y3 = mtile_info->mtile_y3;
364 }
365 }
366
367 pvr_csb_pack (&te_regs->screen, CR_TE_SCREEN, value) {
368 value.xmax = mtile_info->x_tile_max;
369 value.ymax = mtile_info->y_tile_max;
370 }
371
372 te_regs->mtile_stride = mtile_info->mtile_x1 * mtile_info->mtile_y1;
373 }
374
pvr_srv_render_target_dataset_create(struct pvr_winsys * ws,const struct pvr_winsys_rt_dataset_create_info * create_info,const struct pvr_device_info * dev_info,struct pvr_winsys_rt_dataset ** const rt_dataset_out)375 VkResult pvr_srv_render_target_dataset_create(
376 struct pvr_winsys *ws,
377 const struct pvr_winsys_rt_dataset_create_info *create_info,
378 const struct pvr_device_info *dev_info,
379 struct pvr_winsys_rt_dataset **const rt_dataset_out)
380 {
381 const pvr_dev_addr_t macrotile_addrs[ROGUE_FWIF_NUM_RTDATAS] = {
382 [0] = create_info->rt_datas[0].macrotile_array_dev_addr,
383 [1] = create_info->rt_datas[1].macrotile_array_dev_addr,
384 };
385 const pvr_dev_addr_t pm_mlist_addrs[ROGUE_FWIF_NUM_RTDATAS] = {
386 [0] = create_info->rt_datas[0].pm_mlist_dev_addr,
387 [1] = create_info->rt_datas[1].pm_mlist_dev_addr,
388 };
389 const pvr_dev_addr_t rgn_header_addrs[ROGUE_FWIF_NUM_RTDATAS] = {
390 [0] = create_info->rt_datas[0].rgn_header_dev_addr,
391 [1] = create_info->rt_datas[1].rgn_header_dev_addr,
392 };
393
394 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
395 struct pvr_srv_winsys_free_list *srv_local_free_list =
396 to_pvr_srv_winsys_free_list(create_info->local_free_list);
397 void *free_lists[ROGUE_FW_MAX_FREELISTS] = { NULL };
398 struct pvr_srv_winsys_rt_dataset *srv_rt_dataset;
399 void *handles[ROGUE_FWIF_NUM_RTDATAS];
400 struct pvr_rogue_cr_te rogue_te_regs;
401 struct pvr_rt_mtile_info mtile_info;
402 uint32_t isp_mtile_size;
403 VkResult result;
404
405 free_lists[ROGUE_FW_LOCAL_FREELIST] = srv_local_free_list->handle;
406
407 if (srv_local_free_list->parent) {
408 free_lists[ROGUE_FW_GLOBAL_FREELIST] =
409 srv_local_free_list->parent->handle;
410 }
411
412 srv_rt_dataset = vk_zalloc(ws->alloc,
413 sizeof(*srv_rt_dataset),
414 8,
415 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
416 if (!srv_rt_dataset)
417 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
418
419 /* If greater than 1 we'll have to pass in an array. For now just passing in
420 * the reference.
421 */
422 STATIC_ASSERT(ROGUE_FWIF_NUM_GEOMDATAS == 1);
423 /* If not 2 the arrays used in the bridge call will require updating. */
424 STATIC_ASSERT(ROGUE_FWIF_NUM_RTDATAS == 2);
425
426 pvr_rt_mtile_info_init(dev_info,
427 &mtile_info,
428 create_info->width,
429 create_info->height,
430 create_info->samples);
431
432 isp_mtile_size = pvr_rogue_get_cr_isp_mtile_size_val(dev_info,
433 &mtile_info,
434 create_info->samples);
435
436 pvr_rogue_ct_te_init(dev_info,
437 &mtile_info,
438 create_info->samples,
439 &rogue_te_regs);
440
441 result = pvr_srv_rgx_create_hwrt_dataset(
442 ws->render_fd,
443 pvr_rogue_get_cr_multisamplectl_val(create_info->samples, true),
444 pvr_rogue_get_cr_multisamplectl_val(create_info->samples, false),
445 macrotile_addrs,
446 pm_mlist_addrs,
447 &create_info->rtc_dev_addr,
448 rgn_header_addrs,
449 &create_info->tpc_dev_addr,
450 &create_info->vheap_table_dev_addr,
451 free_lists,
452 create_info->isp_merge_lower_x,
453 create_info->isp_merge_lower_y,
454 create_info->isp_merge_scale_x,
455 create_info->isp_merge_scale_y,
456 create_info->isp_merge_upper_x,
457 create_info->isp_merge_upper_y,
458 isp_mtile_size,
459 rogue_te_regs.mtile_stride,
460 pvr_rogue_get_ppp_screen_val(create_info->width, create_info->height),
461 create_info->rgn_header_size,
462 rogue_te_regs.aa,
463 rogue_te_regs.mtile1,
464 rogue_te_regs.mtile2,
465 rogue_te_regs.screen,
466 create_info->tpc_size,
467 create_info->tpc_stride,
468 create_info->layers,
469 handles);
470 if (result != VK_SUCCESS)
471 goto err_vk_free_srv_rt_dataset;
472
473 srv_rt_dataset->rt_datas[0].handle = handles[0];
474 srv_rt_dataset->rt_datas[1].handle = handles[1];
475
476 for (uint32_t i = 0; i < ARRAY_SIZE(srv_rt_dataset->rt_datas); i++) {
477 srv_rt_dataset->rt_datas[i].sync_prim = pvr_srv_sync_prim_alloc(srv_ws);
478 if (!srv_rt_dataset->rt_datas[i].sync_prim)
479 goto err_srv_sync_prim_free;
480 }
481
482 srv_rt_dataset->base.ws = ws;
483
484 *rt_dataset_out = &srv_rt_dataset->base;
485
486 return VK_SUCCESS;
487
488 err_srv_sync_prim_free:
489 for (uint32_t i = 0; i < ARRAY_SIZE(srv_rt_dataset->rt_datas); i++) {
490 pvr_srv_sync_prim_free(srv_ws, srv_rt_dataset->rt_datas[i].sync_prim);
491
492 if (srv_rt_dataset->rt_datas[i].handle) {
493 pvr_srv_rgx_destroy_hwrt_dataset(ws->render_fd,
494 srv_rt_dataset->rt_datas[i].handle);
495 }
496 }
497
498 err_vk_free_srv_rt_dataset:
499 vk_free(ws->alloc, srv_rt_dataset);
500
501 return result;
502 }
503
pvr_srv_render_target_dataset_destroy(struct pvr_winsys_rt_dataset * rt_dataset)504 void pvr_srv_render_target_dataset_destroy(
505 struct pvr_winsys_rt_dataset *rt_dataset)
506 {
507 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(rt_dataset->ws);
508 struct pvr_srv_winsys_rt_dataset *srv_rt_dataset =
509 to_pvr_srv_winsys_rt_dataset(rt_dataset);
510
511 for (uint32_t i = 0; i < ARRAY_SIZE(srv_rt_dataset->rt_datas); i++) {
512 pvr_srv_sync_prim_free(srv_ws, srv_rt_dataset->rt_datas[i].sync_prim);
513
514 if (srv_rt_dataset->rt_datas[i].handle) {
515 pvr_srv_rgx_destroy_hwrt_dataset(srv_ws->base.render_fd,
516 srv_rt_dataset->rt_datas[i].handle);
517 }
518 }
519
520 vk_free(srv_ws->base.alloc, srv_rt_dataset);
521 }
522
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)523 static void pvr_srv_render_ctx_fw_static_state_init(
524 struct pvr_winsys_render_ctx_create_info *create_info,
525 struct rogue_fwif_static_rendercontext_state *static_state)
526 {
527 struct pvr_winsys_render_ctx_static_state *ws_static_state =
528 &create_info->static_state;
529 struct rogue_fwif_ta_regs_cswitch *regs =
530 &static_state->ctx_switch_geom_regs[0];
531
532 memset(static_state, 0, sizeof(*static_state));
533
534 regs->vdm_context_state_base_addr = ws_static_state->vdm_ctx_state_base_addr;
535 regs->ta_context_state_base_addr = ws_static_state->geom_ctx_state_base_addr;
536
537 STATIC_ASSERT(ARRAY_SIZE(regs->ta_state) ==
538 ARRAY_SIZE(ws_static_state->geom_state));
539 for (uint32_t i = 0; i < ARRAY_SIZE(ws_static_state->geom_state); i++) {
540 regs->ta_state[i].vdm_context_store_task0 =
541 ws_static_state->geom_state[i].vdm_ctx_store_task0;
542 regs->ta_state[i].vdm_context_store_task1 =
543 ws_static_state->geom_state[i].vdm_ctx_store_task1;
544 regs->ta_state[i].vdm_context_store_task2 =
545 ws_static_state->geom_state[i].vdm_ctx_store_task2;
546
547 regs->ta_state[i].vdm_context_resume_task0 =
548 ws_static_state->geom_state[i].vdm_ctx_resume_task0;
549 regs->ta_state[i].vdm_context_resume_task1 =
550 ws_static_state->geom_state[i].vdm_ctx_resume_task1;
551 regs->ta_state[i].vdm_context_resume_task2 =
552 ws_static_state->geom_state[i].vdm_ctx_resume_task2;
553 }
554 }
555
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)556 VkResult pvr_srv_winsys_render_ctx_create(
557 struct pvr_winsys *ws,
558 struct pvr_winsys_render_ctx_create_info *create_info,
559 struct pvr_winsys_render_ctx **const ctx_out)
560 {
561 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ws);
562 struct rogue_fwif_rf_cmd reset_cmd = { 0 };
563
564 struct rogue_fwif_static_rendercontext_state static_state;
565 struct pvr_srv_winsys_render_ctx *srv_ctx;
566 const uint32_t call_stack_depth = 1U;
567 VkResult result;
568
569 srv_ctx = vk_zalloc(ws->alloc,
570 sizeof(*srv_ctx),
571 8,
572 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
573 if (!srv_ctx)
574 return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
575
576 result = pvr_srv_create_timeline(ws->render_fd, &srv_ctx->timeline_geom);
577 if (result != VK_SUCCESS)
578 goto err_free_srv_ctx;
579
580 result = pvr_srv_create_timeline(ws->render_fd, &srv_ctx->timeline_frag);
581 if (result != VK_SUCCESS)
582 goto err_close_timeline_geom;
583
584 pvr_srv_render_ctx_fw_static_state_init(create_info, &static_state);
585
586 /* TODO: Add support for reset framework. Currently we subtract
587 * reset_cmd.regs size from reset_cmd size to only pass empty flags field.
588 */
589 result = pvr_srv_rgx_create_render_context(
590 ws->render_fd,
591 pvr_srv_from_winsys_priority(create_info->priority),
592 create_info->vdm_callstack_addr,
593 call_stack_depth,
594 sizeof(reset_cmd) - sizeof(reset_cmd.regs),
595 (uint8_t *)&reset_cmd,
596 srv_ws->server_memctx_data,
597 sizeof(static_state),
598 (uint8_t *)&static_state,
599 0,
600 RGX_CONTEXT_FLAG_DISABLESLR,
601 0,
602 UINT_MAX,
603 UINT_MAX,
604 &srv_ctx->handle);
605 if (result != VK_SUCCESS)
606 goto err_close_timeline_frag;
607
608 srv_ctx->base.ws = ws;
609
610 *ctx_out = &srv_ctx->base;
611
612 return VK_SUCCESS;
613
614 err_close_timeline_frag:
615 close(srv_ctx->timeline_frag);
616
617 err_close_timeline_geom:
618 close(srv_ctx->timeline_geom);
619
620 err_free_srv_ctx:
621 vk_free(ws->alloc, srv_ctx);
622
623 return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
624 }
625
pvr_srv_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx * ctx)626 void pvr_srv_winsys_render_ctx_destroy(struct pvr_winsys_render_ctx *ctx)
627 {
628 struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
629 struct pvr_srv_winsys_render_ctx *srv_ctx =
630 to_pvr_srv_winsys_render_ctx(ctx);
631
632 pvr_srv_rgx_destroy_render_context(srv_ws->base.render_fd, srv_ctx->handle);
633 close(srv_ctx->timeline_frag);
634 close(srv_ctx->timeline_geom);
635 vk_free(srv_ws->base.alloc, srv_ctx);
636 }
637
638 static uint32_t
pvr_srv_geometry_cmd_stream_load(struct rogue_fwif_cmd_ta * const cmd,const uint8_t * const stream,const uint32_t stream_len,const struct pvr_device_info * const dev_info)639 pvr_srv_geometry_cmd_stream_load(struct rogue_fwif_cmd_ta *const cmd,
640 const uint8_t *const stream,
641 const uint32_t stream_len,
642 const struct pvr_device_info *const dev_info)
643 {
644 const uint32_t *stream_ptr = (const uint32_t *)stream;
645 struct rogue_fwif_ta_regs *const regs = &cmd->regs;
646 uint32_t main_stream_len =
647 pvr_csb_unpack((const uint64_t *)stream_ptr, KMD_STREAM_HDR).length;
648
649 stream_ptr += pvr_cmd_length(KMD_STREAM_HDR);
650
651 regs->vdm_ctrl_stream_base = *(const uint64_t *)stream_ptr;
652 stream_ptr += pvr_cmd_length(CR_VDM_CTRL_STREAM_BASE);
653
654 regs->tpu_border_colour_table = *(const uint64_t *)stream_ptr;
655 stream_ptr += pvr_cmd_length(CR_TPU_BORDER_COLOUR_TABLE_VDM);
656
657 regs->ppp_ctrl = *stream_ptr;
658 stream_ptr += pvr_cmd_length(CR_PPP_CTRL);
659
660 regs->te_psg = *stream_ptr;
661 stream_ptr += pvr_cmd_length(CR_TE_PSG);
662
663 regs->vdm_context_resume_task0_size = *stream_ptr;
664 stream_ptr += pvr_cmd_length(VDMCTRL_PDS_STATE0);
665
666 regs->view_idx = *stream_ptr;
667 stream_ptr++;
668
669 assert((const uint8_t *)stream_ptr - stream <= stream_len);
670 assert((const uint8_t *)stream_ptr - stream == main_stream_len);
671
672 return main_stream_len;
673 }
674
pvr_srv_geometry_cmd_ext_stream_load(struct rogue_fwif_cmd_ta * const cmd,const uint8_t * const stream,const uint32_t stream_len,const uint32_t ext_stream_offset,const struct pvr_device_info * const dev_info)675 static void pvr_srv_geometry_cmd_ext_stream_load(
676 struct rogue_fwif_cmd_ta *const cmd,
677 const uint8_t *const stream,
678 const uint32_t stream_len,
679 const uint32_t ext_stream_offset,
680 const struct pvr_device_info *const dev_info)
681 {
682 const uint32_t *ext_stream_ptr =
683 (const uint32_t *)((uint8_t *)stream + ext_stream_offset);
684 struct rogue_fwif_ta_regs *const regs = &cmd->regs;
685
686 struct ROGUE_KMD_STREAM_EXTHDR_GEOM0 header0;
687
688 header0 = pvr_csb_unpack(ext_stream_ptr, KMD_STREAM_EXTHDR_GEOM0);
689 ext_stream_ptr += pvr_cmd_length(KMD_STREAM_EXTHDR_GEOM0);
690
691 assert(PVR_HAS_QUIRK(dev_info, 49927) == header0.has_brn49927);
692 if (header0.has_brn49927) {
693 regs->tpu = *ext_stream_ptr;
694 ext_stream_ptr += pvr_cmd_length(CR_TPU);
695 }
696
697 assert((const uint8_t *)ext_stream_ptr - stream == stream_len);
698 }
699
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,const struct pvr_device_info * const dev_info)700 static void pvr_srv_geometry_cmd_init(
701 const struct pvr_winsys_render_submit_info *submit_info,
702 const struct pvr_srv_sync_prim *sync_prim,
703 struct rogue_fwif_cmd_ta *cmd,
704 const struct pvr_device_info *const dev_info)
705 {
706 const struct pvr_winsys_geometry_state *state = &submit_info->geometry;
707 uint32_t ext_stream_offset;
708
709 memset(cmd, 0, sizeof(*cmd));
710
711 cmd->cmd_shared.cmn.frame_num = submit_info->frame_num;
712
713 ext_stream_offset = pvr_srv_geometry_cmd_stream_load(cmd,
714 state->fw_stream,
715 state->fw_stream_len,
716 dev_info);
717
718 if (ext_stream_offset < state->fw_stream_len) {
719 pvr_srv_geometry_cmd_ext_stream_load(cmd,
720 state->fw_stream,
721 state->fw_stream_len,
722 ext_stream_offset,
723 dev_info);
724 }
725
726 if (state->flags.is_first_geometry)
727 cmd->flags |= ROGUE_FWIF_TAFLAGS_FIRSTKICK;
728
729 if (state->flags.is_last_geometry)
730 cmd->flags |= ROGUE_FWIF_TAFLAGS_LASTKICK;
731
732 if (state->flags.use_single_core)
733 cmd->flags |= ROGUE_FWIF_TAFLAGS_SINGLE_CORE;
734
735 cmd->partial_render_ta_3d_fence.ufo_addr.addr =
736 pvr_srv_sync_prim_get_fw_addr(sync_prim);
737 cmd->partial_render_ta_3d_fence.value = sync_prim->value;
738 }
739
740 static uint32_t
pvr_srv_fragment_cmd_stream_load(struct rogue_fwif_cmd_3d * const cmd,const uint8_t * const stream,const uint32_t stream_len,const struct pvr_device_info * const dev_info)741 pvr_srv_fragment_cmd_stream_load(struct rogue_fwif_cmd_3d *const cmd,
742 const uint8_t *const stream,
743 const uint32_t stream_len,
744 const struct pvr_device_info *const dev_info)
745 {
746 const uint32_t *stream_ptr = (const uint32_t *)stream;
747 struct rogue_fwif_3d_regs *const regs = &cmd->regs;
748 uint32_t main_stream_len =
749 pvr_csb_unpack((const uint64_t *)stream_ptr, KMD_STREAM_HDR).length;
750
751 stream_ptr += pvr_cmd_length(KMD_STREAM_HDR);
752
753 regs->isp_scissor_base = *(const uint64_t *)stream_ptr;
754 stream_ptr += pvr_cmd_length(CR_ISP_SCISSOR_BASE);
755
756 regs->isp_dbias_base = *(const uint64_t *)stream_ptr;
757 stream_ptr += pvr_cmd_length(CR_ISP_DBIAS_BASE);
758
759 regs->isp_oclqry_base = *(const uint64_t *)stream_ptr;
760 stream_ptr += pvr_cmd_length(CR_ISP_OCLQRY_BASE);
761
762 regs->isp_zlsctl = *(const uint64_t *)stream_ptr;
763 stream_ptr += pvr_cmd_length(CR_ISP_ZLSCTL);
764
765 regs->isp_zload_store_base = *(const uint64_t *)stream_ptr;
766 stream_ptr += pvr_cmd_length(CR_ISP_ZLOAD_BASE);
767
768 regs->isp_stencil_load_store_base = *(const uint64_t *)stream_ptr;
769 stream_ptr += pvr_cmd_length(CR_ISP_STENCIL_LOAD_BASE);
770
771 if (PVR_HAS_FEATURE(dev_info, requires_fb_cdc_zls_setup)) {
772 regs->fb_cdc_zls = *(const uint64_t *)stream_ptr;
773 stream_ptr += 2U;
774 }
775
776 STATIC_ASSERT(ARRAY_SIZE(regs->pbe_word) == 8U);
777 STATIC_ASSERT(ARRAY_SIZE(regs->pbe_word[0]) == 3U);
778 STATIC_ASSERT(sizeof(regs->pbe_word[0][0]) == sizeof(uint64_t));
779 memcpy(regs->pbe_word, stream_ptr, sizeof(regs->pbe_word));
780 stream_ptr += 8U * 3U * 2U;
781
782 regs->tpu_border_colour_table = *(const uint64_t *)stream_ptr;
783 stream_ptr += pvr_cmd_length(CR_TPU_BORDER_COLOUR_TABLE_PDM);
784
785 STATIC_ASSERT(ARRAY_SIZE(regs->pds_bgnd) == 3U);
786 STATIC_ASSERT(sizeof(regs->pds_bgnd[0]) == sizeof(uint64_t));
787 memcpy(regs->pds_bgnd, stream_ptr, sizeof(regs->pds_bgnd));
788 stream_ptr += 3U * 2U;
789
790 STATIC_ASSERT(ARRAY_SIZE(regs->pds_pr_bgnd) == 3U);
791 STATIC_ASSERT(sizeof(regs->pds_pr_bgnd[0]) == sizeof(uint64_t));
792 memcpy(regs->pds_pr_bgnd, stream_ptr, sizeof(regs->pds_pr_bgnd));
793 stream_ptr += 3U * 2U;
794
795 STATIC_ASSERT(ARRAY_SIZE(regs->usc_clear_register) == 8U);
796 STATIC_ASSERT(sizeof(regs->usc_clear_register[0]) == sizeof(uint32_t));
797 memcpy(regs->usc_clear_register,
798 stream_ptr,
799 sizeof(regs->usc_clear_register));
800 stream_ptr += 8U;
801
802 regs->usc_pixel_output_ctrl = *stream_ptr;
803 stream_ptr += pvr_cmd_length(CR_USC_PIXEL_OUTPUT_CTRL);
804
805 regs->isp_bgobjdepth = *stream_ptr;
806 stream_ptr += pvr_cmd_length(CR_ISP_BGOBJDEPTH);
807
808 regs->isp_bgobjvals = *stream_ptr;
809 stream_ptr += pvr_cmd_length(CR_ISP_BGOBJVALS);
810
811 regs->isp_aa = *stream_ptr;
812 stream_ptr += pvr_cmd_length(CR_ISP_AA);
813
814 regs->isp_ctl = *stream_ptr;
815 stream_ptr += pvr_cmd_length(CR_ISP_CTL);
816
817 regs->event_pixel_pds_info = *stream_ptr;
818 stream_ptr += pvr_cmd_length(CR_EVENT_PIXEL_PDS_INFO);
819
820 if (PVR_HAS_FEATURE(dev_info, cluster_grouping)) {
821 regs->pixel_phantom = *stream_ptr;
822 stream_ptr++;
823 }
824
825 regs->view_idx = *stream_ptr;
826 stream_ptr++;
827
828 regs->event_pixel_pds_data = *stream_ptr;
829 stream_ptr += pvr_cmd_length(CR_EVENT_PIXEL_PDS_DATA);
830
831 if (PVR_HAS_FEATURE(dev_info, gpu_multicore_support)) {
832 regs->isp_oclqry_stride = *stream_ptr;
833 stream_ptr++;
834 }
835
836 if (PVR_HAS_FEATURE(dev_info, zls_subtile)) {
837 regs->isp_zls_pixels = *stream_ptr;
838 stream_ptr += pvr_cmd_length(CR_ISP_ZLS_PIXELS);
839 }
840
841 cmd->zls_stride = *stream_ptr;
842 stream_ptr++;
843
844 cmd->sls_stride = *stream_ptr;
845 stream_ptr++;
846
847 if (PVR_HAS_FEATURE(dev_info, gpu_multicore_support)) {
848 cmd->execute_count = *stream_ptr;
849 stream_ptr++;
850 }
851
852 assert((const uint8_t *)stream_ptr - stream <= stream_len);
853 assert((const uint8_t *)stream_ptr - stream == main_stream_len);
854
855 return main_stream_len;
856 }
857
pvr_srv_fragment_cmd_ext_stream_load(struct rogue_fwif_cmd_3d * const cmd,const uint8_t * const stream,const uint32_t stream_len,const uint32_t ext_stream_offset,const struct pvr_device_info * const dev_info)858 static void pvr_srv_fragment_cmd_ext_stream_load(
859 struct rogue_fwif_cmd_3d *const cmd,
860 const uint8_t *const stream,
861 const uint32_t stream_len,
862 const uint32_t ext_stream_offset,
863 const struct pvr_device_info *const dev_info)
864 {
865 const uint32_t *ext_stream_ptr =
866 (const uint32_t *)((uint8_t *)stream + ext_stream_offset);
867 struct rogue_fwif_3d_regs *const regs = &cmd->regs;
868
869 struct ROGUE_KMD_STREAM_EXTHDR_FRAG0 header0;
870
871 header0 = pvr_csb_unpack(ext_stream_ptr, KMD_STREAM_EXTHDR_FRAG0);
872 ext_stream_ptr += pvr_cmd_length(KMD_STREAM_EXTHDR_FRAG0);
873
874 assert(PVR_HAS_QUIRK(dev_info, 49927) == header0.has_brn49927);
875 if (header0.has_brn49927) {
876 regs->tpu = *ext_stream_ptr;
877 ext_stream_ptr += pvr_cmd_length(CR_TPU);
878 }
879
880 assert((const uint8_t *)ext_stream_ptr - stream == stream_len);
881 }
882
883 static void
pvr_srv_fragment_cmd_init(struct rogue_fwif_cmd_3d * cmd,const struct pvr_winsys_fragment_state * state,const struct pvr_device_info * dev_info,uint32_t frame_num)884 pvr_srv_fragment_cmd_init(struct rogue_fwif_cmd_3d *cmd,
885 const struct pvr_winsys_fragment_state *state,
886 const struct pvr_device_info *dev_info,
887 uint32_t frame_num)
888 {
889 uint32_t ext_stream_offset;
890
891 memset(cmd, 0, sizeof(*cmd));
892
893 cmd->cmd_shared.cmn.frame_num = frame_num;
894
895 ext_stream_offset = pvr_srv_fragment_cmd_stream_load(cmd,
896 state->fw_stream,
897 state->fw_stream_len,
898 dev_info);
899
900 if (ext_stream_offset < state->fw_stream_len) {
901 pvr_srv_fragment_cmd_ext_stream_load(cmd,
902 state->fw_stream,
903 state->fw_stream_len,
904 ext_stream_offset,
905 dev_info);
906 }
907
908 if (state->flags.has_depth_buffer)
909 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_DEPTHBUFFER;
910
911 if (state->flags.has_stencil_buffer)
912 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_STENCILBUFFER;
913
914 if (state->flags.prevent_cdm_overlap)
915 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_PREVENT_CDM_OVERLAP;
916
917 if (state->flags.use_single_core)
918 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_SINGLE_CORE;
919
920 if (state->flags.get_vis_results)
921 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_GETVISRESULTS;
922
923 if (state->flags.has_spm_scratch_buffer)
924 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_SPMSCRATCHBUFFER;
925
926 if (state->flags.disable_pixel_merging)
927 cmd->flags |= ROGUE_FWIF_RENDERFLAGS_DISABLE_PIXELMERGE;
928 }
929
pvr_srv_winsys_render_submit(const struct pvr_winsys_render_ctx * ctx,const struct pvr_winsys_render_submit_info * submit_info,const struct pvr_device_info * dev_info,struct vk_sync * signal_sync_geom,struct vk_sync * signal_sync_frag)930 VkResult pvr_srv_winsys_render_submit(
931 const struct pvr_winsys_render_ctx *ctx,
932 const struct pvr_winsys_render_submit_info *submit_info,
933 const struct pvr_device_info *dev_info,
934 struct vk_sync *signal_sync_geom,
935 struct vk_sync *signal_sync_frag)
936 {
937 const struct pvr_srv_winsys_rt_dataset *srv_rt_dataset =
938 to_pvr_srv_winsys_rt_dataset(submit_info->rt_dataset);
939 struct pvr_srv_sync_prim *sync_prim =
940 srv_rt_dataset->rt_datas[submit_info->rt_data_idx].sync_prim;
941 void *rt_data_handle =
942 srv_rt_dataset->rt_datas[submit_info->rt_data_idx].handle;
943 const struct pvr_srv_winsys_render_ctx *srv_ctx =
944 to_pvr_srv_winsys_render_ctx(ctx);
945 const struct pvr_srv_winsys *srv_ws = to_pvr_srv_winsys(ctx->ws);
946
947 struct pvr_srv_sync *srv_signal_sync_geom;
948 struct pvr_srv_sync *srv_signal_sync_frag;
949
950 struct rogue_fwif_cmd_ta geom_cmd;
951 struct rogue_fwif_cmd_3d frag_cmd = { 0 };
952 struct rogue_fwif_cmd_3d pr_cmd = { 0 };
953
954 uint8_t *frag_cmd_ptr = NULL;
955 uint32_t frag_cmd_size = 0;
956
957 uint32_t current_sync_value = sync_prim->value;
958 uint32_t geom_sync_update_value;
959 uint32_t frag_to_geom_fence_count = 0;
960 uint32_t frag_to_geom_fence_value;
961 uint32_t frag_sync_update_count = 0;
962 uint32_t frag_sync_update_value;
963
964 int in_frag_fd = -1;
965 int in_geom_fd = -1;
966 int fence_frag;
967 int fence_geom;
968
969 VkResult result;
970
971 pvr_srv_geometry_cmd_init(submit_info, sync_prim, &geom_cmd, dev_info);
972
973 pvr_srv_fragment_cmd_init(&pr_cmd,
974 &submit_info->fragment_pr,
975 dev_info,
976 submit_info->frame_num);
977
978 if (submit_info->has_fragment_job) {
979 pvr_srv_fragment_cmd_init(&frag_cmd,
980 &submit_info->fragment,
981 dev_info,
982 submit_info->frame_num);
983
984 frag_cmd_ptr = (uint8_t *)&frag_cmd;
985 frag_cmd_size = sizeof(frag_cmd);
986 }
987
988 if (submit_info->geometry.wait) {
989 struct pvr_srv_sync *srv_wait_sync =
990 to_srv_sync(submit_info->geometry.wait);
991
992 if (srv_wait_sync->fd >= 0) {
993 in_geom_fd = dup(srv_wait_sync->fd);
994 if (in_geom_fd == -1) {
995 return vk_errorf(NULL,
996 VK_ERROR_OUT_OF_HOST_MEMORY,
997 "dup called on wait sync failed, Errno: %s",
998 strerror(errno));
999 }
1000 }
1001 }
1002
1003 if (submit_info->fragment.wait) {
1004 struct pvr_srv_sync *srv_wait_sync =
1005 to_srv_sync(submit_info->fragment.wait);
1006
1007 if (srv_wait_sync->fd >= 0) {
1008 in_frag_fd = dup(srv_wait_sync->fd);
1009 if (in_frag_fd == -1) {
1010 return vk_errorf(NULL,
1011 VK_ERROR_OUT_OF_HOST_MEMORY,
1012 "dup called on wait sync failed, Errno: %s",
1013 strerror(errno));
1014 }
1015 }
1016 }
1017
1018 if (submit_info->geometry.flags.is_first_geometry) {
1019 frag_to_geom_fence_count = 1;
1020 frag_to_geom_fence_value = current_sync_value;
1021 }
1022
1023 /* Geometery is always kicked */
1024 geom_sync_update_value = ++current_sync_value;
1025
1026 if (submit_info->has_fragment_job) {
1027 frag_sync_update_count = 1;
1028 frag_sync_update_value = ++current_sync_value;
1029 }
1030
1031 do {
1032 /* The fw allows the ZS and MSAA scratch buffers to be lazily allocated in
1033 * which case we need to provide a status update (i.e. if they are
1034 * physically backed or not) to the fw. In our case they will always be
1035 * physically backed so no need to inform the fw about their status and
1036 * pass in anything. We'll just pass in NULL.
1037 */
1038 result = pvr_srv_rgx_kick_render2(srv_ws->base.render_fd,
1039 srv_ctx->handle,
1040 frag_to_geom_fence_count,
1041 &sync_prim->ctx->block_handle,
1042 &sync_prim->offset,
1043 &frag_to_geom_fence_value,
1044 1,
1045 &sync_prim->ctx->block_handle,
1046 &sync_prim->offset,
1047 &geom_sync_update_value,
1048 frag_sync_update_count,
1049 &sync_prim->ctx->block_handle,
1050 &sync_prim->offset,
1051 &frag_sync_update_value,
1052 sync_prim->ctx->block_handle,
1053 sync_prim->offset,
1054 geom_sync_update_value,
1055 in_geom_fd,
1056 srv_ctx->timeline_geom,
1057 &fence_geom,
1058 "GEOM",
1059 in_frag_fd,
1060 srv_ctx->timeline_frag,
1061 &fence_frag,
1062 "FRAG",
1063 sizeof(geom_cmd),
1064 (uint8_t *)&geom_cmd,
1065 sizeof(pr_cmd),
1066 (uint8_t *)&pr_cmd,
1067 frag_cmd_size,
1068 frag_cmd_ptr,
1069 submit_info->job_num,
1070 /* Always kick the TA. */
1071 true,
1072 /* Always kick a PR. */
1073 true,
1074 submit_info->has_fragment_job,
1075 false,
1076 0,
1077 rt_data_handle,
1078 NULL,
1079 NULL,
1080 0,
1081 NULL,
1082 NULL,
1083 0,
1084 0,
1085 0,
1086 0,
1087 0);
1088 } while (result == VK_NOT_READY);
1089
1090 if (result != VK_SUCCESS)
1091 goto end_close_in_fds;
1092
1093 /* The job submission was succesful, update the sync prim value. */
1094 sync_prim->value = current_sync_value;
1095
1096 if (signal_sync_geom) {
1097 srv_signal_sync_geom = to_srv_sync(signal_sync_geom);
1098 pvr_srv_set_sync_payload(srv_signal_sync_geom, fence_geom);
1099 } else if (fence_geom != -1) {
1100 close(fence_geom);
1101 }
1102
1103 if (signal_sync_frag) {
1104 srv_signal_sync_frag = to_srv_sync(signal_sync_frag);
1105 pvr_srv_set_sync_payload(srv_signal_sync_frag, fence_frag);
1106 } else if (fence_frag != -1) {
1107 close(fence_frag);
1108 }
1109
1110 end_close_in_fds:
1111 if (in_geom_fd >= 0)
1112 close(in_geom_fd);
1113
1114 if (in_frag_fd >= 0)
1115 close(in_frag_fd);
1116
1117 return result;
1118 }
1119