• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 						  &current_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