Home | History | Annotate | Download | only in vl
      1 /**************************************************************************
      2  *
      3  * Copyright 2011 Christian Knig
      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_screen.h"
     31 #include "pipe/p_context.h"
     32 
     33 #include "util/u_draw.h"
     34 #include "util/u_sampler.h"
     35 #include "util/u_inlines.h"
     36 #include "util/u_memory.h"
     37 
     38 #include "tgsi/tgsi_ureg.h"
     39 
     40 #include "vl_defines.h"
     41 #include "vl_types.h"
     42 
     43 #include "vl_zscan.h"
     44 #include "vl_vertex_buffers.h"
     45 
     46 enum VS_OUTPUT
     47 {
     48    VS_O_VPOS = 0,
     49    VS_O_VTEX = 0
     50 };
     51 
     52 const int vl_zscan_normal_16[] =
     53 {
     54    /* Zig-Zag scan pattern */
     55     0, 1, 4, 8, 5, 2, 3, 6,
     56     9,12,13,10, 7,11,14,15
     57 };
     58 
     59 const int vl_zscan_linear[] =
     60 {
     61    /* Linear scan pattern */
     62     0, 1, 2, 3, 4, 5, 6, 7,
     63     8, 9,10,11,12,13,14,15,
     64    16,17,18,19,20,21,22,23,
     65    24,25,26,27,28,29,30,31,
     66    32,33,34,35,36,37,38,39,
     67    40,41,42,43,44,45,46,47,
     68    48,49,50,51,52,53,54,55,
     69    56,57,58,59,60,61,62,63
     70 };
     71 
     72 const int vl_zscan_normal[] =
     73 {
     74    /* Zig-Zag scan pattern */
     75     0, 1, 8,16, 9, 2, 3,10,
     76    17,24,32,25,18,11, 4, 5,
     77    12,19,26,33,40,48,41,34,
     78    27,20,13, 6, 7,14,21,28,
     79    35,42,49,56,57,50,43,36,
     80    29,22,15,23,30,37,44,51,
     81    58,59,52,45,38,31,39,46,
     82    53,60,61,54,47,55,62,63
     83 };
     84 
     85 const int vl_zscan_alternate[] =
     86 {
     87    /* Alternate scan pattern */
     88     0, 8,16,24, 1, 9, 2,10,
     89    17,25,32,40,48,56,57,49,
     90    41,33,26,18, 3,11, 4,12,
     91    19,27,34,42,50,58,35,43,
     92    51,59,20,28, 5,13, 6,14,
     93    21,29,36,44,52,60,37,45,
     94    53,61,22,30, 7,15,23,31,
     95    38,46,54,62,39,47,55,63
     96 };
     97 
     98 static void *
     99 create_vert_shader(struct vl_zscan *zscan)
    100 {
    101    struct ureg_program *shader;
    102    struct ureg_src scale;
    103    struct ureg_src vrect, vpos, block_num;
    104    struct ureg_dst tmp;
    105    struct ureg_dst o_vpos;
    106    struct ureg_dst *o_vtex;
    107    unsigned i;
    108 
    109    shader = ureg_create(PIPE_SHADER_VERTEX);
    110    if (!shader)
    111       return NULL;
    112 
    113    o_vtex = MALLOC(zscan->num_channels * sizeof(struct ureg_dst));
    114 
    115    scale = ureg_imm2f(shader,
    116       (float)VL_BLOCK_WIDTH / zscan->buffer_width,
    117       (float)VL_BLOCK_HEIGHT / zscan->buffer_height);
    118 
    119    vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
    120    vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
    121    block_num = ureg_DECL_vs_input(shader, VS_I_BLOCK_NUM);
    122 
    123    tmp = ureg_DECL_temporary(shader);
    124 
    125    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
    126 
    127    for (i = 0; i < zscan->num_channels; ++i)
    128       o_vtex[i] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX + i);
    129 
    130    /*
    131     * o_vpos.xy = (vpos + vrect) * scale
    132     * o_vpos.zw = 1.0f
    133     *
    134     * tmp.xy = InstanceID / blocks_per_line
    135     * tmp.x = frac(tmp.x)
    136     * tmp.y = floor(tmp.y)
    137     *
    138     * o_vtex.x = vrect.x / blocks_per_line + tmp.x
    139     * o_vtex.y = vrect.y
    140     * o_vtex.z = tmp.z * blocks_per_line / blocks_total
    141     */
    142    ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XY), vpos, vrect);
    143    ureg_MUL(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_XY), ureg_src(tmp), scale);
    144    ureg_MOV(shader, ureg_writemask(o_vpos, TGSI_WRITEMASK_ZW), ureg_imm1f(shader, 1.0f));
    145 
    146    ureg_MUL(shader, ureg_writemask(tmp, TGSI_WRITEMASK_XW), ureg_scalar(block_num, TGSI_SWIZZLE_X),
    147             ureg_imm1f(shader, 1.0f / zscan->blocks_per_line));
    148 
    149    ureg_FRC(shader, ureg_writemask(tmp, TGSI_WRITEMASK_Y), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_X));
    150    ureg_FLR(shader, ureg_writemask(tmp, TGSI_WRITEMASK_W), ureg_src(tmp));
    151 
    152    for (i = 0; i < zscan->num_channels; ++i) {
    153       ureg_ADD(shader, ureg_writemask(tmp, TGSI_WRITEMASK_X), ureg_scalar(ureg_src(tmp), TGSI_SWIZZLE_Y),
    154                ureg_imm1f(shader, 1.0f / (zscan->blocks_per_line * VL_BLOCK_WIDTH)
    155                 * ((signed)i - (signed)zscan->num_channels / 2)));
    156 
    157       ureg_MAD(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_X), vrect,
    158                ureg_imm1f(shader, 1.0f / zscan->blocks_per_line), ureg_src(tmp));
    159       ureg_MOV(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_Y), vrect);
    160       ureg_MOV(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_Z), vpos);
    161       ureg_MUL(shader, ureg_writemask(o_vtex[i], TGSI_WRITEMASK_W), ureg_src(tmp),
    162                ureg_imm1f(shader, (float)zscan->blocks_per_line / zscan->blocks_total));
    163    }
    164 
    165    ureg_release_temporary(shader, tmp);
    166    ureg_END(shader);
    167 
    168    FREE(o_vtex);
    169 
    170    return ureg_create_shader_and_destroy(shader, zscan->pipe);
    171 }
    172 
    173 static void *
    174 create_frag_shader(struct vl_zscan *zscan)
    175 {
    176    struct ureg_program *shader;
    177    struct ureg_src *vtex;
    178 
    179    struct ureg_src samp_src, samp_scan, samp_quant;
    180 
    181    struct ureg_dst *tmp;
    182    struct ureg_dst quant, fragment;
    183 
    184    unsigned i;
    185 
    186    shader = ureg_create(PIPE_SHADER_FRAGMENT);
    187    if (!shader)
    188       return NULL;
    189 
    190    vtex = MALLOC(zscan->num_channels * sizeof(struct ureg_src));
    191    tmp = MALLOC(zscan->num_channels * sizeof(struct ureg_dst));
    192 
    193    for (i = 0; i < zscan->num_channels; ++i)
    194       vtex[i] = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX + i, TGSI_INTERPOLATE_LINEAR);
    195 
    196    samp_src = ureg_DECL_sampler(shader, 0);
    197    samp_scan = ureg_DECL_sampler(shader, 1);
    198    samp_quant = ureg_DECL_sampler(shader, 2);
    199 
    200    for (i = 0; i < zscan->num_channels; ++i)
    201       tmp[i] = ureg_DECL_temporary(shader);
    202    quant = ureg_DECL_temporary(shader);
    203 
    204    fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    205 
    206    /*
    207     * tmp.x = tex(vtex, 1)
    208     * tmp.y = vtex.z
    209     * fragment = tex(tmp, 0) * quant
    210     */
    211    for (i = 0; i < zscan->num_channels; ++i)
    212       ureg_TEX(shader, ureg_writemask(tmp[i], TGSI_WRITEMASK_X), TGSI_TEXTURE_2D, vtex[i], samp_scan);
    213 
    214    for (i = 0; i < zscan->num_channels; ++i)
    215       ureg_MOV(shader, ureg_writemask(tmp[i], TGSI_WRITEMASK_Y), ureg_scalar(vtex[i], TGSI_SWIZZLE_W));
    216 
    217    for (i = 0; i < zscan->num_channels; ++i) {
    218       ureg_TEX(shader, ureg_writemask(tmp[0], TGSI_WRITEMASK_X << i), TGSI_TEXTURE_2D, ureg_src(tmp[i]), samp_src);
    219       ureg_TEX(shader, ureg_writemask(quant, TGSI_WRITEMASK_X << i), TGSI_TEXTURE_3D, vtex[i], samp_quant);
    220    }
    221 
    222    ureg_MUL(shader, quant, ureg_src(quant), ureg_imm1f(shader, 16.0f));
    223    ureg_MUL(shader, fragment, ureg_src(tmp[0]), ureg_src(quant));
    224 
    225    for (i = 0; i < zscan->num_channels; ++i)
    226       ureg_release_temporary(shader, tmp[i]);
    227    ureg_END(shader);
    228 
    229    FREE(vtex);
    230    FREE(tmp);
    231 
    232    return ureg_create_shader_and_destroy(shader, zscan->pipe);
    233 }
    234 
    235 static bool
    236 init_shaders(struct vl_zscan *zscan)
    237 {
    238    assert(zscan);
    239 
    240    zscan->vs = create_vert_shader(zscan);
    241    if (!zscan->vs)
    242       goto error_vs;
    243 
    244    zscan->fs = create_frag_shader(zscan);
    245    if (!zscan->fs)
    246       goto error_fs;
    247 
    248    return true;
    249 
    250 error_fs:
    251    zscan->pipe->delete_vs_state(zscan->pipe, zscan->vs);
    252 
    253 error_vs:
    254    return false;
    255 }
    256 
    257 static void
    258 cleanup_shaders(struct vl_zscan *zscan)
    259 {
    260    assert(zscan);
    261 
    262    zscan->pipe->delete_vs_state(zscan->pipe, zscan->vs);
    263    zscan->pipe->delete_fs_state(zscan->pipe, zscan->fs);
    264 }
    265 
    266 static bool
    267 init_state(struct vl_zscan *zscan)
    268 {
    269    struct pipe_blend_state blend;
    270    struct pipe_rasterizer_state rs_state;
    271    struct pipe_sampler_state sampler;
    272    unsigned i;
    273 
    274    assert(zscan);
    275 
    276    memset(&rs_state, 0, sizeof(rs_state));
    277    rs_state.half_pixel_center = true;
    278    rs_state.bottom_edge_rule = true;
    279    rs_state.depth_clip = 1;
    280    zscan->rs_state = zscan->pipe->create_rasterizer_state(zscan->pipe, &rs_state);
    281    if (!zscan->rs_state)
    282       goto error_rs_state;
    283 
    284    memset(&blend, 0, sizeof blend);
    285 
    286    blend.independent_blend_enable = 0;
    287    blend.rt[0].blend_enable = 0;
    288    blend.rt[0].rgb_func = PIPE_BLEND_ADD;
    289    blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
    290    blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
    291    blend.rt[0].alpha_func = PIPE_BLEND_ADD;
    292    blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
    293    blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
    294    blend.logicop_enable = 0;
    295    blend.logicop_func = PIPE_LOGICOP_CLEAR;
    296    /* Needed to allow color writes to FB, even if blending disabled */
    297    blend.rt[0].colormask = PIPE_MASK_RGBA;
    298    blend.dither = 0;
    299    zscan->blend = zscan->pipe->create_blend_state(zscan->pipe, &blend);
    300    if (!zscan->blend)
    301       goto error_blend;
    302 
    303    for (i = 0; i < 3; ++i) {
    304       memset(&sampler, 0, sizeof(sampler));
    305       sampler.wrap_s = PIPE_TEX_WRAP_REPEAT;
    306       sampler.wrap_t = PIPE_TEX_WRAP_REPEAT;
    307       sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    308       sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
    309       sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    310       sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
    311       sampler.compare_mode = PIPE_TEX_COMPARE_NONE;
    312       sampler.compare_func = PIPE_FUNC_ALWAYS;
    313       sampler.normalized_coords = 1;
    314       zscan->samplers[i] = zscan->pipe->create_sampler_state(zscan->pipe, &sampler);
    315       if (!zscan->samplers[i])
    316          goto error_samplers;
    317    }
    318 
    319    return true;
    320 
    321 error_samplers:
    322    for (i = 0; i < 2; ++i)
    323       if (zscan->samplers[i])
    324          zscan->pipe->delete_sampler_state(zscan->pipe, zscan->samplers[i]);
    325 
    326    zscan->pipe->delete_rasterizer_state(zscan->pipe, zscan->rs_state);
    327 
    328 error_blend:
    329    zscan->pipe->delete_blend_state(zscan->pipe, zscan->blend);
    330 
    331 error_rs_state:
    332    return false;
    333 }
    334 
    335 static void
    336 cleanup_state(struct vl_zscan *zscan)
    337 {
    338    unsigned i;
    339 
    340    assert(zscan);
    341 
    342    for (i = 0; i < 3; ++i)
    343       zscan->pipe->delete_sampler_state(zscan->pipe, zscan->samplers[i]);
    344 
    345    zscan->pipe->delete_rasterizer_state(zscan->pipe, zscan->rs_state);
    346    zscan->pipe->delete_blend_state(zscan->pipe, zscan->blend);
    347 }
    348 
    349 struct pipe_sampler_view *
    350 vl_zscan_layout(struct pipe_context *pipe, const int layout[64], unsigned blocks_per_line)
    351 {
    352    const unsigned total_size = blocks_per_line * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT;
    353 
    354    int patched_layout[64];
    355 
    356    struct pipe_resource res_tmpl, *res;
    357    struct pipe_sampler_view sv_tmpl, *sv;
    358    struct pipe_transfer *buf_transfer;
    359    unsigned x, y, i, pitch;
    360    float *f;
    361 
    362    struct pipe_box rect =
    363    {
    364       0, 0, 0,
    365       VL_BLOCK_WIDTH * blocks_per_line,
    366       VL_BLOCK_HEIGHT,
    367       1
    368    };
    369 
    370    assert(pipe && layout && blocks_per_line);
    371 
    372    for (i = 0; i < 64; ++i)
    373       patched_layout[layout[i]] = i;
    374 
    375    memset(&res_tmpl, 0, sizeof(res_tmpl));
    376    res_tmpl.target = PIPE_TEXTURE_2D;
    377    res_tmpl.format = PIPE_FORMAT_R32_FLOAT;
    378    res_tmpl.width0 = VL_BLOCK_WIDTH * blocks_per_line;
    379    res_tmpl.height0 = VL_BLOCK_HEIGHT;
    380    res_tmpl.depth0 = 1;
    381    res_tmpl.array_size = 1;
    382    res_tmpl.usage = PIPE_USAGE_IMMUTABLE;
    383    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
    384 
    385    res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    386    if (!res)
    387       goto error_resource;
    388 
    389    f = pipe->transfer_map(pipe, res,
    390                           0, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE,
    391                           &rect, &buf_transfer);
    392    if (!f)
    393       goto error_map;
    394 
    395    pitch = buf_transfer->stride / sizeof(float);
    396 
    397    for (i = 0; i < blocks_per_line; ++i)
    398       for (y = 0; y < VL_BLOCK_HEIGHT; ++y)
    399          for (x = 0; x < VL_BLOCK_WIDTH; ++x) {
    400             float addr = patched_layout[x + y * VL_BLOCK_WIDTH] +
    401                i * VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT;
    402 
    403             addr /= total_size;
    404 
    405             f[i * VL_BLOCK_WIDTH + y * pitch + x] = addr;
    406          }
    407 
    408    pipe->transfer_unmap(pipe, buf_transfer);
    409 
    410    memset(&sv_tmpl, 0, sizeof(sv_tmpl));
    411    u_sampler_view_default_template(&sv_tmpl, res, res->format);
    412    sv = pipe->create_sampler_view(pipe, res, &sv_tmpl);
    413    pipe_resource_reference(&res, NULL);
    414    if (!sv)
    415       goto error_map;
    416 
    417    return sv;
    418 
    419 error_map:
    420    pipe_resource_reference(&res, NULL);
    421 
    422 error_resource:
    423    return NULL;
    424 }
    425 
    426 bool
    427 vl_zscan_init(struct vl_zscan *zscan, struct pipe_context *pipe,
    428               unsigned buffer_width, unsigned buffer_height,
    429               unsigned blocks_per_line, unsigned blocks_total,
    430               unsigned num_channels)
    431 {
    432    assert(zscan && pipe);
    433 
    434    zscan->pipe = pipe;
    435    zscan->buffer_width = buffer_width;
    436    zscan->buffer_height = buffer_height;
    437    zscan->num_channels = num_channels;
    438    zscan->blocks_per_line = blocks_per_line;
    439    zscan->blocks_total = blocks_total;
    440 
    441    if(!init_shaders(zscan))
    442       return false;
    443 
    444    if(!init_state(zscan)) {
    445       cleanup_shaders(zscan);
    446       return false;
    447    }
    448 
    449    return true;
    450 }
    451 
    452 void
    453 vl_zscan_cleanup(struct vl_zscan *zscan)
    454 {
    455    assert(zscan);
    456 
    457    cleanup_shaders(zscan);
    458    cleanup_state(zscan);
    459 }
    460 
    461 bool
    462 vl_zscan_init_buffer(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer,
    463                      struct pipe_sampler_view *src, struct pipe_surface *dst)
    464 {
    465    struct pipe_resource res_tmpl, *res;
    466    struct pipe_sampler_view sv_tmpl;
    467 
    468    assert(zscan && buffer);
    469 
    470    memset(buffer, 0, sizeof(struct vl_zscan_buffer));
    471 
    472    pipe_sampler_view_reference(&buffer->src, src);
    473 
    474    buffer->viewport.scale[0] = dst->width;
    475    buffer->viewport.scale[1] = dst->height;
    476    buffer->viewport.scale[2] = 1;
    477    buffer->viewport.translate[0] = 0;
    478    buffer->viewport.translate[1] = 0;
    479    buffer->viewport.translate[2] = 0;
    480 
    481    buffer->fb_state.width = dst->width;
    482    buffer->fb_state.height = dst->height;
    483    buffer->fb_state.nr_cbufs = 1;
    484    pipe_surface_reference(&buffer->fb_state.cbufs[0], dst);
    485 
    486    memset(&res_tmpl, 0, sizeof(res_tmpl));
    487    res_tmpl.target = PIPE_TEXTURE_3D;
    488    res_tmpl.format = PIPE_FORMAT_R8_UNORM;
    489    res_tmpl.width0 = VL_BLOCK_WIDTH * zscan->blocks_per_line;
    490    res_tmpl.height0 = VL_BLOCK_HEIGHT;
    491    res_tmpl.depth0 = 2;
    492    res_tmpl.array_size = 1;
    493    res_tmpl.usage = PIPE_USAGE_IMMUTABLE;
    494    res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
    495 
    496    res = zscan->pipe->screen->resource_create(zscan->pipe->screen, &res_tmpl);
    497    if (!res)
    498       return false;
    499 
    500    memset(&sv_tmpl, 0, sizeof(sv_tmpl));
    501    u_sampler_view_default_template(&sv_tmpl, res, res->format);
    502    sv_tmpl.swizzle_r = sv_tmpl.swizzle_g = sv_tmpl.swizzle_b = sv_tmpl.swizzle_a = TGSI_SWIZZLE_X;
    503    buffer->quant = zscan->pipe->create_sampler_view(zscan->pipe, res, &sv_tmpl);
    504    pipe_resource_reference(&res, NULL);
    505    if (!buffer->quant)
    506       return false;
    507 
    508    return true;
    509 }
    510 
    511 void
    512 vl_zscan_cleanup_buffer(struct vl_zscan_buffer *buffer)
    513 {
    514    assert(buffer);
    515 
    516    pipe_sampler_view_reference(&buffer->src, NULL);
    517    pipe_sampler_view_reference(&buffer->layout, NULL);
    518    pipe_sampler_view_reference(&buffer->quant, NULL);
    519    pipe_surface_reference(&buffer->fb_state.cbufs[0], NULL);
    520 }
    521 
    522 void
    523 vl_zscan_set_layout(struct vl_zscan_buffer *buffer, struct pipe_sampler_view *layout)
    524 {
    525    assert(buffer);
    526    assert(layout);
    527 
    528    pipe_sampler_view_reference(&buffer->layout, layout);
    529 }
    530 
    531 void
    532 vl_zscan_upload_quant(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer,
    533                       const uint8_t matrix[64], bool intra)
    534 {
    535    struct pipe_context *pipe;
    536    struct pipe_transfer *buf_transfer;
    537    unsigned x, y, i, pitch;
    538    uint8_t *data;
    539 
    540    struct pipe_box rect =
    541    {
    542       0, 0, intra ? 1 : 0,
    543       VL_BLOCK_WIDTH,
    544       VL_BLOCK_HEIGHT,
    545       1
    546    };
    547 
    548    assert(buffer);
    549    assert(matrix);
    550 
    551    pipe = zscan->pipe;
    552 
    553    rect.width *= zscan->blocks_per_line;
    554 
    555    data = pipe->transfer_map(pipe, buffer->quant->texture,
    556                              0, PIPE_TRANSFER_WRITE |
    557                              PIPE_TRANSFER_DISCARD_RANGE,
    558                              &rect, &buf_transfer);
    559    if (!data)
    560       return;
    561 
    562    pitch = buf_transfer->stride;
    563 
    564    for (i = 0; i < zscan->blocks_per_line; ++i)
    565       for (y = 0; y < VL_BLOCK_HEIGHT; ++y)
    566          for (x = 0; x < VL_BLOCK_WIDTH; ++x)
    567             data[i * VL_BLOCK_WIDTH + y * pitch + x] = matrix[x + y * VL_BLOCK_WIDTH];
    568 
    569    pipe->transfer_unmap(pipe, buf_transfer);
    570 }
    571 
    572 void
    573 vl_zscan_render(struct vl_zscan *zscan, struct vl_zscan_buffer *buffer, unsigned num_instances)
    574 {
    575    assert(buffer);
    576 
    577    zscan->pipe->bind_rasterizer_state(zscan->pipe, zscan->rs_state);
    578    zscan->pipe->bind_blend_state(zscan->pipe, zscan->blend);
    579    zscan->pipe->bind_sampler_states(zscan->pipe, PIPE_SHADER_FRAGMENT,
    580                                     0, 3, zscan->samplers);
    581    zscan->pipe->set_framebuffer_state(zscan->pipe, &buffer->fb_state);
    582    zscan->pipe->set_viewport_states(zscan->pipe, 0, 1, &buffer->viewport);
    583    zscan->pipe->set_sampler_views(zscan->pipe, PIPE_SHADER_FRAGMENT,
    584                                   0, 3, &buffer->src);
    585    zscan->pipe->bind_vs_state(zscan->pipe, zscan->vs);
    586    zscan->pipe->bind_fs_state(zscan->pipe, zscan->fs);
    587    util_draw_arrays_instanced(zscan->pipe, PIPE_PRIM_QUADS, 0, 4, 0, num_instances);
    588 }
    589