Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2011-2013 Maarten Lankhorst
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20.  * OTHER DEALINGS IN THE SOFTWARE.
  21.  */
  22.  
  23. #include "nvc0_video.h"
  24.  
  25. #include "util/u_sampler.h"
  26. #include "util/u_format.h"
  27.  
  28. #include <sys/mman.h>
  29. #include <fcntl.h>
  30.  
  31. int
  32. nvc0_screen_get_video_param(struct pipe_screen *pscreen,
  33.                             enum pipe_video_profile profile,
  34.                             enum pipe_video_cap param)
  35. {
  36.    switch (param) {
  37.    case PIPE_VIDEO_CAP_SUPPORTED:
  38.       return profile >= PIPE_VIDEO_PROFILE_MPEG1;
  39.    case PIPE_VIDEO_CAP_NPOT_TEXTURES:
  40.       return 1;
  41.    case PIPE_VIDEO_CAP_MAX_WIDTH:
  42.    case PIPE_VIDEO_CAP_MAX_HEIGHT:
  43.       return nouveau_screen(pscreen)->device->chipset < 0xd0 ? 2048 : 4096;
  44.    case PIPE_VIDEO_CAP_PREFERED_FORMAT:
  45.       return PIPE_FORMAT_NV12;
  46.    case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
  47.    case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
  48.       return true;
  49.    case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
  50.       return false;
  51.    default:
  52.       debug_printf("unknown video param: %d\n", param);
  53.       return 0;
  54.    }
  55. }
  56.  
  57. static void
  58. nvc0_decoder_decode_bitstream(struct pipe_video_decoder *decoder,
  59.                               struct pipe_video_buffer *video_target,
  60.                               struct pipe_picture_desc *picture,
  61.                               unsigned num_buffers,
  62.                               const void *const *data,
  63.                               const unsigned *num_bytes)
  64. {
  65.    struct nvc0_decoder *dec = (struct nvc0_decoder *)decoder;
  66.    struct nvc0_video_buffer *target = (struct nvc0_video_buffer *)video_target;
  67.    uint32_t comm_seq = ++dec->fence_seq;
  68.    union pipe_desc desc;
  69.  
  70.    unsigned vp_caps, is_ref, ret;
  71.    struct nvc0_video_buffer *refs[16] = {};
  72.  
  73.    desc.base = picture;
  74.  
  75.    assert(target->base.buffer_format == PIPE_FORMAT_NV12);
  76.  
  77.    ret = nvc0_decoder_bsp(dec, desc, target, comm_seq,
  78.                           num_buffers, data, num_bytes,
  79.                           &vp_caps, &is_ref, refs);
  80.  
  81.    /* did we decode bitstream correctly? */
  82.    assert(ret == 2);
  83.  
  84.    nvc0_decoder_vp(dec, desc, target, comm_seq, vp_caps, is_ref, refs);
  85.    nvc0_decoder_ppp(dec, desc, target, comm_seq);
  86. }
  87.  
  88. static void
  89. nvc0_decoder_flush(struct pipe_video_decoder *decoder)
  90. {
  91.    struct nvc0_decoder *dec = (struct nvc0_decoder *)decoder;
  92.    (void)dec;
  93. }
  94.  
  95. static void
  96. nvc0_decoder_begin_frame(struct pipe_video_decoder *decoder,
  97.                          struct pipe_video_buffer *target,
  98.                          struct pipe_picture_desc *picture)
  99. {
  100. }
  101.  
  102. static void
  103. nvc0_decoder_end_frame(struct pipe_video_decoder *decoder,
  104.                        struct pipe_video_buffer *target,
  105.                        struct pipe_picture_desc *picture)
  106. {
  107. }
  108.  
  109. static void
  110. nvc0_decoder_destroy(struct pipe_video_decoder *decoder)
  111. {
  112.    struct nvc0_decoder *dec = (struct nvc0_decoder *)decoder;
  113.    int i;
  114.  
  115.    nouveau_bo_ref(NULL, &dec->ref_bo);
  116.    nouveau_bo_ref(NULL, &dec->bitplane_bo);
  117.    nouveau_bo_ref(NULL, &dec->inter_bo[0]);
  118.    nouveau_bo_ref(NULL, &dec->inter_bo[1]);
  119. #ifdef NVC0_DEBUG_FENCE
  120.    nouveau_bo_ref(NULL, &dec->fence_bo);
  121. #endif
  122.    nouveau_bo_ref(NULL, &dec->fw_bo);
  123.  
  124.    for (i = 0; i < NVC0_VIDEO_QDEPTH; ++i)
  125.       nouveau_bo_ref(NULL, &dec->bsp_bo[i]);
  126.  
  127.    nouveau_object_del(&dec->bsp);
  128.    nouveau_object_del(&dec->vp);
  129.    nouveau_object_del(&dec->ppp);
  130.  
  131.    if (dec->channel[0] != dec->channel[1]) {
  132.       for (i = 0; i < 3; ++i) {
  133.          nouveau_pushbuf_del(&dec->pushbuf[i]);
  134.          nouveau_object_del(&dec->channel[i]);
  135.       }
  136.    } else {
  137.       nouveau_pushbuf_del(dec->pushbuf);
  138.       nouveau_object_del(dec->channel);
  139.    }
  140.  
  141.    FREE(dec);
  142. }
  143.  
  144. static void nvc0_video_getpath(enum pipe_video_profile profile, char *path)
  145. {
  146.    switch (u_reduce_video_profile(profile)) {
  147.       case PIPE_VIDEO_CODEC_MPEG12: {
  148.          sprintf(path, "/lib/firmware/nouveau/vuc-mpeg12-0");
  149.          break;
  150.       }
  151.       case PIPE_VIDEO_CODEC_MPEG4: {
  152.          sprintf(path, "/lib/firmware/nouveau/vuc-mpeg4-0");
  153.          break;
  154.       }
  155.       case PIPE_VIDEO_CODEC_VC1: {
  156.          sprintf(path, "/lib/firmware/nouveau/vuc-vc1-0");
  157.          break;
  158.       }
  159.       case PIPE_VIDEO_CODEC_MPEG4_AVC: {
  160.          sprintf(path, "/lib/firmware/nouveau/vuc-h264-0");
  161.          break;
  162.       }
  163.       default: assert(0);
  164.    }
  165. }
  166.  
  167. struct pipe_video_decoder *
  168. nvc0_create_decoder(struct pipe_context *context,
  169.                     enum pipe_video_profile profile,
  170.                     enum pipe_video_entrypoint entrypoint,
  171.                     enum pipe_video_chroma_format chroma_format,
  172.                     unsigned width, unsigned height, unsigned max_references,
  173.                     bool chunked_decode)
  174. {
  175.    struct nouveau_screen *screen = &((struct nvc0_context *)context)->screen->base;
  176.    struct nvc0_decoder *dec;
  177.    struct nouveau_pushbuf **push;
  178.    union nouveau_bo_config cfg;
  179.    bool kepler = screen->device->chipset >= 0xe0;
  180.  
  181.    cfg.nvc0.tile_mode = 0x10;
  182.    cfg.nvc0.memtype = 0xfe;
  183.  
  184.    int ret, i;
  185.    uint32_t codec = 1, ppp_codec = 3;
  186.    uint32_t timeout;
  187.    u32 tmp_size = 0;
  188.  
  189.    if (getenv("XVMC_VL"))
  190.        return vl_create_decoder(context, profile, entrypoint,
  191.                                 chroma_format, width, height,
  192.                                 max_references, chunked_decode);
  193.  
  194.    if (entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
  195.       debug_printf("%x\n", entrypoint);
  196.       return NULL;
  197.    }
  198.  
  199.    dec = CALLOC_STRUCT(nvc0_decoder);
  200.    if (!dec)
  201.       return NULL;
  202.    dec->client = screen->client;
  203.  
  204.    if (!kepler) {
  205.       dec->bsp_idx = 5;
  206.       dec->vp_idx = 6;
  207.       dec->ppp_idx = 7;
  208.    } else {
  209.       dec->bsp_idx = 2;
  210.       dec->vp_idx = 2;
  211.       dec->ppp_idx = 2;
  212.    }
  213.  
  214.    for (i = 0; i < 3; ++i)
  215.       if (i && !kepler) {
  216.          dec->channel[i] = dec->channel[0];
  217.          dec->pushbuf[i] = dec->pushbuf[0];
  218.       } else {
  219.          void *data;
  220.          u32 size;
  221.          struct nvc0_fifo nvc0_args = {};
  222.          struct nve0_fifo nve0_args = {};
  223.  
  224.          if (!kepler) {
  225.             size = sizeof(nvc0_args);
  226.             data = &nvc0_args;
  227.          } else {
  228.             unsigned engine[] = {
  229.                NVE0_FIFO_ENGINE_BSP,
  230.                NVE0_FIFO_ENGINE_VP,
  231.                NVE0_FIFO_ENGINE_PPP
  232.             };
  233.  
  234.             nve0_args.engine = engine[i];
  235.             size = sizeof(nve0_args);
  236.             data = &nve0_args;
  237.          }
  238.  
  239.          ret = nouveau_object_new(&screen->device->object, 0,
  240.                                   NOUVEAU_FIFO_CHANNEL_CLASS,
  241.                                   data, size, &dec->channel[i]);
  242.  
  243.          if (!ret)
  244.             ret = nouveau_pushbuf_new(screen->client, dec->channel[i], 4,
  245.                                    32 * 1024, true, &dec->pushbuf[i]);
  246.          if (ret)
  247.             break;
  248.       }
  249.    push = dec->pushbuf;
  250.  
  251.    if (!kepler) {
  252.       if (!ret)
  253.          ret = nouveau_object_new(dec->channel[0], 0x390b1, 0x90b1, NULL, 0, &dec->bsp);
  254.       if (!ret)
  255.          ret = nouveau_object_new(dec->channel[1], 0x190b2, 0x90b2, NULL, 0, &dec->vp);
  256.       if (!ret)
  257.          ret = nouveau_object_new(dec->channel[2], 0x290b3, 0x90b3, NULL, 0, &dec->ppp);
  258.    } else {
  259.       if (!ret)
  260.          ret = nouveau_object_new(dec->channel[0], 0x95b1, 0x95b1, NULL, 0, &dec->bsp);
  261.       if (!ret)
  262.          ret = nouveau_object_new(dec->channel[1], 0x95b2, 0x95b2, NULL, 0, &dec->vp);
  263.       if (!ret)
  264.          ret = nouveau_object_new(dec->channel[2], 0x90b3, 0x90b3, NULL, 0, &dec->ppp);
  265.    }
  266.    if (ret)
  267.       goto fail;
  268.  
  269.    BEGIN_NVC0(push[0], SUBC_BSP(NV01_SUBCHAN_OBJECT), 1);
  270.    PUSH_DATA (push[0], dec->bsp->handle);
  271.  
  272.    BEGIN_NVC0(push[1], SUBC_VP(NV01_SUBCHAN_OBJECT), 1);
  273.    PUSH_DATA (push[1], dec->vp->handle);
  274.  
  275.    BEGIN_NVC0(push[2], SUBC_PPP(NV01_SUBCHAN_OBJECT), 1);
  276.    PUSH_DATA (push[2], dec->ppp->handle);
  277.  
  278.    dec->base.context = context;
  279.    dec->base.profile = profile;
  280.    dec->base.entrypoint = entrypoint;
  281.    dec->base.chroma_format = chroma_format;
  282.    dec->base.width = width;
  283.    dec->base.height = height;
  284.    dec->base.max_references = max_references;
  285.    dec->base.destroy = nvc0_decoder_destroy;
  286.    dec->base.flush = nvc0_decoder_flush;
  287.    dec->base.decode_bitstream = nvc0_decoder_decode_bitstream;
  288.    dec->base.begin_frame = nvc0_decoder_begin_frame;
  289.    dec->base.end_frame = nvc0_decoder_end_frame;
  290.  
  291.    for (i = 0; i < NVC0_VIDEO_QDEPTH && !ret; ++i)
  292.       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,
  293.                            0, 1 << 20, &cfg, &dec->bsp_bo[i]);
  294.    if (!ret)
  295.       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,
  296.                            0x100, 4 << 20, &cfg, &dec->inter_bo[0]);
  297.    if (!ret) {
  298.       if (!kepler)
  299.          nouveau_bo_ref(dec->inter_bo[0], &dec->inter_bo[1]);
  300.       else
  301.          ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,
  302.                               0x100, dec->inter_bo[0]->size, &cfg,
  303.                               &dec->inter_bo[1]);
  304.    }
  305.    if (ret)
  306.       goto fail;
  307.  
  308.    switch (u_reduce_video_profile(profile)) {
  309.    case PIPE_VIDEO_CODEC_MPEG12: {
  310.       codec = 1;
  311.       assert(max_references <= 2);
  312.       break;
  313.    }
  314.    case PIPE_VIDEO_CODEC_MPEG4: {
  315.       codec = 4;
  316.       tmp_size = mb(height)*16 * mb(width)*16;
  317.       assert(max_references <= 2);
  318.       break;
  319.    }
  320.    case PIPE_VIDEO_CODEC_VC1: {
  321.       ppp_codec = codec = 2;
  322.       tmp_size = mb(height)*16 * mb(width)*16;
  323.       assert(max_references <= 2);
  324.       break;
  325.    }
  326.    case PIPE_VIDEO_CODEC_MPEG4_AVC: {
  327.       codec = 3;
  328.       dec->tmp_stride = 16 * mb_half(width) * nvc0_video_align(height) * 3 / 2;
  329.       tmp_size = dec->tmp_stride * (max_references + 1);
  330.       assert(max_references <= 16);
  331.       break;
  332.    }
  333.    default:
  334.       fprintf(stderr, "invalid codec\n");
  335.       goto fail;
  336.    }
  337.  
  338.    if (screen->device->chipset < 0xd0) {
  339.       int fd;
  340.       char path[PATH_MAX];
  341.       ssize_t r;
  342.       uint32_t *end, endval;
  343.  
  344.       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,
  345.                            0x4000, &cfg, &dec->fw_bo);
  346.       if (!ret)
  347.          ret = nouveau_bo_map(dec->fw_bo, NOUVEAU_BO_WR, dec->client);
  348.       if (ret)
  349.          goto fail;
  350.  
  351.       nvc0_video_getpath(profile, path);
  352.  
  353.       fd = open(path, O_RDONLY | O_CLOEXEC);
  354.       if (fd < 0) {
  355.          fprintf(stderr, "opening firmware file %s failed: %m\n", path);
  356.          goto fw_fail;
  357.       }
  358.       r = read(fd, dec->fw_bo->map, 0x4000);
  359.       close(fd);
  360.  
  361.       if (r < 0) {
  362.          fprintf(stderr, "reading firmware file %s failed: %m\n", path);
  363.          goto fw_fail;
  364.       }
  365.  
  366.       if (r == 0x4000) {
  367.          fprintf(stderr, "firmware file %s too large!\n", path);
  368.          goto fw_fail;
  369.       }
  370.  
  371.       if (r & 0xff) {
  372.          fprintf(stderr, "firmware file %s wrong size!\n", path);
  373.          goto fw_fail;
  374.       }
  375.  
  376.       end = dec->fw_bo->map + r - 4;
  377.       endval = *end;
  378.       while (endval == *end)
  379.          end--;
  380.  
  381.       r = (intptr_t)end - (intptr_t)dec->fw_bo->map + 4;
  382.  
  383.       switch (u_reduce_video_profile(profile)) {
  384.       case PIPE_VIDEO_CODEC_MPEG12: {
  385.          assert((r & 0xff) == 0xe0);
  386.          dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
  387.          break;
  388.       }
  389.       case PIPE_VIDEO_CODEC_MPEG4: {
  390.          assert((r & 0xff) == 0xe0);
  391.          dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
  392.          break;
  393.       }
  394.       case PIPE_VIDEO_CODEC_VC1: {
  395.          assert((r & 0xff) == 0xac);
  396.          dec->fw_sizes = (0x3ac<<16) | (r - 0x3ac);
  397.          break;
  398.       }
  399.       case PIPE_VIDEO_CODEC_MPEG4_AVC: {
  400.          assert((r & 0xff) == 0x70);
  401.          dec->fw_sizes = (0x370<<16) | (r - 0x370);
  402.          break;
  403.       }
  404.       default:
  405.          goto fw_fail;
  406.       }
  407.       munmap(dec->fw_bo->map, dec->fw_bo->size);
  408.       dec->fw_bo->map = NULL;
  409.    }
  410.  
  411.    if (codec != 3) {
  412.       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,
  413.                            0x400, &cfg, &dec->bitplane_bo);
  414.       if (ret)
  415.          goto fail;
  416.    }
  417.  
  418.    dec->ref_stride = mb(width)*16 * (mb_half(height)*32 + nvc0_video_align(height)/2);
  419.    ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,
  420.                         dec->ref_stride * (max_references+2) + tmp_size,
  421.                         &cfg, &dec->ref_bo);
  422.    if (ret)
  423.       goto fail;
  424.  
  425.    timeout = 0;
  426.  
  427.    BEGIN_NVC0(push[0], SUBC_BSP(0x200), 2);
  428.    PUSH_DATA (push[0], codec);
  429.    PUSH_DATA (push[0], timeout);
  430.  
  431.    BEGIN_NVC0(push[1], SUBC_VP(0x200), 2);
  432.    PUSH_DATA (push[1], codec);
  433.    PUSH_DATA (push[1], timeout);
  434.  
  435.    BEGIN_NVC0(push[2], SUBC_PPP(0x200), 2);
  436.    PUSH_DATA (push[2], ppp_codec);
  437.    PUSH_DATA (push[2], timeout);
  438.  
  439.    ++dec->fence_seq;
  440.  
  441. #if NVC0_DEBUG_FENCE
  442.    ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART|NOUVEAU_BO_MAP,
  443.                         0, 0x1000, NULL, &dec->fence_bo);
  444.    if (ret)
  445.       goto fail;
  446.  
  447.    nouveau_bo_map(dec->fence_bo, NOUVEAU_BO_RDWR, screen->client);
  448.    dec->fence_map = dec->fence_bo->map;
  449.    dec->fence_map[0] = dec->fence_map[4] = dec->fence_map[8] = 0;
  450.    dec->comm = (struct comm *)(dec->fence_map + (COMM_OFFSET/sizeof(*dec->fence_map)));
  451.  
  452.    /* So lets test if the fence is working? */
  453.    nouveau_pushbuf_space(push[0], 6, 1, 0);
  454.    PUSH_REFN (push[0], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);
  455.    BEGIN_NVC0(push[0], SUBC_BSP(0x240), 3);
  456.    PUSH_DATAh(push[0], dec->fence_bo->offset);
  457.    PUSH_DATA (push[0], dec->fence_bo->offset);
  458.    PUSH_DATA (push[0], dec->fence_seq);
  459.  
  460.    BEGIN_NVC0(push[0], SUBC_BSP(0x304), 1);
  461.    PUSH_DATA (push[0], 0);
  462.    PUSH_KICK (push[0]);
  463.  
  464.    nouveau_pushbuf_space(push[1], 6, 1, 0);
  465.    PUSH_REFN (push[1], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);
  466.    BEGIN_NVC0(push[1], SUBC_VP(0x240), 3);
  467.    PUSH_DATAh(push[1], (dec->fence_bo->offset + 0x10));
  468.    PUSH_DATA (push[1], (dec->fence_bo->offset + 0x10));
  469.    PUSH_DATA (push[1], dec->fence_seq);
  470.  
  471.    BEGIN_NVC0(push[1], SUBC_VP(0x304), 1);
  472.    PUSH_DATA (push[1], 0);
  473.    PUSH_KICK (push[1]);
  474.  
  475.    nouveau_pushbuf_space(push[2], 6, 1, 0);
  476.    PUSH_REFN (push[2], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);
  477.    BEGIN_NVC0(push[2], SUBC_PPP(0x240), 3);
  478.    PUSH_DATAh(push[2], (dec->fence_bo->offset + 0x20));
  479.    PUSH_DATA (push[2], (dec->fence_bo->offset + 0x20));
  480.    PUSH_DATA (push[2], dec->fence_seq);
  481.  
  482.    BEGIN_NVC0(push[2], SUBC_PPP(0x304), 1);
  483.    PUSH_DATA (push[2], 0);
  484.    PUSH_KICK (push[2]);
  485.  
  486.    usleep(100);
  487.    while (dec->fence_seq > dec->fence_map[0] ||
  488.           dec->fence_seq > dec->fence_map[4] ||
  489.           dec->fence_seq > dec->fence_map[8]) {
  490.       debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]);
  491.       usleep(100);
  492.    }
  493.    debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]);
  494. #endif
  495.  
  496.    return &dec->base;
  497.  
  498. fw_fail:
  499.    debug_printf("Cannot create decoder without firmware..\n");
  500.    nvc0_decoder_destroy(&dec->base);
  501.    return NULL;
  502.  
  503. fail:
  504.    debug_printf("Creation failed: %s (%i)\n", strerror(-ret), ret);
  505.    nvc0_decoder_destroy(&dec->base);
  506.    return NULL;
  507. }
  508.  
  509. static struct pipe_sampler_view **
  510. nvc0_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
  511. {
  512.    struct nvc0_video_buffer *buf = (struct nvc0_video_buffer *)buffer;
  513.    return buf->sampler_view_planes;
  514. }
  515.  
  516. static struct pipe_sampler_view **
  517. nvc0_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
  518. {
  519.    struct nvc0_video_buffer *buf = (struct nvc0_video_buffer *)buffer;
  520.    return buf->sampler_view_components;
  521. }
  522.  
  523. static struct pipe_surface **
  524. nvc0_video_buffer_surfaces(struct pipe_video_buffer *buffer)
  525. {
  526.    struct nvc0_video_buffer *buf = (struct nvc0_video_buffer *)buffer;
  527.    return buf->surfaces;
  528. }
  529.  
  530. static void
  531. nvc0_video_buffer_destroy(struct pipe_video_buffer *buffer)
  532. {
  533.    struct nvc0_video_buffer *buf = (struct nvc0_video_buffer *)buffer;
  534.    unsigned i;
  535.  
  536.    assert(buf);
  537.  
  538.    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
  539.       pipe_resource_reference(&buf->resources[i], NULL);
  540.       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
  541.       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
  542.       pipe_surface_reference(&buf->surfaces[i * 2], NULL);
  543.       pipe_surface_reference(&buf->surfaces[i * 2 + 1], NULL);
  544.    }
  545.    FREE(buffer);
  546. }
  547.  
  548. struct pipe_video_buffer *
  549. nvc0_video_buffer_create(struct pipe_context *pipe,
  550.                          const struct pipe_video_buffer *templat)
  551. {
  552.    struct nvc0_video_buffer *buffer;
  553.    struct pipe_resource templ;
  554.    unsigned i, j, component;
  555.    struct pipe_sampler_view sv_templ;
  556.    struct pipe_surface surf_templ;
  557.  
  558.    assert(templat->interlaced);
  559.    if (getenv("XVMC_VL") || templat->buffer_format != PIPE_FORMAT_NV12)
  560.       return vl_video_buffer_create(pipe, templat);
  561.  
  562.    assert(templat->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
  563.  
  564.    buffer = CALLOC_STRUCT(nvc0_video_buffer);
  565.    if (!buffer)
  566.       return NULL;
  567.  
  568.    buffer->base.buffer_format = templat->buffer_format;
  569.    buffer->base.context = pipe;
  570.    buffer->base.destroy = nvc0_video_buffer_destroy;
  571.    buffer->base.chroma_format = templat->chroma_format;
  572.    buffer->base.width = templat->width;
  573.    buffer->base.height = templat->height;
  574.    buffer->base.get_sampler_view_planes = nvc0_video_buffer_sampler_view_planes;
  575.    buffer->base.get_sampler_view_components = nvc0_video_buffer_sampler_view_components;
  576.    buffer->base.get_surfaces = nvc0_video_buffer_surfaces;
  577.    buffer->base.interlaced = true;
  578.  
  579.    memset(&templ, 0, sizeof(templ));
  580.    templ.target = PIPE_TEXTURE_2D_ARRAY;
  581.    templ.depth0 = 1;
  582.    templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
  583.    templ.format = PIPE_FORMAT_R8_UNORM;
  584.    templ.width0 = buffer->base.width;
  585.    templ.height0 = (buffer->base.height + 1)/2;
  586.    templ.flags = NVC0_RESOURCE_FLAG_VIDEO;
  587.    templ.array_size = 2;
  588.  
  589.    buffer->resources[0] = pipe->screen->resource_create(pipe->screen, &templ);
  590.    if (!buffer->resources[0])
  591.       goto error;
  592.  
  593.    templ.format = PIPE_FORMAT_R8G8_UNORM;
  594.    buffer->num_planes = 2;
  595.    templ.width0 = (templ.width0 + 1) / 2;
  596.    templ.height0 = (templ.height0 + 1) / 2;
  597.    for (i = 1; i < buffer->num_planes; ++i) {
  598.       buffer->resources[i] = pipe->screen->resource_create(pipe->screen, &templ);
  599.       if (!buffer->resources[i])
  600.          goto error;
  601.    }
  602.  
  603.    memset(&sv_templ, 0, sizeof(sv_templ));
  604.    for (component = 0, i = 0; i < buffer->num_planes; ++i ) {
  605.       struct pipe_resource *res = buffer->resources[i];
  606.       unsigned nr_components = util_format_get_nr_components(res->format);
  607.  
  608.       u_sampler_view_default_template(&sv_templ, res, res->format);
  609.       buffer->sampler_view_planes[i] = pipe->create_sampler_view(pipe, res, &sv_templ);
  610.       if (!buffer->sampler_view_planes[i])
  611.          goto error;
  612.  
  613.       for (j = 0; j < nr_components; ++j, ++component) {
  614.          sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j;
  615.          sv_templ.swizzle_a = PIPE_SWIZZLE_ONE;
  616.  
  617.          buffer->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
  618.          if (!buffer->sampler_view_components[component])
  619.             goto error;
  620.       }
  621.   }
  622.  
  623.    memset(&surf_templ, 0, sizeof(surf_templ));
  624.    for (j = 0; j < buffer->num_planes; ++j) {
  625.       surf_templ.format = buffer->resources[j]->format;
  626.       surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 0;
  627.       buffer->surfaces[j * 2] = pipe->create_surface(pipe, buffer->resources[j], &surf_templ);
  628.       if (!buffer->surfaces[j * 2])
  629.          goto error;
  630.  
  631.       surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 1;
  632.       buffer->surfaces[j * 2 + 1] = pipe->create_surface(pipe, buffer->resources[j], &surf_templ);
  633.       if (!buffer->surfaces[j * 2 + 1])
  634.          goto error;
  635.    }
  636.  
  637.    return &buffer->base;
  638.  
  639. error:
  640.    nvc0_video_buffer_destroy(&buffer->base);
  641.    return NULL;
  642. }
  643.