1 /*
2 * Copyright © 2018 Renesas Electronics Corp.
3 *
4 * Based on vaapi-recorder by:
5 * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
6 * Copyright © 2013 Intel Corporation
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial
18 * portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 *
29 * Authors: IGEL Co., Ltd.
30 */
31
32 #include "config.h"
33
34 #include <stdint.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39
40 #include <gst/gst.h>
41 #include <gst/allocators/gstdmabuf.h>
42 #include <gst/app/gstappsrc.h>
43 #include <gst/video/gstvideometa.h>
44 #include <drm_fourcc.h>
45
46 #include "remoting-plugin.h"
47 #include <libweston/backend-drm.h>
48 #include "shared/helpers.h"
49 #include "shared/timespec-util.h"
50 #include "backend.h"
51 #include "libweston-internal.h"
52
53 #define MAX_RETRY_COUNT 3
54
55 struct weston_remoting {
56 struct weston_compositor *compositor;
57 struct wl_list output_list;
58 struct wl_listener destroy_listener;
59 const struct weston_drm_virtual_output_api *virtual_output_api;
60
61 GstAllocator *allocator;
62 };
63
64 struct remoted_gstpipe {
65 int readfd;
66 int writefd;
67 struct wl_event_source *source;
68 };
69
70 /* supported gbm format list */
71 struct remoted_output_support_gbm_format {
72 /* GBM_FORMAT_* tokens are strictly aliased with DRM_FORMAT_*, so we
73 * use the latter to avoid a dependency on GBM */
74 uint32_t gbm_format;
75 const char *gst_format_string;
76 GstVideoFormat gst_video_format;
77 };
78
79 static const struct remoted_output_support_gbm_format supported_formats[] = {
80 {
81 .gbm_format = DRM_FORMAT_XRGB8888,
82 .gst_format_string = "BGRx",
83 .gst_video_format = GST_VIDEO_FORMAT_BGRx,
84 }, {
85 .gbm_format = DRM_FORMAT_RGB565,
86 .gst_format_string = "RGB16",
87 .gst_video_format = GST_VIDEO_FORMAT_RGB16,
88 }, {
89 .gbm_format = DRM_FORMAT_XRGB2101010,
90 .gst_format_string = "r210",
91 .gst_video_format = GST_VIDEO_FORMAT_r210,
92 }
93 };
94
95 struct remoted_output {
96 struct weston_output *output;
97 void (*saved_destroy)(struct weston_output *output);
98 int (*saved_enable)(struct weston_output *output);
99 int (*saved_disable)(struct weston_output *output);
100 int (*saved_start_repaint_loop)(struct weston_output *output);
101
102 char *host;
103 int port;
104 char *gst_pipeline;
105 const struct remoted_output_support_gbm_format *format;
106
107 struct weston_head *head;
108
109 struct weston_remoting *remoting;
110 struct wl_event_source *finish_frame_timer;
111 struct wl_list link;
112 bool submitted_frame;
113 int fence_sync_fd;
114 struct wl_event_source *fence_sync_event_source;
115
116 GstElement *pipeline;
117 GstAppSrc *appsrc;
118 GstBus *bus;
119 struct remoted_gstpipe gstpipe;
120 GstClockTime start_time;
121 int retry_count;
122 enum dpms_enum dpms;
123 };
124
125 struct mem_free_cb_data {
126 struct remoted_output *output;
127 struct drm_fb *output_buffer;
128 };
129
130 struct gst_frame_buffer_data {
131 struct remoted_output *output;
132 GstBuffer *buffer;
133 };
134
135 /* message type for pipe */
136 #define GSTPIPE_MSG_BUS_SYNC 1
137 #define GSTPIPE_MSG_BUFFER_RELEASE 2
138
139 struct gstpipe_msg_data {
140 int type;
141 void *data;
142 };
143
144 static int
remoting_gst_init(struct weston_remoting * remoting)145 remoting_gst_init(struct weston_remoting *remoting)
146 {
147 GError *err = NULL;
148
149 if (!gst_init_check(NULL, NULL, &err)) {
150 weston_log("GStreamer initialization error: %s\n",
151 err->message);
152 g_error_free(err);
153 return -1;
154 }
155
156 remoting->allocator = gst_dmabuf_allocator_new();
157
158 return 0;
159 }
160
161 static void
remoting_gst_deinit(struct weston_remoting * remoting)162 remoting_gst_deinit(struct weston_remoting *remoting)
163 {
164 gst_object_unref(remoting->allocator);
165 }
166
167 static GstBusSyncReply
remoting_gst_bus_sync_handler(GstBus * bus,GstMessage * message,gpointer user_data)168 remoting_gst_bus_sync_handler(GstBus *bus, GstMessage *message,
169 gpointer user_data)
170 {
171 struct remoted_gstpipe *pipe = user_data;
172 struct gstpipe_msg_data msg = {
173 .type = GSTPIPE_MSG_BUS_SYNC,
174 .data = NULL
175 };
176 ssize_t ret;
177
178 ret = write(pipe->writefd, &msg, sizeof(msg));
179 if (ret != sizeof(msg))
180 weston_log("ERROR: failed to write, ret=%zd, errno=%d\n",
181 ret, errno);
182
183 return GST_BUS_PASS;
184 }
185
186 static int
remoting_gst_pipeline_init(struct remoted_output * output)187 remoting_gst_pipeline_init(struct remoted_output *output)
188 {
189 GstCaps *caps;
190 GError *err = NULL;
191 GstStateChangeReturn ret;
192 struct weston_mode *mode = output->output->current_mode;
193
194 if (!output->gst_pipeline) {
195 char pipeline_str[1024];
196 /* TODO: use encodebin instead of jpegenc */
197 snprintf(pipeline_str, sizeof(pipeline_str),
198 "rtpbin name=rtpbin "
199 "appsrc name=src ! videoconvert ! "
200 "video/x-raw,format=I420 ! jpegenc ! rtpjpegpay ! "
201 "rtpbin.send_rtp_sink_0 "
202 "rtpbin.send_rtp_src_0 ! "
203 "udpsink name=sink host=%s port=%d "
204 "rtpbin.send_rtcp_src_0 ! "
205 "udpsink host=%s port=%d sync=false async=false "
206 "udpsrc port=%d ! rtpbin.recv_rtcp_sink_0",
207 output->host, output->port, output->host,
208 output->port + 1, output->port + 2);
209 output->gst_pipeline = strdup(pipeline_str);
210 }
211 weston_log("GST pipeline: %s\n", output->gst_pipeline);
212
213 output->pipeline = gst_parse_launch(output->gst_pipeline, &err);
214 if (!output->pipeline) {
215 weston_log("Could not create gstreamer pipeline. Error: %s\n",
216 err->message);
217 g_error_free(err);
218 return -1;
219 }
220
221 output->appsrc = (GstAppSrc*)
222 gst_bin_get_by_name(GST_BIN(output->pipeline), "src");
223 if (!output->appsrc) {
224 weston_log("Could not get appsrc from gstreamer pipeline\n");
225 goto err;
226 }
227
228 /* check sink */
229 if (!gst_bin_get_by_name(GST_BIN(output->pipeline), "sink")) {
230 weston_log("Could not get sink from gstreamer pipeline\n");
231 goto err;
232 }
233
234 caps = gst_caps_new_simple("video/x-raw",
235 "format", G_TYPE_STRING,
236 output->format->gst_format_string,
237 "width", G_TYPE_INT, mode->width,
238 "height", G_TYPE_INT, mode->height,
239 "framerate", GST_TYPE_FRACTION,
240 mode->refresh, 1000,
241 NULL);
242 if (!caps) {
243 weston_log("Could not create gstreamer caps.\n");
244 goto err;
245 }
246 g_object_set(G_OBJECT(output->appsrc),
247 "caps", caps,
248 "stream-type", 0,
249 "format", GST_FORMAT_TIME,
250 "is-live", TRUE,
251 NULL);
252 gst_caps_unref(caps);
253
254 output->bus = gst_pipeline_get_bus(GST_PIPELINE(output->pipeline));
255 if (!output->bus) {
256 weston_log("Could not get bus from gstreamer pipeline\n");
257 goto err;
258 }
259 gst_bus_set_sync_handler(output->bus, remoting_gst_bus_sync_handler,
260 &output->gstpipe, NULL);
261
262 output->start_time = 0;
263 ret = gst_element_set_state(output->pipeline, GST_STATE_PLAYING);
264 if (ret == GST_STATE_CHANGE_FAILURE) {
265 weston_log("Couldn't set GST_STATE_PLAYING to pipeline\n");
266 goto err;
267 }
268
269 return 0;
270
271 err:
272 gst_object_unref(GST_OBJECT(output->pipeline));
273 output->pipeline = NULL;
274 return -1;
275 }
276
277 static void
remoting_gst_pipeline_deinit(struct remoted_output * output)278 remoting_gst_pipeline_deinit(struct remoted_output *output)
279 {
280 if (!output->pipeline)
281 return;
282
283 gst_element_set_state(output->pipeline, GST_STATE_NULL);
284 if (output->bus)
285 gst_object_unref(GST_OBJECT(output->bus));
286 gst_object_unref(GST_OBJECT(output->pipeline));
287 output->pipeline = NULL;
288 }
289
290 static int
291 remoting_output_disable(struct weston_output *output);
292
293 static void
remoting_gst_restart(void * data)294 remoting_gst_restart(void *data)
295 {
296 struct remoted_output *output = data;
297
298 if (remoting_gst_pipeline_init(output) < 0) {
299 weston_log("gst: Could not restart pipeline!!\n");
300 remoting_output_disable(output->output);
301 }
302 }
303
304 static void
remoting_gst_schedule_restart(struct remoted_output * output)305 remoting_gst_schedule_restart(struct remoted_output *output)
306 {
307 struct wl_event_loop *loop;
308 struct weston_compositor *c = output->remoting->compositor;
309
310 loop = wl_display_get_event_loop(c->wl_display);
311 wl_event_loop_add_idle(loop, remoting_gst_restart, output);
312 }
313
314 static void
remoting_gst_bus_message_handler(struct remoted_output * output)315 remoting_gst_bus_message_handler(struct remoted_output *output)
316 {
317 GstMessage *message;
318 GError *error;
319 gchar *debug;
320
321 /* get message from bus queue */
322 message = gst_bus_pop(output->bus);
323 if (!message)
324 return;
325
326 switch (GST_MESSAGE_TYPE(message)) {
327 case GST_MESSAGE_STATE_CHANGED: {
328 GstState new_state;
329 gst_message_parse_state_changed(message, NULL, &new_state,
330 NULL);
331 if (!strcmp(GST_OBJECT_NAME(message->src), "sink") &&
332 new_state == GST_STATE_PLAYING)
333 output->retry_count = 0;
334 break;
335 }
336 case GST_MESSAGE_WARNING:
337 gst_message_parse_warning(message, &error, &debug);
338 weston_log("gst: Warning: %s: %s\n",
339 GST_OBJECT_NAME(message->src), error->message);
340 break;
341 case GST_MESSAGE_ERROR:
342 gst_message_parse_error(message, &error, &debug);
343 weston_log("gst: Error: %s: %s\n",
344 GST_OBJECT_NAME(message->src), error->message);
345 if (output->retry_count < MAX_RETRY_COUNT) {
346 output->retry_count++;
347 remoting_gst_pipeline_deinit(output);
348 remoting_gst_schedule_restart(output);
349 } else {
350 remoting_output_disable(output->output);
351 }
352 break;
353 default:
354 break;
355 }
356 }
357
358 static void
remoting_output_buffer_release(struct remoted_output * output,void * buffer)359 remoting_output_buffer_release(struct remoted_output *output, void *buffer)
360 {
361 const struct weston_drm_virtual_output_api *api
362 = output->remoting->virtual_output_api;
363
364 api->buffer_released(buffer);
365 }
366
367 static int
remoting_gstpipe_handler(int fd,uint32_t mask,void * data)368 remoting_gstpipe_handler(int fd, uint32_t mask, void *data)
369 {
370 ssize_t ret;
371 struct gstpipe_msg_data msg;
372 struct remoted_output *output = data;
373
374 /* receive message */
375 ret = read(fd, &msg, sizeof(msg));
376 if (ret != sizeof(msg)) {
377 weston_log("ERROR: failed to read, ret=%zd, errno=%d\n",
378 ret, errno);
379 remoting_output_disable(output->output);
380 return 0;
381 }
382
383 switch (msg.type) {
384 case GSTPIPE_MSG_BUS_SYNC:
385 remoting_gst_bus_message_handler(output);
386 break;
387 case GSTPIPE_MSG_BUFFER_RELEASE:
388 remoting_output_buffer_release(output, msg.data);
389 break;
390 default:
391 weston_log("Received unknown message! msg=%d\n", msg.type);
392 }
393 return 1;
394 }
395
396 static int
remoting_gstpipe_init(struct weston_compositor * c,struct remoted_output * output)397 remoting_gstpipe_init(struct weston_compositor *c,
398 struct remoted_output *output)
399 {
400 struct wl_event_loop *loop;
401 int fd[2];
402
403 if (pipe2(fd, O_CLOEXEC) == -1)
404 return -1;
405
406 output->gstpipe.readfd = fd[0];
407 output->gstpipe.writefd = fd[1];
408 loop = wl_display_get_event_loop(c->wl_display);
409 output->gstpipe.source =
410 wl_event_loop_add_fd(loop, output->gstpipe.readfd,
411 WL_EVENT_READABLE,
412 remoting_gstpipe_handler, output);
413 if (!output->gstpipe.source) {
414 close(fd[0]);
415 close(fd[1]);
416 return -1;
417 }
418
419 return 0;
420 }
421
422 static void
remoting_gstpipe_release(struct remoted_gstpipe * pipe)423 remoting_gstpipe_release(struct remoted_gstpipe *pipe)
424 {
425 wl_event_source_remove(pipe->source);
426 close(pipe->readfd);
427 close(pipe->writefd);
428 }
429
430 static void
431 remoting_output_destroy(struct weston_output *output);
432
433 static void
weston_remoting_destroy(struct wl_listener * l,void * data)434 weston_remoting_destroy(struct wl_listener *l, void *data)
435 {
436 struct weston_remoting *remoting =
437 container_of(l, struct weston_remoting, destroy_listener);
438 struct remoted_output *output, *next;
439
440 wl_list_for_each_safe(output, next, &remoting->output_list, link)
441 remoting_output_destroy(output->output);
442
443 /* Finalize gstreamer */
444 remoting_gst_deinit(remoting);
445
446 wl_list_remove(&remoting->destroy_listener.link);
447 free(remoting);
448 }
449
450 static struct weston_remoting *
weston_remoting_get(struct weston_compositor * compositor)451 weston_remoting_get(struct weston_compositor *compositor)
452 {
453 struct wl_listener *listener;
454 struct weston_remoting *remoting;
455
456 listener = wl_signal_get(&compositor->destroy_signal,
457 weston_remoting_destroy);
458 if (!listener)
459 return NULL;
460
461 remoting = wl_container_of(listener, remoting, destroy_listener);
462 return remoting;
463 }
464
465 static int
remoting_output_finish_frame_handler(void * data)466 remoting_output_finish_frame_handler(void *data)
467 {
468 struct remoted_output *output = data;
469 const struct weston_drm_virtual_output_api *api
470 = output->remoting->virtual_output_api;
471 struct timespec now;
472 int64_t msec;
473
474 if (output->submitted_frame) {
475 struct weston_compositor *c = output->remoting->compositor;
476 output->submitted_frame = false;
477 weston_compositor_read_presentation_clock(c, &now);
478 api->finish_frame(output->output, &now, 0);
479 }
480
481 if (output->dpms == WESTON_DPMS_ON) {
482 msec = millihz_to_nsec(output->output->current_mode->refresh) / 1000000;
483 wl_event_source_timer_update(output->finish_frame_timer, msec);
484 } else {
485 wl_event_source_timer_update(output->finish_frame_timer, 0);
486 }
487 return 0;
488 }
489
490 static void
remoting_gst_mem_free_cb(struct mem_free_cb_data * cb_data,GstMiniObject * obj)491 remoting_gst_mem_free_cb(struct mem_free_cb_data *cb_data, GstMiniObject *obj)
492 {
493 struct remoted_output *output = cb_data->output;
494 struct remoted_gstpipe *pipe = &output->gstpipe;
495 struct gstpipe_msg_data msg = {
496 .type = GSTPIPE_MSG_BUFFER_RELEASE,
497 .data = cb_data->output_buffer
498 };
499 ssize_t ret;
500
501 ret = write(pipe->writefd, &msg, sizeof(msg));
502 if (ret != sizeof(msg))
503 weston_log("ERROR: failed to write, ret=%zd, errno=%d\n", ret,
504 errno);
505 free(cb_data);
506 }
507
508 static struct remoted_output *
lookup_remoted_output(struct weston_output * output)509 lookup_remoted_output(struct weston_output *output)
510 {
511 struct weston_compositor *c = output->compositor;
512 struct weston_remoting *remoting = weston_remoting_get(c);
513 struct remoted_output *remoted_output;
514
515 wl_list_for_each(remoted_output, &remoting->output_list, link) {
516 if (remoted_output->output == output)
517 return remoted_output;
518 }
519
520 weston_log("%s: %s: could not find output\n", __FILE__, __func__);
521 return NULL;
522 }
523
524 static void
remoting_output_gst_push_buffer(struct remoted_output * output,GstBuffer * buffer)525 remoting_output_gst_push_buffer(struct remoted_output *output,
526 GstBuffer *buffer)
527 {
528 struct timespec current_frame_ts;
529 GstClockTime ts, current_frame_time;
530
531 weston_compositor_read_presentation_clock(output->remoting->compositor,
532 ¤t_frame_ts);
533 current_frame_time = GST_TIMESPEC_TO_TIME(current_frame_ts);
534 if (output->start_time == 0)
535 output->start_time = current_frame_time;
536 ts = current_frame_time - output->start_time;
537
538 if (GST_CLOCK_TIME_IS_VALID(ts))
539 GST_BUFFER_PTS(buffer) = ts;
540 else
541 GST_BUFFER_PTS(buffer) = GST_CLOCK_TIME_NONE;
542 GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE;
543
544 gst_app_src_push_buffer(output->appsrc, buffer);
545 output->submitted_frame = true;
546 }
547
548 static int
remoting_output_fence_sync_handler(int fd,uint32_t mask,void * data)549 remoting_output_fence_sync_handler(int fd, uint32_t mask, void *data)
550 {
551 struct gst_frame_buffer_data *frame_data = data;
552 struct remoted_output *output = frame_data->output;
553
554 remoting_output_gst_push_buffer(output, frame_data->buffer);
555
556 wl_event_source_remove(output->fence_sync_event_source);
557 close(output->fence_sync_fd);
558 free(frame_data);
559
560 return 0;
561 }
562
563 static int
remoting_output_frame(struct weston_output * output_base,int fd,int stride,struct drm_fb * output_buffer)564 remoting_output_frame(struct weston_output *output_base, int fd, int stride,
565 struct drm_fb *output_buffer)
566 {
567 struct remoted_output *output = lookup_remoted_output(output_base);
568 struct weston_remoting *remoting = output->remoting;
569 struct weston_mode *mode;
570 const struct weston_drm_virtual_output_api *api
571 = output->remoting->virtual_output_api;
572 struct wl_event_loop *loop;
573 GstBuffer *buf;
574 GstMemory *mem;
575 gsize offset = 0;
576 struct mem_free_cb_data *cb_data;
577 struct gst_frame_buffer_data *frame_data;
578
579 if (!output)
580 return -1;
581
582 cb_data = zalloc(sizeof *cb_data);
583 if (!cb_data)
584 return -1;
585
586 mode = output->output->current_mode;
587 buf = gst_buffer_new();
588 mem = gst_dmabuf_allocator_alloc(remoting->allocator, fd,
589 stride * mode->height);
590 gst_buffer_append_memory(buf, mem);
591 gst_buffer_add_video_meta_full(buf,
592 GST_VIDEO_FRAME_FLAG_NONE,
593 output->format->gst_video_format,
594 mode->width,
595 mode->height,
596 1,
597 &offset,
598 &stride);
599
600 cb_data->output = output;
601 cb_data->output_buffer = output_buffer;
602 gst_mini_object_weak_ref(GST_MINI_OBJECT(mem),
603 (GstMiniObjectNotify)remoting_gst_mem_free_cb,
604 cb_data);
605
606 output->fence_sync_fd = api->get_fence_sync_fd(output->output);
607 /* Push buffer to gstreamer immediately on get_fence_sync_fd failure */
608 if (output->fence_sync_fd == -1) {
609 remoting_output_gst_push_buffer(output, buf);
610 return 0;
611 }
612
613 frame_data = zalloc(sizeof *frame_data);
614 if (!frame_data) {
615 close(output->fence_sync_fd);
616 remoting_output_gst_push_buffer(output, buf);
617 return 0;
618 }
619
620 frame_data->output = output;
621 frame_data->buffer = buf;
622 loop = wl_display_get_event_loop(remoting->compositor->wl_display);
623 output->fence_sync_event_source =
624 wl_event_loop_add_fd(loop, output->fence_sync_fd,
625 WL_EVENT_READABLE,
626 remoting_output_fence_sync_handler,
627 frame_data);
628
629 return 0;
630 }
631
632 static void
remoting_output_destroy(struct weston_output * output)633 remoting_output_destroy(struct weston_output *output)
634 {
635 struct remoted_output *remoted_output = lookup_remoted_output(output);
636 struct weston_mode *mode, *next;
637
638 wl_list_for_each_safe(mode, next, &output->mode_list, link) {
639 wl_list_remove(&mode->link);
640 free(mode);
641 }
642
643 remoted_output->saved_destroy(output);
644
645 remoting_gst_pipeline_deinit(remoted_output);
646 remoting_gstpipe_release(&remoted_output->gstpipe);
647
648 if (remoted_output->host)
649 free(remoted_output->host);
650 if (remoted_output->gst_pipeline)
651 free(remoted_output->gst_pipeline);
652
653 wl_list_remove(&remoted_output->link);
654 weston_head_release(remoted_output->head);
655 free(remoted_output->head);
656 free(remoted_output);
657 }
658
659 static int
remoting_output_start_repaint_loop(struct weston_output * output)660 remoting_output_start_repaint_loop(struct weston_output *output)
661 {
662 struct remoted_output *remoted_output = lookup_remoted_output(output);
663 int64_t msec;
664
665 remoted_output->saved_start_repaint_loop(output);
666
667 msec = millihz_to_nsec(remoted_output->output->current_mode->refresh)
668 / 1000000;
669 wl_event_source_timer_update(remoted_output->finish_frame_timer, msec);
670
671 return 0;
672 }
673
674 static void
remoting_output_set_dpms(struct weston_output * base_output,enum dpms_enum level)675 remoting_output_set_dpms(struct weston_output *base_output, enum dpms_enum level)
676 {
677 struct remoted_output *output = lookup_remoted_output(base_output);
678
679 if (output->dpms == level)
680 return;
681
682 output->dpms = level;
683 remoting_output_finish_frame_handler(output);
684 }
685
686 static int
remoting_output_enable(struct weston_output * output)687 remoting_output_enable(struct weston_output *output)
688 {
689 struct remoted_output *remoted_output = lookup_remoted_output(output);
690 struct weston_compositor *c = output->compositor;
691 const struct weston_drm_virtual_output_api *api
692 = remoted_output->remoting->virtual_output_api;
693 struct wl_event_loop *loop;
694 int ret;
695
696 api->set_submit_frame_cb(output, remoting_output_frame);
697
698 ret = remoted_output->saved_enable(output);
699 if (ret < 0)
700 return ret;
701
702 remoted_output->saved_start_repaint_loop = output->start_repaint_loop;
703 output->start_repaint_loop = remoting_output_start_repaint_loop;
704 output->set_dpms = remoting_output_set_dpms;
705
706 ret = remoting_gst_pipeline_init(remoted_output);
707 if (ret < 0) {
708 remoted_output->saved_disable(output);
709 return ret;
710 }
711
712 loop = wl_display_get_event_loop(c->wl_display);
713 remoted_output->finish_frame_timer =
714 wl_event_loop_add_timer(loop,
715 remoting_output_finish_frame_handler,
716 remoted_output);
717
718 remoted_output->dpms = WESTON_DPMS_ON;
719 return 0;
720 }
721
722 static int
remoting_output_disable(struct weston_output * output)723 remoting_output_disable(struct weston_output *output)
724 {
725 struct remoted_output *remoted_output = lookup_remoted_output(output);
726
727 wl_event_source_remove(remoted_output->finish_frame_timer);
728 remoting_gst_pipeline_deinit(remoted_output);
729
730 return remoted_output->saved_disable(output);
731 }
732
733 static struct weston_output *
remoting_output_create(struct weston_compositor * c,char * name)734 remoting_output_create(struct weston_compositor *c, char *name)
735 {
736 struct weston_remoting *remoting = weston_remoting_get(c);
737 struct remoted_output *output;
738 struct weston_head *head;
739 const struct weston_drm_virtual_output_api *api;
740 const char *make = "Renesas";
741 const char *model = "Virtual Display";
742 const char *serial_number = "unknown";
743 const char *connector_name = "remoting";
744
745 if (!name || !strlen(name))
746 return NULL;
747
748 api = remoting->virtual_output_api;
749
750 output = zalloc(sizeof *output);
751 if (!output)
752 return NULL;
753
754 head = zalloc(sizeof *head);
755 if (!head)
756 goto err;
757
758 if (remoting_gstpipe_init(c, output) < 0) {
759 weston_log("Can not create pipe for gstreamer\n");
760 goto err;
761 }
762
763 output->output = api->create_output(c, name);
764 if (!output->output) {
765 weston_log("Can not create virtual output\n");
766 goto err;
767 }
768
769 output->saved_destroy = output->output->destroy;
770 output->output->destroy = remoting_output_destroy;
771 output->saved_enable = output->output->enable;
772 output->output->enable = remoting_output_enable;
773 output->saved_disable = output->output->disable;
774 output->output->disable = remoting_output_disable;
775 output->remoting = remoting;
776 wl_list_insert(remoting->output_list.prev, &output->link);
777
778 weston_head_init(head, connector_name);
779 weston_head_set_subpixel(head, WL_OUTPUT_SUBPIXEL_NONE);
780 weston_head_set_monitor_strings(head, make, model, serial_number);
781 head->compositor = c;
782
783 weston_output_attach_head(output->output, head);
784 output->head = head;
785
786 /* set XRGB8888 format */
787 output->format = &supported_formats[0];
788
789 return output->output;
790
791 err:
792 if (output->gstpipe.source)
793 remoting_gstpipe_release(&output->gstpipe);
794 if (head)
795 free(head);
796 free(output);
797 return NULL;
798 }
799
800 static bool
remoting_output_is_remoted(struct weston_output * output)801 remoting_output_is_remoted(struct weston_output *output)
802 {
803 struct remoted_output *remoted_output = lookup_remoted_output(output);
804
805 if (remoted_output)
806 return true;
807
808 return false;
809 }
810
811 static int
remoting_output_set_mode(struct weston_output * output,const char * modeline)812 remoting_output_set_mode(struct weston_output *output, const char *modeline)
813 {
814 struct weston_mode *mode;
815 int n, width, height, refresh = 0;
816
817 if (!remoting_output_is_remoted(output)) {
818 weston_log("Output is not remoted.\n");
819 return -1;
820 }
821
822 if (!modeline)
823 return -1;
824
825 n = sscanf(modeline, "%dx%d@%d", &width, &height, &refresh);
826 if (n != 2 && n != 3)
827 return -1;
828
829 mode = zalloc(sizeof *mode);
830 if (!mode)
831 return -1;
832
833 mode->flags = WL_OUTPUT_MODE_CURRENT;
834 mode->width = width;
835 mode->height = height;
836 mode->refresh = (refresh ? refresh : 60) * 1000LL;
837
838 wl_list_insert(output->mode_list.prev, &mode->link);
839
840 output->current_mode = mode;
841
842 return 0;
843 }
844
845 static void
remoting_output_set_gbm_format(struct weston_output * output,const char * gbm_format)846 remoting_output_set_gbm_format(struct weston_output *output,
847 const char *gbm_format)
848 {
849 struct remoted_output *remoted_output = lookup_remoted_output(output);
850 const struct weston_drm_virtual_output_api *api;
851 uint32_t format, i;
852
853 if (!remoted_output)
854 return;
855
856 api = remoted_output->remoting->virtual_output_api;
857 format = api->set_gbm_format(output, gbm_format);
858
859 for (i = 0; i < ARRAY_LENGTH(supported_formats); i++) {
860 if (format == supported_formats[i].gbm_format) {
861 remoted_output->format = &supported_formats[i];
862 return;
863 }
864 }
865 }
866
867 static void
remoting_output_set_seat(struct weston_output * output,const char * seat)868 remoting_output_set_seat(struct weston_output *output, const char *seat)
869 {
870 /* for now, nothing todo */
871 }
872
873 static void
remoting_output_set_host(struct weston_output * output,char * host)874 remoting_output_set_host(struct weston_output *output, char *host)
875 {
876 struct remoted_output *remoted_output = lookup_remoted_output(output);
877
878 if (!remoted_output)
879 return;
880
881 if (remoted_output->host)
882 free(remoted_output->host);
883 remoted_output->host = strdup(host);
884 }
885
886 static void
remoting_output_set_port(struct weston_output * output,int port)887 remoting_output_set_port(struct weston_output *output, int port)
888 {
889 struct remoted_output *remoted_output = lookup_remoted_output(output);
890
891 if (remoted_output)
892 remoted_output->port = port;
893 }
894
895 static void
remoting_output_set_gst_pipeline(struct weston_output * output,char * gst_pipeline)896 remoting_output_set_gst_pipeline(struct weston_output *output,
897 char *gst_pipeline)
898 {
899 struct remoted_output *remoted_output = lookup_remoted_output(output);
900
901 if (!remoted_output)
902 return;
903
904 if (remoted_output->gst_pipeline)
905 free(remoted_output->gst_pipeline);
906 remoted_output->gst_pipeline = strdup(gst_pipeline);
907 }
908
909 static const struct weston_remoting_api remoting_api = {
910 remoting_output_create,
911 remoting_output_is_remoted,
912 remoting_output_set_mode,
913 remoting_output_set_gbm_format,
914 remoting_output_set_seat,
915 remoting_output_set_host,
916 remoting_output_set_port,
917 remoting_output_set_gst_pipeline,
918 };
919
920 WL_EXPORT int
weston_module_init(struct weston_compositor * compositor)921 weston_module_init(struct weston_compositor *compositor)
922 {
923 int ret;
924 struct weston_remoting *remoting;
925 const struct weston_drm_virtual_output_api *api =
926 weston_drm_virtual_output_get_api(compositor);
927
928 if (!api)
929 return -1;
930
931 remoting = zalloc(sizeof *remoting);
932 if (!remoting)
933 return -1;
934
935 if (!weston_compositor_add_destroy_listener_once(compositor,
936 &remoting->destroy_listener,
937 weston_remoting_destroy)) {
938 free(remoting);
939 return 0;
940 }
941
942 remoting->virtual_output_api = api;
943 remoting->compositor = compositor;
944 wl_list_init(&remoting->output_list);
945
946 ret = weston_plugin_api_register(compositor, WESTON_REMOTING_API_NAME,
947 &remoting_api, sizeof(remoting_api));
948
949 if (ret < 0) {
950 weston_log("Failed to register remoting API.\n");
951 goto failed;
952 }
953
954 /* Initialize gstreamer */
955 ret = remoting_gst_init(remoting);
956 if (ret < 0) {
957 weston_log("Failed to initialize gstreamer.\n");
958 goto failed;
959 }
960
961 return 0;
962
963 failed:
964 wl_list_remove(&remoting->destroy_listener.link);
965 free(remoting);
966 return -1;
967 }
968