Path: blob/21.2-virgl/src/gallium/frontends/omx/vid_enc_common.c
4561 views
/**************************************************************************1*2* Copyright 2013 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 "vid_enc_common.h"2829#include "vl/vl_video_buffer.h"30#include "tgsi/tgsi_text.h"3132void enc_ReleaseTasks(struct list_head *head)33{34struct encode_task *i, *next;3536if (!head || !list_is_linked(head))37return;3839LIST_FOR_EACH_ENTRY_SAFE(i, next, head, list) {40pipe_resource_reference(&i->bitstream, NULL);41i->buf->destroy(i->buf);42FREE(i);43}44}4546void enc_MoveTasks(struct list_head *from, struct list_head *to)47{48to->prev->next = from->next;49from->next->prev = to->prev;50from->prev->next = to;51to->prev = from->prev;52list_inithead(from);53}5455static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc *picture)56{57picture->motion_est.enc_disable_sub_mode = 0x000000fe;58picture->motion_est.enc_ime2_search_range_x = 0x00000001;59picture->motion_est.enc_ime2_search_range_y = 0x00000001;60picture->pic_ctrl.enc_constraint_set_flags = 0x00000040;61}6263enum pipe_video_profile enc_TranslateOMXProfileToPipe(unsigned omx_profile)64{65switch (omx_profile) {66case OMX_VIDEO_AVCProfileBaseline:67return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE;68case OMX_VIDEO_AVCProfileMain:69return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN;70case OMX_VIDEO_AVCProfileExtended:71return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED;72case OMX_VIDEO_AVCProfileHigh:73return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;74case OMX_VIDEO_AVCProfileHigh10:75return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10;76case OMX_VIDEO_AVCProfileHigh422:77return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422;78case OMX_VIDEO_AVCProfileHigh444:79return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444;80default:81return PIPE_VIDEO_PROFILE_UNKNOWN;82}83}8485unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level)86{87switch (omx_level) {88case OMX_VIDEO_AVCLevel1:89case OMX_VIDEO_AVCLevel1b:90return 10;91case OMX_VIDEO_AVCLevel11:92return 11;93case OMX_VIDEO_AVCLevel12:94return 12;95case OMX_VIDEO_AVCLevel13:96return 13;97case OMX_VIDEO_AVCLevel2:98return 20;99case OMX_VIDEO_AVCLevel21:100return 21;101case OMX_VIDEO_AVCLevel22:102return 22;103case OMX_VIDEO_AVCLevel3:104return 30;105case OMX_VIDEO_AVCLevel31:106return 31;107case OMX_VIDEO_AVCLevel32:108return 32;109case OMX_VIDEO_AVCLevel4:110return 40;111case OMX_VIDEO_AVCLevel41:112return 41;113default:114case OMX_VIDEO_AVCLevel42:115return 42;116case OMX_VIDEO_AVCLevel5:117return 50;118case OMX_VIDEO_AVCLevel51:119return 51;120}121}122123void vid_enc_BufferEncoded_common(vid_enc_PrivateType * priv, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output)124{125struct output_buf_private *outp = output->pOutputPortPrivate;126struct input_buf_private *inp = input->pInputPortPrivate;127struct encode_task *task;128struct pipe_box box = {};129unsigned size;130131#if ENABLE_ST_OMX_BELLAGIO132if (!inp || list_is_empty(&inp->tasks)) {133input->nFilledLen = 0; /* mark buffer as empty */134enc_MoveTasks(&priv->used_tasks, &inp->tasks);135return;136}137#endif138139task = LIST_ENTRY(struct encode_task, inp->tasks.next, list);140list_del(&task->list);141list_addtail(&task->list, &priv->used_tasks);142143if (!task->bitstream)144return;145146/* ------------- map result buffer ----------------- */147148if (outp->transfer)149pipe_buffer_unmap(priv->t_pipe, outp->transfer);150151pipe_resource_reference(&outp->bitstream, task->bitstream);152pipe_resource_reference(&task->bitstream, NULL);153154box.width = outp->bitstream->width0;155box.height = outp->bitstream->height0;156box.depth = outp->bitstream->depth0;157158output->pBuffer = priv->t_pipe->buffer_map(priv->t_pipe, outp->bitstream, 0,159PIPE_MAP_READ_WRITE,160&box, &outp->transfer);161162/* ------------- get size of result ----------------- */163164priv->codec->get_feedback(priv->codec, task->feedback, &size);165166output->nOffset = 0;167output->nFilledLen = size; /* mark buffer as full */168169/* all output buffers contain exactly one frame */170output->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;171172#if ENABLE_ST_OMX_TIZONIA173input->nFilledLen = 0; /* mark buffer as empty */174enc_MoveTasks(&priv->used_tasks, &inp->tasks);175#endif176}177178179struct encode_task *enc_NeedTask_common(vid_enc_PrivateType * priv, OMX_VIDEO_PORTDEFINITIONTYPE *def)180{181struct pipe_video_buffer templat = {};182struct encode_task *task;183184if (!list_is_empty(&priv->free_tasks)) {185task = LIST_ENTRY(struct encode_task, priv->free_tasks.next, list);186list_del(&task->list);187return task;188}189190/* allocate a new one */191task = CALLOC_STRUCT(encode_task);192if (!task)193return NULL;194195templat.buffer_format = PIPE_FORMAT_NV12;196templat.width = def->nFrameWidth;197templat.height = def->nFrameHeight;198templat.interlaced = false;199200task->buf = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat);201if (!task->buf) {202FREE(task);203return NULL;204}205206return task;207}208209void enc_ScaleInput_common(vid_enc_PrivateType * priv, OMX_VIDEO_PORTDEFINITIONTYPE *def,210struct pipe_video_buffer **vbuf, unsigned *size)211{212struct pipe_video_buffer *src_buf = *vbuf;213struct vl_compositor *compositor = &priv->compositor;214struct vl_compositor_state *s = &priv->cstate;215struct pipe_sampler_view **views;216struct pipe_surface **dst_surface;217unsigned i;218219if (!priv->scale_buffer[priv->current_scale_buffer])220return;221222views = src_buf->get_sampler_view_planes(src_buf);223dst_surface = priv->scale_buffer[priv->current_scale_buffer]->get_surfaces224(priv->scale_buffer[priv->current_scale_buffer]);225vl_compositor_clear_layers(s);226227for (i = 0; i < VL_MAX_SURFACES; ++i) {228struct u_rect src_rect;229if (!views[i] || !dst_surface[i])230continue;231src_rect.x0 = 0;232src_rect.y0 = 0;233src_rect.x1 = def->nFrameWidth;234src_rect.y1 = def->nFrameHeight;235if (i > 0) {236src_rect.x1 /= 2;237src_rect.y1 /= 2;238}239vl_compositor_set_rgba_layer(s, compositor, 0, views[i], &src_rect, NULL, NULL);240vl_compositor_render(s, compositor, dst_surface[i], NULL, false);241}242*size = priv->scale.xWidth * priv->scale.xHeight * 2;243*vbuf = priv->scale_buffer[priv->current_scale_buffer++];244priv->current_scale_buffer %= OMX_VID_ENC_NUM_SCALING_BUFFERS;245}246247void enc_ControlPicture_common(vid_enc_PrivateType * priv, struct pipe_h264_enc_picture_desc *picture)248{249struct pipe_h264_enc_rate_control *rate_ctrl = &picture->rate_ctrl;250251/* Get bitrate from port */252switch (priv->bitrate.eControlRate) {253case OMX_Video_ControlRateVariable:254rate_ctrl->rate_ctrl_method = PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE;255break;256case OMX_Video_ControlRateConstant:257rate_ctrl->rate_ctrl_method = PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT;258break;259case OMX_Video_ControlRateVariableSkipFrames:260rate_ctrl->rate_ctrl_method = PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP;261break;262case OMX_Video_ControlRateConstantSkipFrames:263rate_ctrl->rate_ctrl_method = PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP;264break;265default:266rate_ctrl->rate_ctrl_method = PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE;267break;268}269270rate_ctrl->frame_rate_den = OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT;271rate_ctrl->frame_rate_num = ((priv->frame_rate) >> 16) * rate_ctrl->frame_rate_den;272273if (rate_ctrl->rate_ctrl_method != PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE) {274if (priv->bitrate.nTargetBitrate < OMX_VID_ENC_BITRATE_MIN)275rate_ctrl->target_bitrate = OMX_VID_ENC_BITRATE_MIN;276else if (priv->bitrate.nTargetBitrate < OMX_VID_ENC_BITRATE_MAX)277rate_ctrl->target_bitrate = priv->bitrate.nTargetBitrate;278else279rate_ctrl->target_bitrate = OMX_VID_ENC_BITRATE_MAX;280rate_ctrl->peak_bitrate = rate_ctrl->target_bitrate;281if (rate_ctrl->target_bitrate < OMX_VID_ENC_BITRATE_MEDIAN)282rate_ctrl->vbv_buffer_size = MIN2((rate_ctrl->target_bitrate * 2.75), OMX_VID_ENC_BITRATE_MEDIAN);283else284rate_ctrl->vbv_buffer_size = rate_ctrl->target_bitrate;285286if (rate_ctrl->frame_rate_num) {287unsigned long long t = rate_ctrl->target_bitrate;288t *= rate_ctrl->frame_rate_den;289rate_ctrl->target_bits_picture = t / rate_ctrl->frame_rate_num;290} else {291rate_ctrl->target_bits_picture = rate_ctrl->target_bitrate;292}293rate_ctrl->peak_bits_picture_integer = rate_ctrl->target_bits_picture;294rate_ctrl->peak_bits_picture_fraction = 0;295}296297picture->quant_i_frames = priv->quant.nQpI;298picture->quant_p_frames = priv->quant.nQpP;299picture->quant_b_frames = priv->quant.nQpB;300301picture->frame_num = priv->frame_num;302picture->ref_idx_l0 = priv->ref_idx_l0;303picture->ref_idx_l1 = priv->ref_idx_l1;304picture->enable_vui = (picture->rate_ctrl.frame_rate_num != 0);305enc_GetPictureParamPreset(picture);306}307308static void *create_compute_state(struct pipe_context *pipe,309const char *source)310{311struct tgsi_token tokens[1024];312struct pipe_compute_state state = {0};313314if (!tgsi_text_translate(source, tokens, ARRAY_SIZE(tokens))) {315assert(false);316return NULL;317}318319state.ir_type = PIPE_SHADER_IR_TGSI;320state.prog = tokens;321322return pipe->create_compute_state(pipe, &state);323}324325void enc_InitCompute_common(vid_enc_PrivateType *priv)326{327struct pipe_context *pipe = priv->s_pipe;328struct pipe_screen *screen = pipe->screen;329330/* We need the partial last block support. */331if (!screen->get_param(screen, PIPE_CAP_COMPUTE_GRID_INFO_LAST_BLOCK))332return;333334static const char *copy_y =335"COMP\n"336"PROPERTY CS_FIXED_BLOCK_WIDTH 64\n"337"PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n"338"PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"339"DCL SV[0], THREAD_ID\n"340"DCL SV[1], BLOCK_ID\n"341"DCL IMAGE[0], 2D, PIPE_FORMAT_R8_UINT\n"342"DCL IMAGE[1], 2D, PIPE_FORMAT_R8_UINT, WR\n"343"DCL TEMP[0..1]\n"344"IMM[0] UINT32 {64, 0, 0, 0}\n"345346"UMAD TEMP[0].x, SV[1], IMM[0], SV[0]\n"347"MOV TEMP[0].y, SV[1]\n"348"LOAD TEMP[1].x, IMAGE[0], TEMP[0], 2D, PIPE_FORMAT_R8_UINT\n"349"STORE IMAGE[1].x, TEMP[0], TEMP[1], 2D, PIPE_FORMAT_R8_UINT\n"350"END\n";351352static const char *copy_uv =353"COMP\n"354"PROPERTY CS_FIXED_BLOCK_WIDTH 64\n"355"PROPERTY CS_FIXED_BLOCK_HEIGHT 1\n"356"PROPERTY CS_FIXED_BLOCK_DEPTH 1\n"357"DCL SV[0], THREAD_ID\n"358"DCL SV[1], BLOCK_ID\n"359"DCL IMAGE[0], 2D, PIPE_FORMAT_R8_UINT\n"360"DCL IMAGE[2], 2D, PIPE_FORMAT_R8G8_UINT, WR\n"361"DCL CONST[0][0]\n" /* .x = offset of the UV portion in the y direction */362"DCL TEMP[0..4]\n"363"IMM[0] UINT32 {64, 0, 2, 1}\n"364/* Destination R8G8 coordinates */365"UMAD TEMP[0].x, SV[1], IMM[0], SV[0]\n"366"MOV TEMP[0].y, SV[1]\n"367/* Source R8 coordinates of U */368"UMUL TEMP[1].x, TEMP[0], IMM[0].zzzz\n"369"UADD TEMP[1].y, TEMP[0], CONST[0].xxxx\n"370/* Source R8 coordinates of V */371"UADD TEMP[2].x, TEMP[1], IMM[0].wwww\n"372"MOV TEMP[2].y, TEMP[1]\n"373374"LOAD TEMP[3].x, IMAGE[0], TEMP[1], 2D, PIPE_FORMAT_R8_UINT\n"375"LOAD TEMP[4].x, IMAGE[0], TEMP[2], 2D, PIPE_FORMAT_R8_UINT\n"376"MOV TEMP[3].y, TEMP[4].xxxx\n"377"STORE IMAGE[2], TEMP[0], TEMP[3], 2D, PIPE_FORMAT_R8G8_UINT\n"378"END\n";379380priv->copy_y_shader = create_compute_state(pipe, copy_y);381priv->copy_uv_shader = create_compute_state(pipe, copy_uv);382}383384void enc_ReleaseCompute_common(vid_enc_PrivateType *priv)385{386struct pipe_context *pipe = priv->s_pipe;387388if (priv->copy_y_shader)389pipe->delete_compute_state(pipe, priv->copy_y_shader);390if (priv->copy_uv_shader)391pipe->delete_compute_state(pipe, priv->copy_uv_shader);392}393394OMX_ERRORTYPE enc_LoadImage_common(vid_enc_PrivateType * priv, OMX_VIDEO_PORTDEFINITIONTYPE *def,395OMX_BUFFERHEADERTYPE *buf,396struct pipe_video_buffer *vbuf)397{398struct pipe_context *pipe = priv->s_pipe;399struct pipe_box box = {};400struct input_buf_private *inp = buf->pInputPortPrivate;401402if (!inp->resource) {403struct pipe_sampler_view **views;404void *ptr;405406views = vbuf->get_sampler_view_planes(vbuf);407if (!views)408return OMX_ErrorInsufficientResources;409410ptr = buf->pBuffer;411box.width = def->nFrameWidth;412box.height = def->nFrameHeight;413box.depth = 1;414pipe->texture_subdata(pipe, views[0]->texture, 0,415PIPE_MAP_WRITE, &box,416ptr, def->nStride, 0);417ptr = ((uint8_t*)buf->pBuffer) + (def->nStride * box.height);418box.width = def->nFrameWidth / 2;419box.height = def->nFrameHeight / 2;420box.depth = 1;421pipe->texture_subdata(pipe, views[1]->texture, 0,422PIPE_MAP_WRITE, &box,423ptr, def->nStride, 0);424} else {425struct vl_video_buffer *dst_buf = (struct vl_video_buffer *)vbuf;426427pipe_texture_unmap(pipe, inp->transfer);428429/* inp->resource uses PIPE_FORMAT_I8 and the layout looks like this:430*431* def->nFrameWidth = 4, def->nFrameHeight = 4:432* |----|433* |YYYY|434* |YYYY|435* |YYYY|436* |YYYY|437* |UVUV|438* |UVUV|439* |----|440*441* The copy has 2 steps:442* - Copy Y to dst_buf->resources[0] as R8.443* - Copy UV to dst_buf->resources[1] as R8G8.444*/445if (priv->copy_y_shader && priv->copy_uv_shader) {446/* Compute path */447/* Set shader images for both copies. */448struct pipe_image_view image[3] = {0};449image[0].resource = inp->resource;450image[0].shader_access = image[0].access = PIPE_IMAGE_ACCESS_READ;451image[0].format = PIPE_FORMAT_R8_UINT;452453image[1].resource = dst_buf->resources[0];454image[1].shader_access = image[1].access = PIPE_IMAGE_ACCESS_WRITE;455image[1].format = PIPE_FORMAT_R8_UINT;456457image[2].resource = dst_buf->resources[1];458image[2].shader_access = image[1].access = PIPE_IMAGE_ACCESS_WRITE;459image[2].format = PIPE_FORMAT_R8G8_UINT;460461pipe->set_shader_images(pipe, PIPE_SHADER_COMPUTE, 0, 3, 0, image);462463/* Set the constant buffer. */464uint32_t constants[4] = {def->nFrameHeight};465struct pipe_constant_buffer cb = {};466467cb.buffer_size = sizeof(constants);468cb.user_buffer = constants;469pipe->set_constant_buffer(pipe, PIPE_SHADER_COMPUTE, 0, false, &cb);470471/* Use the optimal block size for the linear image layout. */472struct pipe_grid_info info = {};473info.block[0] = 64;474info.block[1] = 1;475info.block[2] = 1;476info.grid[2] = 1;477478/* Copy Y */479pipe->bind_compute_state(pipe, priv->copy_y_shader);480481info.grid[0] = DIV_ROUND_UP(def->nFrameWidth, 64);482info.grid[1] = def->nFrameHeight;483info.last_block[0] = def->nFrameWidth % 64;484pipe->launch_grid(pipe, &info);485486/* Copy UV */487pipe->bind_compute_state(pipe, priv->copy_uv_shader);488489info.grid[0] = DIV_ROUND_UP(def->nFrameWidth / 2, 64);490info.grid[1] = def->nFrameHeight / 2;491info.last_block[0] = (def->nFrameWidth / 2) % 64;492pipe->launch_grid(pipe, &info);493494/* Make the result visible to all clients. */495pipe->memory_barrier(pipe, PIPE_BARRIER_ALL);496497/* Unbind. */498pipe->set_shader_images(pipe, PIPE_SHADER_COMPUTE, 0, 0, 3, NULL);499pipe->set_constant_buffer(pipe, PIPE_SHADER_COMPUTE, 0, false, NULL);500pipe->bind_compute_state(pipe, NULL);501} else {502/* Graphics path */503struct pipe_blit_info blit;504505box.width = def->nFrameWidth;506box.height = def->nFrameHeight;507box.depth = 1;508509/* Copy Y */510pipe->resource_copy_region(pipe,511dst_buf->resources[0],5120, 0, 0, 0, inp->resource, 0, &box);513514/* Copy U */515memset(&blit, 0, sizeof(blit));516blit.src.resource = inp->resource;517blit.src.format = inp->resource->format;518519blit.src.box.x = -1;520blit.src.box.y = def->nFrameHeight;521blit.src.box.width = def->nFrameWidth;522blit.src.box.height = def->nFrameHeight / 2 ;523blit.src.box.depth = 1;524525blit.dst.resource = dst_buf->resources[1];526blit.dst.format = blit.dst.resource->format;527528blit.dst.box.width = def->nFrameWidth / 2;529blit.dst.box.height = def->nFrameHeight / 2;530blit.dst.box.depth = 1;531blit.filter = PIPE_TEX_FILTER_NEAREST;532533blit.mask = PIPE_MASK_R;534pipe->blit(pipe, &blit);535536/* Copy V */537blit.src.box.x = 0;538blit.mask = PIPE_MASK_G;539pipe->blit(pipe, &blit);540}541542pipe->flush(pipe, NULL, 0);543544box.width = inp->resource->width0;545box.height = inp->resource->height0;546box.depth = inp->resource->depth0;547buf->pBuffer = pipe->texture_map(pipe, inp->resource, 0,548PIPE_MAP_WRITE, &box,549&inp->transfer);550}551552return OMX_ErrorNone;553}554555556