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