virgl/video: Add support for H.264 encoding
authorFeng Jiang <jiangfeng@kylinos.cn>
Thu, 29 Sep 2022 03:38:20 +0000 (11:38 +0800)
committerMarge Bot <emma+marge@anholt.net>
Fri, 18 Nov 2022 07:46:11 +0000 (07:46 +0000)
Implement encoding framework and support H.264 encoding.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
Signed-off-by: Ming Xie <xieming@kylinos.cn>
Signed-off-by: Liming Sun <sunliming@kylinos.cn>
Reviewed-by: Gert Wollny <gert.wollny@collabora.com>
Reviewed-by: Boyuan Zhang <Boyuan.Zhang@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18831>

src/gallium/drivers/virgl/virgl_encode.c
src/gallium/drivers/virgl/virgl_encode.h
src/gallium/drivers/virgl/virgl_video.c
src/gallium/drivers/virgl/virgl_video.h
src/virtio/virtio-gpu/virgl_protocol.h
src/virtio/virtio-gpu/virgl_video_hw.h

index 364f92b..7e7e10b 100644 (file)
@@ -1706,6 +1706,19 @@ void virgl_encode_decode_bitstream(struct virgl_context *ctx,
    virgl_encoder_write_dword(ctx->cbuf, cdc->bs_size);
 }
 
+void virgl_encode_encode_bitstream(struct virgl_context *ctx,
+                                   struct virgl_video_codec *cdc,
+                                   struct virgl_video_buffer *buf,
+                                   struct virgl_resource *tgt)
+{
+   virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_ENCODE_BITSTREAM, 0, 5));
+   virgl_encoder_write_dword(ctx->cbuf, cdc->handle);
+   virgl_encoder_write_dword(ctx->cbuf, buf->handle);
+   virgl_encoder_write_res(ctx, tgt);
+   virgl_encoder_write_res(ctx, virgl_resource(cdc->desc_buffers[cdc->cur_buffer]));
+   virgl_encoder_write_res(ctx, virgl_resource(cdc->feed_buffers[cdc->cur_buffer]));
+}
+
 void virgl_encode_end_frame(struct virgl_context *ctx,
                             struct virgl_video_codec *cdc,
                             struct virgl_video_buffer *buf)
index 90fe8d1..bcb0ad6 100644 (file)
@@ -340,6 +340,11 @@ void virgl_encode_decode_bitstream(struct virgl_context *ctx,
                                    struct virgl_video_buffer *buf,
                                    void *desc, uint32_t desc_size);
 
+void virgl_encode_encode_bitstream(struct virgl_context *ctx,
+                                   struct virgl_video_codec *cdc,
+                                   struct virgl_video_buffer *buf,
+                                   struct virgl_resource *tgt);
+
 void virgl_encode_end_frame(struct virgl_context *ctx,
                             struct virgl_video_codec *cdc,
                             struct virgl_video_buffer *buf);
