1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 * Copyright (c) Imagination Technologies Limited, UK
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 *    Zeng Li <zeng.li@intel.com>
27 *    Shengquan Yuan  <shengquan.yuan@intel.com>
28 *    Binglin Chen <binglin.chen@intel.com>
29 *
30 */
31
32
33
34#include "psb_drv_video.h"
35
36#include "lnc_hostcode.h"
37#include "hwdefs/topaz_defs.h"
38#include "psb_def.h"
39#include "psb_cmdbuf.h"
40#include <stdio.h>
41#include "psb_output.h"
42#include <wsbm/wsbm_manager.h>
43#include "lnc_hostheader.h"
44#include "psb_drv_debug.h"
45
46#define ALIGN_TO(value, align) ((value + align - 1) & ~(align - 1))
47#define PAGE_ALIGN(value) ALIGN_TO(value, 4096)
48
49static VAStatus lnc__alloc_context_buffer(context_ENC_p ctx)
50{
51    int width, height;
52    VAStatus vaStatus = VA_STATUS_SUCCESS;
53
54    /* width and height should be source surface's w and h or ?? */
55    width = ctx->obj_context->picture_width;
56    height = ctx->obj_context->picture_height;
57
58    ctx->pic_params_size  = 256;
59
60    ctx->header_buffer_size = 4 * HEADER_SIZE + MAX_SLICES_PER_PICTURE * HEADER_SIZE;
61
62    ctx->seq_header_ofs = 0;
63    ctx->pic_header_ofs = HEADER_SIZE;
64    ctx->eoseq_header_ofs = 2 * HEADER_SIZE;
65    ctx->eostream_header_ofs = 3 * HEADER_SIZE;
66    ctx->slice_header_ofs = 4 * HEADER_SIZE;
67
68    ctx->sliceparam_buffer_size = ((sizeof(SLICE_PARAMS) + 15) & 0xfff0) * MAX_SLICES_PER_PICTURE;
69
70    /* All frame share same MTX_CURRENT_IN_PARAMS and above/bellow param
71     * create MTX_CURRENT_IN_PARAMS buffer seperately
72     * every MB has one MTX_CURRENT_IN_PARAMS structure, and the (N+1) frame can
73     * reuse (N) frame's structure
74     */
75    ctx->in_params_size = (10 + width * height / (16 * 16)) * sizeof(MTX_CURRENT_IN_PARAMS);
76    ctx->bellow_params_size = BELOW_PARAMS_SIZE * width * height / (16 * 16) * 16;
77    ctx->above_params_size = (width * height / 16) * 128 + 15;
78
79    ctx->topaz_buffer_size = ctx->in_params_size + /* MTX_CURRENT_IN_PARAMS size */
80                             ctx->bellow_params_size + /* above_params */
81                             ctx->above_params_size; /* above_params */
82
83    vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_I);
84    vaStatus |= psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_P);
85    vaStatus |= psb_buffer_create(ctx->obj_context->driver_data, ctx->above_params_size + ctx->bellow_params_size, psb_bt_cpu_vpu, &ctx->topaz_above_bellow_params);
86
87    ctx->in_params_ofs = 0;
88    ctx->bellow_params_ofs = 0;
89    ctx->above_params_ofs = ctx->bellow_params_ofs + ctx->bellow_params_size;
90
91    return vaStatus;
92}
93
94unsigned int lnc__get_ipe_control(enum drm_lnc_topaz_codec  eEncodingFormat)
95{
96    unsigned int RegVal = 0;
97
98    RegVal = F_ENCODE(2, MVEA_CR_IPE_GRID_FINE_SEARCH) |
99             F_ENCODE(0, MVEA_CR_IPE_GRID_SEARCH_SIZE) |
100             F_ENCODE(1, MVEA_CR_IPE_Y_FINE_SEARCH);
101
102    switch (eEncodingFormat) {
103    case IMG_CODEC_H263_NO_RC:
104    case IMG_CODEC_H263_VBR:
105    case IMG_CODEC_H263_CBR:
106        RegVal |= F_ENCODE(0, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(0, MVEA_CR_IPE_ENCODING_FORMAT);
107        break;
108    case IMG_CODEC_MPEG4_NO_RC:
109    case IMG_CODEC_MPEG4_VBR:
110    case IMG_CODEC_MPEG4_CBR:
111        RegVal |= F_ENCODE(1, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(1, MVEA_CR_IPE_ENCODING_FORMAT);
112    default:
113        break;
114    case IMG_CODEC_H264_NO_RC:
115    case IMG_CODEC_H264_VBR:
116    case IMG_CODEC_H264_CBR:
117    case IMG_CODEC_H264_VCM:
118        RegVal |= F_ENCODE(2, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(2, MVEA_CR_IPE_ENCODING_FORMAT);
119        break;
120    }
121    RegVal |= F_ENCODE(6, MVEA_CR_IPE_Y_CANDIDATE_NUM);
122    return RegVal;
123}
124
125
126void lnc_DestroyContext(object_context_p obj_context)
127{
128    context_ENC_p ctx;
129    ctx = (context_ENC_p)obj_context->format_data;
130    if (NULL != ctx->slice_param_cache)
131        free(ctx->slice_param_cache);
132    if (NULL == ctx->save_seq_header_p)
133        free(ctx->save_seq_header_p);
134    free(obj_context->format_data);
135    obj_context->format_data = NULL;
136}
137
138VAStatus lnc_CreateContext(
139    object_context_p obj_context,
140    object_config_p obj_config)
141{
142    int width, height;
143    context_ENC_p ctx;
144    VAStatus vaStatus;
145
146    width = obj_context->picture_width;
147    height = obj_context->picture_height;
148    ctx = (context_ENC_p) calloc(1, sizeof(struct context_ENC_s));
149    if (NULL == ctx) {
150        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
151        DEBUG_FAILURE;
152        return vaStatus;
153    }
154
155    obj_context->format_data = (void*) ctx;
156    ctx->obj_context = obj_context;
157
158    ctx->RawWidth = (unsigned short) width;
159    ctx->RawHeight = (unsigned short) height;
160
161    ctx->Width = (unsigned short)(~0xf & (width + 0xf));
162    ctx->Height = (unsigned short)(~0xf & (height + 0xf));
163
164    ctx->HeightMinus16MinusLRBTopOffset = ctx->Height - (MVEA_LRB_TOP_OFFSET + 16);
165    ctx->HeightMinus32MinusLRBTopOffset = ctx->Height - (MVEA_LRB_TOP_OFFSET + 32);
166    ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16 = ctx->Height - (MVEA_LRB_TOP_OFFSET + MVEA_LRB_TOP_OFFSET + 16);
167    ctx->HeightMinusLRBSearchHeight = ctx->Height - MVEA_LRB_SEARCH_HEIGHT;
168
169    ctx->FCode = 0;
170
171    ctx->sRCParams.VCMBitrateMargin = 0;
172    ctx->sRCParams.BufferSize = 0;
173    ctx->sRCParams.InitialQp = 0;
174    ctx->sRCParams.MinQP = 0;
175
176    vaStatus = lnc__alloc_context_buffer(ctx);
177
178    return vaStatus;
179}
180
181
182VAStatus lnc_BeginPicture(context_ENC_p ctx)
183{
184    VAStatus vaStatus = VA_STATUS_SUCCESS;
185    lnc_cmdbuf_p cmdbuf;
186    int ret;
187
188    ctx->src_surface = ctx->obj_context->current_render_target;
189
190    /* clear frameskip flag to 0 */
191    CLEAR_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface);
192
193    /* Initialise the command buffer */
194    ret = lnc_context_get_next_cmdbuf(ctx->obj_context);
195    if (ret) {
196        drv_debug_msg(VIDEO_DEBUG_GENERAL, "get next cmdbuf fail\n");
197        vaStatus = VA_STATUS_ERROR_UNKNOWN;
198        return vaStatus;
199    }
200    cmdbuf = ctx->obj_context->lnc_cmdbuf;
201
202    /* map start_pic param */
203    vaStatus = psb_buffer_map(&cmdbuf->pic_params, &cmdbuf->pic_params_p);
204    if (vaStatus) {
205        return vaStatus;
206    }
207    vaStatus = psb_buffer_map(&cmdbuf->header_mem, &cmdbuf->header_mem_p);
208    if (vaStatus) {
209        psb_buffer_unmap(&cmdbuf->pic_params);
210        return vaStatus;
211    }
212
213    vaStatus = psb_buffer_map(&cmdbuf->slice_params, &cmdbuf->slice_params_p);
214    if (vaStatus) {
215        psb_buffer_unmap(&cmdbuf->pic_params);
216        psb_buffer_unmap(&cmdbuf->header_mem);
217        return vaStatus;
218    }
219
220    /* only map topaz param when necessary */
221    cmdbuf->topaz_in_params_I_p = NULL;
222    cmdbuf->topaz_in_params_P_p = NULL;
223    cmdbuf->topaz_above_bellow_params_p = NULL;
224
225    if (ctx->obj_context->frame_count == 0) { /* first picture */
226        psb_driver_data_p driver_data = ctx->obj_context->driver_data;
227
228        lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_SW_NEW_CODEC, 3, driver_data->drm_context);
229        lnc_cmdbuf_insert_command_param(cmdbuf, ctx->eCodec);
230        lnc_cmdbuf_insert_command_param(cmdbuf, (ctx->Width << 16) | ctx->Height);
231    }
232
233    /* insert START_PIC command */
234    lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_START_PIC, 3, ctx->obj_context->frame_count);
235    /* write the address of structure PIC_PARAMS following command MTX_CMDID_START_PIC
236     * the content of PIC_PARAMS is filled when RenderPicture(...,VAEncPictureParameterBufferXXX)
237     */
238    RELOC_CMDBUF(cmdbuf->cmd_idx, 0, &cmdbuf->pic_params);
239    cmdbuf->cmd_idx++;
240    ctx->initial_qp_in_cmdbuf = cmdbuf->cmd_idx; /* remember the place */
241    cmdbuf->cmd_idx++;
242
243    ctx->obj_context->slice_count = 0;
244
245    /* no RC paramter provided in vaBeginPicture
246     * so delay RC param setup into vaRenderPicture(SequenceHeader...)
247     */
248    return vaStatus;
249}
250
251
252VAStatus lnc_RenderPictureParameter(context_ENC_p ctx)
253{
254    PIC_PARAMS *psPicParams;    /* PIC_PARAMS has been put in lnc_hostcode.h */
255    object_surface_p src_surface;
256    unsigned int srf_buf_offset;
257    object_surface_p rec_surface;
258    object_surface_p ref_surface;
259    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
260    VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;
261
262    psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
263
264    /* second frame will reuse some rate control parameters (IN_PARAMS_MP4)
265     * so only memset picture parames except IN_PARAMS
266     * BUT now IN_RC_PARAMS was reload from the cache, so it now can
267     * memset entirE PIC_PARAMS
268     */
269    memset(psPicParams, 0, (int)((unsigned char *)&psPicParams->sInParams - (unsigned char *)psPicParams));
270
271    src_surface = ctx->src_surface;
272    if (NULL == src_surface) {
273        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
274        DEBUG_FAILURE;
275        return vaStatus;
276    }
277
278    rec_surface = ctx->dest_surface;
279    if (NULL == rec_surface) {
280        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
281        DEBUG_FAILURE;
282        return vaStatus;
283    }
284
285    /*The fisrt frame always is I frame and the content of reference frame wouldn't be used.
286     * But the heights of ref and dest frame should be the same.
287     * That allows Topaz to keep its motion vectors up to date, which helps maintain performance */
288    if (ctx->obj_context->frame_count == 0)
289        ctx->ref_surface = ctx->dest_surface;
290
291    ref_surface = ctx->ref_surface;
292    if (NULL == ref_surface) {
293        vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
294        DEBUG_FAILURE;
295        return vaStatus;
296    }
297
298    /* clear frameskip flag */
299    CLEAR_SURFACE_INFO_skipped_flag(rec_surface->psb_surface);
300    CLEAR_SURFACE_INFO_skipped_flag(ref_surface->psb_surface);
301
302    /* Write video data byte offset into Coded buffer
303     * If it is here, it will be a SYNC point, which have performance impact
304     * Move to psb__CreateBuffer
305     vaStatus = psb_buffer_map(ctx->coded_buf->psb_buffer, &pBuffer);
306     if(vaStatus) {
307     DEBUG_FAILURE;
308     return vaStatus;
309     }
310     *(IMG_UINT32 *)(pBuffer+8) = 16;
311     psb_buffer_unmap(ctx->coded_buf->psb_buffer);
312    */
313
314    psPicParams->SrcYStride = src_surface->psb_surface->stride;
315    switch (ctx->eFormat) {
316    case IMG_CODEC_IYUV:        /* IYUV */
317    case IMG_CODEC_PL8:
318        psPicParams->SrcUVStride = src_surface->psb_surface->stride / 2;
319        psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2;
320        break;
321    case IMG_CODEC_IMC2:    /* IMC2 */
322    case IMG_CODEC_PL12:
323        psPicParams->SrcUVStride = src_surface->psb_surface->stride;
324        psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16;
325        break;
326    default:
327        break;
328    }
329    psPicParams->SrcYRowStride    = src_surface->psb_surface->stride * 16;
330    /* psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2; */
331
332    /* Dest(rec) stride
333     * The are now literally Dst stride (not equivalent to 'offset to next row')
334     */
335#ifdef VA_EMULATOR
336    /* only for simulator, va-emulator needs the actually stride for
337     * reconstructed frame transfer (va-emulator->driver)
338     */
339    psPicParams->DstYStride = rec_surface->psb_surface->stride;
340    psPicParams->DstUVStride = rec_surface->psb_surface->stride;
341    psPicParams->DstYRowStride = rec_surface->psb_surface->stride * 16;
342    psPicParams->DstUVRowStride = rec_surface->psb_surface->stride * 16 / 2;
343#else
344    psPicParams->DstYStride = rec_surface->height * 16;
345    psPicParams->DstUVStride = rec_surface->height * 16 / 2;
346    psPicParams->DstYRowStride = psPicParams->DstYStride;
347    psPicParams->DstUVRowStride = psPicParams->DstUVStride;
348#endif
349
350    psPicParams->InParamsRowStride = (ctx->obj_context->picture_width / 16) * 256;
351    psPicParams->BelowParamRowStride = (ctx->obj_context->picture_width / 16) * 32;
352
353    psPicParams->Width  = ctx->Width;
354    psPicParams->Height = ctx->Height;
355
356    /* not sure why we are setting this up here... */
357    psPicParams->Flags = 0;
358    switch (ctx->eCodec) {
359    case IMG_CODEC_H264_NO_RC:
360    case IMG_CODEC_H264_VBR:
361    case IMG_CODEC_H264_CBR:
362    case IMG_CODEC_H264_VCM:
363        psPicParams->Flags |= ISH264_FLAGS;
364        break;
365    case IMG_CODEC_H263_VBR:
366    case IMG_CODEC_H263_CBR:
367    case IMG_CODEC_H263_NO_RC:
368        psPicParams->Flags |= ISH263_FLAGS;
369        break;
370    case IMG_CODEC_MPEG4_NO_RC:
371    case IMG_CODEC_MPEG4_VBR:
372    case IMG_CODEC_MPEG4_CBR:
373        psPicParams->Flags |= ISMPEG4_FLAGS;
374        break;
375    default:
376        return VA_STATUS_ERROR_UNKNOWN;
377    }
378
379    switch (ctx->eCodec) {
380    case IMG_CODEC_H264_VBR:
381    case IMG_CODEC_MPEG4_VBR:
382    case IMG_CODEC_H263_VBR:
383        psPicParams->Flags |= ISVBR_FLAGS;
384        break;
385    case IMG_CODEC_H264_VCM:
386        psPicParams->Flags |= ISVCM_FLAGS;
387        /* drop through to CBR case */
388    case IMG_CODEC_H263_CBR:
389    case IMG_CODEC_H264_CBR:
390    case IMG_CODEC_MPEG4_CBR:
391        psPicParams->Flags |= ISCBR_FLAGS;
392        break;
393    case IMG_CODEC_MPEG4_NO_RC:
394    case IMG_CODEC_H263_NO_RC:
395    case IMG_CODEC_H264_NO_RC:
396        break;
397    default:
398        return VA_STATUS_ERROR_UNKNOWN;
399    }
400
401
402    if (ctx->sRCParams.RCEnable) {
403        /* for the first frame, will setup RC params in EndPicture */
404        if (ctx->obj_context->frame_count > 0) { /* reuse in_params parameter */
405            /* reload IN_RC_PARAMS from cache */
406            memcpy(&psPicParams->sInParams, &ctx->in_params_cache, sizeof(IN_RC_PARAMS));
407
408            /* delay these into END_PICTURE timeframe */
409            /*
410            psPicParams->sInParams.BitsTransmitted = ctx->sRCParams.BitsTransmitted;
411            */
412        }
413    } else
414        psPicParams->sInParams.SeInitQP = ctx->sRCParams.InitialQp;
415
416    /* some relocations have to been done here */
417    srf_buf_offset = src_surface->psb_surface->buf.buffer_ofs;
418    if (src_surface->psb_surface->buf.type == psb_bt_camera)
419        drv_debug_msg(VIDEO_DEBUG_GENERAL, "src surface GPU offset 0x%08x, luma offset 0x%08x\n",
420                                 wsbmBOOffsetHint(src_surface->psb_surface->buf.drm_buf), srf_buf_offset);
421
422    RELOC_PIC_PARAMS(&psPicParams->SrcYBase, srf_buf_offset, &src_surface->psb_surface->buf);
423    switch (ctx->eFormat) {
424    case IMG_CODEC_IYUV:
425    case IMG_CODEC_PL8:
426    case IMG_CODEC_PL12:
427        RELOC_PIC_PARAMS(&psPicParams->SrcUBase,
428                         srf_buf_offset + src_surface->psb_surface->chroma_offset,
429                         &src_surface->psb_surface->buf);
430
431        RELOC_PIC_PARAMS(&psPicParams->SrcVBase,
432                         srf_buf_offset + src_surface->psb_surface->chroma_offset,
433                         &src_surface->psb_surface->buf);
434
435        break;
436    case IMG_CODEC_IMC2:
437    case IMG_CODEC_NV12:
438        break;
439    }
440
441    /*
442     * Do not forget this!
443     * MTXWriteMem(MTXData.ui32CCBCtrlAddr + MTX_CCBCTRL_QP, sRCParams.ui32InitialQp);
444     */
445    /* following START_PIC, insert initial QP */
446    *ctx->initial_qp_in_cmdbuf = ctx->sRCParams.InitialQp;
447
448
449    RELOC_PIC_PARAMS(&psPicParams->DstYBase, 0, &rec_surface->psb_surface->buf);
450
451    RELOC_PIC_PARAMS(&psPicParams->DstUVBase,
452                     rec_surface->psb_surface->stride * rec_surface->height,
453                     &rec_surface->psb_surface->buf);
454
455    RELOC_PIC_PARAMS(&psPicParams->CodedBase, 0, ctx->coded_buf->psb_buffer);
456
457    /* MTX_CURRENT_IN_PARAMS buffer is seperate buffer now */
458    /*The type of frame will decide psPicParams->InParamsBase should
459     * use cmdbuf->topaz_in_params_P or cmdbuf->topaz_in_params_I*/
460    /*RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_P);*/
461    RELOC_PIC_PARAMS(&psPicParams->BelowParamsBase, ctx->bellow_params_ofs, cmdbuf->topaz_above_bellow_params);
462    RELOC_PIC_PARAMS(&psPicParams->AboveParamsBase, ctx->above_params_ofs, cmdbuf->topaz_above_bellow_params);
463
464    return VA_STATUS_SUCCESS;
465}
466
467static VAStatus lnc__PatchBitsConsumedInRCParam(context_ENC_p ctx)
468{
469    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
470    /* PIC_PARAMS  *psPicParams = cmdbuf->pic_params_p; */
471    VAStatus vaStatus;
472
473    (void)cmdbuf;
474    /* it will wait until last encode session is done */
475    /* now it just wait the last session is done and the frame skip
476     * is  */
477    drv_debug_msg(VIDEO_DEBUG_GENERAL, "will patch bits consumed for rc\n");
478    if (ctx->pprevious_coded_buf) {
479        vaStatus = psb_buffer_sync(ctx->pprevious_coded_buf->psb_buffer);
480        if (vaStatus)
481            return vaStatus;
482    }
483
484    return VA_STATUS_SUCCESS;
485}
486
487static VAStatus lnc_RedoRenderPictureSkippedFrame(context_ENC_p ctx)
488{
489    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
490    VAStatus vaStatus = VA_STATUS_SUCCESS;
491    int i = 0;
492
493    /* reset cmdbuf to skip existing picture/slice DO_HEAD commands */
494    cmdbuf->cmd_idx = cmdbuf->cmd_idx_saved_frameskip;
495
496    switch (ctx->eCodec) {
497    case IMG_CODEC_H263_CBR: /* H263 don't need picture header/slice header, only reset command buf */
498    case IMG_CODEC_H263_VBR:
499        break;
500    case IMG_CODEC_H264_VBR:
501    case IMG_CODEC_H264_CBR: /* slice header needs redo */
502    case IMG_CODEC_H264_VCM: {
503        /* only need one slice header here */
504        VAEncSliceParameterBuffer *pBuffer = &ctx->slice_param_cache[i];
505        unsigned int MBSkipRun, FirstMBAddress;
506        int deblock_on;
507
508        if ((pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 0)
509            || (pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 2))
510            deblock_on = IMG_TRUE;
511        else
512            deblock_on = IMG_FALSE;
513
514        if (1 /* ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip */) /* we know it is true */
515            MBSkipRun = (ctx->Width * ctx->Height) / 256;
516        else
517            MBSkipRun = 0;
518
519        FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16;
520        /* Insert Do Header command, relocation is needed */
521
522        lnc__H264_prepare_slice_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->slice_header_ofs + i * HEADER_SIZE),
523                                       0, /*pBuffer->slice_flags.bits.is_intra*/
524                                       pBuffer->slice_flags.bits.disable_deblocking_filter_idc,
525                                       ctx->obj_context->frame_count,
526                                       FirstMBAddress,
527                                       MBSkipRun,
528                                       (ctx->obj_context->frame_count == 0),
529                                       pBuffer->slice_flags.bits.uses_long_term_ref,
530                                       pBuffer->slice_flags.bits.is_long_term_ref,
531                                       ctx->idr_pic_id);
532
533
534        lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, (i << 2) | 2);
535        RELOC_CMDBUF(cmdbuf->cmd_idx++,
536                     ctx->slice_header_ofs + i * HEADER_SIZE,
537                     &cmdbuf->header_mem);
538    }
539
540    break;
541    case IMG_CODEC_MPEG4_VBR:
542    case IMG_CODEC_MPEG4_CBR: /* only picture header need redo */
543        lnc__MPEG4_prepare_vop_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->pic_header_ofs),
544                                      IMG_FALSE /* bIsVOPCoded is false now */,
545                                      ctx->MPEG4_vop_time_increment_frameskip, /* In testbench, this should be FrameNum */
546                                      4,/* default value is 4,search range */
547                                      ctx->MPEG4_picture_type_frameskip,
548                                      ctx->MPEG4_vop_time_increment_resolution/* defaule value */);
549
550        lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 1);
551        RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->pic_header_ofs, &cmdbuf->header_mem);
552        vaStatus = lnc_RenderPictureParameter(ctx);
553        break;
554    default:
555        drv_debug_msg(VIDEO_DEBUG_ERROR, "Non-RC mode should be here for FrameSkip handling\n");
556        ASSERT(0);
557    }
558
559    return vaStatus;
560}
561
562static VAStatus lnc_SetupRCParam(context_ENC_p ctx)
563{
564    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
565    PIC_PARAMS  *psPicParams = (PIC_PARAMS  *)cmdbuf->pic_params_p;
566    int origin_qp;/* in DDK setup_rc will change qp strangly,
567                   * just for keep same with DDK
568                   */
569
570    origin_qp = ctx->sRCParams.InitialQp;
571
572    drv_debug_msg(VIDEO_DEBUG_GENERAL, "will setup rc data\n");
573
574    psPicParams->Flags |= ISRC_FLAGS;
575    lnc__setup_rcdata(ctx, psPicParams, &ctx->sRCParams);
576
577    /* restore it, just keep same with DDK */
578    ctx->sRCParams.InitialQp = origin_qp;
579
580    /* save IN_RC_PARAMS into the cache */
581    memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
582
583    return VA_STATUS_SUCCESS;
584}
585
586static VAStatus lnc_UpdateRCParam(context_ENC_p ctx)
587{
588    int origin_qp;
589    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
590    PIC_PARAMS  *psPicParams = (PIC_PARAMS  *)cmdbuf->pic_params_p;
591
592    origin_qp = ctx->sRCParams.InitialQp;
593
594    drv_debug_msg(VIDEO_DEBUG_GENERAL, "will update rc data\n");
595    lnc__update_rcdata(ctx, psPicParams, &ctx->sRCParams);
596
597    /* set minQP if hosts set minQP */
598    if (ctx->sRCParams.MinQP)
599        psPicParams->sInParams.MinQPVal = ctx->sRCParams.MinQP;
600
601    /* if seinitqp is set, restore the value hosts want */
602    if (origin_qp) {
603        psPicParams->sInParams.SeInitQP = origin_qp;
604        psPicParams->sInParams.MyInitQP = origin_qp;
605        ctx->sRCParams.InitialQp = origin_qp;
606    }
607
608    /* save IN_RC_PARAMS into the cache */
609    memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
610
611    return VA_STATUS_SUCCESS;
612}
613
614static VAStatus lnc_PatchRCMode(context_ENC_p ctx)
615{
616    int frame_skip = 0;
617
618    drv_debug_msg(VIDEO_DEBUG_GENERAL, "will patch rc data\n");
619    /* it will ensure previous encode finished */
620    lnc__PatchBitsConsumedInRCParam(ctx);
621
622    /* get frameskip flag */
623    lnc_surface_get_frameskip(ctx->obj_context->driver_data, ctx->src_surface->psb_surface, &frame_skip);
624    /* current frame is skipped
625     * redo RenderPicture with FrameSkip set
626     */
627    if (frame_skip == 1)
628        lnc_RedoRenderPictureSkippedFrame(ctx);
629
630    return VA_STATUS_SUCCESS;
631}
632
633VAStatus lnc_EndPicture(context_ENC_p ctx)
634{
635    VAStatus vaStatus = VA_STATUS_SUCCESS;
636    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
637
638    if (ctx->sRCParams.RCEnable == IMG_TRUE) {
639        if (ctx->obj_context->frame_count == 0)
640            lnc_SetupRCParam(ctx);
641        else if (ctx->update_rc_control)
642            lnc_UpdateRCParam(ctx);
643        else
644            lnc_PatchRCMode(ctx);
645    }
646    ctx->update_rc_control = 0;
647
648    /* save current settings */
649    ctx->previous_src_surface = ctx->src_surface;
650    ctx->previous_ref_surface = ctx->ref_surface;
651    ctx->previous_dest_surface = ctx->dest_surface; /* reconstructed surface */
652    ctx->pprevious_coded_buf = ctx->previous_coded_buf;
653    ctx->previous_coded_buf = ctx->coded_buf;
654
655    lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_END_PIC, 3, 0);
656    lnc_cmdbuf_insert_command_param(cmdbuf, 0);/* two meaningless parameters */
657    lnc_cmdbuf_insert_command_param(cmdbuf, 0);
658    psb_buffer_unmap(&cmdbuf->pic_params);
659    psb_buffer_unmap(&cmdbuf->header_mem);
660    psb_buffer_unmap(&cmdbuf->slice_params);
661
662    /* unmap MTX_CURRENT_IN_PARAMS buffer only when it is mapped */
663    if (cmdbuf->topaz_in_params_I_p != NULL) {
664        psb_buffer_unmap(cmdbuf->topaz_in_params_I);
665        cmdbuf->topaz_in_params_I_p = NULL;
666    }
667
668    if (cmdbuf->topaz_in_params_P_p != NULL) {
669        psb_buffer_unmap(cmdbuf->topaz_in_params_P);
670        cmdbuf->topaz_in_params_P_p = NULL;
671    }
672
673    if (cmdbuf->topaz_above_bellow_params_p != NULL) {
674        psb_buffer_unmap(cmdbuf->topaz_above_bellow_params);
675        cmdbuf->topaz_above_bellow_params_p = NULL;
676    }
677
678    if (lnc_context_flush_cmdbuf(ctx->obj_context)) {
679        vaStatus = VA_STATUS_ERROR_UNKNOWN;
680    }
681
682    return vaStatus;
683}
684
685static void lnc__setup_busize(context_ENC_p ctx)
686{
687    unsigned int old_busize = ctx->sRCParams.BUSize;
688
689    /* it is called at EndPicture, we should now the Slice number */
690    ctx->Slices = ctx->obj_context->slice_count;
691
692    /* if no BU size is given then pick one ourselves */
693    if (ctx->sRCParams.BUSize != 0)  { /* application provided BUSize */
694        IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
695        IMG_UINT32 BUs;
696        IMG_INT32  SliceHeight;
697
698        MBs     = ctx->Height * ctx->Width / (16 * 16);
699
700        SliceHeight     = ctx->Height / ctx->Slices;
701        /* SliceHeight += 15; */
702        SliceHeight &= ~15;
703
704        MBsperSlice     = (SliceHeight * ctx->Width) / (16 * 16);
705        MBsLastSlice    = MBs - (MBsperSlice * (ctx->Slices - 1));
706
707        /* they have given us a basic unit so validate it */
708        if (ctx->sRCParams.BUSize < 6) {
709            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small, must be greater than 6\n");
710            ctx->sRCParams.BUSize = 0; /* need repatch */;
711        }
712        if (ctx->sRCParams.BUSize > MBsperSlice) {
713            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than the number of macroblocks in a slice\n");
714            ctx->sRCParams.BUSize = 0; /* need repatch */;
715        }
716        if (ctx->sRCParams.BUSize > MBsLastSlice) {
717            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than number of macroblocks in the last slice\n");
718            ctx->sRCParams.BUSize = 0; /* need repatch */;
719        }
720        BUs = MBsperSlice / ctx->sRCParams.BUSize;
721        if ((BUs * ctx->sRCParams.BUSize) != MBsperSlice)   {
722            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size not an integer divisor of MB's in a slice");
723            ctx->sRCParams.BUSize = 0; /* need repatch */;
724        }
725        if (BUs > 200) {
726            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
727            ctx->sRCParams.BUSize = 0; /* need repatch */;
728        }
729        BUs = MBsLastSlice / ctx->sRCParams.BUSize;
730        if (BUs > 200) {
731            drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
732            ctx->sRCParams.BUSize = 0; /* need repatch */;
733        }
734    }
735
736    if (ctx->sRCParams.BUSize == 0)  {
737        IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
738        IMG_UINT32 BUs, BUsperSlice, BUsLastSlice;
739        IMG_INT32  SliceHeight;
740
741        MBs     = ctx->Height * ctx->Width / (16 * 16);
742
743        SliceHeight     = ctx->Height / ctx->Slices;
744        /* SliceHeight += 15; */
745        SliceHeight &= ~15;
746
747        MBsperSlice     = (SliceHeight * ctx->Width) / (16 * 16);
748        MBsLastSlice = MBs - (MBsperSlice * (ctx->Slices - 1));
749
750        /* we have to verify that MBs is divisiable by BU AND that BU is > pipeline length */
751        if (ctx->sRCParams.BUSize < 6)  {
752            ctx->sRCParams.BUSize = 6;
753        }
754
755        BUs = MBs / ctx->sRCParams.BUSize;
756        while (BUs*ctx->sRCParams.BUSize != MBs) {
757            ctx->sRCParams.BUSize++;
758            BUs = MBs / ctx->sRCParams.BUSize;
759        }
760
761        /* Check number of BUs in the pipe is less than maximum number allowed 200  */
762        BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
763        BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
764        while ((BUsperSlice  *(ctx->Slices - 1) + BUsLastSlice) > 200)  {
765            ctx->sRCParams.BUSize++;
766            BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
767            BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
768        }
769
770        /* Check whether there are integer number of BUs in the slices  */
771        BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
772        BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
773        while ((BUsperSlice*ctx->sRCParams.BUSize != MBsperSlice) ||
774               (BUsLastSlice*ctx->sRCParams.BUSize != MBsLastSlice))   {
775            ctx->sRCParams.BUSize++;
776            BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
777            BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
778        }
779
780        if (ctx->sRCParams.BUSize != old_busize)
781            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Patched Basic unit to %d (original=%d)\n", ctx->sRCParams.BUSize, old_busize);
782    }
783}
784
785
786/***********************************************************************************
787 * Function Name      : SetupRCData
788 * Inputs             :
789 * Outputs            :
790 * Returns            :
791 * Description        : Sets up RC Data
792 ************************************************************************************/
793void lnc__setup_rcdata(
794    context_ENC_p psContext,
795    PIC_PARAMS *psPicParams,
796    IMG_RC_PARAMS *psRCParams)
797{
798    IMG_UINT32   max_bitrate = psContext->Width * psContext->Height * 1.5 * 8 * 60;
799    IMG_UINT8 InitialSeInitQP = 0;
800
801    /* frameskip is always cleared, specially handled at vaEndPicture */
802    psRCParams->FrameSkip = 0;
803
804    if (!psRCParams->BitsPerSecond)
805        psRCParams->BitsPerSecond = 64000;
806    if (psRCParams->BitsPerSecond > max_bitrate)
807        psRCParams->BitsPerSecond = max_bitrate;
808
809    if (!psRCParams->FrameRate)
810        psRCParams->FrameRate = 30;
811
812    if (psRCParams->BufferSize == 0) {
813        if (psRCParams->BitsPerSecond < 256000)
814            psRCParams->BufferSize = (9 * psRCParams->BitsPerSecond) >> 1;
815        else
816            psRCParams->BufferSize = (5 * psRCParams->BitsPerSecond) >> 1;
817    }
818    psRCParams->InitialLevel = (3 * psRCParams->BufferSize) >> 4;
819    psRCParams->InitialDelay = (13 * psRCParams->BufferSize) >> 4;
820
821    lnc__setup_busize(psContext); /* calculate BasicUnitSize */
822
823    psPicParams->sInParams.SeInitQP = psRCParams->InitialQp;
824
825    psPicParams->sInParams.MBPerRow = (psContext->Width >> 4);
826    psPicParams->sInParams.MBPerBU = psRCParams->BUSize;
827    psPicParams->sInParams.MBPerFrm     = (psContext->Width >> 4) * (psContext->Height >> 4);
828    psPicParams->sInParams.BUPerFrm     = (psPicParams->sInParams.MBPerFrm) / psRCParams->BUSize;
829
830    InitialSeInitQP = psPicParams->sInParams.SeInitQP;
831
832    lnc__update_rcdata(psContext, psPicParams, psRCParams);
833    /* set minQP if hosts set minQP */
834    if (psRCParams->MinQP)
835        psPicParams->sInParams.MinQPVal = psRCParams->MinQP;
836
837    /* if seinitqp is set, restore the value hosts want */
838    if (InitialSeInitQP) {
839        psPicParams->sInParams.SeInitQP = InitialSeInitQP;
840        psPicParams->sInParams.MyInitQP = InitialSeInitQP;
841        psRCParams->InitialQp = InitialSeInitQP;
842    }
843}
844
845void lnc__update_rcdata(context_ENC_p psContext,
846                        PIC_PARAMS *psPicParams,
847                        IMG_RC_PARAMS *psRCParams)
848{
849    double              L1, L2, L3, L4, L5, flBpp;
850    INT16               i16TempQP;
851    IMG_INT32   i32BufferSizeInFrames;
852
853    flBpp                                                                       = 1.0 * psRCParams->BitsPerSecond / (psRCParams->FrameRate * psContext->Width * psContext->Height);
854
855    /* recalculate for small frames */
856    if (psContext->Width <= 176)
857        flBpp = flBpp / 2.0;
858
859    psPicParams->sInParams.IntraPeriod  = psRCParams->IntraFreq;
860    psPicParams->sInParams.BitRate              = psRCParams->BitsPerSecond;
861    psPicParams->sInParams.IntraPeriod  = psRCParams->IntraFreq;
862
863    psPicParams->sInParams.BitsPerFrm   = psRCParams->BitsPerSecond / psRCParams->FrameRate;
864    psPicParams->sInParams.BitsPerGOP   = psPicParams->sInParams.BitsPerFrm * psRCParams->IntraFreq;
865    psPicParams->sInParams.BitsPerBU            = psPicParams->sInParams.BitsPerFrm / (4 * psPicParams->sInParams.BUPerFrm);
866    psPicParams->sInParams.BitsPerMB            = psPicParams->sInParams.BitsPerBU / psRCParams->BUSize;
867
868    i32BufferSizeInFrames = psRCParams->BufferSize / psPicParams->sInParams.BitsPerFrm;
869
870    // select thresholds and initial Qps etc that are codec dependent
871    switch (psContext->eCodec) {
872    case IMG_CODEC_H264_CBR:
873    case IMG_CODEC_H264_VCM:
874    case IMG_CODEC_H264_VBR:
875        L1 = 0.1;
876        L2 = 0.15;
877        L3 = 0.2;
878        psPicParams->sInParams.MaxQPVal = 51;
879
880        // Set THSkip Values
881        if (flBpp <= 0.07)
882            psPicParams->THSkip = TH_SKIP_24;
883        else if (flBpp <= 0.14)
884            psPicParams->THSkip = TH_SKIP_12;
885        else
886            psPicParams->THSkip = TH_SKIP_0;
887
888        if (flBpp <= 0.3)
889            psPicParams->Flags |= ISRC_I16BIAS;
890
891        // Setup MAX and MIN Quant Values
892        if (flBpp >= 0.50)
893            i16TempQP = 4;
894        else if (flBpp > 0.133)
895            i16TempQP = (unsigned int)(24 - (40 * flBpp));
896        else
897            i16TempQP = (unsigned int)(32 - (100 * flBpp));
898
899        psPicParams->sInParams.MinQPVal = (max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));
900        // Calculate Initial QP if it has not been specified
901
902        L1 = 0.050568;
903        L2 = 0.202272;
904        L3 = 0.40454321;
905        L4 = 0.80908642;
906        L5 = 1.011358025;
907        if (flBpp < L1)
908            i16TempQP = (IMG_INT16)(47 - 78.10 * flBpp);
909
910        else if (flBpp >= L1 && flBpp < L2)
911            i16TempQP = (IMG_INT16)(46 - 72.51 * flBpp);
912
913        else if (flBpp >= L2 && flBpp < L3)
914            i16TempQP = (IMG_INT16)(36 - 24.72 * flBpp);
915
916        else if (flBpp >= L3 && flBpp < L4)
917            i16TempQP = (IMG_INT16)(34 - 19.78 * flBpp);
918
919        else if (flBpp >= L4 && flBpp < L5)
920            i16TempQP = (IMG_INT16)(27 - 9.89 * flBpp);
921
922        else if (flBpp >= L5)
923            i16TempQP = (IMG_INT16)(20 - 4.95 * flBpp);
924
925        psPicParams->sInParams.SeInitQP = (IMG_UINT8)(max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));
926        break;
927
928    case IMG_CODEC_MPEG4_CBR:
929    case IMG_CODEC_MPEG4_VBR:
930        psPicParams->sInParams.MaxQPVal  = 31;
931
932        if (psContext->Width == 176) {
933            L1 = 0.1;
934            L2 = 0.3;
935            L3 = 0.6;
936        } else if (psContext->Width == 352) {
937            L1 = 0.2;
938            L2 = 0.6;
939            L3 = 1.2;
940        } else {
941            L1 = 0.25;
942            L2 = 1.4;
943            L3 = 2.4;
944        }
945
946        // Calculate Initial QP if it has not been specified
947        if (flBpp <= L1)
948            psPicParams->sInParams.SeInitQP = 31;
949        else {
950            if (flBpp <= L2)
951                psPicParams->sInParams.SeInitQP = 25;
952            else
953                psPicParams->sInParams.SeInitQP = (flBpp <= L3) ? 20 : 10;
954        }
955
956        if (flBpp >= 0.25) {
957            psPicParams->sInParams.MinQPVal = 1;
958        } else {
959            psPicParams->sInParams.MinQPVal = 2;
960        }
961        break;
962
963    case IMG_CODEC_H263_CBR:
964    case IMG_CODEC_H263_VBR:
965        psPicParams->sInParams.MaxQPVal  = 31;
966
967        if (psContext->Width == 176) {
968            L1 = 0.1;
969            L2 = 0.3;
970            L3 = 0.6;
971        } else if (psContext->Width == 352) {
972            L1 = 0.2;
973            L2 = 0.6;
974            L3 = 1.2;
975        } else {
976            L1 = 0.25;
977            L2 = 1.4;
978            L3 = 2.4;
979        }
980
981        // Calculate Initial QP if it has not been specified
982        if (flBpp <= L1)
983            psPicParams->sInParams.SeInitQP = 31;
984        else {
985            if (flBpp <= L2)
986                psPicParams->sInParams.SeInitQP = 25;
987            else
988                psPicParams->sInParams.SeInitQP = (flBpp <= L3) ? 20 : 10;
989        }
990
991        psPicParams->sInParams.MinQPVal = 3;
992
993        break;
994
995    default:
996        /* the NO RC cases will fall here */
997        break;
998    }
999
1000    // Set up Input Parameters that are mode dependent
1001    switch (psContext->eCodec) {
1002    case IMG_CODEC_H264_NO_RC:
1003    case IMG_CODEC_H263_NO_RC:
1004    case IMG_CODEC_MPEG4_NO_RC:
1005        return;
1006
1007    case IMG_CODEC_H264_VCM:
1008        psPicParams->Flags                              |= ISVCM_FLAGS | ISCBR_FLAGS;
1009        /* drop through to CBR case */
1010        /* for SD and above we can target 95% (122/128) of maximum bitrate */
1011        if (psRCParams->VCMBitrateMargin) {
1012            psPicParams->sInParams.VCMBitrateMargin = psRCParams->VCMBitrateMargin;
1013        } else {
1014            if (psContext->Height >= 480)
1015                psPicParams->sInParams.VCMBitrateMargin = 122;
1016            else
1017                psPicParams->sInParams.VCMBitrateMargin = 115; /* for less and SD we target 90% (115/128) of maximum bitrate */
1018            if (i32BufferSizeInFrames < 15)
1019                psPicParams->sInParams.VCMBitrateMargin -= 5;/* when we have a very small window size we reduce the target further to avoid too much skipping */
1020        }
1021        psPicParams->sInParams.ForceSkipMargin = 500;/* start skipping MBs when within 500 bits of slice or frame limit */
1022
1023        // Set a scale factor to avoid overflows in maths
1024        if (psRCParams->BitsPerSecond < 1000000) {      // 1 Mbits/s
1025            psPicParams->sInParams.ScaleFactor = 0;
1026        } else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
1027            psPicParams->sInParams.ScaleFactor = 1;
1028        } else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
1029            psPicParams->sInParams.ScaleFactor = 2;
1030        } else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
1031            psPicParams->sInParams.ScaleFactor = 3;
1032        } else {
1033            psPicParams->sInParams.ScaleFactor = 4;
1034        }
1035
1036        psPicParams->sInParams.BufferSize = i32BufferSizeInFrames;
1037        break;
1038
1039    case IMG_CODEC_H264_CBR:
1040        psPicParams->Flags                              |= ISCBR_FLAGS;
1041        // ------------------- H264 CBR RC ------------------- //
1042        // Initialize the parameters of fluid flow traffic model.
1043        psPicParams->sInParams.BufferSize = psRCParams->BufferSize;
1044
1045        // HRD consideration - These values are used by H.264 reference code.
1046        if (psRCParams->BitsPerSecond < 1000000) {      // 1 Mbits/s
1047            psPicParams->sInParams.ScaleFactor = 0;
1048        } else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
1049            psPicParams->sInParams.ScaleFactor = 1;
1050        } else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
1051            psPicParams->sInParams.ScaleFactor = 2;
1052        } else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
1053            psPicParams->sInParams.ScaleFactor = 3;
1054        } else {
1055            psPicParams->sInParams.ScaleFactor = 4;
1056        }
1057        break;
1058
1059    case IMG_CODEC_MPEG4_CBR:
1060    case IMG_CODEC_H263_CBR:
1061        psPicParams->Flags                                      |= ISCBR_FLAGS;
1062
1063        flBpp  = 256 * (psRCParams->BitsPerSecond / psContext->Width);
1064        flBpp /= (psContext->Height * psRCParams->FrameRate);
1065
1066        if ((psPicParams->sInParams.MBPerFrm > 1024 && flBpp < 16) || (psPicParams->sInParams.MBPerFrm <= 1024 && flBpp < 24))
1067            psPicParams->sInParams.HalfFrameRate = 1;
1068        else
1069            psPicParams->sInParams.HalfFrameRate = 0;
1070
1071        if (psPicParams->sInParams.HalfFrameRate >= 1) {
1072            psPicParams->sInParams.SeInitQP = 31;
1073            psPicParams->sInParams.AvQPVal = 31;
1074            psPicParams->sInParams.MyInitQP = 31;
1075        }
1076
1077        if (psRCParams->BitsPerSecond <= 384000)
1078            psPicParams->sInParams.BufferSize = ((psRCParams->BitsPerSecond * 5) >> 1);
1079        else
1080            psPicParams->sInParams.BufferSize = psRCParams->BitsPerSecond * 4;
1081        break;
1082
1083    case IMG_CODEC_MPEG4_VBR:
1084    case IMG_CODEC_H263_VBR:
1085    case IMG_CODEC_H264_VBR:
1086        psPicParams->Flags                              |= ISVBR_FLAGS;
1087
1088        psPicParams->sInParams.MBPerBU  = psPicParams->sInParams.MBPerFrm;
1089        psPicParams->sInParams.BUPerFrm = 1;
1090
1091        // Initialize the parameters of fluid flow traffic model.
1092        psPicParams->sInParams.BufferSize       = ((5 * psRCParams->BitsPerSecond) >> 1);
1093
1094        // These scale factor are used only for rate control to avoid overflow
1095        // in fixed-point calculation these scale factors are decided by bit rate
1096        if (psRCParams->BitsPerSecond < 640000) {
1097            psPicParams->sInParams.ScaleFactor  = 2;                                            // related to complexity
1098        } else if (psRCParams->BitsPerSecond < 2000000) {
1099            psPicParams->sInParams.ScaleFactor  = 4;
1100        } else {
1101            psPicParams->sInParams.ScaleFactor  = 6;
1102        }
1103        break;
1104    default:
1105        break;
1106    }
1107
1108    psPicParams->sInParams.MyInitQP             = psPicParams->sInParams.SeInitQP;
1109    psPicParams->sInParams.InitialDelay = psRCParams->InitialDelay;
1110    psPicParams->sInParams.InitialLevel = psRCParams->InitialLevel;
1111    psRCParams->InitialQp                               = psPicParams->sInParams.SeInitQP;
1112}
1113
1114
1115
1116static void lnc__setup_qpvalue_h264(
1117    MTX_CURRENT_IN_PARAMS * psCurrent,
1118    IMG_BYTE bySliceQP)
1119{
1120    /* H.264 QP scaling tables */
1121    IMG_BYTE HOST_PVR_QP_SCALE_CR[52] = {
1122        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
1123        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
1124        28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37,
1125        37, 38, 38, 38, 39, 39, 39, 39
1126    };
1127
1128    psCurrent->bySliceQP = bySliceQP;
1129    psCurrent->bySliceQPC = HOST_PVR_QP_SCALE_CR[psCurrent->bySliceQP];
1130}
1131
1132
1133static void lnc__setup_qpvalues_mpeg4(
1134    MTX_CURRENT_IN_PARAMS * psCurrent,
1135    IMG_BYTE bySliceQP)
1136{
1137    psCurrent->bySliceQP =      bySliceQP;
1138}
1139
1140
1141static void lnc__setup_slice_row_params(
1142    context_ENC_p ctx,
1143    IMG_BOOL IsIntra,
1144    IMG_UINT16 CurrentRowY,
1145    IMG_INT16 SliceStartRowY,
1146    IMG_INT16 SliceHeight,
1147    IMG_BOOL VectorsValid,
1148    int bySliceQP)
1149{
1150    /* Note: CurrentRowY and SliceStartRowY are now in pixels (not MacroBlocks)
1151     * - saves needless multiplications and divisions
1152     */
1153    IMG_INT16   Pos, YPos, srcY;
1154    MTX_CURRENT_IN_PARAMS *psCurrent;
1155    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
1156    IMG_UINT16  tmp;
1157
1158    if (IsIntra && cmdbuf->topaz_in_params_I_p == NULL) {
1159        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_I, &cmdbuf->topaz_in_params_I_p);
1160        if (vaStatus != VA_STATUS_SUCCESS) {
1161            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
1162            return;
1163        }
1164    }
1165
1166    if ((!IsIntra) && cmdbuf->topaz_in_params_P_p == NULL) {
1167        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_P, &cmdbuf->topaz_in_params_P_p);
1168        if (vaStatus != VA_STATUS_SUCCESS) {
1169            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
1170            return;
1171        }
1172    }
1173    if (IsIntra)
1174        psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_I_p + ctx->in_params_ofs);
1175    else
1176        psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_P_p + ctx->in_params_ofs);
1177
1178    psCurrent += (CurrentRowY  * (ctx->Width) / 256);
1179
1180    if ((YPos = srcY = CurrentRowY - MVEA_LRB_TOP_OFFSET) < 0)
1181        srcY = 0;
1182    else if (YPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16)
1183        srcY = ctx->HeightMinusLRBSearchHeight;
1184
1185    tmp = (CurrentRowY != SliceStartRowY);
1186
1187    for (Pos = 0; Pos < (int)ctx->Width; Pos += 16, psCurrent++) {
1188        memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS));
1189        psCurrent->MVValid = 0;
1190        psCurrent->ParamsValid = 0;
1191
1192        /* Setup the parameters and motion vectors */
1193        if (tmp) {
1194            psCurrent->MVValid = 66;
1195            psCurrent->ParamsValid |= PARAMS_ABOVE_VALID;
1196
1197            if (Pos + 16 < (int)ctx->Width) {
1198                psCurrent->ParamsValid |= PARAMS_ABOVER_VALID;
1199                psCurrent->MVValid |= 4; /* (1<<2) */
1200            }
1201
1202            if (Pos > 0 && (Pos < (int)ctx->Width)) {
1203                psCurrent->ParamsValid |= PARAMS_ABOVEL_VALID;
1204                psCurrent->MVValid |= 1; /* (1<<0) */
1205            }
1206        }
1207        if ((Pos == 0) && (CurrentRowY == SliceStartRowY)) {
1208            psCurrent->ParamsValid |= MB_START_OF_SLICE;/* OPTI? */
1209        }
1210        /* Have to fill in the right hand row of 4x4 vectors into the the left block */
1211        if (Pos) {
1212            psCurrent->MVValid |= 72; /* (1<<3)+(1<<6) */
1213            psCurrent->ParamsValid |= 8; /* (1<<3) */
1214        }
1215        if (Pos == (int)(ctx->Width - 16)) {
1216            /* indicate the last MB in a row */
1217            psCurrent->ParamsValid |= MB_END_OF_ROW;
1218            /* are we the last mb in the slice? */
1219            if (YPos == (SliceStartRowY + SliceHeight - (MVEA_LRB_TOP_OFFSET + 16))) {
1220                psCurrent->ParamsValid |= MB_END_OF_SLICE;
1221                if (YPos == ctx->HeightMinus16MinusLRBTopOffset) {
1222                    psCurrent->ParamsValid |= MB_END_OF_PICTURE;
1223                }
1224            }
1225        }
1226        /* And now the below block
1227         * should do some kind of check to see if we are the first inter block,
1228         * as otherwise the vectors will be invalid!
1229         */
1230        if (VectorsValid) {
1231            if (YPos < ctx->HeightMinus16MinusLRBTopOffset) {
1232                psCurrent->MVValid |= 16; /* (1<<4) */
1233
1234                if (YPos < ctx->HeightMinus32MinusLRBTopOffset) {
1235                    psCurrent->MVValid |= 32; /* (1<<5) */
1236                }
1237            }
1238        }
1239
1240        /* Set up IPEMin and Max for coordinate X in the search reference region */
1241        /* And set up flags in SPEMax when needed */
1242        if (Pos <= 48) {
1243            psCurrent->IPEMin[0] = 48 - Pos;
1244            psCurrent->RealEdge |= SPE_EDGE_LEFT;
1245        } else {
1246            psCurrent->IPEMin[0] = 3;
1247        }
1248
1249        if ((Pos + 48 + 16) > (int)ctx->Width) {
1250            psCurrent->IPEMax[0] = (47 + ctx->Width) - Pos; /* (112 - 1) - ((Pos + 48+16) - ctx->Width); */
1251            psCurrent->RealEdge |= SPE_EDGE_RIGHT;
1252        } else {
1253            psCurrent->IPEMax[0] = 108; /* (112 - 1) - 3; */
1254        }
1255
1256        /* Set up IPEMin and Max for Y coordinate in the search reference region */
1257        /* And set up flags in SPEMax when needed */
1258        if (YPos <= 0) {
1259            psCurrent->IPEMin[1] = 0;
1260            psCurrent->RealEdge |= SPE_EDGE_TOP;
1261        } else {
1262            psCurrent->IPEMin[1] = 3;
1263        }
1264
1265        /* Max Y */
1266        if (YPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16) {
1267            psCurrent->IPEMax[1] = MVEA_LRB_SEARCH_HEIGHT - 1;
1268            psCurrent->RealEdge |= SPE_EDGE_BOTTOM;
1269        } else {
1270            psCurrent->IPEMax[1] = MVEA_LRB_SEARCH_HEIGHT - 4;
1271        }
1272
1273        psCurrent->CurBlockAddr = ((IMG_UINT8)(((YPos + MVEA_LRB_TOP_OFFSET) - srcY) / 16) << 4) | 0x3;
1274
1275        /* Setup the control register values These will get setup and transferred to a different location within
1276         * the macroblock parameter structure.  They are then read out of the esb by the mtx and used to control
1277         * the hardware units
1278         */
1279        psCurrent->IPEControl = ctx->IPEControl;
1280
1281        switch (ctx->eCodec) {
1282        case IMG_CODEC_H263_NO_RC:
1283        case IMG_CODEC_H263_VBR:
1284        case IMG_CODEC_H263_CBR:
1285            lnc__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
1286            psCurrent->JMCompControl = F_ENCODE(2, MVEA_CR_JMCOMP_MODE);
1287            psCurrent->VLCControl = F_ENCODE(3, TOPAZ_VLC_CR_CODEC) |
1288                                    F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
1289            break;
1290        case IMG_CODEC_MPEG4_NO_RC:
1291        case IMG_CODEC_MPEG4_VBR:
1292        case IMG_CODEC_MPEG4_CBR:
1293            lnc__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
1294            psCurrent->JMCompControl = F_ENCODE(1, MVEA_CR_JMCOMP_MODE) |
1295                                       F_ENCODE(1, MVEA_CR_JMCOMP_AC_ENABLE);
1296            psCurrent->VLCControl = F_ENCODE(2, TOPAZ_VLC_CR_CODEC) |
1297                                    F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
1298            break;
1299        default:
1300        case IMG_CODEC_H264_NO_RC:
1301        case IMG_CODEC_H264_VBR:
1302        case IMG_CODEC_H264_CBR:
1303        case IMG_CODEC_H264_VCM:
1304            lnc__setup_qpvalue_h264(psCurrent, bySliceQP);
1305            psCurrent->JMCompControl = F_ENCODE(0, MVEA_CR_JMCOMP_MODE);
1306            psCurrent->VLCControl = F_ENCODE(1, TOPAZ_VLC_CR_CODEC) |
1307                                    F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
1308            break;
1309        }
1310    }
1311
1312    psCurrent->RealEdge = 0;
1313
1314}
1315
1316void lnc_setup_slice_params(
1317    context_ENC_p  ctx,
1318    IMG_UINT16 YSliceStartPos,
1319    IMG_UINT16 SliceHeight,
1320    IMG_BOOL IsIntra,
1321    IMG_BOOL  VectorsValid,
1322    int bySliceQP)
1323{
1324    IMG_UINT16 Rows, CurrentRowY;
1325
1326    Rows = SliceHeight / 16;
1327    CurrentRowY = YSliceStartPos;
1328
1329    while (Rows) {
1330        lnc__setup_slice_row_params(
1331            ctx,
1332            IsIntra,
1333            CurrentRowY,
1334            YSliceStartPos,
1335            SliceHeight,
1336            VectorsValid, bySliceQP);
1337
1338        CurrentRowY += 16;
1339        Rows--;
1340    }
1341
1342}
1343
1344
1345
1346IMG_UINT32 lnc__send_encode_slice_params(
1347    context_ENC_p ctx,
1348    IMG_BOOL IsIntra,
1349    IMG_UINT16 CurrentRow,
1350    IMG_BOOL DeblockSlice,
1351    IMG_UINT32 FrameNum,
1352    IMG_UINT16 SliceHeight,
1353    IMG_UINT16 CurrentSlice,
1354    IMG_UINT32 MaxSliceSize)
1355{
1356    SLICE_PARAMS *psSliceParams;
1357    IMG_UINT16 RowOffset;
1358
1359    psb_buffer_p psCoded;
1360    object_surface_p ref_surface;
1361    psb_buffer_p psRef;
1362    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
1363
1364
1365    ref_surface = ctx->ref_surface;
1366    psRef = &ctx->ref_surface->psb_surface->buf;
1367    psCoded = ctx->coded_buf->psb_buffer;
1368
1369    psSliceParams = (SLICE_PARAMS *)(cmdbuf->slice_params_p +
1370                                     CurrentSlice * ((sizeof(SLICE_PARAMS) + 15) & 0xfff0));
1371
1372    psSliceParams->SliceHeight = SliceHeight;
1373    psSliceParams->SliceStartRowNum = CurrentRow / 16;
1374
1375    /* We want multiple ones of these so we can submit multiple slices without having to wait for the next */
1376    psSliceParams->CodedDataPos = 0;
1377    psSliceParams->TotalCoded = 0;
1378    psSliceParams->Flags = 0;
1379
1380#ifdef VA_EMULATOR
1381    psSliceParams->RefYStride = ref_surface->psb_surface->stride;
1382    psSliceParams->RefUVStride = ref_surface->psb_surface->stride;
1383    psSliceParams->RefYRowStride =  ref_surface->psb_surface->stride * 16;
1384    psSliceParams->RefUVRowStride = ref_surface->psb_surface->stride * 16 / 2;
1385#else
1386    psSliceParams->RefYStride = ref_surface->height * 16;
1387    psSliceParams->RefUVStride = ref_surface->height * 8;
1388    psSliceParams->RefYRowStride =  psSliceParams->RefYStride;
1389    psSliceParams->RefUVRowStride = psSliceParams->RefUVStride;
1390#endif
1391
1392    psSliceParams->FCode = ctx->FCode;/* Not clear yet, This field is not appare in firmware doc */
1393    RowOffset = CurrentRow - 32;
1394    if (RowOffset <= 0)
1395        RowOffset = 0;
1396    if (RowOffset > (ctx->Height - 80))
1397        RowOffset = (ctx->Height - 80);
1398
1399    psSliceParams->MaxSliceSize = MaxSliceSize;
1400    psSliceParams->NumAirMBs = ctx->num_air_mbs;
1401    /* DDKv145: 3 lsb of threshold used as spacing between AIR MBs */
1402    psSliceParams->AirThreshold = ctx->air_threshold + (FrameNum & 3) + 2;
1403
1404    if (ctx->autotune_air_flag)
1405        psSliceParams->Flags |= AUTOTUNE_AIR;
1406
1407    if (!IsIntra) {
1408        psSliceParams->Flags |= ISINTER_FLAGS;
1409    }
1410    if (DeblockSlice) {
1411        psSliceParams->Flags |= DEBLOCK_FRAME;
1412    }
1413    switch (ctx->eCodec) {
1414    case IMG_CODEC_H263_NO_RC:
1415    case IMG_CODEC_H263_VBR:
1416    case IMG_CODEC_H263_CBR:
1417        psSliceParams->Flags |= ISH263_FLAGS;
1418        break;
1419    case IMG_CODEC_MPEG4_NO_RC:
1420    case IMG_CODEC_MPEG4_VBR:
1421    case IMG_CODEC_MPEG4_CBR:
1422        psSliceParams->Flags |= ISMPEG4_FLAGS;
1423        break;
1424    case IMG_CODEC_H264_NO_RC:
1425    case IMG_CODEC_H264_VBR:
1426    case IMG_CODEC_H264_CBR:
1427    case IMG_CODEC_H264_VCM:
1428        psSliceParams->Flags |= ISH264_FLAGS;
1429        break;
1430    default:
1431        psSliceParams->Flags |= ISH264_FLAGS;
1432        drv_debug_msg(VIDEO_DEBUG_ERROR, "No format specified defaulting to h.264\n");
1433        break;
1434    }
1435    /* we should also setup the interleaving requirements based on the source format */
1436    if (ctx->eFormat != IMG_CODEC_PL12)
1437        psSliceParams->Flags |= INTERLEAVE_TARGET;
1438
1439    cmdbuf = ctx->obj_context->lnc_cmdbuf;
1440
1441    RELOC_SLICE_PARAMS(&(psSliceParams->RefYBase), 16 * RowOffset, psRef);
1442    RELOC_SLICE_PARAMS(&(psSliceParams->RefUVBase),
1443                       ref_surface->psb_surface->stride * ref_surface->height + (RowOffset * 16 / 2),
1444                       psRef);
1445    RELOC_SLICE_PARAMS(&(psSliceParams->CodedData), 0, psCoded);
1446
1447    lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_ENCODE_SLICE, 2, (CurrentSlice << 2) | (IsIntra & 0x3));
1448    RELOC_CMDBUF(cmdbuf->cmd_idx++,
1449                 CurrentSlice *((sizeof(SLICE_PARAMS) + 15) & 0xfff0),
1450                 &cmdbuf->slice_params);
1451
1452    return 0;
1453}
1454
1455
1456
1457/*
1458 * Function Name      : Reset_EncoderParams
1459 * Description        : Reset Above & Below Params at the Start of Intra frame
1460 */
1461void lnc_reset_encoder_params(context_ENC_p ctx)
1462{
1463    unsigned char *Add_Below, *Add_Above;
1464    lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
1465
1466    /* all frames share the same Topaz param, in_param/aboveparam/bellow
1467     * map it only when necessary
1468     */
1469    if (cmdbuf->topaz_above_bellow_params_p == NULL) {
1470        VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_above_bellow_params, &cmdbuf->topaz_above_bellow_params_p);
1471        if (vaStatus != VA_STATUS_SUCCESS) {
1472            drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
1473            return;
1474        }
1475    }
1476
1477    Add_Below = cmdbuf->topaz_above_bellow_params_p + ctx->bellow_params_ofs;
1478    memset(Add_Below, 0, ctx->bellow_params_size);
1479
1480    Add_Above = cmdbuf->topaz_above_bellow_params_p + ctx->above_params_ofs;
1481    memset(Add_Above, 0, ctx->above_params_size);
1482}
1483