diff --git a/src/gallium/drivers/virgl/meson.build b/src/gallium/drivers/virgl/meson.build index b3adb120719..0bb26c67c7c 100644 --- a/src/gallium/drivers/virgl/meson.build +++ b/src/gallium/drivers/virgl/meson.build @@ -30,6 +30,7 @@ files_libvirgl = files( 'virgl_transfer_queue.c', 'virgl_texture.c', 'virgl_tgsi.c', + 'virgl_video.c', ) libvirgl = static_library( diff --git a/src/gallium/drivers/virgl/virgl_context.c b/src/gallium/drivers/virgl/virgl_context.c index 771c204d65a..ad1ed8756c9 100644 --- a/src/gallium/drivers/virgl/virgl_context.c +++ b/src/gallium/drivers/virgl/virgl_context.c @@ -49,6 +49,7 @@ #include "virgl_resource.h" #include "virgl_screen.h" #include "virgl_staging_mgr.h" +#include "virgl_video.h" struct virgl_vertex_elements_state { uint32_t handle; @@ -859,6 +860,17 @@ static void virgl_clear(struct pipe_context *ctx, virgl_encode_clear(vctx, buffers, color, depth, stencil); } +static void virgl_clear_render_target(struct pipe_context *ctx, + struct pipe_surface *dst, + const union pipe_color_union *color, + unsigned dstx, unsigned dsty, + unsigned width, unsigned height, + bool render_condition_enabled) +{ + if (virgl_debug & VIRGL_DEBUG_VERBOSE) + debug_printf("VIRGL: clear render target unsupported.\n"); +} + static void virgl_clear_texture(struct pipe_context *ctx, struct pipe_resource *res, unsigned int level, @@ -1624,6 +1636,7 @@ struct pipe_context *virgl_context_create(struct pipe_screen *pscreen, vctx->base.launch_grid = virgl_launch_grid; vctx->base.clear = virgl_clear; + vctx->base.clear_render_target = virgl_clear_render_target; vctx->base.clear_texture = virgl_clear_texture; vctx->base.draw_vbo = virgl_draw_vbo; vctx->base.flush = virgl_flush_from_st; @@ -1660,6 +1673,9 @@ struct pipe_context *virgl_context_create(struct pipe_screen *pscreen, vctx->base.memory_barrier = virgl_memory_barrier; vctx->base.emit_string_marker = virgl_emit_string_marker; + vctx->base.create_video_codec = virgl_video_create_codec; + vctx->base.create_video_buffer = virgl_video_create_buffer; + if (rs->caps.caps.v2.host_feature_check_version >= 7) vctx->base.link_shader = virgl_link_shader; diff --git a/src/gallium/drivers/virgl/virgl_encode.c b/src/gallium/drivers/virgl/virgl_encode.c index b09bce5cc72..3a3e212e6bb 100644 --- a/src/gallium/drivers/virgl/virgl_encode.c +++ b/src/gallium/drivers/virgl/virgl_encode.c @@ -36,6 +36,7 @@ #include "virtio-gpu/virgl_protocol.h" #include "virgl_resource.h" #include "virgl_screen.h" +#include "virgl_video.h" #define VIRGL_ENCODE_MAX_DWORDS MIN2(VIRGL_MAX_CMDBUF_DWORDS, VIRGL_CMD0_MAX_DWORDS) @@ -308,6 +309,18 @@ enum virgl_formats pipe_to_virgl_format(enum pipe_format format) return vformat; } +enum pipe_format virgl_to_pipe_format(enum virgl_formats format) +{ + enum pipe_format pformat; + + for (pformat = PIPE_FORMAT_NONE; pformat < PIPE_FORMAT_COUNT; pformat++) + if (virgl_formats_conv_table[pformat] == format) + return pformat; + + debug_printf("VIRGL: virgl format %u not in the format table\n", format); + return PIPE_FORMAT_NONE; +} + static int virgl_encoder_write_cmd_dword(struct virgl_context *ctx, uint32_t dword) { @@ -1613,3 +1626,76 @@ void virgl_encode_emit_string_marker(struct virgl_context *ctx, virgl_encoder_write_dword(ctx->cbuf, len); virgl_encoder_write_block(ctx->cbuf, (const uint8_t *)message, len); } + +void virgl_encode_create_video_codec(struct virgl_context *ctx, + struct virgl_video_codec *cdc) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_CREATE_VIDEO_CODEC, 0, 7)); + virgl_encoder_write_dword(ctx->cbuf, cdc->handle); + virgl_encoder_write_dword(ctx->cbuf, cdc->base.profile); + virgl_encoder_write_dword(ctx->cbuf, cdc->base.entrypoint); + virgl_encoder_write_dword(ctx->cbuf, cdc->base.chroma_format); + virgl_encoder_write_dword(ctx->cbuf, cdc->base.level); + virgl_encoder_write_dword(ctx->cbuf, cdc->base.width); + virgl_encoder_write_dword(ctx->cbuf, cdc->base.height); +} + +void virgl_encode_destroy_video_codec(struct virgl_context *ctx, + struct virgl_video_codec *cdc) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_DESTROY_VIDEO_CODEC, 0, 1)); + virgl_encoder_write_dword(ctx->cbuf, cdc->handle); +} + +void virgl_encode_create_video_buffer(struct virgl_context *ctx, + struct virgl_video_buffer *vbuf) +{ + unsigned i; + + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_CREATE_VIDEO_BUFFER, 0, + 4 + vbuf->num_planes)); + virgl_encoder_write_dword(ctx->cbuf, vbuf->handle); + virgl_encoder_write_dword(ctx->cbuf, pipe_to_virgl_format(vbuf->buf->buffer_format)); + virgl_encoder_write_dword(ctx->cbuf, vbuf->buf->width); + virgl_encoder_write_dword(ctx->cbuf, vbuf->buf->height); + for (i = 0; i < vbuf->num_planes; i++) + virgl_encoder_write_res(ctx, virgl_resource(vbuf->plane_views[i]->texture)); +} + +void virgl_encode_destroy_video_buffer(struct virgl_context *ctx, + struct virgl_video_buffer *buf) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_DESTROY_VIDEO_BUFFER, 0, 1)); + virgl_encoder_write_dword(ctx->cbuf, buf->handle); +} + +void virgl_encode_begin_frame(struct virgl_context *ctx, + struct virgl_video_codec *cdc, + struct virgl_video_buffer *buf) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_BEGIN_FRAME, 0, 2)); + virgl_encoder_write_dword(ctx->cbuf, cdc->handle); + virgl_encoder_write_dword(ctx->cbuf, buf->handle); +} + +void virgl_encode_decode_bitstream(struct virgl_context *ctx, + struct virgl_video_codec *cdc, + struct virgl_video_buffer *buf, + void *desc, uint32_t desc_size) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_DECODE_BITSTREAM, 0, 5)); + virgl_encoder_write_dword(ctx->cbuf, cdc->handle); + virgl_encoder_write_dword(ctx->cbuf, buf->handle); + virgl_encoder_write_res(ctx, virgl_resource(cdc->desc_buffers[cdc->cur_buffer])); + virgl_encoder_write_res(ctx, virgl_resource(cdc->bs_buffers[cdc->cur_buffer])); + virgl_encoder_write_dword(ctx->cbuf, cdc->bs_size); +} + +void virgl_encode_end_frame(struct virgl_context *ctx, + struct virgl_video_codec *cdc, + struct virgl_video_buffer *buf) +{ + virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_END_FRAME, 0, 2)); + virgl_encoder_write_dword(ctx->cbuf, cdc->handle); + virgl_encoder_write_dword(ctx->cbuf, buf->handle); +} diff --git a/src/gallium/drivers/virgl/virgl_encode.h b/src/gallium/drivers/virgl/virgl_encode.h index dd116900599..90fe8d1ffe5 100644 --- a/src/gallium/drivers/virgl/virgl_encode.h +++ b/src/gallium/drivers/virgl/virgl_encode.h @@ -36,6 +36,8 @@ struct virgl_resource; struct virgl_screen; struct virgl_transfer; struct virgl_sampler_view; +struct virgl_video_codec; +struct virgl_video_buffer; struct virgl_surface { struct pipe_surface base; @@ -317,5 +319,31 @@ void virgl_encode_get_memory_info(struct virgl_context *ctx, struct virgl_resour void virgl_encode_emit_string_marker(struct virgl_context *ctx, const char *message, int len); +void virgl_encode_create_video_codec(struct virgl_context *ctx, + struct virgl_video_codec *cdc); + +void virgl_encode_destroy_video_codec(struct virgl_context *ctx, + struct virgl_video_codec *cdc); + +void virgl_encode_create_video_buffer(struct virgl_context *ctx, + struct virgl_video_buffer *buf); + +void virgl_encode_destroy_video_buffer(struct virgl_context *ctx, + struct virgl_video_buffer *buf); + +void virgl_encode_begin_frame(struct virgl_context *ctx, + struct virgl_video_codec *cdc, + struct virgl_video_buffer *buf); + +void virgl_encode_decode_bitstream(struct virgl_context *ctx, + struct virgl_video_codec *cdc, + struct virgl_video_buffer *buf, + void *desc, uint32_t desc_size); + +void virgl_encode_end_frame(struct virgl_context *ctx, + struct virgl_video_codec *cdc, + struct virgl_video_buffer *buf); + enum virgl_formats pipe_to_virgl_format(enum pipe_format format); +enum pipe_format virgl_to_pipe_format(enum virgl_formats format); #endif diff --git a/src/gallium/drivers/virgl/virgl_screen.c b/src/gallium/drivers/virgl/virgl_screen.c index 63026cc7b39..6e8058018f3 100644 --- a/src/gallium/drivers/virgl/virgl_screen.c +++ b/src/gallium/drivers/virgl/virgl_screen.c @@ -32,6 +32,8 @@ #include "pipe/p_defines.h" #include "pipe/p_screen.h" #include "nir/nir_to_tgsi.h" +#include "vl/vl_decoder.h" +#include "vl/vl_video_buffer.h" #include "tgsi/tgsi_exec.h" @@ -53,6 +55,7 @@ static const struct debug_named_value virgl_debug_options[] = { { "xfer", VIRGL_DEBUG_XFER, "Do not optimize for transfers" }, { "r8srgb-readback", VIRGL_DEBUG_L8_SRGB_ENABLE_READBACK, "Enable redaback for L8 sRGB textures" }, { "nocoherent", VIRGL_DEBUG_NO_COHERENT, "Disable coherent memory"}, + { "video", VIRGL_DEBUG_VIDEO, "Video codec"}, DEBUG_NAMED_VALUE_END }; DEBUG_GET_ONCE_FLAGS_OPTION(virgl_debug, "VIRGL_DEBUG", virgl_debug_options, 0) @@ -457,6 +460,72 @@ virgl_get_shader_param(struct pipe_screen *screen, } } +static int +virgl_get_video_param(struct pipe_screen *screen, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint, + enum pipe_video_cap param) +{ + unsigned i; + struct virgl_video_caps *vcaps = NULL; + struct virgl_screen *vscreen; + + if (!screen) + return 0; + + vscreen = virgl_screen(screen); + if (vscreen->caps.caps.v2.num_video_caps > ARRAY_SIZE(vscreen->caps.caps.v2.video_caps)) + return 0; + + for (i = 0; i < vscreen->caps.caps.v2.num_video_caps; i++) { + if (vscreen->caps.caps.v2.video_caps[i].profile == profile && + vscreen->caps.caps.v2.video_caps[i].entrypoint == entrypoint) { + vcaps = &vscreen->caps.caps.v2.video_caps[i]; + break; + } + } + + /* + * Since there are calls like this: + * pot_buffers = !pipe->screen->get_video_param + * ( + * pipe->screen, + * PIPE_VIDEO_PROFILE_UNKNOWN, + * PIPE_VIDEO_ENTRYPOINT_UNKNOWN, + * PIPE_VIDEO_CAP_NPOT_TEXTURES + * ); + * All parameters need to check the vcaps. + */ + switch (param) { + case PIPE_VIDEO_CAP_SUPPORTED: + return vcaps != NULL; + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return vcaps ? vcaps->npot_texture : true; + case PIPE_VIDEO_CAP_MAX_WIDTH: + return vcaps ? vcaps->max_width : 0; + case PIPE_VIDEO_CAP_MAX_HEIGHT: + return vcaps ? vcaps->max_height : 0; + case PIPE_VIDEO_CAP_PREFERED_FORMAT: + return vcaps ? virgl_to_pipe_format(vcaps->prefered_format) : PIPE_FORMAT_NV12; + case PIPE_VIDEO_CAP_PREFERS_INTERLACED: + return vcaps ? vcaps->prefers_interlaced : false; + case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED: + return vcaps ? vcaps->supports_interlaced : false; + case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE: + return vcaps ? vcaps->supports_progressive : true; + case PIPE_VIDEO_CAP_MAX_LEVEL: + return vcaps ? vcaps->max_level : 0; + case PIPE_VIDEO_CAP_STACKED_FRAMES: + return vcaps ? vcaps->stacked_frames : 0; + case PIPE_VIDEO_CAP_MAX_MACROBLOCKS: + return vcaps ? vcaps->max_macroblocks : 0; + case PIPE_VIDEO_CAP_MAX_TEMPORAL_LAYERS: + return vcaps ? vcaps->max_temporal_layers : 0; + default: + return 0; + } +} + static float virgl_get_paramf(struct pipe_screen *screen, enum pipe_capf param) { @@ -804,6 +873,15 @@ virgl_is_format_supported( struct pipe_screen *screen, may_emulate_bgra); } +static bool virgl_is_video_format_supported(struct pipe_screen *screen, + enum pipe_format format, + enum pipe_video_profile profile, + enum pipe_video_entrypoint entrypoint) +{ + return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint); +} + + static void virgl_flush_frontbuffer(struct pipe_screen *screen, struct pipe_context *ctx, struct pipe_resource *res, @@ -1055,10 +1133,12 @@ virgl_create_screen(struct virgl_winsys *vws, const struct pipe_screen_config *c screen->base.get_vendor = virgl_get_vendor; screen->base.get_param = virgl_get_param; screen->base.get_shader_param = virgl_get_shader_param; + screen->base.get_video_param = virgl_get_video_param; screen->base.get_compute_param = virgl_get_compute_param; screen->base.get_paramf = virgl_get_paramf; screen->base.get_compiler_options = virgl_get_compiler_options; screen->base.is_format_supported = virgl_is_format_supported; + screen->base.is_video_format_supported = virgl_is_video_format_supported; screen->base.destroy = virgl_destroy_screen; screen->base.context_create = virgl_context_create; screen->base.flush_frontbuffer = virgl_flush_frontbuffer; diff --git a/src/gallium/drivers/virgl/virgl_screen.h b/src/gallium/drivers/virgl/virgl_screen.h index cbebb8d422a..89d8361e1fa 100644 --- a/src/gallium/drivers/virgl/virgl_screen.h +++ b/src/gallium/drivers/virgl/virgl_screen.h @@ -39,6 +39,7 @@ enum virgl_debug_flags { VIRGL_DEBUG_NO_COHERENT = 1 << 6, VIRGL_DEBUG_USE_TGSI = 1 << 7, VIRGL_DEBUG_L8_SRGB_ENABLE_READBACK = 1 << 8, + VIRGL_DEBUG_VIDEO = 1 << 9, }; extern int virgl_debug; diff --git a/src/gallium/drivers/virgl/virgl_video.c b/src/gallium/drivers/virgl/virgl_video.c new file mode 100644 index 00000000000..dc668dbcc80 --- /dev/null +++ b/src/gallium/drivers/virgl/virgl_video.c @@ -0,0 +1,567 @@ +/* + * 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 +#include + +#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; +} + diff --git a/src/gallium/drivers/virgl/virgl_video.h b/src/gallium/drivers/virgl/virgl_video.h new file mode 100644 index 00000000000..7d88b770adb --- /dev/null +++ b/src/gallium/drivers/virgl/virgl_video.h @@ -0,0 +1,347 @@ +/* + * 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 */ + diff --git a/src/gallium/targets/va/meson.build b/src/gallium/targets/va/meson.build index 10f94951ecc..44addd45bb1 100644 --- a/src/gallium/targets/va/meson.build +++ b/src/gallium/targets/va/meson.build @@ -51,7 +51,7 @@ libva_gallium = shared_library( link_whole : [libva_st], link_with : link_with_libva_gallium, dependencies : [ - dep_libdrm, driver_r600, driver_radeonsi, driver_nouveau, driver_d3d12, + dep_libdrm, driver_r600, driver_radeonsi, driver_nouveau, driver_d3d12, driver_virgl, idep_mesautil, ], link_depends : va_link_depends, @@ -64,6 +64,7 @@ libva_gallium = shared_library( foreach d : [[with_gallium_r600, 'r600'], [with_gallium_radeonsi, 'radeonsi'], [with_gallium_nouveau, 'nouveau'], + [with_gallium_virgl, 'virtio_gpu'], [with_gallium_d3d12_video, 'd3d12']] if d[0] va_drivers += '@0@_drv_video.so'.format(d[1]) diff --git a/src/gallium/targets/vdpau/meson.build b/src/gallium/targets/vdpau/meson.build index 1e793ebf9c9..d51af5c2bde 100644 --- a/src/gallium/targets/vdpau/meson.build +++ b/src/gallium/targets/vdpau/meson.build @@ -56,7 +56,7 @@ libvdpau_gallium = shared_library( link_with : link_with_libvdpau_gallium, dependencies : [ idep_mesautil, - driver_r300, driver_r600, driver_radeonsi, driver_nouveau, driver_d3d12, + driver_r300, driver_r600, driver_radeonsi, driver_nouveau, driver_d3d12, driver_virgl, ], link_depends : vdpau_link_depends, soversion : '@0@.@1@.0'.format(VDPAU_MAJOR, VDPAU_MINOR), @@ -69,6 +69,7 @@ foreach d : [[with_gallium_r300, 'r300'], [with_gallium_r600, 'r600'], [with_gallium_radeonsi, 'radeonsi'], [with_gallium_nouveau, 'nouveau'], + [with_gallium_virgl, 'virtio_gpu'], [with_gallium_d3d12_video, 'd3d12']] if d[0] vdpau_drivers += 'libvdpau_@0@.so.@1@.@2@.0'.format(d[1], VDPAU_MAJOR, VDPAU_MINOR) diff --git a/src/virtio/virtio-gpu/virgl_hw.h b/src/virtio/virtio-gpu/virgl_hw.h index eafc0b41912..b713ef6b943 100644 --- a/src/virtio/virtio-gpu/virgl_hw.h +++ b/src/virtio/virtio-gpu/virgl_hw.h @@ -546,6 +546,26 @@ struct virgl_caps_v1 { uint32_t max_texture_gather_components; }; +struct virgl_video_caps { + uint32_t profile:8; + uint32_t entrypoint:8; + uint32_t max_level:8; + uint32_t stacked_frames:8; + + uint32_t max_width:16; + uint32_t max_height:16; + + uint32_t prefered_format:16; + uint32_t max_macroblocks:16; + + uint32_t npot_texture:1; + uint32_t supports_progressive:1; + uint32_t supports_interlaced:1; + uint32_t prefers_interlaced:1; + uint32_t max_temporal_layers:8; + uint32_t reserved:20; +}; + /* * This struct should be growable when used in capset 2, * so we shouldn't have to add a v3 ever. @@ -603,6 +623,8 @@ struct virgl_caps_v2 { uint32_t max_shader_sampler_views; struct virgl_supported_format_mask supported_multisample_formats; uint32_t max_const_buffer_size[6]; // PIPE_SHADER_TYPES + uint32_t num_video_caps; + struct virgl_video_caps video_caps[32]; }; union virgl_caps { diff --git a/src/virtio/virtio-gpu/virgl_protocol.h b/src/virtio/virtio-gpu/virgl_protocol.h index 71629538514..31ce72e435a 100644 --- a/src/virtio/virtio-gpu/virgl_protocol.h +++ b/src/virtio/virtio-gpu/virgl_protocol.h @@ -117,6 +117,18 @@ enum virgl_context_cmd { VIRGL_CCMD_GET_MEMORY_INFO, VIRGL_CCMD_EMIT_STRING_MARKER, VIRGL_CCMD_LINK_SHADER, + + /* video codec */ + VIRGL_CCMD_CREATE_VIDEO_CODEC, + VIRGL_CCMD_DESTROY_VIDEO_CODEC, + VIRGL_CCMD_CREATE_VIDEO_BUFFER, + VIRGL_CCMD_DESTROY_VIDEO_BUFFER, + VIRGL_CCMD_BEGIN_FRAME, + VIRGL_CCMD_DECODE_MACROBLOCK, + VIRGL_CCMD_DECODE_BITSTREAM, + VIRGL_CCMD_ENCODE_BITSTREAM, + VIRGL_CCMD_END_FRAME, + VIRGL_MAX_COMMANDS }; @@ -696,4 +708,52 @@ enum vrend_tweak_type { #define VIRGL_LINK_SHADER_TESS_EVAL_HANDLE 5 #define VIRGL_LINK_SHADER_COMPUTE_HANDLE 6 +/* VIRGL_CCMD_CREATE_VIDEO_CODEC */ +#define VIRGL_CREATE_VIDEO_CODEC_SIZE 7 +#define VIRGL_CREATE_VIDEO_CODEC_HANDLE 1 +#define VIRGL_CREATE_VIDEO_CODEC_PROFILE 2 +#define VIRGL_CREATE_VIDEO_CODEC_ENTRYPOINT 3 +#define VIRGL_CREATE_VIDEO_CODEC_CHROMA_FMT 4 +#define VIRGL_CREATE_VIDEO_CODEC_LEVEL 5 +#define VIRGL_CREATE_VIDEO_CODEC_WIDTH 6 +#define VIRGL_CREATE_VIDEO_CODEC_HEIGHT 7 + +/* VIRGL_CCMD_DESTROY_VIDEO_CODEC */ +#define VIRGL_DESTROY_VIDEO_CODEC_SIZE 1 +#define VIRGL_DESTROY_VIDEO_CODEC_HANDLE 1 + +/* VIRGL_CCMD_CREATE_VIDEO_BUFFER */ +#define VIRGL_CREATE_VIDEO_BUFFER_MIN_SIZE 5 +#define VIRGL_CREATE_VIDEO_BUFFER_HANDLE 1 +#define VIRGL_CREATE_VIDEO_BUFFER_FORMAT 2 +#define VIRGL_CREATE_VIDEO_BUFFER_WIDTH 3 +#define VIRGL_CREATE_VIDEO_BUFFER_HEIGHT 4 +#define VIRGL_CREATE_VIDEO_BUFFER_RES_BASE 5 + +/* VIRGL_CCMD_DESTROY_VIDEO_BUFFER */ +#define VIRGL_DESTROY_VIDEO_BUFFER_SIZE 1 +#define VIRGL_DESTROY_VIDEO_BUFFER_HANDLE 1 + +/* VIRGL_CCMD_BEGIN_FRAME */ +#define VIRGL_BEGIN_FRAME_SIZE 2 +#define VIRGL_BEGIN_FRAME_CDC_HANDLE 1 +#define VIRGL_BEGIN_FRAME_TGT_HANDLE 2 + +/* VIRGL_CCMD_DECODE_MACROBLOCK */ + +/* VIRGL_CCMD_DECODE_BITSTREAM */ +#define VIRGL_DECODE_BS_SIZE 5 +#define VIRGL_DECODE_BS_CDC_HANDLE 1 +#define VIRGL_DECODE_BS_TGT_HANDLE 2 +#define VIRGL_DECODE_BS_DSC_HANDLE 3 +#define VIRGL_DECODE_BS_BUF_HANDLE 4 +#define VIRGL_DECODE_BS_BUF_SIZE 5 + +/* VIRGL_CCMD_ENCODE_BITSTREAM */ + +/* VIRGL_CCMD_END_FRAME */ +#define VIRGL_END_FRAME_SIZE 2 +#define VIRGL_END_FRAME_CDC_HANDLE 1 +#define VIRGL_END_FRAME_TGT_HANDLE 2 + #endif