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
26/*
27 * Authors:
28 *    Li Zeng <li.zeng@intel.com>
29 */
30#include "tng_vld_dec.h"
31#include "psb_drv_debug.h"
32#include "hwdefs/dxva_fw_ctrl.h"
33#include "hwdefs/reg_io2.h"
34#include "hwdefs/msvdx_offsets.h"
35#include "hwdefs/msvdx_cmds_io2.h"
36#include "va/va_dec_jpeg.h"
37#include "va/va_dec_vp8.h"
38
39#define GET_SURFACE_INFO_colocated_index(psb_surface) ((int) (psb_surface->extra_info[3]))
40#define SET_SURFACE_INFO_colocated_index(psb_surface, val) psb_surface->extra_info[3] = (uint32_t) val;
41
42/* Set MSVDX Front end register */
43void vld_dec_FE_state(object_context_p obj_context, psb_buffer_p buf)
44{
45    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
46    context_DEC_p ctx = (context_DEC_p) obj_context->format_data;
47    CTRL_ALLOC_HEADER *cmd_header = (CTRL_ALLOC_HEADER *)psb_cmdbuf_alloc_space(cmdbuf, sizeof(CTRL_ALLOC_HEADER));
48
49    cmd_header->ui32Cmd_AdditionalParams = CMD_CTRL_ALLOC_HEADER;
50    cmd_header->ui32ExternStateBuffAddr = 0;
51    if (buf)
52        RELOC(cmd_header->ui32ExternStateBuffAddr, 0, buf);
53    cmd_header->ui32MacroblockParamAddr = 0; /* Only EC needs to set this */
54
55    ctx->cmd_params = &cmd_header->ui32Cmd_AdditionalParams;
56    ctx->p_slice_params = &cmd_header->ui32SliceParams;
57    cmd_header->ui32SliceParams = 0;
58
59    ctx->slice_first_pic_last = &cmd_header->uiSliceFirstMbYX_uiPicLastMbYX;
60    *ctx->slice_first_pic_last = 0;
61
62    ctx->p_range_mapping_base0 = &cmd_header->ui32AltOutputAddr[0];
63    ctx->p_range_mapping_base1 = &cmd_header->ui32AltOutputAddr[1];
64
65    ctx->alt_output_flags = &cmd_header->ui32AltOutputFlags;
66
67    cmd_header->ui32AltOutputFlags = 0;
68    cmd_header->ui32AltOutputAddr[0] = 0;
69    cmd_header->ui32AltOutputAddr[1] = 0;
70}
71
72/* Programme the Alt output if there is a rotation*/
73void vld_dec_setup_alternative_frame(object_context_p obj_context)
74{
75    uint32_t cmd = 0;
76    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
77    context_DEC_p ctx = (context_DEC_p) obj_context->format_data;
78    psb_surface_p src_surface = obj_context->current_render_target->psb_surface;
79    psb_surface_p out_loop_surface = obj_context->current_render_target->out_loop_surface;
80    int ved_scaling = (CONTEXT_SCALING(obj_context) && !ctx->yuv_ctx);
81    uint32_t startX = 0, startY = 0, luma_addr_offset = 0, chroma_addr_offset = 0;
82
83    /*  In VPP ctx, current_render_target is rotated surface */
84    if (ctx->yuv_ctx && (VAEntrypointVideoProc == obj_context->entry_point)) {
85        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Setup second-pass rotation\n");
86        out_loop_surface = src_surface;
87        src_surface = ctx->yuv_ctx->src_surface;
88    }
89
90    if (CONTEXT_ALTERNATIVE_OUTPUT(obj_context) || obj_context->entry_point == VAEntrypointVideoProc) {
91        if (ved_scaling) {
92            out_loop_surface = obj_context->current_render_target->scaling_surface;
93#ifndef BAYTRAIL
94            tng_ved_write_scale_reg(obj_context);
95
96            REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,ALTERNATIVE_OUTPUT_PICTURE_ROTATION, SCALE_INPUT_SIZE_SEL, 1);
97            REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS,ALTERNATIVE_OUTPUT_PICTURE_ROTATION, SCALE_ENABLE, 1);
98#endif
99        } else {
100            startX = ((uint32_t)obj_context->current_render_target->offset_x_s + 0x3f) & ~0x3f;
101            startY = ((uint32_t)obj_context->current_render_target->offset_y_s + 0x1) & ~0x1;
102            luma_addr_offset = (((uint32_t)(startX + out_loop_surface->stride * startY))  + 0x3f ) & ~0x3f;
103            chroma_addr_offset = (((uint32_t)(startX + out_loop_surface->stride * startY / 2))  + 0x3f ) & ~0x3f;
104        }
105
106        if (out_loop_surface == NULL) {
107            drv_debug_msg(VIDEO_DEBUG_ERROR, "out-loop surface is NULL, abort msvdx alternative output\n");
108            return;
109        }
110
111        if (GET_SURFACE_INFO_rotate(out_loop_surface) != obj_context->msvdx_rotate && !ved_scaling)
112            drv_debug_msg(VIDEO_DEBUG_WARNING, "Display rotate mode does not match surface rotate mode!\n");
113
114        /* CRendecBlock    RendecBlk( mCtrlAlloc , RENDEC_REGISTER_OFFSET(MSVDX_CMDS, VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS) ); */
115        psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET(MSVDX_CMDS, VC1_LUMA_RANGE_MAPPING_BASE_ADDRESS));
116
117        psb_cmdbuf_rendec_write_address(cmdbuf, &out_loop_surface->buf, out_loop_surface->buf.buffer_ofs + luma_addr_offset);
118        psb_cmdbuf_rendec_write_address(cmdbuf, &out_loop_surface->buf, out_loop_surface->buf.buffer_ofs + chroma_addr_offset + out_loop_surface->chroma_offset);
119
120        psb_cmdbuf_rendec_end(cmdbuf);
121
122        REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION , ALT_PICTURE_ENABLE, 1);
123        REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION , ROTATION_ROW_STRIDE, out_loop_surface->stride_mode);
124        REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION , RECON_WRITE_DISABLE, 0); /* FIXME Always generate Rec */
125        REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION , ROTATION_MODE, GET_SURFACE_INFO_rotate(out_loop_surface));
126
127        RELOC(*ctx->p_range_mapping_base0, out_loop_surface->buf.buffer_ofs + luma_addr_offset, &out_loop_surface->buf);
128        RELOC(*ctx->p_range_mapping_base1, out_loop_surface->buf.buffer_ofs + chroma_addr_offset + out_loop_surface->chroma_offset, &out_loop_surface->buf);
129    }
130
131    if (obj_context->profile == VAProfileVP8Version0_3 ||
132        obj_context->profile == VAProfileJPEGBaseline || ctx->yuv_ctx) {
133        psb_cmdbuf_rendec_start(cmdbuf, (REG_MSVDX_CMD_OFFSET + MSVDX_CMDS_AUX_LINE_BUFFER_BASE_ADDRESS_OFFSET));
134        psb_cmdbuf_rendec_write_address(cmdbuf, &ctx->aux_line_buffer_vld, ctx->aux_line_buffer_vld.buffer_ofs);
135        psb_cmdbuf_rendec_end(cmdbuf);
136
137        REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION, USE_AUX_LINE_BUF, 1);
138        if (ctx->yuv_ctx)
139            REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION , RECON_WRITE_DISABLE, 1);
140    }
141
142    /* Set the rotation registers */
143    psb_cmdbuf_rendec_start(cmdbuf, RENDEC_REGISTER_OFFSET(MSVDX_CMDS, ALTERNATIVE_OUTPUT_PICTURE_ROTATION));
144    psb_cmdbuf_rendec_write(cmdbuf, cmd);
145    *ctx->alt_output_flags = cmd;
146
147    cmd = 0;
148    REGIO_WRITE_FIELD_LITE(cmd, MSVDX_CMDS, EXTENDED_ROW_STRIDE, EXT_ROW_STRIDE, src_surface->stride / 64);
149    psb_cmdbuf_rendec_write(cmdbuf, cmd);
150
151    psb_cmdbuf_rendec_end(cmdbuf);
152}
153
154int vld_dec_slice_parameter_size(object_context_p obj_context)
155{
156    int size;
157
158    switch (obj_context->profile) {
159    case VAProfileMPEG2Simple:
160    case VAProfileMPEG2Main:
161        size = sizeof(VASliceParameterBufferMPEG2);
162        break;
163    case VAProfileMPEG4Simple:
164    case VAProfileMPEG4AdvancedSimple:
165    case VAProfileMPEG4Main:
166    case VAProfileH263Baseline:
167        size = sizeof(VASliceParameterBufferMPEG4);
168        break;
169    case VAProfileH264Baseline:
170    case VAProfileH264Main:
171    case VAProfileH264High:
172    case VAProfileH264ConstrainedBaseline:
173        size = sizeof(VASliceParameterBufferH264);
174        break;
175    case VAProfileVC1Simple:
176    case VAProfileVC1Main:
177    case VAProfileVC1Advanced:
178        size = sizeof(VASliceParameterBufferVC1);
179        break;
180    case VAProfileVP8Version0_3:
181        size = sizeof(VASliceParameterBufferVP8);
182    case VAProfileJPEGBaseline:
183        size = sizeof(VASliceParameterBufferJPEGBaseline);
184    default:
185        size = 0;
186        break;
187    }
188
189    return size;
190}
191
192VAStatus vld_dec_process_slice_data(context_DEC_p ctx, object_buffer_p obj_buffer)
193{
194    VAStatus vaStatus = VA_STATUS_SUCCESS;
195    void *slice_param;
196    int buffer_idx = 0;
197    unsigned int element_idx = 0, element_size;
198
199    ASSERT((obj_buffer->type == VASliceDataBufferType) || (obj_buffer->type == VAProtectedSliceDataBufferType));
200
201    ASSERT(ctx->pic_params);
202    ASSERT(ctx->slice_param_list_idx);
203
204#if 0
205    if (!ctx->pic_params) {
206        /* Picture params missing */
207        return VA_STATUS_ERROR_UNKNOWN;
208    }
209#endif
210    if ((NULL == obj_buffer->psb_buffer) ||
211        (0 == obj_buffer->size)) {
212        /* We need to have data in the bitstream buffer */
213        return VA_STATUS_ERROR_UNKNOWN;
214    }
215
216    element_size = vld_dec_slice_parameter_size(ctx->obj_context);
217
218    while (buffer_idx < ctx->slice_param_list_idx) {
219        object_buffer_p slice_buf = ctx->slice_param_list[buffer_idx];
220        if (element_idx >= slice_buf->num_elements) {
221            /* Move to next buffer */
222            element_idx = 0;
223            buffer_idx++;
224            continue;
225        }
226
227        slice_param = slice_buf->buffer_data;
228        slice_param = (void *)((unsigned long)slice_param + element_idx * element_size);
229        element_idx++;
230        vaStatus = vld_dec_process_slice(ctx, slice_param, obj_buffer);
231        if (vaStatus != VA_STATUS_SUCCESS) {
232            DEBUG_FAILURE;
233            break;
234        }
235    }
236    ctx->slice_param_list_idx = 0;
237
238    return vaStatus;
239}
240/*
241 * Adds a VASliceParameterBuffer to the list of slice params
242 */
243VAStatus vld_dec_add_slice_param(context_DEC_p ctx, object_buffer_p obj_buffer)
244{
245    ASSERT(obj_buffer->type == VASliceParameterBufferType);
246    if (ctx->slice_param_list_idx >= ctx->slice_param_list_size) {
247        unsigned char *new_list;
248        ctx->slice_param_list_size += 8;
249        new_list = realloc(ctx->slice_param_list,
250                           sizeof(object_buffer_p) * ctx->slice_param_list_size);
251        if (NULL == new_list) {
252            return VA_STATUS_ERROR_ALLOCATION_FAILED;
253        }
254        ctx->slice_param_list = (object_buffer_p*) new_list;
255    }
256    ctx->slice_param_list[ctx->slice_param_list_idx] = obj_buffer;
257    ctx->slice_param_list_idx++;
258    return VA_STATUS_SUCCESS;
259}
260
261void vld_dec_write_kick(object_context_p obj_context)
262{
263    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
264    *cmdbuf->cmd_idx++ = CMD_COMPLETION;
265}
266
267VAStatus vld_dec_process_slice(context_DEC_p ctx,
268                                        void *vld_slice_param,
269                                        object_buffer_p obj_buffer)
270{
271    VAStatus vaStatus = VA_STATUS_SUCCESS;
272    VASliceParameterBufferBase *slice_param = (VASliceParameterBufferBase *) vld_slice_param;
273
274    ASSERT((obj_buffer->type == VASliceDataBufferType) || (obj_buffer->type == VAProtectedSliceDataBufferType));
275
276    if ((slice_param->slice_data_flag == VA_SLICE_DATA_FLAG_BEGIN) ||
277        (slice_param->slice_data_flag == VA_SLICE_DATA_FLAG_ALL)) {
278#ifndef SLICE_HEADER_PARSING
279        if (0 == slice_param->slice_data_size) {
280            vaStatus = VA_STATUS_ERROR_UNKNOWN;
281            DEBUG_FAILURE;
282            return vaStatus;
283        }
284#endif
285        ASSERT(!ctx->split_buffer_pending);
286
287        if (psb_context_get_next_cmdbuf(ctx->obj_context)) {
288            vaStatus = VA_STATUS_ERROR_UNKNOWN;
289            DEBUG_FAILURE;
290            return vaStatus;
291        }
292        vld_dec_FE_state(ctx->obj_context, ctx->preload_buffer);
293        ctx->begin_slice(ctx, slice_param);
294        ctx->slice_data_buffer = obj_buffer->psb_buffer;
295#ifdef SLICE_HEADER_PARSING
296        if (ctx->parse_enabled == 1)
297            psb_cmdbuf_dma_write_key(ctx->obj_context->cmdbuf,
298                                         ctx->SR_flags,
299                                         ctx->parse_key);
300        else
301#endif
302            psb_cmdbuf_dma_write_bitstream(ctx->obj_context->cmdbuf,
303                                         obj_buffer->psb_buffer,
304                                         obj_buffer->psb_buffer->buffer_ofs + slice_param->slice_data_offset,
305                                         slice_param->slice_data_size,
306                                         ctx->bits_offset,
307                                         ctx->SR_flags);
308
309        if (slice_param->slice_data_flag == VA_SLICE_DATA_FLAG_BEGIN) {
310            ctx->split_buffer_pending = TRUE;
311        }
312    } else {
313        ASSERT(ctx->split_buffer_pending);
314        ASSERT(0 == slice_param->slice_data_offset);
315        if (slice_param->slice_data_size) {
316            psb_cmdbuf_dma_write_bitstream_chained(ctx->obj_context->cmdbuf,
317                    obj_buffer->psb_buffer,
318                    slice_param->slice_data_size);
319        }
320    }
321
322    if ((slice_param->slice_data_flag == VA_SLICE_DATA_FLAG_ALL) ||
323        (slice_param->slice_data_flag == VA_SLICE_DATA_FLAG_END)) {
324        if (slice_param->slice_data_flag == VA_SLICE_DATA_FLAG_END) {
325            ASSERT(ctx->split_buffer_pending);
326        }
327
328        ctx->process_slice(ctx, slice_param);
329        vld_dec_write_kick(ctx->obj_context);
330
331        ctx->split_buffer_pending = FALSE;
332        ctx->obj_context->video_op = psb_video_vld;
333        ctx->obj_context->flags = 0;
334
335        ctx->end_slice(ctx);
336
337        if (psb_context_submit_cmdbuf(ctx->obj_context)) {
338            vaStatus = VA_STATUS_ERROR_UNKNOWN;
339        }
340    }
341    return vaStatus;
342}
343
344VAStatus vld_dec_allocate_colocated_buffer(context_DEC_p ctx, object_surface_p obj_surface, uint32_t size)
345{
346    psb_buffer_p buf;
347    VAStatus vaStatus;
348    psb_surface_p surface = obj_surface->psb_surface;
349    int index = GET_SURFACE_INFO_colocated_index(surface);
350
351    if (!index) {
352        index = ctx->colocated_buffers_idx;
353        if (index >= ctx->colocated_buffers_size) {
354            return VA_STATUS_ERROR_UNKNOWN;
355        }
356
357        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocating colocated buffer for surface %08x size = %08x\n", surface, size);
358
359        buf = &(ctx->colocated_buffers[index]);
360        vaStatus = psb_buffer_create(ctx->obj_context->driver_data, size, psb_bt_vpu_only, buf);
361        if (VA_STATUS_SUCCESS != vaStatus) {
362            return vaStatus;
363        }
364        ctx->colocated_buffers_idx++;
365        SET_SURFACE_INFO_colocated_index(surface, index + 1); /* 0 means unset, index is offset by 1 */
366    } else {
367        buf = &(ctx->colocated_buffers[index - 1]);
368        if (buf->size < size) {
369            psb_buffer_destroy(buf);
370            vaStatus = psb_buffer_create(ctx->obj_context->driver_data, size, psb_bt_vpu_only, buf);
371            if (VA_STATUS_SUCCESS != vaStatus) {
372                return vaStatus;
373            }
374            SET_SURFACE_INFO_colocated_index(surface, index); /* replace the original buffer */
375        }
376    }
377    return VA_STATUS_SUCCESS;
378}
379
380psb_buffer_p vld_dec_lookup_colocated_buffer(context_DEC_p ctx, psb_surface_p surface)
381{
382    int index = GET_SURFACE_INFO_colocated_index(surface);
383    if (!index) {
384        return NULL;
385    }
386    return &(ctx->colocated_buffers[index-1]); /* 0 means unset, index is offset by 1 */
387}
388
389VAStatus vld_dec_CreateContext(context_DEC_p ctx, object_context_p obj_context)
390{
391    VAStatus vaStatus = VA_STATUS_SUCCESS;
392
393    ctx->obj_context = obj_context;
394    ctx->split_buffer_pending = FALSE;
395    ctx->slice_param_list_size = 8;
396    ctx->slice_param_list = (object_buffer_p*) calloc(1, sizeof(object_buffer_p) * ctx->slice_param_list_size);
397    ctx->slice_param_list_idx = 0;
398
399    if (NULL == ctx->slice_param_list) {
400        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
401        DEBUG_FAILURE;
402        return vaStatus;
403    }
404
405    ctx->colocated_buffers_size = obj_context->num_render_targets;
406    ctx->colocated_buffers_idx = 0;
407    ctx->colocated_buffers = (psb_buffer_p) calloc(1, sizeof(struct psb_buffer_s) * ctx->colocated_buffers_size);
408    if (NULL == ctx->colocated_buffers) {
409        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
410        DEBUG_FAILURE;
411        free(ctx->slice_param_list);
412    }
413
414    if (vaStatus == VA_STATUS_SUCCESS) {
415        vaStatus = psb_buffer_create(obj_context->driver_data,
416                                     AUX_LINE_BUFFER_VLD_SIZE,
417                                     psb_bt_cpu_vpu,
418                                     &ctx->aux_line_buffer_vld);
419        DEBUG_FAILURE;
420    }
421
422    return vaStatus;
423}
424
425void vld_dec_DestroyContext(context_DEC_p ctx)
426{
427    int i;
428    ctx->preload_buffer = NULL;
429
430    psb_buffer_destroy(&ctx->aux_line_buffer_vld);
431
432    if (ctx->slice_param_list) {
433        free(ctx->slice_param_list);
434        ctx->slice_param_list = NULL;
435    }
436
437    if (ctx->colocated_buffers) {
438        for (i = 0; i < ctx->colocated_buffers_idx; ++i)
439            psb_buffer_destroy(&(ctx->colocated_buffers[i]));
440
441        free(ctx->colocated_buffers);
442        ctx->colocated_buffers = NULL;
443    }
444}
445
446VAStatus vld_dec_RenderPicture(
447    object_context_p obj_context,
448    object_buffer_p *buffers,
449    int num_buffers)
450{
451    int i;
452    context_DEC_p ctx = (context_DEC_p) obj_context->format_data;
453    VAStatus vaStatus = VA_STATUS_SUCCESS;
454
455    for (i = 0; i < num_buffers; i++) {
456        object_buffer_p obj_buffer = buffers[i];
457        psb__dump_va_buffers_verbose(obj_buffer);
458
459        switch (obj_buffer->type) {
460        case VASliceParameterBufferType:
461            vaStatus = vld_dec_add_slice_param(ctx, obj_buffer);
462            DEBUG_FAILURE;
463            break;
464
465        case VASliceDataBufferType:
466        case VAProtectedSliceDataBufferType:
467            vaStatus = vld_dec_process_slice_data(ctx, obj_buffer);
468            DEBUG_FAILURE;
469            break;
470
471        default:
472            vaStatus = ctx->process_buffer(ctx, obj_buffer);
473            DEBUG_FAILURE;
474        }
475        if (vaStatus != VA_STATUS_SUCCESS) {
476            break;
477        }
478    }
479
480    return vaStatus;
481}
482
483void vld_dec_yuv_rotate(object_context_p obj_context)
484{
485    VAStatus vaStatus = VA_STATUS_SUCCESS;
486    struct format_vtable_s *vtable = &tng_yuv_processor_vtable;
487    struct surface_param_s surface_param;
488    struct object_buffer_s buffer;
489    object_buffer_p buffer_p = &buffer;
490
491    surface_param.src_surface = obj_context->current_render_target->scaling_surface;
492    surface_param.display_width =	obj_context->current_render_target->buffer_width_s;
493    surface_param.display_height = obj_context->current_render_target->buffer_height_s;
494    surface_param.coded_width = obj_context->current_render_target->width_s;
495    surface_param.coded_height = obj_context->current_render_target->height_s;
496
497    buffer.num_elements = 1;
498    buffer.type = YUVProcessorSurfaceType;
499    buffer.size = sizeof(struct surface_param_s);
500    buffer.buffer_data = (unsigned char *)&surface_param;
501
502    vtable->createContext(obj_context, NULL);
503    vtable->beginPicture(obj_context);
504    vtable->renderPicture(obj_context, &buffer_p, 1);
505    vtable->endPicture(obj_context);
506    vtable->destroyContext(obj_context);
507}
508