gboolean meta_wayland_egl_stream_attach (MetaWaylandEglStream *stream, GError **error) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); EGLint stream_state; if (!meta_egl_query_stream (egl, egl_display, stream->egl_stream, EGL_STREAM_STATE_KHR, &stream_state, error)) return FALSE; if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { if (!meta_egl_stream_consumer_acquire (egl, egl_display, stream->egl_stream, error)) return FALSE; } return TRUE; }
gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer) { EGLint format; MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); #ifdef HAVE_WAYLAND_EGLSTREAM MetaWaylandEglStream *stream; #endif MetaWaylandDmaBufBuffer *dma_buf; if (wl_shm_buffer_get (buffer->resource) != NULL) { buffer->type = META_WAYLAND_BUFFER_TYPE_SHM; return TRUE; } #ifdef HAVE_WAYLAND_EGLSTREAM stream = meta_wayland_egl_stream_new (buffer, NULL); if (stream) { CoglTexture2D *texture; texture = meta_wayland_egl_stream_create_texture (stream, NULL); if (!texture) return FALSE; buffer->egl_stream.stream = stream; buffer->type = META_WAYLAND_BUFFER_TYPE_EGL_STREAM; buffer->egl_stream.texture = COGL_TEXTURE (texture); buffer->is_y_inverted = meta_wayland_egl_stream_is_y_inverted (stream); return TRUE; } #endif /* HAVE_WAYLAND_EGLSTREAM */ if (meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_TEXTURE_FORMAT, &format, NULL)) { buffer->type = META_WAYLAND_BUFFER_TYPE_EGL_IMAGE; return TRUE; } dma_buf = meta_wayland_dma_buf_from_buffer (buffer); if (dma_buf) { buffer->dma_buf.dma_buf = dma_buf; buffer->type = META_WAYLAND_BUFFER_TYPE_DMA_BUF; return TRUE; } return FALSE; }
CoglTexture2D * meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream, GError **error) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); CoglTexture2D *texture; int width, height; int y_inverted; if (!meta_egl_query_wayland_buffer (egl, egl_display, stream->buffer->resource, EGL_WIDTH, &width, error)) return NULL; if (!meta_egl_query_wayland_buffer (egl, egl_display, stream->buffer->resource, EGL_HEIGHT, &height, error)) return NULL; if (!meta_egl_query_wayland_buffer (egl, egl_display, stream->buffer->resource, EGL_WAYLAND_Y_INVERTED_WL, &y_inverted, NULL)) y_inverted = EGL_TRUE; texture = cogl_texture_2d_new_from_egl_image_external (cogl_context, width, height, alloc_egl_stream_texture, g_object_ref (stream), stream_texture_destroyed, error); if (!texture) { g_object_unref (stream); return NULL; } if (!cogl_texture_allocate (COGL_TEXTURE (texture), error)) { cogl_object_unref (texture); return NULL; } stream->texture = texture; stream->is_y_inverted = !!y_inverted; return texture; }
static void meta_wayland_egl_stream_finalize (GObject *object) { MetaWaylandEglStream *stream = META_WAYLAND_EGL_STREAM (object); MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); g_assert (!stream->texture); meta_egl_destroy_stream (egl, egl_display, stream->egl_stream, NULL); G_OBJECT_CLASS (meta_wayland_egl_stream_parent_class)->finalize (object); }
static gboolean alloc_egl_stream_texture (CoglTexture2D *texture, gpointer user_data, GError **error) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); MetaWaylandEglStream *stream = user_data; return meta_egl_stream_consumer_gl_texture_external (egl, egl_display, stream->egl_stream, error); }
MetaWaylandEglStream * meta_wayland_egl_stream_new (MetaWaylandBuffer *buffer, GError **error) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); g_autoptr (MetaWaylandEglStream) stream = NULL; int stream_fd; EGLStreamKHR egl_stream; stream = g_object_new (META_TYPE_WAYLAND_EGL_STREAM, NULL); /* * HACK: Use a (as far as I can tell) undocumented hack by passing * EGL_WAYLAND_BUFFER_WL to eglQueryWaylandBufferWL. If it happens to be a * dummy EGLStream buffer, we'll get a EGLStream file descriptor. * * FIXME: At some point, replace this with the EGL_WL_wayland_eglstream * extension. */ if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_WAYLAND_BUFFER_WL, &stream_fd, error)) return NULL; if (stream_fd == EGL_NO_FILE_DESCRIPTOR_KHR) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Stream already used with other wl_buffer"); return NULL; } egl_stream = meta_egl_create_stream_from_file_descriptor (egl, egl_display, stream_fd, error); close (stream_fd); if (egl_stream == EGL_NO_STREAM_KHR) return NULL; stream->egl_stream = egl_stream; stream->buffer = buffer; return g_steal_pointer (&stream); }
gboolean meta_wayland_is_egl_stream_buffer (MetaWaylandBuffer *buffer) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); int stream_fd; if (!meta_egl_has_extensions (egl, egl_display, NULL, "EGL_KHR_stream_consumer_gltexture", "EGL_KHR_stream_cross_process_fd", NULL)) return FALSE; if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_WAYLAND_BUFFER_WL, &stream_fd, NULL)) return FALSE; return TRUE; }
static gboolean egl_image_buffer_attach (MetaWaylandBuffer *buffer, CoglTexture **texture, gboolean *changed_texture, GError **error) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend); EGLDisplay egl_display = cogl_egl_context_get_egl_display (cogl_context); int format, width, height, y_inverted; CoglPixelFormat cogl_format; EGLImageKHR egl_image; CoglTexture2D *texture_2d; if (buffer->egl_image.texture) { *changed_texture = *texture != buffer->egl_image.texture; cogl_clear_object (texture); *texture = cogl_object_ref (buffer->egl_image.texture); return TRUE; } if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_TEXTURE_FORMAT, &format, error)) return FALSE; if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_WIDTH, &width, error)) return FALSE; if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_HEIGHT, &height, error)) return FALSE; if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_WAYLAND_Y_INVERTED_WL, &y_inverted, NULL)) y_inverted = EGL_TRUE; switch (format) { case EGL_TEXTURE_RGB: cogl_format = COGL_PIXEL_FORMAT_RGB_888; break; case EGL_TEXTURE_RGBA: cogl_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE; break; default: g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unsupported buffer format %d", format); return FALSE; } /* The WL_bind_wayland_display spec states that EGL_NO_CONTEXT is to be used * in conjunction with the EGL_WAYLAND_BUFFER_WL target. */ egl_image = meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL, buffer->resource, NULL, error); if (egl_image == EGL_NO_IMAGE_KHR) return FALSE; texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context, width, height, cogl_format, egl_image, error); meta_egl_destroy_image (egl, egl_display, egl_image, NULL); if (!texture_2d) return FALSE; buffer->egl_image.texture = COGL_TEXTURE (texture_2d); buffer->is_y_inverted = !!y_inverted; cogl_clear_object (texture); *texture = cogl_object_ref (buffer->egl_image.texture); *changed_texture = TRUE; return TRUE; }