Home | History | Annotate | Download | only in nvc0
      1 /*
      2  * Copyright 2011-2013 Maarten Lankhorst
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  */
     22 
     23 #include "nvc0/nvc0_video.h"
     24 #include <sys/mman.h>
     25 
     26 #if NOUVEAU_VP3_DEBUG_FENCE
     27 static void dump_comm_vp(struct nouveau_vp3_decoder *dec, struct comm *comm, u32 comm_seq,
     28                          struct nouveau_bo *inter_bo, unsigned slice_size)
     29 {
     30    unsigned i, idx = comm->pvp_cur_index & 0xf;
     31    debug_printf("Status: %08x, stage: %08x\n", comm->status_vp[idx], comm->pvp_stage);
     32 #if 0
     33    debug_printf("Acked byte ofs: %x, bsp byte ofs: %x\n", comm->acked_byte_ofs, comm->byte_ofs);
     34    debug_printf("Irq/parse indexes: %i %i\n", comm->irq_index, comm->parse_endpos_index);
     35 
     36    for (i = 0; i != comm->irq_index; ++i)
     37       debug_printf("irq[%i] = { @ %08x -> %04x }\n", i, comm->irq_pos[i], comm->irq_470[i]);
     38    for (i = 0; i != comm->parse_endpos_index; ++i)
     39       debug_printf("parse_endpos[%i] = { @ %08x}\n", i, comm->parse_endpos[i]);
     40 #endif
     41    debug_printf("mb_y = %u\n", comm->mb_y[idx]);
     42    if (comm->status_vp[idx] <= 1)
     43       return;
     44 
     45    if ((comm->pvp_stage & 0xff) != 0xff) {
     46       unsigned *map;
     47       int ret = nouveau_bo_map(inter_bo, NOUVEAU_BO_RD|NOUVEAU_BO_NOBLOCK, dec->client);
     48       assert(ret >= 0);
     49       map = inter_bo->map;
     50       for (i = 0; i < comm->byte_ofs + slice_size; i += 0x10) {
     51          debug_printf("%05x: %08x %08x %08x %08x\n", i, map[i/4], map[i/4+1], map[i/4+2], map[i/4+3]);
     52       }
     53       munmap(inter_bo->map, inter_bo->size);
     54       inter_bo->map = NULL;
     55    }
     56    assert((comm->pvp_stage & 0xff) == 0xff);
     57 }
     58 #endif
     59 
     60 static void
     61 nvc0_decoder_kick_ref(struct nouveau_vp3_decoder *dec, struct nouveau_vp3_video_buffer *target)
     62 {
     63    dec->refs[target->valid_ref].last_used = 0;
     64 //   debug_printf("Unreffed %p\n", target);
     65 }
     66 
     67 void
     68 nvc0_decoder_vp(struct nouveau_vp3_decoder *dec, union pipe_desc desc,
     69                 struct nouveau_vp3_video_buffer *target, unsigned comm_seq,
     70                 unsigned caps, unsigned is_ref,
     71                 struct nouveau_vp3_video_buffer *refs[16])
     72 {
     73    struct nouveau_pushbuf *push = dec->pushbuf[1];
     74    uint32_t bsp_addr, comm_addr, inter_addr, ucode_addr, pic_addr[17], last_addr, null_addr;
     75    uint32_t slice_size, bucket_size, ring_size, i;
     76    enum pipe_video_format codec = u_reduce_video_profile(dec->base.profile);
     77    struct nouveau_bo *bsp_bo = dec->bsp_bo[comm_seq % NOUVEAU_VP3_VIDEO_QDEPTH];
     78    struct nouveau_bo *inter_bo = dec->inter_bo[comm_seq & 1];
     79    u32 codec_extra = 0;
     80    struct nouveau_pushbuf_refn bo_refs[] = {
     81       { inter_bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM },
     82       { dec->ref_bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM },
     83       { bsp_bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM },
     84 #if NOUVEAU_VP3_DEBUG_FENCE
     85       { dec->fence_bo, NOUVEAU_BO_WR | NOUVEAU_BO_GART },
     86 #endif
     87       { dec->fw_bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM },
     88    };
     89    int num_refs = ARRAY_SIZE(bo_refs) - !dec->fw_bo;
     90 
     91    if (codec == PIPE_VIDEO_FORMAT_MPEG4_AVC) {
     92       nouveau_vp3_inter_sizes(dec, desc.h264->slice_count, &slice_size, &bucket_size, &ring_size);
     93       codec_extra += 2;
     94    } else
     95       nouveau_vp3_inter_sizes(dec, 1, &slice_size, &bucket_size, &ring_size);
     96 
     97    if (dec->base.max_references > 2)
     98       codec_extra += 1 + (dec->base.max_references - 2);
     99 
    100    pic_addr[16] = nouveau_vp3_video_addr(dec, target) >> 8;
    101    last_addr = null_addr = nouveau_vp3_video_addr(dec, NULL) >> 8;
    102 
    103    for (i = 0; i < dec->base.max_references; ++i) {
    104       if (!refs[i])
    105          pic_addr[i] = last_addr;
    106       else if (dec->refs[refs[i]->valid_ref].vidbuf == refs[i])
    107          last_addr = pic_addr[i] = nouveau_vp3_video_addr(dec, refs[i]) >> 8;
    108       else
    109          pic_addr[i] = null_addr;
    110    }
    111    if (!is_ref && (dec->refs[target->valid_ref].decoded_top && dec->refs[target->valid_ref].decoded_bottom))
    112       nvc0_decoder_kick_ref(dec, target);
    113 
    114    nouveau_pushbuf_space(push, 32 + codec_extra, num_refs, 0);
    115 
    116    nouveau_pushbuf_refn(push, bo_refs, num_refs);
    117 
    118    bsp_addr = bsp_bo->offset >> 8;
    119 #if NOUVEAU_VP3_DEBUG_FENCE
    120    comm_addr = (dec->fence_bo->offset + COMM_OFFSET)>>8;
    121 #else
    122    comm_addr = bsp_addr + (COMM_OFFSET>>8);
    123 #endif
    124    inter_addr = inter_bo->offset >> 8;
    125    if (dec->fw_bo)
    126       ucode_addr = dec->fw_bo->offset >> 8;
    127    else
    128       ucode_addr = 0;
    129 
    130    BEGIN_NVC0(push, SUBC_VP(0x700), 7);
    131    PUSH_DATA (push, caps); // 700
    132    PUSH_DATA (push, comm_seq); // 704
    133    PUSH_DATA (push, 0); // 708 fuc targets, ignored for nvc0
    134    PUSH_DATA (push, dec->fw_sizes); // 70c
    135    PUSH_DATA (push, bsp_addr+(VP_OFFSET>>8)); // 710 picparm_addr
    136    PUSH_DATA (push, inter_addr); // 714 inter_parm
    137    PUSH_DATA (push, inter_addr + slice_size + bucket_size); // 718 inter_data_ofs
    138 
    139    if (bucket_size) {
    140       uint64_t tmpimg_addr = dec->ref_bo->offset + dec->ref_stride * (dec->base.max_references+2);
    141 
    142       BEGIN_NVC0(push, SUBC_VP(0x71c), 2);
    143       PUSH_DATA (push, tmpimg_addr >> 8); // 71c
    144       PUSH_DATA (push, inter_addr + slice_size); // 720 bucket_ofs
    145    }
    146 
    147    BEGIN_NVC0(push, SUBC_VP(0x724), 5);
    148    PUSH_DATA (push, comm_addr); // 724
    149    PUSH_DATA (push, ucode_addr); // 728
    150    PUSH_DATA (push, pic_addr[16]); // 734
    151    PUSH_DATA (push, pic_addr[0]); // 72c
    152    PUSH_DATA (push, pic_addr[1]); // 730
    153 
    154    if (dec->base.max_references > 2) {
    155       int i;
    156 
    157       BEGIN_NVC0(push, SUBC_VP(0x400), dec->base.max_references - 2);
    158       for (i = 2; i < dec->base.max_references; ++i) {
    159          assert(0x400 + (i - 2) * 4 < 0x438);
    160          PUSH_DATA (push, pic_addr[i]);
    161       }
    162    }
    163 
    164    if (codec == PIPE_VIDEO_FORMAT_MPEG4_AVC) {
    165       BEGIN_NVC0(push, SUBC_VP(0x438), 1);
    166       PUSH_DATA (push, desc.h264->slice_count);
    167    }
    168 
    169    //debug_printf("Decoding %08lx with %08lx and %08lx\n", pic_addr[16], pic_addr[0], pic_addr[1]);
    170 
    171 #if NOUVEAU_VP3_DEBUG_FENCE
    172    BEGIN_NVC0(push, SUBC_VP(0x240), 3);
    173    PUSH_DATAh(push, (dec->fence_bo->offset + 0x10));
    174    PUSH_DATA (push, (dec->fence_bo->offset + 0x10));
    175    PUSH_DATA (push, dec->fence_seq);
    176 
    177    BEGIN_NVC0(push, SUBC_VP(0x300), 1);
    178    PUSH_DATA (push, 1);
    179    PUSH_KICK(push);
    180 
    181    {
    182       unsigned spin = 0;
    183       do {
    184          usleep(100);
    185          if ((spin++ & 0xff) == 0xff) {
    186             debug_printf("v%u: %u\n", dec->fence_seq, dec->fence_map[4]);
    187             dump_comm_vp(dec, dec->comm, comm_seq, inter_bo, slice_size << 8);
    188          }
    189       } while (dec->fence_seq > dec->fence_map[4]);
    190    }
    191    dump_comm_vp(dec, dec->comm, comm_seq, inter_bo, slice_size << 8);
    192 #else
    193    BEGIN_NVC0(push, SUBC_VP(0x300), 1);
    194    PUSH_DATA (push, 0);
    195    PUSH_KICK (push);
    196 #endif
    197 }
    198