index b1b5750..128ddf3 100644 (file)
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/**
+ * @file
+ * Virgl video driver implementation.
+ *
+ * The virgl video driver acts as the frontend, and the virglrenderer acts as
+ * the backend. Currently, the backend is implemented via VA-API, but it is
+ * not limited to this.
+ *
+ * The relationship between vaSurface and video buffer objects:
+ *
+ *           GUEST (Mesa)           |       HOST (Virglrenderer)
+ *                                  |
+ *         +------------+           |          +------------+
+ *         | vaSurface  |           |          | vaSurface  | <------+
+ *         +------------+           |          +------------+        |
+ *               |                  |                                |
+ *  +---------------------------+   |   +-------------------------+  |
+ *  |    virgl_video_buffer     |   |   |    vrend_video_buffer   |  |
+ *  | +-----------------------+ |   |   |  +-------------------+  |  |
+ *  | |    vl_video_buffer    | |   |   |  | vrend_resource(s) |  |  |
+ *  | | +-------------------+ | |<--+-->|  +-------------------+  |  |
+ *  | | | virgl_resource(s) | | |   |   |  +--------------------+ |  |
+ *  | | +-------------------+ | |   |   |  | virgl_video_buffer |-+--+
+ *  | +-----------------------+ |   |   |  +--------------------+ |
+ *  +---------------------------+   |   +-------------------------+
+ *
+ * The relationship between vaContext and video codec objects:
+ *
+ *           GUEST (Mesa)         |         HOST (Virglrenderer)
+ *                                |
+ *         +------------+         |           +------------+
+ *         | vaContext  |         |           | vaContext  | <-------+
+ *         +------------+         |           +------------+         |
+ *               |                |                                  |
+ *  +------------------------+    |    +--------------------------+  |
+ *  |    virgl_video_codec   | <--+--> |    vrend_video_codec     |  |
+ *  +------------------------+    |    |  +--------------------+  |  |
+ *                                |    |  | virgl_video_codec  | -+--+
+ *                                |    |  +--------------------+  |
+ *                                |    +--------------------------+
+ *
+ * @author Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
 #include <string.h>
 #include <sys/param.h>
 
@@ -149,6 +193,112 @@ static int fill_h264_picture_desc(const struct pipe_picture_desc *desc,
     return 0;
 }
 
+static int fill_h264_enc_picture_desc(const struct pipe_picture_desc *desc,
+                                      union virgl_picture_desc *vdsc)
+{
+    unsigned i;
+    struct virgl_h264_enc_picture_desc *vh264 = &vdsc->h264_enc;
+    struct pipe_h264_enc_picture_desc *h264 = (struct pipe_h264_enc_picture_desc *)desc;
+
+    fill_base_picture_desc(desc, &vh264->base);
+
+    /* seq param */
+    ITEM_SET(vh264, h264, seq.enc_constraint_set_flags);
+    ITEM_SET(vh264, h264, seq.enc_frame_cropping_flag);
+    ITEM_SET(vh264, h264, seq.enc_frame_crop_left_offset);
+    ITEM_SET(vh264, h264, seq.enc_frame_crop_right_offset);
+    ITEM_SET(vh264, h264, seq.enc_frame_crop_top_offset);
+    ITEM_SET(vh264, h264, seq.enc_frame_crop_bottom_offset);
+    ITEM_SET(vh264, h264, seq.pic_order_cnt_type);
+    ITEM_SET(vh264, h264, seq.num_temporal_layers);
+    ITEM_SET(vh264, h264, seq.vui_parameters_present_flag);
+    ITEM_SET(vh264, h264, seq.vui_flags.aspect_ratio_info_present_flag);
+    ITEM_SET(vh264, h264, seq.vui_flags.timing_info_present_flag);
+    ITEM_SET(vh264, h264, seq.aspect_ratio_idc);
+    ITEM_SET(vh264, h264, seq.sar_width);
+    ITEM_SET(vh264, h264, seq.sar_height);
+    ITEM_SET(vh264, h264, seq.num_units_in_tick);
+    ITEM_SET(vh264, h264, seq.time_scale);
+
+    /* rate_ctrl */
+    for (i = 0; i < 4; i++) {
+        ITEM_SET(vh264, h264, rate_ctrl[i].rate_ctrl_method);
+        ITEM_SET(vh264, h264, rate_ctrl[i].target_bitrate);
+        ITEM_SET(vh264, h264, rate_ctrl[i].peak_bitrate);
+        ITEM_SET(vh264, h264, rate_ctrl[i].frame_rate_num);
+        ITEM_SET(vh264, h264, rate_ctrl[i].frame_rate_den);
+        ITEM_SET(vh264, h264, rate_ctrl[i].vbv_buffer_size);
+        ITEM_SET(vh264, h264, rate_ctrl[i].vbv_buf_lv);
+        ITEM_SET(vh264, h264, rate_ctrl[i].target_bits_picture);
+        ITEM_SET(vh264, h264, rate_ctrl[i].peak_bits_picture_integer);
+        ITEM_SET(vh264, h264, rate_ctrl[i].peak_bits_picture_fraction);
+        ITEM_SET(vh264, h264, rate_ctrl[i].fill_data_enable);
+        ITEM_SET(vh264, h264, rate_ctrl[i].skip_frame_enable);
+        ITEM_SET(vh264, h264, rate_ctrl[i].enforce_hrd);
+        ITEM_SET(vh264, h264, rate_ctrl[i].max_au_size);
+        ITEM_SET(vh264, h264, rate_ctrl[i].max_qp);
+        ITEM_SET(vh264, h264, rate_ctrl[i].min_qp);
+    }
+
+    /* motion_est */
+    ITEM_SET(vh264, h264, motion_est.motion_est_quarter_pixel);
+    ITEM_SET(vh264, h264, motion_est.enc_disable_sub_mode);
+    ITEM_SET(vh264, h264, motion_est.lsmvert);
+    ITEM_SET(vh264, h264, motion_est.enc_en_ime_overw_dis_subm);
+    ITEM_SET(vh264, h264, motion_est.enc_ime_overw_dis_subm_no);
+    ITEM_SET(vh264, h264, motion_est.enc_ime2_search_range_x);
+    ITEM_SET(vh264, h264, motion_est.enc_ime2_search_range_y);
+
+    /* pic_ctrl */
+    ITEM_SET(vh264, h264, pic_ctrl.enc_cabac_enable);
+    ITEM_SET(vh264, h264, pic_ctrl.enc_cabac_init_idc);
+
+    ITEM_SET(vh264, h264, intra_idr_period);
+
+    ITEM_SET(vh264, h264, quant_i_frames);
+    ITEM_SET(vh264, h264, quant_p_frames);
+    ITEM_SET(vh264, h264, quant_b_frames);
+
+    ITEM_SET(vh264, h264, picture_type);
+    ITEM_SET(vh264, h264, frame_num);
+    ITEM_SET(vh264, h264, frame_num_cnt);
+    ITEM_SET(vh264, h264, p_remain);
+    ITEM_SET(vh264, h264, i_remain);
+    ITEM_SET(vh264, h264, idr_pic_id);
+    ITEM_SET(vh264, h264, gop_cnt);
+    ITEM_SET(vh264, h264, pic_order_cnt);
+    ITEM_SET(vh264, h264, num_ref_idx_l0_active_minus1);
+    ITEM_SET(vh264, h264, num_ref_idx_l1_active_minus1);
+
+    for (i = 0; i < 32; i++) {
+        ITEM_SET(vh264, h264, ref_idx_l0_list[i]);
+        ITEM_SET(vh264, h264, ref_idx_l1_list[i]);
+        ITEM_SET(vh264, h264, l0_is_long_term[i]);
+        ITEM_SET(vh264, h264, l1_is_long_term[i]);
+    }
+
+    ITEM_SET(vh264, h264, gop_size);
+
+    ITEM_SET(vh264, h264, quality_modes.level);
+    ITEM_SET(vh264, h264, quality_modes.preset_mode);
+    ITEM_SET(vh264, h264, quality_modes.pre_encode_mode);
+    ITEM_SET(vh264, h264, quality_modes.vbaq_mode);
+
+    ITEM_SET(vh264, h264, not_referenced);
+    ITEM_SET(vh264, h264, is_ltr);
+    ITEM_SET(vh264, h264, ltr_index);
+    ITEM_SET(vh264, h264, enable_vui);
+
+    ITEM_SET(vh264, h264, num_slice_descriptors);
+    for (i = 0; i < vh264->num_slice_descriptors; i++) {
+        ITEM_SET(vh264, h264, slices_descriptors[i].macroblock_address);
+        ITEM_SET(vh264, h264, slices_descriptors[i].num_macroblocks);
+        ITEM_SET(vh264, h264, slices_descriptors[i].slice_type);
+    }
+
+    return 0;
+}
+
 static int fill_h265_picture_desc(const struct pipe_picture_desc *desc,
                                   union virgl_picture_desc *vdsc)
 {
@@ -312,6 +462,17 @@ static int fill_picture_desc(const struct pipe_picture_desc *desc,
     }
 }
 
