1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc. 4bf215546Sopenharmony_ci * All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 16bf215546Sopenharmony_ci * of the Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR 22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci **************************************************************************/ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/* 29bf215546Sopenharmony_ci * Authors: 30bf215546Sopenharmony_ci * Christian König <christian.koenig@amd.com> 31bf215546Sopenharmony_ci * 32bf215546Sopenharmony_ci */ 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include <stdio.h> 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "pipe/p_video_codec.h" 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci#include "util/u_video.h" 39bf215546Sopenharmony_ci#include "util/u_memory.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#include "vl/vl_video_buffer.h" 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci#include "r600_pipe_common.h" 44bf215546Sopenharmony_ci#include "radeon_video.h" 45bf215546Sopenharmony_ci#include "radeon_vce.h" 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci#define FW_40_2_2 ((40 << 24) | (2 << 16) | (2 << 8)) 48bf215546Sopenharmony_ci#define FW_50_0_1 ((50 << 24) | (0 << 16) | (1 << 8)) 49bf215546Sopenharmony_ci#define FW_50_1_2 ((50 << 24) | (1 << 16) | (2 << 8)) 50bf215546Sopenharmony_ci#define FW_50_10_2 ((50 << 24) | (10 << 16) | (2 << 8)) 51bf215546Sopenharmony_ci#define FW_50_17_3 ((50 << 24) | (17 << 16) | (3 << 8)) 52bf215546Sopenharmony_ci#define FW_52_0_3 ((52 << 24) | (0 << 16) | (3 << 8)) 53bf215546Sopenharmony_ci#define FW_52_4_3 ((52 << 24) | (4 << 16) | (3 << 8)) 54bf215546Sopenharmony_ci#define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8)) 55bf215546Sopenharmony_ci#define FW_53 (53 << 24) 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci/* version specific function for getting parameters */ 58bf215546Sopenharmony_cistatic void (*get_pic_param)(struct rvce_encoder *enc, 59bf215546Sopenharmony_ci struct pipe_h264_enc_picture_desc *pic) = NULL; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci/** 62bf215546Sopenharmony_ci * flush commands to the hardware 63bf215546Sopenharmony_ci */ 64bf215546Sopenharmony_cistatic void flush(struct rvce_encoder *enc) 65bf215546Sopenharmony_ci{ 66bf215546Sopenharmony_ci enc->ws->cs_flush(&enc->cs, PIPE_FLUSH_ASYNC, NULL); 67bf215546Sopenharmony_ci enc->task_info_idx = 0; 68bf215546Sopenharmony_ci enc->bs_idx = 0; 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci#if 0 72bf215546Sopenharmony_cistatic void dump_feedback(struct rvce_encoder *enc, struct rvid_buffer *fb) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci uint32_t *ptr = enc->ws->buffer_map(fb->res->buf, &enc->cs, PIPE_MAP_READ_WRITE); 75bf215546Sopenharmony_ci unsigned i = 0; 76bf215546Sopenharmony_ci fprintf(stderr, "\n"); 77bf215546Sopenharmony_ci fprintf(stderr, "encStatus:\t\t\t%08x\n", ptr[i++]); 78bf215546Sopenharmony_ci fprintf(stderr, "encHasBitstream:\t\t%08x\n", ptr[i++]); 79bf215546Sopenharmony_ci fprintf(stderr, "encHasAudioBitstream:\t\t%08x\n", ptr[i++]); 80bf215546Sopenharmony_ci fprintf(stderr, "encBitstreamOffset:\t\t%08x\n", ptr[i++]); 81bf215546Sopenharmony_ci fprintf(stderr, "encBitstreamSize:\t\t%08x\n", ptr[i++]); 82bf215546Sopenharmony_ci fprintf(stderr, "encAudioBitstreamOffset:\t%08x\n", ptr[i++]); 83bf215546Sopenharmony_ci fprintf(stderr, "encAudioBitstreamSize:\t\t%08x\n", ptr[i++]); 84bf215546Sopenharmony_ci fprintf(stderr, "encExtrabytes:\t\t\t%08x\n", ptr[i++]); 85bf215546Sopenharmony_ci fprintf(stderr, "encAudioExtrabytes:\t\t%08x\n", ptr[i++]); 86bf215546Sopenharmony_ci fprintf(stderr, "videoTimeStamp:\t\t\t%08x\n", ptr[i++]); 87bf215546Sopenharmony_ci fprintf(stderr, "audioTimeStamp:\t\t\t%08x\n", ptr[i++]); 88bf215546Sopenharmony_ci fprintf(stderr, "videoOutputType:\t\t%08x\n", ptr[i++]); 89bf215546Sopenharmony_ci fprintf(stderr, "attributeFlags:\t\t\t%08x\n", ptr[i++]); 90bf215546Sopenharmony_ci fprintf(stderr, "seiPrivatePackageOffset:\t%08x\n", ptr[i++]); 91bf215546Sopenharmony_ci fprintf(stderr, "seiPrivatePackageSize:\t\t%08x\n", ptr[i++]); 92bf215546Sopenharmony_ci fprintf(stderr, "\n"); 93bf215546Sopenharmony_ci enc->ws->buffer_unmap(fb->res->buf); 94bf215546Sopenharmony_ci} 95bf215546Sopenharmony_ci#endif 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci/** 98bf215546Sopenharmony_ci * reset the CPB handling 99bf215546Sopenharmony_ci */ 100bf215546Sopenharmony_cistatic void reset_cpb(struct rvce_encoder *enc) 101bf215546Sopenharmony_ci{ 102bf215546Sopenharmony_ci unsigned i; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci list_inithead(&enc->cpb_slots); 105bf215546Sopenharmony_ci for (i = 0; i < enc->cpb_num; ++i) { 106bf215546Sopenharmony_ci struct rvce_cpb_slot *slot = &enc->cpb_array[i]; 107bf215546Sopenharmony_ci slot->index = i; 108bf215546Sopenharmony_ci slot->picture_type = PIPE_H2645_ENC_PICTURE_TYPE_SKIP; 109bf215546Sopenharmony_ci slot->frame_num = 0; 110bf215546Sopenharmony_ci slot->pic_order_cnt = 0; 111bf215546Sopenharmony_ci list_addtail(&slot->list, &enc->cpb_slots); 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci/** 116bf215546Sopenharmony_ci * sort l0 and l1 to the top of the list 117bf215546Sopenharmony_ci */ 118bf215546Sopenharmony_cistatic void sort_cpb(struct rvce_encoder *enc) 119bf215546Sopenharmony_ci{ 120bf215546Sopenharmony_ci struct rvce_cpb_slot *i, *l0 = NULL, *l1 = NULL; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci LIST_FOR_EACH_ENTRY(i, &enc->cpb_slots, list) { 123bf215546Sopenharmony_ci if (i->frame_num == enc->pic.ref_idx_l0_list[0]) 124bf215546Sopenharmony_ci l0 = i; 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci if (i->frame_num == enc->pic.ref_idx_l1_list[0]) 127bf215546Sopenharmony_ci l1 = i; 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci if (enc->pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_P && l0) 130bf215546Sopenharmony_ci break; 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci if (enc->pic.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B && 133bf215546Sopenharmony_ci l0 && l1) 134bf215546Sopenharmony_ci break; 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci if (l1) { 138bf215546Sopenharmony_ci list_del(&l1->list); 139bf215546Sopenharmony_ci list_add(&l1->list, &enc->cpb_slots); 140bf215546Sopenharmony_ci } 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci if (l0) { 143bf215546Sopenharmony_ci list_del(&l0->list); 144bf215546Sopenharmony_ci list_add(&l0->list, &enc->cpb_slots); 145bf215546Sopenharmony_ci } 146bf215546Sopenharmony_ci} 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci/** 149bf215546Sopenharmony_ci * get number of cpbs based on dpb 150bf215546Sopenharmony_ci */ 151bf215546Sopenharmony_cistatic unsigned get_cpb_num(struct rvce_encoder *enc) 152bf215546Sopenharmony_ci{ 153bf215546Sopenharmony_ci unsigned w = align(enc->base.width, 16) / 16; 154bf215546Sopenharmony_ci unsigned h = align(enc->base.height, 16) / 16; 155bf215546Sopenharmony_ci unsigned dpb; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci switch (enc->base.level) { 158bf215546Sopenharmony_ci case 10: 159bf215546Sopenharmony_ci dpb = 396; 160bf215546Sopenharmony_ci break; 161bf215546Sopenharmony_ci case 11: 162bf215546Sopenharmony_ci dpb = 900; 163bf215546Sopenharmony_ci break; 164bf215546Sopenharmony_ci case 12: 165bf215546Sopenharmony_ci case 13: 166bf215546Sopenharmony_ci case 20: 167bf215546Sopenharmony_ci dpb = 2376; 168bf215546Sopenharmony_ci break; 169bf215546Sopenharmony_ci case 21: 170bf215546Sopenharmony_ci dpb = 4752; 171bf215546Sopenharmony_ci break; 172bf215546Sopenharmony_ci case 22: 173bf215546Sopenharmony_ci case 30: 174bf215546Sopenharmony_ci dpb = 8100; 175bf215546Sopenharmony_ci break; 176bf215546Sopenharmony_ci case 31: 177bf215546Sopenharmony_ci dpb = 18000; 178bf215546Sopenharmony_ci break; 179bf215546Sopenharmony_ci case 32: 180bf215546Sopenharmony_ci dpb = 20480; 181bf215546Sopenharmony_ci break; 182bf215546Sopenharmony_ci case 40: 183bf215546Sopenharmony_ci case 41: 184bf215546Sopenharmony_ci dpb = 32768; 185bf215546Sopenharmony_ci break; 186bf215546Sopenharmony_ci case 42: 187bf215546Sopenharmony_ci dpb = 34816; 188bf215546Sopenharmony_ci break; 189bf215546Sopenharmony_ci case 50: 190bf215546Sopenharmony_ci dpb = 110400; 191bf215546Sopenharmony_ci break; 192bf215546Sopenharmony_ci default: 193bf215546Sopenharmony_ci case 51: 194bf215546Sopenharmony_ci case 52: 195bf215546Sopenharmony_ci dpb = 184320; 196bf215546Sopenharmony_ci break; 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci return MIN2(dpb / (w * h), 16); 200bf215546Sopenharmony_ci} 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci/** 203bf215546Sopenharmony_ci * Get the slot for the currently encoded frame 204bf215546Sopenharmony_ci */ 205bf215546Sopenharmony_cistruct rvce_cpb_slot *current_slot(struct rvce_encoder *enc) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci return list_entry(enc->cpb_slots.prev, struct rvce_cpb_slot, list); 208bf215546Sopenharmony_ci} 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci/** 211bf215546Sopenharmony_ci * Get the slot for L0 212bf215546Sopenharmony_ci */ 213bf215546Sopenharmony_cistruct rvce_cpb_slot *l0_slot(struct rvce_encoder *enc) 214bf215546Sopenharmony_ci{ 215bf215546Sopenharmony_ci return list_entry(enc->cpb_slots.next, struct rvce_cpb_slot, list); 216bf215546Sopenharmony_ci} 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci/** 219bf215546Sopenharmony_ci * Get the slot for L1 220bf215546Sopenharmony_ci */ 221bf215546Sopenharmony_cistruct rvce_cpb_slot *l1_slot(struct rvce_encoder *enc) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci return list_entry(enc->cpb_slots.next->next, struct rvce_cpb_slot, list); 224bf215546Sopenharmony_ci} 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci/** 227bf215546Sopenharmony_ci * Calculate the offsets into the CPB 228bf215546Sopenharmony_ci */ 229bf215546Sopenharmony_civoid rvce_frame_offset(struct rvce_encoder *enc, struct rvce_cpb_slot *slot, 230bf215546Sopenharmony_ci signed *luma_offset, signed *chroma_offset) 231bf215546Sopenharmony_ci{ 232bf215546Sopenharmony_ci unsigned pitch, vpitch, fsize; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci pitch = align(enc->luma->u.legacy.level[0].nblk_x * enc->luma->bpe, 128); 235bf215546Sopenharmony_ci vpitch = align(enc->luma->u.legacy.level[0].nblk_y, 16); 236bf215546Sopenharmony_ci fsize = pitch * (vpitch + vpitch / 2); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci *luma_offset = slot->index * fsize; 239bf215546Sopenharmony_ci *chroma_offset = *luma_offset + pitch * vpitch; 240bf215546Sopenharmony_ci} 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci/** 243bf215546Sopenharmony_ci * destroy this video encoder 244bf215546Sopenharmony_ci */ 245bf215546Sopenharmony_cistatic void rvce_destroy(struct pipe_video_codec *encoder) 246bf215546Sopenharmony_ci{ 247bf215546Sopenharmony_ci struct rvce_encoder *enc = (struct rvce_encoder*)encoder; 248bf215546Sopenharmony_ci if (enc->stream_handle) { 249bf215546Sopenharmony_ci struct rvid_buffer fb; 250bf215546Sopenharmony_ci rvid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING); 251bf215546Sopenharmony_ci enc->fb = &fb; 252bf215546Sopenharmony_ci enc->session(enc); 253bf215546Sopenharmony_ci enc->feedback(enc); 254bf215546Sopenharmony_ci enc->destroy(enc); 255bf215546Sopenharmony_ci flush(enc); 256bf215546Sopenharmony_ci rvid_destroy_buffer(&fb); 257bf215546Sopenharmony_ci } 258bf215546Sopenharmony_ci rvid_destroy_buffer(&enc->cpb); 259bf215546Sopenharmony_ci enc->ws->cs_destroy(&enc->cs); 260bf215546Sopenharmony_ci FREE(enc->cpb_array); 261bf215546Sopenharmony_ci FREE(enc); 262bf215546Sopenharmony_ci} 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_cistatic void rvce_begin_frame(struct pipe_video_codec *encoder, 265bf215546Sopenharmony_ci struct pipe_video_buffer *source, 266bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 267bf215546Sopenharmony_ci{ 268bf215546Sopenharmony_ci struct rvce_encoder *enc = (struct rvce_encoder*)encoder; 269bf215546Sopenharmony_ci struct vl_video_buffer *vid_buf = (struct vl_video_buffer *)source; 270bf215546Sopenharmony_ci struct pipe_h264_enc_picture_desc *pic = (struct pipe_h264_enc_picture_desc *)picture; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci bool need_rate_control = 273bf215546Sopenharmony_ci enc->pic.rate_ctrl[0].rate_ctrl_method != pic->rate_ctrl[0].rate_ctrl_method || 274bf215546Sopenharmony_ci enc->pic.quant_i_frames != pic->quant_i_frames || 275bf215546Sopenharmony_ci enc->pic.quant_p_frames != pic->quant_p_frames || 276bf215546Sopenharmony_ci enc->pic.quant_b_frames != pic->quant_b_frames; 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci enc->pic = *pic; 279bf215546Sopenharmony_ci get_pic_param(enc, pic); 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci enc->get_buffer(vid_buf->resources[0], &enc->handle, &enc->luma); 282bf215546Sopenharmony_ci enc->get_buffer(vid_buf->resources[1], NULL, &enc->chroma); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci if (pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) 285bf215546Sopenharmony_ci reset_cpb(enc); 286bf215546Sopenharmony_ci else if (pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_P || 287bf215546Sopenharmony_ci pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B) 288bf215546Sopenharmony_ci sort_cpb(enc); 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci if (!enc->stream_handle) { 291bf215546Sopenharmony_ci struct rvid_buffer fb; 292bf215546Sopenharmony_ci enc->stream_handle = rvid_alloc_stream_handle(); 293bf215546Sopenharmony_ci rvid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING); 294bf215546Sopenharmony_ci enc->fb = &fb; 295bf215546Sopenharmony_ci enc->session(enc); 296bf215546Sopenharmony_ci enc->create(enc); 297bf215546Sopenharmony_ci enc->config(enc); 298bf215546Sopenharmony_ci enc->feedback(enc); 299bf215546Sopenharmony_ci flush(enc); 300bf215546Sopenharmony_ci //dump_feedback(enc, &fb); 301bf215546Sopenharmony_ci rvid_destroy_buffer(&fb); 302bf215546Sopenharmony_ci need_rate_control = false; 303bf215546Sopenharmony_ci } 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci if (need_rate_control) { 306bf215546Sopenharmony_ci enc->session(enc); 307bf215546Sopenharmony_ci enc->config(enc); 308bf215546Sopenharmony_ci flush(enc); 309bf215546Sopenharmony_ci } 310bf215546Sopenharmony_ci} 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_cistatic void rvce_encode_bitstream(struct pipe_video_codec *encoder, 313bf215546Sopenharmony_ci struct pipe_video_buffer *source, 314bf215546Sopenharmony_ci struct pipe_resource *destination, 315bf215546Sopenharmony_ci void **fb) 316bf215546Sopenharmony_ci{ 317bf215546Sopenharmony_ci struct rvce_encoder *enc = (struct rvce_encoder*)encoder; 318bf215546Sopenharmony_ci enc->get_buffer(destination, &enc->bs_handle, NULL); 319bf215546Sopenharmony_ci enc->bs_size = destination->width0; 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci *fb = enc->fb = CALLOC_STRUCT(rvid_buffer); 322bf215546Sopenharmony_ci if (!rvid_create_buffer(enc->screen, enc->fb, 512, PIPE_USAGE_STAGING)) { 323bf215546Sopenharmony_ci RVID_ERR("Can't create feedback buffer.\n"); 324bf215546Sopenharmony_ci return; 325bf215546Sopenharmony_ci } 326bf215546Sopenharmony_ci if (!radeon_emitted(&enc->cs, 0)) 327bf215546Sopenharmony_ci enc->session(enc); 328bf215546Sopenharmony_ci enc->encode(enc); 329bf215546Sopenharmony_ci enc->feedback(enc); 330bf215546Sopenharmony_ci} 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_cistatic void rvce_end_frame(struct pipe_video_codec *encoder, 333bf215546Sopenharmony_ci struct pipe_video_buffer *source, 334bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 335bf215546Sopenharmony_ci{ 336bf215546Sopenharmony_ci struct rvce_encoder *enc = (struct rvce_encoder*)encoder; 337bf215546Sopenharmony_ci struct rvce_cpb_slot *slot = list_entry(enc->cpb_slots.prev, 338bf215546Sopenharmony_ci struct rvce_cpb_slot, 339bf215546Sopenharmony_ci list); 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci if (!enc->dual_inst || enc->bs_idx > 1) 342bf215546Sopenharmony_ci flush(enc); 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci /* update the CPB backtrack with the just encoded frame */ 345bf215546Sopenharmony_ci slot->picture_type = enc->pic.picture_type; 346bf215546Sopenharmony_ci slot->frame_num = enc->pic.frame_num; 347bf215546Sopenharmony_ci slot->pic_order_cnt = enc->pic.pic_order_cnt; 348bf215546Sopenharmony_ci if (!enc->pic.not_referenced) { 349bf215546Sopenharmony_ci list_del(&slot->list); 350bf215546Sopenharmony_ci list_add(&slot->list, &enc->cpb_slots); 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci} 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_cistatic void rvce_get_feedback(struct pipe_video_codec *encoder, 355bf215546Sopenharmony_ci void *feedback, unsigned *size) 356bf215546Sopenharmony_ci{ 357bf215546Sopenharmony_ci struct rvce_encoder *enc = (struct rvce_encoder*)encoder; 358bf215546Sopenharmony_ci struct rvid_buffer *fb = feedback; 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci if (size) { 361bf215546Sopenharmony_ci uint32_t *ptr = enc->ws->buffer_map(enc->ws, 362bf215546Sopenharmony_ci fb->res->buf, &enc->cs, 363bf215546Sopenharmony_ci PIPE_MAP_READ_WRITE | RADEON_MAP_TEMPORARY); 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci if (ptr[1]) { 366bf215546Sopenharmony_ci *size = ptr[4] - ptr[9]; 367bf215546Sopenharmony_ci } else { 368bf215546Sopenharmony_ci *size = 0; 369bf215546Sopenharmony_ci } 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ci enc->ws->buffer_unmap(enc->ws, fb->res->buf); 372bf215546Sopenharmony_ci } 373bf215546Sopenharmony_ci //dump_feedback(enc, fb); 374bf215546Sopenharmony_ci rvid_destroy_buffer(fb); 375bf215546Sopenharmony_ci FREE(fb); 376bf215546Sopenharmony_ci} 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci/** 379bf215546Sopenharmony_ci * flush any outstanding command buffers to the hardware 380bf215546Sopenharmony_ci */ 381bf215546Sopenharmony_cistatic void rvce_flush(struct pipe_video_codec *encoder) 382bf215546Sopenharmony_ci{ 383bf215546Sopenharmony_ci struct rvce_encoder *enc = (struct rvce_encoder*)encoder; 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci flush(enc); 386bf215546Sopenharmony_ci} 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_cistatic void rvce_cs_flush(void *ctx, unsigned flags, 389bf215546Sopenharmony_ci struct pipe_fence_handle **fence) 390bf215546Sopenharmony_ci{ 391bf215546Sopenharmony_ci // just ignored 392bf215546Sopenharmony_ci} 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_cistruct pipe_video_codec *rvce_create_encoder(struct pipe_context *context, 395bf215546Sopenharmony_ci const struct pipe_video_codec *templ, 396bf215546Sopenharmony_ci struct radeon_winsys* ws, 397bf215546Sopenharmony_ci rvce_get_buffer get_buffer) 398bf215546Sopenharmony_ci{ 399bf215546Sopenharmony_ci struct r600_common_screen *rscreen = (struct r600_common_screen *)context->screen; 400bf215546Sopenharmony_ci struct r600_common_context *rctx = (struct r600_common_context*)context; 401bf215546Sopenharmony_ci struct rvce_encoder *enc; 402bf215546Sopenharmony_ci struct pipe_video_buffer *tmp_buf, templat = {}; 403bf215546Sopenharmony_ci struct radeon_surf *tmp_surf; 404bf215546Sopenharmony_ci unsigned cpb_size; 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci if (!rscreen->info.vce_fw_version) { 407bf215546Sopenharmony_ci RVID_ERR("Kernel doesn't supports VCE!\n"); 408bf215546Sopenharmony_ci return NULL; 409bf215546Sopenharmony_ci 410bf215546Sopenharmony_ci } else if (!rvce_is_fw_version_supported(rscreen)) { 411bf215546Sopenharmony_ci RVID_ERR("Unsupported VCE fw version loaded!\n"); 412bf215546Sopenharmony_ci return NULL; 413bf215546Sopenharmony_ci } 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci enc = CALLOC_STRUCT(rvce_encoder); 416bf215546Sopenharmony_ci if (!enc) 417bf215546Sopenharmony_ci return NULL; 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci enc->use_vui = true; 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci enc->base = *templ; 422bf215546Sopenharmony_ci enc->base.context = context; 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci enc->base.destroy = rvce_destroy; 425bf215546Sopenharmony_ci enc->base.begin_frame = rvce_begin_frame; 426bf215546Sopenharmony_ci enc->base.encode_bitstream = rvce_encode_bitstream; 427bf215546Sopenharmony_ci enc->base.end_frame = rvce_end_frame; 428bf215546Sopenharmony_ci enc->base.flush = rvce_flush; 429bf215546Sopenharmony_ci enc->base.get_feedback = rvce_get_feedback; 430bf215546Sopenharmony_ci enc->get_buffer = get_buffer; 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci enc->screen = context->screen; 433bf215546Sopenharmony_ci enc->ws = ws; 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_ci if (!ws->cs_create(&enc->cs, rctx->ctx, AMD_IP_VCE, rvce_cs_flush, enc, false)) { 436bf215546Sopenharmony_ci RVID_ERR("Can't get command submission context.\n"); 437bf215546Sopenharmony_ci goto error; 438bf215546Sopenharmony_ci } 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci templat.buffer_format = PIPE_FORMAT_NV12; 441bf215546Sopenharmony_ci templat.width = enc->base.width; 442bf215546Sopenharmony_ci templat.height = enc->base.height; 443bf215546Sopenharmony_ci templat.interlaced = false; 444bf215546Sopenharmony_ci if (!(tmp_buf = context->create_video_buffer(context, &templat))) { 445bf215546Sopenharmony_ci RVID_ERR("Can't create video buffer.\n"); 446bf215546Sopenharmony_ci goto error; 447bf215546Sopenharmony_ci } 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci enc->cpb_num = get_cpb_num(enc); 450bf215546Sopenharmony_ci if (!enc->cpb_num) 451bf215546Sopenharmony_ci goto error; 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci get_buffer(((struct vl_video_buffer *)tmp_buf)->resources[0], NULL, &tmp_surf); 454bf215546Sopenharmony_ci 455bf215546Sopenharmony_ci cpb_size = align(tmp_surf->u.legacy.level[0].nblk_x * tmp_surf->bpe, 128) * 456bf215546Sopenharmony_ci align(tmp_surf->u.legacy.level[0].nblk_y, 32); 457bf215546Sopenharmony_ci 458bf215546Sopenharmony_ci cpb_size = cpb_size * 3 / 2; 459bf215546Sopenharmony_ci cpb_size = cpb_size * enc->cpb_num; 460bf215546Sopenharmony_ci if (enc->dual_pipe) 461bf215546Sopenharmony_ci cpb_size += RVCE_MAX_AUX_BUFFER_NUM * 462bf215546Sopenharmony_ci RVCE_MAX_BITSTREAM_OUTPUT_ROW_SIZE * 2; 463bf215546Sopenharmony_ci tmp_buf->destroy(tmp_buf); 464bf215546Sopenharmony_ci if (!rvid_create_buffer(enc->screen, &enc->cpb, cpb_size, PIPE_USAGE_DEFAULT)) { 465bf215546Sopenharmony_ci RVID_ERR("Can't create CPB buffer.\n"); 466bf215546Sopenharmony_ci goto error; 467bf215546Sopenharmony_ci } 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci enc->cpb_array = CALLOC(enc->cpb_num, sizeof(struct rvce_cpb_slot)); 470bf215546Sopenharmony_ci if (!enc->cpb_array) 471bf215546Sopenharmony_ci goto error; 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci reset_cpb(enc); 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci goto error; 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci return &enc->base; 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_cierror: 480bf215546Sopenharmony_ci enc->ws->cs_destroy(&enc->cs); 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci rvid_destroy_buffer(&enc->cpb); 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci FREE(enc->cpb_array); 485bf215546Sopenharmony_ci FREE(enc); 486bf215546Sopenharmony_ci return NULL; 487bf215546Sopenharmony_ci} 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci/** 490bf215546Sopenharmony_ci * check if kernel has the right fw version loaded 491bf215546Sopenharmony_ci */ 492bf215546Sopenharmony_cibool rvce_is_fw_version_supported(struct r600_common_screen *rscreen) 493bf215546Sopenharmony_ci{ 494bf215546Sopenharmony_ci switch (rscreen->info.vce_fw_version) { 495bf215546Sopenharmony_ci case FW_40_2_2: 496bf215546Sopenharmony_ci case FW_50_0_1: 497bf215546Sopenharmony_ci case FW_50_1_2: 498bf215546Sopenharmony_ci case FW_50_10_2: 499bf215546Sopenharmony_ci case FW_50_17_3: 500bf215546Sopenharmony_ci case FW_52_0_3: 501bf215546Sopenharmony_ci case FW_52_4_3: 502bf215546Sopenharmony_ci case FW_52_8_3: 503bf215546Sopenharmony_ci return true; 504bf215546Sopenharmony_ci default: 505bf215546Sopenharmony_ci if ((rscreen->info.vce_fw_version & (0xff << 24)) == FW_53) 506bf215546Sopenharmony_ci return true; 507bf215546Sopenharmony_ci else 508bf215546Sopenharmony_ci return false; 509bf215546Sopenharmony_ci } 510bf215546Sopenharmony_ci} 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci/** 513bf215546Sopenharmony_ci * Add the buffer as relocation to the current command submission 514bf215546Sopenharmony_ci */ 515bf215546Sopenharmony_civoid rvce_add_buffer(struct rvce_encoder *enc, struct pb_buffer *buf, 516bf215546Sopenharmony_ci unsigned usage, enum radeon_bo_domain domain, 517bf215546Sopenharmony_ci signed offset) 518bf215546Sopenharmony_ci{ 519bf215546Sopenharmony_ci int reloc_idx; 520bf215546Sopenharmony_ci 521bf215546Sopenharmony_ci reloc_idx = enc->ws->cs_add_buffer(&enc->cs, buf, usage | RADEON_USAGE_SYNCHRONIZED, 522bf215546Sopenharmony_ci domain); 523bf215546Sopenharmony_ci if (enc->use_vm) { 524bf215546Sopenharmony_ci uint64_t addr; 525bf215546Sopenharmony_ci addr = enc->ws->buffer_get_virtual_address(buf); 526bf215546Sopenharmony_ci addr = addr + offset; 527bf215546Sopenharmony_ci RVCE_CS(addr >> 32); 528bf215546Sopenharmony_ci RVCE_CS(addr); 529bf215546Sopenharmony_ci } else { 530bf215546Sopenharmony_ci offset += enc->ws->buffer_get_reloc_offset(buf); 531bf215546Sopenharmony_ci RVCE_CS(reloc_idx * 4); 532bf215546Sopenharmony_ci RVCE_CS(offset); 533bf215546Sopenharmony_ci } 534bf215546Sopenharmony_ci} 535