+/**
+ * reset the CPB handling
+ */
+static void reset_cpb(struct rvce_encoder *enc)
+{
+ unsigned i;
+
+ list_inithead(&enc->cpb_slots);
+ for (i = 0; i < enc->cpb_num; ++i) {
+ struct rvce_cpb_slot *slot = &enc->cpb_array[i];
+ slot->index = i;
+ slot->picture_type = PIPE_H264_ENC_PICTURE_TYPE_SKIP;
+ slot->frame_num = 0;
+ slot->pic_order_cnt = 0;
+ list_addtail(&slot->list, &enc->cpb_slots);
+ }
+}
+
+/**
+ * sort l0 and l1 to the top of the list
+ */
+static void sort_cpb(struct rvce_encoder *enc)
+{
+ struct rvce_cpb_slot *i, *l0 = NULL, *l1 = NULL;
+
+ LIST_FOR_EACH_ENTRY(i, &enc->cpb_slots, list) {
+ if (i->frame_num == enc->pic.ref_idx_l0)
+ l0 = i;
+
+ if (i->frame_num == enc->pic.ref_idx_l1)
+ l1 = i;
+
+ if (enc->pic.picture_type == PIPE_H264_ENC_PICTURE_TYPE_P && l0)
+ break;
+
+ if (enc->pic.picture_type == PIPE_H264_ENC_PICTURE_TYPE_B &&
+ l0 && l1)
+ break;
+ }
+
+ if (l1) {
+ list_del(&l1->list);
+ list_add(&l1->list, &enc->cpb_slots);
+ }
+
+ if (l0) {
+ list_del(&l0->list);
+ list_add(&l0->list, &enc->cpb_slots);
+ }
+}
+
+/**
+ * get number of cpbs based on dpb
+ */
+static unsigned get_cpb_num(struct rvce_encoder *enc)
+{
+ unsigned w = align(enc->base.width, 16) / 16;
+ unsigned h = align(enc->base.height, 16) / 16;
+ unsigned dpb;
+
+ switch (enc->base.level) {
+ case 10:
+ dpb = 396;
+ break;
+ case 11:
+ dpb = 900;
+ break;
+ case 12:
+ case 13:
+ case 20:
+ dpb = 2376;
+ break;
+ case 21:
+ dpb = 4752;
+ break;
+ case 22:
+ case 30:
+ dpb = 8100;
+ break;
+ case 31:
+ dpb = 18000;
+ break;
+ case 32:
+ dpb = 20480;
+ break;
+ case 40:
+ case 41:
+ dpb = 32768;
+ break;
+ case 42:
+ dpb = 34816;
+ break;
+ case 50:
+ dpb = 110400;
+ break;
+ default:
+ case 51:
+ case 52:
+ dpb = 184320;
+ break;
+ }
+
+ return MIN2(dpb / (w * h), 16);
+}
+
+/**
+ * Get the slot for the currently encoded frame
+ */
+struct rvce_cpb_slot *si_current_slot(struct rvce_encoder *enc)
+{
+ return LIST_ENTRY(struct rvce_cpb_slot, enc->cpb_slots.prev, list);
+}
+
+/**
+ * Get the slot for L0
+ */
+struct rvce_cpb_slot *si_l0_slot(struct rvce_encoder *enc)
+{
+ return LIST_ENTRY(struct rvce_cpb_slot, enc->cpb_slots.next, list);
+}
+
+/**
+ * Get the slot for L1
+ */
+struct rvce_cpb_slot *si_l1_slot(struct rvce_encoder *enc)
+{
+ return LIST_ENTRY(struct rvce_cpb_slot, enc->cpb_slots.next->next, list);
+}
+
+/**
+ * Calculate the offsets into the CPB
+ */
+void si_vce_frame_offset(struct rvce_encoder *enc, struct rvce_cpb_slot *slot,
+ signed *luma_offset, signed *chroma_offset)
+{
+ struct si_screen *sscreen = (struct si_screen *)enc->screen;
+ unsigned pitch, vpitch, fsize;
+
+ if (sscreen->info.chip_class < GFX9) {
+ pitch = align(enc->luma->u.legacy.level[0].nblk_x * enc->luma->bpe, 128);
+ vpitch = align(enc->luma->u.legacy.level[0].nblk_y, 16);
+ } else {
+ pitch = align(enc->luma->u.gfx9.surf_pitch * enc->luma->bpe, 256);
+ vpitch = align(enc->luma->u.gfx9.surf_height, 16);
+ }
+ fsize = pitch * (vpitch + vpitch / 2);
+
+ *luma_offset = slot->index * fsize;
+ *chroma_offset = *luma_offset + pitch * vpitch;
+}
+