/* * Copyright (c) 2011 Intel Corporation. All Rights Reserved. * Copyright (c) Imagination Technologies Limited, UK * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Elaine Wang <elaine.wang@intel.com> * Zeng Li <zeng.li@intel.com> * */ #include "img_types.h" #include "psb_drv_video.h" #include "psb_surface.h" #include "pnw_cmdbuf.h" #include "pnw_hostjpeg.h" #include "pnw_hostheader.h" #define TOPAZ_PIC_PARAMS_VERBOSE 0 #define MAX_SLICES_PER_PICTURE 72 #define MAX_TOPAZ_CORES 4 #define MAX_TOPAZ_CMD_COUNT (0x1000) #define TH_SKIP_IPE 6 #define TH_INTER 60 #define TH_INTER_QP 10 #define TH_INTER_MAX_LEVEL 1500 #define TH_SKIP_SPE 6 #define SPE_ZERO_THRESHOLD 6 #define MAX_NUM_CORES 2 /* defines used for the second 32 bit word of the coded data header */ /* the average Qp used in this frame */ #define RC_STATUS_FRAME_AVE_QP_MASK 0x0ff /* At least one slice in this frame was large enough for the firmware to * try to reduce it by increasing Qp or skipping MBs */ #define RC_STATUS_FLAG_LARGE_SLICE 0x100 /* At least one slice in this frame was larger than the slice limit */ #define RC_STATUS_FLAG_SLICE_OVERFLOW 0x200 /* The peak bitrate was exceeded for this frame (VCM only) */ #define RC_STATUS_FLAG_BITRATE_OVERFLOW 0x400 #define SKIP_NEXT_FRAME 0x800 /* The next frame should be skipped */ #define IS_H264_ENC(codec) \ (IMG_CODEC_H264_CBR == (codec) || IMG_CODEC_H264_VCM == (codec)) /* commands for topaz,shared with user space driver */ enum drm_pnw_topaz_cmd { /* Common Commands */ MTX_CMDID_NULL, MTX_CMDID_SHUTDOWN, /* Video Commands */ MTX_CMDID_START_PIC, MTX_CMDID_DO_HEADER, MTX_CMDID_ENCODE_SLICE, MTX_CMDID_END_PIC, MTX_CMDID_FLUSH, /* JPEG Commands */ MTX_CMDID_SETQUANT, //!< (data: #JPEG_MTX_QUANT_TABLE)\n MTX_CMDID_RESET_ENCODE, //!< (no data)\n MTX_CMDID_ISSUEBUFF, //!< (data: #MTX_ISSUE_BUFFERS)\n MTX_CMDID_SETUP, //!< (data: #JPEG_MTX_DMA_SETUP)\n\n /* SW Commands */ MTX_CMDID_PAD = 0x7a, //!< Will be ignored by kernel MTX_CMDID_SW_WRITEREG = 0x7b, MTX_CMDID_SW_LEAVE_LOWPOWER = 0x7c, MTX_CMDID_SW_ENTER_LOWPOWER = 0x7e, MTX_CMDID_SW_NEW_CODEC = 0x7f }; /* codecs topaz supports,shared with user space driver */ enum drm_pnw_topaz_codec { IMG_CODEC_JPEG = 0, IMG_CODEC_H264_NO_RC, IMG_CODEC_H264_VBR, IMG_CODEC_H264_CBR, IMG_CODEC_H263_NO_RC, IMG_CODEC_H263_VBR, IMG_CODEC_H263_CBR, IMG_CODEC_MPEG4_NO_RC, IMG_CODEC_MPEG4_VBR, IMG_CODEC_MPEG4_CBR, IMG_CODEC_H264_VCM, //!< H264 low constant bitrate (video conferencing mode) IMG_CODEC_NUM }; typedef struct _RC_PARAMS_ { IMG_UINT32 BitsPerSecond; IMG_UINT32 InitialQp; IMG_UINT32 BUSize; IMG_UINT32 FrameRate; IMG_UINT32 BufferSize; IMG_UINT32 IntraFreq; IMG_UINT16 IDRFreq; IMG_UINT16 MinQP; IMG_BOOL RCEnable; IMG_BOOL FrameSkip; IMG_UINT8 Slices; IMG_UINT32 InitialLevel; IMG_INT32 InitialDelay; IMG_INT8 QCPOffset; IMG_BOOL bDisableFrameSkipping; IMG_BOOL bDisableBitStuffing; IMG_BOOL bBitrateChanged; } IMG_RC_PARAMS; /*! ***************************************************************************** * * @Description Struct describing rate control input parameters * * @Brief Rate control input parameters * ****************************************************************************/ typedef struct { IMG_UINT8 SeInitQP; /* Initial QP for Sequence */ IMG_UINT8 MinQPVal; /* Minimum QP value to use */ IMG_UINT8 MaxQPVal; /* Maximum QP value to use */ IMG_UINT8 MBPerRow; /* Number of MBs Per Row */ IMG_UINT16 MBPerFrm; /* Number of MBs Per Frame */ IMG_UINT16 MBPerBU; /* Number of MBs Per BU */ IMG_UINT16 BUPerFrm; /* Number of BUs Per Frame */ IMG_UINT16 IntraPeriod; /* Intra frame frequency */ IMG_INT32 BitsPerFrm; /* Bits Per Frame */ IMG_INT32 BitsPerBU; /* Bits Per BU */ IMG_INT32 BitsPerMB; /* Bits Per MB */ IMG_INT32 BitRate; /* Bit Rate (bps) */ IMG_INT32 BufferSize; /* Size of Buffer */ IMG_INT32 InitialLevel; /* Initial Level of Buffer */ IMG_INT32 InitialDelay; /* Initial Delay of Buffer */ IMG_UINT8 ScaleFactor; /* Scale Factor (H264 only) */ /* Bitrate that should be targetted as a fraction of 128 * relative to maximum bitrate i32BitRate (VCM mode only)*/ IMG_UINT8 VCMBitrateMargin; IMG_UINT8 HalfFrameRate; /* Half Frame Rate (MP4 only) */ IMG_UINT8 FCode; /* F Code (MP4 only) */ /* TO BE DELETED -- ONCE MP4 RC CODE IS OPTIMISED */ IMG_INT32 BitsPerGOP; /* Bits Per GOP (MP4 only) */ IMG_UINT16 AvQPVal; /* Average QP in Current Picture */ IMG_UINT16 MyInitQP; /* Initial Quantizer */ /* The number of bits of margin to leave before forcing * skipped macroblocks (VCM mode only)*/ IMG_INT32 ForeceSkipMargin; /* A constant used in rate control = * (GopSize/(BufferSize-InitialLevel))*256 */ IMG_UINT32 RCScaleFactor; /* Only used in peak constrained VBR */ IMG_INT32 TransferRate; IMG_INT32 MaxFrameSize; } IN_RC_PARAMS; typedef enum _TH_SKIP_SCALE_ { TH_SKIP_0 = 0, TH_SKIP_12 = 1, TH_SKIP_24 = 2 } TH_SKIP_SCALE; struct context_ENC_s { object_context_p obj_context; /* back reference */ IMG_UINT32 NumCores; /* Number of encode cores in Penwell */ IMG_UINT32 ParallelCores; /* Number of cores to use */ IMG_INT32 BelowParamsBufIdx; IMG_INT16 RawWidth; IMG_INT16 RawHeight; IMG_UINT16 Width; /* ~0xf & (RawWidth + 0xf)*/ IMG_UINT16 Height; /* ~0xf & (RawHeight + 0xf */ IMG_UINT16 Slices; enum drm_pnw_topaz_codec eCodec; IMG_FORMAT eFormat; unsigned int FCode; IMG_RC_PARAMS sRCParams; IMG_INT32 AccessUnitNum; IMG_UINT32 CmdCount; IMG_UINT32 LastSync[2][MAX_TOPAZ_CORES]; IMG_INT32 FrmIdx; IMG_BOOL SliceHeaderReady[MAX_SLICES_PER_PICTURE]; IMG_UINT32 InBuffer; /* total coded data in Byte */ IMG_INT16 HeightMinus16MinusLRBTopOffset; IMG_INT16 HeightMinus32MinusLRBTopOffset; IMG_INT16 HeightMinusLRB_TopAndBottom_OffsetsPlus16; IMG_INT16 HeightMinusLRBSearchHeight; IMG_UINT32 IPEControl; IMG_BOOL SyncSequencer; IMG_UINT32 SliceToCore; /* Core number to send current slice to */ IMG_INT32 LastSliceNum[MAX_TOPAZ_CORES]; /* Slice number of last slice sent to core */ object_surface_p src_surface; object_surface_p ref_surface; object_surface_p dest_surface;/* reconstructed surface */ object_buffer_p coded_buf; /* save previous settings */ object_surface_p previous_src_surface; object_surface_p previous_ref_surface; object_surface_p previous_dest_surface; /* reconstructed surface */ /* point to the place in cmdbuf following START_PIC, the initial_qp will fill into it later */ uint32_t *initial_qp_in_cmdbuf; /* global topaz_params buffer shared by every cmdbuffer * it is because filling InParams for every MB is very time-consuming * and in most cases, we can reuse previous frames buffer */ /* 0 and 1 are for in_parms, 2 is for bellow and above params*/ struct psb_buffer_s topaz_in_params_I; struct psb_buffer_s topaz_in_params_P; struct psb_buffer_s topaz_below_params; /* MB MVs read & written by HW */ struct psb_buffer_s topaz_above_params; /* MB MVs read & written by HW */ uint32_t topaz_buffer_size; uint32_t in_params_size; uint32_t below_params_size; uint32_t above_params_size; /* offset in topaz_param buffer */ uint32_t in_params_ofs; uint32_t below_params_ofs; uint32_t above_params_ofs; uint32_t pic_params_size; uint32_t header_buffer_size; uint32_t seq_header_ofs; uint32_t pic_header_ofs; uint32_t eoseq_header_ofs; uint32_t eostream_header_ofs; uint32_t slice_header_ofs; /*HRD SEI header*/ uint32_t aud_header_ofs; uint32_t sei_buf_prd_ofs; uint32_t sei_pic_tm_ofs; uint32_t sei_pic_fpa_ofs; uint32_t sei_pic_data_size; uint32_t sliceparam_buffer_size; IN_RC_PARAMS in_params_cache; /* following frames reuse the first frame's IN_RC_PARAMS, cache it */ TH_SKIP_SCALE THSkip; uint32_t pic_params_flags; VAEncSliceParameterBuffer *slice_param_cache; uint16_t slice_param_num; IMG_UINT16 MPEG4_vop_time_increment_resolution; /* saved information for FrameSkip redo */ uint32_t MPEG4_vop_time_increment_frameskip; uint32_t MPEG4_picture_type_frameskip; uint8_t profile_idc; uint8_t force_idr_h264; /*If only one slice, it's zero. Otherwise it indicates size of parted coded_buf per slice*/ uint32_t coded_buf_per_slice; /*JPEG context*/ TOPAZSC_JPEG_ENCODER_CONTEXT *jpeg_ctx; /*H264 SEI_INSERTION*/ IMG_BOOL bInserHRDParams; uint32_t max_slice_size; unsigned char *save_seq_header_p; IMG_INT16 num_air_mbs; IMG_INT16 air_threshold; uint32_t buffer_size; uint32_t initial_buffer_fullness; H264_VUI_PARAMS VUI_Params; IMG_BOOL bInsertVUI; /*H264 idr_pic_id field in slice header*/ uint16_t idr_pic_id; unsigned char none_vcl_nal; /*Keep growing and won't be reset on IDR frame*/ uint32_t raw_frame_count; }; typedef struct context_ENC_s *context_ENC_p; /*#define BELOW_PARAMS_SIZE 8*/ #define HEADER_SIZE 128*2 #define BELOW_PARAMS_SIZE 16 #define REGION_TYPE_2D 1 #define REGION_TYPE_LINEAR 0 #define REGION_TYPE_2DREF 3 #define MAX_RESIDUAL_PER_MB_H264 1260 #define ISINTER_FLAGS 0x1 #define ISH264_FLAGS 0x2 #define ISMPEG4_FLAGS 0x4 #define ISH263_FLAGS 0x8 #define DEBLOCK_FRAME 0x10 #define ISRC_FLAGS 0x20 #define ISCBR_FLAGS 0x40 #define ISVCM_FLAGS 0x80 #define ISVBR_FLAGS 0x100 #define ISCFS_FLAGS 0x200 #define INTERLEAVE_TARGET 0x400 #define FIRST_FRAME 0x800 #define SYNC_SEQUENCER 0x1000 #define DEBLOCK_SLICE 0x2000 #define DISABLE_FRAME_SKIPPING 0x4000 //!< Flag indicatest that frame skipping should be disabled. #define DISABLE_BIT_STUFFING 0x8000 //!< Flag indicates that bit stuffing should be disabled. #define SPE_EDGE_LEFT 1 /* ->bMinXRealEdge*/ #define SPE_EDGE_RIGHT 2 /* ->bMaxXRealEdge*/ #define SPE_EDGE_TOP 4 /* ->bMinYRealEdge*/ #define SPE_EDGE_BOTTOM 8 /* ->bMaxYRealEdge*/ #define BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_SIZE 23 #define PTH_SEI_NAL_CPB_REMOVAL_DELAY_SIZE 23 #define PTH_SEI_NAL_DPB_OUTPUT_DELAY_SIZE 7 #define FW_TOKEN_USED 0 #define NOT_USED_BY_TOPAZ 0 typedef struct { /* Transferred into the input params area of the macroblock parameter structure*/ IMG_BYTE CurBlockAddr; IMG_BYTE IPEMin[2]; IMG_BYTE IPEMax[2]; IMG_BYTE RealEdge; /*bMinXRealEdge, bMaxXRealEdge, bMinXRealEdge and bMinYRealEdge*/ /* Surrounding block availability */ IMG_BYTE MVValid; IMG_BYTE ParamsValid; IMG_BYTE bySliceQP; IMG_BYTE bySliceQPC; IMG_BYTE Reserved[6]; /* This is padding to make the transfers 16 bytes aligned*/ /* Transferred into the SW communication section of the macroblock * parameter structure We shall EDMA the whole lot of this into eiob * in one go, and then use two TDMA's to put it into seperate locations * within the macroblock structure */ IMG_UINT32 IPEControl; IMG_UINT32 SPEControl; IMG_UINT32 JMCompControl; IMG_UINT32 VLCControl; } MTX_CURRENT_IN_PARAMS; typedef struct { /* corresponding bytes inside the MB_IN structure: */ IMG_BYTE BlockSizes; /****************/ IMG_BYTE IntraMode; /* */ IMG_BYTE Intra4x4ModesBottom[2]; /* */ IMG_BYTE CodeType; /* [64 : 71] */ IMG_BYTE Reserved2; /* */ /*IMG_BYTE SAD;*/ IMG_BYTE QPy; /* */ IMG_BYTE QPc; /****************/ IMG_BYTE Reserved3[8]; /* This is padding to make the transfers 16 byte aligned*/ IMG_UINT16 LumaSubBlockCoded; /****************/ IMG_BYTE ChromaSubBlockCoded; /* */ IMG_BYTE LumaChromaDCCoded; /* */ /* [129 : 143] */ IMG_BYTE Lambda; /* */ IMG_BYTE Reserved[3]; /* */ /* */ IMG_BYTE Intra4x4ModeDeltas[8]; /****************/ /* Motion vectors */ IMG_UINT16 IntegerMV[16][2]; /* [207 : 144] */ /* input region from host */ } MTX_CURRENT_OUT_PARAMS; typedef struct _PIC_PARAMS_ { IMG_UINT32 SrcYBase; IMG_UINT32 SrcUBase; IMG_UINT32 SrcVBase; IMG_UINT32 DstYBase; IMG_UINT32 DstUVBase; IMG_UINT16 SrcYStride; IMG_UINT16 SrcUVStride; IMG_UINT16 SrcYRowStride; IMG_UINT16 SrcUVRowStride; IMG_UINT16 DstYStride; IMG_UINT16 DstUVStride; IMG_UINT32 CodedBase; IMG_UINT32 BelowParamsInBase; IMG_UINT32 BelowParamsOutBase; IMG_UINT32 AboveParamsBase; IMG_UINT16 Width; IMG_UINT16 Height; IMG_UINT32 Flags; IN_RC_PARAMS sInParams; IMG_UINT16 SearchWidth; IMG_UINT16 SearchHeight; IMG_UINT16 NumSlices; //!< Number of slices in the picture IMG_BOOL16 IsPerSliceOutput; // SEI_INSERTION IMG_UINT64 ClockDivBitrate; IMG_UINT32 MaxBufferMultClockDivBitrate; } PIC_PARAMS; typedef enum { INTRA_MB_OFF = 0, INTRA_MB_AIR = 1, INTRA_MB_SCANNING = 2 } INTRA_MB_OPERATION_MODE; /* ScanningIntraParams */ #define SCANNING_INTRA_MODE_MASK (0x0000000f) #define SCANNING_INTRA_MODE_SHIFT (0) #define SCANNING_INTRA_WIDTH_MASK (0x000000f0) #define SCANNING_INTRA_WIDTH_SHIFT (4) #define SCANNING_INTRA_WIDTH_MAX (15) #define SCANNING_INTRA_STEP_MASK (0x00000f00) #define SCANNING_INTRA_STEP_SHIFT (8) #define SCANNING_INTRA_STEP_MAX (15) #define MTX_FLAG_WB_SKIPFRAME (0x00000002) #define MTX_FLAG_RC_MASK (0xFFFF0000) #define MTX_FLAG_RC_PICPARAM (0x00010000) #define MTX_FLAG_RC_SLICEPARAM (0x00020000) #define MTX_FLAG_RC_BUPARAM (0x00040000) #define MTX_FLAG_RC_GETBUPARAM (0x00080000) #define MTX_FLAG_RC_FRM_LEN (0x00100000) /* This holds the data that is needed at the start of a slice */ typedef struct _SLICE_PARAMS_ { IMG_UINT16 SliceStartRowNum; IMG_UINT16 SliceHeight; /*Height of slice in pixels*/ IMG_UINT32 RefYBase; IMG_UINT32 RefUVBase; IMG_UINT16 RefYStride; IMG_UINT16 RefUVStride; IMG_UINT16 RefYRowStride; IMG_UINT16 RefUVRowStride; IMG_UINT32 HostCtx; /*Host context to insert into coded data header*/ IMG_UINT32 Flags; IMG_UINT32 MaxSliceSize; IMG_UINT32 FCode; /*FCode value MP4 only*/ /*Pointer to array of MTX_CURRENT_IN_PARAMS for each MB*/ IMG_UINT32 InParamsBase; /*Maximum number of Adaptive intra refresh macroblocks for this slice*/ IMG_INT16 NumAirMBs; /*Theshold value used in Adaptive intra refresh calculation.*/ IMG_INT16 AirThreshold; IMG_UINT32 ScanningIntraParams; } SLICE_PARAMS; enum { CBR = 0, VBR } eRCMode; enum { EH263 = 0, EMpeg4 = 1, EH264 = 2, EHJpeg = 3 } eEncodingFormat; #define VAEncSliceParameter_Equal(src, dst) \ (((src)->start_row_number == (dst)->start_row_number) \ && ((src)->slice_height == (dst)->slice_height) \ && ((src)->slice_flags.bits.is_intra == (dst)->slice_flags.bits.is_intra) \ && ((src)->slice_flags.bits.disable_deblocking_filter_idc == (dst)->slice_flags.bits.disable_deblocking_filter_idc)) #define VAEncSliceParameter_LightEqual(src, dst) \ (((src)->start_row_number == (dst)->start_row_number) \ && ((src)->slice_height == (dst)->slice_height) \ && ((src)->slice_flags.bits.disable_deblocking_filter_idc == (dst)->slice_flags.bits.disable_deblocking_filter_idc)) #define SURFACE_INFO_SKIP_FLAG_SETTLED 0X80000000 #define GET_SURFACE_INFO_skipped_flag(psb_surface) ((int) (psb_surface->extra_info[5])) #define SET_SURFACE_INFO_skipped_flag(psb_surface, value) psb_surface->extra_info[5] = (SURFACE_INFO_SKIP_FLAG_SETTLED | value) #define CLEAR_SURFACE_INFO_skipped_flag(psb_surface) psb_surface->extra_info[5] = 0 VAStatus pnw_CreateContext(object_context_p obj_context, object_config_p obj_config, unsigned char is_JPEG); void pnw__setup_rcdata(context_ENC_p ctx, PIC_PARAMS *psPicParams, IMG_RC_PARAMS *rc_params); void pnw_DestroyContext( object_context_p obj_context ); VAStatus pnw_BeginPicture(context_ENC_p ctx); VAStatus pnw_EndPicture(context_ENC_p ctx); void pnw_setup_slice_params( context_ENC_p ctx, IMG_UINT16 YSliceStartPos, IMG_UINT16 SliceHeight, IMG_BOOL IsIntra, IMG_BOOL VectorsValid, int bySliceQP); IMG_UINT32 pnw__send_encode_slice_params( context_ENC_p ctx, IMG_BOOL IsIntra, IMG_UINT16 CurrentRow, IMG_UINT8 DeblockIDC, IMG_UINT32 FrameNum, IMG_UINT16 SliceHeight, IMG_UINT16 CurrentSlice); VAStatus pnw_RenderPictureParameter(context_ENC_p ctx, int core); void pnw_reset_encoder_params(context_ENC_p ctx); unsigned int pnw__get_ipe_control(enum drm_pnw_topaz_codec eEncodingFormat); VAStatus pnw_set_bias(context_ENC_p ctx, int core);