renderer-native: Add hybrid GPU system support

A hybrid GPU system is a system where more than one GPU is connected to
connectors. A common configuration is having a integrated GPU (iGPU)
connected to a laptop panel, and a dedicated GPU (dGPU) connected to
one or more external connector (such as HDMI).

This commit adds support for rendering the compositor stage using the
iGPU, then copying the framebuffer content onto a secondary framebuffer
that will be page flipped on the CRTC of the dGPU.

This can work in two different ways: GPU accelerated using Open GL ES
3, or CPU unaccelerated.

When supported, GPU accelerated copying works by exporting the iGPU
onscreen framebuffer as a DMA-BUF, importing it as a texture on a
separate dGPU EGL context, then using glBlitFramebuffer(), blitting it
onto a framebuffer on the dGPU that can then be page flipped on the dGPU
CRTC.

When GPU acceleration is not available, copying works by creating two
dumb buffers, and each frame glReadPixels() from the iGPU EGL render
context directly into the dumb buffer. The dumb buffer is then page
flipped on the dGPU CRTC.

https://bugzilla.gnome.org/show_bug.cgi?id=785381
This commit is contained in:
Jonas Ådahl 2017-07-25 10:21:04 +08:00
parent 492d2eb573
commit c9259c2b15
4 changed files with 1182 additions and 205 deletions

View File

@ -476,6 +476,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES += \
backends/native/meta-output-kms.h \
backends/native/meta-renderer-native.c \
backends/native/meta-renderer-native.h \
backends/native/meta-renderer-native-gles3.c \
backends/native/meta-renderer-native-gles3.h \
backends/native/meta-stage-native.c \
backends/native/meta-stage-native.h \
backends/native/dbus-utils.c \

View File

@ -0,0 +1,169 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2017 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include "config.h"
#define GL_GLEXT_PROTOTYPES
#include "backends/native/meta-renderer-native-gles3.h"
#include <errno.h>
#include <GLES3/gl3.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-gles3.h"
#include "backends/meta-gles3-table.h"
#include "backends/native/meta-renderer-native.h"
static EGLImageKHR
create_egl_image (MetaEgl *egl,
EGLDisplay egl_display,
EGLContext egl_context,
unsigned int width,
unsigned int height,
uint32_t stride,
uint32_t format,
int fd,
GError **error)
{
EGLint attributes[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_LINUX_DRM_FOURCC_EXT, format,
EGL_DMA_BUF_PLANE0_FD_EXT, fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, stride,
EGL_NONE
};
return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT, NULL,
attributes,
error);
}
static void
paint_egl_image (MetaGles3 *gles3,
EGLImageKHR egl_image,
int width,
int height)
{
GLuint texture;
GLuint framebuffer;
meta_gles3_clear_error (gles3);
GLBAS (gles3, glGenFramebuffers, (1, &framebuffer));
GLBAS (gles3, glBindFramebuffer, (GL_READ_FRAMEBUFFER, framebuffer));
GLBAS (gles3, glActiveTexture, (GL_TEXTURE0));
GLBAS (gles3, glGenTextures, (1, &texture));
GLBAS (gles3, glBindTexture, (GL_TEXTURE_2D, texture));
GLEXT (gles3, glEGLImageTargetTexture2DOES, (GL_TEXTURE_2D, egl_image));
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));
GLBAS (gles3, glFramebufferTexture2D, (GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture, 0));
GLBAS (gles3, glBindFramebuffer, (GL_READ_FRAMEBUFFER, framebuffer));
GLBAS (gles3, glBlitFramebuffer, (0, height, width, 0,
0, 0, width, height,
GL_COLOR_BUFFER_BIT,
GL_NEAREST));
}
gboolean
meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl,
MetaGles3 *gles3,
MetaGpuKms *gpu_kms,
EGLDisplay egl_display,
EGLContext egl_context,
EGLSurface egl_surface,
struct gbm_bo *shared_bo,
GError **error)
{
int shared_bo_fd;
unsigned int width;
unsigned int height;
uint32_t stride;
uint32_t format;
EGLImageKHR egl_image;
shared_bo_fd = gbm_bo_get_fd (shared_bo);
if (shared_bo_fd < 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to export gbm_bo: %s", strerror (errno));
return FALSE;
}
width = gbm_bo_get_width (shared_bo);
height = gbm_bo_get_height (shared_bo);
stride = gbm_bo_get_stride (shared_bo);
format = gbm_bo_get_format (shared_bo);
egl_image = create_egl_image (egl,
egl_display,
egl_context,
width, height, stride,
format,
shared_bo_fd,
error);
close (shared_bo_fd);
if (!egl_image)
return FALSE;
paint_egl_image (gles3, egl_image, width, height);
meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
return TRUE;
}
void
meta_renderer_native_gles3_read_pixels (MetaEgl *egl,
MetaGles3 *gles3,
int width,
int height,
uint8_t *target_data)
{
int y;
GLBAS (gles3, glFinish, ());
for (y = 0; y < height; y++)
{
GLBAS (gles3, glReadPixels, (0, height - y, width, 1,
GL_RGBA, GL_UNSIGNED_BYTE,
target_data + width * y * 4));
}
}

View File

@ -0,0 +1,47 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2017 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#ifndef META_RENDERER_NATIVE_GLES3_H
#define META_RENDERER_NATIVE_GLES3_H
#include <gbm.h>
#include "backends/meta-egl.h"
#include "backends/meta-gles3.h"
#include "backends/native/meta-gpu-kms.h"
gboolean meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl,
MetaGles3 *gles3,
MetaGpuKms *gpu_kms,
EGLDisplay egl_display,
EGLContext egl_context,
EGLSurface egl_surface,
struct gbm_bo *shared_bo,
GError **error);
void meta_renderer_native_gles3_read_pixels (MetaEgl *egl,
MetaGles3 *gles3,
int width,
int height,
uint8_t *target_data);
#endif /* META_RENDERER_NATIVE_GLES3_H */

File diff suppressed because it is too large Load Diff