Home | History | Annotate | Download | only in vl
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 Younes Manton.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include <assert.h>
     29 
     30 #include "pipe/p_context.h"
     31 
     32 #include "util/u_sampler.h"
     33 #include "util/u_draw.h"
     34 
     35 #include "tgsi/tgsi_ureg.h"
     36 
     37 #include "vl_defines.h"
     38 #include "vl_vertex_buffers.h"
     39 #include "vl_mc.h"
     40 #include "vl_idct.h"
     41 
     42 enum VS_OUTPUT
     43 {
     44    VS_O_VPOS = 0,
     45    VS_O_VTOP = 0,
     46    VS_O_VBOTTOM,
     47 
     48    VS_O_FLAGS = VS_O_VTOP,
     49    VS_O_VTEX = VS_O_VBOTTOM
     50 };
     51 
     52 static struct ureg_dst
     53 calc_position(struct vl_mc *r, struct ureg_program *shader, struct ureg_src block_scale)
     54 {
     55    struct ureg_src vrect, vpos;
     56    struct ureg_dst t_vpos;
     57    struct ureg_dst o_vpos;
     58 
     59    vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
     60    vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
     61 
     62    t_vpos = ureg_DECL_temporary(shader);
     63 
     64    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
     65 
     66    /*
     67     * block_scale = (VL_MACROBLOCK_WIDTH, VL_MACROBLOCK_HEIGHT) / (dst.width, dst.height)
     68     *
     69     * t_vpos = (vpos + vrect) * block_scale
     70     * o_vpos.xy = t_vpos
     71     * o_vpos.zw = vpos
     72     */
     73    ureg_ADD(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), vpos, vrect);
     74    ureg_MUL(shader, ureg_writemask(t_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos), block_scale);
     75    ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(t_vpos));
     76    ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
     77 
     78    return t_vpos;
     79 }
     80 
     81 static struct ureg_dst
     82 calc_line(struct ureg_program *shader)
     83 {
     84    struct ureg_dst tmp;
     85    struct ureg_src pos;
     86 
     87    tmp = ureg_DECL_temporary(shader);
     88 
     89    pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS, TGSI_INTERPOLATE_LINEAR);
     90 
     91    /*
     92     * tmp.y = fraction(pos.y / 2) >= 0.5 ? 1 : 0
     93     */
     94    ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f));
     95    ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp));
     96    ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
     97 
     98    return tmp;
     99 }
    100 
    101 static void *
    102 create_ref_vert_shader(struct vl_mc *r)
    103 {
    104    struct ureg_program *shader;
    105    struct ureg_src mv_scale;
    106    struct ureg_src vmv[2];
    107    struct ureg_dst t_vpos;
    108    struct ureg_dst o_vmv[2];
    109    unsigned i;
    110 
    111    shader = ureg_create(TGSI_PROCESSOR_VERTEX);
    112    if (!shader)
    113       return NULL;
    114 
    115    vmv[0] = ureg_DECL_vs_input(shader, VS_I_MV_TOP);
    116    vmv[1] = ureg_DECL_vs_input(shader, VS_I_MV_BOTTOM);
    117 
    118    t_vpos = calc_position(r, shader, ureg_imm2f(shader,
    119       (float)VL_MACROBLOCK_WIDTH / r->buffer_width,
    120       (float)VL_MACROBLOCK_HEIGHT / r->buffer_height)
    121    );
    122 
    123    o_vmv[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP);
    124    o_vmv[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM);
    125 
    126    /*
    127     * mv_scale.xy = 0.5 / (dst.width, dst.height);
    128     * mv_scale.z = 1.0f / 4.0f
    129     * mv_scale.w = 1.0f / 255.0f
    130     *
    131     * // Apply motion vectors
    132     * o_vmv[0..1].xy = vmv[0..1] * mv_scale + t_vpos
    133     * o_vmv[0..1].zw = vmv[0..1] * mv_scale
    134     *
    135     */
    136 
    137    mv_scale = ureg_imm4f(shader,
    138       0.5f / r->buffer_width,
    139       0.5f / r->buffer_height,
    140       1.0f / 4.0f,
    141       1.0f / PIPE_VIDEO_MV_WEIGHT_MAX);
    142 
    143    for (i = 0; i < 2; ++i) {
    144       ureg_MAD(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_XY), mv_scale, vmv[i], ureg_src(t_vpos));
    145       ureg_MUL(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_ZW), mv_scale, vmv[i]);
    146    }
    147 
    148    ureg_release_temporary(shader, t_vpos);
    149 
    150    ureg_END(shader);
    151 
    152    return ureg_create_shader_and_destroy(shader, r->pipe);
    153 }
    154 
    155 static void *
    156 create_ref_frag_shader(struct vl_mc *r)
    157 {
    158    const float y_scale =
    159       r->buffer_height / 2 *
    160       r->macroblock_size / VL_MACROBLOCK_HEIGHT;
    161 
    162    struct ureg_program *shader;
    163    struct ureg_src tc[2], sampler;
    164    struct ureg_dst ref, field;
    165    struct ureg_dst fragment;
    166    unsigned label;
    167 
    168    shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
    169    if (!shader)
    170       return NULL;
    171 
    172    tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP, TGSI_INTERPOLATE_LINEAR);
    173    tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM, TGSI_INTERPOLATE_LINEAR);
    174 
    175    sampler = ureg_DECL_sampler(shader, 0);
    176    ref = ureg_DECL_temporary(shader);
    177 
    178    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    179 
    180    field = calc_line(shader);
    181 
    182    /*
    183     * ref = field.z ? tc[1] : tc[0]
    184     *
    185     * // Adjust tc acording to top/bottom field selection
    186     * if (|ref.z|) {
    187     *    ref.y *= y_scale
    188     *    ref.y = floor(ref.y)
    189     *    ref.y += ref.z
    190     *    ref.y /= y_scale
    191     * }
    192     * fragment.xyz = tex(ref, sampler[0])
    193     */
    194    ureg_CMP(shader, ureg_writemask(ref, TGSI_WRITEMASK_XYZ),
    195             ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
    196             tc[1], tc[0]);
    197    ureg_CMP(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W),
    198             ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
    199             tc[1], tc[0]);
    200 
    201    ureg_IF(shader, ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z), &label);
    202 
    203       ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
    204                ureg_src(ref), ureg_imm1f(shader, y_scale));
    205       ureg_FLR(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), ureg_src(ref));
    206       ureg_ADD(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
    207                ureg_src(ref), ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z));
    208       ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
    209                ureg_src(ref), ureg_imm1f(shader, 1.0f / y_scale));
    210 
    211    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    212    ureg_ENDIF(shader);
    213 
    214    ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), TGSI_TEXTURE_2D, ureg_src(ref), sampler);
    215 
    216    ureg_release_temporary(shader, ref);
    217 
    218    ureg_release_temporary(shader, field);
    219    ureg_END(shader);
    220 
    221    return ureg_create_shader_and_destroy(shader, r->pipe);
    222 }
    223 
    224 static void *
    225 create_ycbcr_vert_shader(struct vl_mc *r, vl_mc_ycbcr_vert_shader vs_callback, void *callback_priv)
    226 {
    227    struct ureg_program *shader;
    228 
    229    struct ureg_src vrect, vpos;
    230    struct ureg_dst t_vpos, t_vtex;
    231    struct ureg_dst o_vpos, o_flags;
    232 
    233    struct vertex2f scale = {
    234       (float)VL_BLOCK_WIDTH / r->buffer_width * VL_MACROBLOCK_WIDTH / r->macroblock_size,
    235       (float)VL_BLOCK_HEIGHT / r->buffer_height * VL_MACROBLOCK_HEIGHT / r->macroblock_size
    236    };
    237 
    238    unsigned label;
    239 
    240    shader = ureg_create(TGSI_PROCESSOR_VERTEX);
    241    if (!shader)
    242       return NULL;
    243 
    244    vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
    245    vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
    246 
    247    t_vpos = calc_position(r, shader, ureg_imm2f(shader, scale.x, scale.y));
    248    t_vtex = ureg_DECL_temporary(shader);
    249 
    250    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
    251    o_flags = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS);
    252 
    253    /*
    254     * o_vtex.xy = t_vpos
    255     * o_flags.z = intra * 0.5
    256     *
    257     * if(interlaced) {
    258     *    t_vtex.xy = vrect.y ? { 0, scale.y } : { -scale.y : 0 }
    259     *    t_vtex.z = vpos.y % 2
    260     *    t_vtex.y = t_vtex.z ? t_vtex.x : t_vtex.y
    261     *    o_vpos.y = t_vtex.y + t_vpos.y
    262     *
    263     *    o_flags.w = t_vtex.z ? 0 : 1
    264     * }
    265     *
    266     */
    267 
    268    vs_callback(callback_priv, r, shader, VS_O_VTEX, t_vpos);
    269 
    270    ureg_MUL(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_Z),
    271             ureg_scalar(vpos, TGSI_SWIZZLE_Z), ureg_imm1f(shader, 0.5f));
    272    ureg_MOV(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W), ureg_imm1f(shader, -1.0f));
    273 
    274    if (r->macroblock_size == VL_MACROBLOCK_HEIGHT) { //TODO
    275       ureg_IF(shader, ureg_scalar(vpos, TGSI_SWIZZLE_W), &label);
    276 
    277          ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_XY),
    278                   ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_Y)),
    279                   ureg_imm2f(shader, 0.0f, scale.y),
    280                   ureg_imm2f(shader, -scale.y, 0.0f));
    281          ureg_MUL(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z),
    282                   ureg_scalar(vpos, TGSI_SWIZZLE_Y), ureg_imm1f(shader, 0.5f));
    283 
    284          ureg_FRC(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z), ureg_src(t_vtex));
    285 
    286          ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y),
    287                   ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
    288                   ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_X),
    289                   ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Y));
    290          ureg_ADD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_Y),
    291                   ureg_src(t_vpos), ureg_src(t_vtex));
    292 
    293          ureg_CMP(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W),
    294                   ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
    295                   ureg_imm1f(shader, 0.0f), ureg_imm1f(shader, 1.0f));
    296 
    297       ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    298       ureg_ENDIF(shader);
    299    }
    300 
    301    ureg_release_temporary(shader, t_vtex);
    302    ureg_release_temporary(shader, t_vpos);
    303 
    304    ureg_END(shader);
    305 
    306    return ureg_create_shader_and_destroy(shader, r->pipe);
    307 }
    308 
    309 static void *
    310 create_ycbcr_frag_shader(struct vl_mc *r, float scale, bool invert,
    311                          vl_mc_ycbcr_frag_shader fs_callback, void *callback_priv)
    312 {
    313    struct ureg_program *shader;
    314    struct ureg_src flags;
    315    struct ureg_dst tmp;
    316    struct ureg_dst fragment;
    317    unsigned label;
    318 
    319    shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
    320    if (!shader)
    321       return NULL;
    322 
    323    flags = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS, TGSI_INTERPOLATE_LINEAR);
    324 
    325    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    326 
    327    tmp = calc_line(shader);
    328 
    329    /*
    330     * if (field == tc.w)
    331     *    kill();
    332     * else {
    333     *    fragment.xyz  = tex(tc, sampler) * scale + tc.z
    334     *    fragment.w = 1.0f
    335     * }
    336     */
    337 
    338    ureg_SEQ(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y),
    339             ureg_scalar(flags, TGSI_SWIZZLE_W), ureg_src(tmp));
    340 
    341    ureg_IF(shader, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), &label);
    342 
    343       ureg_KILP(shader);
    344 
    345    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    346    ureg_ELSE(shader, &label);
    347 
    348       fs_callback(callback_priv, r, shader, VS_O_VTEX, tmp);
    349 
    350       if (scale != 1.0f)
    351          ureg_MAD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
    352                   ureg_src(tmp), ureg_imm1f(shader, scale),
    353                   ureg_scalar(flags, TGSI_SWIZZLE_Z));
    354       else
    355          ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
    356                   ureg_src(tmp), ureg_scalar(flags, TGSI_SWIZZLE_Z));
    357 
    358       ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(tmp), ureg_imm1f(shader, invert ? -1.0f : 1.0f));
    359       ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
    360 
    361    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    362    ureg_ENDIF(shader);
    363 
    364    ureg_release_temporary(shader, tmp);
    365 
    366    ureg_END(shader);
    367 
    368    return ureg_create_shader_and_destroy(shader, r->pipe);
    369 }
    370 
    371 static bool
    372 init_pipe_state(struct vl_mc *r)
    373 {
    374    struct pipe_sampler_state sampler;
    375    struct pipe_blend_state blend;
    376    struct pipe_rasterizer_state rs_state;
    377    unsigned i;
    378 
    379    assert(r);
    380 
    381    memset(&sampler, 0, sizeof(sampler));
    382    sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    383    sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    384    sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
    385    sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
    386    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    387    sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
    388    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    389    sampler.compare_func = PIPE_FUNC_ALWAYS;
    390    sampler.normalized_coords = 1;
    391    r->sampler_ref = r->pipe->create_sampler_state(r->pipe, &sampler);
    392    if (!r->sampler_ref)
    393       goto error_sampler_ref;
    394 
    395    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
    396       memset(&blend, 0, sizeof blend);
    397       blend.independent_blend_enable = 0;
    398       blend.rt[0].blend_enable = 1;
    399       blend.rt[0].rgb_func = PIPE_BLEND_ADD;
    400       blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
    401       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
    402       blend.rt[0].alpha_func = PIPE_BLEND_ADD;
    403       blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
    404       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
    405       blend.logicop_enable = 0;
    406       blend.logicop_func = PIPE_LOGICOP_CLEAR;
    407       blend.rt[0].colormask = i;
    408       blend.dither = 0;
    409       r->blend_clear[i] = r->pipe->create_blend_state(r->pipe, &blend);
    410       if (!r->blend_clear[i])
    411          goto error_blend;
    412 
    413       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
    414       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
    415       r->blend_add[i] = r->pipe->create_blend_state(r->pipe, &blend);
    416       if (!r->blend_add[i])
    417          goto error_blend;
    418 
    419       blend.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT;
    420       blend.rt[0].alpha_dst_factor = PIPE_BLEND_REVERSE_SUBTRACT;
    421       r->blend_sub[i] = r->pipe->create_blend_state(r->pipe, &blend);
    422       if (!r->blend_sub[i])
    423          goto error_blend;
    424    }
    425 
    426    memset(&rs_state, 0, sizeof(rs_state));
    427    /*rs_state.sprite_coord_enable */
    428    rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
    429    rs_state.point_quad_rasterization = true;
    430    rs_state.point_size = VL_BLOCK_WIDTH;
    431    rs_state.gl_rasterization_rules = true;
    432    rs_state.depth_clip = 1;
    433    r->rs_state = r->pipe->create_rasterizer_state(r->pipe, &rs_state);
    434    if (!r->rs_state)
    435       goto error_rs_state;
    436 
    437    return true;
    438 
    439 error_rs_state:
    440 error_blend:
    441    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
    442       if (r->blend_sub[i])
    443          r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
    444 
    445       if (r->blend_add[i])
    446          r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
    447 
    448       if (r->blend_clear[i])
    449          r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
    450    }
    451 
    452    r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
    453 
    454 error_sampler_ref:
    455    return false;
    456 }
    457 
    458 static void
    459 cleanup_pipe_state(struct vl_mc *r)
    460 {
    461    unsigned i;
    462 
    463    assert(r);
    464 
    465    r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
    466    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
    467       r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
    468       r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
    469       r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
    470    }
    471    r->pipe->delete_rasterizer_state(r->pipe, r->rs_state);
    472 }
    473 
    474 bool
    475 vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe,
    476            unsigned buffer_width, unsigned buffer_height,
    477            unsigned macroblock_size, float scale,
    478            vl_mc_ycbcr_vert_shader vs_callback,
    479            vl_mc_ycbcr_frag_shader fs_callback,
    480            void *callback_priv)
    481 {
    482    assert(renderer);
    483    assert(pipe);
    484 
    485    memset(renderer, 0, sizeof(struct vl_mc));
    486 
    487    renderer->pipe = pipe;
    488    renderer->buffer_width = buffer_width;
    489    renderer->buffer_height = buffer_height;
    490    renderer->macroblock_size = macroblock_size;
    491 
    492    if (!init_pipe_state(renderer))
    493       goto error_pipe_state;
    494 
    495    renderer->vs_ref = create_ref_vert_shader(renderer);
    496    if (!renderer->vs_ref)
    497       goto error_vs_ref;
    498 
    499    renderer->vs_ycbcr = create_ycbcr_vert_shader(renderer, vs_callback, callback_priv);
    500    if (!renderer->vs_ycbcr)
    501       goto error_vs_ycbcr;
    502 
    503    renderer->fs_ref = create_ref_frag_shader(renderer);
    504    if (!renderer->fs_ref)
    505       goto error_fs_ref;
    506 
    507    renderer->fs_ycbcr = create_ycbcr_frag_shader(renderer, scale, false, fs_callback, callback_priv);
    508    if (!renderer->fs_ycbcr)
    509       goto error_fs_ycbcr;
    510 
    511    renderer->fs_ycbcr_sub = create_ycbcr_frag_shader(renderer, scale, true, fs_callback, callback_priv);
    512    if (!renderer->fs_ycbcr_sub)
    513       goto error_fs_ycbcr_sub;
    514 
    515    return true;
    516 
    517 error_fs_ycbcr_sub:
    518    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
    519 
    520 error_fs_ycbcr:
    521    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
    522 
    523 error_fs_ref:
    524    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
    525 
    526 error_vs_ycbcr:
    527    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
    528 
    529 error_vs_ref:
    530    cleanup_pipe_state(renderer);
    531 
    532 error_pipe_state:
    533    return false;
    534 }
    535 
    536 void
    537 vl_mc_cleanup(struct vl_mc *renderer)
    538 {
    539    assert(renderer);
    540 
    541    cleanup_pipe_state(renderer);
    542 
    543    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
    544    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
    545    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
    546    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
    547    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
    548 }
    549 
    550 bool
    551 vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer)
    552 {
    553    assert(renderer && buffer);
    554 
    555    buffer->viewport.scale[2] = 1;
    556    buffer->viewport.scale[3] = 1;
    557    buffer->viewport.translate[0] = 0;
    558    buffer->viewport.translate[1] = 0;
    559    buffer->viewport.translate[2] = 0;
    560    buffer->viewport.translate[3] = 0;
    561 
    562    buffer->fb_state.nr_cbufs = 1;
    563    buffer->fb_state.zsbuf = NULL;
    564 
    565    return true;
    566 }
    567 
    568 void
    569 vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer)
    570 {
    571    assert(buffer);
    572 }
    573 
    574 void
    575 vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface)
    576 {
    577    assert(buffer && surface);
    578 
    579    buffer->surface_cleared = false;
    580 
    581    buffer->viewport.scale[0] = surface->width;
    582    buffer->viewport.scale[1] = surface->height;
    583 
    584    buffer->fb_state.width = surface->width;
    585    buffer->fb_state.height = surface->height;
    586    buffer->fb_state.cbufs[0] = surface;
    587 }
    588 
    589 static void
    590 prepare_pipe_4_rendering(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned mask)
    591 {
    592    assert(buffer);
    593 
    594    renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state);
    595 
    596    if (buffer->surface_cleared)
    597       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_add[mask]);
    598    else
    599       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_clear[mask]);
    600 
    601    renderer->pipe->set_framebuffer_state(renderer->pipe, &buffer->fb_state);
    602    renderer->pipe->set_viewport_state(renderer->pipe, &buffer->viewport);
    603 }
    604 
    605 void
    606 vl_mc_render_ref(struct vl_mc *renderer, struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref)
    607 {
    608    assert(buffer && ref);
    609 
    610    prepare_pipe_4_rendering(renderer, buffer, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B);
    611 
    612    renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ref);
    613    renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ref);
    614 
    615    renderer->pipe->set_fragment_sampler_views(renderer->pipe, 1, &ref);
    616    renderer->pipe->bind_fragment_sampler_states(renderer->pipe, 1, &renderer->sampler_ref);
    617 
    618    util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0,
    619                               renderer->buffer_width / VL_MACROBLOCK_WIDTH *
    620                               renderer->buffer_height / VL_MACROBLOCK_HEIGHT);
    621 
    622    buffer->surface_cleared = true;
    623 }
    624 
    625 void
    626 vl_mc_render_ycbcr(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances)
    627 {
    628    unsigned mask = 1 << component;
    629 
    630    assert(buffer);
    631 
    632    if (num_instances == 0)
    633       return;
    634 
    635    prepare_pipe_4_rendering(renderer, buffer, mask);
    636 
    637    renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ycbcr);
    638    renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr);
    639 
    640    util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
    641 
    642    if (buffer->surface_cleared) {
    643       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_sub[mask]);
    644       renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
    645       util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
    646    }
    647 }
    648