1 /*
2 * Copyright (C) 2011 Intel Corporation.
3 * Copyright (C) 2016-2020 Red Hat
4 * Copyright (c) 2018,2019 DisplayLink (UK) Ltd.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 */
27
28 #include "config.h"
29
30 #include "backends/native/meta-onscreen-native.h"
31
32 #include <drm_fourcc.h>
33
34 #include "backends/meta-egl-ext.h"
35 #include "backends/native/meta-cogl-utils.h"
36 #include "backends/native/meta-crtc-kms.h"
37 #include "backends/native/meta-device-pool.h"
38 #include "backends/native/meta-drm-buffer-dumb.h"
39 #include "backends/native/meta-drm-buffer-gbm.h"
40 #include "backends/native/meta-drm-buffer-import.h"
41 #include "backends/native/meta-drm-buffer.h"
42 #include "backends/native/meta-kms-device.h"
43 #include "backends/native/meta-kms-utils.h"
44 #include "backends/native/meta-kms.h"
45 #include "backends/native/meta-output-kms.h"
46 #include "backends/native/meta-renderer-native-gles3.h"
47 #include "backends/native/meta-renderer-native-private.h"
48
49 typedef enum _MetaSharedFramebufferImportStatus
50 {
51 /* Not tried importing yet. */
52 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE,
53 /* Tried before and failed. */
54 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED,
55 /* Tried before and succeeded. */
56 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK
57 } MetaSharedFramebufferImportStatus;
58
59 typedef struct _MetaOnscreenNativeSecondaryGpuState
60 {
61 MetaGpuKms *gpu_kms;
62 MetaRendererNativeGpuData *renderer_gpu_data;
63
64 EGLSurface egl_surface;
65
66 struct {
67 struct gbm_surface *surface;
68 MetaDrmBuffer *current_fb;
69 MetaDrmBuffer *next_fb;
70 } gbm;
71
72 struct {
73 MetaDrmBufferDumb *current_dumb_fb;
74 MetaDrmBufferDumb *dumb_fbs[2];
75 } cpu;
76
77 gboolean noted_primary_gpu_copy_ok;
78 gboolean noted_primary_gpu_copy_failed;
79 MetaSharedFramebufferImportStatus import_status;
80 } MetaOnscreenNativeSecondaryGpuState;
81
82 struct _MetaOnscreenNative
83 {
84 CoglOnscreenEgl parent;
85
86 MetaRendererNative *renderer_native;
87 MetaGpuKms *render_gpu;
88 MetaOutput *output;
89 MetaCrtc *crtc;
90
91 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
92
93 struct {
94 struct gbm_surface *surface;
95 MetaDrmBuffer *current_fb;
96 MetaDrmBuffer *next_fb;
97 } gbm;
98
99 #ifdef HAVE_EGL_DEVICE
100 struct {
101 EGLStreamKHR stream;
102
103 MetaDrmBufferDumb *dumb_fb;
104 } egl;
105 #endif
106
107 MetaRendererView *view;
108 };
109
110 G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native,
111 COGL_TYPE_ONSCREEN_EGL)
112
113 static gboolean
114 init_secondary_gpu_state (MetaRendererNative *renderer_native,
115 CoglOnscreen *onscreen,
116 GError **error);
117
118 static void
swap_secondary_drm_fb(CoglOnscreen * onscreen)119 swap_secondary_drm_fb (CoglOnscreen *onscreen)
120 {
121 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
122 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
123
124 secondary_gpu_state = onscreen_native->secondary_gpu_state;
125 if (!secondary_gpu_state)
126 return;
127
128 g_set_object (&secondary_gpu_state->gbm.current_fb,
129 secondary_gpu_state->gbm.next_fb);
130 g_clear_object (&secondary_gpu_state->gbm.next_fb);
131 }
132
133 static void
free_current_secondary_bo(CoglOnscreen * onscreen)134 free_current_secondary_bo (CoglOnscreen *onscreen)
135 {
136 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
137 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
138
139 secondary_gpu_state = onscreen_native->secondary_gpu_state;
140 if (!secondary_gpu_state)
141 return;
142
143 g_clear_object (&secondary_gpu_state->gbm.current_fb);
144 }
145
146 static void
free_current_bo(CoglOnscreen * onscreen)147 free_current_bo (CoglOnscreen *onscreen)
148 {
149 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
150
151 g_clear_object (&onscreen_native->gbm.current_fb);
152 free_current_secondary_bo (onscreen);
153 }
154
155 static void
meta_onscreen_native_swap_drm_fb(CoglOnscreen * onscreen)156 meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
157 {
158 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
159
160 if (!onscreen_native->gbm.next_fb)
161 return;
162
163 free_current_bo (onscreen);
164
165 g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
166 g_clear_object (&onscreen_native->gbm.next_fb);
167
168 swap_secondary_drm_fb (onscreen);
169 }
170
171 static void
maybe_update_frame_info(MetaCrtc * crtc,CoglFrameInfo * frame_info,int64_t time_us,CoglFrameInfoFlag flags,unsigned int sequence)172 maybe_update_frame_info (MetaCrtc *crtc,
173 CoglFrameInfo *frame_info,
174 int64_t time_us,
175 CoglFrameInfoFlag flags,
176 unsigned int sequence)
177 {
178 const MetaCrtcConfig *crtc_config;
179 const MetaCrtcModeInfo *crtc_mode_info;
180 float refresh_rate;
181
182 g_return_if_fail (crtc);
183
184 crtc_config = meta_crtc_get_config (crtc);
185 if (!crtc_config)
186 return;
187
188 crtc_mode_info = meta_crtc_mode_get_info (crtc_config->mode);
189 refresh_rate = crtc_mode_info->refresh_rate;
190 if (refresh_rate >= frame_info->refresh_rate)
191 {
192 frame_info->presentation_time_us = time_us;
193 frame_info->refresh_rate = refresh_rate;
194 frame_info->flags |= flags;
195 frame_info->sequence = sequence;
196 }
197 }
198
199 static void
meta_onscreen_native_notify_frame_complete(CoglOnscreen * onscreen)200 meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen)
201 {
202 CoglFrameInfo *info;
203
204 info = cogl_onscreen_pop_head_frame_info (onscreen);
205
206 g_assert (!cogl_onscreen_peek_head_frame_info (onscreen));
207
208 _cogl_onscreen_notify_frame_sync (onscreen, info);
209 _cogl_onscreen_notify_complete (onscreen, info);
210 cogl_object_unref (info);
211 }
212
213 static void
notify_view_crtc_presented(MetaRendererView * view,MetaKmsCrtc * kms_crtc,int64_t time_us,CoglFrameInfoFlag flags,unsigned int sequence)214 notify_view_crtc_presented (MetaRendererView *view,
215 MetaKmsCrtc *kms_crtc,
216 int64_t time_us,
217 CoglFrameInfoFlag flags,
218 unsigned int sequence)
219 {
220 ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
221 CoglFramebuffer *framebuffer =
222 clutter_stage_view_get_onscreen (stage_view);
223 CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
224 CoglFrameInfo *frame_info;
225 MetaCrtc *crtc;
226
227 frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
228
229 crtc = META_CRTC (meta_crtc_kms_from_kms_crtc (kms_crtc));
230 maybe_update_frame_info (crtc, frame_info, time_us, flags, sequence);
231
232 meta_onscreen_native_notify_frame_complete (onscreen);
233 meta_onscreen_native_swap_drm_fb (onscreen);
234 }
235
236 static int64_t
timeval_to_microseconds(const struct timeval * tv)237 timeval_to_microseconds (const struct timeval *tv)
238 {
239 return ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec;
240 }
241
242 static void
page_flip_feedback_flipped(MetaKmsCrtc * kms_crtc,unsigned int sequence,unsigned int tv_sec,unsigned int tv_usec,gpointer user_data)243 page_flip_feedback_flipped (MetaKmsCrtc *kms_crtc,
244 unsigned int sequence,
245 unsigned int tv_sec,
246 unsigned int tv_usec,
247 gpointer user_data)
248 {
249 MetaRendererView *view = user_data;
250 struct timeval page_flip_time;
251 MetaKmsDevice *kms_device;
252 int64_t presentation_time_us;
253 CoglFrameInfoFlag flags = COGL_FRAME_INFO_FLAG_VSYNC;
254
255 page_flip_time = (struct timeval) {
256 .tv_sec = tv_sec,
257 .tv_usec = tv_usec,
258 };
259
260 kms_device = meta_kms_crtc_get_device (kms_crtc);
261 if (meta_kms_device_uses_monotonic_clock (kms_device))
262 {
263 presentation_time_us = timeval_to_microseconds (&page_flip_time);
264 flags |= COGL_FRAME_INFO_FLAG_HW_CLOCK;
265 }
266 else
267 {
268 /*
269 * Other parts of the code assume MONOTONIC timestamps. So, if the device
270 * timestamp isn't MONOTONIC, don't use it.
271 */
272 presentation_time_us = g_get_monotonic_time ();
273 }
274
275 notify_view_crtc_presented (view, kms_crtc,
276 presentation_time_us,
277 flags,
278 sequence);
279 }
280
281 static void
page_flip_feedback_ready(MetaKmsCrtc * kms_crtc,gpointer user_data)282 page_flip_feedback_ready (MetaKmsCrtc *kms_crtc,
283 gpointer user_data)
284 {
285 MetaRendererView *view = user_data;
286 CoglFramebuffer *framebuffer =
287 clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
288 CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
289 CoglFrameInfo *frame_info;
290
291 frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
292 frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
293
294 meta_onscreen_native_notify_frame_complete (onscreen);
295 }
296
297 static void
page_flip_feedback_mode_set_fallback(MetaKmsCrtc * kms_crtc,gpointer user_data)298 page_flip_feedback_mode_set_fallback (MetaKmsCrtc *kms_crtc,
299 gpointer user_data)
300 {
301 MetaRendererView *view = user_data;
302 int64_t now_us;
303
304 /*
305 * We ended up not page flipping, thus we don't have a presentation time to
306 * use. Lets use the next best thing: the current time.
307 */
308
309 now_us = g_get_monotonic_time ();
310
311 notify_view_crtc_presented (view,
312 kms_crtc,
313 now_us,
314 COGL_FRAME_INFO_FLAG_NONE,
315 0);
316 }
317
318 static void
page_flip_feedback_discarded(MetaKmsCrtc * kms_crtc,gpointer user_data,const GError * error)319 page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc,
320 gpointer user_data,
321 const GError *error)
322 {
323 MetaRendererView *view = user_data;
324 CoglFramebuffer *framebuffer =
325 clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view));
326 CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
327 CoglFrameInfo *frame_info;
328
329 /*
330 * Page flipping failed, but we want to fail gracefully, so to avoid freezing
331 * the frame clock, emit a symbolic flip.
332 */
333
334 if (error &&
335 !g_error_matches (error,
336 G_IO_ERROR,
337 G_IO_ERROR_PERMISSION_DENIED))
338 g_warning ("Page flip discarded: %s", error->message);
339
340 frame_info = cogl_onscreen_peek_head_frame_info (onscreen);
341 frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
342
343 meta_onscreen_native_notify_frame_complete (onscreen);
344 meta_onscreen_native_swap_drm_fb (onscreen);
345 }
346
347 static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = {
348 .flipped = page_flip_feedback_flipped,
349 .ready = page_flip_feedback_ready,
350 .mode_set_fallback = page_flip_feedback_mode_set_fallback,
351 .discarded = page_flip_feedback_discarded,
352 };
353
354 static MetaEgl *
meta_onscreen_native_get_egl(MetaOnscreenNative * onscreen_native)355 meta_onscreen_native_get_egl (MetaOnscreenNative *onscreen_native)
356 {
357 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
358
359 return meta_renderer_native_get_egl (renderer_native);
360 }
361
362 #ifdef HAVE_EGL_DEVICE
363 static int
custom_egl_stream_page_flip(gpointer custom_page_flip_data,gpointer user_data)364 custom_egl_stream_page_flip (gpointer custom_page_flip_data,
365 gpointer user_data)
366 {
367 CoglOnscreen *onscreen = custom_page_flip_data;
368 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
369 MetaRendererView *view = user_data;
370 MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
371 MetaRendererNativeGpuData *renderer_gpu_data;
372 EGLDisplay *egl_display;
373 EGLAttrib *acquire_attribs;
374 g_autoptr (GError) error = NULL;
375
376 acquire_attribs = (EGLAttrib[]) {
377 EGL_DRM_FLIP_EVENT_DATA_NV,
378 (EGLAttrib) view,
379 EGL_NONE
380 };
381
382 renderer_gpu_data =
383 meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
384 onscreen_native->render_gpu);
385
386 egl_display = renderer_gpu_data->egl_display;
387 if (!meta_egl_stream_consumer_acquire_attrib (egl,
388 egl_display,
389 onscreen_native->egl.stream,
390 acquire_attribs,
391 &error))
392 {
393 if (g_error_matches (error, META_EGL_ERROR, EGL_RESOURCE_BUSY_EXT))
394 return -EBUSY;
395 else
396 return -EINVAL;
397 }
398
399 return 0;
400 }
401 #endif /* HAVE_EGL_DEVICE */
402
403 void
meta_onscreen_native_dummy_power_save_page_flip(CoglOnscreen * onscreen)404 meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen)
405 {
406 CoglFrameInfo *frame_info;
407
408 meta_onscreen_native_swap_drm_fb (onscreen);
409
410 frame_info = cogl_onscreen_peek_tail_frame_info (onscreen);
411 frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC;
412 meta_onscreen_native_notify_frame_complete (onscreen);
413 }
414
415 static void
meta_onscreen_native_flip_crtc(CoglOnscreen * onscreen,MetaRendererView * view,MetaCrtc * crtc,MetaKmsPageFlipListenerFlag flags,const int * rectangles,int n_rectangles)416 meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
417 MetaRendererView *view,
418 MetaCrtc *crtc,
419 MetaKmsPageFlipListenerFlag flags,
420 const int *rectangles,
421 int n_rectangles)
422 {
423 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
424 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
425 MetaGpuKms *render_gpu = onscreen_native->render_gpu;
426 MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc);
427 MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
428 MetaRendererNativeGpuData *renderer_gpu_data;
429 MetaGpuKms *gpu_kms;
430 MetaKmsDevice *kms_device;
431 MetaKms *kms;
432 MetaKmsUpdate *kms_update;
433 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL;
434 MetaDrmBuffer *buffer;
435 MetaKmsPlaneAssignment *plane_assignment;
436
437 COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs,
438 "Onscreen (flip CRTCs)");
439
440 gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
441 kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
442 kms = meta_kms_device_get_kms (kms_device);
443 kms_update = meta_kms_ensure_pending_update (kms, kms_device);
444
445 g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc));
446
447 renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
448 render_gpu);
449 switch (renderer_gpu_data->mode)
450 {
451 case META_RENDERER_NATIVE_MODE_GBM:
452 if (gpu_kms == render_gpu)
453 {
454 buffer = onscreen_native->gbm.next_fb;
455 }
456 else
457 {
458 secondary_gpu_state = onscreen_native->secondary_gpu_state;
459 buffer = secondary_gpu_state->gbm.next_fb;
460 }
461
462 plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms,
463 buffer,
464 kms_update);
465
466 if (rectangles != NULL && n_rectangles != 0)
467 {
468 meta_kms_plane_assignment_set_fb_damage (plane_assignment,
469 rectangles, n_rectangles);
470 }
471 break;
472 case META_RENDERER_NATIVE_MODE_SURFACELESS:
473 g_assert_not_reached ();
474 break;
475 #ifdef HAVE_EGL_DEVICE
476 case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
477 meta_kms_update_set_custom_page_flip (kms_update,
478 custom_egl_stream_page_flip,
479 onscreen_native);
480 break;
481 #endif
482 }
483
484 meta_kms_update_add_page_flip_listener (kms_update,
485 kms_crtc,
486 &page_flip_listener_vtable,
487 flags,
488 g_object_ref (view),
489 g_object_unref);
490 }
491
492 static void
meta_onscreen_native_set_crtc_mode(CoglOnscreen * onscreen,MetaRendererNativeGpuData * renderer_gpu_data)493 meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen,
494 MetaRendererNativeGpuData *renderer_gpu_data)
495 {
496 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
497 MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
498 MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms);
499 MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);
500 MetaKms *kms = meta_kms_device_get_kms (kms_device);
501 MetaKmsUpdate *kms_update;
502
503 COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeSetCrtcModes,
504 "Onscreen (set CRTC modes)");
505
506 kms_update = meta_kms_ensure_pending_update (kms, kms_device);
507
508 switch (renderer_gpu_data->mode)
509 {
510 case META_RENDERER_NATIVE_MODE_GBM:
511 break;
512 case META_RENDERER_NATIVE_MODE_SURFACELESS:
513 g_assert_not_reached ();
514 break;
515 #ifdef HAVE_EGL_DEVICE
516 case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
517 {
518 MetaDrmBuffer *buffer;
519
520 buffer = META_DRM_BUFFER (onscreen_native->egl.dumb_fb);
521 meta_crtc_kms_assign_primary_plane (crtc_kms, buffer, kms_update);
522 break;
523 }
524 #endif
525 }
526
527 meta_crtc_kms_set_mode (crtc_kms, kms_update);
528 meta_output_kms_set_underscan (META_OUTPUT_KMS (onscreen_native->output),
529 kms_update);
530 }
531
532 static void
secondary_gpu_release_dumb(MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state)533 secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
534 {
535 unsigned i;
536
537 for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
538 g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]);
539 }
540
541 static void
secondary_gpu_state_free(MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state)542 secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
543 {
544 MetaGpu *gpu = META_GPU (secondary_gpu_state->gpu_kms);
545 MetaBackend *backend = meta_gpu_get_backend (gpu);
546 MetaEgl *egl = meta_backend_get_egl (backend);
547
548 if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE)
549 {
550 MetaRendererNativeGpuData *renderer_gpu_data;
551
552 renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
553 meta_egl_destroy_surface (egl,
554 renderer_gpu_data->egl_display,
555 secondary_gpu_state->egl_surface,
556 NULL);
557 }
558
559 g_clear_object (&secondary_gpu_state->gbm.current_fb);
560 g_clear_object (&secondary_gpu_state->gbm.next_fb);
561 g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy);
562
563 secondary_gpu_release_dumb (secondary_gpu_state);
564
565 g_free (secondary_gpu_state);
566 }
567
568 static gboolean
import_shared_framebuffer(CoglOnscreen * onscreen,MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state)569 import_shared_framebuffer (CoglOnscreen *onscreen,
570 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
571 {
572 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
573 MetaGpuKms *gpu_kms;
574 MetaDeviceFile *device_file;
575 struct gbm_device *gbm_device;
576 MetaDrmBufferGbm *buffer_gbm;
577 MetaDrmBufferImport *buffer_import;
578 g_autoptr (GError) error = NULL;
579
580 buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
581
582 gpu_kms = secondary_gpu_state->gpu_kms;
583 device_file = secondary_gpu_state->renderer_gpu_data->device_file;
584 gbm_device = meta_gbm_device_from_gpu (gpu_kms);
585 buffer_import = meta_drm_buffer_import_new (device_file,
586 gbm_device,
587 buffer_gbm,
588 &error);
589 if (!buffer_import)
590 {
591 meta_topic (META_DEBUG_KMS,
592 "Zero-copy disabled for %s, "
593 "meta_drm_buffer_import_new failed: %s",
594 meta_device_file_get_path (device_file),
595 error->message);
596
597 g_warn_if_fail (secondary_gpu_state->import_status ==
598 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE);
599
600 /*
601 * Fall back. If META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE is
602 * in effect, we have COPY_MODE_PRIMARY prepared already, so we
603 * simply retry with that path. Import status cannot be FAILED,
604 * because we should not retry if failed once.
605 *
606 * If import status is OK, that is unexpected and we do not
607 * have the fallback path prepared which means this output cannot
608 * work anymore.
609 */
610 secondary_gpu_state->renderer_gpu_data->secondary.copy_mode =
611 META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY;
612
613 secondary_gpu_state->import_status =
614 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED;
615 return FALSE;
616 }
617
618 /*
619 * next_fb may already contain a fallback buffer, so clear it only
620 * when we are sure to succeed.
621 */
622 g_clear_object (&secondary_gpu_state->gbm.next_fb);
623 secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_import);
624
625 if (secondary_gpu_state->import_status ==
626 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE)
627 {
628 /*
629 * Clean up the cpu-copy part of
630 * init_secondary_gpu_state_cpu_copy_mode ()
631 */
632 secondary_gpu_release_dumb (secondary_gpu_state);
633
634 meta_topic (META_DEBUG_KMS,
635 "Using zero-copy for %s succeeded once.",
636 meta_device_file_get_path (device_file));
637 }
638
639 secondary_gpu_state->import_status =
640 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK;
641 return TRUE;
642 }
643
644 static void
copy_shared_framebuffer_gpu(CoglOnscreen * onscreen,MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state,MetaRendererNativeGpuData * renderer_gpu_data,gboolean * egl_context_changed)645 copy_shared_framebuffer_gpu (CoglOnscreen *onscreen,
646 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
647 MetaRendererNativeGpuData *renderer_gpu_data,
648 gboolean *egl_context_changed)
649 {
650 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
651 MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
652 MetaEgl *egl = meta_renderer_native_get_egl (renderer_native);
653 MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native);
654 GError *error = NULL;
655 gboolean use_modifiers;
656 MetaDeviceFile *device_file;
657 MetaDrmBufferGbm *buffer_gbm;
658 struct gbm_bo *bo;
659
660 COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu,
661 "FB Copy (secondary GPU)");
662
663 g_warn_if_fail (secondary_gpu_state->gbm.next_fb == NULL);
664 g_clear_object (&secondary_gpu_state->gbm.next_fb);
665
666 if (!meta_egl_make_current (egl,
667 renderer_gpu_data->egl_display,
668 secondary_gpu_state->egl_surface,
669 secondary_gpu_state->egl_surface,
670 renderer_gpu_data->secondary.egl_context,
671 &error))
672 {
673 g_warning ("Failed to make current: %s", error->message);
674 g_error_free (error);
675 return;
676 }
677
678 *egl_context_changed = TRUE;
679
680
681 buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb);
682 bo = meta_drm_buffer_gbm_get_bo (buffer_gbm);
683 if (!meta_renderer_native_gles3_blit_shared_bo (egl,
684 gles3,
685 renderer_gpu_data->egl_display,
686 renderer_gpu_data->secondary.egl_context,
687 secondary_gpu_state->egl_surface,
688 bo,
689 &error))
690 {
691 g_warning ("Failed to blit shared framebuffer: %s", error->message);
692 g_error_free (error);
693 return;
694 }
695
696 if (!meta_egl_swap_buffers (egl,
697 renderer_gpu_data->egl_display,
698 secondary_gpu_state->egl_surface,
699 &error))
700 {
701 g_warning ("Failed to swap buffers: %s", error->message);
702 g_error_free (error);
703 return;
704 }
705
706 use_modifiers = meta_renderer_native_use_modifiers (renderer_native);
707 device_file = secondary_gpu_state->renderer_gpu_data->device_file;
708 buffer_gbm =
709 meta_drm_buffer_gbm_new_lock_front (device_file,
710 secondary_gpu_state->gbm.surface,
711 use_modifiers,
712 &error);
713 if (!buffer_gbm)
714 {
715 g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s",
716 error->message);
717 g_error_free (error);
718 return;
719 }
720
721 secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
722 }
723
724 static MetaDrmBufferDumb *
secondary_gpu_get_next_dumb_buffer(MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state)725 secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
726 {
727 MetaDrmBufferDumb *current_dumb_fb;
728
729 current_dumb_fb = secondary_gpu_state->cpu.current_dumb_fb;
730 if (current_dumb_fb == secondary_gpu_state->cpu.dumb_fbs[0])
731 return secondary_gpu_state->cpu.dumb_fbs[1];
732 else
733 return secondary_gpu_state->cpu.dumb_fbs[0];
734 }
735
736 static gboolean
copy_shared_framebuffer_primary_gpu(CoglOnscreen * onscreen,MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state)737 copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscreen,
738 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
739 {
740 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
741 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
742 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
743 MetaGpuKms *primary_gpu;
744 MetaRendererNativeGpuData *primary_gpu_data;
745 MetaDrmBufferDumb *buffer_dumb;
746 MetaDrmBuffer *buffer;
747 int width, height, stride;
748 uint32_t drm_format;
749 CoglFramebuffer *dmabuf_fb;
750 int dmabuf_fd;
751 g_autoptr (GError) error = NULL;
752 CoglPixelFormat cogl_format;
753 int ret;
754
755 COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferPrimaryGpu,
756 "FB Copy (primary GPU)");
757
758 primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native);
759 primary_gpu_data =
760 meta_renderer_native_get_gpu_data (renderer_native, primary_gpu);
761 if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers)
762 return FALSE;
763
764 buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
765 buffer = META_DRM_BUFFER (buffer_dumb);
766
767 width = meta_drm_buffer_get_width (buffer);
768 height = meta_drm_buffer_get_height (buffer);
769 stride = meta_drm_buffer_get_stride (buffer);
770 drm_format = meta_drm_buffer_get_format (buffer);
771
772 g_assert (cogl_framebuffer_get_width (framebuffer) == width);
773 g_assert (cogl_framebuffer_get_height (framebuffer) == height);
774
775 ret = meta_cogl_pixel_format_from_drm_format (drm_format,
776 &cogl_format,
777 NULL);
778 g_assert (ret);
779
780 dmabuf_fd = meta_drm_buffer_dumb_ensure_dmabuf_fd (buffer_dumb, &error);
781 if (!dmabuf_fd)
782 {
783 meta_topic (META_DEBUG_KMS,
784 "Failed to create DMA buffer: %s", error->message);
785 return FALSE;
786 }
787
788 dmabuf_fb =
789 meta_renderer_native_create_dma_buf_framebuffer (renderer_native,
790 dmabuf_fd,
791 width,
792 height,
793 stride,
794 0, DRM_FORMAT_MOD_LINEAR,
795 drm_format,
796 &error);
797
798 if (error)
799 {
800 meta_topic (META_DEBUG_KMS,
801 "Failed to create DMA buffer for blitting: %s",
802 error->message);
803 return FALSE;
804 }
805
806 if (!cogl_blit_framebuffer (framebuffer, COGL_FRAMEBUFFER (dmabuf_fb),
807 0, 0, 0, 0,
808 width, height,
809 &error))
810 {
811 g_object_unref (dmabuf_fb);
812 return FALSE;
813 }
814
815 g_object_unref (dmabuf_fb);
816
817 g_set_object (&secondary_gpu_state->gbm.next_fb, buffer);
818 secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
819
820 return TRUE;
821 }
822
823 static void
copy_shared_framebuffer_cpu(CoglOnscreen * onscreen,MetaOnscreenNativeSecondaryGpuState * secondary_gpu_state,MetaRendererNativeGpuData * renderer_gpu_data)824 copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
825 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state,
826 MetaRendererNativeGpuData *renderer_gpu_data)
827 {
828 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
829 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
830 MetaDrmBufferDumb *buffer_dumb;
831 MetaDrmBuffer *buffer;
832 int width, height, stride;
833 uint32_t drm_format;
834 void *buffer_data;
835 CoglBitmap *dumb_bitmap;
836 CoglPixelFormat cogl_format;
837 gboolean ret;
838
839 COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferCpu,
840 "FB Copy (CPU)");
841
842 buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state);
843 buffer = META_DRM_BUFFER (buffer_dumb);
844
845 width = meta_drm_buffer_get_width (buffer);
846 height = meta_drm_buffer_get_height (buffer);
847 stride = meta_drm_buffer_get_stride (buffer);
848 drm_format = meta_drm_buffer_get_format (buffer);
849 buffer_data = meta_drm_buffer_dumb_get_data (buffer_dumb);
850
851 g_assert (cogl_framebuffer_get_width (framebuffer) == width);
852 g_assert (cogl_framebuffer_get_height (framebuffer) == height);
853
854 ret = meta_cogl_pixel_format_from_drm_format (drm_format,
855 &cogl_format,
856 NULL);
857 g_assert (ret);
858
859 dumb_bitmap = cogl_bitmap_new_for_data (cogl_context,
860 width,
861 height,
862 cogl_format,
863 stride,
864 buffer_data);
865
866 if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
867 0 /* x */,
868 0 /* y */,
869 COGL_READ_PIXELS_COLOR_BUFFER,
870 dumb_bitmap))
871 g_warning ("Failed to CPU-copy to a secondary GPU output");
872
873 cogl_object_unref (dumb_bitmap);
874
875 g_clear_object (&secondary_gpu_state->gbm.next_fb);
876 secondary_gpu_state->gbm.next_fb = buffer;
877 secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb;
878 }
879
880 static void
update_secondary_gpu_state_pre_swap_buffers(CoglOnscreen * onscreen)881 update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen)
882 {
883 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
884 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
885
886 COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePreSwapBuffers,
887 "Onscreen (secondary gpu pre-swap-buffers)");
888
889 secondary_gpu_state = onscreen_native->secondary_gpu_state;
890 if (secondary_gpu_state)
891 {
892 MetaRendererNativeGpuData *renderer_gpu_data;
893 MetaDeviceFile *device_file;
894
895 renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
896 device_file = renderer_gpu_data->device_file;
897 switch (renderer_gpu_data->secondary.copy_mode)
898 {
899 case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
900 /* Done after eglSwapBuffers. */
901 break;
902 case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
903 /* Done after eglSwapBuffers. */
904 if (secondary_gpu_state->import_status ==
905 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK)
906 break;
907 /* prepare fallback */
908 G_GNUC_FALLTHROUGH;
909 case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
910 if (!copy_shared_framebuffer_primary_gpu (onscreen,
911 secondary_gpu_state))
912 {
913 if (!secondary_gpu_state->noted_primary_gpu_copy_failed)
914 {
915 meta_topic (META_DEBUG_KMS,
916 "Using primary GPU to copy for %s failed once.",
917 meta_device_file_get_path (device_file));
918 secondary_gpu_state->noted_primary_gpu_copy_failed = TRUE;
919 }
920
921 copy_shared_framebuffer_cpu (onscreen,
922 secondary_gpu_state,
923 renderer_gpu_data);
924 }
925 else if (!secondary_gpu_state->noted_primary_gpu_copy_ok)
926 {
927 meta_topic (META_DEBUG_KMS,
928 "Using primary GPU to copy for %s succeeded once.",
929 meta_device_file_get_path (device_file));
930 secondary_gpu_state->noted_primary_gpu_copy_ok = TRUE;
931 }
932 break;
933 }
934 }
935 }
936
937 static void
update_secondary_gpu_state_post_swap_buffers(CoglOnscreen * onscreen,gboolean * egl_context_changed)938 update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
939 gboolean *egl_context_changed)
940 {
941 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
942 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
943 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
944
945 COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePostSwapBuffers,
946 "Onscreen (secondary gpu post-swap-buffers)");
947
948 secondary_gpu_state = onscreen_native->secondary_gpu_state;
949 if (secondary_gpu_state)
950 {
951 MetaRendererNativeGpuData *renderer_gpu_data;
952
953 renderer_gpu_data =
954 meta_renderer_native_get_gpu_data (renderer_native,
955 secondary_gpu_state->gpu_kms);
956 retry:
957 switch (renderer_gpu_data->secondary.copy_mode)
958 {
959 case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
960 if (!import_shared_framebuffer (onscreen,
961 secondary_gpu_state))
962 goto retry;
963 break;
964 case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
965 copy_shared_framebuffer_gpu (onscreen,
966 secondary_gpu_state,
967 renderer_gpu_data,
968 egl_context_changed);
969 break;
970 case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
971 /* Done before eglSwapBuffers. */
972 break;
973 }
974 }
975 }
976
977 static void
ensure_crtc_modes(CoglOnscreen * onscreen)978 ensure_crtc_modes (CoglOnscreen *onscreen)
979 {
980 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
981 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
982 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
983 CoglRenderer *cogl_renderer = cogl_context->display->renderer;
984 CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
985 MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
986 MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
987
988 if (meta_renderer_native_pop_pending_mode_set (renderer_native,
989 onscreen_native->view))
990 meta_onscreen_native_set_crtc_mode (onscreen, renderer_gpu_data);
991 }
992
993 static void
meta_onscreen_native_swap_buffers_with_damage(CoglOnscreen * onscreen,const int * rectangles,int n_rectangles,CoglFrameInfo * frame_info,gpointer user_data)994 meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
995 const int *rectangles,
996 int n_rectangles,
997 CoglFrameInfo *frame_info,
998 gpointer user_data)
999 {
1000 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1001 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
1002 CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
1003 CoglRenderer *cogl_renderer = cogl_context->display->renderer;
1004 CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
1005 MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
1006 MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
1007 MetaRenderer *renderer = META_RENDERER (renderer_native);
1008 MetaBackend *backend = meta_renderer_get_backend (renderer);
1009 MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
1010 MetaMonitorManager *monitor_manager =
1011 meta_backend_get_monitor_manager (backend);
1012 MetaKms *kms = meta_backend_native_get_kms (backend_native);
1013 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1014 MetaGpuKms *render_gpu = onscreen_native->render_gpu;
1015 MetaDeviceFile *render_device_file;
1016 ClutterFrame *frame = user_data;
1017 CoglOnscreenClass *parent_class;
1018 gboolean egl_context_changed = FALSE;
1019 gboolean use_modifiers;
1020 MetaPowerSave power_save_mode;
1021 g_autoptr (GError) error = NULL;
1022 MetaDrmBufferGbm *buffer_gbm;
1023 MetaKmsCrtc *kms_crtc;
1024 MetaKmsDevice *kms_device;
1025 MetaKmsUpdateFlag flags;
1026 g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
1027 const GError *feedback_error;
1028
1029 COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers,
1030 "Onscreen (swap-buffers)");
1031
1032 update_secondary_gpu_state_pre_swap_buffers (onscreen);
1033
1034 parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class);
1035 parent_class->swap_buffers_with_damage (onscreen,
1036 rectangles,
1037 n_rectangles,
1038 frame_info,
1039 user_data);
1040
1041 renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
1042 render_gpu);
1043 render_device_file = renderer_gpu_data->device_file;
1044 switch (renderer_gpu_data->mode)
1045 {
1046 case META_RENDERER_NATIVE_MODE_GBM:
1047 g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
1048 g_clear_object (&onscreen_native->gbm.next_fb);
1049
1050 use_modifiers = meta_renderer_native_use_modifiers (renderer_native);
1051 buffer_gbm =
1052 meta_drm_buffer_gbm_new_lock_front (render_device_file,
1053 onscreen_native->gbm.surface,
1054 use_modifiers,
1055 &error);
1056 if (!buffer_gbm)
1057 {
1058 g_warning ("Failed to lock front buffer on %s: %s",
1059 meta_device_file_get_path (render_device_file),
1060 error->message);
1061 return;
1062 }
1063
1064 onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm);
1065
1066 break;
1067 case META_RENDERER_NATIVE_MODE_SURFACELESS:
1068 g_assert_not_reached ();
1069 break;
1070 #ifdef HAVE_EGL_DEVICE
1071 case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
1072 break;
1073 #endif
1074 }
1075
1076 update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed);
1077
1078 /*
1079 * If we changed EGL context, cogl will have the wrong idea about what is
1080 * current, making it fail to set it when it needs to. Avoid that by making
1081 * EGL_NO_CONTEXT current now, making cogl eventually set the correct
1082 * context.
1083 */
1084 if (egl_context_changed)
1085 _cogl_winsys_egl_ensure_current (cogl_display);
1086
1087 power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
1088 if (power_save_mode == META_POWER_SAVE_ON)
1089 {
1090 ensure_crtc_modes (onscreen);
1091 meta_onscreen_native_flip_crtc (onscreen,
1092 onscreen_native->view,
1093 onscreen_native->crtc,
1094 META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
1095 rectangles,
1096 n_rectangles);
1097 }
1098 else
1099 {
1100 meta_renderer_native_queue_power_save_page_flip (renderer_native,
1101 onscreen);
1102 clutter_frame_set_result (frame,
1103 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1104 return;
1105 }
1106
1107 COGL_TRACE_BEGIN_SCOPED (MetaRendererNativePostKmsUpdate,
1108 "Onscreen (post pending update)");
1109 kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
1110 kms_device = meta_kms_crtc_get_device (kms_crtc);
1111
1112 switch (renderer_gpu_data->mode)
1113 {
1114 case META_RENDERER_NATIVE_MODE_GBM:
1115 if (meta_renderer_native_has_pending_mode_sets (renderer_native))
1116 {
1117 meta_topic (META_DEBUG_KMS,
1118 "Postponing primary plane composite update for CRTC %u (%s)",
1119 meta_kms_crtc_get_id (kms_crtc),
1120 meta_kms_device_get_path (kms_device));
1121
1122 clutter_frame_set_result (frame,
1123 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1124 return;
1125 }
1126 else if (meta_renderer_native_has_pending_mode_set (renderer_native))
1127 {
1128 meta_topic (META_DEBUG_KMS, "Posting global mode set updates on %s",
1129 meta_kms_device_get_path (kms_device));
1130
1131 meta_renderer_native_notify_mode_sets_reset (renderer_native);
1132 meta_renderer_native_post_mode_set_updates (renderer_native);
1133 clutter_frame_set_result (frame,
1134 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1135 return;
1136 }
1137 break;
1138 case META_RENDERER_NATIVE_MODE_SURFACELESS:
1139 g_assert_not_reached ();
1140 break;
1141 #ifdef HAVE_EGL_DEVICE
1142 case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
1143 if (meta_renderer_native_has_pending_mode_set (renderer_native))
1144 {
1145 meta_renderer_native_notify_mode_sets_reset (renderer_native);
1146 meta_renderer_native_post_mode_set_updates (renderer_native);
1147 clutter_frame_set_result (frame,
1148 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1149 return;
1150 }
1151 break;
1152 #endif
1153 }
1154
1155 meta_topic (META_DEBUG_KMS,
1156 "Posting primary plane composite update for CRTC %u (%s)",
1157 meta_kms_crtc_get_id (kms_crtc),
1158 meta_kms_device_get_path (kms_device));
1159
1160 flags = META_KMS_UPDATE_FLAG_NONE;
1161 kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
1162
1163 switch (meta_kms_feedback_get_result (kms_feedback))
1164 {
1165 case META_KMS_FEEDBACK_PASSED:
1166 clutter_frame_set_result (frame,
1167 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1168 break;
1169 case META_KMS_FEEDBACK_FAILED:
1170 clutter_frame_set_result (frame,
1171 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1172
1173 feedback_error = meta_kms_feedback_get_error (kms_feedback);
1174 if (!g_error_matches (feedback_error,
1175 G_IO_ERROR,
1176 G_IO_ERROR_PERMISSION_DENIED))
1177 g_warning ("Failed to post KMS update: %s", feedback_error->message);
1178 break;
1179 }
1180 }
1181
1182 gboolean
meta_onscreen_native_is_buffer_scanout_compatible(CoglOnscreen * onscreen,uint32_t drm_format,uint64_t drm_modifier,uint32_t stride)1183 meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen,
1184 uint32_t drm_format,
1185 uint64_t drm_modifier,
1186 uint32_t stride)
1187 {
1188 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1189 const MetaCrtcConfig *crtc_config;
1190 MetaDrmBuffer *fb;
1191 struct gbm_bo *gbm_bo;
1192
1193 crtc_config = meta_crtc_get_config (onscreen_native->crtc);
1194 if (crtc_config->transform != META_MONITOR_TRANSFORM_NORMAL)
1195 return FALSE;
1196
1197 if (onscreen_native->secondary_gpu_state)
1198 return FALSE;
1199
1200 if (!onscreen_native->gbm.surface)
1201 return FALSE;
1202
1203 fb = onscreen_native->gbm.current_fb ? onscreen_native->gbm.current_fb
1204 : onscreen_native->gbm.next_fb;
1205 if (!fb)
1206 return FALSE;
1207
1208 if (!META_IS_DRM_BUFFER_GBM (fb))
1209 return FALSE;
1210
1211 gbm_bo = meta_drm_buffer_gbm_get_bo (META_DRM_BUFFER_GBM (fb));
1212
1213 if (gbm_bo_get_format (gbm_bo) != drm_format)
1214 return FALSE;
1215
1216 if (gbm_bo_get_modifier (gbm_bo) != drm_modifier)
1217 return FALSE;
1218
1219 if (gbm_bo_get_stride (gbm_bo) != stride)
1220 return FALSE;
1221
1222 return TRUE;
1223 }
1224
1225 static gboolean
meta_onscreen_native_direct_scanout(CoglOnscreen * onscreen,CoglScanout * scanout,CoglFrameInfo * frame_info,gpointer user_data,GError ** error)1226 meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen,
1227 CoglScanout *scanout,
1228 CoglFrameInfo *frame_info,
1229 gpointer user_data,
1230 GError **error)
1231 {
1232 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1233 MetaGpuKms *render_gpu = onscreen_native->render_gpu;
1234 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1235 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
1236 CoglRenderer *cogl_renderer = cogl_context->display->renderer;
1237 CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
1238 MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
1239 MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
1240 MetaRenderer *renderer = META_RENDERER (renderer_native);
1241 MetaBackend *backend = meta_renderer_get_backend (renderer);
1242 MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
1243 MetaKms *kms = meta_backend_native_get_kms (backend_native);
1244 MetaMonitorManager *monitor_manager =
1245 meta_backend_get_monitor_manager (backend);
1246 MetaPowerSave power_save_mode;
1247 ClutterFrame *frame = user_data;
1248 MetaDrmBuffer *scanout_buffer;
1249 GError *fill_timings_error = NULL;
1250 MetaKmsCrtc *kms_crtc;
1251 MetaKmsDevice *kms_device;
1252 MetaKmsUpdateFlag flags;
1253 g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
1254 const GError *feedback_error;
1255
1256 power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
1257 if (power_save_mode != META_POWER_SAVE_ON)
1258 {
1259 g_set_error_literal (error,
1260 COGL_SCANOUT_ERROR,
1261 COGL_SCANOUT_ERROR_INHIBITED,
1262 "Direct scanout is inhibited during power saving mode");
1263 return FALSE;
1264 }
1265
1266 if (meta_renderer_native_has_pending_mode_set (renderer_native))
1267 {
1268 g_set_error_literal (error,
1269 COGL_SCANOUT_ERROR,
1270 COGL_SCANOUT_ERROR_INHIBITED,
1271 "Direct scanout is inhibited when a mode set is pending");
1272 return FALSE;
1273 }
1274
1275 renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
1276 render_gpu);
1277
1278 g_warn_if_fail (renderer_gpu_data->mode == META_RENDERER_NATIVE_MODE_GBM);
1279 g_warn_if_fail (!onscreen_native->gbm.next_fb);
1280
1281 g_set_object (&onscreen_native->gbm.next_fb, META_DRM_BUFFER (scanout));
1282
1283 /* Try to get a measurement of GPU rendering time on the scanout buffer.
1284 *
1285 * The successful operation here adds ~0.4 ms to a ~0.1 ms total frame clock
1286 * dispatch duration when displaying an unredirected client, thus
1287 * unfortunately bringing it more in line with duration of the regular
1288 * non-unredirected frame clock dispatch. However, measuring GPU rendering
1289 * time is important for computing accurate max render time without
1290 * underestimating. Also this operation should be optimizable by caching
1291 * EGLImage for each buffer instead of re-creating it every time it's needed.
1292 * This should also help all other cases which convert the buffer to a
1293 * EGLImage.
1294 */
1295 if (META_IS_DRM_BUFFER (scanout))
1296 {
1297 scanout_buffer = META_DRM_BUFFER (scanout);
1298 if (meta_drm_buffer_supports_fill_timings (scanout_buffer))
1299 {
1300 if (!meta_drm_buffer_fill_timings (scanout_buffer, frame_info,
1301 &fill_timings_error))
1302 {
1303 g_warning ("Failed to fill timings for a scanout buffer: %s",
1304 fill_timings_error->message);
1305 g_error_free (fill_timings_error);
1306 }
1307 }
1308 }
1309
1310 ensure_crtc_modes (onscreen);
1311 meta_onscreen_native_flip_crtc (onscreen,
1312 onscreen_native->view,
1313 onscreen_native->crtc,
1314 META_KMS_PAGE_FLIP_LISTENER_FLAG_DROP_ON_ERROR,
1315 NULL,
1316 0);
1317
1318 kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (onscreen_native->crtc));
1319 kms_device = meta_kms_crtc_get_device (kms_crtc);
1320
1321 meta_topic (META_DEBUG_KMS,
1322 "Posting direct scanout update for CRTC %u (%s)",
1323 meta_kms_crtc_get_id (kms_crtc),
1324 meta_kms_device_get_path (kms_device));
1325
1326 flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR;
1327 kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags);
1328 switch (meta_kms_feedback_get_result (kms_feedback))
1329 {
1330 case META_KMS_FEEDBACK_PASSED:
1331 clutter_frame_set_result (frame,
1332 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1333 break;
1334 case META_KMS_FEEDBACK_FAILED:
1335 feedback_error = meta_kms_feedback_get_error (kms_feedback);
1336
1337 if (g_error_matches (feedback_error,
1338 G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
1339 break;
1340
1341 g_clear_object (&onscreen_native->gbm.next_fb);
1342 g_propagate_error (error, g_error_copy (feedback_error));
1343 return FALSE;
1344 }
1345
1346 return TRUE;
1347 }
1348
1349 static void
add_onscreen_frame_info(MetaCrtc * crtc)1350 add_onscreen_frame_info (MetaCrtc *crtc)
1351 {
1352 MetaGpu *gpu = meta_crtc_get_gpu (crtc);
1353 MetaBackend *backend = meta_gpu_get_backend (gpu);
1354 ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
1355 ClutterStageWindow *stage_window = _clutter_stage_get_window (stage);
1356 MetaRenderer *renderer = meta_backend_get_renderer (backend);
1357 MetaRendererView *view = meta_renderer_get_view_for_crtc (renderer, crtc);
1358
1359 meta_stage_impl_add_onscreen_frame_info (META_STAGE_IMPL (stage_window),
1360 CLUTTER_STAGE_VIEW (view));
1361 }
1362
1363 void
meta_onscreen_native_finish_frame(CoglOnscreen * onscreen,ClutterFrame * frame)1364 meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
1365 ClutterFrame *frame)
1366 {
1367 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1368 MetaCrtc *crtc = onscreen_native->crtc;
1369 MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc));
1370 MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);;
1371 MetaKms *kms = meta_kms_device_get_kms (kms_device);
1372 MetaKmsUpdateFlag flags;
1373 MetaKmsUpdate *kms_update;
1374 g_autoptr (MetaKmsFeedback) kms_feedback = NULL;
1375 const GError *error;
1376
1377 kms_update = meta_kms_get_pending_update (kms, kms_device);
1378 if (!kms_update)
1379 {
1380 clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE);
1381 return;
1382 }
1383
1384 meta_kms_update_add_page_flip_listener (kms_update,
1385 kms_crtc,
1386 &page_flip_listener_vtable,
1387 META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE,
1388 g_object_ref (onscreen_native->view),
1389 g_object_unref);
1390
1391 flags = META_KMS_UPDATE_FLAG_NONE;
1392 kms_feedback = meta_kms_post_pending_update_sync (kms,
1393 kms_device,
1394 flags);
1395 switch (meta_kms_feedback_get_result (kms_feedback))
1396 {
1397 case META_KMS_FEEDBACK_PASSED:
1398 add_onscreen_frame_info (crtc);
1399 clutter_frame_set_result (frame,
1400 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1401 break;
1402 case META_KMS_FEEDBACK_FAILED:
1403 add_onscreen_frame_info (crtc);
1404 clutter_frame_set_result (frame,
1405 CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
1406
1407 error = meta_kms_feedback_get_error (kms_feedback);
1408 if (!g_error_matches (error,
1409 G_IO_ERROR,
1410 G_IO_ERROR_PERMISSION_DENIED))
1411 g_warning ("Failed to post KMS update: %s", error->message);
1412 break;
1413 }
1414 }
1415
1416 static gboolean
should_surface_be_sharable(CoglOnscreen * onscreen)1417 should_surface_be_sharable (CoglOnscreen *onscreen)
1418 {
1419 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1420
1421 if (META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc)) ==
1422 onscreen_native->render_gpu)
1423 return FALSE;
1424 else
1425 return TRUE;
1426 }
1427
1428 static uint32_t
get_gbm_format_from_egl(MetaEgl * egl,EGLDisplay egl_display,EGLConfig egl_config)1429 get_gbm_format_from_egl (MetaEgl *egl,
1430 EGLDisplay egl_display,
1431 EGLConfig egl_config)
1432 {
1433 uint32_t gbm_format;
1434 EGLint native_visual_id;
1435
1436 if (meta_egl_get_config_attrib (egl,
1437 egl_display,
1438 egl_config,
1439 EGL_NATIVE_VISUAL_ID,
1440 &native_visual_id,
1441 NULL))
1442 gbm_format = (uint32_t) native_visual_id;
1443 else
1444 g_assert_not_reached ();
1445
1446 return gbm_format;
1447 }
1448
1449 static GArray *
get_supported_kms_modifiers(MetaCrtcKms * crtc_kms,uint32_t format)1450 get_supported_kms_modifiers (MetaCrtcKms *crtc_kms,
1451 uint32_t format)
1452 {
1453 GArray *modifiers;
1454 GArray *crtc_mods;
1455 unsigned int i;
1456
1457 crtc_mods = meta_crtc_kms_get_modifiers (crtc_kms, format);
1458 if (!crtc_mods)
1459 return NULL;
1460
1461 modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
1462
1463 /*
1464 * For each modifier from base_crtc, check if it's available on all other
1465 * CRTCs.
1466 */
1467 for (i = 0; i < crtc_mods->len; i++)
1468 {
1469 uint64_t modifier = g_array_index (crtc_mods, uint64_t, i);
1470
1471 g_array_append_val (modifiers, modifier);
1472 }
1473
1474 if (modifiers->len == 0)
1475 {
1476 g_array_free (modifiers, TRUE);
1477 return NULL;
1478 }
1479
1480 return modifiers;
1481 }
1482
1483 static GArray *
get_supported_egl_modifiers(CoglOnscreen * onscreen,MetaCrtcKms * crtc_kms,uint32_t format)1484 get_supported_egl_modifiers (CoglOnscreen *onscreen,
1485 MetaCrtcKms *crtc_kms,
1486 uint32_t format)
1487 {
1488 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1489 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
1490 MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
1491 MetaGpu *gpu;
1492 MetaRendererNativeGpuData *renderer_gpu_data;
1493 EGLint num_modifiers;
1494 GArray *modifiers;
1495 GError *error = NULL;
1496 gboolean ret;
1497
1498 gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
1499 renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
1500 META_GPU_KMS (gpu));
1501
1502 if (!meta_egl_has_extensions (egl, renderer_gpu_data->egl_display, NULL,
1503 "EGL_EXT_image_dma_buf_import_modifiers",
1504 NULL))
1505 return NULL;
1506
1507 ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
1508 format, 0, NULL, NULL,
1509 &num_modifiers, NULL);
1510 if (!ret || num_modifiers == 0)
1511 return NULL;
1512
1513 modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t),
1514 num_modifiers);
1515 ret = meta_egl_query_dma_buf_modifiers (egl, renderer_gpu_data->egl_display,
1516 format, num_modifiers,
1517 (EGLuint64KHR *) modifiers->data, NULL,
1518 &num_modifiers, &error);
1519
1520 if (!ret)
1521 {
1522 g_warning ("Failed to query DMABUF modifiers: %s", error->message);
1523 g_error_free (error);
1524 g_array_free (modifiers, TRUE);
1525 return NULL;
1526 }
1527
1528 return modifiers;
1529 }
1530
1531 static GArray *
get_supported_modifiers(CoglOnscreen * onscreen,uint32_t format)1532 get_supported_modifiers (CoglOnscreen *onscreen,
1533 uint32_t format)
1534 {
1535 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1536 MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
1537 MetaGpu *gpu;
1538 g_autoptr (GArray) modifiers = NULL;
1539
1540 gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms));
1541 if (gpu == META_GPU (onscreen_native->render_gpu))
1542 modifiers = get_supported_kms_modifiers (crtc_kms, format);
1543 else
1544 modifiers = get_supported_egl_modifiers (onscreen, crtc_kms, format);
1545
1546 return g_steal_pointer (&modifiers);
1547 }
1548
1549 static GArray *
get_supported_kms_formats(CoglOnscreen * onscreen)1550 get_supported_kms_formats (CoglOnscreen *onscreen)
1551 {
1552 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1553 MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc);
1554
1555 return meta_crtc_kms_copy_drm_format_list (crtc_kms);
1556 }
1557
1558 static gboolean
create_surfaces_gbm(CoglOnscreen * onscreen,int width,int height,struct gbm_surface ** gbm_surface,EGLSurface * egl_surface,GError ** error)1559 create_surfaces_gbm (CoglOnscreen *onscreen,
1560 int width,
1561 int height,
1562 struct gbm_surface **gbm_surface,
1563 EGLSurface *egl_surface,
1564 GError **error)
1565 {
1566 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1567 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
1568 MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
1569 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1570 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
1571 CoglDisplay *cogl_display = cogl_context->display;
1572 CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
1573 CoglRenderer *cogl_renderer = cogl_display->renderer;
1574 CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
1575 MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
1576 struct gbm_surface *new_gbm_surface = NULL;
1577 EGLNativeWindowType egl_native_window;
1578 EGLSurface new_egl_surface;
1579 uint32_t format;
1580 GArray *modifiers;
1581
1582 renderer_gpu_data =
1583 meta_renderer_native_get_gpu_data (renderer_native,
1584 onscreen_native->render_gpu);
1585
1586 format = get_gbm_format_from_egl (egl,
1587 cogl_renderer_egl->edpy,
1588 cogl_display_egl->egl_config);
1589
1590 if (meta_renderer_native_use_modifiers (renderer_native))
1591 modifiers = get_supported_modifiers (onscreen, format);
1592 else
1593 modifiers = NULL;
1594
1595 if (modifiers)
1596 {
1597 new_gbm_surface =
1598 gbm_surface_create_with_modifiers (renderer_gpu_data->gbm.device,
1599 width, height, format,
1600 (uint64_t *) modifiers->data,
1601 modifiers->len);
1602 g_array_free (modifiers, TRUE);
1603 }
1604
1605 if (!new_gbm_surface)
1606 {
1607 uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
1608
1609 if (should_surface_be_sharable (onscreen))
1610 flags |= GBM_BO_USE_LINEAR;
1611
1612 new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
1613 width, height,
1614 format,
1615 flags);
1616 }
1617
1618 if (!new_gbm_surface)
1619 {
1620 g_set_error (error, COGL_WINSYS_ERROR,
1621 COGL_WINSYS_ERROR_CREATE_ONSCREEN,
1622 "Failed to allocate surface");
1623 return FALSE;
1624 }
1625
1626 egl_native_window = (EGLNativeWindowType) new_gbm_surface;
1627 new_egl_surface =
1628 meta_egl_create_window_surface (egl,
1629 cogl_renderer_egl->edpy,
1630 cogl_display_egl->egl_config,
1631 egl_native_window,
1632 NULL,
1633 error);
1634 if (new_egl_surface == EGL_NO_SURFACE)
1635 {
1636 gbm_surface_destroy (new_gbm_surface);
1637 return FALSE;
1638 }
1639
1640 *gbm_surface = new_gbm_surface;
1641 *egl_surface = new_egl_surface;
1642
1643 return TRUE;
1644 }
1645
1646 #ifdef HAVE_EGL_DEVICE
1647 static gboolean
create_surfaces_egl_device(CoglOnscreen * onscreen,int width,int height,EGLStreamKHR * out_egl_stream,EGLSurface * out_egl_surface,GError ** error)1648 create_surfaces_egl_device (CoglOnscreen *onscreen,
1649 int width,
1650 int height,
1651 EGLStreamKHR *out_egl_stream,
1652 EGLSurface *out_egl_surface,
1653 GError **error)
1654 {
1655 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1656 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1657 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
1658 CoglDisplay *cogl_display = cogl_context->display;
1659 CoglDisplayEGL *cogl_display_egl = cogl_display->winsys;
1660 CoglRenderer *cogl_renderer = cogl_display->renderer;
1661 CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
1662 MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
1663 MetaEgl *egl =
1664 meta_renderer_native_get_egl (renderer_gpu_data->renderer_native);
1665 EGLDisplay egl_display = renderer_gpu_data->egl_display;
1666 EGLConfig egl_config;
1667 EGLStreamKHR egl_stream;
1668 EGLSurface egl_surface;
1669 EGLint num_layers;
1670 EGLOutputLayerEXT output_layer;
1671 EGLAttrib output_attribs[3];
1672 EGLint stream_attribs[] = {
1673 EGL_STREAM_FIFO_LENGTH_KHR, 0,
1674 EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
1675 EGL_NONE
1676 };
1677 EGLint stream_producer_attribs[] = {
1678 EGL_WIDTH, width,
1679 EGL_HEIGHT, height,
1680 EGL_NONE
1681 };
1682
1683 egl_stream = meta_egl_create_stream (egl, egl_display, stream_attribs, error);
1684 if (egl_stream == EGL_NO_STREAM_KHR)
1685 return FALSE;
1686
1687 output_attribs[0] = EGL_DRM_CRTC_EXT;
1688 output_attribs[1] = meta_crtc_get_id (onscreen_native->crtc);
1689 output_attribs[2] = EGL_NONE;
1690
1691 if (!meta_egl_get_output_layers (egl, egl_display,
1692 output_attribs,
1693 &output_layer, 1, &num_layers,
1694 error))
1695 {
1696 meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
1697 return FALSE;
1698 }
1699
1700 if (num_layers < 1)
1701 {
1702 meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
1703 g_set_error (error, G_IO_ERROR,
1704 G_IO_ERROR_FAILED,
1705 "Unable to find output layers.");
1706 return FALSE;
1707 }
1708
1709 if (!meta_egl_stream_consumer_output (egl, egl_display,
1710 egl_stream, output_layer,
1711 error))
1712 {
1713 meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
1714 return FALSE;
1715 }
1716
1717 egl_config = cogl_display_egl->egl_config;
1718 egl_surface = meta_egl_create_stream_producer_surface (egl,
1719 egl_display,
1720 egl_config,
1721 egl_stream,
1722 stream_producer_attribs,
1723 error);
1724 if (egl_surface == EGL_NO_SURFACE)
1725 {
1726 meta_egl_destroy_stream (egl, egl_display, egl_stream, NULL);
1727 return FALSE;
1728 }
1729
1730 *out_egl_stream = egl_stream;
1731 *out_egl_surface = egl_surface;
1732
1733 return TRUE;
1734 }
1735 #endif /* HAVE_EGL_DEVICE */
1736
1737 void
meta_onscreen_native_set_view(CoglOnscreen * onscreen,MetaRendererView * view)1738 meta_onscreen_native_set_view (CoglOnscreen *onscreen,
1739 MetaRendererView *view)
1740 {
1741 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1742 onscreen_native->view = view;
1743 }
1744
1745 static gboolean
meta_onscreen_native_allocate(CoglFramebuffer * framebuffer,GError ** error)1746 meta_onscreen_native_allocate (CoglFramebuffer *framebuffer,
1747 GError **error)
1748 {
1749 CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
1750 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1751 CoglOnscreenEgl *onscreen_egl = COGL_ONSCREEN_EGL (onscreen);
1752 MetaRendererNativeGpuData *renderer_gpu_data;
1753 struct gbm_surface *gbm_surface;
1754 EGLSurface egl_surface;
1755 int width;
1756 int height;
1757 #ifdef HAVE_EGL_DEVICE
1758 MetaDeviceFile *render_device_file;
1759 EGLStreamKHR egl_stream;
1760 #endif
1761 CoglFramebufferClass *parent_class;
1762
1763 if (META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc)) !=
1764 onscreen_native->render_gpu)
1765 {
1766 if (!init_secondary_gpu_state (onscreen_native->renderer_native,
1767 onscreen, error))
1768 return FALSE;
1769 }
1770
1771 width = cogl_framebuffer_get_width (framebuffer);
1772 height = cogl_framebuffer_get_height (framebuffer);
1773
1774 renderer_gpu_data =
1775 meta_renderer_native_get_gpu_data (onscreen_native->renderer_native,
1776 onscreen_native->render_gpu);
1777 switch (renderer_gpu_data->mode)
1778 {
1779 case META_RENDERER_NATIVE_MODE_GBM:
1780 if (!create_surfaces_gbm (onscreen,
1781 width, height,
1782 &gbm_surface,
1783 &egl_surface,
1784 error))
1785 return FALSE;
1786
1787 onscreen_native->gbm.surface = gbm_surface;
1788 cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface);
1789 break;
1790 case META_RENDERER_NATIVE_MODE_SURFACELESS:
1791 g_assert_not_reached ();
1792 break;
1793 #ifdef HAVE_EGL_DEVICE
1794 case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
1795 render_device_file = renderer_gpu_data->device_file;
1796 onscreen_native->egl.dumb_fb =
1797 meta_drm_buffer_dumb_new (render_device_file,
1798 width, height,
1799 DRM_FORMAT_XRGB8888,
1800 error);
1801 if (!onscreen_native->egl.dumb_fb)
1802 return FALSE;
1803
1804 if (!create_surfaces_egl_device (onscreen,
1805 width, height,
1806 &egl_stream,
1807 &egl_surface,
1808 error))
1809 return FALSE;
1810
1811 onscreen_native->egl.stream = egl_stream;
1812 cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface);
1813 break;
1814 #endif /* HAVE_EGL_DEVICE */
1815 }
1816
1817 parent_class = COGL_FRAMEBUFFER_CLASS (meta_onscreen_native_parent_class);
1818 return parent_class->allocate (framebuffer, error);
1819 }
1820
1821 static gboolean
init_secondary_gpu_state_gpu_copy_mode(MetaRendererNative * renderer_native,CoglOnscreen * onscreen,MetaRendererNativeGpuData * renderer_gpu_data,GError ** error)1822 init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative *renderer_native,
1823 CoglOnscreen *onscreen,
1824 MetaRendererNativeGpuData *renderer_gpu_data,
1825 GError **error)
1826 {
1827 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1828 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1829 MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
1830 int width, height;
1831 EGLNativeWindowType egl_native_window;
1832 struct gbm_surface *gbm_surface;
1833 EGLSurface egl_surface;
1834 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
1835 MetaGpuKms *gpu_kms;
1836 uint32_t format;
1837
1838 width = cogl_framebuffer_get_width (framebuffer);
1839 height = cogl_framebuffer_get_height (framebuffer);
1840 format = get_gbm_format_from_egl (egl,
1841 renderer_gpu_data->egl_display,
1842 renderer_gpu_data->secondary.egl_config);
1843
1844 gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device,
1845 width, height,
1846 format,
1847 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
1848 if (!gbm_surface)
1849 {
1850 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1851 "Failed to create gbm_surface: %s", strerror (errno));
1852 return FALSE;
1853 }
1854
1855 egl_native_window = (EGLNativeWindowType) gbm_surface;
1856 egl_surface =
1857 meta_egl_create_window_surface (egl,
1858 renderer_gpu_data->egl_display,
1859 renderer_gpu_data->secondary.egl_config,
1860 egl_native_window,
1861 NULL,
1862 error);
1863 if (egl_surface == EGL_NO_SURFACE)
1864 {
1865 gbm_surface_destroy (gbm_surface);
1866 return FALSE;
1867 }
1868
1869 secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
1870
1871 gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc));
1872 secondary_gpu_state->gpu_kms = gpu_kms;
1873 secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
1874 secondary_gpu_state->gbm.surface = gbm_surface;
1875 secondary_gpu_state->egl_surface = egl_surface;
1876
1877 onscreen_native->secondary_gpu_state = secondary_gpu_state;
1878
1879 return TRUE;
1880 }
1881
1882 static uint32_t
pick_secondary_gpu_framebuffer_format_for_cpu(CoglOnscreen * onscreen)1883 pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen)
1884 {
1885 /*
1886 * cogl_framebuffer_read_pixels_into_bitmap () supported formats in
1887 * preference order. Ideally these should depend on the render buffer
1888 * format copy_shared_framebuffer_cpu () will be reading from but
1889 * alpha channel ignored.
1890 */
1891 static const uint32_t preferred_formats[] =
1892 {
1893 /*
1894 * DRM_FORMAT_XBGR8888 a.k.a GL_RGBA, GL_UNSIGNED_BYTE on
1895 * little-endian is possibly the most optimized glReadPixels
1896 * output format. glReadPixels cannot avoid manufacturing an alpha
1897 * channel if the render buffer does not have one and converting
1898 * to ABGR8888 may be more optimized than ARGB8888.
1899 */
1900 DRM_FORMAT_XBGR8888,
1901 /* The rest are other fairly commonly used formats in OpenGL. */
1902 DRM_FORMAT_XRGB8888,
1903 };
1904 g_autoptr (GArray) formats = NULL;
1905 size_t k;
1906 unsigned int i;
1907 uint32_t drm_format;
1908
1909 formats = get_supported_kms_formats (onscreen);
1910
1911 /* Check if any of our preferred formats are supported. */
1912 for (k = 0; k < G_N_ELEMENTS (preferred_formats); k++)
1913 {
1914 g_assert (meta_cogl_pixel_format_from_drm_format (preferred_formats[k],
1915 NULL,
1916 NULL));
1917
1918 for (i = 0; i < formats->len; i++)
1919 {
1920 drm_format = g_array_index (formats, uint32_t, i);
1921
1922 if (drm_format == preferred_formats[k])
1923 return drm_format;
1924 }
1925 }
1926
1927 /*
1928 * Otherwise just pick an arbitrary format we recognize. The formats
1929 * list is not in any specific order and we don't know any better
1930 * either.
1931 */
1932 for (i = 0; i < formats->len; i++)
1933 {
1934 drm_format = g_array_index (formats, uint32_t, i);
1935
1936 if (meta_cogl_pixel_format_from_drm_format (drm_format, NULL, NULL))
1937 return drm_format;
1938 }
1939
1940 return DRM_FORMAT_INVALID;
1941 }
1942
1943 static gboolean
init_secondary_gpu_state_cpu_copy_mode(MetaRendererNative * renderer_native,CoglOnscreen * onscreen,MetaRendererNativeGpuData * renderer_gpu_data,GError ** error)1944 init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_native,
1945 CoglOnscreen *onscreen,
1946 MetaRendererNativeGpuData *renderer_gpu_data,
1947 GError **error)
1948 {
1949 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
1950 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
1951 MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
1952 MetaGpuKms *gpu_kms;
1953 MetaDeviceFile *device_file;
1954 int width, height;
1955 unsigned int i;
1956 uint32_t drm_format;
1957 MetaDrmFormatBuf tmp;
1958
1959 drm_format = pick_secondary_gpu_framebuffer_format_for_cpu (onscreen);
1960 if (drm_format == DRM_FORMAT_INVALID)
1961 {
1962 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1963 "Could not find a suitable pixel format in CPU copy mode");
1964 return FALSE;
1965 }
1966
1967 width = cogl_framebuffer_get_width (framebuffer);
1968 height = cogl_framebuffer_get_height (framebuffer);
1969
1970 gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (onscreen_native->crtc));
1971 device_file = renderer_gpu_data->device_file;
1972 meta_topic (META_DEBUG_KMS,
1973 "Secondary GPU %s using DRM format '%s' (0x%x) for a %dx%d output.",
1974 meta_device_file_get_path (device_file),
1975 meta_drm_format_to_string (&tmp, drm_format),
1976 drm_format,
1977 width, height);
1978
1979 secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1);
1980 secondary_gpu_state->renderer_gpu_data = renderer_gpu_data;
1981 secondary_gpu_state->gpu_kms = gpu_kms;
1982 secondary_gpu_state->egl_surface = EGL_NO_SURFACE;
1983
1984 for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++)
1985 {
1986 secondary_gpu_state->cpu.dumb_fbs[i] =
1987 meta_drm_buffer_dumb_new (device_file,
1988 width, height,
1989 drm_format,
1990 error);
1991 if (!secondary_gpu_state->cpu.dumb_fbs[i])
1992 {
1993 secondary_gpu_state_free (secondary_gpu_state);
1994 return FALSE;
1995 }
1996 }
1997
1998 /*
1999 * This function initializes everything needed for
2000 * META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO as well.
2001 */
2002 secondary_gpu_state->import_status =
2003 META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE;
2004
2005 onscreen_native->secondary_gpu_state = secondary_gpu_state;
2006
2007 return TRUE;
2008 }
2009
2010 static gboolean
init_secondary_gpu_state(MetaRendererNative * renderer_native,CoglOnscreen * onscreen,GError ** error)2011 init_secondary_gpu_state (MetaRendererNative *renderer_native,
2012 CoglOnscreen *onscreen,
2013 GError **error)
2014 {
2015 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
2016 MetaGpu *gpu = meta_crtc_get_gpu (onscreen_native->crtc);
2017 MetaRendererNativeGpuData *renderer_gpu_data;
2018
2019 renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
2020 META_GPU_KMS (gpu));
2021
2022 switch (renderer_gpu_data->secondary.copy_mode)
2023 {
2024 case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU:
2025 if (!init_secondary_gpu_state_gpu_copy_mode (renderer_native,
2026 onscreen,
2027 renderer_gpu_data,
2028 error))
2029 return FALSE;
2030 break;
2031 case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO:
2032 /*
2033 * Initialize also the primary copy mode, so that if zero-copy
2034 * path fails, which is quite likely, we can simply continue
2035 * with the primary copy path on the very first frame.
2036 */
2037 G_GNUC_FALLTHROUGH;
2038 case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY:
2039 if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
2040 onscreen,
2041 renderer_gpu_data,
2042 error))
2043 return FALSE;
2044 break;
2045 }
2046
2047 return TRUE;
2048 }
2049
2050 MetaOnscreenNative *
meta_onscreen_native_new(MetaRendererNative * renderer_native,MetaGpuKms * render_gpu,MetaOutput * output,MetaCrtc * crtc,CoglContext * cogl_context,int width,int height)2051 meta_onscreen_native_new (MetaRendererNative *renderer_native,
2052 MetaGpuKms *render_gpu,
2053 MetaOutput *output,
2054 MetaCrtc *crtc,
2055 CoglContext *cogl_context,
2056 int width,
2057 int height)
2058 {
2059 MetaOnscreenNative *onscreen_native;
2060 CoglFramebufferDriverConfig driver_config;
2061
2062 driver_config = (CoglFramebufferDriverConfig) {
2063 .type = COGL_FRAMEBUFFER_DRIVER_TYPE_BACK,
2064 };
2065 onscreen_native = g_object_new (META_TYPE_ONSCREEN_NATIVE,
2066 "context", cogl_context,
2067 "driver-config", &driver_config,
2068 "width", width,
2069 "height", height,
2070 NULL);
2071
2072 onscreen_native->renderer_native = renderer_native;
2073 onscreen_native->render_gpu = render_gpu;
2074 onscreen_native->output = output;
2075 onscreen_native->crtc = crtc;
2076
2077 return onscreen_native;
2078 }
2079
2080 static void
meta_onscreen_native_dispose(GObject * object)2081 meta_onscreen_native_dispose (GObject *object)
2082 {
2083 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (object);
2084 CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
2085 MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen);
2086 MetaRendererNative *renderer_native = onscreen_native->renderer_native;
2087 MetaRendererNativeGpuData *renderer_gpu_data;
2088
2089 renderer_gpu_data =
2090 meta_renderer_native_get_gpu_data (renderer_native,
2091 onscreen_native->render_gpu);
2092 switch (renderer_gpu_data->mode)
2093 {
2094 case META_RENDERER_NATIVE_MODE_GBM:
2095 /* flip state takes a reference on the onscreen so there should
2096 * never be outstanding flips when we reach here. */
2097 g_warn_if_fail (onscreen_native->gbm.next_fb == NULL);
2098
2099 free_current_bo (onscreen);
2100 break;
2101 case META_RENDERER_NATIVE_MODE_SURFACELESS:
2102 g_assert_not_reached ();
2103 break;
2104 #ifdef HAVE_EGL_DEVICE
2105 case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
2106 g_clear_object (&onscreen_native->egl.dumb_fb);
2107
2108 if (onscreen_native->egl.stream != EGL_NO_STREAM_KHR)
2109 {
2110 MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native);
2111 CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer);
2112 CoglRenderer *cogl_renderer = cogl_context->display->renderer;
2113 CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
2114
2115 meta_egl_destroy_stream (egl,
2116 cogl_renderer_egl->edpy,
2117 onscreen_native->egl.stream,
2118 NULL);
2119 onscreen_native->egl.stream = EGL_NO_STREAM_KHR;
2120 }
2121 break;
2122 #endif /* HAVE_EGL_DEVICE */
2123 }
2124
2125 G_OBJECT_CLASS (meta_onscreen_native_parent_class)->dispose (object);
2126
2127 g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy);
2128 g_clear_pointer (&onscreen_native->secondary_gpu_state,
2129 secondary_gpu_state_free);
2130 }
2131
2132 static void
meta_onscreen_native_init(MetaOnscreenNative * onscreen_native)2133 meta_onscreen_native_init (MetaOnscreenNative *onscreen_native)
2134 {
2135 }
2136
2137 static void
meta_onscreen_native_class_init(MetaOnscreenNativeClass * klass)2138 meta_onscreen_native_class_init (MetaOnscreenNativeClass *klass)
2139 {
2140 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2141 CoglFramebufferClass *framebuffer_class = COGL_FRAMEBUFFER_CLASS (klass);
2142 CoglOnscreenClass *onscreen_class = COGL_ONSCREEN_CLASS (klass);
2143
2144 object_class->dispose = meta_onscreen_native_dispose;
2145
2146 framebuffer_class->allocate = meta_onscreen_native_allocate;
2147
2148 onscreen_class->swap_buffers_with_damage =
2149 meta_onscreen_native_swap_buffers_with_damage;
2150 onscreen_class->direct_scanout = meta_onscreen_native_direct_scanout;
2151 }
2152