+static int fill_enc_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_AVC:
+        return fill_h264_enc_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)
@@ -319,6 +480,9 @@ static void virgl_video_begin_frame(struct pipe_video_codec *codec,
     struct virgl_video_codec *vcdc = virgl_video_codec(codec);
     struct virgl_video_buffer *vbuf = virgl_video_buffer(target);
 
+    if (codec->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE)
+        fill_enc_picture_desc(picture, &vcdc->desc);
+
     virgl_encode_begin_frame(vcdc->vctx, vcdc, vbuf);
 }
 
@@ -390,6 +554,51 @@ static void virgl_video_decode_bitstream(struct pipe_video_codec *codec,
     virgl_encode_decode_bitstream(vctx, vcdc, vbuf, &vdsc, sizeof(vdsc));
 }
 
+static void virgl_video_encode_bitstream(struct pipe_video_codec *codec,
+                                         struct pipe_video_buffer *source,
+                                         struct pipe_resource *target,
+                                         void **feedback)
+{
+    struct virgl_video_codec *vcdc = virgl_video_codec(codec);
+    struct virgl_context *vctx = vcdc->vctx;
+    struct virgl_screen *vs = virgl_screen(vctx->base.screen);
+    struct virgl_resource *vres;
+    struct virgl_video_encode_feedback *fb;
+    struct pipe_transfer *xfer = NULL;
+    void *ptr;
+
+    /* Transfer picture desc */
+    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, &vcdc->desc, sizeof(vcdc->desc));
+    pipe_buffer_unmap(&vctx->base, xfer);
+
+    /* Init feedback */
+    vres = virgl_resource(vcdc->feed_buffers[vcdc->cur_buffer]);
+    vs->vws->resource_wait(vs->vws, vres->hw_res);
+    fb = pipe_buffer_map(&vctx->base, vcdc->feed_buffers[vcdc->cur_buffer],
+                         PIPE_MAP_WRITE, &xfer);
+    if (!fb)
+        return;
+    fb->stat = VIRGL_VIDEO_ENCODE_STAT_NOT_STARTED;
+    fb->coded_size = 0;
+    pipe_buffer_unmap(&vctx->base, xfer);
+    *feedback = vres;
+
+    /*
+     * These objects do not need to be transferred manually:
+     *   source - corresponds to VASurface in VA-API
+     *   target - corresponds to VACodedBuffer in VA-API
+     */
+
+    virgl_encode_encode_bitstream(vctx, vcdc, virgl_video_buffer(source),
+                                  virgl_resource(target));
+}
+
 static void virgl_video_end_frame(struct pipe_video_codec *codec,
                                   struct pipe_video_buffer *target,
                                   struct pipe_picture_desc *picture)
