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 VMWARE 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 pipe_screen *screen, struct ureg_program *shader)
     83 {
     84    struct ureg_dst tmp;
     85    struct ureg_src pos;
     86 
     87    tmp = ureg_DECL_temporary(shader);
     88 
     89    if (screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL))
     90       pos = ureg_DECL_system_value(shader, TGSI_SEMANTIC_POSITION, 0);
     91    else
     92       pos = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS,
     93                                TGSI_INTERPOLATE_LINEAR);
     94 
     95    /*
     96     * tmp.y = fraction(pos.y / 2) >= 0.5 ? 1 : 0
     97     */
     98    ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), pos, ureg_imm1f(shader, 0.5f));
     99    ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp));
    100    ureg_SGE(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_src(tmp), ureg_imm1f(shader, 0.5f));
    101 
    102    return tmp;
    103 }
    104 
    105 static void *
    106 create_ref_vert_shader(struct vl_mc *r)
    107 {
    108    struct ureg_program *shader;
    109    struct ureg_src mv_scale;
    110    struct ureg_src vmv[2];
    111    struct ureg_dst t_vpos;
    112    struct ureg_dst o_vmv[2];
    113    unsigned i;
    114 
    115    shader = ureg_create(PIPE_SHADER_VERTEX);
    116    if (!shader)
    117       return NULL;
    118 
    119    vmv[0] = ureg_DECL_vs_input(shader, VS_I_MV_TOP);
    120    vmv[1] = ureg_DECL_vs_input(shader, VS_I_MV_BOTTOM);
    121 
    122    t_vpos = calc_position(r, shader, ureg_imm2f(shader,
    123       (float)VL_MACROBLOCK_WIDTH / r->buffer_width,
    124       (float)VL_MACROBLOCK_HEIGHT / r->buffer_height)
    125    );
    126 
    127    o_vmv[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP);
    128    o_vmv[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM);
    129 
    130    /*
    131     * mv_scale.xy = 0.5 / (dst.width, dst.height);
    132     * mv_scale.z = 1.0f / 4.0f
    133     * mv_scale.w = 1.0f / 255.0f
    134     *
    135     * // Apply motion vectors
    136     * o_vmv[0..1].xy = vmv[0..1] * mv_scale + t_vpos
    137     * o_vmv[0..1].zw = vmv[0..1] * mv_scale
    138     *
    139     */
    140 
    141    mv_scale = ureg_imm4f(shader,
    142       0.5f / r->buffer_width,
    143       0.5f / r->buffer_height,
    144       1.0f / 4.0f,
    145       1.0f / PIPE_VIDEO_MV_WEIGHT_MAX);
    146 
    147    for (i = 0; i < 2; ++i) {
    148       ureg_MAD(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_XY), mv_scale, vmv[i], ureg_src(t_vpos));
    149       ureg_MUL(shader, ureg_writemask(o_vmv[i], TGSI_WRITEMASK_ZW), mv_scale, vmv[i]);
    150    }
    151 
    152    ureg_release_temporary(shader, t_vpos);
    153 
    154    ureg_END(shader);
    155 
    156    return ureg_create_shader_and_destroy(shader, r->pipe);
    157 }
    158 
    159 static void *
    160 create_ref_frag_shader(struct vl_mc *r)
    161 {
    162    const float y_scale =
    163       r->buffer_height / 2 *
    164       r->macroblock_size / VL_MACROBLOCK_HEIGHT;
    165 
    166    struct ureg_program *shader;
    167    struct ureg_src tc[2], sampler;
    168    struct ureg_dst ref, field;
    169    struct ureg_dst fragment;
    170    unsigned label;
    171 
    172    shader = ureg_create(PIPE_SHADER_FRAGMENT);
    173    if (!shader)
    174       return NULL;
    175 
    176    tc[0] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP, TGSI_INTERPOLATE_LINEAR);
    177    tc[1] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM, TGSI_INTERPOLATE_LINEAR);
    178 
    179    sampler = ureg_DECL_sampler(shader, 0);
    180    ref = ureg_DECL_temporary(shader);
    181 
    182    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    183 
    184    field = calc_line(r->pipe->screen, shader);
    185 
    186    /*
    187     * ref = field.z ? tc[1] : tc[0]
    188     *
    189     * // Adjust tc acording to top/bottom field selection
    190     * if (|ref.z|) {
    191     *    ref.y *= y_scale
    192     *    ref.y = floor(ref.y)
    193     *    ref.y += ref.z
    194     *    ref.y /= y_scale
    195     * }
    196     * fragment.xyz = tex(ref, sampler[0])
    197     */
    198    ureg_CMP(shader, ureg_writemask(ref, TGSI_WRITEMASK_XYZ),
    199             ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
    200             tc[1], tc[0]);
    201    ureg_CMP(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W),
    202             ureg_negate(ureg_scalar(ureg_src(field), TGSI_SWIZZLE_Y)),
    203             tc[1], tc[0]);
    204 
    205    ureg_IF(shader, ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z), &label);
    206 
    207       ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
    208                ureg_src(ref), ureg_imm1f(shader, y_scale));
    209       ureg_FLR(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y), ureg_src(ref));
    210       ureg_ADD(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
    211                ureg_src(ref), ureg_scalar(ureg_src(ref), TGSI_SWIZZLE_Z));
    212       ureg_MUL(shader, ureg_writemask(ref, TGSI_WRITEMASK_Y),
    213                ureg_src(ref), ureg_imm1f(shader, 1.0f / y_scale));
    214 
    215    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    216    ureg_ENDIF(shader);
    217 
    218    ureg_TEX(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), TGSI_TEXTURE_2D, ureg_src(ref), sampler);
    219 
    220    ureg_release_temporary(shader, ref);
    221 
    222    ureg_release_temporary(shader, field);
    223    ureg_END(shader);
    224 
    225    return ureg_create_shader_and_destroy(shader, r->pipe);
    226 }
    227 
    228 static void *
    229 create_ycbcr_vert_shader(struct vl_mc *r, vl_mc_ycbcr_vert_shader vs_callback, void *callback_priv)
    230 {
    231    struct ureg_program *shader;
    232 
    233    struct ureg_src vrect, vpos;
    234    struct ureg_dst t_vpos, t_vtex;
    235    struct ureg_dst o_vpos, o_flags;
    236 
    237    struct vertex2f scale = {
    238       (float)VL_BLOCK_WIDTH / r->buffer_width * VL_MACROBLOCK_WIDTH / r->macroblock_size,
    239       (float)VL_BLOCK_HEIGHT / r->buffer_height * VL_MACROBLOCK_HEIGHT / r->macroblock_size
    240    };
    241 
    242    unsigned label;
    243 
    244    shader = ureg_create(PIPE_SHADER_VERTEX);
    245    if (!shader)
    246       return NULL;
    247 
    248    vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
    249    vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
    250 
    251    t_vpos = calc_position(r, shader, ureg_imm2f(shader, scale.x, scale.y));
    252    t_vtex = ureg_DECL_temporary(shader);
    253 
    254    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
    255    o_flags = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS);
    256 
    257    /*
    258     * o_vtex.xy = t_vpos
    259     * o_flags.z = intra * 0.5
    260     *
    261     * if(interlaced) {
    262     *    t_vtex.xy = vrect.y ? { 0, scale.y } : { -scale.y : 0 }
    263     *    t_vtex.z = vpos.y % 2
    264     *    t_vtex.y = t_vtex.z ? t_vtex.x : t_vtex.y
    265     *    o_vpos.y = t_vtex.y + t_vpos.y
    266     *
    267     *    o_flags.w = t_vtex.z ? 0 : 1
    268     * }
    269     *
    270     */
    271 
    272    vs_callback(callback_priv, r, shader, VS_O_VTEX, t_vpos);
    273 
    274    ureg_MUL(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_Z),
    275             ureg_scalar(vpos, TGSI_SWIZZLE_Z), ureg_imm1f(shader, 0.5f));
    276    ureg_MOV(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W), ureg_imm1f(shader, -1.0f));
    277 
    278    if (r->macroblock_size == VL_MACROBLOCK_HEIGHT) { //TODO
    279       ureg_IF(shader, ureg_scalar(vpos, TGSI_SWIZZLE_W), &label);
    280 
    281          ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_XY),
    282                   ureg_negate(ureg_scalar(vrect, TGSI_SWIZZLE_Y)),
    283                   ureg_imm2f(shader, 0.0f, scale.y),
    284                   ureg_imm2f(shader, -scale.y, 0.0f));
    285          ureg_MUL(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z),
    286                   ureg_scalar(vpos, TGSI_SWIZZLE_Y), ureg_imm1f(shader, 0.5f));
    287 
    288          ureg_FRC(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Z), ureg_src(t_vtex));
    289 
    290          ureg_CMP(shader, ureg_writemask(t_vtex, TGSI_WRITEMASK_Y),
    291                   ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
    292                   ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_X),
    293                   ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Y));
    294          ureg_ADD(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_Y),
    295                   ureg_src(t_vpos), ureg_src(t_vtex));
    296 
    297          ureg_CMP(shader, ureg_writemask(o_flags, TGSI_WRITEMASK_W),
    298                   ureg_negate(ureg_scalar(ureg_src(t_vtex), TGSI_SWIZZLE_Z)),
    299                   ureg_imm1f(shader, 0.0f), ureg_imm1f(shader, 1.0f));
    300 
    301       ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    302       ureg_ENDIF(shader);
    303    }
    304 
    305    ureg_release_temporary(shader, t_vtex);
    306    ureg_release_temporary(shader, t_vpos);
    307 
    308    ureg_END(shader);
    309 
    310    return ureg_create_shader_and_destroy(shader, r->pipe);
    311 }
    312 
    313 static void *
    314 create_ycbcr_frag_shader(struct vl_mc *r, float scale, bool invert,
    315                          vl_mc_ycbcr_frag_shader fs_callback, void *callback_priv)
    316 {
    317    struct ureg_program *shader;
    318    struct ureg_src flags;
    319    struct ureg_dst tmp;
    320    struct ureg_dst fragment;
    321    unsigned label;
    322 
    323    shader = ureg_create(PIPE_SHADER_FRAGMENT);
    324    if (!shader)
    325       return NULL;
    326 
    327    flags = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_FLAGS, TGSI_INTERPOLATE_LINEAR);
    328 
    329    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    330 
    331    tmp = calc_line(r->pipe->screen, shader);
    332 
    333    /*
    334     * if (field == tc.w)
    335     *    kill();
    336     * else {
    337     *    fragment.xyz  = tex(tc, sampler) * scale + tc.z
    338     *    fragment.w = 1.0f
    339     * }
    340     */
    341 
    342    ureg_SEQ(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y),
    343             ureg_scalar(flags, TGSI_SWIZZLE_W), ureg_src(tmp));
    344 
    345    ureg_IF(shader, ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y), &label);
    346 
    347       ureg_KILL(shader);
    348 
    349    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    350    ureg_ELSE(shader, &label);
    351 
    352       fs_callback(callback_priv, r, shader, VS_O_VTEX, tmp);
    353 
    354       if (scale != 1.0f)
    355          ureg_MAD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
    356                   ureg_src(tmp), ureg_imm1f(shader, scale),
    357                   ureg_scalar(flags, TGSI_SWIZZLE_Z));
    358       else
    359          ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XYZ),
    360                   ureg_src(tmp), ureg_scalar(flags, TGSI_SWIZZLE_Z));
    361 
    362       ureg_MUL(shader, ureg_writemask(fragment, TGSI_WRITEMASK_XYZ), ureg_src(tmp), ureg_imm1f(shader, invert ? -1.0f : 1.0f));
    363       ureg_MOV(shader, ureg_writemask(fragment, TGSI_WRITEMASK_W), ureg_imm1f(shader, 1.0f));
    364 
    365    ureg_fixup_label(shader, label, ureg_get_instruction_number(shader));
    366    ureg_ENDIF(shader);
    367 
    368    ureg_release_temporary(shader, tmp);
    369 
    370    ureg_END(shader);
    371 
    372    return ureg_create_shader_and_destroy(shader, r->pipe);
    373 }
    374 
    375 static bool
    376 init_pipe_state(struct vl_mc *r)
    377 {
    378    struct pipe_sampler_state sampler;
    379    struct pipe_blend_state blend;
    380    struct pipe_rasterizer_state rs_state;
    381    unsigned i;
    382 
    383    assert(r);
    384 
    385    memset(&sampler, 0, sizeof(sampler));
    386    sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    387    sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    388    sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_BORDER;
    389    sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
    390    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    391    sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
    392    sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    393    sampler.compare_func = PIPE_FUNC_ALWAYS;
    394    sampler.normalized_coords = 1;
    395    r->sampler_ref = r->pipe->create_sampler_state(r->pipe, &sampler);
    396    if (!r->sampler_ref)
    397       goto error_sampler_ref;
    398 
    399    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
    400       memset(&blend, 0, sizeof blend);
    401       blend.independent_blend_enable = 0;
    402       blend.rt[0].blend_enable = 1;
    403       blend.rt[0].rgb_func = PIPE_BLEND_ADD;
    404       blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
    405       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
    406       blend.rt[0].alpha_func = PIPE_BLEND_ADD;
    407       blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
    408       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
    409       blend.logicop_enable = 0;
    410       blend.logicop_func = PIPE_LOGICOP_CLEAR;
    411       blend.rt[0].colormask = i;
    412       blend.dither = 0;
    413       r->blend_clear[i] = r->pipe->create_blend_state(r->pipe, &blend);
    414       if (!r->blend_clear[i])
    415          goto error_blend;
    416 
    417       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
    418       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
    419       r->blend_add[i] = r->pipe->create_blend_state(r->pipe, &blend);
    420       if (!r->blend_add[i])
    421          goto error_blend;
    422 
    423       blend.rt[0].rgb_func = PIPE_BLEND_REVERSE_SUBTRACT;
    424       blend.rt[0].alpha_dst_factor = PIPE_BLEND_REVERSE_SUBTRACT;
    425       r->blend_sub[i] = r->pipe->create_blend_state(r->pipe, &blend);
    426       if (!r->blend_sub[i])
    427          goto error_blend;
    428    }
    429 
    430    memset(&rs_state, 0, sizeof(rs_state));
    431    /*rs_state.sprite_coord_enable */
    432    rs_state.sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
    433    rs_state.point_quad_rasterization = true;
    434    rs_state.point_size = VL_BLOCK_WIDTH;
    435    rs_state.half_pixel_center = true;
    436    rs_state.bottom_edge_rule = true;
    437    rs_state.depth_clip = 1;
    438    r->rs_state = r->pipe->create_rasterizer_state(r->pipe, &rs_state);
    439    if (!r->rs_state)
    440       goto error_rs_state;
    441 
    442    return true;
    443 
    444 error_rs_state:
    445 error_blend:
    446    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
    447       if (r->blend_sub[i])
    448          r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
    449 
    450       if (r->blend_add[i])
    451          r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
    452 
    453       if (r->blend_clear[i])
    454          r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
    455    }
    456 
    457    r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
    458 
    459 error_sampler_ref:
    460    return false;
    461 }
    462 
    463 static void
    464 cleanup_pipe_state(struct vl_mc *r)
    465 {
    466    unsigned i;
    467 
    468    assert(r);
    469 
    470    r->pipe->delete_sampler_state(r->pipe, r->sampler_ref);
    471    for (i = 0; i < VL_MC_NUM_BLENDERS; ++i) {
    472       r->pipe->delete_blend_state(r->pipe, r->blend_clear[i]);
    473       r->pipe->delete_blend_state(r->pipe, r->blend_add[i]);
    474       r->pipe->delete_blend_state(r->pipe, r->blend_sub[i]);
    475    }
    476    r->pipe->delete_rasterizer_state(r->pipe, r->rs_state);
    477 }
    478 
    479 bool
    480 vl_mc_init(struct vl_mc *renderer, struct pipe_context *pipe,
    481            unsigned buffer_width, unsigned buffer_height,
    482            unsigned macroblock_size, float scale,
    483            vl_mc_ycbcr_vert_shader vs_callback,
    484            vl_mc_ycbcr_frag_shader fs_callback,
    485            void *callback_priv)
    486 {
    487    assert(renderer);
    488    assert(pipe);
    489 
    490    memset(renderer, 0, sizeof(struct vl_mc));
    491 
    492    renderer->pipe = pipe;
    493    renderer->buffer_width = buffer_width;
    494    renderer->buffer_height = buffer_height;
    495    renderer->macroblock_size = macroblock_size;
    496 
    497    if (!init_pipe_state(renderer))
    498       goto error_pipe_state;
    499 
    500    renderer->vs_ref = create_ref_vert_shader(renderer);
    501    if (!renderer->vs_ref)
    502       goto error_vs_ref;
    503 
    504    renderer->vs_ycbcr = create_ycbcr_vert_shader(renderer, vs_callback, callback_priv);
    505    if (!renderer->vs_ycbcr)
    506       goto error_vs_ycbcr;
    507 
    508    renderer->fs_ref = create_ref_frag_shader(renderer);
    509    if (!renderer->fs_ref)
    510       goto error_fs_ref;
    511 
    512    renderer->fs_ycbcr = create_ycbcr_frag_shader(renderer, scale, false, fs_callback, callback_priv);
    513    if (!renderer->fs_ycbcr)
    514       goto error_fs_ycbcr;
    515 
    516    renderer->fs_ycbcr_sub = create_ycbcr_frag_shader(renderer, scale, true, fs_callback, callback_priv);
    517    if (!renderer->fs_ycbcr_sub)
    518       goto error_fs_ycbcr_sub;
    519 
    520    return true;
    521 
    522 error_fs_ycbcr_sub:
    523    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
    524 
    525 error_fs_ycbcr:
    526    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
    527 
    528 error_fs_ref:
    529    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
    530 
    531 error_vs_ycbcr:
    532    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
    533 
    534 error_vs_ref:
    535    cleanup_pipe_state(renderer);
    536 
    537 error_pipe_state:
    538    return false;
    539 }
    540 
    541 void
    542 vl_mc_cleanup(struct vl_mc *renderer)
    543 {
    544    assert(renderer);
    545 
    546    cleanup_pipe_state(renderer);
    547 
    548    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ref);
    549    renderer->pipe->delete_vs_state(renderer->pipe, renderer->vs_ycbcr);
    550    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ref);
    551    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr);
    552    renderer->pipe->delete_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
    553 }
    554 
    555 bool
    556 vl_mc_init_buffer(struct vl_mc *renderer, struct vl_mc_buffer *buffer)
    557 {
    558    assert(renderer && buffer);
    559 
    560    buffer->viewport.scale[2] = 1;
    561    buffer->viewport.translate[0] = 0;
    562    buffer->viewport.translate[1] = 0;
    563    buffer->viewport.translate[2] = 0;
    564 
    565    buffer->fb_state.nr_cbufs = 1;
    566    buffer->fb_state.zsbuf = NULL;
    567 
    568    return true;
    569 }
    570 
    571 void
    572 vl_mc_cleanup_buffer(struct vl_mc_buffer *buffer)
    573 {
    574    assert(buffer);
    575 }
    576 
    577 void
    578 vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface)
    579 {
    580    assert(buffer && surface);
    581 
    582    buffer->surface_cleared = false;
    583 
    584    buffer->viewport.scale[0] = surface->width;
    585    buffer->viewport.scale[1] = surface->height;
    586 
    587    buffer->fb_state.width = surface->width;
    588    buffer->fb_state.height = surface->height;
    589    buffer->fb_state.cbufs[0] = surface;
    590 }
    591 
    592 static void
    593 prepare_pipe_4_rendering(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned mask)
    594 {
    595    assert(buffer);
    596 
    597    renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state);
    598 
    599    if (buffer->surface_cleared)
    600       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_add[mask]);
    601    else
    602       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_clear[mask]);
    603 
    604    renderer->pipe->set_framebuffer_state(renderer->pipe, &buffer->fb_state);
    605    renderer->pipe->set_viewport_states(renderer->pipe, 0, 1, &buffer->viewport);
    606 }
    607 
    608 void
    609 vl_mc_render_ref(struct vl_mc *renderer, struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref)
    610 {
    611    assert(buffer && ref);
    612 
    613    prepare_pipe_4_rendering(renderer, buffer, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B);
    614 
    615    renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ref);
    616    renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ref);
    617 
    618    renderer->pipe->set_sampler_views(renderer->pipe, PIPE_SHADER_FRAGMENT,
    619                                      0, 1, &ref);
    620    renderer->pipe->bind_sampler_states(renderer->pipe, PIPE_SHADER_FRAGMENT,
    621                                        0, 1, &renderer->sampler_ref);
    622 
    623    util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0,
    624                               renderer->buffer_width / VL_MACROBLOCK_WIDTH *
    625                               renderer->buffer_height / VL_MACROBLOCK_HEIGHT);
    626 
    627    buffer->surface_cleared = true;
    628 }
    629 
    630 void
    631 vl_mc_render_ycbcr(struct vl_mc *renderer, struct vl_mc_buffer *buffer, unsigned component, unsigned num_instances)
    632 {
    633    unsigned mask = 1 << component;
    634 
    635    assert(buffer);
    636 
    637    if (num_instances == 0)
    638       return;
    639 
    640    prepare_pipe_4_rendering(renderer, buffer, mask);
    641 
    642    renderer->pipe->bind_vs_state(renderer->pipe, renderer->vs_ycbcr);
    643    renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr);
    644 
    645    util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
    646 
    647    if (buffer->surface_cleared) {
    648       renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_sub[mask]);
    649       renderer->pipe->bind_fs_state(renderer->pipe, renderer->fs_ycbcr_sub);
    650       util_draw_arrays_instanced(renderer->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
    651    }
    652 }
    653