diff --git a/src/backends/native/meta-renderer-native-gles3.c b/src/backends/native/meta-renderer-native-gles3.c index 7afea8648..4665add83 100644 --- a/src/backends/native/meta-renderer-native-gles3.c +++ b/src/backends/native/meta-renderer-native-gles3.c @@ -179,6 +179,97 @@ paint_egl_image (MetaGles3 *gles3, GL_NEAREST)); } +/* FIXME: all these declarations are just floating here + */ +struct __attribute__ ((__packed__)) position +{ + float x, y; +}; + +struct __attribute__ ((__packed__)) texture_coordinate +{ + float u, v; +}; + +struct __attribute__ ((__packed__)) vertex +{ + struct position position; + struct texture_coordinate texture_coordinate; +}; + +struct __attribute__ ((__packed__)) triangle +{ + unsigned int first_vertex; + unsigned int middle_vertex; + unsigned int last_vertex; +}; + +enum +{ + RIGHT_TOP_VERTEX = 0, + BOTTOM_RIGHT_VERTEX, + BOTTOM_LEFT_VERTEX, + TOP_LEFT_VERTEX +}; + +static const float view_left = -1.0f, view_right = 1.0f, view_top = 1.0f, view_bottom = -1.0f; +static const float texture_left = 0.0f, texture_right = 1.0f, texture_top = 0.0f, texture_bottom = 1.0f; +static GLuint vertex_array; +static GLuint vertex_buffer; +static GLuint triangle_buffer; + +struct vertex vertices[] = { + [RIGHT_TOP_VERTEX] = {{view_right, view_top}, + {texture_right, texture_top}}, + [BOTTOM_RIGHT_VERTEX] = {{view_right, view_bottom}, + {texture_right, texture_bottom}}, + [BOTTOM_LEFT_VERTEX] = {{view_left, view_bottom}, + {texture_left, texture_bottom}}, + [TOP_LEFT_VERTEX] = {{view_left, view_top}, + {texture_left, texture_top}}, +}; + +struct triangle triangles[] = { + {TOP_LEFT_VERTEX, BOTTOM_RIGHT_VERTEX, BOTTOM_LEFT_VERTEX}, + {TOP_LEFT_VERTEX, RIGHT_TOP_VERTEX, BOTTOM_RIGHT_VERTEX}, +}; + +gboolean +meta_renderer_native_gles3_draw_pixels (MetaEgl *egl, + MetaGles3 *gles3, + unsigned int width, + unsigned int height, + uint8_t *pixels, + GError **error) +{ + meta_gles3_clear_error (gles3); + + GLBAS (gles3, glClearColor, (0.0,1.0,0.0,1.0)); + GLBAS (gles3, glClear, (GL_COLOR_BUFFER_BIT)); + + GLBAS (gles3, glViewport, (0, 0, width, height)); + GLBAS (gles3, glTexImage2D, (GL_TEXTURE_2D, 0, GL_RGBA, + width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, pixels)); + + GLBAS (gles3, glBindBuffer, (GL_ARRAY_BUFFER, vertex_buffer)); + GLBAS (gles3, glEnableVertexAttribArray, (0)); + GLBAS (gles3, glVertexAttribPointer, (0, + sizeof (struct position) / sizeof (float), GL_FLOAT, + GL_FALSE, + sizeof (struct vertex), (void *) offsetof (struct vertex, position))); + GLBAS (gles3, glEnableVertexAttribArray, (1)); + GLBAS (gles3, glVertexAttribPointer, (1, + sizeof (struct texture_coordinate) / sizeof (float), GL_FLOAT, + GL_FALSE, + sizeof (struct vertex), (void *) offsetof (struct vertex, texture_coordinate))); + GLBAS (gles3, glDrawElements, (GL_TRIANGLES, + G_N_ELEMENTS (triangles) * (sizeof (struct triangle) / sizeof (unsigned int)), GL_UNSIGNED_INT, + 0)); + + return TRUE; +} + gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, MetaGles3 *gles3, @@ -238,3 +329,126 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, return TRUE; } + +static void +meta_renderer_native_gles3_load_basic_shaders (MetaEgl *egl, + MetaGles3 *gles3) +{ + GLuint vertex_shader = 0, fragment_shader = 0, shader_program; + gboolean status = FALSE; + const char *vertex_shader_source = +"#version 330 core\n" +"layout (location = 0) in vec2 position;\n" +"layout (location = 1) in vec2 input_texture_coords;\n" +"out vec2 texture_coords;\n" +"void main()\n" +"{\n" +" gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);\n" +" texture_coords = input_texture_coords;\n" +"}\n"; + + const char *fragment_shader_source = +"#version 330 core\n" +"uniform sampler2D input_texture;\n" +"in vec2 texture_coords;\n" +"out vec4 output_color;\n" +"void main()\n" +"{\n" +/* FIXME: cogl uses a framebuffer format of COGL_PIXEL_FORMAT_RGBA_8888_PRE + * by default which maps to DRM_FORMAT_ABGR8888 on little endian. The + * destination format is DRM_FORMAT_XRGB8888, so the color channels are + * swapped. The .bgra swizzle here swaps it back, but we should see if + * we can find a better fix (this probably breaks on big endian) */ +" output_color = texture(input_texture, texture_coords).bgra;\n" +"}\n"; + + vertex_shader = glCreateShader (GL_VERTEX_SHADER); + glShaderSource (vertex_shader, 1, &vertex_shader_source, NULL); + glCompileShader (vertex_shader); + glGetShaderiv (vertex_shader, GL_COMPILE_STATUS, &status); + + if (!status) + { + char compile_log[1024] = ""; + glGetShaderInfoLog (vertex_shader, sizeof (compile_log), NULL, compile_log); + g_warning ("vertex shader compilation failed:\n %s\n", compile_log); + goto out; + } + + fragment_shader = glCreateShader (GL_FRAGMENT_SHADER); + glShaderSource (fragment_shader, 1, &fragment_shader_source, NULL); + glCompileShader (fragment_shader); + glGetShaderiv (fragment_shader, GL_COMPILE_STATUS, &status); + + if (!status) + { + char compile_log[1024] = ""; + glGetShaderInfoLog (fragment_shader, sizeof (compile_log), NULL, compile_log); + g_warning ("fragment shader compilation failed:\n %s\n", compile_log); + goto out; + } + + shader_program = glCreateProgram (); + glAttachShader (shader_program, vertex_shader); + glAttachShader (shader_program, fragment_shader); + glLinkProgram (shader_program); + + glGetProgramiv (shader_program, GL_LINK_STATUS, &status); + + if (!status) + { + char link_log[1024] = ""; + + glGetProgramInfoLog (shader_program, sizeof (link_log), NULL, link_log); + g_warning ("shader link failed:\n %s\n", link_log); + goto out; + } + + glUseProgram (shader_program); + +out: + if (vertex_shader) + glDeleteShader (vertex_shader); + if (fragment_shader) + glDeleteShader (fragment_shader); +} + +gboolean +meta_renderer_native_gles3_prepare_for_drawing (MetaEgl *egl, + MetaGles3 *gles3, + GError **error) +{ + GLuint texture; + + meta_renderer_native_gles3_load_basic_shaders (egl, gles3); + + meta_gles3_clear_error (gles3); + + GLBAS (gles3, glGenVertexArrays, (1, &vertex_array)); + GLBAS (gles3, glBindVertexArray, (vertex_array)); + + GLBAS (gles3, glGenBuffers, (1, &vertex_buffer)); + GLBAS (gles3, glBindBuffer, (GL_ARRAY_BUFFER, vertex_buffer)); + GLBAS (gles3, glBufferData, (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STREAM_DRAW)); + + GLBAS (gles3, glGenBuffers, (1, &triangle_buffer)); + GLBAS (gles3, glBindBuffer, (GL_ELEMENT_ARRAY_BUFFER, triangle_buffer)); + GLBAS (gles3, glBufferData, (GL_ELEMENT_ARRAY_BUFFER, sizeof (triangles), triangles, GL_STREAM_DRAW)); + + GLBAS (gles3, glActiveTexture, (GL_TEXTURE0)); + GLBAS (gles3, glGenTextures, (1, &texture)); + GLBAS (gles3, glBindTexture, (GL_TEXTURE_2D, texture)); + + GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_NEAREST)); + GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST)); + GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE)); + GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE)); + GLBAS (gles3, glTexParameteri, (GL_TEXTURE_2D, GL_TEXTURE_WRAP_R_OES, + GL_CLAMP_TO_EDGE)); + + return TRUE; +} diff --git a/src/backends/native/meta-renderer-native-gles3.h b/src/backends/native/meta-renderer-native-gles3.h index 4e7324c8d..1de13f9be 100644 --- a/src/backends/native/meta-renderer-native-gles3.h +++ b/src/backends/native/meta-renderer-native-gles3.h @@ -37,4 +37,15 @@ gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, struct gbm_bo *shared_bo, GError **error); +gboolean meta_renderer_native_gles3_prepare_for_drawing (MetaEgl *egl, + MetaGles3 *gles3, + GError **error); + +gboolean meta_renderer_native_gles3_draw_pixels (MetaEgl *egl, + MetaGles3 *gles3, + unsigned int width, + unsigned int height, + uint8_t *pixels, + GError **error); + #endif /* META_RENDERER_NATIVE_GLES3_H */ diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index d57a76d4e..59f3147d7 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -84,7 +84,10 @@ static GParamSpec *obj_props[PROP_LAST]; typedef enum _MetaSharedFramebufferCopyMode { META_SHARED_FRAMEBUFFER_COPY_MODE_GPU, - META_SHARED_FRAMEBUFFER_COPY_MODE_CPU + META_SHARED_FRAMEBUFFER_COPY_MODE_CPU, +#ifdef HAVE_EGL_DEVICE + META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM +#endif } MetaSharedFramebufferCopyMode; typedef struct _MetaRendererNativeGpuData @@ -111,6 +114,7 @@ typedef struct _MetaRendererNativeGpuData * Fields used for blitting iGPU framebuffer content onto dGPU framebuffers. */ struct { + MetaRendererNativeMode mode; MetaSharedFramebufferCopyMode copy_mode; #ifdef HAVE_EGL_DEVICE @@ -150,6 +154,14 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState struct gbm_bo *next_bo; } gbm; +#ifdef HAVE_EGL_DEVICE + struct { + uint8_t *copied_pixels; + MetaDumbBuffer dumb_fb; + EGLStreamKHR stream; + } egl; +#endif + struct { MetaDumbBuffer *dumb_fb; MetaDumbBuffer dumb_fbs[2]; @@ -235,6 +247,19 @@ init_dumb_fb (MetaDumbBuffer *dumb_fb, uint32_t format, GError **error); +#ifdef HAVE_EGL_DEVICE +static gboolean +meta_renderer_native_create_surface_egl_device (CoglOnscreen *onscreen, + MetaMonitor *monitor, + EGLDisplay egl_display, + EGLConfig egl_config, + int width, + int height, + EGLStreamKHR *out_egl_stream, + EGLSurface *out_egl_surface, + GError **error); +#endif + static MetaEgl * meta_renderer_native_get_egl (MetaRendererNative *renderer_native); @@ -640,6 +665,63 @@ init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative *renderer_nat return TRUE; } +#ifdef HAVE_EGL_DEVICE +static gboolean +init_secondary_gpu_state_stream_copy_mode (MetaRendererNative *renderer_native, + CoglOnscreen *onscreen, + MetaMonitor *monitor, + MetaRendererNativeGpuData *renderer_gpu_data, + MetaGpuKms *gpu_kms, + GError **error) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + EGLStreamKHR egl_stream; + int width, height; + EGLSurface egl_surface; + MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; + + width = cogl_framebuffer_get_width (framebuffer); + height = cogl_framebuffer_get_height (framebuffer); + + secondary_gpu_state = g_new0 (MetaOnscreenNativeSecondaryGpuState, 1); + + if (!init_dumb_fb (&secondary_gpu_state->egl.dumb_fb, + gpu_kms, + width, height, + DRM_FORMAT_XRGB8888, + error)) + goto failed; + + if (!meta_renderer_native_create_surface_egl_device (onscreen, + monitor, + renderer_gpu_data->secondary.egl_display, + renderer_gpu_data->secondary.egl_config, + width, height, + &egl_stream, + &egl_surface, + error)) + goto failed; + + secondary_gpu_state->gpu_kms = gpu_kms; + secondary_gpu_state->renderer_gpu_data = renderer_gpu_data; + secondary_gpu_state->egl.stream = egl_stream; + secondary_gpu_state->egl.copied_pixels = g_malloc (width * height * 4); + secondary_gpu_state->egl_surface = egl_surface; + + g_hash_table_insert (onscreen_native->secondary_gpu_states, + gpu_kms, secondary_gpu_state); + + return TRUE; + +failed: + if (secondary_gpu_state->egl.dumb_fb.fb_id) + release_dumb_fb (&secondary_gpu_state->egl.dumb_fb, gpu_kms); + return FALSE; +} +#endif + static void secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) { @@ -648,6 +730,25 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta MetaGpuKms *gpu_kms = secondary_gpu_state->gpu_kms; unsigned int i; +#ifdef HAVE_EGL_DEVICE + if (secondary_gpu_state->egl.dumb_fb.fb_id) + release_dumb_fb (&secondary_gpu_state->egl.dumb_fb, gpu_kms); + + if (secondary_gpu_state->egl.stream != EGL_NO_STREAM_KHR) + { + MetaRendererNativeGpuData *renderer_gpu_data; + + renderer_gpu_data = secondary_gpu_state->renderer_gpu_data; + meta_egl_destroy_stream (egl, + renderer_gpu_data->secondary.egl_display, + secondary_gpu_state->egl.stream, + NULL); + secondary_gpu_state->egl.stream = EGL_NO_STREAM_KHR; + g_clear_pointer (&secondary_gpu_state->egl.copied_pixels, + g_free); + } +#endif + if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE) { MetaRendererNativeGpuData *renderer_gpu_data; @@ -720,6 +821,7 @@ init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_nat static gboolean init_secondary_gpu_state (MetaRendererNative *renderer_native, CoglOnscreen *onscreen, + MetaMonitor *monitor, MetaGpuKms *gpu_kms, GError **error) { @@ -738,6 +840,17 @@ init_secondary_gpu_state (MetaRendererNative *renderer_native, error)) return FALSE; break; +#ifdef HAVE_EGL_DEVICE + case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM: + if (!init_secondary_gpu_state_stream_copy_mode (renderer_native, + onscreen, + monitor, + renderer_gpu_data, + gpu_kms, + error)) + return FALSE; + break; +#endif case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native, onscreen, @@ -838,6 +951,10 @@ free_current_secondary_bo (MetaGpuKms *gpu_kms, secondary_gpu_state->gbm.current_bo = NULL; } break; +#ifdef HAVE_EGL_DEVICE + case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM: + break; +#endif case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: break; } @@ -1272,6 +1389,10 @@ free_next_secondary_bo (MetaGpuKms *gpu_kms, secondary_gpu_state->gbm.next_bo = NULL; } break; +#ifdef HAVE_EGL_DEVICE + case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM: + break; +#endif case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: break; } @@ -1395,6 +1516,29 @@ flip_primary_egl_stream (MetaOnscreenNative *onscreen_native, return ret; } + +static gboolean +flip_secondary_gpu_egl_stream (MetaOnscreenNative *onscreen_native, + MetaGpuKms *gpu_kms, + MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, + GClosure *flip_closure) +{ + MetaRendererNativeGpuData *renderer_gpu_data; + gboolean ret; + + renderer_gpu_data = + meta_renderer_native_get_gpu_data (onscreen_native->renderer_native, + gpu_kms); + + ret = flip_egl_stream (onscreen_native, + gpu_kms, + renderer_gpu_data->secondary.egl_display, + secondary_gpu_state->egl.stream, + flip_closure); + g_closure_ref (flip_closure); + + return ret; +} #endif /* HAVE_EGL_DEVICE */ static void @@ -1423,7 +1567,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, } renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); + gpu_kms); if (gpu_kms == render_gpu) { @@ -1460,9 +1604,25 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: - if (flip_primary_egl_stream (onscreen_native, - flip_closure)) - onscreen_native->total_pending_flips++; + if (gpu_kms == render_gpu) + { + if (!flip_primary_egl_stream (onscreen_native, + flip_closure)) + return; + } + else + { + if (!flip_secondary_gpu_egl_stream (onscreen_native, + gpu_kms, + secondary_gpu_state, + flip_closure)) + return; + } + + onscreen_native->total_pending_flips++; + if (secondary_gpu_state) + secondary_gpu_state->pending_flips++; + *fb_in_use = TRUE; break; #endif @@ -1496,12 +1656,25 @@ set_crtc_fb (MetaLogicalMonitor *logical_monitor, else { MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; + MetaRendererNativeGpuData *renderer_gpu_data; secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms); if (!secondary_gpu_state) return; - fb_id = secondary_gpu_state->gbm.next_fb_id; + renderer_gpu_data = secondary_gpu_state->renderer_gpu_data; + + switch (renderer_gpu_data->secondary.mode) + { + case META_RENDERER_NATIVE_MODE_GBM: + fb_id = secondary_gpu_state->gbm.next_fb_id; + break; +#ifdef HAVE_EGL_DEVICE + case META_RENDERER_NATIVE_MODE_EGL_DEVICE: + fb_id = secondary_gpu_state->egl.dumb_fb.fb_id; + break; +#endif + } } x = crtc->rect.x - logical_monitor->rect.x; @@ -1849,6 +2022,60 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, &secondary_gpu_state->gbm.next_fb_id); } +#ifdef HAVE_EGL_DEVICE +static void +draw_shared_framebuffer_stream (CoglOnscreen *onscreen, + MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, + MetaRendererNativeGpuData *renderer_gpu_data, + gboolean *egl_context_changed) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaRendererNative *renderer_native = onscreen_native->renderer_native; + GError *error = NULL; + MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); + uint32_t width, height; + void *target_data; + + width = cogl_framebuffer_get_width (framebuffer); + height = cogl_framebuffer_get_height (framebuffer); + + target_data = secondary_gpu_state->egl.copied_pixels; + + if (!meta_egl_make_current (egl, + renderer_gpu_data->secondary.egl_display, + secondary_gpu_state->egl_surface, + secondary_gpu_state->egl_surface, + renderer_gpu_data->secondary.egl_context, + &error)) + { + g_warning ("Failed to make current: %s", error->message); + g_error_free (error); + return; + } + + *egl_context_changed = TRUE; + + meta_renderer_native_gles3_draw_pixels (egl, + renderer_native->gles3, + width, + height, + target_data, + &error); + + if (!meta_egl_swap_buffers (egl, + renderer_gpu_data->secondary.egl_display, + secondary_gpu_state->egl_surface, + &error)) + { + g_warning ("Failed to swap buffers: %s", error->message); + g_error_free (error); + return; + } +} +#endif + typedef struct _PixelFormatMap { uint32_t drm_format; CoglPixelFormat cogl_format; @@ -1968,6 +2195,48 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen, secondary_gpu_state->gbm.next_fb_id = target_fb_id; } +#ifdef HAVE_EGL_DEVICE +static void +copy_shared_framebuffer_stream (CoglOnscreen *onscreen, + MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, + MetaRendererNativeGpuData *renderer_gpu_data) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *cogl_context = framebuffer->context; + int width, height; + uint8_t *target_data; + uint32_t target_drm_format = DRM_FORMAT_XRGB8888; + CoglBitmap *dumb_bitmap; + CoglPixelFormat cogl_format; + gboolean ret; + + width = cogl_framebuffer_get_width (framebuffer); + height = cogl_framebuffer_get_height (framebuffer); + target_data = secondary_gpu_state->egl.copied_pixels; + + ret = cogl_pixel_format_from_drm_format (target_drm_format, + &cogl_format, + NULL); + g_assert (ret); + + dumb_bitmap = cogl_bitmap_new_for_data (cogl_context, + width, + height, + cogl_format, + width * 4, + target_data); + + if (!cogl_framebuffer_read_pixels_into_bitmap (framebuffer, + 0 /* x */, + 0 /* y */, + COGL_READ_PIXELS_COLOR_BUFFER, + dumb_bitmap)) + g_warning ("Failed to read pixels from primary renderer"); + + cogl_object_unref (dumb_bitmap); +} +#endif + static void update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen) { @@ -1989,6 +2258,13 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen) case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU: /* Done after eglSwapBuffers. */ break; +#ifdef HAVE_EGL_DEVICE + case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM: + copy_shared_framebuffer_stream (onscreen, + secondary_gpu_state, + renderer_gpu_data); + break; +#endif case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: copy_shared_framebuffer_cpu (onscreen, secondary_gpu_state, @@ -2026,6 +2302,14 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, renderer_gpu_data, egl_context_changed); break; +#ifdef HAVE_EGL_DEVICE + case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM: + draw_shared_framebuffer_stream (onscreen, + secondary_gpu_state, + renderer_gpu_data, + egl_context_changed); + break; +#endif case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: /* Done before eglSwapBuffers. */ break; @@ -2815,7 +3099,7 @@ meta_renderer_native_create_onscreen (MetaRendererNative *renderer_native, if (get_secondary_gpu_state (onscreen, gpu_kms)) continue; - if (!init_secondary_gpu_state (renderer_native, onscreen, gpu_kms, error)) + if (!init_secondary_gpu_state (renderer_native, onscreen, monitor, gpu_kms, error)) { cogl_object_unref (onscreen); return NULL; @@ -3267,11 +3551,55 @@ init_secondary_gpu_data_gpu (MetaRendererNativeGpuData *renderer_gpu_data, renderer_gpu_data->secondary.egl_context = egl_context; renderer_gpu_data->secondary.egl_config = egl_config; + renderer_gpu_data->secondary.mode = META_RENDERER_NATIVE_MODE_GBM; renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU; return TRUE; } +#ifdef HAVE_EGL_DEVICE +static gboolean +init_secondary_gpu_data_stream (MetaRendererNativeGpuData *renderer_gpu_data, + GError **error) +{ + MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); + EGLDisplay egl_display = renderer_gpu_data->secondary.egl_display; + EGLConfig egl_config; + EGLContext egl_context; + + if (!create_secondary_egl_config (egl, + renderer_gpu_data->secondary.mode, egl_display, + &egl_config, error)) + return FALSE; + + egl_context = create_secondary_egl_context (egl, egl_display, egl_config, error); + if (egl_context == EGL_NO_CONTEXT) + return FALSE; + + meta_renderer_native_ensure_gles3 (renderer_native); + + if (!meta_egl_make_current (egl, + egl_display, + EGL_NO_SURFACE, + EGL_NO_SURFACE, + egl_context, + error)) + { + meta_egl_destroy_context (egl, egl_display, egl_context, NULL); + return FALSE; + } + + meta_renderer_native_gles3_prepare_for_drawing (egl, renderer_native->gles3, NULL); + + renderer_gpu_data->secondary.egl_context = egl_context; + renderer_gpu_data->secondary.egl_config = egl_config; + renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM; + + return TRUE; +} +#endif + static void init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data) { @@ -3283,8 +3611,20 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data) { GError *error = NULL; - if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error)) - return; + switch (renderer_gpu_data->secondary.mode) + { + case META_RENDERER_NATIVE_MODE_GBM: + if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error)) + return; + break; + +#ifdef HAVE_EGL_DEVICE + case META_RENDERER_NATIVE_MODE_EGL_DEVICE: + if (init_secondary_gpu_data_stream (renderer_gpu_data, &error)) + return; + break; +#endif + } g_warning ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s", error->message);