wip! renderer/native: start to add stream copy mode

At the moment, mutter only supports using GBM for
doing GPU blits to secondary video cards.

This commit starts to sketch out using eglstreams
for doing the copy.

FIXME: in order to get memcpy fastpath we get
inverted colors and have to fix it up in the shader.

FIXME: need to move some of the globals to be in
a more structured place

Closes https://gitlab.gnome.org/GNOME/mutter/issues/205
This commit is contained in:
Ray Strode 2018-09-13 13:36:52 -04:00
parent 8f538671d6
commit 82f03c51ac
3 changed files with 574 additions and 9 deletions

View File

@ -179,6 +179,97 @@ paint_egl_image (MetaGles3 *gles3,
GL_NEAREST)); 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 gboolean
meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl,
MetaGles3 *gles3, MetaGles3 *gles3,
@ -238,3 +329,126 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl,
return TRUE; 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;
}

View File

@ -37,4 +37,15 @@ gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl,
struct gbm_bo *shared_bo, struct gbm_bo *shared_bo,
GError **error); 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 */ #endif /* META_RENDERER_NATIVE_GLES3_H */

View File

@ -84,7 +84,10 @@ static GParamSpec *obj_props[PROP_LAST];
typedef enum _MetaSharedFramebufferCopyMode typedef enum _MetaSharedFramebufferCopyMode
{ {
META_SHARED_FRAMEBUFFER_COPY_MODE_GPU, 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; } MetaSharedFramebufferCopyMode;
typedef struct _MetaRendererNativeGpuData typedef struct _MetaRendererNativeGpuData
@ -111,6 +114,7 @@ typedef struct _MetaRendererNativeGpuData
* Fields used for blitting iGPU framebuffer content onto dGPU framebuffers. * Fields used for blitting iGPU framebuffer content onto dGPU framebuffers.
*/ */
struct { struct {
MetaRendererNativeMode mode;
MetaSharedFramebufferCopyMode copy_mode; MetaSharedFramebufferCopyMode copy_mode;
#ifdef HAVE_EGL_DEVICE #ifdef HAVE_EGL_DEVICE
@ -150,6 +154,14 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState
struct gbm_bo *next_bo; struct gbm_bo *next_bo;
} gbm; } gbm;
#ifdef HAVE_EGL_DEVICE
struct {
uint8_t *copied_pixels;
MetaDumbBuffer dumb_fb;
EGLStreamKHR stream;
} egl;
#endif
struct { struct {
MetaDumbBuffer *dumb_fb; MetaDumbBuffer *dumb_fb;
MetaDumbBuffer dumb_fbs[2]; MetaDumbBuffer dumb_fbs[2];
@ -235,6 +247,19 @@ init_dumb_fb (MetaDumbBuffer *dumb_fb,
uint32_t format, uint32_t format,
GError **error); 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 * static MetaEgl *
meta_renderer_native_get_egl (MetaRendererNative *renderer_native); meta_renderer_native_get_egl (MetaRendererNative *renderer_native);
@ -640,6 +665,63 @@ init_secondary_gpu_state_gpu_copy_mode (MetaRendererNative *renderer_nat
return TRUE; 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 static void
secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) 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; MetaGpuKms *gpu_kms = secondary_gpu_state->gpu_kms;
unsigned int i; 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) if (secondary_gpu_state->egl_surface != EGL_NO_SURFACE)
{ {
MetaRendererNativeGpuData *renderer_gpu_data; MetaRendererNativeGpuData *renderer_gpu_data;
@ -720,6 +821,7 @@ init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_nat
static gboolean static gboolean
init_secondary_gpu_state (MetaRendererNative *renderer_native, init_secondary_gpu_state (MetaRendererNative *renderer_native,
CoglOnscreen *onscreen, CoglOnscreen *onscreen,
MetaMonitor *monitor,
MetaGpuKms *gpu_kms, MetaGpuKms *gpu_kms,
GError **error) GError **error)
{ {
@ -738,6 +840,17 @@ init_secondary_gpu_state (MetaRendererNative *renderer_native,
error)) error))
return FALSE; return FALSE;
break; 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: case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native, if (!init_secondary_gpu_state_cpu_copy_mode (renderer_native,
onscreen, onscreen,
@ -838,6 +951,10 @@ free_current_secondary_bo (MetaGpuKms *gpu_kms,
secondary_gpu_state->gbm.current_bo = NULL; secondary_gpu_state->gbm.current_bo = NULL;
} }
break; break;
#ifdef HAVE_EGL_DEVICE
case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
break;
#endif
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
break; break;
} }
@ -1272,6 +1389,10 @@ free_next_secondary_bo (MetaGpuKms *gpu_kms,
secondary_gpu_state->gbm.next_bo = NULL; secondary_gpu_state->gbm.next_bo = NULL;
} }
break; break;
#ifdef HAVE_EGL_DEVICE
case META_SHARED_FRAMEBUFFER_COPY_MODE_STREAM:
break;
#endif
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU: case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
break; break;
} }
@ -1395,6 +1516,29 @@ flip_primary_egl_stream (MetaOnscreenNative *onscreen_native,
return ret; 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 */ #endif /* HAVE_EGL_DEVICE */
static void static void
@ -1423,7 +1567,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
} }
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
render_gpu); gpu_kms);
if (gpu_kms == render_gpu) if (gpu_kms == render_gpu)
{ {
@ -1460,9 +1604,25 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
break; break;
#ifdef HAVE_EGL_DEVICE #ifdef HAVE_EGL_DEVICE
case META_RENDERER_NATIVE_MODE_EGL_DEVICE: case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
if (flip_primary_egl_stream (onscreen_native, if (gpu_kms == render_gpu)
flip_closure)) {
onscreen_native->total_pending_flips++; 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; *fb_in_use = TRUE;
break; break;
#endif #endif
@ -1496,12 +1656,25 @@ set_crtc_fb (MetaLogicalMonitor *logical_monitor,
else else
{ {
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state;
MetaRendererNativeGpuData *renderer_gpu_data;
secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms); secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms);
if (!secondary_gpu_state) if (!secondary_gpu_state)
return; 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; 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); &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 { typedef struct _PixelFormatMap {
uint32_t drm_format; uint32_t drm_format;
CoglPixelFormat cogl_format; CoglPixelFormat cogl_format;
@ -1968,6 +2195,48 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen,
secondary_gpu_state->gbm.next_fb_id = target_fb_id; 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 static void
update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen) 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: case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
/* Done after eglSwapBuffers. */ /* Done after eglSwapBuffers. */
break; 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: case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
copy_shared_framebuffer_cpu (onscreen, copy_shared_framebuffer_cpu (onscreen,
secondary_gpu_state, secondary_gpu_state,
@ -2026,6 +2302,14 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen,
renderer_gpu_data, renderer_gpu_data,
egl_context_changed); egl_context_changed);
break; 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: case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
/* Done before eglSwapBuffers. */ /* Done before eglSwapBuffers. */
break; break;
@ -2815,7 +3099,7 @@ meta_renderer_native_create_onscreen (MetaRendererNative *renderer_native,
if (get_secondary_gpu_state (onscreen, gpu_kms)) if (get_secondary_gpu_state (onscreen, gpu_kms))
continue; 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); cogl_object_unref (onscreen);
return NULL; 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_context = egl_context;
renderer_gpu_data->secondary.egl_config = egl_config; 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; renderer_gpu_data->secondary.copy_mode = META_SHARED_FRAMEBUFFER_COPY_MODE_GPU;
return TRUE; 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 static void
init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data) init_secondary_gpu_data_cpu (MetaRendererNativeGpuData *renderer_gpu_data)
{ {
@ -3283,8 +3611,20 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data)
{ {
GError *error = NULL; GError *error = NULL;
if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error)) switch (renderer_gpu_data->secondary.mode)
return; {
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", g_warning ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s",
error->message); error->message);