summarylogtreecommitdiffstats
path: root/0004-gl-renderer-Add-EGL-client-support-for-EGLStream-fra.patch
diff options
context:
space:
mode:
Diffstat (limited to '0004-gl-renderer-Add-EGL-client-support-for-EGLStream-fra.patch')
-rw-r--r--0004-gl-renderer-Add-EGL-client-support-for-EGLStream-fra.patch326
1 files changed, 326 insertions, 0 deletions
diff --git a/0004-gl-renderer-Add-EGL-client-support-for-EGLStream-fra.patch b/0004-gl-renderer-Add-EGL-client-support-for-EGLStream-fra.patch
new file mode 100644
index 000000000000..2f2a7a9c5377
--- /dev/null
+++ b/0004-gl-renderer-Add-EGL-client-support-for-EGLStream-fra.patch
@@ -0,0 +1,326 @@
+From 1c422fb24eadccabd3ed07de15923acc982aa6a1 Mon Sep 17 00:00:00 2001
+From: "Miguel A. Vico" <mvicomoya@nvidia.com>
+Date: Thu, 29 Mar 2018 00:15:49 -0700
+Subject: [PATCH 4/8] gl-renderer: Add EGL client support for EGLStream frame
+ presentation
+X-NVConfidentiality: public
+
+By attaching a GLTexture consumer to a stream, a producer (wayland EGL
+client) could feed frames to a texture, which in turn can be used by a
+compositor to prepare the final frame to be presented.
+
+This change adds required logic to support presentation approach
+described above.
+
+Note that some unpublished EGL extensions were needed:
+
+ - EGL_NV_stream_attrib:
+ https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_NV_stream_attrib.txt
+
+ - EGL_WL_wayland_eglstream:
+ https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_WL_wayland_eglstream.txt
+
+Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
+Reviewed-by: Adam Cheney <acheney@nvidia.com>
+Reviewed-by: James Jones <jajones@nvidia.com>
+---
+ libweston/gl-renderer.c | 183 +++++++++++++++++++++++++++++++++++++++-
+ shared/weston-egl-ext.h | 5 ++
+ 2 files changed, 187 insertions(+), 1 deletion(-)
+
+diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
+index f3fb2c65..5e594535 100644
+--- a/libweston/gl-renderer.c
++++ b/libweston/gl-renderer.c
+@@ -189,6 +189,9 @@ struct gl_surface_state {
+ int hsub[3]; /* horizontal subsampling per plane */
+ int vsub[3]; /* vertical subsampling per plane */
+
++ EGLStreamKHR egl_stream;
++ bool new_stream;
++
+ struct weston_surface *surface;
+
+ /* Whether this surface was used in the current output repaint.
+@@ -248,6 +251,7 @@ struct gl_renderer {
+
+ PFNEGLCREATESTREAMKHRPROC create_stream;
+ PFNEGLDESTROYSTREAMKHRPROC destroy_stream;
++ PFNEGLQUERYSTREAMKHRPROC query_stream;
+ int has_egl_stream;
+
+ PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC create_stream_producer_surface;
+@@ -257,11 +261,16 @@ struct gl_renderer {
+ int has_egl_stream_consumer_egloutput;
+
+ #ifdef EGL_NV_stream_attrib
++ PFNEGLCREATESTREAMATTRIBNVPROC create_stream_attrib;
+ PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC stream_consumer_acquire_attrib;
+ #endif
+ int has_egl_stream_attrib;
+ int has_egl_stream_acquire_mode;
+
++ PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC stream_consumer_gltexture;
++ int has_egl_stream_consumer_gltexture;
++ int has_egl_wayland_eglstream;
++
+ int has_dmabuf_import;
+ struct wl_list dmabuf_images;
+
+@@ -2528,6 +2537,145 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
+ surface->is_opaque = dmabuf_is_opaque(dmabuf);
+ }
+
++/*
++ * gl_renderer_attach_stream_texture
++ *
++ * Try to bind given <buffer> to an EGLStream. If the given buffer was already
++ * bound, it will acquire next frame on the stream.
++ *
++ * Return true if the given <buffer> corresponds to an EGLStream; otherwise,
++ * return false (if might be another kind of buffer).
++ */
++static bool
++gl_renderer_attach_stream_texture(struct weston_surface *es,
++ struct weston_buffer *buffer)
++{
++#ifdef EGL_NV_stream_attrib
++ struct weston_compositor *ec = es->compositor;
++ struct gl_renderer *gr = get_renderer(ec);
++ struct gl_surface_state *gs = get_surface_state(es);
++ EGLStreamKHR stream = EGL_NO_STREAM_KHR;
++ EGLAttrib stream_attribs[] = {
++#ifdef EGL_WL_wayland_eglstream
++ EGL_WAYLAND_EGLSTREAM_WL, (EGLAttrib)buffer->resource,
++#endif
++ EGL_NONE
++ };
++ EGLint stream_state = EGL_STREAM_STATE_EMPTY_KHR;
++
++ /* Check for required extensions. If they arent supported, there's no
++ * way the given buffer corresponds to an EGLStream */
++ if (!gr->has_egl_stream_attrib ||
++ !gr->has_egl_stream_consumer_gltexture ||
++ !gr->has_egl_wayland_eglstream)
++ return false;
++
++ stream = gr->create_stream_attrib(gr->egl_display, stream_attribs);
++ if (stream == EGL_NO_STREAM_KHR) {
++ EGLint err = eglGetError();
++
++ switch (err) {
++ case EGL_BAD_ACCESS:
++ /* EGL_BAD_ACCESS is generated whenever buffer->resource
++ * does not corresponds to a stream */
++ return false;
++
++ case EGL_BAD_STREAM_KHR:
++ /* EGL_BAD_STREAM_KHR is generated whenever
++ * buffer->resource corresponds to a previously created
++ * stream so we must have a valid stream handle already
++ * we can use to acquire next frame */
++ break;
++
++ default:
++ /* An unknown error was generated */
++ assert(0);
++ return false;
++ }
++ } else {
++ /* Clean up current stream resources if needed */
++ if (gs->egl_stream != EGL_NO_STREAM_KHR)
++ gr->destroy_stream(gr->egl_display, gs->egl_stream);
++
++ gs->egl_stream = stream;
++ gs->shader = &gr->texture_shader_egl_external;
++ gs->target = GL_TEXTURE_EXTERNAL_OES;
++
++ glActiveTexture(GL_TEXTURE0);
++ ensure_textures(gs, 2);
++ glBindTexture(gs->target, gs->textures[1]);
++
++ gs->new_stream = (gr->stream_consumer_gltexture(
++ gr->egl_display,
++ gs->egl_stream) == EGL_TRUE);
++
++ if (!gs->new_stream) {
++ weston_log("failed to set stream consumer\n");
++ gl_renderer_print_egl_error_state();
++ gr->destroy_stream(gr->egl_display, gs->egl_stream);
++ gs->egl_stream = EGL_NO_STREAM_KHR;
++ return true; /* buffer->resource is EGLStream */
++ }
++ }
++
++ /* At this point we should have a valid stream handle */
++ assert(gs->egl_stream != EGL_NO_STREAM_KHR);
++
++ /* Check whether there are new frames available */
++ if (gr->query_stream(gr->egl_display,
++ gs->egl_stream,
++ EGL_STREAM_STATE_KHR,
++ &stream_state) != EGL_TRUE) {
++ weston_log("failed to query stream state\n");
++ gl_renderer_print_egl_error_state();
++ return true; /* buffer->resource is EGLStream */
++ }
++
++ /* If no new frame available, re-use last one */
++ if (stream_state != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
++ /* Fake size of last frame */
++ buffer->width = gs->pitch;
++ buffer->height = gs->height;
++ return true; /* buffer->resource is EGLStream */
++ }
++
++ if (gr->stream_consumer_acquire_attrib(gr->egl_display,
++ gs->egl_stream,
++ NULL) != EGL_TRUE) {
++ weston_log("failed to acquire buffer\n");
++ gl_renderer_print_egl_error_state();
++ return true; /* buffer->resource is EGLStream */
++ }
++
++ /* Swap textures if new stream was created */
++ if (gs->new_stream) {
++ GLuint tmp = gs->textures[0];
++
++ gs->textures[0] = gs->textures[1];
++ gs->textures[1] = tmp;
++ gs->new_stream = false;
++ }
++
++ /* Update buffer and surface data */
++ buffer->legacy_buffer = (void *)buffer->resource;
++ gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
++ EGL_WIDTH, &buffer->width);
++ gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
++ EGL_HEIGHT, &buffer->height);
++ gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
++ EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
++
++ gs->pitch = buffer->width;
++ gs->height = buffer->height;
++ gs->buffer_type = BUFFER_TYPE_EGL;
++ gs->y_inverted = buffer->y_inverted;
++
++ return true; /* buffer->resource is EGLStream */
++#else
++ return false;
++#endif
++}
++
+ static void
+ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+ {
+@@ -2554,6 +2702,12 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+ gs->buffer_type = BUFFER_TYPE_NULL;
+ gs->y_inverted = 1;
+ es->is_opaque = false;
++
++ if (gs->egl_stream != EGL_NO_STREAM_KHR) {
++ gr->destroy_stream(gr->egl_display, gs->egl_stream);
++ gs->egl_stream = EGL_NO_STREAM_KHR;
++ }
++
+ return;
+ }
+
+@@ -2567,7 +2721,7 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+ gl_renderer_attach_egl(es, buffer, format);
+ else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
+ gl_renderer_attach_dmabuf(es, buffer, dmabuf);
+- else {
++ else if (!gl_renderer_attach_stream_texture(es, buffer)) {
+ weston_log("unhandled buffer type!\n");
+ if (gr->has_bind_display) {
+ weston_log("eglQueryWaylandBufferWL failed\n");
+@@ -2764,6 +2918,10 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
+ weston_buffer_reference(&gs->buffer_ref, NULL);
+ weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
+ pixman_region32_fini(&gs->texture_damage);
++
++ if (gs->egl_stream != EGL_NO_STREAM_KHR)
++ gr->destroy_stream(gr->egl_display, gs->egl_stream);
++
+ free(gs);
+ }
+
+@@ -2814,6 +2972,8 @@ gl_renderer_create_surface(struct weston_surface *surface)
+
+ gs->surface = surface;
+
++ gs->egl_stream = EGL_NO_STREAM_KHR;
++
+ pixman_region32_init(&gs->texture_damage);
+ surface->renderer_state = gs;
+
+@@ -3570,14 +3730,19 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
+ (void *) eglGetProcAddress("eglQueryOutputLayerAttribEXT");
+ gr->create_stream = (void *) eglGetProcAddress("eglCreateStreamKHR");
+ gr->destroy_stream = (void *) eglGetProcAddress("eglDestroyStreamKHR");
++ gr->query_stream = (void *) eglGetProcAddress("eglQueryStreamKHR");
+ gr->create_stream_producer_surface =
+ (void *) eglGetProcAddress("eglCreateStreamProducerSurfaceKHR");
+ gr->stream_consumer_output =
+ (void *) eglGetProcAddress("eglStreamConsumerOutputEXT");
+ #ifdef EGL_NV_stream_attrib
++ gr->create_stream_attrib =
++ (void *) eglGetProcAddress("eglCreateStreamAttribNV");
+ gr->stream_consumer_acquire_attrib =
+ (void *) eglGetProcAddress("eglStreamConsumerAcquireAttribNV");
+ #endif
++ gr->stream_consumer_gltexture =
++ (void *) eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR");
+
+ extensions =
+ (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
+@@ -3676,6 +3841,12 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
+ if (weston_check_egl_extension(extensions, "EGL_EXT_stream_acquire_mode"))
+ gr->has_egl_stream_acquire_mode = 1;
+
++ if (weston_check_egl_extension(extensions, "EGL_KHR_stream_consumer_gltexture"))
++ gr->has_egl_stream_consumer_gltexture = 1;
++
++ if (weston_check_egl_extension(extensions, "EGL_WL_wayland_eglstream"))
++ gr->has_egl_wayland_eglstream = 1;
++
+ renderer_setup_egl_client_extensions(gr);
+
+ return 0;
+@@ -3953,6 +4124,16 @@ gl_renderer_display_create(struct weston_compositor *ec, EGLenum platform,
+ goto fail_terminate;
+ }
+
++ if (!gr->has_egl_stream_consumer_gltexture ||
++ !gr->has_egl_wayland_eglstream)
++ weston_log("warning: following required extensions for "
++ "EGL client frame presentation through "
++ "EGLDevice not supported:\n%s%s",
++ (gr->has_egl_stream_consumer_gltexture ? "" :
++ " EGL_KHR_stream_consumer_gltexture\n"),
++ (gr->has_egl_wayland_eglstream ? "" :
++ " EGL_WL_wayland_eglstream\n"));
++
+ if (!gr->has_egl_output_drm_flip_event)
+ weston_log("warning: EGL page flip event notification "
+ "not supported\n");
+diff --git a/shared/weston-egl-ext.h b/shared/weston-egl-ext.h
+index f39990ed..96982e2d 100644
+--- a/shared/weston-egl-ext.h
++++ b/shared/weston-egl-ext.h
+@@ -243,6 +243,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribEXT (EGLDisplay dpy,
+ #define EGL_DRM_FLIP_EVENT_DATA_NV 0x333E
+ #endif /* EGL_NV_output_drm_flip_event */
+
++#ifndef EGL_WL_wayland_eglstream
++#define EGL_WL_wayland_eglstream 1
++#define EGL_WAYLAND_EGLSTREAM_WL 0x334B
++#endif /* EGL_WL_wayland_eglstream */
++
+ #else /* ENABLE_EGL */
+
+ /* EGL platform definition are keept to allow compositor-xx.c to build */
+--
+2.21.0
+