Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv50/nv84_video.c
4574 views
/*1* Copyright 2013 Ilia Mirkin2*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 <sys/mman.h>23#include <sys/stat.h>24#include <sys/types.h>25#include <fcntl.h>2627#include "util/format/u_format.h"28#include "util/u_sampler.h"29#include "vl/vl_zscan.h"3031#include "nv50/nv84_video.h"3233static int34nv84_copy_firmware(const char *path, void *dest, ssize_t len)35{36int fd = open(path, O_RDONLY | O_CLOEXEC);37ssize_t r;38if (fd < 0) {39fprintf(stderr, "opening firmware file %s failed: %m\n", path);40return 1;41}42r = read(fd, dest, len);43close(fd);4445if (r != len) {46fprintf(stderr, "reading firmware file %s failed: %m\n", path);47return 1;48}4950return 0;51}5253static int54filesize(const char *path)55{56int ret;57struct stat statbuf;5859ret = stat(path, &statbuf);60if (ret)61return ret;62return statbuf.st_size;63}6465static struct nouveau_bo *66nv84_load_firmwares(struct nouveau_device *dev, struct nv84_decoder *dec,67const char *fw1, const char *fw2)68{69int ret, size1, size2 = 0;70struct nouveau_bo *fw;7172size1 = filesize(fw1);73if (fw2)74size2 = filesize(fw2);75if (size1 < 0 || size2 < 0)76return NULL;7778dec->vp_fw2_offset = align(size1, 0x100);7980ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, dec->vp_fw2_offset + size2, NULL, &fw);81if (ret)82return NULL;83ret = nouveau_bo_map(fw, NOUVEAU_BO_WR, dec->client);84if (ret)85goto error;8687ret = nv84_copy_firmware(fw1, fw->map, size1);88if (fw2 && !ret)89ret = nv84_copy_firmware(fw2, fw->map + dec->vp_fw2_offset, size2);90munmap(fw->map, fw->size);91fw->map = NULL;92if (!ret)93return fw;94error:95nouveau_bo_ref(NULL, &fw);96return NULL;97}9899static struct nouveau_bo *100nv84_load_bsp_firmware(struct nouveau_device *dev, struct nv84_decoder *dec)101{102return nv84_load_firmwares(103dev, dec, "/lib/firmware/nouveau/nv84_bsp-h264", NULL);104}105106static struct nouveau_bo *107nv84_load_vp_firmware(struct nouveau_device *dev, struct nv84_decoder *dec)108{109return nv84_load_firmwares(110dev, dec,111"/lib/firmware/nouveau/nv84_vp-h264-1",112"/lib/firmware/nouveau/nv84_vp-h264-2");113}114115static struct nouveau_bo *116nv84_load_vp_firmware_mpeg(struct nouveau_device *dev, struct nv84_decoder *dec)117{118return nv84_load_firmwares(119dev, dec, "/lib/firmware/nouveau/nv84_vp-mpeg12", NULL);120}121122static void123nv84_decoder_decode_bitstream_h264(struct pipe_video_codec *decoder,124struct pipe_video_buffer *video_target,125struct pipe_picture_desc *picture,126unsigned num_buffers,127const void *const *data,128const unsigned *num_bytes)129{130struct nv84_decoder *dec = (struct nv84_decoder *)decoder;131struct nv84_video_buffer *target = (struct nv84_video_buffer *)video_target;132133struct pipe_h264_picture_desc *desc = (struct pipe_h264_picture_desc *)picture;134135assert(target->base.buffer_format == PIPE_FORMAT_NV12);136137nv84_decoder_bsp(dec, desc, num_buffers, data, num_bytes, target);138nv84_decoder_vp_h264(dec, desc, target);139}140141static void142nv84_decoder_flush(struct pipe_video_codec *decoder)143{144}145146static void147nv84_decoder_begin_frame_h264(struct pipe_video_codec *decoder,148struct pipe_video_buffer *target,149struct pipe_picture_desc *picture)150{151}152153static void154nv84_decoder_end_frame_h264(struct pipe_video_codec *decoder,155struct pipe_video_buffer *target,156struct pipe_picture_desc *picture)157{158}159160static void161nv84_decoder_decode_bitstream_mpeg12(struct pipe_video_codec *decoder,162struct pipe_video_buffer *video_target,163struct pipe_picture_desc *picture,164unsigned num_buffers,165const void *const *data,166const unsigned *num_bytes)167{168struct nv84_decoder *dec = (struct nv84_decoder *)decoder;169170assert(video_target->buffer_format == PIPE_FORMAT_NV12);171172vl_mpg12_bs_decode(dec->mpeg12_bs,173video_target,174(struct pipe_mpeg12_picture_desc *)picture,175num_buffers,176data,177num_bytes);178}179180static void181nv84_decoder_begin_frame_mpeg12(struct pipe_video_codec *decoder,182struct pipe_video_buffer *target,183struct pipe_picture_desc *picture)184{185struct nv84_decoder *dec = (struct nv84_decoder *)decoder;186struct pipe_mpeg12_picture_desc *desc = (struct pipe_mpeg12_picture_desc *)picture;187int i;188189nouveau_bo_wait(dec->mpeg12_bo, NOUVEAU_BO_RDWR, dec->client);190dec->mpeg12_mb_info = dec->mpeg12_bo->map + 0x100;191dec->mpeg12_data = dec->mpeg12_bo->map + 0x100 +192align(0x20 * mb(dec->base.width) * mb(dec->base.height), 0x100);193if (desc->intra_matrix) {194dec->zscan = desc->alternate_scan ? vl_zscan_alternate : vl_zscan_normal;195for (i = 0; i < 64; i++) {196dec->mpeg12_intra_matrix[i] = desc->intra_matrix[dec->zscan[i]];197dec->mpeg12_non_intra_matrix[i] = desc->non_intra_matrix[dec->zscan[i]];198}199dec->mpeg12_intra_matrix[0] = 1 << (7 - desc->intra_dc_precision);200}201}202203static void204nv84_decoder_end_frame_mpeg12(struct pipe_video_codec *decoder,205struct pipe_video_buffer *target,206struct pipe_picture_desc *picture)207{208nv84_decoder_vp_mpeg12(209(struct nv84_decoder *)decoder,210(struct pipe_mpeg12_picture_desc *)picture,211(struct nv84_video_buffer *)target);212}213214static void215nv84_decoder_decode_macroblock(struct pipe_video_codec *decoder,216struct pipe_video_buffer *target,217struct pipe_picture_desc *picture,218const struct pipe_macroblock *macroblocks,219unsigned num_macroblocks)220{221const struct pipe_mpeg12_macroblock *mb = (const struct pipe_mpeg12_macroblock *)macroblocks;222for (int i = 0; i < num_macroblocks; i++, mb++) {223nv84_decoder_vp_mpeg12_mb(224(struct nv84_decoder *)decoder,225(struct pipe_mpeg12_picture_desc *)picture,226mb);227}228}229230static void231nv84_decoder_destroy(struct pipe_video_codec *decoder)232{233struct nv84_decoder *dec = (struct nv84_decoder *)decoder;234235nouveau_bo_ref(NULL, &dec->bsp_fw);236nouveau_bo_ref(NULL, &dec->bsp_data);237nouveau_bo_ref(NULL, &dec->vp_fw);238nouveau_bo_ref(NULL, &dec->vp_data);239nouveau_bo_ref(NULL, &dec->mbring);240nouveau_bo_ref(NULL, &dec->vpring);241nouveau_bo_ref(NULL, &dec->bitstream);242nouveau_bo_ref(NULL, &dec->vp_params);243nouveau_bo_ref(NULL, &dec->fence);244245nouveau_object_del(&dec->bsp);246nouveau_object_del(&dec->vp);247248nouveau_bufctx_del(&dec->bsp_bufctx);249nouveau_pushbuf_del(&dec->bsp_pushbuf);250nouveau_object_del(&dec->bsp_channel);251252nouveau_bufctx_del(&dec->vp_bufctx);253nouveau_pushbuf_del(&dec->vp_pushbuf);254nouveau_object_del(&dec->vp_channel);255256nouveau_client_del(&dec->client);257258FREE(dec->mpeg12_bs);259FREE(dec);260}261262struct pipe_video_codec *263nv84_create_decoder(struct pipe_context *context,264const struct pipe_video_codec *templ)265{266struct nv50_context *nv50 = (struct nv50_context *)context;267struct nouveau_screen *screen = &nv50->screen->base;268struct nv84_decoder *dec;269struct nouveau_pushbuf *bsp_push, *vp_push;270struct nv50_surface surf;271struct nv50_miptree mip;272union pipe_color_union color;273struct nv04_fifo nv04_data = { .vram = 0xbeef0201, .gart = 0xbeef0202 };274int ret, i;275int is_h264 = u_reduce_video_profile(templ->profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC;276int is_mpeg12 = u_reduce_video_profile(templ->profile) == PIPE_VIDEO_FORMAT_MPEG12;277278if (getenv("XVMC_VL"))279return vl_create_decoder(context, templ);280281if ((is_h264 && templ->entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) ||282(is_mpeg12 && templ->entrypoint > PIPE_VIDEO_ENTRYPOINT_IDCT)) {283debug_printf("%x\n", templ->entrypoint);284return NULL;285}286287if (!is_h264 && !is_mpeg12) {288debug_printf("invalid profile: %x\n", templ->profile);289return NULL;290}291292dec = CALLOC_STRUCT(nv84_decoder);293if (!dec)294return NULL;295296dec->base = *templ;297dec->base.context = context;298dec->base.destroy = nv84_decoder_destroy;299dec->base.flush = nv84_decoder_flush;300if (is_h264) {301dec->base.decode_bitstream = nv84_decoder_decode_bitstream_h264;302dec->base.begin_frame = nv84_decoder_begin_frame_h264;303dec->base.end_frame = nv84_decoder_end_frame_h264;304305dec->frame_mbs = mb(dec->base.width) * mb_half(dec->base.height) * 2;306dec->frame_size = dec->frame_mbs << 8;307dec->vpring_deblock = align(0x30 * dec->frame_mbs, 0x100);308dec->vpring_residual = 0x2000 + MAX2(0x32000, 0x600 * dec->frame_mbs);309dec->vpring_ctrl = MAX2(0x10000, align(0x1080 + 0x144 * dec->frame_mbs, 0x100));310} else if (is_mpeg12) {311dec->base.decode_macroblock = nv84_decoder_decode_macroblock;312dec->base.begin_frame = nv84_decoder_begin_frame_mpeg12;313dec->base.end_frame = nv84_decoder_end_frame_mpeg12;314315if (templ->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {316dec->mpeg12_bs = CALLOC_STRUCT(vl_mpg12_bs);317if (!dec->mpeg12_bs)318goto fail;319vl_mpg12_bs_init(dec->mpeg12_bs, &dec->base);320dec->base.decode_bitstream = nv84_decoder_decode_bitstream_mpeg12;321}322} else {323goto fail;324}325326ret = nouveau_client_new(screen->device, &dec->client);327if (ret)328goto fail;329330if (is_h264) {331ret = nouveau_object_new(&screen->device->object, 0,332NOUVEAU_FIFO_CHANNEL_CLASS,333&nv04_data, sizeof(nv04_data), &dec->bsp_channel);334if (ret)335goto fail;336337ret = nouveau_pushbuf_new(dec->client, dec->bsp_channel, 4,33832 * 1024, true, &dec->bsp_pushbuf);339if (ret)340goto fail;341342ret = nouveau_bufctx_new(dec->client, 1, &dec->bsp_bufctx);343if (ret)344goto fail;345}346347ret = nouveau_object_new(&screen->device->object, 0,348NOUVEAU_FIFO_CHANNEL_CLASS,349&nv04_data, sizeof(nv04_data), &dec->vp_channel);350if (ret)351goto fail;352ret = nouveau_pushbuf_new(dec->client, dec->vp_channel, 4,35332 * 1024, true, &dec->vp_pushbuf);354if (ret)355goto fail;356357ret = nouveau_bufctx_new(dec->client, 1, &dec->vp_bufctx);358if (ret)359goto fail;360361bsp_push = dec->bsp_pushbuf;362vp_push = dec->vp_pushbuf;363364if (is_h264) {365dec->bsp_fw = nv84_load_bsp_firmware(screen->device, dec);366dec->vp_fw = nv84_load_vp_firmware(screen->device, dec);367if (!dec->bsp_fw || !dec->vp_fw)368goto fail;369}370if (is_mpeg12) {371dec->vp_fw = nv84_load_vp_firmware_mpeg(screen->device, dec);372if (!dec->vp_fw)373goto fail;374}375376if (is_h264) {377ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,3780, 0x40000, NULL, &dec->bsp_data);379if (ret)380goto fail;381}382ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,3830, 0x40000, NULL, &dec->vp_data);384if (ret)385goto fail;386if (is_h264) {387ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,3880,3892 * (dec->vpring_deblock +390dec->vpring_residual +391dec->vpring_ctrl +3920x1000),393NULL, &dec->vpring);394if (ret)395goto fail;396ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,3970,398(templ->max_references + 1) * dec->frame_mbs * 0x40 +399dec->frame_size + 0x2000,400NULL, &dec->mbring);401if (ret)402goto fail;403ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART,4040, 2 * (0x700 + MAX2(0x40000, 0x800 + 0x180 * dec->frame_mbs)),405NULL, &dec->bitstream);406if (ret)407goto fail;408ret = nouveau_bo_map(dec->bitstream, NOUVEAU_BO_WR, dec->client);409if (ret)410goto fail;411ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART,4120, 0x2000, NULL, &dec->vp_params);413if (ret)414goto fail;415ret = nouveau_bo_map(dec->vp_params, NOUVEAU_BO_WR, dec->client);416if (ret)417goto fail;418}419if (is_mpeg12) {420ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART,4210,422align(0x20 * mb(templ->width) * mb(templ->height), 0x100) +423(6 * 64 * 8) * mb(templ->width) * mb(templ->height) + 0x100,424NULL, &dec->mpeg12_bo);425if (ret)426goto fail;427ret = nouveau_bo_map(dec->mpeg12_bo, NOUVEAU_BO_WR, dec->client);428if (ret)429goto fail;430}431432ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,4330, 0x1000, NULL, &dec->fence);434if (ret)435goto fail;436ret = nouveau_bo_map(dec->fence, NOUVEAU_BO_WR, dec->client);437if (ret)438goto fail;439*(uint32_t *)dec->fence->map = 0;440441if (is_h264) {442nouveau_pushbuf_bufctx(bsp_push, dec->bsp_bufctx);443nouveau_bufctx_refn(dec->bsp_bufctx, 0,444dec->bsp_fw, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);445nouveau_bufctx_refn(dec->bsp_bufctx, 0,446dec->bsp_data, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);447}448449nouveau_pushbuf_bufctx(vp_push, dec->vp_bufctx);450nouveau_bufctx_refn(dec->vp_bufctx, 0, dec->vp_fw,451NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);452nouveau_bufctx_refn(dec->vp_bufctx, 0, dec->vp_data,453NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);454455if (is_h264 && !ret)456ret = nouveau_object_new(dec->bsp_channel, 0xbeef74b0, 0x74b0,457NULL, 0, &dec->bsp);458459if (!ret)460ret = nouveau_object_new(dec->vp_channel, 0xbeef7476, 0x7476,461NULL, 0, &dec->vp);462463if (ret)464goto fail;465466467if (is_h264) {468/* Zero out some parts of mbring/vpring. there's gotta be some cleaner way469* of doing this... perhaps makes sense to just copy the relevant logic470* here. */471color.f[0] = color.f[1] = color.f[2] = color.f[3] = 0;472surf.offset = dec->frame_size;473surf.width = 64;474surf.height = (templ->max_references + 1) * dec->frame_mbs / 4;475surf.depth = 1;476surf.base.format = PIPE_FORMAT_B8G8R8A8_UNORM;477surf.base.u.tex.level = 0;478surf.base.texture = &mip.base.base;479mip.level[0].tile_mode = 0;480mip.level[0].pitch = surf.width * 4;481mip.base.domain = NOUVEAU_BO_VRAM;482mip.base.bo = dec->mbring;483mip.base.address = dec->mbring->offset;484context->clear_render_target(context, &surf.base, &color, 0, 0, 64, 4760, false);485surf.offset = dec->vpring->size / 2 - 0x1000;486surf.width = 1024;487surf.height = 1;488mip.level[0].pitch = surf.width * 4;489mip.base.bo = dec->vpring;490mip.base.address = dec->vpring->offset;491context->clear_render_target(context, &surf.base, &color, 0, 0, 1024, 1, false);492surf.offset = dec->vpring->size - 0x1000;493context->clear_render_target(context, &surf.base, &color, 0, 0, 1024, 1, false);494495PUSH_SPACE(screen->pushbuf, 5);496PUSH_REFN(screen->pushbuf, dec->fence, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);497/* The clear_render_target is done via 3D engine, so use it to write to a498* sempahore to indicate that it's done.499*/500BEGIN_NV04(screen->pushbuf, NV50_3D(QUERY_ADDRESS_HIGH), 4);501PUSH_DATAh(screen->pushbuf, dec->fence->offset);502PUSH_DATA (screen->pushbuf, dec->fence->offset);503PUSH_DATA (screen->pushbuf, 1);504PUSH_DATA (screen->pushbuf, 0xf010);505PUSH_KICK (screen->pushbuf);506507PUSH_SPACE(bsp_push, 2 + 12 + 2 + 4 + 3);508509BEGIN_NV04(bsp_push, SUBC_BSP(NV01_SUBCHAN_OBJECT), 1);510PUSH_DATA (bsp_push, dec->bsp->handle);511512BEGIN_NV04(bsp_push, SUBC_BSP(0x180), 11);513for (i = 0; i < 11; i++)514PUSH_DATA(bsp_push, nv04_data.vram);515BEGIN_NV04(bsp_push, SUBC_BSP(0x1b8), 1);516PUSH_DATA (bsp_push, nv04_data.vram);517518BEGIN_NV04(bsp_push, SUBC_BSP(0x600), 3);519PUSH_DATAh(bsp_push, dec->bsp_fw->offset);520PUSH_DATA (bsp_push, dec->bsp_fw->offset);521PUSH_DATA (bsp_push, dec->bsp_fw->size);522523BEGIN_NV04(bsp_push, SUBC_BSP(0x628), 2);524PUSH_DATA (bsp_push, dec->bsp_data->offset >> 8);525PUSH_DATA (bsp_push, dec->bsp_data->size);526PUSH_KICK (bsp_push);527}528529PUSH_SPACE(vp_push, 2 + 12 + 2 + 4 + 3);530531BEGIN_NV04(vp_push, SUBC_VP(NV01_SUBCHAN_OBJECT), 1);532PUSH_DATA (vp_push, dec->vp->handle);533534BEGIN_NV04(vp_push, SUBC_VP(0x180), 11);535for (i = 0; i < 11; i++)536PUSH_DATA(vp_push, nv04_data.vram);537538BEGIN_NV04(vp_push, SUBC_VP(0x1b8), 1);539PUSH_DATA (vp_push, nv04_data.vram);540541BEGIN_NV04(vp_push, SUBC_VP(0x600), 3);542PUSH_DATAh(vp_push, dec->vp_fw->offset);543PUSH_DATA (vp_push, dec->vp_fw->offset);544PUSH_DATA (vp_push, dec->vp_fw->size);545546BEGIN_NV04(vp_push, SUBC_VP(0x628), 2);547PUSH_DATA (vp_push, dec->vp_data->offset >> 8);548PUSH_DATA (vp_push, dec->vp_data->size);549PUSH_KICK (vp_push);550551return &dec->base;552fail:553nv84_decoder_destroy(&dec->base);554return NULL;555}556557static struct pipe_sampler_view **558nv84_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)559{560struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;561return buf->sampler_view_planes;562}563564static struct pipe_sampler_view **565nv84_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)566{567struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;568return buf->sampler_view_components;569}570571static struct pipe_surface **572nv84_video_buffer_surfaces(struct pipe_video_buffer *buffer)573{574struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;575return buf->surfaces;576}577578static void579nv84_video_buffer_destroy(struct pipe_video_buffer *buffer)580{581struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;582unsigned i;583584assert(buf);585586for (i = 0; i < VL_NUM_COMPONENTS; ++i) {587pipe_resource_reference(&buf->resources[i], NULL);588pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);589pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);590pipe_surface_reference(&buf->surfaces[i * 2], NULL);591pipe_surface_reference(&buf->surfaces[i * 2 + 1], NULL);592}593594nouveau_bo_ref(NULL, &buf->interlaced);595nouveau_bo_ref(NULL, &buf->full);596597FREE(buffer);598}599600struct pipe_video_buffer *601nv84_video_buffer_create(struct pipe_context *pipe,602const struct pipe_video_buffer *template)603{604struct nv84_video_buffer *buffer;605struct pipe_resource templ;606unsigned i, j, component;607struct pipe_sampler_view sv_templ;608struct pipe_surface surf_templ;609struct nv50_miptree *mt0, *mt1;610struct nouveau_screen *screen = &((struct nv50_context *)pipe)->screen->base;611union nouveau_bo_config cfg;612unsigned bo_size;613614if (getenv("XVMC_VL") || template->buffer_format != PIPE_FORMAT_NV12)615return vl_video_buffer_create(pipe, template);616617if (!template->interlaced) {618debug_printf("Require interlaced video buffers\n");619return NULL;620}621if (pipe_format_to_chroma_format(template->buffer_format) != PIPE_VIDEO_CHROMA_FORMAT_420) {622debug_printf("Must use 4:2:0 format\n");623return NULL;624}625626/*627* Note that there are always going to be exactly two planes, one for Y,628* and one for UV. These are also the resources. VP expects these to be629* adjacent, so they need to belong to the same BO.630*/631632buffer = CALLOC_STRUCT(nv84_video_buffer);633if (!buffer) return NULL;634635buffer->mvidx = -1;636637buffer->base.buffer_format = template->buffer_format;638buffer->base.context = pipe;639buffer->base.destroy = nv84_video_buffer_destroy;640buffer->base.width = template->width;641buffer->base.height = template->height;642buffer->base.get_sampler_view_planes = nv84_video_buffer_sampler_view_planes;643buffer->base.get_sampler_view_components = nv84_video_buffer_sampler_view_components;644buffer->base.get_surfaces = nv84_video_buffer_surfaces;645buffer->base.interlaced = true;646647memset(&templ, 0, sizeof(templ));648templ.target = PIPE_TEXTURE_2D_ARRAY;649templ.depth0 = 1;650templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;651templ.format = PIPE_FORMAT_R8_UNORM;652templ.width0 = align(template->width, 2);653templ.height0 = align(template->height, 4) / 2;654templ.flags = NV50_RESOURCE_FLAG_VIDEO | NV50_RESOURCE_FLAG_NOALLOC;655templ.array_size = 2;656657cfg.nv50.tile_mode = 0x20;658cfg.nv50.memtype = 0x70;659660buffer->resources[0] = pipe->screen->resource_create(pipe->screen, &templ);661if (!buffer->resources[0])662goto error;663664templ.format = PIPE_FORMAT_R8G8_UNORM;665templ.width0 /= 2;666templ.height0 /= 2;667buffer->resources[1] = pipe->screen->resource_create(pipe->screen, &templ);668if (!buffer->resources[1])669goto error;670671mt0 = nv50_miptree(buffer->resources[0]);672mt1 = nv50_miptree(buffer->resources[1]);673674bo_size = mt0->total_size + mt1->total_size;675if (nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP, 0,676bo_size, &cfg, &buffer->interlaced))677goto error;678/* XXX Change reference frame management so that this is only allocated in679* the decoder when necessary. */680if (nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP, 0,681bo_size, &cfg, &buffer->full))682goto error;683684nouveau_bo_ref(buffer->interlaced, &mt0->base.bo);685mt0->base.domain = NOUVEAU_BO_VRAM;686mt0->base.address = buffer->interlaced->offset;687688nouveau_bo_ref(buffer->interlaced, &mt1->base.bo);689mt1->base.domain = NOUVEAU_BO_VRAM;690mt1->base.offset = mt0->total_size;691mt1->base.address = buffer->interlaced->offset + mt0->total_size;692693memset(&sv_templ, 0, sizeof(sv_templ));694for (component = 0, i = 0; i < 2; ++i ) {695struct pipe_resource *res = buffer->resources[i];696unsigned nr_components = util_format_get_nr_components(res->format);697698u_sampler_view_default_template(&sv_templ, res, res->format);699buffer->sampler_view_planes[i] =700pipe->create_sampler_view(pipe, res, &sv_templ);701if (!buffer->sampler_view_planes[i])702goto error;703704for (j = 0; j < nr_components; ++j, ++component) {705sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b =706PIPE_SWIZZLE_X + j;707sv_templ.swizzle_a = PIPE_SWIZZLE_1;708709buffer->sampler_view_components[component] =710pipe->create_sampler_view(pipe, res, &sv_templ);711if (!buffer->sampler_view_components[component])712goto error;713}714}715716memset(&surf_templ, 0, sizeof(surf_templ));717for (j = 0; j < 2; ++j) {718surf_templ.format = buffer->resources[j]->format;719surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 0;720buffer->surfaces[j * 2] =721pipe->create_surface(pipe, buffer->resources[j], &surf_templ);722if (!buffer->surfaces[j * 2])723goto error;724725surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 1;726buffer->surfaces[j * 2 + 1] =727pipe->create_surface(pipe, buffer->resources[j], &surf_templ);728if (!buffer->surfaces[j * 2 + 1])729goto error;730}731732return &buffer->base;733734error:735nv84_video_buffer_destroy(&buffer->base);736return NULL;737}738739#define FIRMWARE_BSP_KERN 0x01740#define FIRMWARE_VP_KERN 0x02741#define FIRMWARE_BSP_H264 0x04742#define FIRMWARE_VP_MPEG2 0x08743#define FIRMWARE_VP_H264_1 0x10744#define FIRMWARE_VP_H264_2 0x20745#define FIRMWARE_PRESENT(val, fw) (val & FIRMWARE_ ## fw)746747static int748firmware_present(struct pipe_screen *pscreen, enum pipe_video_format codec)749{750struct nouveau_screen *screen = nouveau_screen(pscreen);751struct nouveau_object *obj = NULL;752struct stat s;753int checked = screen->firmware_info.profiles_checked;754int present, ret;755756if (!FIRMWARE_PRESENT(checked, VP_KERN)) {757ret = nouveau_object_new(screen->channel, 0, 0x7476, NULL, 0, &obj);758if (!ret)759screen->firmware_info.profiles_present |= FIRMWARE_VP_KERN;760nouveau_object_del(&obj);761screen->firmware_info.profiles_checked |= FIRMWARE_VP_KERN;762}763764if (codec == PIPE_VIDEO_FORMAT_MPEG4_AVC) {765if (!FIRMWARE_PRESENT(checked, BSP_KERN)) {766ret = nouveau_object_new(screen->channel, 0, 0x74b0, NULL, 0, &obj);767if (!ret)768screen->firmware_info.profiles_present |= FIRMWARE_BSP_KERN;769nouveau_object_del(&obj);770screen->firmware_info.profiles_checked |= FIRMWARE_BSP_KERN;771}772773if (!FIRMWARE_PRESENT(checked, VP_H264_1)) {774ret = stat("/lib/firmware/nouveau/nv84_vp-h264-1", &s);775if (!ret && s.st_size > 1000)776screen->firmware_info.profiles_present |= FIRMWARE_VP_H264_1;777screen->firmware_info.profiles_checked |= FIRMWARE_VP_H264_1;778}779780/* should probably check the others, but assume that 1 means all */781782present = screen->firmware_info.profiles_present;783return FIRMWARE_PRESENT(present, VP_KERN) &&784FIRMWARE_PRESENT(present, BSP_KERN) &&785FIRMWARE_PRESENT(present, VP_H264_1);786} else {787if (!FIRMWARE_PRESENT(checked, VP_MPEG2)) {788ret = stat("/lib/firmware/nouveau/nv84_vp-mpeg12", &s);789if (!ret && s.st_size > 1000)790screen->firmware_info.profiles_present |= FIRMWARE_VP_MPEG2;791screen->firmware_info.profiles_checked |= FIRMWARE_VP_MPEG2;792}793present = screen->firmware_info.profiles_present;794return FIRMWARE_PRESENT(present, VP_KERN) &&795FIRMWARE_PRESENT(present, VP_MPEG2);796}797}798799int800nv84_screen_get_video_param(struct pipe_screen *pscreen,801enum pipe_video_profile profile,802enum pipe_video_entrypoint entrypoint,803enum pipe_video_cap param)804{805enum pipe_video_format codec;806807switch (param) {808case PIPE_VIDEO_CAP_SUPPORTED:809codec = u_reduce_video_profile(profile);810return (codec == PIPE_VIDEO_FORMAT_MPEG4_AVC ||811codec == PIPE_VIDEO_FORMAT_MPEG12) &&812firmware_present(pscreen, codec);813case PIPE_VIDEO_CAP_NPOT_TEXTURES:814return 1;815case PIPE_VIDEO_CAP_MAX_WIDTH:816case PIPE_VIDEO_CAP_MAX_HEIGHT:817return 2048;818case PIPE_VIDEO_CAP_PREFERED_FORMAT:819return PIPE_FORMAT_NV12;820case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:821case PIPE_VIDEO_CAP_PREFERS_INTERLACED:822return true;823case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:824return false;825case PIPE_VIDEO_CAP_MAX_LEVEL:826switch (profile) {827case PIPE_VIDEO_PROFILE_MPEG1:828return 0;829case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:830case PIPE_VIDEO_PROFILE_MPEG2_MAIN:831return 3;832case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:833case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:834case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:835return 41;836default:837debug_printf("unknown video profile: %d\n", profile);838return 0;839}840case PIPE_VIDEO_CAP_MAX_MACROBLOCKS:841return 8192; /* vc-1 actually has 8190, but this is not supported */842default:843debug_printf("unknown video param: %d\n", param);844return 0;845}846}847848bool849nv84_screen_video_supported(struct pipe_screen *screen,850enum pipe_format format,851enum pipe_video_profile profile,852enum pipe_video_entrypoint entrypoint)853{854if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)855return format == PIPE_FORMAT_NV12;856857return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);858}859860861