Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nvc0/nvc0_video.c
4574 views
/*1* Copyright 2011-2013 Maarten Lankhorst2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include "nvc0/nvc0_video.h"2324#include "util/u_sampler.h"25#include "util/format/u_format.h"2627static void28nvc0_decoder_begin_frame(struct pipe_video_codec *decoder,29struct pipe_video_buffer *target,30struct pipe_picture_desc *picture)31{32struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;33uint32_t comm_seq = ++dec->fence_seq;34ASSERTED unsigned ret = 0; /* used in debug checks */3536assert(dec);37assert(target);38assert(target->buffer_format == PIPE_FORMAT_NV12);3940ret = nvc0_decoder_bsp_begin(dec, comm_seq);4142assert(ret == 2);43}4445static void46nvc0_decoder_decode_bitstream(struct pipe_video_codec *decoder,47struct pipe_video_buffer *video_target,48struct pipe_picture_desc *picture,49unsigned num_buffers,50const void *const *data,51const unsigned *num_bytes)52{53struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;54uint32_t comm_seq = dec->fence_seq;55ASSERTED unsigned ret = 0; /* used in debug checks */5657assert(decoder);5859ret = nvc0_decoder_bsp_next(dec, comm_seq, num_buffers, data, num_bytes);6061assert(ret == 2);62}6364static void65nvc0_decoder_end_frame(struct pipe_video_codec *decoder,66struct pipe_video_buffer *video_target,67struct pipe_picture_desc *picture)68{69struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;70struct nouveau_vp3_video_buffer *target = (struct nouveau_vp3_video_buffer *)video_target;71uint32_t comm_seq = dec->fence_seq;72union pipe_desc desc;7374unsigned vp_caps, is_ref;75ASSERTED unsigned ret; /* used in debug checks */76struct nouveau_vp3_video_buffer *refs[16] = {};7778desc.base = picture;7980ret = nvc0_decoder_bsp_end(dec, desc, target, comm_seq, &vp_caps, &is_ref, refs);8182/* did we decode bitstream correctly? */83assert(ret == 2);8485nvc0_decoder_vp(dec, desc, target, comm_seq, vp_caps, is_ref, refs);86nvc0_decoder_ppp(dec, desc, target, comm_seq);87}8889struct pipe_video_codec *90nvc0_create_decoder(struct pipe_context *context,91const struct pipe_video_codec *templ)92{93struct nouveau_screen *screen = &((struct nvc0_context *)context)->screen->base;94struct nouveau_vp3_decoder *dec;95struct nouveau_pushbuf **push;96union nouveau_bo_config cfg;97bool kepler = screen->device->chipset >= 0xe0;9899cfg.nvc0.tile_mode = 0x10;100cfg.nvc0.memtype = 0xfe;101102int ret, i;103uint32_t codec = 1, ppp_codec = 3;104uint32_t timeout;105u32 tmp_size = 0;106107if (getenv("XVMC_VL"))108return vl_create_decoder(context, templ);109110if (templ->entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {111debug_printf("%x\n", templ->entrypoint);112return NULL;113}114115dec = CALLOC_STRUCT(nouveau_vp3_decoder);116if (!dec)117return NULL;118dec->client = screen->client;119dec->base = *templ;120nouveau_vp3_decoder_init_common(&dec->base);121122if (!kepler) {123dec->bsp_idx = 5;124dec->vp_idx = 6;125dec->ppp_idx = 7;126} else {127dec->bsp_idx = 2;128dec->vp_idx = 2;129dec->ppp_idx = 2;130}131132for (i = 0; i < 3; ++i)133if (i && !kepler) {134dec->channel[i] = dec->channel[0];135dec->pushbuf[i] = dec->pushbuf[0];136} else {137void *data;138u32 size;139struct nvc0_fifo nvc0_args = {};140struct nve0_fifo nve0_args = {};141142if (!kepler) {143size = sizeof(nvc0_args);144data = &nvc0_args;145} else {146unsigned engine[] = {147NVE0_FIFO_ENGINE_BSP,148NVE0_FIFO_ENGINE_VP,149NVE0_FIFO_ENGINE_PPP150};151152nve0_args.engine = engine[i];153size = sizeof(nve0_args);154data = &nve0_args;155}156157ret = nouveau_object_new(&screen->device->object, 0,158NOUVEAU_FIFO_CHANNEL_CLASS,159data, size, &dec->channel[i]);160161if (!ret)162ret = nouveau_pushbuf_new(screen->client, dec->channel[i], 4,16332 * 1024, true, &dec->pushbuf[i]);164if (ret)165break;166}167push = dec->pushbuf;168169if (!kepler) {170if (!ret)171ret = nouveau_object_new(dec->channel[0], 0x390b1, 0x90b1, NULL, 0, &dec->bsp);172if (!ret)173ret = nouveau_object_new(dec->channel[1], 0x190b2, 0x90b2, NULL, 0, &dec->vp);174if (!ret)175ret = nouveau_object_new(dec->channel[2], 0x290b3, 0x90b3, NULL, 0, &dec->ppp);176} else {177if (!ret)178ret = nouveau_object_new(dec->channel[0], 0x95b1, 0x95b1, NULL, 0, &dec->bsp);179if (!ret)180ret = nouveau_object_new(dec->channel[1], 0x95b2, 0x95b2, NULL, 0, &dec->vp);181if (!ret)182ret = nouveau_object_new(dec->channel[2], 0x90b3, 0x90b3, NULL, 0, &dec->ppp);183}184if (ret)185goto fail;186187BEGIN_NVC0(push[0], SUBC_BSP(NV01_SUBCHAN_OBJECT), 1);188PUSH_DATA (push[0], dec->bsp->handle);189190BEGIN_NVC0(push[1], SUBC_VP(NV01_SUBCHAN_OBJECT), 1);191PUSH_DATA (push[1], dec->vp->handle);192193BEGIN_NVC0(push[2], SUBC_PPP(NV01_SUBCHAN_OBJECT), 1);194PUSH_DATA (push[2], dec->ppp->handle);195196dec->base.context = context;197dec->base.begin_frame = nvc0_decoder_begin_frame;198dec->base.decode_bitstream = nvc0_decoder_decode_bitstream;199dec->base.end_frame = nvc0_decoder_end_frame;200201for (i = 0; i < NOUVEAU_VP3_VIDEO_QDEPTH && !ret; ++i)202ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,2030, 1 << 20, &cfg, &dec->bsp_bo[i]);204if (!ret) {205/* total fudge factor... just has to be bigger for higher bitrates? */206unsigned inter_size = align(templ->width * templ->height * 2, 4 << 20);207ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,2080x100, inter_size, &cfg, &dec->inter_bo[0]);209}210if (!ret) {211ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,2120x100, dec->inter_bo[0]->size, &cfg,213&dec->inter_bo[1]);214}215if (ret)216goto fail;217switch (u_reduce_video_profile(templ->profile)) {218case PIPE_VIDEO_FORMAT_MPEG12: {219codec = 1;220assert(templ->max_references <= 2);221break;222}223case PIPE_VIDEO_FORMAT_MPEG4: {224codec = 4;225tmp_size = mb(templ->height)*16 * mb(templ->width)*16;226assert(templ->max_references <= 2);227break;228}229case PIPE_VIDEO_FORMAT_VC1: {230ppp_codec = codec = 2;231tmp_size = mb(templ->height)*16 * mb(templ->width)*16;232assert(templ->max_references <= 2);233break;234}235case PIPE_VIDEO_FORMAT_MPEG4_AVC: {236codec = 3;237dec->tmp_stride = 16 * mb_half(templ->width) * nouveau_vp3_video_align(templ->height) * 3 / 2;238tmp_size = dec->tmp_stride * (templ->max_references + 1);239assert(templ->max_references <= 16);240break;241}242default:243fprintf(stderr, "invalid codec\n");244goto fail;245}246247if (screen->device->chipset < 0xd0) {248ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,2490x4000, &cfg, &dec->fw_bo);250if (ret)251goto fail;252253ret = nouveau_vp3_load_firmware(dec, templ->profile, screen->device->chipset);254if (ret)255goto fw_fail;256}257258if (codec != 3) {259ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,2600x400, &cfg, &dec->bitplane_bo);261if (ret)262goto fail;263}264265dec->ref_stride = mb(templ->width)*16 * (mb_half(templ->height)*32 + nouveau_vp3_video_align(templ->height)/2);266ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,267dec->ref_stride * (templ->max_references+2) + tmp_size,268&cfg, &dec->ref_bo);269if (ret)270goto fail;271272timeout = 0;273274BEGIN_NVC0(push[0], SUBC_BSP(0x200), 2);275PUSH_DATA (push[0], codec);276PUSH_DATA (push[0], timeout);277278BEGIN_NVC0(push[1], SUBC_VP(0x200), 2);279PUSH_DATA (push[1], codec);280PUSH_DATA (push[1], timeout);281282BEGIN_NVC0(push[2], SUBC_PPP(0x200), 2);283PUSH_DATA (push[2], ppp_codec);284PUSH_DATA (push[2], timeout);285286++dec->fence_seq;287288#if NOUVEAU_VP3_DEBUG_FENCE289ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART|NOUVEAU_BO_MAP,2900, 0x1000, NULL, &dec->fence_bo);291if (ret)292goto fail;293294nouveau_bo_map(dec->fence_bo, NOUVEAU_BO_RDWR, screen->client);295dec->fence_map = dec->fence_bo->map;296dec->fence_map[0] = dec->fence_map[4] = dec->fence_map[8] = 0;297dec->comm = (struct comm *)(dec->fence_map + (COMM_OFFSET/sizeof(*dec->fence_map)));298299/* So lets test if the fence is working? */300nouveau_pushbuf_space(push[0], 16, 1, 0);301PUSH_REFN (push[0], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);302BEGIN_NVC0(push[0], SUBC_BSP(0x240), 3);303PUSH_DATAh(push[0], dec->fence_bo->offset);304PUSH_DATA (push[0], dec->fence_bo->offset);305PUSH_DATA (push[0], dec->fence_seq);306307BEGIN_NVC0(push[0], SUBC_BSP(0x304), 1);308PUSH_DATA (push[0], 0);309PUSH_KICK (push[0]);310311nouveau_pushbuf_space(push[1], 16, 1, 0);312PUSH_REFN (push[1], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);313BEGIN_NVC0(push[1], SUBC_VP(0x240), 3);314PUSH_DATAh(push[1], (dec->fence_bo->offset + 0x10));315PUSH_DATA (push[1], (dec->fence_bo->offset + 0x10));316PUSH_DATA (push[1], dec->fence_seq);317318BEGIN_NVC0(push[1], SUBC_VP(0x304), 1);319PUSH_DATA (push[1], 0);320PUSH_KICK (push[1]);321322nouveau_pushbuf_space(push[2], 16, 1, 0);323PUSH_REFN (push[2], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);324BEGIN_NVC0(push[2], SUBC_PPP(0x240), 3);325PUSH_DATAh(push[2], (dec->fence_bo->offset + 0x20));326PUSH_DATA (push[2], (dec->fence_bo->offset + 0x20));327PUSH_DATA (push[2], dec->fence_seq);328329BEGIN_NVC0(push[2], SUBC_PPP(0x304), 1);330PUSH_DATA (push[2], 0);331PUSH_KICK (push[2]);332333usleep(100);334while (dec->fence_seq > dec->fence_map[0] ||335dec->fence_seq > dec->fence_map[4] ||336dec->fence_seq > dec->fence_map[8]) {337debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]);338usleep(100);339}340debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]);341#endif342343return &dec->base;344345fw_fail:346debug_printf("Cannot create decoder without firmware..\n");347dec->base.destroy(&dec->base);348return NULL;349350fail:351debug_printf("Creation failed: %s (%i)\n", strerror(-ret), ret);352dec->base.destroy(&dec->base);353return NULL;354}355356struct pipe_video_buffer *357nvc0_video_buffer_create(struct pipe_context *pipe,358const struct pipe_video_buffer *templat)359{360return nouveau_vp3_video_buffer_create(361pipe, templat, NVC0_RESOURCE_FLAG_VIDEO);362}363364365