Path: blob/21.2-virgl/src/gallium/drivers/radeon/radeon_uvd_enc.c
4570 views
/**************************************************************************1*2* Copyright 2018 Advanced Micro Devices, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include "radeon_uvd_enc.h"2829#include "pipe/p_video_codec.h"30#include "radeon_video.h"31#include "radeonsi/si_pipe.h"32#include "util/u_memory.h"33#include "util/u_video.h"34#include "vl/vl_video_buffer.h"3536#include <stdio.h>3738#define UVD_HEVC_LEVEL_1 3039#define UVD_HEVC_LEVEL_2 6040#define UVD_HEVC_LEVEL_2_1 6341#define UVD_HEVC_LEVEL_3 9042#define UVD_HEVC_LEVEL_3_1 9343#define UVD_HEVC_LEVEL_4 12044#define UVD_HEVC_LEVEL_4_1 12345#define UVD_HEVC_LEVEL_5 15046#define UVD_HEVC_LEVEL_5_1 15347#define UVD_HEVC_LEVEL_5_2 15648#define UVD_HEVC_LEVEL_6 18049#define UVD_HEVC_LEVEL_6_1 18350#define UVD_HEVC_LEVEL_6_2 1865152static void radeon_uvd_enc_get_param(struct radeon_uvd_encoder *enc,53struct pipe_h265_enc_picture_desc *pic)54{55enc->enc_pic.picture_type = pic->picture_type;56enc->enc_pic.frame_num = pic->frame_num;57enc->enc_pic.pic_order_cnt = pic->pic_order_cnt;58enc->enc_pic.pic_order_cnt_type = pic->pic_order_cnt_type;59enc->enc_pic.not_referenced = pic->not_referenced;60enc->enc_pic.is_iframe = (pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) ||61(pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I);6263if (pic->seq.conformance_window_flag) {64enc->enc_pic.crop_left = pic->seq.conf_win_left_offset;65enc->enc_pic.crop_right = pic->seq.conf_win_right_offset;66enc->enc_pic.crop_top = pic->seq.conf_win_top_offset;67enc->enc_pic.crop_bottom = pic->seq.conf_win_bottom_offset;68} else {69enc->enc_pic.crop_left = 0;70enc->enc_pic.crop_right = (align(enc->base.width, 16) - enc->base.width) / 2;71enc->enc_pic.crop_top = 0;72enc->enc_pic.crop_bottom = (align(enc->base.height, 16) - enc->base.height) / 2;73}7475enc->enc_pic.general_tier_flag = pic->seq.general_tier_flag;76enc->enc_pic.general_profile_idc = pic->seq.general_profile_idc;77enc->enc_pic.general_level_idc = pic->seq.general_level_idc;78enc->enc_pic.max_poc = MAX2(16, util_next_power_of_two(pic->seq.intra_period));79enc->enc_pic.log2_max_poc = 0;80for (int i = enc->enc_pic.max_poc; i != 0; enc->enc_pic.log2_max_poc++)81i = (i >> 1);82enc->enc_pic.chroma_format_idc = pic->seq.chroma_format_idc;83enc->enc_pic.pic_width_in_luma_samples = pic->seq.pic_width_in_luma_samples;84enc->enc_pic.pic_height_in_luma_samples = pic->seq.pic_height_in_luma_samples;85enc->enc_pic.log2_diff_max_min_luma_coding_block_size =86pic->seq.log2_diff_max_min_luma_coding_block_size;87enc->enc_pic.log2_min_transform_block_size_minus2 =88pic->seq.log2_min_transform_block_size_minus2;89enc->enc_pic.log2_diff_max_min_transform_block_size =90pic->seq.log2_diff_max_min_transform_block_size;91enc->enc_pic.max_transform_hierarchy_depth_inter = pic->seq.max_transform_hierarchy_depth_inter;92enc->enc_pic.max_transform_hierarchy_depth_intra = pic->seq.max_transform_hierarchy_depth_intra;93enc->enc_pic.log2_parallel_merge_level_minus2 = pic->pic.log2_parallel_merge_level_minus2;94enc->enc_pic.bit_depth_luma_minus8 = pic->seq.bit_depth_luma_minus8;95enc->enc_pic.bit_depth_chroma_minus8 = pic->seq.bit_depth_chroma_minus8;96enc->enc_pic.nal_unit_type = pic->pic.nal_unit_type;97enc->enc_pic.max_num_merge_cand = pic->slice.max_num_merge_cand;98enc->enc_pic.sample_adaptive_offset_enabled_flag = pic->seq.sample_adaptive_offset_enabled_flag;99enc->enc_pic.pcm_enabled_flag = 0; /*HW not support PCM */100enc->enc_pic.sps_temporal_mvp_enabled_flag = pic->seq.sps_temporal_mvp_enabled_flag;101}102103static void flush(struct radeon_uvd_encoder *enc)104{105enc->ws->cs_flush(&enc->cs, PIPE_FLUSH_ASYNC, NULL);106}107108static void radeon_uvd_enc_flush(struct pipe_video_codec *encoder)109{110struct radeon_uvd_encoder *enc = (struct radeon_uvd_encoder *)encoder;111flush(enc);112}113114static void radeon_uvd_enc_cs_flush(void *ctx, unsigned flags, struct pipe_fence_handle **fence)115{116// just ignored117}118119static unsigned get_cpb_num(struct radeon_uvd_encoder *enc)120{121unsigned w = align(enc->base.width, 16) / 16;122unsigned h = align(enc->base.height, 16) / 16;123unsigned dpb;124125switch (enc->base.level) {126case UVD_HEVC_LEVEL_1:127dpb = 36864;128break;129130case UVD_HEVC_LEVEL_2:131dpb = 122880;132break;133134case UVD_HEVC_LEVEL_2_1:135dpb = 245760;136break;137138case UVD_HEVC_LEVEL_3:139dpb = 552960;140break;141142case UVD_HEVC_LEVEL_3_1:143dpb = 983040;144break;145146case UVD_HEVC_LEVEL_4:147case UVD_HEVC_LEVEL_4_1:148dpb = 2228224;149break;150151case UVD_HEVC_LEVEL_5:152case UVD_HEVC_LEVEL_5_1:153case UVD_HEVC_LEVEL_5_2:154dpb = 8912896;155break;156157case UVD_HEVC_LEVEL_6:158case UVD_HEVC_LEVEL_6_1:159case UVD_HEVC_LEVEL_6_2:160default:161dpb = 35651584;162break;163}164165return MIN2(dpb / (w * h), 16);166}167168static void radeon_uvd_enc_begin_frame(struct pipe_video_codec *encoder,169struct pipe_video_buffer *source,170struct pipe_picture_desc *picture)171{172struct radeon_uvd_encoder *enc = (struct radeon_uvd_encoder *)encoder;173struct vl_video_buffer *vid_buf = (struct vl_video_buffer *)source;174175radeon_uvd_enc_get_param(enc, (struct pipe_h265_enc_picture_desc *)picture);176177enc->get_buffer(vid_buf->resources[0], &enc->handle, &enc->luma);178enc->get_buffer(vid_buf->resources[1], NULL, &enc->chroma);179180enc->need_feedback = false;181182if (!enc->stream_handle) {183struct rvid_buffer fb;184enc->stream_handle = si_vid_alloc_stream_handle();185enc->si = CALLOC_STRUCT(rvid_buffer);186si_vid_create_buffer(enc->screen, enc->si, 128 * 1024, PIPE_USAGE_STAGING);187si_vid_create_buffer(enc->screen, &fb, 4096, PIPE_USAGE_STAGING);188enc->fb = &fb;189enc->begin(enc, picture);190flush(enc);191si_vid_destroy_buffer(&fb);192}193}194195static void radeon_uvd_enc_encode_bitstream(struct pipe_video_codec *encoder,196struct pipe_video_buffer *source,197struct pipe_resource *destination, void **fb)198{199struct radeon_uvd_encoder *enc = (struct radeon_uvd_encoder *)encoder;200enc->get_buffer(destination, &enc->bs_handle, NULL);201enc->bs_size = destination->width0;202203*fb = enc->fb = CALLOC_STRUCT(rvid_buffer);204205if (!si_vid_create_buffer(enc->screen, enc->fb, 4096, PIPE_USAGE_STAGING)) {206RVID_ERR("Can't create feedback buffer.\n");207return;208}209210enc->need_feedback = true;211enc->encode(enc);212}213214static void radeon_uvd_enc_end_frame(struct pipe_video_codec *encoder,215struct pipe_video_buffer *source,216struct pipe_picture_desc *picture)217{218struct radeon_uvd_encoder *enc = (struct radeon_uvd_encoder *)encoder;219flush(enc);220}221222static void radeon_uvd_enc_destroy(struct pipe_video_codec *encoder)223{224struct radeon_uvd_encoder *enc = (struct radeon_uvd_encoder *)encoder;225226if (enc->stream_handle) {227struct rvid_buffer fb;228enc->need_feedback = false;229si_vid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING);230enc->fb = &fb;231enc->destroy(enc);232flush(enc);233si_vid_destroy_buffer(&fb);234}235236si_vid_destroy_buffer(&enc->cpb);237enc->ws->cs_destroy(&enc->cs);238FREE(enc);239}240241static void radeon_uvd_enc_get_feedback(struct pipe_video_codec *encoder, void *feedback,242unsigned *size)243{244struct radeon_uvd_encoder *enc = (struct radeon_uvd_encoder *)encoder;245struct rvid_buffer *fb = feedback;246247if (NULL != size) {248radeon_uvd_enc_feedback_t *fb_data = (radeon_uvd_enc_feedback_t *)enc->ws->buffer_map(249enc->ws, fb->res->buf, &enc->cs, PIPE_MAP_READ_WRITE | RADEON_MAP_TEMPORARY);250251if (!fb_data->status)252*size = fb_data->bitstream_size;253else254*size = 0;255enc->ws->buffer_unmap(enc->ws, fb->res->buf);256}257258si_vid_destroy_buffer(fb);259FREE(fb);260}261262struct pipe_video_codec *radeon_uvd_create_encoder(struct pipe_context *context,263const struct pipe_video_codec *templ,264struct radeon_winsys *ws,265radeon_uvd_enc_get_buffer get_buffer)266{267struct si_screen *sscreen = (struct si_screen *)context->screen;268struct si_context *sctx = (struct si_context *)context;269struct radeon_uvd_encoder *enc;270struct pipe_video_buffer *tmp_buf, templat = {};271struct radeon_surf *tmp_surf;272unsigned cpb_size;273274if (!si_radeon_uvd_enc_supported(sscreen)) {275RVID_ERR("Unsupported UVD ENC fw version loaded!\n");276return NULL;277}278279enc = CALLOC_STRUCT(radeon_uvd_encoder);280281if (!enc)282return NULL;283284enc->base = *templ;285enc->base.context = context;286enc->base.destroy = radeon_uvd_enc_destroy;287enc->base.begin_frame = radeon_uvd_enc_begin_frame;288enc->base.encode_bitstream = radeon_uvd_enc_encode_bitstream;289enc->base.end_frame = radeon_uvd_enc_end_frame;290enc->base.flush = radeon_uvd_enc_flush;291enc->base.get_feedback = radeon_uvd_enc_get_feedback;292enc->get_buffer = get_buffer;293enc->bits_in_shifter = 0;294enc->screen = context->screen;295enc->ws = ws;296297if (!ws->cs_create(&enc->cs, sctx->ctx, RING_UVD_ENC, radeon_uvd_enc_cs_flush, enc, false)) {298RVID_ERR("Can't get command submission context.\n");299goto error;300}301302struct rvid_buffer si;303si_vid_create_buffer(enc->screen, &si, 128 * 1024, PIPE_USAGE_STAGING);304enc->si = &si;305306templat.buffer_format = PIPE_FORMAT_NV12;307templat.width = enc->base.width;308templat.height = enc->base.height;309templat.interlaced = false;310311if (!(tmp_buf = context->create_video_buffer(context, &templat))) {312RVID_ERR("Can't create video buffer.\n");313goto error;314}315316enc->cpb_num = get_cpb_num(enc);317318if (!enc->cpb_num)319goto error;320321get_buffer(((struct vl_video_buffer *)tmp_buf)->resources[0], NULL, &tmp_surf);322323cpb_size = (sscreen->info.chip_class < GFX9)324? align(tmp_surf->u.legacy.level[0].nblk_x * tmp_surf->bpe, 128) *325align(tmp_surf->u.legacy.level[0].nblk_y, 32)326: align(tmp_surf->u.gfx9.surf_pitch * tmp_surf->bpe, 256) *327align(tmp_surf->u.gfx9.surf_height, 32);328329cpb_size = cpb_size * 3 / 2;330cpb_size = cpb_size * enc->cpb_num;331tmp_buf->destroy(tmp_buf);332333if (!si_vid_create_buffer(enc->screen, &enc->cpb, cpb_size, PIPE_USAGE_DEFAULT)) {334RVID_ERR("Can't create CPB buffer.\n");335goto error;336}337338radeon_uvd_enc_1_1_init(enc);339340return &enc->base;341342error:343enc->ws->cs_destroy(&enc->cs);344345si_vid_destroy_buffer(&enc->cpb);346347FREE(enc);348return NULL;349}350351bool si_radeon_uvd_enc_supported(struct si_screen *sscreen)352{353return (sscreen->info.has_video_hw.uvd_encode);354}355356357