History

avcodec/vvcdec: move frame tab memset from the main thread to worker threads

memset tables in the main thread can become a bottleneck for the decoder. For example, if it takes 1% of the processing time for one core, the maximum achievable FPS will be 100. Move the memeset to worker threads will fix the issue.

Nuo Mi committed 2 years ago

Commit 80af1951 parent daf6fcd3 files · +85 −51Browse files

Showing the changes to libavcodec (3 of 3 files). Show all

Unified · Split

3 files
  1. libavcodec/vvc/dec.c +12 −1
  2. libavcodec/vvc/thread.c +72 −50
  3. libavcodec/vvc/thread.h +1 −0
libavcodec/vvc/dec.c+12−1
@@ -82,7 +82,13 @@ static int tl_create(TabList *l) · 81 unmodified lines
82 if (!*t->tab)82 if (!*t->tab)
83 return AVERROR(ENOMEM);83 return AVERROR(ENOMEM);
84 }84 }
85 } else if (l->zero) {85 }
86 return 0;
87}
88
89static int tl_zero(TabList *l)
90{
91 if (l->zero) {
86 for (int i = 0; i < l->nb_tabs; i++) {92 for (int i = 0; i < l->nb_tabs; i++) {
87 Tab *t = l->tabs + i;93 Tab *t = l->tabs + i;
88 memset(*t->tab, 0, t->size);94 memset(*t->tab, 0, t->size);
@@ -404,6 +410,11 @@ static int pic_arrays_init(VVCContext *s, VVCFrameContext *fc) · 315 unmodified lines
404 return 0;410 return 0;
405}411}
406 412
413int ff_vvc_per_frame_init(VVCFrameContext *fc)
414{
415 return frame_context_for_each_tl(fc, tl_zero);
416}
417
407static int min_positive(const int idx, const int diff, const int min_diff)418static int min_positive(const int idx, const int diff, const int min_diff)
408{419{
409 return diff > 0 && (idx < 0 || diff < min_diff);420 return diff > 0 && (idx < 0 || diff < min_diff);
libavcodec/vvc/thread.c+72−50
@@ -40,6 +40,7 @@ typedef struct ProgressListener { · 39 unmodified lines
40} ProgressListener;40} ProgressListener;
41 41
42typedef enum VVCTaskStage {42typedef enum VVCTaskStage {
43 VVC_TASK_STAGE_INIT, // for CTU(0, 0) only
43 VVC_TASK_STAGE_PARSE,44 VVC_TASK_STAGE_PARSE,
44 VVC_TASK_STAGE_INTER,45 VVC_TASK_STAGE_INTER,
45 VVC_TASK_STAGE_RECON,46 VVC_TASK_STAGE_RECON,
@@ -175,10 +176,14 @@ static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uin · 129 unmodified lines
175 uint8_t target = 0;176 uint8_t target = 0;
176 VVCFrameContext *fc = t->fc;177 VVCFrameContext *fc = t->fc;
177 178
179 if (stage == VVC_TASK_STAGE_INIT)
180 return 1;
181
178 if (stage == VVC_TASK_STAGE_PARSE) {182 if (stage == VVC_TASK_STAGE_PARSE) {
179 const H266RawSPS *rsps = fc->ps.sps->r;183 const H266RawSPS *rsps = fc->ps.sps->r;
180 const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);184 const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);
181 target = 2 + wpp - 1; //left parse + colocation + wpp - no previous stage185 const int no_prev_stage = t->rs > 0;
186 target = 2 + wpp - no_prev_stage; //left parse + colocation + wpp - no_prev_stage
182 } else if (stage == VVC_TASK_STAGE_INTER) {187 } else if (stage == VVC_TASK_STAGE_INTER) {
183 target = atomic_load(&t->target_inter_score);188 target = atomic_load(&t->target_inter_score);
184 } else {189 } else {
@@ -399,6 +404,55 @@ static int task_priority_higher(const AVTask *_a, const AVTask *_b) · 214 unmodified lines
399 return a->ry < b->ry;404 return a->ry < b->ry;
400}405}
401 406
407static void check_colocation(VVCContext *s, VVCTask *t)
408{
409 const VVCFrameContext *fc = t->fc;
410
411 if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
412 VVCFrame *col = fc->ref->collocated_ref;
413 const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
414 if (col && first_col) {
415 //we depend on bottom and right boundary, do not - 1 for y
416 const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
417 add_progress_listener(col, &t->col_listener, t, s, VVC_PROGRESS_MV, y);
418 return;
419 }
420 }
421 frame_thread_add_score(s, fc->ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
422}
423
424static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
425{
426 const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
427 VVCTask *t = ft->tasks + rs;
428
429 frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
430}
431
432static int run_init(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
433{
434 VVCFrameContext *fc = lc->fc;
435 VVCFrameThread *ft = fc->ft;
436 const int ret = ff_vvc_per_frame_init(fc);
437
438 if (ret < 0)
439 return ret;
440
441 for (int i = 0; i < fc->nb_slices; i++) {
442 SliceContext *sc = fc->slices[i];
443 for (int j = 0; j < sc->nb_eps; j++) {
444 EntryPoint *ep = sc->eps + j;
445 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
446 const int rs = sc->sh.ctb_addr_in_curr_slice[k];
447 VVCTask *t = ft->tasks + rs;
448 check_colocation(s, t);
449 }
450 submit_entry_point(s, ft, sc, ep);
451 }
452 }
453 return 0;
454}
455
402static void report_frame_progress(VVCFrameContext *fc,456static void report_frame_progress(VVCFrameContext *fc,
403 const int ry, const VVCProgress idx)457 const int ry, const VVCProgress idx)
404{458{
@@ -547,6 +601,7 @@ static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t) · 142 unmodified lines
547#define VVC_THREAD_DEBUG601#define VVC_THREAD_DEBUG
548#ifdef VVC_THREAD_DEBUG602#ifdef VVC_THREAD_DEBUG
549const static char* task_name[] = {603const static char* task_name[] = {
604 "INIT",
550 "P",605 "P",
551 "I",606 "I",
552 "R",607 "R",
@@ -567,6 +622,7 @@ static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc) · 14 unmodified lines
567 VVCFrameThread *ft = fc->ft;622 VVCFrameThread *ft = fc->ft;
568 const VVCTaskStage stage = t->stage;623 const VVCTaskStage stage = t->stage;
569 static const run_func run[] = {624 static const run_func run[] = {
625 run_init,
570 run_parse,626 run_parse,
571 run_inter,627 run_inter,
572 run_recon,628 run_recon,
@@ -726,7 +782,7 @@ int ff_vvc_frame_thread_init(VVCFrameContext *fc) · 153 unmodified lines
726 782
727 for (int rs = 0; rs < ft->ctu_count; rs++) {783 for (int rs = 0; rs < ft->ctu_count; rs++) {
728 VVCTask *t = ft->tasks + rs;784 VVCTask *t = ft->tasks + rs;
729 task_init(t, VVC_TASK_STAGE_PARSE, fc, rs % ft->ctu_width, rs / ft->ctu_width);785 task_init(t, rs ? VVC_TASK_STAGE_PARSE : VVC_TASK_STAGE_INIT, fc, rs % ft->ctu_width, rs / ft->ctu_width);
730 }786 }
731 787
732 memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));788 memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));
@@ -745,59 +801,25 @@ fail: · 12 unmodified lines
745 return AVERROR(ENOMEM);801 return AVERROR(ENOMEM);
746}802}
747 803
748static void check_colocation(VVCContext *s, VVCTask *t)
749{
750 const VVCFrameContext *fc = t->fc;
751
752 if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
753 VVCFrame *col = fc->ref->collocated_ref;
754 const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
755 if (col && first_col) {
756 //we depend on bottom and right boundary, do not - 1 for y
757 const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
758 add_progress_listener(col, &t->col_listener, t, s, VVC_PROGRESS_MV, y);
759 return;
760 }
761 }
762 frame_thread_add_score(s, fc->ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
763}
764
765static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
766{
767 const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
768 VVCTask *t = ft->tasks + rs;
769
770 frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
771}
772
773int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)804int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
774{805{
775 VVCFrameThread *ft = fc->ft;806 VVCFrameThread *ft = fc->ft;
776 807
777 // We'll handle this in two passes:808 for (int i = 0; i < fc->nb_slices; i++) {
778 // Pass 0 to initialize tasks with parser, this will help detect bit stream error809 SliceContext *sc = fc->slices[i];
779 // Pass 1 to shedule location check and submit the entry point810 for (int j = 0; j < sc->nb_eps; j++) {
780 for (int pass = 0; pass < 2; pass++) {811 EntryPoint *ep = sc->eps + j;
781 for (int i = 0; i < fc->nb_slices; i++) {812 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
782 SliceContext *sc = fc->slices[i];813 const int rs = sc->sh.ctb_addr_in_curr_slice[k];
783 for (int j = 0; j < sc->nb_eps; j++) {814 VVCTask *t = ft->tasks + rs;
784 EntryPoint *ep = sc->eps + j;815 const int ret = task_init_parse(t, sc, ep, k);
785 for (int k = ep->ctu_start; k < ep->ctu_end; k++) {816 if (ret < 0)
786 const int rs = sc->sh.ctb_addr_in_curr_slice[k];817 return ret;
787 VVCTask *t = ft->tasks + rs;
788 if (pass) {
789 check_colocation(s, t);
790 } else {
791 const int ret = task_init_parse(t, sc, ep, k);
792 if (ret < 0)
793 return ret;
794 }
795 }
796 if (pass)
797 submit_entry_point(s, ft, sc, ep);
798 }818 }
799 }819 }
800 }820 }
821 frame_thread_add_score(s, ft, 0, 0, VVC_TASK_STAGE_INIT);
822
801 return 0;823 return 0;
802}824}
803 825
libavcodec/vvc/thread.h+1−0
@@ -32,5 +32,6 @@ int ff_vvc_frame_thread_init(VVCFrameContext *fc); · 31 unmodified lines
32void ff_vvc_frame_thread_free(VVCFrameContext *fc);32void ff_vvc_frame_thread_free(VVCFrameContext *fc);
33int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc);33int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc);
34int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc);34int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc);
35int ff_vvc_per_frame_init(VVCFrameContext *fc);
35 36
36#endif // AVCODEC_VVC_THREAD_H37#endif // AVCODEC_VVC_THREAD_H

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t