/* * Copyright 2011-2013 Maarten Lankhorst * * 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 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 "nvc0_context.h" #include "nvc0_screen.h" #include "vl/vl_decoder.h" #include "vl/vl_video_buffer.h" #include "vl/vl_types.h" #include "util/u_video.h" #define SLICE_SIZE 0x200 #define VP_OFFSET 0x200 #define COMM_OFFSET 0x500 //#define NVC0_DEBUG_FENCE 1 #ifdef NVC0_DEBUG_FENCE # define NVC0_VIDEO_QDEPTH 1 #else # define NVC0_VIDEO_QDEPTH 2 #endif #define SUBC_BSP(m) dec->bsp_idx, (m) #define SUBC_VP(m) dec->vp_idx, (m) #define SUBC_PPP(m) dec->ppp_idx, (m) union pipe_desc { struct pipe_picture_desc *base; struct pipe_mpeg12_picture_desc *mpeg12; struct pipe_mpeg4_picture_desc *mpeg4; struct pipe_vc1_picture_desc *vc1; struct pipe_h264_picture_desc *h264; }; struct nvc0_video_buffer { struct pipe_video_buffer base; unsigned num_planes, valid_ref; struct pipe_resource *resources[VL_NUM_COMPONENTS]; struct pipe_sampler_view *sampler_view_planes[VL_NUM_COMPONENTS]; struct pipe_sampler_view *sampler_view_components[VL_NUM_COMPONENTS]; struct pipe_surface *surfaces[VL_NUM_COMPONENTS * 2]; }; struct nvc0_decoder { struct pipe_video_decoder base; struct nouveau_client *client; struct nouveau_object *channel[3], *bsp, *vp, *ppp; struct nouveau_pushbuf *pushbuf[3]; #ifdef NVC0_DEBUG_FENCE /* dump fence and comm, as needed.. */ unsigned *fence_map; struct comm *comm; struct nouveau_bo *fence_bo; #endif struct nouveau_bo *fw_bo, *bitplane_bo; // array size max_references + 2, contains unpostprocessed images // added at the end of ref_bo is a tmp array // tmp is an array for h264, with each member being used for a ref frame or current // target.. size = (((mb(w)*((mb(h)+1)&~1))+3)>>2)<<8 * (max_references+1) // for other codecs, it simply seems that size = w*h is enough // unsure what it's supposed to contain.. struct nouveau_bo *ref_bo; struct nouveau_bo *inter_bo[2]; struct nouveau_bo *bsp_bo[NVC0_VIDEO_QDEPTH]; // bo's used by each cycle: // bsp_bo: contains raw bitstream data and parameters for BSP and VP. // inter_bo: contains data shared between BSP and VP // ref_bo: reference image data, used by PPP and VP // bitplane_bo: contain bitplane data (similar to ref_bo), used by BSP only // fw_bo: used by VP only. // Needed amount of copies in optimal case: // 2 copies of inter_bo, VP would process the last inter_bo, while BSP is // writing out a new set. // NVC0_VIDEO_QDEPTH copies of bsp_bo. We don't want to block the pipeline ever, // and give shaders a chance to run as well. struct { struct nvc0_video_buffer *vidbuf; unsigned last_used; unsigned field_pic_flag : 1; unsigned decoded_top : 1; unsigned decoded_bottom : 1; } refs[17]; unsigned fence_seq, fw_sizes, last_frame_num, tmp_stride, ref_stride; unsigned bsp_idx, vp_idx, ppp_idx; }; struct comm { uint32_t bsp_cur_index; // 000 uint32_t byte_ofs; // 004 uint32_t status[0x10]; // 008 uint32_t pos[0x10]; // 048 uint8_t pad[0x100 - 0x88]; // 0a0 bool comm_encrypted uint32_t pvp_cur_index; // 100 uint32_t acked_byte_ofs; // 104 uint32_t status_vp[0x10]; // 108 uint16_t mb_y[0x10]; //148 uint32_t pvp_stage; // 168 0xeeXX uint16_t parse_endpos_index; // 16c uint16_t irq_index; // 16e uint8_t irq_470[0x10]; // 170 uint32_t irq_pos[0x10]; // 180 uint32_t parse_endpos[0x10]; // 1c0 }; static INLINE uint32_t nvc0_video_align(uint32_t h) { return ((h+0x3f)&~0x3f); }; static INLINE uint32_t mb(uint32_t coord) { return (coord + 0xf)>>4; } static INLINE uint32_t mb_half(uint32_t coord) { return (coord + 0x1f)>>5; } static INLINE uint64_t nvc0_video_addr(struct nvc0_decoder *dec, struct nvc0_video_buffer *target) { uint64_t ret; if (target) ret = dec->ref_stride * target->valid_ref; else ret = dec->ref_stride * (dec->base.max_references+1); return dec->ref_bo->offset + ret; } static INLINE void nvc0_decoder_ycbcr_offsets(struct nvc0_decoder *dec, uint32_t *y2, uint32_t *cbcr, uint32_t *cbcr2) { uint32_t w = mb(dec->base.width), size; *y2 = mb_half(dec->base.height)*w; *cbcr = *y2 * 2; *cbcr2 = *cbcr + w * (nvc0_video_align(dec->base.height)>>6); /* The check here should never fail because it means a bug * in the code rather than a bug in hardware.. */ size = (2 * (*cbcr2 - *cbcr) + *cbcr) << 8; if (size > dec->ref_stride) { debug_printf("Overshot ref_stride (%u) with size %u and ofs (%u,%u,%u)\n", dec->ref_stride, size, *y2<<8, *cbcr<<8, *cbcr2<<8); *y2 = *cbcr = *cbcr2 = 0; assert(size <= dec->ref_stride); } } static INLINE void nvc0_decoder_inter_sizes(struct nvc0_decoder *dec, uint32_t slice_count, uint32_t *slice_size, uint32_t *bucket_size, uint32_t *ring_size) { *slice_size = (SLICE_SIZE * slice_count)>>8; if (u_reduce_video_profile(dec->base.profile) == PIPE_VIDEO_CODEC_MPEG12) *bucket_size = 0; else *bucket_size = mb(dec->base.width) * 3; *ring_size = (dec->inter_bo[0]->size >> 8) - *bucket_size - *slice_size; } extern unsigned nvc0_decoder_bsp(struct nvc0_decoder *dec, union pipe_desc desc, struct nvc0_video_buffer *target, unsigned comm_seq, unsigned num_buffers, const void *const *data, const unsigned *num_bytes, unsigned *vp_caps, unsigned *is_ref, struct nvc0_video_buffer *refs[16]); extern void nvc0_decoder_vp_caps(struct nvc0_decoder *dec, union pipe_desc desc, struct nvc0_video_buffer *target, unsigned comm_seq, unsigned *caps, unsigned *is_ref, struct nvc0_video_buffer *refs[16]); extern void nvc0_decoder_vp(struct nvc0_decoder *dec, union pipe_desc desc, struct nvc0_video_buffer *target, unsigned comm_seq, unsigned caps, unsigned is_ref, struct nvc0_video_buffer *refs[16]); extern void nvc0_decoder_ppp(struct nvc0_decoder *dec, union pipe_desc desc, struct nvc0_video_buffer *target, unsigned comm_seq);