xref: /aosp_15_r20/external/virglrenderer/src/vrend_video.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1 /**************************************************************************
2  *
3  * Copyright (C) 2022 Kylin Software Co., Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  **************************************************************************/
24 
25 /**
26  * @file
27  * The video implementation of the vrend renderer.
28  *
29  * It is based on the general virgl video submodule and handles data transfer
30  * and synchronization between host and guest.
31  *
32  * The relationship between vaSurface and video buffer objects:
33  *
34  *           GUEST (Mesa)           |       HOST (Virglrenderer)
35  *                                  |
36  *         +------------+           |          +------------+
37  *         | vaSurface  |           |          | vaSurface  | <------+
38  *         +------------+           |          +------------+        |
39  *               |                  |                                |
40  *  +---------------------------+   |   +-------------------------+  |
41  *  |    virgl_video_buffer     |   |   |    vrend_video_buffer   |  |
42  *  | +-----------------------+ |   |   |  +-------------------+  |  |
43  *  | |    vl_video_buffer    | |   |   |  | vrend_resource(s) |  |  |
44  *  | | +-------------------+ | |<--+-->|  +-------------------+  |  |
45  *  | | | virgl_resource(s) | | |   |   |  +--------------------+ |  |
46  *  | | +-------------------+ | |   |   |  | virgl_video_buffer |-+--+
47  *  | +-----------------------+ |   |   |  +--------------------+ |
48  *  +---------------------------+   |   +-------------------------+
49  *
50  * The relationship between vaContext and video codec objects:
51  *
52  *           GUEST (Mesa)         |         HOST (Virglrenderer)
53  *                                |
54  *         +------------+         |           +------------+
55  *         | vaContext  |         |           | vaContext  | <-------+
56  *         +------------+         |           +------------+         |
57  *               |                |                                  |
58  *  +------------------------+    |    +--------------------------+  |
59  *  |    virgl_video_codec   | <--+--> |    vrend_video_codec     |  |
60  *  +------------------------+    |    |  +--------------------+  |  |
61  *                                |    |  | virgl_video_codec  | -+--+
62  *                                |    |  +--------------------+  |
63  *                                |    +--------------------------+
64  *
65  * @author Feng Jiang <[email protected]>
66  */
67 
68 
69 #include <sys/param.h>
70 
71 #include "virgl_video.h"
72 #include "virgl_video_hw.h"
73 
74 #include "vrend_debug.h"
75 #include "vrend_winsys.h"
76 #include "vrend_renderer.h"
77 #include "vrend_video.h"
78 
79 struct vrend_context;
80 
81 struct vrend_video_context {
82     struct vrend_context *ctx;
83     struct list_head codecs;
84     struct list_head buffers;
85 };
86 
87 struct vrend_video_codec {
88     struct virgl_video_codec *codec;
89     uint32_t handle;
90     struct vrend_resource *feed_res;    /* encoding feedback */
91     struct vrend_resource *dest_res;    /* encoding coded buffer */
92     struct vrend_video_context *ctx;
93     struct list_head head;
94 };
95 
96 struct vrend_video_plane {
97     uint32_t res_handle;
98     GLuint texture;         /* texture for temporary use */
99     GLuint framebuffer;     /* framebuffer for temporary use */
100     EGLImageKHR egl_image;  /* egl image for temporary use */
101 };
102 
103 struct vrend_video_buffer {
104     struct virgl_video_buffer *buffer;
105 
106     uint32_t handle;
107     struct vrend_video_context *ctx;
108     struct list_head head;
109 
110     uint32_t num_planes;
111     struct vrend_video_plane planes[3];
112 };
113 
vrend_video_codec(struct virgl_video_codec * codec)114 static struct vrend_video_codec *vrend_video_codec(
115         struct virgl_video_codec *codec)
116 {
117     return virgl_video_codec_opaque_data(codec);
118 }
119 
vrend_video_buffer(struct virgl_video_buffer * buffer)120 static struct vrend_video_buffer *vrend_video_buffer(
121         struct virgl_video_buffer *buffer)
122 {
123     return virgl_video_buffer_opaque_data(buffer);
124 }
125 
get_video_codec(struct vrend_video_context * ctx,uint32_t cdc_handle)126 static struct vrend_video_codec *get_video_codec(
127                                         struct vrend_video_context *ctx,
128                                         uint32_t cdc_handle)
129 {
130     struct vrend_video_codec *cdc;
131 
132     LIST_FOR_EACH_ENTRY(cdc, &ctx->codecs, head) {
133         if (cdc->handle == cdc_handle)
134             return cdc;
135     }
136 
137     return NULL;
138 }
139 
get_video_buffer(struct vrend_video_context * ctx,uint32_t buf_handle)140 static struct vrend_video_buffer *get_video_buffer(
141                                         struct vrend_video_context *ctx,
142                                         uint32_t buf_handle)
143 {
144     struct vrend_video_buffer *buf;
145 
146     LIST_FOR_EACH_ENTRY(buf, &ctx->buffers, head) {
147         if (buf->handle == buf_handle)
148             return buf;
149     }
150 
151     return NULL;
152 }
153 
154 
sync_dmabuf_to_video_buffer(struct vrend_video_buffer * buf,const struct virgl_video_dma_buf * dmabuf)155 static int sync_dmabuf_to_video_buffer(struct vrend_video_buffer *buf,
156                                        const struct virgl_video_dma_buf *dmabuf)
157 {
158     if (!(dmabuf->flags & VIRGL_VIDEO_DMABUF_READ_ONLY)) {
159         vrend_printf("%s: dmabuf is not readable\n", __func__);
160         return -1;
161     }
162 
163     for (unsigned i = 0; i < dmabuf->num_planes && i < buf->num_planes; i++) {
164         struct vrend_video_plane *plane = &buf->planes[i];
165         struct vrend_resource *res;
166 
167         res = vrend_renderer_ctx_res_lookup(buf->ctx->ctx, plane->res_handle);
168         if (!res) {
169             vrend_printf("%s: res %d not found\n", __func__, plane->res_handle);
170             continue;
171         }
172 
173         /* dmabuf -> eglimage */
174         if (EGL_NO_IMAGE_KHR == plane->egl_image) {
175             EGLint img_attrs[16] = {
176                 EGL_LINUX_DRM_FOURCC_EXT,       dmabuf->planes[i].drm_format,
177                 EGL_WIDTH,                      dmabuf->width / (i + 1),
178                 EGL_HEIGHT,                     dmabuf->height / (i + 1),
179                 EGL_DMA_BUF_PLANE0_FD_EXT,      dmabuf->planes[i].fd,
180                 EGL_DMA_BUF_PLANE0_OFFSET_EXT,  dmabuf->planes[i].offset,
181                 EGL_DMA_BUF_PLANE0_PITCH_EXT,   dmabuf->planes[i].pitch,
182                 EGL_NONE
183             };
184 
185             plane->egl_image = eglCreateImageKHR(eglGetCurrentDisplay(),
186                     EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, img_attrs);
187         }
188 
189         if (EGL_NO_IMAGE_KHR == plane->egl_image) {
190             vrend_printf("%s: create egl image failed\n", __func__);
191             continue;
192         }
193 
194         /* eglimage -> texture */
195         glBindTexture(GL_TEXTURE_2D, plane->texture);
196         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
197                                     (GLeglImageOES)(plane->egl_image));
198 
199         /* texture -> framebuffer */
200         glBindFramebuffer(GL_READ_FRAMEBUFFER, plane->framebuffer);
201         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
202                                GL_TEXTURE_2D, plane->texture, 0);
203 
204         /* framebuffer -> vrend_video_buffer.planes[i] */
205         glBindTexture(GL_TEXTURE_2D, res->id);
206         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
207                             res->base.width0, res->base.height0);
208     }
209 
210     glBindTexture(GL_TEXTURE_2D, 0);
211     glBindFramebuffer(GL_FRAMEBUFFER, 0);
212 
213     return 0;
214 }
215 
sync_video_buffer_to_dmabuf(struct vrend_video_buffer * buf,const struct virgl_video_dma_buf * dmabuf)216 static int sync_video_buffer_to_dmabuf(struct vrend_video_buffer *buf,
217                                        const struct virgl_video_dma_buf *dmabuf)
218 {
219     if (!(dmabuf->flags & VIRGL_VIDEO_DMABUF_WRITE_ONLY)) {
220         vrend_printf("%s: dmabuf is not writable\n", __func__);
221         return -1;
222     }
223 
224     for (unsigned i = 0; i < dmabuf->num_planes && i < buf->num_planes; i++) {
225         struct vrend_video_plane *plane = &buf->planes[i];
226         struct vrend_resource *res;
227 
228         res = vrend_renderer_ctx_res_lookup(buf->ctx->ctx, plane->res_handle);
229         if (!res) {
230             vrend_printf("%s: res %d not found\n", __func__, plane->res_handle);
231             continue;
232         }
233 
234         /* dmabuf -> eglimage */
235         if (EGL_NO_IMAGE_KHR == plane->egl_image) {
236             EGLint img_attrs[16] = {
237                 EGL_LINUX_DRM_FOURCC_EXT,       dmabuf->planes[i].drm_format,
238                 EGL_WIDTH,                      dmabuf->width / (i + 1),
239                 EGL_HEIGHT,                     dmabuf->height / (i + 1),
240                 EGL_DMA_BUF_PLANE0_FD_EXT,      dmabuf->planes[i].fd,
241                 EGL_DMA_BUF_PLANE0_OFFSET_EXT,  dmabuf->planes[i].offset,
242                 EGL_DMA_BUF_PLANE0_PITCH_EXT,   dmabuf->planes[i].pitch,
243                 EGL_NONE
244             };
245 
246             plane->egl_image = eglCreateImageKHR(eglGetCurrentDisplay(),
247                     EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, img_attrs);
248         }
249 
250         if (EGL_NO_IMAGE_KHR == plane->egl_image) {
251             vrend_printf("%s: create egl image failed\n", __func__);
252             continue;
253         }
254 
255         /* eglimage -> texture */
256         glBindTexture(GL_TEXTURE_2D, plane->texture);
257         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
258                                     (GLeglImageOES)(plane->egl_image));
259 
260         /* vrend_video_buffer.planes[i] -> framebuffer */
261         glBindFramebuffer(GL_READ_FRAMEBUFFER, plane->framebuffer);
262         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
263                                GL_TEXTURE_2D, res->id, 0);
264 
265         /* framebuffer -> texture */
266         glBindTexture(GL_TEXTURE_2D, plane->texture);
267         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
268                             res->base.width0, res->base.height0);
269 
270     }
271 
272     glBindTexture(GL_TEXTURE_2D, 0);
273     glBindFramebuffer(GL_FRAMEBUFFER, 0);
274 
275     return 0;
276 }
277 
278 
vrend_video_decode_completed(struct virgl_video_codec * codec,const struct virgl_video_dma_buf * dmabuf)279 static void vrend_video_decode_completed(
280                                 struct virgl_video_codec *codec,
281                                 const struct virgl_video_dma_buf *dmabuf)
282 {
283     struct vrend_video_buffer *buf = vrend_video_buffer(dmabuf->buf);
284 
285     (void)codec;
286 
287     sync_dmabuf_to_video_buffer(buf, dmabuf);
288 }
289 
290 
vrend_video_enocde_upload_picture(struct virgl_video_codec * codec,const struct virgl_video_dma_buf * dmabuf)291 static void vrend_video_enocde_upload_picture(
292                                 struct virgl_video_codec *codec,
293                                 const struct virgl_video_dma_buf *dmabuf)
294 {
295     struct vrend_video_buffer *buf = vrend_video_buffer(dmabuf->buf);
296 
297     (void)codec;
298 
299     sync_video_buffer_to_dmabuf(buf, dmabuf);
300 }
301 
vrend_video_encode_completed(struct virgl_video_codec * codec,const struct virgl_video_dma_buf * src_buf,const struct virgl_video_dma_buf * ref_buf,unsigned num_coded_bufs,const void * const * coded_bufs,const unsigned * coded_sizes)302 static void vrend_video_encode_completed(
303                                 struct virgl_video_codec *codec,
304                                 const struct virgl_video_dma_buf *src_buf,
305                                 const struct virgl_video_dma_buf *ref_buf,
306                                 unsigned num_coded_bufs,
307                                 const void * const *coded_bufs,
308                                 const unsigned *coded_sizes)
309 {
310     void *buf;
311     unsigned i, size, data_size;
312     struct virgl_video_encode_feedback feedback;
313     struct vrend_video_codec *cdc = vrend_video_codec(codec);
314 
315     (void)src_buf;
316     (void)ref_buf;
317 
318     if (!cdc->dest_res || !cdc->feed_res)
319         return;
320 
321     memset(&feedback, 0, sizeof(feedback));
322 
323     /* sync coded data to guest */
324     if (has_bit(cdc->dest_res->storage_bits, VREND_STORAGE_GL_BUFFER)) {
325         glBindBufferARB(cdc->dest_res->target, cdc->dest_res->id);
326         buf = glMapBufferRange(cdc->dest_res->target, 0,
327                                cdc->dest_res->base.width0, GL_MAP_WRITE_BIT);
328         for (i = 0, data_size = 0; i < num_coded_bufs &&
329                     data_size < cdc->dest_res->base.width0; i++) {
330             size = MIN(cdc->dest_res->base.width0 - data_size, coded_sizes[i]);
331             memcpy((uint8_t *)buf + data_size, coded_bufs[i], size);
332             vrend_write_to_iovec(cdc->dest_res->iov, cdc->dest_res->num_iovs,
333                                  data_size, coded_bufs[i], size);
334             data_size += size;
335         }
336         glUnmapBuffer(cdc->dest_res->target);
337         glBindBufferARB(cdc->dest_res->target, 0);
338         feedback.stat = VIRGL_VIDEO_ENCODE_STAT_SUCCESS;
339         feedback.coded_size = data_size;
340     } else {
341         vrend_printf("unexcepted coded res type\n");
342         feedback.stat = VIRGL_VIDEO_ENCODE_STAT_FAILURE;
343         feedback.coded_size = 0;
344     }
345 
346     /* send feedback */
347     vrend_write_to_iovec(cdc->feed_res->iov, cdc->feed_res->num_iovs,
348                          0, (char *)(&feedback),
349                          MIN(cdc->feed_res->base.width0, sizeof(feedback)));
350 
351     cdc->dest_res = NULL;
352     cdc->feed_res = NULL;
353 }
354 
355 static struct virgl_video_callbacks video_callbacks = {
356     .decode_completed           = vrend_video_decode_completed,
357     .encode_upload_picture      = vrend_video_enocde_upload_picture,
358     .encode_completed           = vrend_video_encode_completed,
359 };
360 
vrend_video_init(int drm_fd)361 int vrend_video_init(int drm_fd)
362 {
363     if (drm_fd < 0)
364         return -1;
365 
366     return virgl_video_init(drm_fd, &video_callbacks, 0);
367 }
368 
vrend_video_fini(void)369 void vrend_video_fini(void)
370 {
371     virgl_video_destroy();
372 }
373 
vrend_video_fill_caps(union virgl_caps * caps)374 int vrend_video_fill_caps(union virgl_caps *caps)
375 {
376     return virgl_video_fill_caps(caps);
377 }
378 
vrend_video_create_codec(struct vrend_video_context * ctx,uint32_t handle,uint32_t profile,uint32_t entrypoint,uint32_t chroma_format,uint32_t level,uint32_t width,uint32_t height,uint32_t max_ref,uint32_t flags)379 int vrend_video_create_codec(struct vrend_video_context *ctx,
380                              uint32_t handle,
381                              uint32_t profile,
382                              uint32_t entrypoint,
383                              uint32_t chroma_format,
384                              uint32_t level,
385                              uint32_t width,
386                              uint32_t height,
387                              uint32_t max_ref,
388                              uint32_t flags)
389 {
390     struct vrend_video_codec *cdc = get_video_codec(ctx, handle);
391     struct virgl_video_create_codec_args args;
392 
393     if (cdc)
394         return 0;
395 
396     if (profile <= PIPE_VIDEO_PROFILE_UNKNOWN ||
397         profile >= PIPE_VIDEO_PROFILE_MAX)
398         return -1;
399 
400     if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_UNKNOWN ||
401         entrypoint > PIPE_VIDEO_ENTRYPOINT_ENCODE)
402         return -1;
403 
404     if (chroma_format >= PIPE_VIDEO_CHROMA_FORMAT_NONE)
405         return -1;
406 
407     if (!width || !height)
408         return -1;
409 
410     cdc = (struct vrend_video_codec *)calloc(1, sizeof(*cdc));
411     if (!cdc)
412         return -1;
413 
414     args.profile = profile;
415     args.entrypoint = entrypoint;
416     args.chroma_format = chroma_format;
417     args.level = level;
418     args.width = width;
419     args.height = height;
420     args.max_references = max_ref;
421     args.flags = flags;
422     args.opaque = cdc;
423     cdc->codec = virgl_video_create_codec(&args);
424     if (!cdc->codec) {
425         free(cdc);
426         return -1;
427     }
428 
429     cdc->handle = handle;
430     cdc->ctx = ctx;
431     list_add(&cdc->head, &ctx->codecs);
432 
433     return 0;
434 }
435 
destroy_video_codec(struct vrend_video_codec * cdc)436 static void destroy_video_codec(struct vrend_video_codec *cdc)
437 {
438     if (cdc) {
439         list_del(&cdc->head);
440         virgl_video_destroy_codec(cdc->codec);
441         free(cdc);
442     }
443 }
444 
vrend_video_destroy_codec(struct vrend_video_context * ctx,uint32_t handle)445 void vrend_video_destroy_codec(struct vrend_video_context *ctx,
446                                uint32_t handle)
447 {
448     struct vrend_video_codec *cdc = get_video_codec(ctx, handle);
449 
450     destroy_video_codec(cdc);
451 }
452 
vrend_video_create_buffer(struct vrend_video_context * ctx,uint32_t handle,uint32_t format,uint32_t width,uint32_t height,uint32_t * res_handles,unsigned int num_res)453 int vrend_video_create_buffer(struct vrend_video_context *ctx,
454                               uint32_t handle,
455                               uint32_t format,
456                               uint32_t width,
457                               uint32_t height,
458                               uint32_t *res_handles,
459                               unsigned int num_res)
460 {
461     unsigned i;
462     struct vrend_video_plane *plane;
463     struct vrend_video_buffer *buf = get_video_buffer(ctx, handle);
464     struct virgl_video_create_buffer_args args;
465 
466     if (buf)
467         return 0;
468 
469     if (format <= PIPE_FORMAT_NONE || format >= PIPE_FORMAT_COUNT)
470         return -1;
471 
472     if (!width || !height || !res_handles || !num_res)
473         return -1;
474 
475     buf = (struct vrend_video_buffer *)calloc(1, sizeof(*buf));
476     if (!buf)
477         return -1;
478 
479     args.format = format;
480     args.width = width;
481     args.height = height;
482     args.interlaced = 0;
483     args.opaque = buf;
484     buf->buffer = virgl_video_create_buffer(&args);
485     if (!buf->buffer) {
486         free(buf);
487         return -1;
488     }
489 
490     for (i = 0; i < ARRAY_SIZE(buf->planes); i++)
491         buf->planes[i].egl_image = EGL_NO_IMAGE_KHR;
492 
493     for (i = 0, buf->num_planes = 0;
494          i < num_res && buf->num_planes < ARRAY_SIZE(buf->planes); i++) {
495 
496         if (!res_handles[i])
497             continue;
498 
499         plane = &buf->planes[buf->num_planes++];
500         plane->res_handle = res_handles[i];
501         glGenFramebuffers(1, &plane->framebuffer);
502         glGenTextures(1, &plane->texture);
503         glBindTexture(GL_TEXTURE_2D, plane->texture);
504         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
505         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
506         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
507         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
508         glBindTexture(GL_TEXTURE_2D, 0);
509     }
510 
511     buf->handle = handle;
512     buf->ctx = ctx;
513     list_add(&buf->head, &ctx->buffers);
514 
515     return 0;
516 }
517 
destroy_video_buffer(struct vrend_video_buffer * buf)518 static void destroy_video_buffer(struct vrend_video_buffer *buf)
519 {
520     unsigned i;
521     struct vrend_video_plane *plane;
522 
523     if (!buf)
524         return;
525 
526     list_del(&buf->head);
527 
528     for (i = 0; i < buf->num_planes; i++) {
529         plane = &buf->planes[i];
530 
531         glDeleteTextures(1, &plane->texture);
532         glDeleteFramebuffers(1, &plane->framebuffer);
533         if (plane->egl_image == EGL_NO_IMAGE_KHR)
534             eglDestroyImageKHR(eglGetCurrentDisplay(), plane->egl_image);
535     }
536 
537     virgl_video_destroy_buffer(buf->buffer);
538 
539     free(buf);
540 }
541 
vrend_video_destroy_buffer(struct vrend_video_context * ctx,uint32_t handle)542 void vrend_video_destroy_buffer(struct vrend_video_context *ctx,
543                                 uint32_t handle)
544 {
545     struct vrend_video_buffer *buf = get_video_buffer(ctx, handle);
546 
547     destroy_video_buffer(buf);
548 }
549 
vrend_video_create_context(struct vrend_context * ctx)550 struct vrend_video_context *vrend_video_create_context(struct vrend_context *ctx)
551 {
552     struct vrend_video_context *vctx;
553 
554     vctx = (struct vrend_video_context *)calloc(1, sizeof(*vctx));
555     if (vctx) {
556         vctx->ctx = ctx;
557         list_inithead(&vctx->codecs);
558         list_inithead(&vctx->buffers);
559     }
560 
561     return vctx;
562 }
563 
vrend_video_destroy_context(struct vrend_video_context * ctx)564 void vrend_video_destroy_context(struct vrend_video_context *ctx)
565 {
566    struct vrend_video_codec *vcdc, *vcdc_tmp;
567    struct vrend_video_buffer *vbuf, *vbuf_tmp;
568 
569    LIST_FOR_EACH_ENTRY_SAFE(vcdc, vcdc_tmp, &ctx->codecs, head)
570       destroy_video_codec(vcdc);
571 
572    LIST_FOR_EACH_ENTRY_SAFE(vbuf, vbuf_tmp, &ctx->buffers, head)
573       destroy_video_buffer(vbuf);
574 
575    free(ctx);
576 }
577 
vrend_video_begin_frame(struct vrend_video_context * ctx,uint32_t cdc_handle,uint32_t tgt_handle)578 int vrend_video_begin_frame(struct vrend_video_context *ctx,
579                             uint32_t cdc_handle,
580                             uint32_t tgt_handle)
581 {
582     struct vrend_video_codec *cdc = get_video_codec(ctx, cdc_handle);
583     struct vrend_video_buffer *tgt = get_video_buffer(ctx, tgt_handle);
584 
585     if (!cdc || !tgt)
586         return -1;
587 
588     return virgl_video_begin_frame(cdc->codec, tgt->buffer);
589 }
590 
modify_h264_picture_desc(struct vrend_video_codec * cdc,struct vrend_video_buffer * tgt,struct virgl_h264_picture_desc * desc)591 static void modify_h264_picture_desc(struct vrend_video_codec *cdc,
592                                      struct vrend_video_buffer *tgt,
593                                      struct virgl_h264_picture_desc *desc)
594 {
595     unsigned i;
596     struct vrend_video_buffer *vbuf;
597 
598     (void)tgt;
599 
600     for (i = 0; i < ARRAY_SIZE(desc->buffer_id); i++) {
601         vbuf = get_video_buffer(cdc->ctx, desc->buffer_id[i]);
602         desc->buffer_id[i] = virgl_video_buffer_id(vbuf ? vbuf->buffer : NULL);
603     }
604 }
605 
modify_h265_picture_desc(struct vrend_video_codec * cdc,struct vrend_video_buffer * tgt,struct virgl_h265_picture_desc * desc)606 static void modify_h265_picture_desc(struct vrend_video_codec *cdc,
607                                      struct vrend_video_buffer *tgt,
608                                      struct virgl_h265_picture_desc *desc)
609 {
610     unsigned i;
611     struct vrend_video_buffer *vbuf;
612 
613     (void)tgt;
614 
615     for (i = 0; i < ARRAY_SIZE(desc->ref); i++) {
616         vbuf = get_video_buffer(cdc->ctx, desc->ref[i]);
617         desc->ref[i] = virgl_video_buffer_id(vbuf ? vbuf->buffer : NULL);
618     }
619 }
620 
modify_picture_desc(struct vrend_video_codec * cdc,struct vrend_video_buffer * tgt,union virgl_picture_desc * desc)621 static void modify_picture_desc(struct vrend_video_codec *cdc,
622                                 struct vrend_video_buffer *tgt,
623                                 union virgl_picture_desc *desc)
624 {
625     switch(virgl_video_codec_profile(cdc->codec)) {
626     case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
627     case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
628     case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
629     case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
630     case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
631     case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
632     case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422:
633     case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444:
634         modify_h264_picture_desc(cdc, tgt, &desc->h264);
635         break;
636     case PIPE_VIDEO_PROFILE_HEVC_MAIN:
637     case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
638     case PIPE_VIDEO_PROFILE_HEVC_MAIN_STILL:
639     case PIPE_VIDEO_PROFILE_HEVC_MAIN_12:
640     case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
641         modify_h265_picture_desc(cdc, tgt, &desc->h265);
642         break;
643     default:
644         break;
645     }
646 }
647 
vrend_video_decode_bitstream(struct vrend_video_context * ctx,uint32_t cdc_handle,uint32_t tgt_handle,uint32_t desc_handle,unsigned num_buffers,const uint32_t * buffer_handles,const uint32_t * buffer_sizes)648 int vrend_video_decode_bitstream(struct vrend_video_context *ctx,
649                                  uint32_t cdc_handle,
650                                  uint32_t tgt_handle,
651                                  uint32_t desc_handle,
652                                  unsigned num_buffers,
653                                  const uint32_t *buffer_handles,
654                                  const uint32_t *buffer_sizes)
655 {
656     int err = -1;
657     unsigned i, num_bs, *bs_sizes = NULL;
658     void **bs_buffers = NULL;
659     struct vrend_resource *res;
660     struct vrend_video_codec  *cdc = get_video_codec(ctx, cdc_handle);
661     struct vrend_video_buffer *tgt = get_video_buffer(ctx, tgt_handle);
662     union virgl_picture_desc desc;
663 
664     if (!cdc || !tgt)
665         return -1;
666 
667     bs_buffers = calloc(num_buffers, sizeof(void *));
668     if (!bs_buffers) {
669         vrend_printf("%s: alloc bs_buffers failed\n", __func__);
670         return -1;
671     }
672 
673     bs_sizes = calloc(num_buffers, sizeof(unsigned));
674     if (!bs_sizes) {
675         vrend_printf("%s: alloc bs_sizes failed\n", __func__);
676         goto err;
677     }
678 
679     for (i = 0, num_bs = 0; i < num_buffers; i++) {
680         res = vrend_renderer_ctx_res_lookup(ctx->ctx, buffer_handles[i]);
681         if (!res || !res->ptr) {
682             vrend_printf("%s: bs res %d invalid or not found",
683                          __func__, buffer_handles[i]);
684             continue;
685         }
686 
687         vrend_read_from_iovec(res->iov, res->num_iovs, 0,
688                               res->ptr, buffer_sizes[i]);
689         bs_buffers[num_bs] = res->ptr;
690         bs_sizes[num_bs] = buffer_sizes[i];
691         num_bs++;
692     }
693 
694     res = vrend_renderer_ctx_res_lookup(ctx->ctx, desc_handle);
695     if (!res) {
696         vrend_printf("%s: desc res %d not found\n", __func__, desc_handle);
697         goto err;
698     }
699     memset(&desc, 0, sizeof(desc));
700     vrend_read_from_iovec(res->iov, res->num_iovs, 0, (char *)(&desc),
701                           MIN(res->base.width0, sizeof(desc)));
702     modify_picture_desc(cdc, tgt, &desc);
703 
704     err = virgl_video_decode_bitstream(cdc->codec, tgt->buffer, &desc,
705                            num_bs, (const void * const *)bs_buffers, bs_sizes);
706 
707 err:
708     free(bs_buffers);
709     free(bs_sizes);
710 
711     return err;
712 }
713 
vrend_video_encode_bitstream(struct vrend_video_context * ctx,uint32_t cdc_handle,uint32_t src_handle,uint32_t dest_handle,uint32_t desc_handle,uint32_t feed_handle)714 int vrend_video_encode_bitstream(struct vrend_video_context *ctx,
715                                  uint32_t cdc_handle,
716                                  uint32_t src_handle,
717                                  uint32_t dest_handle,
718                                  uint32_t desc_handle,
719                                  uint32_t feed_handle)
720 {
721     union virgl_picture_desc desc;
722     struct vrend_resource *dest_res, *desc_res, *feed_res;
723     struct vrend_video_codec  *cdc = get_video_codec(ctx, cdc_handle);
724     struct vrend_video_buffer *src = get_video_buffer(ctx, src_handle);
725 
726     if (!cdc || !src)
727         return -1;
728 
729     /* Feedback resource */
730     feed_res = vrend_renderer_ctx_res_lookup(ctx->ctx, feed_handle);
731     if (!feed_res) {
732         vrend_printf("%s: feedback res %d not found\n", __func__, feed_handle);
733         return -1;
734     }
735 
736     /* Picture descriptor resource */
737     desc_res = vrend_renderer_ctx_res_lookup(ctx->ctx, desc_handle);
738     if (!desc_res) {
739         vrend_printf("%s: desc res %d not found\n", __func__, desc_handle);
740         return -1;
741     }
742     memset(&desc, 0, sizeof(desc));
743     vrend_read_from_iovec(desc_res->iov, desc_res->num_iovs, 0, (char *)(&desc),
744                           MIN(desc_res->base.width0, sizeof(desc)));
745 
746     /* Destination buffer resource. */
747     dest_res = vrend_renderer_ctx_res_lookup(ctx->ctx, dest_handle);
748     if (!dest_res) {
749         vrend_printf("%s: dest res %d not found\n", __func__, dest_handle);
750         return -1;
751     }
752 
753     cdc->feed_res = feed_res;
754     cdc->dest_res = dest_res;
755 
756     return virgl_video_encode_bitstream(cdc->codec, src->buffer, &desc);
757 }
758 
vrend_video_end_frame(struct vrend_video_context * ctx,uint32_t cdc_handle,uint32_t tgt_handle)759 int vrend_video_end_frame(struct vrend_video_context *ctx,
760                           uint32_t cdc_handle,
761                           uint32_t tgt_handle)
762 {
763     struct vrend_video_codec *cdc = get_video_codec(ctx, cdc_handle);
764     struct vrend_video_buffer *tgt = get_video_buffer(ctx, tgt_handle);
765 
766     if (!cdc || !tgt)
767         return -1;
768 
769     return virgl_video_end_frame(cdc->codec, tgt->buffer);
770 }
771 
772