--- /dev/null
+/*
+ * Copyright 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <sys/param.h>
+
+#include "vl/vl_decoder.h"
+#include "vl/vl_video_buffer.h"
+#include "util/u_video.h"
+#include "util/u_memory.h"
+
+#include "virgl_screen.h"
+#include "virgl_resource.h"
+#include "virgl_encode.h"
+#include "virgl_video.h"
+
+/*
+ * The max size of bs buffer is approximately:
+ * num_of_macroblocks * max_size_of_per_macroblock + size_of_some_headers
+ * Now, we only support YUV420 formats, this means that we have a limit of
+ * 3200 bits(400 Bytes) per macroblock. To simplify the calculation, we
+ * directly use 512 instead of 400.
+ */
+#define BS_BUF_DEFAULT_SIZE(width, height) \
+ ((width) * (height) / (VL_MACROBLOCK_WIDTH * VL_MACROBLOCK_HEIGHT) * 512)
+
+static void switch_buffer(struct virgl_video_codec *vcdc)
+{
+ vcdc->cur_buffer++;
+ vcdc->cur_buffer %= VIRGL_VIDEO_CODEC_BUF_NUM;
+}
+
+#define ITEM_SET(dest, src, item) (dest)->item = (src)->item
+#define ITEM_CPY(dest, src, item) memcpy(&(dest)->item, &(src)->item, sizeof((dest)->item))
+
+static int fill_base_picture_desc(const struct pipe_picture_desc *desc,
+ struct virgl_base_picture_desc *vbase)
+{
+ ITEM_SET(vbase, desc, profile);
+ ITEM_SET(vbase, desc, entry_point);
+ ITEM_SET(vbase, desc, protected_playback);
+ ITEM_SET(vbase, desc, key_size);
+ memcpy(vbase->decrypt_key, desc->decrypt_key,
+ MIN(desc->key_size, sizeof(vbase->decrypt_key)));
+
+ return 0;
+}
+
+static int fill_h264_picture_desc(const struct pipe_picture_desc *desc,
+ union virgl_picture_desc *vdsc)
+{
+ unsigned i;
+ struct virgl_video_buffer *vbuf;
+
+ struct virgl_h264_picture_desc *vh264 = &vdsc->h264;
+ struct virgl_h264_pps *vpps = &vh264->pps;
+ struct virgl_h264_sps *vsps = &vh264->pps.sps;
+
+ struct pipe_h264_picture_desc *h264 = (struct pipe_h264_picture_desc *)desc;
+ struct pipe_h264_pps *pps = h264->pps;
+ struct pipe_h264_sps *sps = h264->pps->sps;
+
+ fill_base_picture_desc(desc, &vh264->base);
+
+ ITEM_SET(vsps, sps, level_idc);
+ ITEM_SET(vsps, sps, chroma_format_idc);
+ ITEM_SET(vsps, sps, separate_colour_plane_flag);
+ ITEM_SET(vsps, sps, bit_depth_luma_minus8);
+ ITEM_SET(vsps, sps, bit_depth_chroma_minus8);
+ ITEM_SET(vsps, sps, seq_scaling_matrix_present_flag);
+ ITEM_CPY(vsps, sps, ScalingList4x4);
+ ITEM_CPY(vsps, sps, ScalingList8x8);
+ ITEM_SET(vsps, sps, log2_max_frame_num_minus4);
+ ITEM_SET(vsps, sps, pic_order_cnt_type);
+ ITEM_SET(vsps, sps, log2_max_pic_order_cnt_lsb_minus4);
+ ITEM_SET(vsps, sps, delta_pic_order_always_zero_flag);
+ ITEM_SET(vsps, sps, offset_for_non_ref_pic);
+ ITEM_SET(vsps, sps, offset_for_top_to_bottom_field);
+ ITEM_CPY(vsps, sps, offset_for_ref_frame);
+ ITEM_SET(vsps, sps, num_ref_frames_in_pic_order_cnt_cycle);
+ ITEM_SET(vsps, sps, max_num_ref_frames);
+ ITEM_SET(vsps, sps, frame_mbs_only_flag);
+ ITEM_SET(vsps, sps, mb_adaptive_frame_field_flag);
+ ITEM_SET(vsps, sps, direct_8x8_inference_flag);
+ ITEM_SET(vsps, sps, MinLumaBiPredSize8x8);
+
+ ITEM_SET(vpps, pps, entropy_coding_mode_flag);
+ ITEM_SET(vpps, pps, bottom_field_pic_order_in_frame_present_flag);
+ ITEM_SET(vpps, pps, num_slice_groups_minus1);
+ ITEM_SET(vpps, pps, slice_group_map_type);
+ ITEM_SET(vpps, pps, slice_group_change_rate_minus1);
+ ITEM_SET(vpps, pps, num_ref_idx_l0_default_active_minus1);
+ ITEM_SET(vpps, pps, num_ref_idx_l1_default_active_minus1);
+ ITEM_SET(vpps, pps, weighted_pred_flag);
+ ITEM_SET(vpps, pps, weighted_bipred_idc);
+ ITEM_SET(vpps, pps, pic_init_qp_minus26);
+ ITEM_SET(vpps, pps, pic_init_qs_minus26);
+ ITEM_SET(vpps, pps, chroma_qp_index_offset);
+ ITEM_SET(vpps, pps, deblocking_filter_control_present_flag);
+ ITEM_SET(vpps, pps, constrained_intra_pred_flag);
+ ITEM_SET(vpps, pps, redundant_pic_cnt_present_flag);
+ ITEM_CPY(vpps, pps, ScalingList4x4);
+ ITEM_CPY(vpps, pps, ScalingList8x8);
+ ITEM_SET(vpps, pps, transform_8x8_mode_flag);
+ ITEM_SET(vpps, pps, second_chroma_qp_index_offset);
+
+ ITEM_SET(vh264, h264, frame_num);
+ ITEM_SET(vh264, h264, field_pic_flag);
+ ITEM_SET(vh264, h264, bottom_field_flag);
+ ITEM_SET(vh264, h264, num_ref_idx_l0_active_minus1);
+ ITEM_SET(vh264, h264, num_ref_idx_l1_active_minus1);
+ ITEM_SET(vh264, h264, slice_count);
+ ITEM_CPY(vh264, h264, field_order_cnt);
+ ITEM_SET(vh264, h264, is_reference);
+ ITEM_SET(vh264, h264, num_ref_frames);
+ ITEM_CPY(vh264, h264, field_order_cnt_list);
+ ITEM_CPY(vh264, h264, frame_num_list);
+
+ for (i = 0; i < 16; i++) {
+ ITEM_SET(vh264, h264, is_long_term[i]);
+ ITEM_SET(vh264, h264, top_is_reference[i]);
+ ITEM_SET(vh264, h264, bottom_is_reference[i]);
+
+ vbuf = virgl_video_buffer(h264->ref[i]);
+ vh264->buffer_id[i] = vbuf ? vbuf->handle : 0;
+ }
+
+ return 0;
+}
+
+static int fill_h265_picture_desc(const struct pipe_picture_desc *desc,
+ union virgl_picture_desc *vdsc)
+{
+ unsigned i;
+ struct virgl_video_buffer *vbuf;
+
+ struct virgl_h265_picture_desc *vh265 = &vdsc->h265;
+ struct pipe_h265_picture_desc *h265 = (struct pipe_h265_picture_desc *)desc;
+
+ fill_base_picture_desc(desc, &vh265->base);
+
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, chroma_format_idc);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, separate_colour_plane_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, pic_width_in_luma_samples);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, pic_height_in_luma_samples);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, bit_depth_luma_minus8);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, bit_depth_chroma_minus8);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_max_pic_order_cnt_lsb_minus4);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, sps_max_dec_pic_buffering_minus1);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_min_luma_coding_block_size_minus3);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_diff_max_min_luma_coding_block_size);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_min_transform_block_size_minus2);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_diff_max_min_transform_block_size);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, max_transform_hierarchy_depth_inter);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, max_transform_hierarchy_depth_intra);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, scaling_list_enabled_flag);
+ ITEM_CPY(&vh265->pps.sps, h265->pps->sps, ScalingList4x4);
+ ITEM_CPY(&vh265->pps.sps, h265->pps->sps, ScalingList8x8);
+ ITEM_CPY(&vh265->pps.sps, h265->pps->sps, ScalingList16x16);
+ ITEM_CPY(&vh265->pps.sps, h265->pps->sps, ScalingList32x32);
+ ITEM_CPY(&vh265->pps.sps, h265->pps->sps, ScalingListDCCoeff16x16);
+ ITEM_CPY(&vh265->pps.sps, h265->pps->sps, ScalingListDCCoeff32x32);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, amp_enabled_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, sample_adaptive_offset_enabled_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, pcm_enabled_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, pcm_sample_bit_depth_luma_minus1);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, pcm_sample_bit_depth_chroma_minus1);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_min_pcm_luma_coding_block_size_minus3);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, log2_diff_max_min_pcm_luma_coding_block_size);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, pcm_loop_filter_disabled_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, num_short_term_ref_pic_sets);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, long_term_ref_pics_present_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, num_long_term_ref_pics_sps);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, sps_temporal_mvp_enabled_flag);
+ ITEM_SET(&vh265->pps.sps, h265->pps->sps, strong_intra_smoothing_enabled_flag);
+
+ ITEM_SET(&vh265->pps, h265->pps, dependent_slice_segments_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, output_flag_present_flag);
+ ITEM_SET(&vh265->pps, h265->pps, num_extra_slice_header_bits);
+ ITEM_SET(&vh265->pps, h265->pps, sign_data_hiding_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, cabac_init_present_flag);
+ ITEM_SET(&vh265->pps, h265->pps, num_ref_idx_l0_default_active_minus1);
+ ITEM_SET(&vh265->pps, h265->pps, num_ref_idx_l1_default_active_minus1);
+ ITEM_SET(&vh265->pps, h265->pps, init_qp_minus26);
+ ITEM_SET(&vh265->pps, h265->pps, constrained_intra_pred_flag);
+ ITEM_SET(&vh265->pps, h265->pps, transform_skip_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, cu_qp_delta_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, diff_cu_qp_delta_depth);
+ ITEM_SET(&vh265->pps, h265->pps, pps_cb_qp_offset);
+ ITEM_SET(&vh265->pps, h265->pps, pps_cr_qp_offset);
+ ITEM_SET(&vh265->pps, h265->pps, pps_slice_chroma_qp_offsets_present_flag);
+ ITEM_SET(&vh265->pps, h265->pps, weighted_pred_flag);
+ ITEM_SET(&vh265->pps, h265->pps, weighted_bipred_flag);
+ ITEM_SET(&vh265->pps, h265->pps, transquant_bypass_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, tiles_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, entropy_coding_sync_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, num_tile_columns_minus1);
+ ITEM_SET(&vh265->pps, h265->pps, num_tile_rows_minus1);
+ ITEM_SET(&vh265->pps, h265->pps, uniform_spacing_flag);
+ ITEM_CPY(&vh265->pps, h265->pps, column_width_minus1);
+ ITEM_CPY(&vh265->pps, h265->pps, row_height_minus1);
+ ITEM_SET(&vh265->pps, h265->pps, loop_filter_across_tiles_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, pps_loop_filter_across_slices_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, deblocking_filter_control_present_flag);
+ ITEM_SET(&vh265->pps, h265->pps, deblocking_filter_override_enabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, pps_deblocking_filter_disabled_flag);
+ ITEM_SET(&vh265->pps, h265->pps, pps_beta_offset_div2);
+ ITEM_SET(&vh265->pps, h265->pps, pps_tc_offset_div2);
+ ITEM_SET(&vh265->pps, h265->pps, lists_modification_present_flag);
+ ITEM_SET(&vh265->pps, h265->pps, log2_parallel_merge_level_minus2);
+ ITEM_SET(&vh265->pps, h265->pps, slice_segment_header_extension_present_flag);
+ ITEM_SET(&vh265->pps, h265->pps, st_rps_bits);
+
+ ITEM_SET(vh265, h265, IDRPicFlag);
+ ITEM_SET(vh265, h265, RAPPicFlag);
+ ITEM_SET(vh265, h265, CurrRpsIdx);
+ ITEM_SET(vh265, h265, NumPocTotalCurr);
+ ITEM_SET(vh265, h265, NumDeltaPocsOfRefRpsIdx);
+ ITEM_SET(vh265, h265, NumShortTermPictureSliceHeaderBits);
+ ITEM_SET(vh265, h265, NumLongTermPictureSliceHeaderBits);
+
+ ITEM_SET(vh265, h265, CurrPicOrderCntVal);
+ for (i = 0; i < 16; i++) {
+ vbuf = virgl_video_buffer(h265->ref[i]);
+ vh265->ref[i] = vbuf ? vbuf->handle : 0;
+ }
+ ITEM_CPY(vh265, h265, PicOrderCntVal);
+ ITEM_CPY(vh265, h265, IsLongTerm);
+ ITEM_SET(vh265, h265, NumPocStCurrBefore);
+ ITEM_SET(vh265, h265, NumPocStCurrAfter);
+ ITEM_SET(vh265, h265, NumPocLtCurr);
+ ITEM_CPY(vh265, h265, RefPicSetStCurrBefore);
+ ITEM_CPY(vh265, h265, RefPicSetStCurrAfter);
+ ITEM_CPY(vh265, h265, RefPicSetLtCurr);
+ ITEM_CPY(vh265, h265, RefPicList);
+ ITEM_SET(vh265, h265, UseRefPicList);
+ ITEM_SET(vh265, h265, UseStRpsBits);
+
+ return 0;
+}
+
+static int fill_mpeg4_picture_desc(const struct pipe_picture_desc *desc,
+ union virgl_picture_desc *vdsc)
+{
+ unsigned i;
+ struct virgl_video_buffer *vbuf;
+ struct virgl_mpeg4_picture_desc *vmpeg4 = &vdsc->mpeg4;
+ struct pipe_mpeg4_picture_desc *mpeg4 = (struct pipe_mpeg4_picture_desc *)desc;
+
+ fill_base_picture_desc(desc, &vmpeg4->base);
+
+ ITEM_CPY(vmpeg4, mpeg4, trd);
+ ITEM_CPY(vmpeg4, mpeg4, trb);
+ ITEM_SET(vmpeg4, mpeg4, vop_time_increment_resolution);
+ ITEM_SET(vmpeg4, mpeg4, vop_coding_type);
+ ITEM_SET(vmpeg4, mpeg4, vop_fcode_forward);
+ ITEM_SET(vmpeg4, mpeg4, vop_fcode_backward);
+ ITEM_SET(vmpeg4, mpeg4, resync_marker_disable);
+ ITEM_SET(vmpeg4, mpeg4, interlaced);
+ ITEM_SET(vmpeg4, mpeg4, quant_type);
+ ITEM_SET(vmpeg4, mpeg4, quarter_sample);
+ ITEM_SET(vmpeg4, mpeg4, short_video_header);
+ ITEM_SET(vmpeg4, mpeg4, rounding_control);
+ ITEM_SET(vmpeg4, mpeg4, alternate_vertical_scan_flag);
+ ITEM_SET(vmpeg4, mpeg4, top_field_first);
+ ITEM_CPY(vmpeg4, mpeg4, intra_matrix);
+ ITEM_CPY(vmpeg4, mpeg4, non_intra_matrix);
+ for (i = 0; i < 16; i++) {
+ vbuf = virgl_video_buffer(mpeg4->ref[i]);
+ vmpeg4->ref[i] = vbuf ? vbuf->handle : 0;
+ }
+
+ return 0;
+}
+
+#undef ITEM_SET
+#undef ITEM_CPY
+
+static int fill_picture_desc(const struct pipe_picture_desc *desc,
+ union virgl_picture_desc *vdsc)
+{
+ switch (u_reduce_video_profile(desc->profile)) {
+ case PIPE_VIDEO_FORMAT_MPEG4:
+ return fill_mpeg4_picture_desc(desc, vdsc);
+ case PIPE_VIDEO_FORMAT_MPEG4_AVC:
+ return fill_h264_picture_desc(desc, vdsc);
+ case PIPE_VIDEO_FORMAT_HEVC:
+ return fill_h265_picture_desc(desc, vdsc);
+ default:
+ return -1;
+ }
+}
+
+static void virgl_video_begin_frame(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *target,
+ struct pipe_picture_desc *picture)
+{
+ struct virgl_video_codec *vcdc = virgl_video_codec(codec);
+ struct virgl_video_buffer *vbuf = virgl_video_buffer(target);
+
+ virgl_encode_begin_frame(vcdc->vctx, vcdc, vbuf);
+}
+
+static void virgl_video_decode_macroblock(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *target,
+ struct pipe_picture_desc *picture,
+ const struct pipe_macroblock *macroblocks,
+ unsigned num_macroblocks)
+{
+ (void)codec;
+ (void)target;
+ (void)picture;
+ (void)macroblocks;
+ (void)num_macroblocks;
+}
+
+static void virgl_video_decode_bitstream(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *target,
+ struct pipe_picture_desc *picture,
+ unsigned num_buffers,
+ const void * const *buffers,
+ const unsigned *sizes)
+{
+ struct virgl_video_codec *vcdc = virgl_video_codec(codec);
+ struct virgl_video_buffer *vbuf = virgl_video_buffer(target);
+ struct virgl_context *vctx = vcdc->vctx;
+ struct virgl_screen *vs = virgl_screen(vctx->base.screen);
+ struct virgl_resource *vres;
+ union virgl_picture_desc vdsc;
+ struct pipe_transfer *xfer = NULL;
+ void *ptr;
+ unsigned i, total_size;
+
+ /* transfer bitstream data */
+ for (i = 0, total_size = 0; i < num_buffers; i++)
+ total_size += sizes[i];
+
+ if (total_size > pipe_buffer_size(vcdc->bs_buffers[vcdc->cur_buffer])) {
+ pipe_resource_reference(&vcdc->bs_buffers[vcdc->cur_buffer], NULL);
+ vcdc->bs_buffers[vcdc->cur_buffer] = pipe_buffer_create(vctx->base.screen,
+ PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING, total_size);
+ }
+
+ vctx->base.flush(&vctx->base, NULL, 0);
+
+ vres = virgl_resource(vcdc->bs_buffers[vcdc->cur_buffer]);
+ vs->vws->resource_wait(vs->vws, vres->hw_res);
+ ptr = pipe_buffer_map(&vctx->base, vcdc->bs_buffers[vcdc->cur_buffer],
+ PIPE_MAP_WRITE, &xfer);
+ if (!ptr)
+ return;
+ for (i = 0, vcdc->bs_size = 0; i < num_buffers; i++) {
+ memcpy(ptr + vcdc->bs_size, buffers[i], sizes[i]);
+ vcdc->bs_size += sizes[i];
+ }
+ pipe_buffer_unmap(&vctx->base, xfer);
+
+ /* transfer picture description */
+ fill_picture_desc(picture, &vdsc);
+ vres = virgl_resource(vcdc->desc_buffers[vcdc->cur_buffer]);
+ vs->vws->resource_wait(vs->vws, vres->hw_res);
+ ptr = pipe_buffer_map(&vctx->base, vcdc->desc_buffers[vcdc->cur_buffer],
+ PIPE_MAP_WRITE, &xfer);
+ if (!ptr)
+ return;
+ memcpy(ptr, &vdsc, sizeof(vdsc));
+ pipe_buffer_unmap(&vctx->base, xfer);
+
+ virgl_encode_decode_bitstream(vctx, vcdc, vbuf, &vdsc, sizeof(vdsc));
+}
+
+static void virgl_video_end_frame(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *target,
+ struct pipe_picture_desc *picture)
+{
+ struct virgl_video_codec *vcdc = virgl_video_codec(codec);
+ struct virgl_context *vctx = virgl_context(vcdc->base.context);
+ struct virgl_video_buffer *vbuf = virgl_video_buffer(target);
+
+ virgl_encode_end_frame(vctx, vcdc, vbuf);
+ virgl_flush_eq(vctx, vctx, NULL);
+
+ switch_buffer(vcdc);
+}
+
+static void virgl_video_flush(struct pipe_video_codec *codec)
+{
+ (void)codec;
+}
+
+static void virgl_video_get_feedback(struct pipe_video_codec *codec,
+ void *feedback,
+ unsigned *size)
+{
+ (void)codec;
+ (void)feedback;
+ (void)size;
+}
+
+static void virgl_video_destroy_codec(struct pipe_video_codec *codec)
+{
+ unsigned i;
+ struct virgl_video_codec *vcdc = virgl_video_codec(codec);
+ struct virgl_context *vctx = virgl_context(vcdc->base.context);
+
+ for (i = 0; i < VIRGL_VIDEO_CODEC_BUF_NUM; i++) {
+ pipe_resource_reference(&vcdc->bs_buffers[i], NULL);
+ pipe_resource_reference(&vcdc->desc_buffers[i], NULL);
+ }
+
+ virgl_encode_destroy_video_codec(vctx, vcdc);
+
+ free(vcdc);
+}
+
+
+struct pipe_video_codec *
+virgl_video_create_codec(struct pipe_context *ctx,
+ const struct pipe_video_codec *templ)
+{
+ unsigned i;
+ struct virgl_video_codec *vcdc;
+ struct virgl_context *vctx = virgl_context(ctx);
+ unsigned width = templ->width, height = templ->height;
+
+ if (virgl_debug & VIRGL_DEBUG_VIDEO)
+ debug_printf("VIDEO: create codec. profile=%d, level=%u, entryp=%d, "
+ "chroma_fmt=%d, size=%ux%u, max_ref=%u, expect=%d\n",
+ templ->profile, templ->level, templ->entrypoint,
+ templ->chroma_format, templ->width, templ->height,
+ templ->max_references, templ->expect_chunked_decode);
+
+ /* encode: not supported now */
+ if (templ->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE)
+ return NULL;
+
+ /* decode: */
+ switch (u_reduce_video_profile(templ->profile)) {
+ case PIPE_VIDEO_FORMAT_MPEG4: /* fall through */
+ case PIPE_VIDEO_FORMAT_MPEG4_AVC:
+ width = align(width, VL_MACROBLOCK_WIDTH);
+ height = align(height, VL_MACROBLOCK_HEIGHT);
+ break;
+ case PIPE_VIDEO_FORMAT_HEVC: /* fall through */
+ default:
+ break;
+ }
+
+ vcdc = CALLOC_STRUCT(virgl_video_codec);
+ if (!vcdc)
+ return NULL;
+
+ vcdc->base = *templ;
+ vcdc->base.width = width;
+ vcdc->base.height = height;
+ vcdc->base.context = ctx;
+
+ vcdc->base.destroy = virgl_video_destroy_codec;
+ vcdc->base.begin_frame = virgl_video_begin_frame;
+ vcdc->base.decode_macroblock = virgl_video_decode_macroblock;
+ vcdc->base.decode_bitstream = virgl_video_decode_bitstream;
+ vcdc->base.end_frame = virgl_video_end_frame;
+ vcdc->base.flush = virgl_video_flush;
+ vcdc->base.get_feedback = virgl_video_get_feedback;
+
+ vcdc->bs_size = 0;
+ vcdc->cur_buffer = 0;
+ for (i = 0; i < VIRGL_VIDEO_CODEC_BUF_NUM; i++) {
+ vcdc->bs_buffers[i] = pipe_buffer_create(ctx->screen,
+ PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING,
+ BS_BUF_DEFAULT_SIZE(width, height));
+
+ vcdc->desc_buffers[i] = pipe_buffer_create(ctx->screen,
+ PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING,
+ sizeof(union virgl_picture_desc));
+ }
+
+ vcdc->handle = virgl_object_assign_handle();
+ vcdc->vctx = vctx;
+
+ virgl_encode_create_video_codec(vctx, vcdc);
+
+ return &vcdc->base;
+}
+
+
+static void virgl_video_destroy_buffer(struct pipe_video_buffer *buffer)
+{
+ struct virgl_video_buffer *vbuf = virgl_video_buffer(buffer);
+
+ virgl_encode_destroy_video_buffer(vbuf->vctx, vbuf);
+
+ vl_video_buffer_destroy(buffer);
+
+ free(vbuf);
+}
+
+static void virgl_video_destroy_buffer_associated_data(void *data)
+{
+ (void)data;
+}
+
+struct pipe_video_buffer *
+virgl_video_create_buffer(struct pipe_context *ctx,
+ const struct pipe_video_buffer *tmpl)
+{
+ struct virgl_context *vctx = virgl_context(ctx);
+ struct virgl_video_buffer *vbuf;
+
+ vbuf = CALLOC_STRUCT(virgl_video_buffer);
+ if (!vbuf)
+ return NULL;
+
+ vbuf->buf = vl_video_buffer_create(ctx, tmpl);
+ if (!vbuf->buf) {
+ free(vbuf);
+ return NULL;
+ }
+ vbuf->buf->destroy = virgl_video_destroy_buffer;
+ vl_video_buffer_set_associated_data(vbuf->buf,
+ NULL, vbuf, virgl_video_destroy_buffer_associated_data);
+
+ vbuf->num_planes = util_format_get_num_planes(vbuf->buf->buffer_format);
+ vbuf->plane_views = vbuf->buf->get_sampler_view_planes(vbuf->buf);
+ vbuf->handle = virgl_object_assign_handle();
+ vbuf->buffer_format = tmpl->buffer_format;
+ vbuf->width = tmpl->width;
+ vbuf->height = tmpl->height;
+ vbuf->vctx = vctx;
+
+ virgl_encode_create_video_buffer(vctx, vbuf);
+
+ if (virgl_debug & VIRGL_DEBUG_VIDEO) {
+ debug_printf("VIDEO: create buffer. fmt=%s, %ux%u, num_planes=%u\n",
+ util_format_name(tmpl->buffer_format),
+ tmpl->width, tmpl->height, vbuf->num_planes);
+
+ for (unsigned i = 0; i < vbuf->num_planes; i++)
+ if (vbuf->plane_views[i])
+ debug_printf("VIDEO: plane[%d]: fmt=%s, target=%u\n", i,
+ util_format_name(vbuf->plane_views[i]->format),
+ vbuf->plane_views[i]->target);
+ }
+
+ return vbuf->buf;
+}
+
--- /dev/null
+/*
+ * Copyright 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef VIRGL_VIDEO_H
+#define VIRGL_VIDEO_H
+
+/*
+ * This file contains parts of the HW ABI, such as union virgl_picture_desc
+ * and other related structures.
+ */
+
+#include "virgl_context.h"
+#include "vl/vl_video_buffer.h"
+#include "pipe/p_video_codec.h"
+
+#define VIRGL_VIDEO_CODEC_BUF_NUM 10
+
+struct virgl_video_codec {
+ struct pipe_video_codec base; /* must be first */
+
+ uint32_t handle;
+ struct virgl_context *vctx;
+
+ uint32_t bs_size; /* size of data in bs_buffer */
+ uint32_t cur_buffer; /* index of current bs/desc buffer */
+ struct pipe_resource *bs_buffers[VIRGL_VIDEO_CODEC_BUF_NUM];
+ struct pipe_resource *desc_buffers[VIRGL_VIDEO_CODEC_BUF_NUM];
+};
+
+struct virgl_video_buffer {
+ uint32_t handle;
+ enum pipe_format buffer_format;
+ unsigned width;
+ unsigned height;
+ struct virgl_context *vctx;
+ struct pipe_video_buffer *buf;
+ unsigned num_planes;
+ struct pipe_sampler_view **plane_views;
+};
+
+struct virgl_base_picture_desc {
+ uint16_t profile; /* enum pipe_video_profile */
+ uint8_t entry_point; /* enum pipe_video_entrypoint */
+ uint8_t protected_playback;
+ uint8_t decrypt_key[256];
+ uint32_t key_size;
+
+};
+
+/* H.264 sequence parameter set */
+struct virgl_h264_sps {
+ uint8_t level_idc;
+ uint8_t chroma_format_idc;
+ uint8_t separate_colour_plane_flag;
+ uint8_t bit_depth_luma_minus8;
+
+ uint8_t bit_depth_chroma_minus8;
+ uint8_t seq_scaling_matrix_present_flag;
+ uint8_t ScalingList4x4[6][16];
+ uint8_t ScalingList8x8[6][64];
+
+ uint8_t log2_max_frame_num_minus4;
+ uint8_t pic_order_cnt_type;
+ uint8_t log2_max_pic_order_cnt_lsb_minus4;
+ uint8_t delta_pic_order_always_zero_flag;
+
+ int32_t offset_for_non_ref_pic;
+ int32_t offset_for_top_to_bottom_field;
+ int32_t offset_for_ref_frame[256];
+
+ uint8_t num_ref_frames_in_pic_order_cnt_cycle;
+ uint8_t max_num_ref_frames;
+ uint8_t frame_mbs_only_flag;
+ uint8_t mb_adaptive_frame_field_flag;
+
+ uint8_t direct_8x8_inference_flag;
+ uint8_t MinLumaBiPredSize8x8;
+ uint8_t reserved[2];
+};
+
+/* H.264 picture parameter set */
+struct virgl_h264_pps {
+ struct virgl_h264_sps sps; /* Seq Param Set */
+
+ uint8_t entropy_coding_mode_flag;
+ uint8_t bottom_field_pic_order_in_frame_present_flag;
+ uint8_t num_slice_groups_minus1;
+ uint8_t slice_group_map_type;
+
+ uint8_t slice_group_change_rate_minus1;
+ uint8_t num_ref_idx_l0_default_active_minus1;
+ uint8_t num_ref_idx_l1_default_active_minus1;
+ uint8_t weighted_pred_flag;
+
+ uint8_t weighted_bipred_idc;
+ int8_t pic_init_qp_minus26;
+ int8_t pic_init_qs_minus26;
+ int8_t chroma_qp_index_offset;
+
+ uint8_t deblocking_filter_control_present_flag;
+ uint8_t constrained_intra_pred_flag;
+ uint8_t redundant_pic_cnt_present_flag;
+ uint8_t transform_8x8_mode_flag;
+
+ uint8_t ScalingList4x4[6][16];
+ uint8_t ScalingList8x8[6][64];
+
+ int8_t second_chroma_qp_index_offset;
+ uint8_t reserved[3];
+};
+
+struct virgl_h264_picture_desc {
+ struct virgl_base_picture_desc base;
+
+ struct virgl_h264_pps pps; /* Picture Param Set */
+
+ uint32_t frame_num;
+
+ uint8_t field_pic_flag;
+ uint8_t bottom_field_flag;
+ uint8_t num_ref_idx_l0_active_minus1;
+ uint8_t num_ref_idx_l1_active_minus1;
+
+ uint32_t slice_count;
+ int32_t field_order_cnt[2];
+
+ uint8_t is_long_term[16];
+ uint8_t top_is_reference[16];
+ uint8_t bottom_is_reference[16];
+ uint32_t field_order_cnt_list[16][2];
+ uint32_t frame_num_list[16];
+ uint32_t buffer_id[16];
+
+ uint8_t is_reference;
+ uint8_t num_ref_frames;
+ uint8_t reserved[2];
+};
+
+struct virgl_h265_sps
+{
+ uint32_t pic_width_in_luma_samples;
+ uint32_t pic_height_in_luma_samples;
+
+ uint8_t chroma_format_idc;
+ uint8_t separate_colour_plane_flag;
+ uint8_t bit_depth_luma_minus8;
+ uint8_t bit_depth_chroma_minus8;
+
+ uint8_t log2_max_pic_order_cnt_lsb_minus4;
+ uint8_t sps_max_dec_pic_buffering_minus1;
+ uint8_t log2_min_luma_coding_block_size_minus3;
+ uint8_t log2_diff_max_min_luma_coding_block_size;
+
+ uint8_t log2_min_transform_block_size_minus2;
+ uint8_t log2_diff_max_min_transform_block_size;
+ uint8_t max_transform_hierarchy_depth_inter;
+ uint8_t max_transform_hierarchy_depth_intra;
+
+ uint8_t ScalingList4x4[6][16];
+ uint8_t ScalingList8x8[6][64];
+ uint8_t ScalingList16x16[6][64];
+ uint8_t ScalingList32x32[2][64];
+
+ uint8_t ScalingListDCCoeff16x16[6];
+ uint8_t ScalingListDCCoeff32x32[2];
+
+ uint8_t scaling_list_enabled_flag;
+ uint8_t amp_enabled_flag;
+ uint8_t sample_adaptive_offset_enabled_flag;
+ uint8_t pcm_enabled_flag;
+
+ uint8_t pcm_sample_bit_depth_luma_minus1;
+ uint8_t pcm_sample_bit_depth_chroma_minus1;
+ uint8_t log2_min_pcm_luma_coding_block_size_minus3;
+ uint8_t log2_diff_max_min_pcm_luma_coding_block_size;
+
+ uint8_t pcm_loop_filter_disabled_flag;
+ uint8_t num_short_term_ref_pic_sets;
+ uint8_t long_term_ref_pics_present_flag;
+ uint8_t num_long_term_ref_pics_sps;
+
+ uint8_t sps_temporal_mvp_enabled_flag;
+ uint8_t strong_intra_smoothing_enabled_flag;
+ uint8_t reserved[2];
+};
+
+struct virgl_h265_pps
+{
+ struct virgl_h265_sps sps;
+
+ uint8_t dependent_slice_segments_enabled_flag;
+ uint8_t output_flag_present_flag;
+ uint8_t num_extra_slice_header_bits;
+ uint8_t sign_data_hiding_enabled_flag;
+
+ uint8_t cabac_init_present_flag;
+ uint8_t num_ref_idx_l0_default_active_minus1;
+ uint8_t num_ref_idx_l1_default_active_minus1;
+ int8_t init_qp_minus26;
+
+ uint8_t constrained_intra_pred_flag;
+ uint8_t transform_skip_enabled_flag;
+ uint8_t cu_qp_delta_enabled_flag;
+ uint8_t diff_cu_qp_delta_depth;
+
+ int8_t pps_cb_qp_offset;
+ int8_t pps_cr_qp_offset;
+ uint8_t pps_slice_chroma_qp_offsets_present_flag;
+ uint8_t weighted_pred_flag;
+
+ uint8_t weighted_bipred_flag;
+ uint8_t transquant_bypass_enabled_flag;
+ uint8_t tiles_enabled_flag;
+ uint8_t entropy_coding_sync_enabled_flag;
+
+ uint16_t column_width_minus1[20];
+ uint16_t row_height_minus1[22];
+
+ uint8_t num_tile_columns_minus1;
+ uint8_t num_tile_rows_minus1;
+ uint8_t uniform_spacing_flag;
+ uint8_t loop_filter_across_tiles_enabled_flag;
+
+ uint8_t pps_loop_filter_across_slices_enabled_flag;
+ uint8_t deblocking_filter_control_present_flag;
+ uint8_t deblocking_filter_override_enabled_flag;
+ uint8_t pps_deblocking_filter_disabled_flag;
+
+ int8_t pps_beta_offset_div2;
+ int8_t pps_tc_offset_div2;
+ uint8_t lists_modification_present_flag;
+ uint8_t log2_parallel_merge_level_minus2;
+
+ uint16_t st_rps_bits;
+ uint8_t slice_segment_header_extension_present_flag;
+ uint8_t reserved;
+};
+
+struct virgl_h265_picture_desc
+{
+ struct virgl_base_picture_desc base;
+
+ struct virgl_h265_pps pps;
+
+ int32_t CurrPicOrderCntVal;
+ uint32_t ref[16];
+ int32_t PicOrderCntVal[16];
+
+ uint32_t NumPocTotalCurr;
+ uint32_t NumDeltaPocsOfRefRpsIdx;
+ uint32_t NumShortTermPictureSliceHeaderBits;
+ uint32_t NumLongTermPictureSliceHeaderBits;
+
+ uint8_t IsLongTerm[16];
+
+ uint8_t IDRPicFlag;
+ uint8_t RAPPicFlag;
+ uint8_t CurrRpsIdx;
+ uint8_t NumPocStCurrBefore;
+
+ uint8_t NumPocStCurrAfter;
+ uint8_t NumPocLtCurr;
+ uint8_t UseRefPicList;
+ uint8_t UseStRpsBits;
+
+ uint8_t RefPicSetStCurrBefore[8];
+ uint8_t RefPicSetStCurrAfter[8];
+ uint8_t RefPicSetLtCurr[8];
+
+ uint8_t RefPicList[2][15];
+ uint8_t reserved[2];
+};
+
+struct virgl_mpeg4_picture_desc
+{
+ struct virgl_base_picture_desc base;
+
+ int32_t trd[2];
+ int32_t trb[2];
+ uint16_t vop_time_increment_resolution;
+ uint8_t vop_coding_type;
+ uint8_t vop_fcode_forward;
+ uint8_t vop_fcode_backward;
+ uint8_t resync_marker_disable;
+ uint8_t interlaced;
+ uint8_t quant_type;
+ uint8_t quarter_sample;
+ uint8_t short_video_header;
+ uint8_t rounding_control;
+ uint8_t alternate_vertical_scan_flag;
+ uint8_t top_field_first;
+
+ uint8_t intra_matrix[64];
+ uint8_t non_intra_matrix[64];
+
+ uint32_t ref[2];
+};
+
+union virgl_picture_desc {
+ struct virgl_base_picture_desc base;
+ struct virgl_h264_picture_desc h264;
+ struct virgl_h265_picture_desc h265;
+ struct virgl_mpeg4_picture_desc mpeg4;
+};
+
+static inline struct virgl_video_codec *
+virgl_video_codec(struct pipe_video_codec *codec)
+{
+ return (struct virgl_video_codec *)codec;
+}
+
+static inline struct virgl_video_buffer *
+virgl_video_buffer(struct pipe_video_buffer *buffer)
+{
+ return buffer ? vl_video_buffer_get_associated_data(buffer, NULL) : NULL;
+}
+
+struct pipe_video_codec *
+virgl_video_create_codec(struct pipe_context *ctx,
+ const struct pipe_video_codec *templ);
+
+struct pipe_video_buffer *
+virgl_video_create_buffer(struct pipe_context *ctx,
+ const struct pipe_video_buffer *tmpl);
+
+#endif /* VIRGL_VIDEO_H */
+