Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2013 Advanced Micro Devices, Inc.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28. /*
  29.  * Authors:
  30.  *      Christian König <christian.koenig@amd.com>
  31.  *
  32.  */
  33.  
  34. #include <stdio.h>
  35.  
  36. #include "pipe/p_video_codec.h"
  37.  
  38. #include "util/u_video.h"
  39. #include "util/u_memory.h"
  40.  
  41. #include "vl/vl_video_buffer.h"
  42.  
  43. #include "r600_pipe_common.h"
  44. #include "radeon_video.h"
  45. #include "radeon_vce.h"
  46.  
  47. /**
  48.  * flush commands to the hardware
  49.  */
  50. static void flush(struct rvce_encoder *enc)
  51. {
  52.         enc->ws->cs_flush(enc->cs, RADEON_FLUSH_ASYNC, NULL, 0);
  53. }
  54.  
  55. #if 0
  56. static void dump_feedback(struct rvce_encoder *enc, struct rvid_buffer *fb)
  57. {
  58.         uint32_t *ptr = enc->ws->buffer_map(fb->res->cs_buf, enc->cs, PIPE_TRANSFER_READ_WRITE);
  59.         unsigned i = 0;
  60.         fprintf(stderr, "\n");
  61.         fprintf(stderr, "encStatus:\t\t\t%08x\n", ptr[i++]);
  62.         fprintf(stderr, "encHasBitstream:\t\t%08x\n", ptr[i++]);
  63.         fprintf(stderr, "encHasAudioBitstream:\t\t%08x\n", ptr[i++]);
  64.         fprintf(stderr, "encBitstreamOffset:\t\t%08x\n", ptr[i++]);
  65.         fprintf(stderr, "encBitstreamSize:\t\t%08x\n", ptr[i++]);
  66.         fprintf(stderr, "encAudioBitstreamOffset:\t%08x\n", ptr[i++]);
  67.         fprintf(stderr, "encAudioBitstreamSize:\t\t%08x\n", ptr[i++]);
  68.         fprintf(stderr, "encExtrabytes:\t\t\t%08x\n", ptr[i++]);
  69.         fprintf(stderr, "encAudioExtrabytes:\t\t%08x\n", ptr[i++]);
  70.         fprintf(stderr, "videoTimeStamp:\t\t\t%08x\n", ptr[i++]);
  71.         fprintf(stderr, "audioTimeStamp:\t\t\t%08x\n", ptr[i++]);
  72.         fprintf(stderr, "videoOutputType:\t\t%08x\n", ptr[i++]);
  73.         fprintf(stderr, "attributeFlags:\t\t\t%08x\n", ptr[i++]);
  74.         fprintf(stderr, "seiPrivatePackageOffset:\t%08x\n", ptr[i++]);
  75.         fprintf(stderr, "seiPrivatePackageSize:\t\t%08x\n", ptr[i++]);
  76.         fprintf(stderr, "\n");
  77.         enc->ws->buffer_unmap(fb->res->cs_buf);
  78. }
  79. #endif
  80.  
  81. /**
  82.  * reset the CPB handling
  83.  */
  84. static void reset_cpb(struct rvce_encoder *enc)
  85. {
  86.         unsigned i;
  87.  
  88.         LIST_INITHEAD(&enc->cpb_slots);
  89.         for (i = 0; i < enc->cpb_num; ++i) {
  90.                 struct rvce_cpb_slot *slot = &enc->cpb_array[i];
  91.                 slot->index = i;
  92.                 slot->picture_type = PIPE_H264_ENC_PICTURE_TYPE_SKIP;
  93.                 slot->frame_num = 0;
  94.                 slot->pic_order_cnt = 0;
  95.                 LIST_ADDTAIL(&slot->list, &enc->cpb_slots);
  96.         }
  97. }
  98.  
  99. /**
  100.  * sort l0 and l1 to the top of the list
  101.  */
  102. static void sort_cpb(struct rvce_encoder *enc)
  103. {
  104.         struct rvce_cpb_slot *i, *l0 = NULL, *l1 = NULL;
  105.  
  106.         LIST_FOR_EACH_ENTRY(i, &enc->cpb_slots, list) {
  107.                 if (i->frame_num == enc->pic.ref_idx_l0)
  108.                         l0 = i;
  109.  
  110.                 if (i->frame_num == enc->pic.ref_idx_l1)
  111.                         l1 = i;
  112.  
  113.                 if (enc->pic.picture_type == PIPE_H264_ENC_PICTURE_TYPE_P && l0)
  114.                         break;
  115.  
  116.                 if (enc->pic.picture_type == PIPE_H264_ENC_PICTURE_TYPE_B &&
  117.                     l0 && l1)
  118.                         break;
  119.         }
  120.  
  121.         if (l1) {
  122.                 LIST_DEL(&l1->list);
  123.                 LIST_ADD(&l1->list, &enc->cpb_slots);
  124.         }
  125.  
  126.         if (l0) {
  127.                 LIST_DEL(&l0->list);
  128.                 LIST_ADD(&l0->list, &enc->cpb_slots);
  129.         }
  130. }
  131.  
  132. /**
  133.  * get number of cpbs based on dpb
  134.  */
  135. static unsigned get_cpb_num(struct rvce_encoder *enc)
  136. {
  137.         unsigned w = align(enc->base.width, 16) / 16;
  138.         unsigned h = align(enc->base.height, 16) / 16;
  139.         unsigned dpb;
  140.  
  141.         switch (enc->base.level) {
  142.         case 10:
  143.                 dpb = 396;
  144.                 break;
  145.         case 11:
  146.                 dpb = 900;
  147.                 break;
  148.         case 12:
  149.         case 13:
  150.         case 20:
  151.                 dpb = 2376;
  152.                 break;
  153.         case 21:
  154.                 dpb = 4752;
  155.                 break;
  156.         case 22:
  157.         case 30:
  158.                 dpb = 8100;
  159.                 break;
  160.         case 31:
  161.                 dpb = 18000;
  162.                 break;
  163.         case 32:
  164.                 dpb = 20480;
  165.                 break;
  166.         case 40:
  167.         case 41:
  168.                 dpb = 32768;
  169.                 break;
  170.         default:
  171.         case 42:
  172.                 dpb = 34816;
  173.                 break;
  174.         case 50:
  175.                 dpb = 110400;
  176.                 break;
  177.         case 51:
  178.                 dpb = 184320;
  179.                 break;
  180.         }
  181.  
  182.         return MIN2(dpb / (w * h), 16);
  183. }
  184.  
  185. /**
  186.  * destroy this video encoder
  187.  */
  188. static void rvce_destroy(struct pipe_video_codec *encoder)
  189. {
  190.         struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
  191.         if (enc->stream_handle) {
  192.                 struct rvid_buffer fb;
  193.                 rvid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING);
  194.                 enc->fb = &fb;
  195.                 enc->session(enc);
  196.                 enc->feedback(enc);
  197.                 enc->destroy(enc);
  198.                 flush(enc);
  199.                 rvid_destroy_buffer(&fb);
  200.         }
  201.         rvid_destroy_buffer(&enc->cpb);
  202.         enc->ws->cs_destroy(enc->cs);
  203.         FREE(enc->cpb_array);
  204.         FREE(enc);
  205. }
  206.  
  207. static void rvce_begin_frame(struct pipe_video_codec *encoder,
  208.                              struct pipe_video_buffer *source,
  209.                              struct pipe_picture_desc *picture)
  210. {
  211.         struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
  212.         struct vl_video_buffer *vid_buf = (struct vl_video_buffer *)source;
  213.         struct pipe_h264_enc_picture_desc *pic = (struct pipe_h264_enc_picture_desc *)picture;
  214.  
  215.         bool need_rate_control =
  216.                 enc->pic.rate_ctrl.rate_ctrl_method != pic->rate_ctrl.rate_ctrl_method ||
  217.                 enc->pic.quant_i_frames != pic->quant_i_frames ||
  218.                 enc->pic.quant_p_frames != pic->quant_p_frames ||
  219.                 enc->pic.quant_b_frames != pic->quant_b_frames;
  220.  
  221.         enc->pic = *pic;
  222.  
  223.         enc->get_buffer(vid_buf->resources[0], &enc->handle, &enc->luma);
  224.         enc->get_buffer(vid_buf->resources[1], NULL, &enc->chroma);
  225.  
  226.         if (pic->picture_type == PIPE_H264_ENC_PICTURE_TYPE_IDR)
  227.                 reset_cpb(enc);
  228.         else if (pic->picture_type == PIPE_H264_ENC_PICTURE_TYPE_P ||
  229.                  pic->picture_type == PIPE_H264_ENC_PICTURE_TYPE_B)
  230.                 sort_cpb(enc);
  231.        
  232.         if (!enc->stream_handle) {
  233.                 struct rvid_buffer fb;
  234.                 enc->stream_handle = rvid_alloc_stream_handle();
  235.                 rvid_create_buffer(enc->screen, &fb, 512, PIPE_USAGE_STAGING);
  236.                 enc->fb = &fb;
  237.                 enc->session(enc);
  238.                 enc->create(enc);
  239.                 enc->rate_control(enc);
  240.                 need_rate_control = false;
  241.                 enc->config_extension(enc);
  242.                 enc->motion_estimation(enc);
  243.                 enc->rdo(enc);
  244.                 if (enc->use_vui)
  245.                         enc->vui(enc);
  246.                 enc->pic_control(enc);
  247.                 enc->feedback(enc);
  248.                 flush(enc);
  249.                 //dump_feedback(enc, &fb);
  250.                 rvid_destroy_buffer(&fb);
  251.         }
  252.  
  253.         enc->session(enc);
  254.  
  255.         if (need_rate_control)
  256.                 enc->rate_control(enc);
  257. }
  258.  
  259. static void rvce_encode_bitstream(struct pipe_video_codec *encoder,
  260.                                   struct pipe_video_buffer *source,
  261.                                   struct pipe_resource *destination,
  262.                                   void **fb)
  263. {
  264.         struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
  265.         enc->get_buffer(destination, &enc->bs_handle, NULL);
  266.         enc->bs_size = destination->width0;
  267.  
  268.         *fb = enc->fb = CALLOC_STRUCT(rvid_buffer);
  269.         if (!rvid_create_buffer(enc->screen, enc->fb, 512, PIPE_USAGE_STAGING)) {
  270.                 RVID_ERR("Can't create feedback buffer.\n");
  271.                 return;
  272.         }
  273.         enc->encode(enc);
  274.         enc->feedback(enc);
  275. }
  276.  
  277. static void rvce_end_frame(struct pipe_video_codec *encoder,
  278.                            struct pipe_video_buffer *source,
  279.                            struct pipe_picture_desc *picture)
  280. {
  281.         struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
  282.         struct rvce_cpb_slot *slot = LIST_ENTRY(
  283.                 struct rvce_cpb_slot, enc->cpb_slots.prev, list);
  284.  
  285.         flush(enc);
  286.  
  287.         /* update the CPB backtrack with the just encoded frame */
  288.         slot->picture_type = enc->pic.picture_type;
  289.         slot->frame_num = enc->pic.frame_num;
  290.         slot->pic_order_cnt = enc->pic.pic_order_cnt;
  291.         if (!enc->pic.not_referenced) {
  292.                 LIST_DEL(&slot->list);
  293.                 LIST_ADD(&slot->list, &enc->cpb_slots);
  294.         }
  295. }
  296.  
  297. static void rvce_get_feedback(struct pipe_video_codec *encoder,
  298.                               void *feedback, unsigned *size)
  299. {
  300.         struct rvce_encoder *enc = (struct rvce_encoder*)encoder;
  301.         struct rvid_buffer *fb = feedback;
  302.  
  303.         if (size) {
  304.                 uint32_t *ptr = enc->ws->buffer_map(fb->res->cs_buf, enc->cs, PIPE_TRANSFER_READ_WRITE);
  305.  
  306.                 if (ptr[1]) {
  307.                         *size = ptr[4] - ptr[9];
  308.                 } else {
  309.                         *size = 0;
  310.                 }
  311.  
  312.                 enc->ws->buffer_unmap(fb->res->cs_buf);
  313.         }
  314.         //dump_feedback(enc, fb);
  315.         rvid_destroy_buffer(fb);
  316.         FREE(fb);
  317. }
  318.  
  319. /**
  320.  * flush any outstanding command buffers to the hardware
  321.  */
  322. static void rvce_flush(struct pipe_video_codec *encoder)
  323. {
  324. }
  325.  
  326. static void rvce_cs_flush(void *ctx, unsigned flags,
  327.                           struct pipe_fence_handle **fence)
  328. {
  329.         // just ignored
  330. }
  331.  
  332. struct pipe_video_codec *rvce_create_encoder(struct pipe_context *context,
  333.                                              const struct pipe_video_codec *templ,
  334.                                              struct radeon_winsys* ws,
  335.                                              rvce_get_buffer get_buffer)
  336. {
  337.         struct r600_common_screen *rscreen = (struct r600_common_screen *)context->screen;
  338.         struct rvce_encoder *enc;
  339.         struct pipe_video_buffer *tmp_buf, templat = {};
  340.         struct radeon_surf *tmp_surf;
  341.         unsigned cpb_size;
  342.  
  343.         if (!rscreen->info.vce_fw_version) {
  344.                 RVID_ERR("Kernel doesn't supports VCE!\n");
  345.                 return NULL;
  346.  
  347.         } else if (!rvce_is_fw_version_supported(rscreen)) {
  348.                 RVID_ERR("Unsupported VCE fw version loaded!\n");
  349.                 return NULL;
  350.         }
  351.  
  352.         enc = CALLOC_STRUCT(rvce_encoder);
  353.         if (!enc)
  354.                 return NULL;
  355.  
  356.         if ((rscreen->info.drm_major > 2) || (rscreen->info.drm_minor >= 42))
  357.                 enc->use_vui = true;
  358.  
  359.         enc->base = *templ;
  360.         enc->base.context = context;
  361.  
  362.         enc->base.destroy = rvce_destroy;
  363.         enc->base.begin_frame = rvce_begin_frame;
  364.         enc->base.encode_bitstream = rvce_encode_bitstream;
  365.         enc->base.end_frame = rvce_end_frame;
  366.         enc->base.flush = rvce_flush;
  367.         enc->base.get_feedback = rvce_get_feedback;
  368.         enc->get_buffer = get_buffer;
  369.  
  370.         enc->screen = context->screen;
  371.         enc->ws = ws;
  372.         enc->cs = ws->cs_create(ws, RING_VCE, rvce_cs_flush, enc, NULL);
  373.         if (!enc->cs) {
  374.                 RVID_ERR("Can't get command submission context.\n");
  375.                 goto error;
  376.         }
  377.  
  378.         templat.buffer_format = PIPE_FORMAT_NV12;
  379.         templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
  380.         templat.width = enc->base.width;
  381.         templat.height = enc->base.height;
  382.         templat.interlaced = false;
  383.         if (!(tmp_buf = context->create_video_buffer(context, &templat))) {
  384.                 RVID_ERR("Can't create video buffer.\n");
  385.                 goto error;
  386.         }
  387.  
  388.         enc->cpb_num = get_cpb_num(enc);
  389.         if (!enc->cpb_num)
  390.                 goto error;
  391.  
  392.         get_buffer(((struct vl_video_buffer *)tmp_buf)->resources[0], NULL, &tmp_surf);
  393.         cpb_size = align(tmp_surf->level[0].pitch_bytes, 128);
  394.         cpb_size = cpb_size * align(tmp_surf->npix_y, 16);
  395.         cpb_size = cpb_size * 3 / 2;
  396.         cpb_size = cpb_size * enc->cpb_num;
  397.         tmp_buf->destroy(tmp_buf);
  398.         if (!rvid_create_buffer(enc->screen, &enc->cpb, cpb_size, PIPE_USAGE_DEFAULT)) {
  399.                 RVID_ERR("Can't create CPB buffer.\n");
  400.                 goto error;
  401.         }
  402.  
  403.         enc->cpb_array = CALLOC(enc->cpb_num, sizeof(struct rvce_cpb_slot));
  404.         if (!enc->cpb_array)
  405.                 goto error;
  406.  
  407.         reset_cpb(enc);
  408.  
  409.         radeon_vce_40_2_2_init(enc);
  410.  
  411.         return &enc->base;
  412.  
  413. error:
  414.         if (enc->cs)
  415.                 enc->ws->cs_destroy(enc->cs);
  416.  
  417.         rvid_destroy_buffer(&enc->cpb);
  418.  
  419.         FREE(enc->cpb_array);
  420.         FREE(enc);
  421.         return NULL;
  422. }
  423.  
  424. /**
  425.  * check if kernel has the right fw version loaded
  426.  */
  427. bool rvce_is_fw_version_supported(struct r600_common_screen *rscreen)
  428. {
  429.         return rscreen->info.vce_fw_version == ((40 << 24) | (2 << 16) | (2 << 8));
  430. }
  431.