aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/nv50/nv98_video_vp.c
diff options
context:
space:
mode:
authorIlia Mirkin <[email protected]>2013-08-10 20:19:24 -0400
committerMaarten Lankhorst <[email protected]>2013-08-16 09:48:47 +0200
commita2061eea0f89b44c816e6c7570b983e8cfda41cd (patch)
treedf7ea1084a69bc4c20b8ef2c11df611613756283 /src/gallium/drivers/nv50/nv98_video_vp.c
parentb3f6f127f28737d034dcf1c12a9b66b88750e93b (diff)
nv50: add vp3/vp4 support for mpeg2/vc1
h264/mpeg4 remain disabled for pre-nvc0, there's some minor bug/difference which causes the decoding to hang after some frames. Signed-off-by: Ilia Mirkin <[email protected]>
Diffstat (limited to 'src/gallium/drivers/nv50/nv98_video_vp.c')
-rw-r--r--src/gallium/drivers/nv50/nv98_video_vp.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/gallium/drivers/nv50/nv98_video_vp.c b/src/gallium/drivers/nv50/nv98_video_vp.c
new file mode 100644
index 00000000000..adba58becf3
--- /dev/null
+++ b/src/gallium/drivers/nv50/nv98_video_vp.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2011-2013 Maarten Lankhorst, Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "nv98_video.h"
+#include <sys/mman.h>
+
+#if NOUVEAU_VP3_DEBUG_FENCE
+static void dump_comm_vp(struct nouveau_vp3_decoder *dec, struct comm *comm, u32 comm_seq,
+ struct nouveau_bo *inter_bo, unsigned slice_size)
+{
+ unsigned i, idx = comm->pvp_cur_index & 0xf;
+ debug_printf("Status: %08x, stage: %08x\n", comm->status_vp[idx], comm->pvp_stage);
+#if 0
+ debug_printf("Acked byte ofs: %x, bsp byte ofs: %x\n", comm->acked_byte_ofs, comm->byte_ofs);
+ debug_printf("Irq/parse indexes: %i %i\n", comm->irq_index, comm->parse_endpos_index);
+
+ for (i = 0; i != comm->irq_index; ++i)
+ debug_printf("irq[%i] = { @ %08x -> %04x }\n", i, comm->irq_pos[i], comm->irq_470[i]);
+ for (i = 0; i != comm->parse_endpos_index; ++i)
+ debug_printf("parse_endpos[%i] = { @ %08x}\n", i, comm->parse_endpos[i]);
+#endif
+ debug_printf("mb_y = %u\n", comm->mb_y[idx]);
+ if (comm->status_vp[idx] == 1)
+ return;
+
+ if ((comm->pvp_stage & 0xff) != 0xff) {
+ unsigned *map;
+ assert(nouveau_bo_map(inter_bo, NOUVEAU_BO_RD|NOUVEAU_BO_NOBLOCK, dec->client) >= 0);
+ map = inter_bo->map;
+ for (i = 0; i < comm->byte_ofs + slice_size; i += 0x10) {
+ debug_printf("%05x: %08x %08x %08x %08x\n", i, map[i/4], map[i/4+1], map[i/4+2], map[i/4+3]);
+ }
+ munmap(inter_bo->map, inter_bo->size);
+ inter_bo->map = NULL;
+ }
+ assert((comm->pvp_stage & 0xff) == 0xff);
+}
+#endif
+
+static void
+nv98_decoder_kick_ref(struct nouveau_vp3_decoder *dec, struct nouveau_vp3_video_buffer *target)
+{
+ dec->refs[target->valid_ref].vidbuf = NULL;
+ dec->refs[target->valid_ref].last_used = 0;
+// debug_printf("Unreffed %p\n", target);
+}
+
+void
+nv98_decoder_vp(struct nouveau_vp3_decoder *dec, union pipe_desc desc,
+ struct nouveau_vp3_video_buffer *target, unsigned comm_seq,
+ unsigned caps, unsigned is_ref,
+ struct nouveau_vp3_video_buffer *refs[16])
+{
+ struct nouveau_pushbuf *push = dec->pushbuf[1];
+ uint32_t bsp_addr, comm_addr, inter_addr, ucode_addr, pic_addr[17], last_addr, null_addr;
+ uint32_t slice_size, bucket_size, ring_size, i;
+ enum pipe_video_codec codec = u_reduce_video_profile(dec->base.profile);
+ struct nouveau_bo *bsp_bo = dec->bsp_bo[comm_seq % NOUVEAU_VP3_VIDEO_QDEPTH];
+ struct nouveau_bo *inter_bo = dec->inter_bo[comm_seq & 1];
+ u32 fence_extra = 0, codec_extra = 0;
+ struct nouveau_pushbuf_refn bo_refs[] = {
+ { inter_bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM },
+ { dec->ref_bo, NOUVEAU_BO_WR | NOUVEAU_BO_VRAM },
+ { bsp_bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM },
+#if NOUVEAU_VP3_DEBUG_FENCE
+ { dec->fence_bo, NOUVEAU_BO_WR | NOUVEAU_BO_GART },
+#endif
+ { dec->fw_bo, NOUVEAU_BO_RD | NOUVEAU_BO_VRAM },
+ };
+ int num_refs = sizeof(bo_refs)/sizeof(*bo_refs) - !dec->fw_bo;
+
+#if NOUVEAU_VP3_DEBUG_FENCE
+ fence_extra = 4;
+#endif
+
+ if (codec == PIPE_VIDEO_CODEC_MPEG4_AVC) {
+ nouveau_vp3_inter_sizes(dec, desc.h264->slice_count, &slice_size, &bucket_size, &ring_size);
+ codec_extra += 2;
+ } else
+ nouveau_vp3_inter_sizes(dec, 1, &slice_size, &bucket_size, &ring_size);
+
+ if (dec->base.max_references > 2)
+ codec_extra += 1 + (dec->base.max_references - 2);
+
+ pic_addr[16] = nouveau_vp3_video_addr(dec, target) >> 8;
+ last_addr = null_addr = nouveau_vp3_video_addr(dec, NULL) >> 8;
+
+ for (i = 0; i < dec->base.max_references; ++i) {
+ if (!refs[i])
+ pic_addr[i] = last_addr;
+ else if (dec->refs[refs[i]->valid_ref].vidbuf == refs[i])
+ last_addr = pic_addr[i] = nouveau_vp3_video_addr(dec, refs[i]) >> 8;
+ else
+ pic_addr[i] = null_addr;
+ }
+ if (!is_ref)
+ nv98_decoder_kick_ref(dec, target);
+
+ nouveau_pushbuf_space(push, 8 + 3 * (codec != PIPE_VIDEO_CODEC_MPEG12) +
+ 6 + codec_extra + fence_extra + 2, num_refs, 0);
+
+ nouveau_pushbuf_refn(push, bo_refs, num_refs);
+
+ bsp_addr = bsp_bo->offset >> 8;
+#if NOUVEAU_VP3_DEBUG_FENCE
+ comm_addr = (dec->fence_bo->offset + COMM_OFFSET)>>8;
+#else
+ comm_addr = bsp_addr + (COMM_OFFSET>>8);
+#endif
+ inter_addr = inter_bo->offset >> 8;
+ if (dec->fw_bo)
+ ucode_addr = dec->fw_bo->offset >> 8;
+ else
+ ucode_addr = 0;
+
+ BEGIN_NV04(push, SUBC_VP(0x700), 7);
+ PUSH_DATA (push, caps); // 700
+ PUSH_DATA (push, comm_seq); // 704
+ PUSH_DATA (push, 0); // 708 fuc targets, ignored for nv98
+ PUSH_DATA (push, dec->fw_sizes); // 70c
+ PUSH_DATA (push, bsp_addr+(VP_OFFSET>>8)); // 710 picparm_addr
+ PUSH_DATA (push, inter_addr); // 714 inter_parm
+ PUSH_DATA (push, inter_addr + slice_size + bucket_size); // 718 inter_data_ofs
+
+ if (bucket_size) {
+ uint64_t tmpimg_addr = dec->ref_bo->offset + dec->ref_stride * (dec->base.max_references+2);
+
+ BEGIN_NV04(push, SUBC_VP(0x71c), 2);
+ PUSH_DATA (push, tmpimg_addr >> 8); // 71c
+ PUSH_DATA (push, inter_addr + slice_size); // 720 bucket_ofs
+ }
+
+ BEGIN_NV04(push, SUBC_VP(0x724), 5);
+ PUSH_DATA (push, comm_addr); // 724
+ PUSH_DATA (push, ucode_addr); // 728
+ PUSH_DATA (push, pic_addr[16]); // 734
+ PUSH_DATA (push, pic_addr[0]); // 72c
+ PUSH_DATA (push, pic_addr[1]); // 730
+
+ if (dec->base.max_references > 2) {
+ int i;
+
+ BEGIN_NV04(push, SUBC_VP(0x400), dec->base.max_references - 2);
+ for (i = 2; i < dec->base.max_references; ++i) {
+ assert(0x400 + (i - 2) * 4 < 0x438);
+ PUSH_DATA (push, pic_addr[i]);
+ }
+ }
+
+ if (codec == PIPE_VIDEO_CODEC_MPEG4_AVC) {
+ BEGIN_NV04(push, SUBC_VP(0x438), 1);
+ PUSH_DATA (push, desc.h264->slice_count);
+ }
+
+ //debug_printf("Decoding %08lx with %08lx and %08lx\n", pic_addr[16], pic_addr[0], pic_addr[1]);
+
+#if NOUVEAU_VP3_DEBUG_FENCE
+ BEGIN_NV04(push, SUBC_VP(0x240), 3);
+ PUSH_DATAh(push, (dec->fence_bo->offset + 0x10));
+ PUSH_DATA (push, (dec->fence_bo->offset + 0x10));
+ PUSH_DATA (push, dec->fence_seq);
+
+ BEGIN_NV04(push, SUBC_VP(0x300), 1);
+ PUSH_DATA (push, 1);
+ PUSH_KICK(push);
+
+ {
+ unsigned spin = 0;
+ do {
+ usleep(100);
+ if ((spin++ & 0xff) == 0xff) {
+ debug_printf("v%u: %u\n", dec->fence_seq, dec->fence_map[4]);
+ dump_comm_vp(dec, dec->comm, comm_seq, inter_bo, slice_size << 8);
+ }
+ } while (dec->fence_seq > dec->fence_map[4]);
+ }
+ dump_comm_vp(dec, dec->comm, comm_seq, inter_bo, slice_size << 8);
+#else
+ BEGIN_NV04(push, SUBC_VP(0x300), 1);
+ PUSH_DATA (push, 0);
+ PUSH_KICK (push);
+#endif
+}