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