diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index 8152991ee..344c80a03 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -29,6 +29,8 @@ #include "backends/meta-backend-private.h" #include "backends/native/meta-gpu-kms.h" +#include + #define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1) #define ALL_TRANSFORMS_MASK ((1 << ALL_TRANSFORMS) - 1) @@ -174,6 +176,18 @@ find_property_index (MetaGpu *gpu, return -1; } +GArray * +meta_crtc_kms_get_modifiers (MetaCrtc *crtc, + uint32_t format) +{ + MetaCrtcKms *crtc_kms = crtc->driver_private; + + if (format != DRM_FORMAT_XRGB8888) + return NULL; + + return crtc_kms->modifiers_xrgb8888; +} + static inline uint32_t * formats_ptr (struct drm_format_modifier_blob *blob) { diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index cb275f4cb..44899f6fc 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -37,6 +37,9 @@ void meta_crtc_kms_apply_transform (MetaCrtc *crtc); void meta_crtc_kms_set_underscan (MetaCrtc *crtc, gboolean is_underscanning); +GArray * meta_crtc_kms_get_modifiers (MetaCrtc *crtc, + uint32_t format); + MetaCrtc * meta_create_kms_crtc (MetaGpuKms *gpu_kms, drmModeCrtc *drm_crtc, unsigned int crtc_index); diff --git a/src/backends/native/meta-renderer-native-gles3.c b/src/backends/native/meta-renderer-native-gles3.c index 0914dfe1d..3bb09ce76 100644 --- a/src/backends/native/meta-renderer-native-gles3.c +++ b/src/backends/native/meta-renderer-native-gles3.c @@ -26,11 +26,13 @@ #include "backends/native/meta-renderer-native-gles3.h" +#include #include #include #include #include +#include "backends/meta-egl-ext.h" #include "backends/meta-gles3.h" #include "backends/meta-gles3-table.h" @@ -48,24 +50,91 @@ create_egl_image (MetaEgl *egl, EGLContext egl_context, unsigned int width, unsigned int height, - uint32_t stride, + uint32_t n_planes, + uint32_t *strides, + uint32_t *offsets, + uint64_t *modifiers, 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 - }; + EGLint attribs[37]; + int atti = 0; + gboolean has_modifier; + + /* This requires the Mesa commit in + * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or + * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652). + * Otherwise Mesa closes the fd behind our back and re-importing + * will fail. + * https://bugs.freedesktop.org/show_bug.cgi?id=76188 + */ + + attribs[atti++] = EGL_WIDTH; + attribs[atti++] = width; + attribs[atti++] = EGL_HEIGHT; + attribs[atti++] = height; + attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[atti++] = format; + + has_modifier = (modifiers[0] != DRM_FORMAT_MOD_INVALID); + + if (n_planes > 0) + { + attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; + attribs[atti++] = fd; + attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; + attribs[atti++] = offsets[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; + attribs[atti++] = strides[0]; + if (has_modifier) + { + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + attribs[atti++] = modifiers[0] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + attribs[atti++] = modifiers[0] >> 32; + } + } + + if (n_planes > 1) + { + attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT; + attribs[atti++] = fd; + attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; + attribs[atti++] = offsets[1]; + attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; + attribs[atti++] = strides[1]; + if (has_modifier) + { + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + attribs[atti++] = modifiers[1] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + attribs[atti++] = modifiers[1] >> 32; + } + } + + if (n_planes > 2) + { + attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT; + attribs[atti++] = fd; + attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; + attribs[atti++] = offsets[2]; + attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; + attribs[atti++] = strides[2]; + if (has_modifier) + { + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + attribs[atti++] = modifiers[2] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + attribs[atti++] = modifiers[2] >> 32; + } + } + + attribs[atti++] = EGL_NONE; return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, - attributes, + attribs, error); } @@ -120,7 +189,10 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, int shared_bo_fd; unsigned int width; unsigned int height; - uint32_t stride; + uint32_t i, n_planes; + uint32_t strides[4] = { 0, }; + uint32_t offsets[4] = { 0, }; + uint64_t modifiers[4] = { 0, }; uint32_t format; EGLImageKHR egl_image; @@ -134,14 +206,23 @@ meta_renderer_native_gles3_blit_shared_bo (MetaEgl *egl, 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); + n_planes = gbm_bo_get_plane_count (shared_bo); + for (i = 0; i < n_planes; i++) + { + strides[i] = gbm_bo_get_stride_for_plane (shared_bo, i); + offsets[i] = gbm_bo_get_offset (shared_bo, i); + modifiers[i] = gbm_bo_get_modifier (shared_bo); + } + egl_image = create_egl_image (egl, egl_display, egl_context, - width, height, stride, - format, + width, height, + n_planes, + strides, offsets, + modifiers, format, shared_bo_fd, error); close (shared_bo_fd); diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 2e59161cc..5b3a9a925 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -56,6 +56,7 @@ #include "backends/meta-logical-monitor.h" #include "backends/meta-output.h" #include "backends/meta-renderer-view.h" +#include "backends/native/meta-crtc-kms.h" #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-monitor-manager-kms.h" #include "backends/native/meta-renderer-native.h" @@ -1638,6 +1639,146 @@ meta_renderer_native_init_egl_context (CoglContext *cogl_context, return TRUE; } +static GArray * +get_supported_modifiers (CoglOnscreen *onscreen, + uint32_t format) +{ + CoglOnscreenEGL *onscreen_egl = onscreen->winsys; + MetaOnscreenNative *onscreen_native = onscreen_egl->platform; + MetaRendererNative *renderer_native = onscreen_native->renderer_native; + MetaLogicalMonitor *logical_monitor = onscreen_native->logical_monitor; + MetaEgl *egl = meta_onscreen_native_get_egl (onscreen_native); + CoglContext *cogl_context = COGL_FRAMEBUFFER (onscreen)->context; + CoglRenderer *cogl_renderer = cogl_context->display->renderer; + CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; + GArray *modifiers; + GArray *base_mods; + GList *l_crtc, *l_monitor; + MetaCrtc *base_crtc = NULL; + GList *other_crtcs = NULL; + unsigned int i; + + if (!logical_monitor) + return NULL; + + /* Find our base CRTC to intersect against. */ + for (l_monitor = meta_logical_monitor_get_monitors (logical_monitor); + l_monitor; + l_monitor = l_monitor->next) + { + MetaMonitor *monitor = l_monitor->data; + MetaGpu *gpu = meta_monitor_get_gpu (monitor); + MetaRendererNativeGpuData *renderer_gpu_data; + + /* All secondary GPUs need to be able to import DMA BUF with modifiers */ + renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, + META_GPU_KMS (gpu)); + if (cogl_renderer_egl->platform != renderer_gpu_data && + !meta_egl_has_extensions (egl, renderer_gpu_data->egl_display, NULL, + "EGL_EXT_image_dma_buf_import_modifiers", + NULL)) + goto out; + + for (l_crtc = meta_gpu_get_crtcs (gpu); l_crtc; l_crtc = l_crtc->next) + { + MetaCrtc *crtc = l_crtc->data; + + if (crtc->logical_monitor != logical_monitor) + continue; + + if (!base_crtc) + base_crtc = crtc; + else if (crtc == base_crtc) + continue; + else if (g_list_index (other_crtcs, crtc) == -1) + other_crtcs = g_list_append (other_crtcs, crtc); + } + } + + if (!base_crtc) + goto out; + + base_mods = meta_crtc_kms_get_modifiers (base_crtc, format); + if (!base_mods) + goto out; + + /* + * If this is the only CRTC we have, we don't need to intersect the sets of + * modifiers. + */ + if (other_crtcs == NULL) + { + modifiers = g_array_sized_new (FALSE, FALSE, sizeof (uint64_t), + base_mods->len); + g_array_append_vals (modifiers, base_mods->data, base_mods->len); + return modifiers; + } + + modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t)); + + /* + * For each modifier from base_crtc, check if it's available on all other + * CRTCs. + */ + for (i = 0; i < base_mods->len; i++) + { + uint64_t modifier = g_array_index (base_mods, uint64_t, i); + gboolean found_everywhere = TRUE; + GList *k; + + /* Check if we have the same modifier available for all CRTCs. */ + for (k = other_crtcs; k; k = k->next) + { + MetaCrtc *crtc = k->data; + GArray *crtc_mods; + unsigned int m; + gboolean found_here = FALSE; + + if (crtc->logical_monitor != logical_monitor) + continue; + + crtc_mods = meta_crtc_kms_get_modifiers (crtc, format); + if (!crtc_mods) + { + g_array_free (modifiers, TRUE); + goto out; + } + + for (m = 0; m < crtc_mods->len; m++) + { + uint64_t local_mod = g_array_index (crtc_mods, uint64_t, m); + + if (local_mod == modifier) + { + found_here = TRUE; + break; + } + } + + if (!found_here) + { + found_everywhere = FALSE; + break; + } + } + + if (found_everywhere) + g_array_append_val (modifiers, modifier); + } + + if (modifiers->len == 0) + { + g_array_free (modifiers, TRUE); + goto out; + } + + return modifiers; + +out: + g_list_free (other_crtcs); + return NULL; +} + static gboolean should_surface_be_sharable (CoglOnscreen *onscreen) { @@ -1690,19 +1831,36 @@ meta_renderer_native_create_surface_gbm (CoglOnscreen *onscreen, struct gbm_surface *new_gbm_surface; EGLNativeWindowType egl_native_window; EGLSurface new_egl_surface; - uint32_t flags; - - flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; - if (should_surface_be_sharable (onscreen)) - flags |= GBM_BO_USE_LINEAR; + uint32_t format = GBM_FORMAT_XRGB8888; + GArray *modifiers; renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, onscreen_native->render_gpu); - new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device, - width, height, - GBM_FORMAT_XRGB8888, - flags); + + modifiers = get_supported_modifiers (onscreen, format); + + if (modifiers) + { + new_gbm_surface = + gbm_surface_create_with_modifiers (renderer_gpu_data->gbm.device, + width, height, format, + (uint64_t *) modifiers->data, + modifiers->len); + g_array_free (modifiers, TRUE); + } + else + { + uint32_t flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; + + if (should_surface_be_sharable (onscreen)) + flags |= GBM_BO_USE_LINEAR; + + new_gbm_surface = gbm_surface_create (renderer_gpu_data->gbm.device, + width, height, + format, + flags); + } if (!new_gbm_surface) {