npv:pts debug tracing, ffmpeg dev tantrum
[nyanmp.git] / npv / video / local / code.frag.c
blobd6f7e54ab5a53716e2c66ea80b2a37da39d183d9
1 STATIC void fatal(u8 *fmt, ...)
3 va_list ap;
5 npv_perr("video:");
6 va_start(ap, fmt);
7 npv_vfatal(fmt, ap);
8 va_end(ap); /* unreachable */
10 STATIC void warning(u8 *fmt, ...)
12 va_list ap;
14 npv_perr("video:");
15 va_start(ap, fmt);
16 npv_vwarning(fmt, ap);
17 va_end(ap);
19 STATIC void fatalff(u8 *fmt, ...)
21 va_list ap;
23 npv_perr("ffmpeg:");
24 va_start(ap, fmt);
25 npv_vfatal(fmt, ap);
26 va_end(ap); /* unreachable */
28 STATIC void poutff(u8 *fmt, ...)
30 va_list ap;
32 npv_pout("ffmpeg:");
33 va_start(ap, fmt);
34 npv_vpout(fmt, ap);
35 va_end(ap);
37 STATIC void fatalvk(u8 *fmt, ...)
39 va_list ap;
41 npv_perr("video:");
42 va_start(ap, fmt);
43 npv_vk_vfatal(fmt, ap);
44 va_end(ap); /* unreachable */
46 STATIC void warningvk(u8 *fmt, ...)
48 va_list ap;
50 npv_perr("video:");
51 va_start(ap, fmt);
52 npv_vk_vwarning(fmt, ap);
53 va_end(ap);
55 #define NONE 0
56 STATIC void init_once_local(void)
58 u8 i;
60 dec_l = 0;
61 memset(&tmp_mem_rqmts_l, 0, sizeof(tmp_mem_rqmts_l));
62 i = 0;
63 loop {
64 if (i == npv_vk_swpchn_imgs_n_max)
65 break;
66 blit_l[i].vp.width = -1;
67 blit_l[i].vp.height = -1;
68 blit_l[i].vp.top_left.x = -1;
69 blit_l[i].vp.top_left.y = -1;
70 blit_l[i].vp.top_left.z = -1;
71 blit_l[i].vp.bottom_right.x = -1;
72 blit_l[i].vp.bottom_right.y = -1;
73 blit_l[i].vp.bottom_right.z = -1;
74 blit_l[i].update_requested = true;
75 ++i;
77 receive_fr_l = avutil_video_fr_ref_alloc();
78 is_swpchn_sem_fence_submitted_l = false;
79 drop_l.prev_now = AV_NOPTS_VALUE;
80 drop_l.until_resync = false;
82 #undef NONE
83 STATIC void scaler_img_create(avutil_video_fr_ref_t *fr)
85 struct vk_img_create_info_t info;
86 s32 r;
88 memset(&info, 0, sizeof(info));
89 info.type = vk_struct_type_img_create_info;
90 info.img_type = vk_img_type_2d;
91 info.texel_mem_blk_fmt = vk_texel_mem_blk_fmt_b8g8r8a8_srgb;
92 info.extent.width = (u32)fr->width;
93 info.extent.height = (u32)fr->height;
94 info.extent.depth = 1;
95 info.mip_lvls_n = 1;
96 info.samples_n = vk_samples_n_1_bit;
97 info.array_layers_n = 1;
98 info.img_tiling = vk_img_tiling_linear;
99 info.usage = vk_img_usage_transfer_src_bit;
100 info.initial_layout = vk_img_layout_undefined;
101 vk_create_img(&info, &scaler_p.img.vk);
102 IF_FATALVVK("%d:device:%p:unable to create scaler frame image\n", r, npv_vk_surf_p.dev.vk);
104 STATIC void img_mem_barrier_run_once(struct vk_img_mem_barrier_t *b)
106 s32 r;
107 struct vk_cb_begin_info_t begin_info;
108 struct vk_submit_info_t submit_info;
110 memset(&begin_info, 0, sizeof(begin_info));
111 begin_info.type = vk_struct_type_cb_begin_info;
112 begin_info.flags = vk_cb_usage_one_time_submit_bit;
113 /* we use the first cb which will be used for the swpchn */
114 vk_begin_cb(npv_vk_surf_p.dev.cbs[0], &begin_info);
115 IF_FATALVVK("%d:unable to begin recording the initial layout transition command buffer\n", r, npv_vk_surf_p.dev.cbs[0]);
116 /*--------------------------------------------------------------------*/
117 vk_cmd_pl_barrier(npv_vk_surf_p.dev.cbs[0], b);
118 /*--------------------------------------------------------------------*/
119 vk_end_cb(npv_vk_surf_p.dev.cbs[0]);
120 IF_FATALVVK("%d:unable to end recording of the initial layout transition command buffer\n", r, npv_vk_surf_p.dev.cbs[0]);
121 /*--------------------------------------------------------------------*/
122 memset(&submit_info, 0, sizeof(submit_info));
123 submit_info.type = vk_struct_type_submit_info;
124 submit_info.cbs_n = 1;
125 submit_info.cbs = &npv_vk_surf_p.dev.cbs[0];
126 vk_q_submit(&submit_info, 0);
127 IF_FATALVVK("%d:queue:%p:unable to submit the initial layout transition command buffer\n", r, npv_vk_surf_p.dev.q);
128 /*--------------------------------------------------------------------*/
129 vk_q_wait_idle();
130 IF_FATALVVK("%d:queue:%p:unable to wait for idle or completion of initial layout transition command buffer\n", r, npv_vk_surf_p.dev.q);
131 /*--------------------------------------------------------------------*/
133 * since it is tagged to run once its state_p is invalid, we need to
134 * reset it to the initial state_p
136 vk_reset_cb(npv_vk_surf_p.dev.cbs[0]);
137 IF_FATALVVK("%d:command buffer:%p:unable to reset the initial layout transition command buffer\n", r, npv_vk_surf_p.dev.cbs[0]);
139 /* once in general layout, the dev sees the img */
140 STATIC void scaler_img_layout_to_general(void)
142 struct vk_img_mem_barrier_t b;
143 struct vk_img_subrsrc_range_t *r;
145 memset(&b, 0, sizeof(b));
146 b.type = vk_struct_type_img_mem_barrier;
147 b.old_layout = vk_img_layout_undefined;
148 b.new_layout = vk_img_layout_general;
149 b.src_q_fam = vk_q_fam_ignored;
150 b.dst_q_fam = vk_q_fam_ignored;
151 b.img = scaler_p.img.vk;
152 r = &b.subrsrc_range;
153 r->aspect = vk_img_aspect_color_bit;
154 r->lvls_n = 1;
155 r->array_layers_n = 1;
156 img_mem_barrier_run_once(&b);
158 STATIC void scaler_img_subrsrc_layout_get(void)
160 struct vk_img_subrsrc_t s;
162 memset(&s, 0, sizeof(s));
163 /* 1 subrsrc = uniq color plane of mip lvl 0 and array 0 */
164 s.aspect = vk_img_aspect_color_bit;
165 vk_get_img_subrsrc_layout(scaler_p.img.vk, &s, &scaler_p.img.layout);
167 STATIC void tmp_scaler_img_mem_rqmts_get(void)
169 struct vk_img_mem_rqmts_info_t info;
170 struct vk_mem_rqmts_t *rqmts;
171 s32 r;
173 memset(&info, 0, sizeof(info));
174 info.type = vk_struct_type_img_mem_rqmts_info;
175 info.img = scaler_p.img.vk;
176 rqmts = &tmp_mem_rqmts_l;
177 memset(rqmts, 0, sizeof(*rqmts));
178 rqmts->type = vk_struct_type_mem_rqmts;
179 vk_get_img_mem_rqmts(&info, rqmts);
180 IF_FATALVVK("%d:device:%p:unable to get memory requirements for scaler image\n", r, npv_vk_surf_p.dev.vk);
182 #define WANTED_MEM_PROPS (vk_mem_prop_host_visible_bit \
183 | vk_mem_prop_host_cached_bit)
184 #define IS_DEV_LOCAL(x) (((x)->prop_flags & vk_mem_prop_dev_local_bit) != 0)
185 STATIC bool match_mem_type(u8 mem_type_idx,
186 struct vk_mem_rqmts_t *img_rqmts, bool ignore_gpu_is_discret)
188 struct vk_mem_type_t *mem_type;
190 /* first check this mem type is in our img rqmts */
191 if (((1 << mem_type_idx) & img_rqmts->core.mem_type_bits) == 0)
192 return false;
193 mem_type = &npv_vk_surf_p.dev.phydev.mem_types[mem_type_idx];
194 if (!ignore_gpu_is_discret)
195 if (npv_vk_surf_p.dev.phydev.is_discret_gpu
196 && IS_DEV_LOCAL(mem_type))
197 return false;
198 if ((mem_type->prop_flags & WANTED_MEM_PROPS) == WANTED_MEM_PROPS)
199 return true;
200 return false;
202 #undef WANTED_MEM_PROPS
203 #undef IS_DEV_LOCAL
204 STATIC bool try_alloc_scaler_img_dev_mem(struct vk_mem_rqmts_t *img_rqmts,
205 u8 mem_type_idx)
207 struct vk_mem_alloc_info_t info;
208 s32 r;
210 memset(&info, 0, sizeof(info));
211 info.type = vk_struct_type_mem_alloc_info;
212 info.sz = img_rqmts->core.sz;
213 info.mem_type_idx = mem_type_idx;
214 vk_alloc_mem(&info, &scaler_p.img.dev_mem);
215 if (r < 0) {
216 warningvk("%d:device:%p:unable to allocate %lu bytes from physical dev %p memory type %u\n", r, npv_vk_surf_p.dev.vk, img_rqmts->core.sz, npv_vk_surf_p.dev.phydev.vk, mem_type_idx);
217 return false;
219 return true;
222 * we are looking for host visible and host cached mem. on discret gpu we would
223 * like non dev local mem that in order to avoid wasting video ram. if we have
224 * a discret gpu but could not find a mem type without dev local mem, let's
225 * retry with only host visible and host cached mem.
227 #define IGNORE_GPU_IS_DISCRET true
228 STATIC void scaler_img_dev_mem_alloc(void)
230 struct vk_mem_rqmts_t *img_rqmts;
231 u8 mem_type;
233 img_rqmts = &tmp_mem_rqmts_l;
234 mem_type = 0;
235 loop {
236 if (mem_type == npv_vk_surf_p.dev.phydev.mem_types_n)
237 break;
238 if (match_mem_type(mem_type, img_rqmts, !IGNORE_GPU_IS_DISCRET))
239 if (try_alloc_scaler_img_dev_mem(img_rqmts, mem_type))
240 return;
241 ++mem_type;
243 if (!npv_vk_surf_p.dev.phydev.is_discret_gpu)
244 fatalvk("physical device:%p:scaler image:unable to find proper memory type or to allocate memory\n", npv_vk_surf_p.dev.phydev.vk);
246 * lookup again, but relax the match based on discret gpu constraint for
247 * gpu
249 mem_type = 0;
250 loop {
251 if (mem_type == npv_vk_surf_p.dev.phydev.mem_types_n)
252 break;
253 if (match_mem_type(mem_type, img_rqmts, IGNORE_GPU_IS_DISCRET)
254 && try_alloc_scaler_img_dev_mem(img_rqmts, mem_type))
255 return;
256 ++mem_type;
258 fatalvk("physical device:%p:unable to find proper memory type or to allocate memory\n", npv_vk_surf_p.dev.phydev.vk);
260 #undef IGNORE_GPU_IS_DISCRET
261 STATIC void scaler_img_dev_mem_bind(void)
263 struct vk_bind_img_mem_info_t info;
264 s32 r;
266 memset(&info, 0, sizeof(info) * 1);
267 info.type = vk_struct_type_bind_img_mem_info;
268 info.img = scaler_p.img.vk;
269 info.mem = scaler_p.img.dev_mem;
271 * TODO: switch to vkBindImageMemory2 if extension in vk 1.1 for
272 * consistency
274 vk_bind_img_mem(&info);
275 IF_FATALVVK("%d:device:%p:scaler image:unable to bind device memory to image\n", r, npv_vk_surf_p.dev.vk);
277 STATIC void scaler_img_dev_mem_map(void)
279 s32 r;
281 vk_map_mem(scaler_p.img.dev_mem, &scaler_p.img.data);
282 IF_FATALVVK("%d:device:%p:scaler image:unable to map image memory\n", r, npv_vk_surf_p.dev.vk);
284 STATIC void dec_a_grow(void)
286 u16 new_idx;
288 new_idx = dec_frs_p.n_max;
289 dec_frs_p.a = realloc(dec_frs_p.a, sizeof(*dec_frs_p.a)
290 * (dec_frs_p.n_max + 1));
291 if (dec_frs_p.a == 0)
292 fatal("unable to allocate memory for an additional pointer on a decoded frame reference\n");
293 dec_frs_p.priv_a = realloc(dec_frs_p.priv_a,
294 sizeof(*dec_frs_p.priv_a) * (dec_frs_p.n_max + 1));
295 if (dec_frs_p.priv_a == 0)
296 fatal("unable to allocate memory for an additional pointer on private data for decoded frames\n");
298 dec_frs_p.a[new_idx] = avutil_video_fr_ref_alloc();
299 if (dec_frs_p.a[new_idx] == 0)
300 fatal("ffmpeg:unable to allocate a decoded frame reference\n");
301 dec_frs_p.priv_a[new_idx] = calloc(1, sizeof(**dec_frs_p.priv_a));
302 if (dec_frs_p.priv_a[new_idx] == 0)
303 fatal("unable to allocate decoded frame private data\n");
305 ++dec_frs_p.n_max;
307 #define NO_FR 0
308 /* extract a fr ref, shift the a, push it back at the e, and unref its bufs */
309 STATIC void fr_drop(u16 fr)
311 struct dec_fr_priv_t *priv_save;
312 avutil_video_fr_ref_t *save;
314 priv_save = dec_frs_p.priv_a[fr];
315 if (!priv_save->was_qed_to_pe)
316 warning("dropping undisplayed frame\n");
317 save = dec_frs_p.a[fr];
318 avutil_video_fr_unref(save);
319 memset(priv_save, 0, sizeof(*priv_save));
320 if (dec_frs_p.n > 1) {
321 u16 e;
323 e = dec_frs_p.n;
324 memmove(&dec_frs_p.a[fr], &dec_frs_p.a[fr + 1],
325 sizeof(*dec_frs_p.a) * (e - (fr + 1)));
326 dec_frs_p.a[e - 1] = save;
328 memmove(&dec_frs_p.priv_a[fr], &dec_frs_p.priv_a[fr + 1],
329 sizeof(*dec_frs_p.priv_a) * (e - (fr + 1)));
330 dec_frs_p.priv_a[e - 1] = priv_save;
332 dec_frs_p.n--;
334 #undef NO_FR
335 #define NO_FR 0
336 STATIC void frs_drop(s64 now, avutil_video_fr_ref_t *selected_fr)
338 u16 fr;
339 s64 lo;
340 s64 hi;
341 s64 resync;
343 if (selected_fr == NO_FR)
344 goto exit;
345 /* backward discont detected */
346 if (drop_l.prev_now != AV_NOPTS_VALUE && now < drop_l.prev_now)
347 drop_l.until_resync = true;
348 /*====================================================================*/
350 * since the frs are supposed inorder, first drop as many of as possible
351 * frs received before the selected one
353 fr = 0;
354 loop {
355 if (dec_frs_p.a[fr] == selected_fr)
356 break;
357 /* don't touch the scaler fr */
358 if (dec_frs_p.a[fr] != scaler_p.img.fr) {
359 if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l)
360 last_fr_sent_to_pe_l = NO_FR;
361 fr_drop(fr); /* do not advance */
362 } else
363 ++fr;
365 /*====================================================================*/
367 * here, we detected a backward discont, we are looking for a
368 * resynchronizing fr based on a time win. we must drop, inorder,
369 * frs which are out of the time win in order to avoid the dec frs a
370 * being full and locked
372 if (!drop_l.until_resync)
373 goto exit;
374 resync = (DISCONT_BACKWARD_RESYNC_MS * st_p.tb.den) / (st_p.tb.num
375 * 1000);
376 lo = now - resync;
377 hi = now + resync;
378 fr = 0;
379 loop {
380 if (fr == dec_frs_p.n)
381 break;
382 /* don't touch the scaler fr or selected fr */
383 if (dec_frs_p.a[fr] != scaler_p.img.fr
384 && dec_frs_p.a[fr] != selected_fr) {
385 if (dec_frs_p.a[fr]->pts < lo
386 || hi < dec_frs_p.a[fr]->pts) {
387 if (dec_frs_p.a[fr] == last_fr_sent_to_pe_l)
388 last_fr_sent_to_pe_l = NO_FR;
389 fr_drop(fr); /* do not advance */
390 } else { /* found a resynchronizing fr */
391 drop_l.until_resync = false;
392 break;
394 } else
395 ++fr;
397 exit:
398 drop_l.prev_now = now;
401 #undef NO_FR
402 #define NO_FR 0
403 STATIC void select_fr(s64 now, avutil_video_fr_ref_t **selected_fr,
404 struct dec_fr_priv_t **selected_fr_priv)
406 u16 fr_idx;
407 u16 selected_fr_idx;
408 u64 selected_fr_delta;
410 fr_idx = 0;
411 *selected_fr = NO_FR;
412 selected_fr_delta = S64_MAX;
413 #ifdef NPV_DEBUG
414 if (npv_debug_p)
415 npv_perr("DEBUG:%s:scanning %u(max=%u) frames, now=%ld\n", __func__, dec_frs_p.n, dec_frs_p.n_max, now);
416 #endif
417 loop {
418 u64 delta;
420 if (fr_idx == dec_frs_p.n)
421 break;
422 delta = s64_abs(now - (s64)dec_frs_p.a[fr_idx]->pts);
423 #ifdef NPV_DEBUG
424 if (npv_debug_p)
425 npv_perr("DEBUG:%s:frame %u pts=%ld delta=%lu/%lu ms\n", __func__, fr_idx, (s64)dec_frs_p.a[fr_idx]->pts, delta, (delta * (u64)st_p.tb.num * 1000) / (u64)st_p.tb.den);
426 #endif
427 if (delta < selected_fr_delta) {
428 *selected_fr = dec_frs_p.a[fr_idx];
429 *selected_fr_priv = dec_frs_p.priv_a[fr_idx];
430 selected_fr_idx = fr_idx;
431 selected_fr_delta = delta;
433 ++fr_idx;
436 #undef NO_FR
437 STATIC void frs_reset(void)
439 u16 fr;
441 fr = 0;
442 loop {
443 if (fr == dec_frs_p.n)
444 break;
445 avutil_video_fr_unref(dec_frs_p.a[fr]);
446 memset(dec_frs_p.priv_a[fr], 0, sizeof(**dec_frs_p.priv_a));
447 ++fr;
449 dec_frs_p.n = 0;
451 STATIC void scaler_img_destroy(void)
453 vk_destroy_img(scaler_p.img.vk);
454 scaler_p.img.vk = 0;
455 vk_unmap_mem(scaler_p.img.dev_mem);
456 scaler_p.img.data = 0;
457 vk_free_mem(scaler_p.img.dev_mem);
458 scaler_p.img.dev_mem = 0;
460 STATIC void blit_compute_offsets(u8 swpchn_img,
461 struct vk_extent_2d_t *new_vp)
463 struct blit_vp_t *vp;
464 s32 want_width;
465 s32 want_height;
467 vp = &blit_l[swpchn_img].vp;
469 * XXX: THE BOUNDS OF THE BLIT ARE NOT PIXEL OFFSETS! THOSE ARE
470 * INTEGER BOUNDS FOR TEXELS COORDS WHICH ARE TAKEN AT THE CENTER OF
471 * EACH PIXEL: NAMELY LAST TEXEL INTEGER BOUND = LAST PIXEL OFFSET + 1.
473 want_width = new_vp->height * aspect_ratio.width / aspect_ratio.height;
474 want_height = new_vp->width * aspect_ratio.height / aspect_ratio.width;
475 if (want_width < new_vp->width) {
476 s32 gap;
478 vp->top_left.y = 0;
479 vp->bottom_right.y = new_vp->height;
481 gap = new_vp->width - want_width;
482 vp->top_left.x = gap / 2;
483 vp->bottom_right.x = new_vp->width - gap / 2;
484 } else if (want_height < new_vp->height) {
485 s32 gap;
487 vp->top_left.x = 0;
488 vp->bottom_right.x = new_vp->width;
490 gap = new_vp->height - want_height;
491 vp->top_left.y = gap / 2;
492 vp->bottom_right.y = new_vp->height - gap / 2;
493 } else {
494 vp->top_left.x = 0;
495 vp->top_left.y = 0;
496 vp->bottom_right.x = new_vp->width;
497 vp->bottom_right.y = new_vp->height;
499 /* keep track in order to detect change */
500 vp->width = new_vp->width;
501 vp->height = new_vp->height;
503 STATIC void blit_setup(u8 swpchn_img)
505 s32 r;
506 struct vk_cb_begin_info_t begin_info;
507 struct vk_img_mem_barrier_t b;
508 struct vk_img_blit_t region;
509 struct vk_extent_2d_t *current;
510 union vk_clr_color_val_t clr_color_val;
511 struct vk_img_subrsrc_range_t range;
512 struct npv_vk_texel_mem_blk_fmt_t *b8g8r8a8_srgb;
513 u32 filt;
515 current = &npv_vk_surf_p.dev.phydev.surf_caps.core.current_extent;
517 if (!blit_l[swpchn_img].update_requested
518 && blit_l[swpchn_img].vp.width == current->width
519 && blit_l[swpchn_img].vp.height == current->height)
520 return;
522 blit_compute_offsets(swpchn_img, current);
524 /* sync: may be in pending state? */
525 vk_reset_cb(npv_vk_surf_p.dev.cbs[swpchn_img]);
526 IF_FATALVVK("%d:swapchain img:%u:command buffer:%p:unable reset\n", r, swpchn_img, npv_vk_surf_p.dev.cbs[swpchn_img]);
527 /*--------------------------------------------------------------------*/
528 memset(&begin_info, 0, sizeof(begin_info));
529 begin_info.type = vk_struct_type_cb_begin_info;
530 vk_begin_cb(npv_vk_surf_p.dev.cbs[swpchn_img], &begin_info);
531 IF_FATALVVK("%d:swapchain img:%u:command buffer:%p:unable to begin recording\n", r, swpchn_img, npv_vk_surf_p.dev.cbs[swpchn_img]);
532 /*--------------------------------------------------------------------*/
533 /* acquired img (undefined layout) to presentation layout */
534 memset(&b, 0, sizeof(b));
535 b.type = vk_struct_type_img_mem_barrier;
536 b.old_layout = vk_img_layout_undefined;
537 b.new_layout = vk_img_layout_present;
538 b.src_q_fam = vk_q_fam_ignored;
539 b.dst_q_fam = vk_q_fam_ignored;
540 b.img = npv_vk_surf_p.dev.swpchn.imgs[swpchn_img];
541 b.subrsrc_range.aspect = vk_img_aspect_color_bit;
542 b.subrsrc_range.lvls_n = 1;
543 b.subrsrc_range.array_layers_n = 1;
544 vk_cmd_pl_barrier(npv_vk_surf_p.dev.cbs[swpchn_img], &b);
545 /*--------------------------------------------------------------------*/
546 /* clear the viewport with integer black pixels since we work in sRGB */
547 memset(&clr_color_val, 0, sizeof(clr_color_val));
548 memset(&range, 0, sizeof(range));
549 range.aspect = vk_img_aspect_color_bit;
550 range.lvls_n = 1;
551 range.array_layers_n = 1;
552 vk_cmd_clr_color_img(npv_vk_surf_p.dev.cbs[swpchn_img],
553 npv_vk_surf_p.dev.swpchn.imgs[swpchn_img],
554 vk_img_layout_present, &clr_color_val, 1,
555 &range);
556 /*--------------------------------------------------------------------*/
557 /* blit from cpu img to pe img */
558 memset(&region, 0, sizeof(region));
559 region.src_subrsrc.aspect = vk_img_aspect_color_bit;
560 region.src_subrsrc.array_layers_n = 1;
561 /* scaler */
562 region.src_offsets[1].x = scaler_p.ctx->cfg.width;
563 region.src_offsets[1].y = scaler_p.ctx->cfg.height;
564 region.src_offsets[1].z = 1; /* see vk specs */
565 region.dst_subrsrc.aspect = vk_img_aspect_color_bit;
566 region.dst_subrsrc.array_layers_n = 1;
567 /* xcb viewport */
568 memcpy(&region.dst_offsets[0], &blit_l[swpchn_img].vp.top_left,
569 sizeof(region.dst_offsets[0]));
570 region.dst_offsets[0].z = 0; /* see vk specs */
571 memcpy(&region.dst_offsets[1], &blit_l[swpchn_img].vp.bottom_right,
572 sizeof(region.dst_offsets[1]));
573 region.dst_offsets[1].z = 1; /* see vk specs */
574 /* linear filtering */
575 b8g8r8a8_srgb = &npv_vk_surf_p.dev.phydev.b8g8r8a8_srgb;
576 if (b8g8r8a8_srgb->linear_tiling_has_linear_filt)
577 filt = vk_filt_linear;
578 else
579 filt = vk_filt_nearest;
580 vk_cmd_blit_img(npv_vk_surf_p.dev.cbs[swpchn_img], scaler_p.img.vk,
581 npv_vk_surf_p.dev.swpchn.imgs[swpchn_img], &region, filt);
582 /*--------------------------------------------------------------------*/
583 vk_end_cb(npv_vk_surf_p.dev.cbs[swpchn_img]);
584 IF_FATALVVK("%d:swapchain img:%u:command buffer:%p:unable to end recording\n", r, swpchn_img, npv_vk_surf_p.dev.cbs[swpchn_img]);
585 blit_l[swpchn_img].update_requested = false;
587 STATIC void blits_request_update(void)
589 u8 i;
591 i = 0;
592 loop {
593 if (i == npv_vk_surf_p.dev.swpchn.imgs_n)
594 break;
595 blit_l[i].update_requested = true;
596 ++i;
599 STATIC bool is_swpchn_sem_consistent(void)
601 s32 r;
603 /* nothing submitted then nothing to check */
604 if (!is_swpchn_sem_fence_submitted_l)
605 return true;
606 /* coarse synchronization (we could use a pool of semaphores/fences) */
607 vk_get_fence_status();
608 if (r == vk_not_ready)
609 return false;
610 else if (r != vk_success)
611 npv_vk_fatal("%d:device:%p:unable to get fence %p status\n", r, npv_vk_surf_p.dev.vk, npv_vk_surf_p.dev.fence);
612 /* vk_success */
613 vk_reset_fences();
614 IF_FATALVVK("%d:device:%p:unable to reset the fence\n", r, npv_vk_surf_p.dev.vk, npv_vk_surf_p.dev.fence);
615 is_swpchn_sem_fence_submitted_l = false;
616 return true;
618 #define READY 0
619 #define NOT_READY 1
620 STATIC u8 swpchn_next_img(u32 *swpchn_img) { loop
622 struct vk_acquire_next_img_info_t info;
623 s32 r;
625 memset(&info, 0, sizeof(info));
626 info.type = vk_struct_type_acquire_next_img_info;
627 info.swpchn = npv_vk_surf_p.dev.swpchn.vk;
628 info.timeout = 0;
629 info.devs = 0x00000001; /* no device group then 1 */
630 info.sem = npv_vk_surf_p.dev.sems[npv_vk_sem_acquire_img_done];
632 * XXX: for this vk func, the wait sem _MUST_ be unsignaled _AND_ have
633 * all its "wait" operations completed. state we secure with our usage
634 * of a fence.
636 vk_acquire_next_img(&info, swpchn_img);
638 * XXX: MESA BUG:
639 * should _NOT_ return vk_timeout for timeout == 0
641 * src/vulkan/wsi/wsi_common_x11.c:x11_acquire_next_image_from_queue
642 * this func does not return vk_not_ready on timeout == 0
644 if (r == vk_not_ready || r == vk_timeout)
645 return NOT_READY;
646 else if (r == vk_out_of_date || r == vk_suboptimal) {
647 vk_q_wait_idle(); /* very violent, hopefully not too long */
648 IF_FATALVVK("%d:queue:%p:unable to wait for idle or completion to prepare for a swpchn update\n", r, npv_vk_surf_p.dev.q);
649 npv_vk_swpchn_update();
650 blits_request_update();
651 continue;
652 } else if (r >= 0)
653 return READY;
654 npv_vk_fatal("%d:device:%p:unable to acquire next image from swapchain %p\n", r, npv_vk_surf_p.dev.vk, npv_vk_surf_p.dev.swpchn.vk);
656 #undef READY
657 #undef NOT_READY
658 #define SENT 0
659 #define SWPCHN_UPDATED 1
660 STATIC u8 send_to_pe(u32 swpchn_img)
662 struct vk_submit_info_t submit_info;
663 struct vk_present_info_t present_info;
664 u32 wait_dst_stage;
665 s32 r;
666 u32 idxs[1];
667 /* run the command buffer and do present queue */
668 /*--------------------------------------------------------------------*/
669 memset(&submit_info, 0, sizeof(submit_info));
670 submit_info.type = vk_struct_type_submit_info;
671 submit_info.wait_sems_n = 1;
673 * the "semaphore wait operation" will unsignal this semaphore once the
674 * "wait" is done.
676 submit_info.wait_sems =
677 &npv_vk_surf_p.dev.sems[npv_vk_sem_acquire_img_done];
678 wait_dst_stage = vk_pl_stage_bottom_of_pipe_bit;
679 submit_info.wait_dst_stages = &wait_dst_stage;
680 submit_info.cbs_n = 1;
681 submit_info.cbs = &npv_vk_surf_p.dev.cbs[swpchn_img];
682 submit_info.signal_sems_n = 1;
683 submit_info.signal_sems = &npv_vk_surf_p.dev.sems[npv_vk_sem_blit_done];
684 /* XXX: coarse synchronization happens here */
685 vk_q_submit(&submit_info, npv_vk_surf_p.dev.fence);
686 IF_FATALVVK("%d:queue:%p:unable to submit the image pre-recorded command buffer\n", r, npv_vk_surf_p.dev.q);
687 is_swpchn_sem_fence_submitted_l = true;
688 /*--------------------------------------------------------------------*/
689 idxs[0] = swpchn_img;
690 memset(&present_info, 0, sizeof(present_info));
691 present_info.type = vk_struct_type_present_info;
693 * the "semaphore wait operation" will unsignal this semaphore once the
694 * "wait" is done.
696 present_info.wait_sems_n = 1;
697 present_info.wait_sems = &npv_vk_surf_p.dev.sems[npv_vk_sem_blit_done];
698 present_info.swpchns_n = 1;
699 present_info.swpchns = &npv_vk_surf_p.dev.swpchn.vk;
700 present_info.idxs = idxs;
701 present_info.results = 0;
702 vk_q_present(&present_info);
703 if (r == vk_out_of_date || r == vk_suboptimal) {
704 vk_q_wait_idle(); /* very violent, hopefully not too long */
705 IF_FATALVVK("%d:queue:%p:unable to wait for idle or completion to prepare for a swpchn update\n", r, npv_vk_surf_p.dev.q);
706 npv_vk_swpchn_update();
707 blits_request_update();
708 return SWPCHN_UPDATED;
710 IF_FATALVVK("%d:queue:%p:unable to submit the image %u to the presentation engine\n", r, npv_vk_surf_p.dev.q, swpchn_img);
711 return SENT;
713 #undef SENT
714 #undef SWPCHN_UPDATED
715 STATIC void start_scaling(avutil_video_fr_ref_t *fr,
716 struct dec_fr_priv_t *fr_priv)
719 if (scaler_p.ctx->cfg.width != fr->width
720 || scaler_p.ctx->cfg.height != fr->height) {
721 u8 i;
723 if (scaler_p.img.vk != 0)
724 scaler_img_destroy();
725 scaler_img_create(fr);
726 scaler_img_layout_to_general();
727 scaler_img_subrsrc_layout_get();
728 tmp_scaler_img_mem_rqmts_get();
729 scaler_img_dev_mem_alloc();
730 scaler_img_dev_mem_bind();
731 scaler_img_dev_mem_map();
733 blits_request_update();
734 scaler_p.ctx->cfg.width = fr->width;
735 scaler_p.ctx->cfg.height = fr->height;
736 npv_video_osd_update_dimensions(scaler_p.img.data,
737 (u16)fr->width, (u16)fr->height,
738 (u32)scaler_p.img.layout.row_pitch);
740 scaler_p.ctx->cfg.src_fmt = fr->fmt;
741 scaler_p.ctx->cfg.dst_fmt = AVUTIL_PIX_FMT_RGB32;
742 scaler_p.ctx->cfg.flags = SWS_POINT; /* | SWS_PRINT_INFO */
744 scaler_p.ctx->scale.src_slices = fr->data;
745 scaler_p.ctx->scale.src_strides = fr->linesize;
746 scaler_p.ctx->scale.dst_slice = scaler_p.img.data;
747 scaler_p.ctx->scale.dst_stride = (u32)scaler_p.img.layout.row_pitch;
748 npv_thdsws_run(scaler_p.ctx);
749 scaler_p.img.fr = fr;
751 * saved pixs for restoration are now irrelevant since we did
752 * overwrite everything
754 npv_video_osd_clear_dirty();
756 STATIC void timer_ack(void)
758 int r;
759 uint64_t exps_n;
761 exps_n = 0;
762 r = read(timer_fd_p, &exps_n, sizeof(exps_n));
763 if (r == -1)
764 warning("unable to read the number of timer expirations\n");