@@ -406,16 +615,43 @@ static void virgl_video_end_frame(struct pipe_video_codec *codec,
 
 static void virgl_video_flush(struct pipe_video_codec *codec)
 {
-    (void)codec;
+    struct pipe_context *ctx = codec->context;
+    struct pipe_fence_handle *fence = NULL;
+
+    ctx->flush(ctx, &fence, 0);
+    if (fence) {
+        ctx->screen->fence_finish(ctx->screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
+        ctx->screen->fence_reference(ctx->screen, &fence, NULL);
+    }
 }
 
 static void virgl_video_get_feedback(struct pipe_video_codec *codec,
                                      void *feedback,
                                      unsigned *size)
 {
-    (void)codec;
-    (void)feedback;
-    (void)size;
+    struct virgl_video_codec *vcdc = virgl_video_codec(codec);
+    struct virgl_context *vctx = vcdc->vctx;
+    struct virgl_screen *vs = virgl_screen(vctx->base.screen);
+    struct virgl_resource *vres = feedback;
+    struct virgl_video_encode_feedback *fb;
+    struct pipe_transfer *xfer;
+
+    if (!feedback || !size)
+        return;
+
+    vs->vws->resource_wait(vs->vws, vres->hw_res);
+    fb = pipe_buffer_map(&vctx->base, &vres->b, PIPE_MAP_READ, &xfer);
+    if (!fb)
+        return;
+    if (fb->stat == VIRGL_VIDEO_ENCODE_STAT_SUCCESS) {
+        *size = fb->coded_size;
+    } else {
+        *size = 0;
+        if (virgl_debug & VIRGL_DEBUG_VIDEO) {
+            debug_printf("unexpected encode feedback: %u\n", fb->stat);
+        }
+    }
+    pipe_buffer_unmap(&vctx->base, xfer);
 }
 
 static void virgl_video_destroy_codec(struct pipe_video_codec *codec)
@@ -425,7 +661,11 @@ static void virgl_video_destroy_codec(struct pipe_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);
+        if (codec->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+            pipe_resource_reference(&vcdc->bs_buffers[i], NULL);
+        } else {
+            pipe_resource_reference(&vcdc->feed_buffers[i], NULL);
+        }
         pipe_resource_reference(&vcdc->desc_buffers[i], NULL);
     }
 
@@ -451,11 +691,6 @@ virgl_video_create_codec(struct pipe_context *ctx,
                      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:
@@ -480,6 +715,7 @@ virgl_video_create_codec(struct pipe_context *ctx,
     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.encode_bitstream = virgl_video_encode_bitstream;
     vcdc->base.end_frame = virgl_video_end_frame;
     vcdc->base.flush = virgl_video_flush;
     vcdc->base.get_feedback = virgl_video_get_feedback;
@@ -487,9 +723,15 @@ virgl_video_create_codec(struct pipe_context *ctx,
     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));
+        if (templ->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+            vcdc->bs_buffers[i] = pipe_buffer_create(ctx->screen,
+                              PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING,
+                              BS_BUF_DEFAULT_SIZE(width, height));
+        } else {
+            vcdc->feed_buffers[i] = pipe_buffer_create(ctx->screen,
+                                PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING,
+                                sizeof(struct virgl_video_encode_feedback));
+        }
 
         vcdc->desc_buffers[i] = pipe_buffer_create(ctx->screen,
                             PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING,
index 7b4a3fd..3ebcb04 100644 (file)
@@ -39,6 +39,7 @@
 #include "virgl_context.h"
 #include "vl/vl_video_buffer.h"
 #include "pipe/p_video_codec.h"
+#include "virtio-gpu/virgl_video_hw.h"
 
 #define VIRGL_VIDEO_CODEC_BUF_NUM    10
 
@@ -47,11 +48,13 @@ struct virgl_video_codec {
 
     uint32_t handle;
     struct virgl_context *vctx;
+    union virgl_picture_desc desc;
 
     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 pipe_resource *feed_buffers[VIRGL_VIDEO_CODEC_BUF_NUM];
 };
 
 struct virgl_video_buffer {
index be65a2f..0501077 100644 (file)
@@ -720,7 +720,7 @@ enum vrend_tweak_type {
 #define VIRGL_CREATE_VIDEO_CODEC_MAX_REF    8
 
 /* VIRGL_CCMD_DESTROY_VIDEO_CODEC */
-#define VIRGL_DESTROY_VIDEO_CODEC_SIZE      1
+#define VIRGL_DESTROY_VIDEO_CODEC_MIN_SIZE  1
 #define VIRGL_DESTROY_VIDEO_CODEC_HANDLE    1
 
 /* VIRGL_CCMD_CREATE_VIDEO_BUFFER */
@@ -732,18 +732,18 @@ enum vrend_tweak_type {
 #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_MIN_SIZE 1
 #define VIRGL_DESTROY_VIDEO_BUFFER_HANDLE   1
 
 /* VIRGL_CCMD_BEGIN_FRAME */
-#define VIRGL_BEGIN_FRAME_SIZE              2
+#define VIRGL_BEGIN_FRAME_MIN_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_MIN_SIZE            5
 #define VIRGL_DECODE_BS_CDC_HANDLE          1
 #define VIRGL_DECODE_BS_TGT_HANDLE          2
 #define VIRGL_DECODE_BS_DSC_HANDLE          3
@@ -751,9 +751,15 @@ enum vrend_tweak_type {
 #define VIRGL_DECODE_BS_BUF_SIZE            5
 
 /* VIRGL_CCMD_ENCODE_BITSTREAM */
+#define VIRGL_ENCODE_BS_MIN_SIZE            5
+#define VIRGL_ENCODE_BS_CDC_HANDLE          1
+#define VIRGL_ENCODE_BS_SRC_HANDLE          2
+#define VIRGL_ENCODE_BS_DEST_HANDLE         3
+#define VIRGL_ENCODE_BS_DESC_HANDLE         4
+#define VIRGL_ENCODE_BS_FEED_HANDLE         5
 
 /* VIRGL_CCMD_END_FRAME */
-#define VIRGL_END_FRAME_SIZE                2
+#define VIRGL_END_FRAME_MIN_SIZE            2
 #define VIRGL_END_FRAME_CDC_HANDLE          1
 #define VIRGL_END_FRAME_TGT_HANDLE          2
 
index e744789..18ea130 100644 (file)
@@ -51,6 +51,13 @@ struct virgl_base_picture_desc {
 
 };
 
+struct virgl_enc_quality_modes {
+    uint32_t level;
+    uint32_t preset_mode;
+    uint32_t pre_encode_mode;
+    uint32_t vbaq_mode;
+};
+
 /* H.264 sequence parameter set */
 struct virgl_h264_sps {
     uint8_t  level_idc;
@@ -140,6 +147,120 @@ struct virgl_h264_picture_desc {
     uint8_t  reserved[2];
 };
 
+struct virgl_h264_enc_seq_param
+{
+   uint32_t enc_constraint_set_flags;
+   uint32_t enc_frame_cropping_flag;
+   uint32_t enc_frame_crop_left_offset;
+   uint32_t enc_frame_crop_right_offset;
+   uint32_t enc_frame_crop_top_offset;
+   uint32_t enc_frame_crop_bottom_offset;
+   uint32_t pic_order_cnt_type;
+   uint32_t num_temporal_layers;
+   uint32_t vui_parameters_present_flag;
+   struct {
+      uint32_t aspect_ratio_info_present_flag: 1;
+      uint32_t timing_info_present_flag: 1;
+      uint32_t reserved:30;
+   } vui_flags;
+   uint32_t aspect_ratio_idc;
+   uint32_t sar_width;
+   uint32_t sar_height;
+   uint32_t num_units_in_tick;
+   uint32_t time_scale;
+};
+
+struct virgl_h264_enc_rate_control
+{
+    uint32_t target_bitrate;
+    uint32_t peak_bitrate;
+    uint32_t frame_rate_num;
+    uint32_t frame_rate_den;
+    uint32_t vbv_buffer_size;
+    uint32_t vbv_buf_lv;
+    uint32_t target_bits_picture;
+    uint32_t peak_bits_picture_integer;
+    uint32_t peak_bits_picture_fraction;
+    uint32_t fill_data_enable;
+    uint32_t skip_frame_enable;
+    uint32_t enforce_hrd;
+    uint32_t max_au_size;
+    uint32_t max_qp;
+    uint32_t min_qp;
+
+    uint8_t  rate_ctrl_method; /* see enum pipe_h2645_enc_rate_control_method */
+    uint8_t  reserved[3];
+};
+
+struct virgl_h264_enc_motion_estimation
+{
+    uint32_t motion_est_quarter_pixel;
+    uint32_t enc_disable_sub_mode;
+    uint32_t lsmvert;
+    uint32_t enc_en_ime_overw_dis_subm;
+    uint32_t enc_ime_overw_dis_subm_no;
+    uint32_t enc_ime2_search_range_x;
+    uint32_t enc_ime2_search_range_y;
+};
+
+struct virgl_h264_enc_pic_control
+{
+    uint32_t enc_cabac_enable;
+    uint32_t enc_cabac_init_idc;
+};
+
+struct virgl_h264_slice_descriptor
+{
+   uint32_t macroblock_address;
+   uint32_t num_macroblocks;
+
+   uint8_t  slice_type; /* see enum pipe_h264_slice_type  */
+   uint8_t  reserved[3];
+};
+
+struct virgl_h264_enc_picture_desc
+{
+   struct virgl_base_picture_desc base;
+
+   struct virgl_h264_enc_seq_param seq;
+   struct virgl_h264_enc_rate_control rate_ctrl[4];
+   struct virgl_h264_enc_motion_estimation motion_est;
+   struct virgl_h264_enc_pic_control pic_ctrl;
+
+   uint32_t intra_idr_period;
+
+   uint32_t quant_i_frames;
+   uint32_t quant_p_frames;
+   uint32_t quant_b_frames;
+
+   uint32_t frame_num;
+   uint32_t frame_num_cnt;
+   uint32_t p_remain;
+   uint32_t i_remain;
+   uint32_t idr_pic_id;
+   uint32_t gop_cnt;
+   uint32_t pic_order_cnt;
+   uint32_t num_ref_idx_l0_active_minus1;
+   uint32_t num_ref_idx_l1_active_minus1;
+   uint32_t ref_idx_l0_list[32];
+   uint8_t  l0_is_long_term[32];
+   uint32_t ref_idx_l1_list[32];
+   uint8_t  l1_is_long_term[32];
+   uint32_t gop_size;
+   struct virgl_enc_quality_modes quality_modes;
+
+   uint32_t num_slice_descriptors;
+   struct virgl_h264_slice_descriptor slices_descriptors[128];
+
+   uint8_t  picture_type; /* see enum pipe_h2645_enc_picture_type */
+   uint8_t  not_referenced;
+   uint8_t  is_ltr;
+   uint8_t  enable_vui;
+
+   uint32_t ltr_index;
+};
+
+
 struct virgl_h265_sps
 {
    uint32_t pic_width_in_luma_samples;
@@ -305,6 +426,21 @@ union virgl_picture_desc {
     struct virgl_h264_picture_desc h264;
     struct virgl_h265_picture_desc h265;
     struct virgl_mpeg4_picture_desc mpeg4;
+    struct virgl_h264_enc_picture_desc h264_enc;
+};
+
+enum virgl_video_encode_stat {
+    VIRGL_VIDEO_ENCODE_STAT_NOT_STARTED = 0,
+    VIRGL_VIDEO_ENCODE_STAT_IN_PROGRESS,
+    VIRGL_VIDEO_ENCODE_STAT_SUCCESS,
+    VIRGL_VIDEO_ENCODE_STAT_FAILURE,
+};
+
+struct virgl_video_encode_feedback {
+    uint8_t stat;           /* see enum virgl_video_encode_stat */
+    uint8_t reserved[3];
+
+    uint32_t coded_size;    /* size of encoded data in bytes */
 };
 
 #endif /* VIRGL_VIDEO_HW_H */