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