Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nouveau_vp3_video.c
4570 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 <sys/mman.h>23#include <sys/stat.h>24#include <stdio.h>25#include <fcntl.h>2627#include <nvif/class.h>2829#include "nouveau_screen.h"30#include "nouveau_context.h"31#include "nouveau_vp3_video.h"3233#include "util/u_video.h"34#include "util/format/u_format.h"35#include "util/u_sampler.h"3637static struct pipe_sampler_view **38nouveau_vp3_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)39{40struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;41return buf->sampler_view_planes;42}4344static struct pipe_sampler_view **45nouveau_vp3_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)46{47struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;48return buf->sampler_view_components;49}5051static struct pipe_surface **52nouveau_vp3_video_buffer_surfaces(struct pipe_video_buffer *buffer)53{54struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;55return buf->surfaces;56}5758static void59nouveau_vp3_video_buffer_destroy(struct pipe_video_buffer *buffer)60{61struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;62unsigned i;6364assert(buf);6566for (i = 0; i < VL_NUM_COMPONENTS; ++i) {67pipe_resource_reference(&buf->resources[i], NULL);68pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);69pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);70pipe_surface_reference(&buf->surfaces[i * 2], NULL);71pipe_surface_reference(&buf->surfaces[i * 2 + 1], NULL);72}73FREE(buffer);74}7576struct pipe_video_buffer *77nouveau_vp3_video_buffer_create(struct pipe_context *pipe,78const struct pipe_video_buffer *templat,79int flags)80{81struct nouveau_vp3_video_buffer *buffer;82struct pipe_resource templ;83unsigned i, j, component;84struct pipe_sampler_view sv_templ;85struct pipe_surface surf_templ;8687if (getenv("XVMC_VL") || templat->buffer_format != PIPE_FORMAT_NV12)88return vl_video_buffer_create(pipe, templat);8990assert(templat->interlaced);91assert(pipe_format_to_chroma_format(templat->buffer_format) == PIPE_VIDEO_CHROMA_FORMAT_420);9293buffer = CALLOC_STRUCT(nouveau_vp3_video_buffer);94if (!buffer)95return NULL;9697buffer->base.buffer_format = templat->buffer_format;98buffer->base.context = pipe;99buffer->base.destroy = nouveau_vp3_video_buffer_destroy;100buffer->base.width = templat->width;101buffer->base.height = templat->height;102buffer->base.get_sampler_view_planes = nouveau_vp3_video_buffer_sampler_view_planes;103buffer->base.get_sampler_view_components = nouveau_vp3_video_buffer_sampler_view_components;104buffer->base.get_surfaces = nouveau_vp3_video_buffer_surfaces;105buffer->base.interlaced = true;106107memset(&templ, 0, sizeof(templ));108templ.target = PIPE_TEXTURE_2D_ARRAY;109templ.depth0 = 1;110templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;111templ.format = PIPE_FORMAT_R8_UNORM;112templ.width0 = buffer->base.width;113templ.height0 = (buffer->base.height + 1)/2;114templ.flags = flags;115templ.array_size = 2;116117buffer->resources[0] = pipe->screen->resource_create(pipe->screen, &templ);118if (!buffer->resources[0])119goto error;120121templ.format = PIPE_FORMAT_R8G8_UNORM;122buffer->num_planes = 2;123templ.width0 = (templ.width0 + 1) / 2;124templ.height0 = (templ.height0 + 1) / 2;125for (i = 1; i < buffer->num_planes; ++i) {126buffer->resources[i] = pipe->screen->resource_create(pipe->screen, &templ);127if (!buffer->resources[i])128goto error;129}130131memset(&sv_templ, 0, sizeof(sv_templ));132for (component = 0, i = 0; i < buffer->num_planes; ++i ) {133struct pipe_resource *res = buffer->resources[i];134unsigned nr_components = util_format_get_nr_components(res->format);135136u_sampler_view_default_template(&sv_templ, res, res->format);137buffer->sampler_view_planes[i] = pipe->create_sampler_view(pipe, res, &sv_templ);138if (!buffer->sampler_view_planes[i])139goto error;140141for (j = 0; j < nr_components; ++j, ++component) {142sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_X + j;143sv_templ.swizzle_a = PIPE_SWIZZLE_1;144145buffer->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);146if (!buffer->sampler_view_components[component])147goto error;148}149}150151memset(&surf_templ, 0, sizeof(surf_templ));152for (j = 0; j < buffer->num_planes; ++j) {153surf_templ.format = buffer->resources[j]->format;154surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 0;155buffer->surfaces[j * 2] = pipe->create_surface(pipe, buffer->resources[j], &surf_templ);156if (!buffer->surfaces[j * 2])157goto error;158159surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 1;160buffer->surfaces[j * 2 + 1] = pipe->create_surface(pipe, buffer->resources[j], &surf_templ);161if (!buffer->surfaces[j * 2 + 1])162goto error;163}164165return &buffer->base;166167error:168nouveau_vp3_video_buffer_destroy(&buffer->base);169return NULL;170}171172static void173nouveau_vp3_decoder_flush(struct pipe_video_codec *decoder)174{175}176177static void178nouveau_vp3_decoder_begin_frame(struct pipe_video_codec *decoder,179struct pipe_video_buffer *target,180struct pipe_picture_desc *picture)181{182}183184static void185nouveau_vp3_decoder_end_frame(struct pipe_video_codec *decoder,186struct pipe_video_buffer *target,187struct pipe_picture_desc *picture)188{189}190191static void192nouveau_vp3_decoder_destroy(struct pipe_video_codec *decoder)193{194struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;195int i;196197nouveau_bo_ref(NULL, &dec->ref_bo);198nouveau_bo_ref(NULL, &dec->bitplane_bo);199nouveau_bo_ref(NULL, &dec->inter_bo[0]);200nouveau_bo_ref(NULL, &dec->inter_bo[1]);201#if NOUVEAU_VP3_DEBUG_FENCE202nouveau_bo_ref(NULL, &dec->fence_bo);203#endif204nouveau_bo_ref(NULL, &dec->fw_bo);205206for (i = 0; i < NOUVEAU_VP3_VIDEO_QDEPTH; ++i)207nouveau_bo_ref(NULL, &dec->bsp_bo[i]);208209nouveau_object_del(&dec->bsp);210nouveau_object_del(&dec->vp);211nouveau_object_del(&dec->ppp);212213if (dec->channel[0] != dec->channel[1]) {214for (i = 0; i < 3; ++i) {215nouveau_pushbuf_del(&dec->pushbuf[i]);216nouveau_object_del(&dec->channel[i]);217}218} else {219nouveau_pushbuf_del(dec->pushbuf);220nouveau_object_del(dec->channel);221}222223FREE(dec);224}225226void227nouveau_vp3_decoder_init_common(struct pipe_video_codec *dec)228{229dec->destroy = nouveau_vp3_decoder_destroy;230dec->flush = nouveau_vp3_decoder_flush;231dec->begin_frame = nouveau_vp3_decoder_begin_frame;232dec->end_frame = nouveau_vp3_decoder_end_frame;233}234235static void vp3_getpath(enum pipe_video_profile profile, char *path)236{237switch (u_reduce_video_profile(profile)) {238case PIPE_VIDEO_FORMAT_MPEG12: {239sprintf(path, "/lib/firmware/nouveau/vuc-vp3-mpeg12-0");240break;241}242case PIPE_VIDEO_FORMAT_VC1: {243sprintf(path, "/lib/firmware/nouveau/vuc-vp3-vc1-0");244break;245}246case PIPE_VIDEO_FORMAT_MPEG4_AVC: {247sprintf(path, "/lib/firmware/nouveau/vuc-vp3-h264-0");248break;249}250default: assert(0);251}252}253254static void vp4_getpath(enum pipe_video_profile profile, char *path)255{256switch (u_reduce_video_profile(profile)) {257case PIPE_VIDEO_FORMAT_MPEG12: {258sprintf(path, "/lib/firmware/nouveau/vuc-mpeg12-0");259break;260}261case PIPE_VIDEO_FORMAT_MPEG4: {262sprintf(path, "/lib/firmware/nouveau/vuc-mpeg4-0");263break;264}265case PIPE_VIDEO_FORMAT_VC1: {266sprintf(path, "/lib/firmware/nouveau/vuc-vc1-0");267break;268}269case PIPE_VIDEO_FORMAT_MPEG4_AVC: {270sprintf(path, "/lib/firmware/nouveau/vuc-h264-0");271break;272}273default: assert(0);274}275}276277int278nouveau_vp3_load_firmware(struct nouveau_vp3_decoder *dec,279enum pipe_video_profile profile,280unsigned chipset)281{282int fd;283char path[PATH_MAX];284ssize_t r;285uint32_t *end, endval;286287if (chipset >= 0xa3 && chipset != 0xaa && chipset != 0xac)288vp4_getpath(profile, path);289else290vp3_getpath(profile, path);291292if (nouveau_bo_map(dec->fw_bo, NOUVEAU_BO_WR, dec->client))293return 1;294295fd = open(path, O_RDONLY | O_CLOEXEC);296if (fd < 0) {297fprintf(stderr, "opening firmware file %s failed: %m\n", path);298return 1;299}300r = read(fd, dec->fw_bo->map, 0x4000);301close(fd);302303if (r < 0) {304fprintf(stderr, "reading firmware file %s failed: %m\n", path);305return 1;306}307308if (r == 0x4000) {309fprintf(stderr, "firmware file %s too large!\n", path);310return 1;311}312313if (r & 0xff) {314fprintf(stderr, "firmware file %s wrong size!\n", path);315return 1;316}317318end = dec->fw_bo->map + r - 4;319endval = *end;320while (endval == *end)321end--;322323r = (intptr_t)end - (intptr_t)dec->fw_bo->map + 4;324325switch (u_reduce_video_profile(profile)) {326case PIPE_VIDEO_FORMAT_MPEG12: {327assert((r & 0xff) == 0xe0);328dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);329break;330}331case PIPE_VIDEO_FORMAT_MPEG4: {332assert((r & 0xff) == 0xe0);333dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);334break;335}336case PIPE_VIDEO_FORMAT_VC1: {337assert((r & 0xff) == 0xac);338dec->fw_sizes = (0x3ac<<16) | (r - 0x3ac);339break;340}341case PIPE_VIDEO_FORMAT_MPEG4_AVC: {342assert((r & 0xff) == 0x70);343dec->fw_sizes = (0x370<<16) | (r - 0x370);344break;345}346default:347return 1;348}349munmap(dec->fw_bo->map, dec->fw_bo->size);350dec->fw_bo->map = NULL;351return 0;352}353354static const struct nouveau_mclass355nouveau_decoder_msvld[] = {356{ G98_MSVLD, -1 },357{ IGT21A_MSVLD, -1 },358{ GT212_MSVLD, -1 },359{ GF100_MSVLD, -1 },360{ GK104_MSVLD, -1 },361{}362};363364static int365firmware_present(struct pipe_screen *pscreen, enum pipe_video_profile profile)366{367struct nouveau_screen *screen = nouveau_screen(pscreen);368int chipset = screen->device->chipset;369int vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;370int vp5 = chipset >= 0xd0;371int ret;372373/* For all chipsets, try to create a BSP objects. Assume that if firmware374* is present for it, firmware is also present for VP/PPP */375if (!(screen->firmware_info.profiles_checked & 1)) {376struct nouveau_object *channel = NULL, *bsp = NULL;377struct nv04_fifo nv04_data = {.vram = 0xbeef0201, .gart = 0xbeef0202};378struct nvc0_fifo nvc0_args = {};379struct nve0_fifo nve0_args = {.engine = NVE0_FIFO_ENGINE_BSP};380void *data = NULL;381int size;382383if (chipset < 0xc0) {384data = &nv04_data;385size = sizeof(nv04_data);386} else if (chipset < 0xe0) {387data = &nvc0_args;388size = sizeof(nvc0_args);389} else {390data = &nve0_args;391size = sizeof(nve0_args);392}393394/* kepler must have its own channel, so just do this for everyone */395nouveau_object_new(&screen->device->object, 0,396NOUVEAU_FIFO_CHANNEL_CLASS,397data, size, &channel);398399if (channel) {400ret = nouveau_object_mclass(channel, nouveau_decoder_msvld);401if (ret >= 0)402nouveau_object_new(channel, 0, nouveau_decoder_msvld[ret].oclass,403NULL, 0, &bsp);404if (bsp)405screen->firmware_info.profiles_present |= 1;406nouveau_object_del(&bsp);407nouveau_object_del(&channel);408}409screen->firmware_info.profiles_checked |= 1;410}411412if (!(screen->firmware_info.profiles_present & 1))413return 0;414415/* For vp3/vp4 chipsets, make sure that the relevant firmware is present */416if (!vp5 && !(screen->firmware_info.profiles_checked & (1 << profile))) {417char path[PATH_MAX];418struct stat s;419if (vp3)420vp3_getpath(profile, path);421else422vp4_getpath(profile, path);423ret = stat(path, &s);424if (!ret && s.st_size > 1000)425screen->firmware_info.profiles_present |= (1 << profile);426screen->firmware_info.profiles_checked |= (1 << profile);427}428429return vp5 || (screen->firmware_info.profiles_present & (1 << profile));430}431432int433nouveau_vp3_screen_get_video_param(struct pipe_screen *pscreen,434enum pipe_video_profile profile,435enum pipe_video_entrypoint entrypoint,436enum pipe_video_cap param)437{438const int chipset = nouveau_screen(pscreen)->device->chipset;439/* Feature Set B = vp3, C = vp4, D = vp5 */440const bool vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;441const bool vp5 = chipset >= 0xd0;442enum pipe_video_format codec = u_reduce_video_profile(profile);443switch (param) {444case PIPE_VIDEO_CAP_SUPPORTED:445/* VP3 does not support MPEG4, VP4+ do. */446return entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM &&447profile >= PIPE_VIDEO_PROFILE_MPEG1 &&448profile < PIPE_VIDEO_PROFILE_HEVC_MAIN &&449(!vp3 || codec != PIPE_VIDEO_FORMAT_MPEG4) &&450firmware_present(pscreen, profile);451case PIPE_VIDEO_CAP_NPOT_TEXTURES:452return 1;453case PIPE_VIDEO_CAP_MAX_WIDTH:454switch (codec) {455case PIPE_VIDEO_FORMAT_MPEG12:456return vp5 ? 4032 : 2048;457case PIPE_VIDEO_FORMAT_MPEG4:458return 2048;459case PIPE_VIDEO_FORMAT_VC1:460return 2048;461case PIPE_VIDEO_FORMAT_MPEG4_AVC:462if (vp3)463return 2032;464if (vp5)465return 4032;466return 2048; /* vp4 */467case PIPE_VIDEO_FORMAT_UNKNOWN:468return vp5 ? 4032 : 2048;469default:470debug_printf("unknown video codec: %d\n", codec);471return 0;472}473case PIPE_VIDEO_CAP_MAX_HEIGHT:474switch (codec) {475case PIPE_VIDEO_FORMAT_MPEG12:476return vp5 ? 4048 : 2048;477case PIPE_VIDEO_FORMAT_MPEG4:478return 2048;479case PIPE_VIDEO_FORMAT_VC1:480return 2048;481case PIPE_VIDEO_FORMAT_MPEG4_AVC:482if (vp3)483return 2048;484if (vp5)485return 4080;486return 2048; /* vp4 */487case PIPE_VIDEO_FORMAT_UNKNOWN:488return vp5 ? 4080 : 2048;489default:490debug_printf("unknown video codec: %d\n", codec);491return 0;492}493case PIPE_VIDEO_CAP_PREFERED_FORMAT:494return PIPE_FORMAT_NV12;495case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:496case PIPE_VIDEO_CAP_PREFERS_INTERLACED:497return true;498case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:499return false;500case PIPE_VIDEO_CAP_MAX_LEVEL:501switch (profile) {502case PIPE_VIDEO_PROFILE_MPEG1:503return 0;504case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:505case PIPE_VIDEO_PROFILE_MPEG2_MAIN:506return 3;507case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:508return 3;509case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:510return 5;511case PIPE_VIDEO_PROFILE_VC1_SIMPLE:512return 1;513case PIPE_VIDEO_PROFILE_VC1_MAIN:514return 2;515case PIPE_VIDEO_PROFILE_VC1_ADVANCED:516return 4;517case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:518case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:519case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:520case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:521return 41;522default:523debug_printf("unknown video profile: %d\n", profile);524return 0;525}526case PIPE_VIDEO_CAP_MAX_MACROBLOCKS:527switch (codec) {528case PIPE_VIDEO_FORMAT_MPEG12:529return vp5 ? 65536 : 8192;530case PIPE_VIDEO_FORMAT_MPEG4:531return 8192;532case PIPE_VIDEO_FORMAT_VC1:533return 8190;534case PIPE_VIDEO_FORMAT_MPEG4_AVC:535if (vp3)536return 8190;537if (vp5)538return 65536;539return 8192; /* vp4 */540default:541debug_printf("unknown video codec: %d\n", codec);542return 0;543}544default:545debug_printf("unknown video param: %d\n", param);546return 0;547}548}549550bool551nouveau_vp3_screen_video_supported(struct pipe_screen *screen,552enum pipe_format format,553enum pipe_video_profile profile,554enum pipe_video_entrypoint entrypoint)555{556if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)557return format == PIPE_FORMAT_NV12;558559return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);560}561562563