summarylogtreecommitdiffstats
path: root/0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch
diff options
context:
space:
mode:
Diffstat (limited to '0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch')
-rw-r--r--0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch820
1 files changed, 820 insertions, 0 deletions
diff --git a/0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch b/0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch
new file mode 100644
index 00000000000..f720cef9b67
--- /dev/null
+++ b/0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch
@@ -0,0 +1,820 @@
+From 89af96dc92477e94383ea02712b46fa2da03a438 Mon Sep 17 00:00:00 2001
+From: "Miguel A. Vico" <mvicomoya@nvidia.com>
+Date: Mon, 21 Mar 2016 17:37:34 +0100
+Subject: [PATCH 4/7] gl-renderer: Add support for EGLDevice+EGLOutput
+X-NVConfidentiality: public
+
+EGLDevice provides means to enumerate native devices, and then create
+an EGL display connection from them.
+
+Similarly, EGLOutput will provide means to access different
+portions of display control hardware associated with an EGLDevice.
+
+For instance, EGLOutputLayer represents a portion of display
+control hardware that accepts an image as input and processes it
+for presentation on a display device.
+
+EGLStream implements a mechanism to communicate frame producers and
+frame consumers. By attaching an EGLOutputLayer consumer to a stream,
+a producer will be able to present frames on a display device.
+
+Thus, a compositor could produce frames and feed them to an
+EGLOutputLayer through an EGLStream for presentation on a display
+device.
+
+In a similar way, by attaching a GLTexture consumer to a stream, a
+producer (wayland 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_EXT_stream_acquire_mode:
+ https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_EXT_stream_acquire_mode.txt
+
+ - EGL_NV_output_drm_flip_event:
+ https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_NV_output_drm_flip_event.txt
+
+Also, in order to allow wl_buffers to be bound to EGLStreams, we
+kludged eglQueryWaylandBufferWL(EGL_WAYLAND_BUFFER_WL) to return
+the stream file descriptor.
+
+We think the proper way to handle this should be:
+
+ - Update WL_bind_wayland_display such that eglQueryWaylandBufferWL() accepts
+ a new attribute EGL_WAYLAND_BUFFER_TYPE_WL, returning
+ EGL_WAYLAND_BUFFER_EGLIMAGE_WL for the non-stream case.
+
+ - Add a new WL_wayland_buffer_eglstream extension, which would define
+ EGL_WAYLAND_BUFFER_EGLSTREAM_WL as a return value for
+ EGL_WAYLAND_BUFFER_TYPE_WL, and yet another attribute
+ EGL_WAYLAND_BUFFER_EGLSTREAM_FD_WL to query the stream file descriptor.
+
+Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
+Reviewed-by: Andy Ritger <aritger@nvidia.com>
+Reviewed-by: Adam Cheney <acheney@nvidia.com>
+---
+ src/gl-renderer.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ src/gl-renderer.h | 26 +++
+ src/weston-egl-ext.h | 19 ++
+ 3 files changed, 517 insertions(+), 4 deletions(-)
+
+diff --git a/src/gl-renderer.c b/src/gl-renderer.c
+index 887d131674f5..07879cb83b60 100644
+--- a/src/gl-renderer.c
++++ b/src/gl-renderer.c
+@@ -30,6 +30,7 @@
+ #include <GLES2/gl2.h>
+ #include <GLES2/gl2ext.h>
+
++#include <unistd.h>
+ #include <stdbool.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -84,6 +85,8 @@ struct gl_output_state {
+ struct gl_border_image borders[4];
+ enum gl_border_status border_status;
+
++ EGLStreamKHR egl_stream;
++
+ struct weston_matrix output_matrix;
+ };
+
+@@ -159,6 +162,9 @@ struct gl_surface_state {
+ int height; /* in pixels */
+ int y_inverted;
+
++ EGLStreamKHR egl_stream;
++ bool stream_frame_acquired;
++
+ struct weston_surface *surface;
+
+ struct wl_listener surface_destroy_listener;
+@@ -202,6 +208,36 @@ struct gl_renderer {
+
+ int has_configless_context;
+
++ PFNEGLCREATESTREAMKHRPROC create_stream;
++ PFNEGLDESTROYSTREAMKHRPROC destroy_stream;
++ PFNEGLQUERYSTREAMKHRPROC query_stream;
++ int has_egl_stream;
++
++ PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC create_stream_producer_surface;
++ int has_egl_stream_producer_eglsurface;
++
++ PFNEGLSTREAMCONSUMEROUTPUTEXTPROC stream_consumer_output;
++ int has_egl_stream_consumer_egloutput;
++
++ PFNEGLSTREAMCONSUMERACQUIREKHRPROC stream_consumer_acquire;
++#ifdef EGL_EXT_stream_acquire_mode
++ PFNEGLSTREAMCONSUMERACQUIREATTRIBEXTPROC stream_consumer_acquire_attrib;
++#endif
++ int has_egl_stream_acquire_mode;
++
++ int has_egl_output_drm;
++ int has_egl_output_drm_flip_event;
++
++ PFNEGLGETOUTPUTLAYERSEXTPROC get_output_layers;
++ PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC query_output_layer_attrib;
++ int has_egl_output_base;
++
++ PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC create_stream_from_file_descriptor;
++ int has_egl_stream_cross_process_fd;
++
++ PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC stream_consumer_gltexture;
++ int has_egl_stream_consumer_gltexture;
++
+ int has_dmabuf_import;
+ struct wl_list dmabuf_images;
+
+@@ -735,6 +771,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
+ /* non-opaque region in surface coordinates: */
+ pixman_region32_t surface_blend;
+ GLint filter;
++ EGLint stream_state = EGL_STREAM_STATE_EMPTY_KHR;
+ int i;
+
+ /* In case of a runtime switch of renderers, we may not have received
+@@ -743,6 +780,21 @@ draw_view(struct weston_view *ev, struct weston_output *output,
+ if (!gs->shader)
+ return;
+
++ /* If using EGLStreams, only continue if we are certain we have something to
++ * render, i.e. a new frame is available or an old one was previously
++ * acquired and is ready to be re-used */
++ if (gs->egl_stream != EGL_NO_STREAM_KHR) {
++ if (gr->query_stream(gr->egl_display,
++ gs->egl_stream,
++ EGL_STREAM_STATE_KHR,
++ &stream_state) != EGL_TRUE)
++ return;
++
++ if (stream_state != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR &&
++ !gs->stream_frame_acquired)
++ return;
++ }
++
+ pixman_region32_init(&repaint);
+ pixman_region32_intersect(&repaint,
+ &ev->transform.boundingbox, damage);
+@@ -774,6 +826,16 @@ draw_view(struct weston_view *ev, struct weston_output *output,
+ glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
+ }
+
++ /* If using EGLStreams, we need to acquire the new frame, if any */
++ if (gs->egl_stream != EGL_NO_STREAM_KHR &&
++ stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
++ if (gr->stream_consumer_acquire(gr->egl_display,
++ gs->egl_stream) != EGL_TRUE)
++ goto out;
++
++ gs->stream_frame_acquired = true;
++ }
++
+ /* blended region is whole surface minus opaque region: */
+ pixman_region32_init_rect(&surface_blend, 0, 0,
+ ev->surface->width, ev->surface->height);
+@@ -1193,6 +1255,37 @@ gl_renderer_repaint_output(struct weston_output *output,
+ }
+
+ static int
++gl_renderer_output_stream_flip(struct weston_output *output,
++ void *flip_data)
++{
++#ifdef EGL_EXT_stream_acquire_mode
++ struct gl_output_state *go = get_output_state(output);
++ struct weston_compositor *compositor = output->compositor;
++ struct gl_renderer *gr = get_renderer(compositor);
++
++ EGLAttrib acquire_attribs[3] = { EGL_NONE };
++
++#ifdef EGL_NV_output_drm_flip_event
++ if (gr->has_egl_output_drm_flip_event) {
++ acquire_attribs[0] = EGL_DRM_FLIP_EVENT_DATA_NV;
++ acquire_attribs[1] = (EGLAttrib)flip_data;
++ acquire_attribs[2] = EGL_NONE;
++ }
++#endif
++
++ if (go->egl_stream != EGL_NO_STREAM_KHR)
++ if (EGL_TRUE != gr->stream_consumer_acquire_attrib(gr->egl_display,
++ go->egl_stream,
++ acquire_attribs))
++ return -1;
++
++ return 0;
++#else
++ return -1;
++#endif
++}
++
++static int
+ gl_renderer_read_pixels(struct weston_output *output,
+ pixman_format_code_t format, void *pixels,
+ uint32_t x, uint32_t y,
+@@ -1884,6 +1977,72 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
+ }
+
+ static void
++gl_renderer_attach_egl_fd_texture(struct weston_surface *es,
++ struct weston_buffer *buffer,
++ EGLNativeFileDescriptorKHR streamFd)
++{
++ struct weston_compositor *ec = es->compositor;
++ struct gl_renderer *gr = get_renderer(ec);
++ struct gl_surface_state *gs = get_surface_state(es);
++
++ /* If an invalid streamFd is provided, either there was an error creating
++ * the buffer or this buffer is already attached. Either case, there's
++ * nothing to be done */
++ if (streamFd < 0)
++ return;
++
++ /* 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 = EGL_NO_STREAM_KHR;
++ gs->stream_frame_acquired = false;
++ }
++
++ gs->egl_stream =
++ gr->create_stream_from_file_descriptor(gr->egl_display, streamFd);
++ close(streamFd);
++
++ if (gs->egl_stream == EGL_NO_STREAM_KHR) {
++ weston_log("failed to create egl stream\n");
++ goto err_attach_egl_fd_base;
++ }
++
++ gs->shader = &gr->texture_shader_egl_external;
++ gs->target = GL_TEXTURE_EXTERNAL_OES;
++
++ glActiveTexture(GL_TEXTURE0);
++ ensure_textures(gs, 1);
++ glBindTexture(gs->target, gs->textures[0]);
++
++ if (gr->stream_consumer_gltexture(gr->egl_display, gs->egl_stream) != EGL_TRUE) {
++ weston_log("failed to set stream consumer\n");
++ goto err_attach_egl_fd_stream;
++ }
++
++ 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);
++ buffer->y_inverted = 0;
++
++ gs->pitch = buffer->width;
++ gs->height = buffer->height;
++ gs->buffer_type = BUFFER_TYPE_EGL;
++ gs->y_inverted = buffer->y_inverted;
++
++ return;
++
++err_attach_egl_fd_stream:
++ gr->destroy_stream(gr->egl_display, gs->egl_stream);
++ gs->egl_stream = EGL_NO_STREAM_KHR;
++
++err_attach_egl_fd_base:
++ gl_renderer_print_egl_error_state();
++ return;
++}
++
++static void
+ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+ {
+ struct weston_compositor *ec = es->compositor;
+@@ -1891,6 +2050,7 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+ struct gl_surface_state *gs = get_surface_state(es);
+ struct wl_shm_buffer *shm_buffer;
+ struct linux_dmabuf_buffer *dmabuf;
++ EGLNativeFileDescriptorKHR streamFd;
+ EGLint format;
+ int i;
+
+@@ -1906,6 +2066,13 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+ gs->num_textures = 0;
+ gs->buffer_type = BUFFER_TYPE_NULL;
+ gs->y_inverted = 1;
++
++ if (gs->egl_stream != EGL_NO_STREAM_KHR) {
++ gr->destroy_stream(gr->egl_display, gs->egl_stream);
++ gs->egl_stream = EGL_NO_STREAM_KHR;
++ gs->stream_frame_acquired = false;
++ }
++
+ return;
+ }
+
+@@ -1918,7 +2085,11 @@ 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 (gr->query_buffer(gr->egl_display, (void *) buffer->resource,
++ EGL_WAYLAND_BUFFER_WL, &streamFd)) {
++ /* FIXME: WL_bind_wayland_display violation */
++ gl_renderer_attach_egl_fd_texture(es, buffer, streamFd);
++ } else {
+ weston_log("unhandled buffer type!\n");
+ weston_buffer_reference(&gs->buffer_ref, NULL);
+ gs->buffer_type = BUFFER_TYPE_NULL;
+@@ -2106,6 +2277,10 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
+
+ weston_buffer_reference(&gs->buffer_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);
+ }
+
+@@ -2156,6 +2331,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;
+
+@@ -2587,9 +2764,92 @@ gl_renderer_create_window_surface(struct gl_renderer *gr,
+ return egl_surface;
+ }
+
++static EGLSurface
++gl_renderer_create_stream_surface(struct gl_renderer *gr,
++ uint32_t plane_id,
++ uint32_t crtc_id,
++ EGLint width, EGLint height,
++ EGLStreamKHR *egl_stream)
++{
++ EGLint stream_attribs[] = {
++ EGL_STREAM_FIFO_LENGTH_KHR, 1,
++#ifdef EGL_EXT_stream_acquire_mode
++ EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
++#endif
++ EGL_NONE
++ };
++ EGLAttrib output_attribs[3];
++ EGLint stream_producer_attribs[] = {
++ EGL_WIDTH, width,
++ EGL_HEIGHT, height,
++ EGL_NONE
++ };
++
++ EGLint num_layers;
++ EGLOutputLayerEXT output_layer;
++ EGLSurface egl_surface = EGL_NO_SURFACE;
++
++ *egl_stream = gr->create_stream(gr->egl_display, stream_attribs);
++
++ if (*egl_stream == EGL_NO_STREAM_KHR) {
++ weston_log("Failed to create EGL stream.\n");
++ goto err_egl_create_surf_base;
++ }
++
++ if (plane_id != ~0u) {
++ output_attribs[0] = EGL_DRM_PLANE_EXT;
++ output_attribs[1] = plane_id;
++ } else {
++ assert(crtc_id != ~0u);
++ output_attribs[0] = EGL_DRM_CRTC_EXT;
++ output_attribs[1] = crtc_id;
++ }
++ output_attribs[2] = EGL_NONE;
++
++ if (gr->get_output_layers(gr->egl_display,
++ output_attribs,
++ &output_layer,
++ 1, &num_layers) != EGL_TRUE) {
++ weston_log("Failed to get output layer.\n");
++ goto err_egl_create_surf_stream;
++ }
++
++ if (num_layers < 1) {
++ weston_log("Unable to find output layers.\n");
++ goto err_egl_create_surf_stream;
++ }
++
++ if (gr->stream_consumer_output(gr->egl_display, *egl_stream,
++ output_layer) != EGL_TRUE) {
++ weston_log("Failed to set EGL stream consumer.\n");
++ goto err_egl_create_surf_stream;
++ }
++
++ egl_surface = gr->create_stream_producer_surface(gr->egl_display,
++ gr->egl_config,
++ *egl_stream,
++ stream_producer_attribs);
++
++ if (egl_surface == EGL_NO_SURFACE) {
++ weston_log("Failed to create EGL producer surface.\n");
++ goto err_egl_create_surf_stream;
++ }
++
++ return egl_surface;
++
++err_egl_create_surf_stream:
++ gr->destroy_stream(gr->egl_display, *egl_stream);
++ *egl_stream = EGL_NO_STREAM_KHR;
++
++err_egl_create_surf_base:
++ gl_renderer_print_egl_error_state();
++ return EGL_NO_SURFACE;
++}
++
+ static int
+ gl_renderer_output_create(struct weston_output *output,
+- EGLSurface surface)
++ EGLSurface surface,
++ EGLStreamKHR stream)
+ {
+ struct weston_compositor *ec = output->compositor;
+ struct gl_renderer *gr = get_renderer(ec);
+@@ -2611,6 +2871,7 @@ gl_renderer_output_create(struct weston_output *output,
+ return -1;
+
+ go->egl_surface = surface;
++ go->egl_stream = stream;
+
+ for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
+ pixman_region32_init(&go->buffer_damage[i]);
+@@ -2639,13 +2900,41 @@ gl_renderer_output_window_create(struct weston_output *output,
+ config_attribs,
+ visual_id, n_ids);
+
+- ret = gl_renderer_output_create(output, egl_surface);
++ ret = gl_renderer_output_create(output, egl_surface, EGL_NO_STREAM_KHR);
+ if (ret < 0 && egl_surface != EGL_NO_SURFACE)
+ eglDestroySurface(gr->egl_display, egl_surface);
+
+ return ret;
+ }
+
++static int
++gl_renderer_output_stream_create(struct weston_output *output,
++ uint32_t plane_id, uint32_t crtc_id)
++{
++ struct weston_compositor *ec = output->compositor;
++ struct gl_renderer *gr = get_renderer(ec);
++ EGLSurface egl_surface = EGL_NO_SURFACE;
++ EGLStreamKHR egl_stream = EGL_NO_STREAM_KHR;
++ int ret;
++
++ egl_surface =
++ gl_renderer_create_stream_surface(gr,
++ plane_id, crtc_id,
++ output->current_mode->width,
++ output->current_mode->height,
++ &egl_stream);
++
++ ret = gl_renderer_output_create(output, egl_surface, egl_stream);
++ if (ret < 0) {
++ if (egl_surface != EGL_NO_SURFACE)
++ eglDestroySurface(gr->egl_display, egl_surface);
++ if (egl_stream != EGL_NO_STREAM_KHR)
++ gr->destroy_stream(gr->egl_display, egl_stream);
++ }
++
++ return ret;
++}
++
+ static void
+ gl_renderer_output_destroy(struct weston_output *output)
+ {
+@@ -2658,6 +2947,9 @@ gl_renderer_output_destroy(struct weston_output *output)
+
+ eglDestroySurface(gr->egl_display, go->egl_surface);
+
++ if (go->egl_stream != EGL_NO_STREAM_KHR)
++ gr->destroy_stream(gr->egl_display, go->egl_stream);
++
+ free(go);
+ }
+
+@@ -2762,6 +3054,26 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
+ (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
+ gr->query_buffer =
+ (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
++ 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");
++ gr->get_output_layers = (void *) eglGetProcAddress("eglGetOutputLayersEXT");
++ gr->query_output_layer_attrib =
++ (void *) eglGetProcAddress("eglQueryOutputLayerAttribEXT");
++ gr->create_stream_from_file_descriptor =
++ (void *) eglGetProcAddress("eglCreateStreamFromFileDescriptorKHR");
++ gr->stream_consumer_gltexture =
++ (void *) eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR");
++ gr->stream_consumer_acquire =
++ (void *) eglGetProcAddress("eglStreamConsumerAcquireKHR");
++#ifdef EGL_EXT_stream_acquire_mode
++ gr->stream_consumer_acquire_attrib =
++ (void *) eglGetProcAddress("eglStreamConsumerAcquireAttribEXT");
++#endif
+
+ extensions =
+ (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
+@@ -2803,6 +3115,33 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
+ gr->has_dmabuf_import = 1;
+ #endif
+
++ if (check_extension(extensions, "EGL_KHR_stream"))
++ gr->has_egl_stream = 1;
++
++ if (check_extension(extensions, "EGL_KHR_stream_producer_eglsurface"))
++ gr->has_egl_stream_producer_eglsurface = 1;
++
++ if (check_extension(extensions, "EGL_EXT_stream_consumer_egloutput"))
++ gr->has_egl_stream_consumer_egloutput = 1;
++
++ if (check_extension(extensions, "EGL_KHR_stream_consumer_gltexture"))
++ gr->has_egl_stream_consumer_gltexture = 1;
++
++ if (check_extension(extensions, "EGL_EXT_stream_acquire_mode"))
++ gr->has_egl_stream_acquire_mode = 1;
++
++ if (check_extension(extensions, "EGL_EXT_output_base"))
++ gr->has_egl_output_base = 1;
++
++ if (check_extension(extensions, "EGL_EXT_output_drm"))
++ gr->has_egl_output_drm = 1;
++
++ if (check_extension(extensions, "EGL_NV_output_drm_flip_event"))
++ gr->has_egl_output_drm_flip_event = 1;
++
++ if (check_extension(extensions, "EGL_KHR_stream_cross_process_fd"))
++ gr->has_egl_stream_cross_process_fd = 1;
++
+ renderer_setup_egl_client_extensions(gr);
+
+ return 0;
+@@ -2828,6 +3167,16 @@ static const EGLint gl_renderer_alpha_attribs[] = {
+ EGL_NONE
+ };
+
++static const EGLint gl_renderer_opaque_stream_attribs[] = {
++ EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR,
++ EGL_RED_SIZE, 1,
++ EGL_GREEN_SIZE, 1,
++ EGL_BLUE_SIZE, 1,
++ EGL_ALPHA_SIZE, 0,
++ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
++ EGL_NONE
++};
++
+ /** Checks whether a platform EGL client extension is supported
+ *
+ * \param ec The weston compositor
+@@ -2900,6 +3249,8 @@ platform_to_extension(EGLenum platform)
+ return "wayland";
+ case EGL_PLATFORM_X11_KHR:
+ return "x11";
++ case EGL_PLATFORM_DEVICE_EXT:
++ return "device";
+ default:
+ assert(0 && "bad EGL platform enum");
+ }
+@@ -2985,6 +3336,38 @@ gl_renderer_create(struct weston_compositor *ec, EGLenum platform,
+ if (gl_renderer_setup_egl_extensions(ec) < 0)
+ goto fail_with_error;
+
++ if (platform == EGL_PLATFORM_DEVICE_EXT) {
++ if (!gr->has_egl_output_base ||
++ !gr->has_egl_output_drm ||
++ !gr->has_egl_stream ||
++ !gr->has_egl_stream_producer_eglsurface ||
++ !gr->has_egl_stream_consumer_egloutput ||
++ !gr->has_egl_stream_consumer_gltexture ||
++ !gr->has_egl_stream_acquire_mode ||
++ !gr->has_egl_stream_cross_process_fd) {
++ weston_log("following required extensions not supported:\n"
++ "%s%s%s%s%s%s%s%s",
++ (gr->has_egl_output_base ? " EGL_EXT_output_base\n" : ""),
++ (gr->has_egl_output_drm ? " EGL_EXT_output_drm\n" : ""),
++ (gr->has_egl_stream ? " EGL_KHR_stream\n" : ""),
++ (gr->has_egl_stream_producer_eglsurface ?
++ " EGL_KHR_stream_producer_eglsurface\n" : ""),
++ (gr->has_egl_stream_consumer_egloutput ?
++ " EGL_EXT_stream_consumer_egloutput\n" : ""),
++ (gr->has_egl_stream_consumer_gltexture ?
++ " EGL_KHR_stream_consumer_gltexture\n" : ""),
++ (gr->has_egl_stream_acquire_mode ?
++ " EGL_EXT_stream_acquire_mode\n" : ""),
++ (gr->has_egl_stream_cross_process_fd ?
++ " EGL_KHR_stream_cross_process_fd\n" : ""));
++ goto fail_terminate;
++ }
++
++ if (!gr->has_egl_output_drm_flip_event)
++ weston_log("warning: EGL page flip event notification not"
++ " supported\n");
++ }
++
+ wl_list_init(&gr->dmabuf_images);
+ if (gr->has_dmabuf_import)
+ gr->base.import_dmabuf = gl_renderer_import_dmabuf;
+@@ -3176,15 +3559,100 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
+ return 0;
+ }
+
++static int
++gl_renderer_get_devices(EGLint max_devices, EGLDeviceEXT *devices,
++ EGLint *num_devices)
++{
++ const char *extensions;
++ PFNEGLQUERYDEVICESEXTPROC query_devices;
++
++ extensions = (const char *)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
++ if (!extensions) {
++ weston_log("Retrieving EGL extension string failed.\n");
++ return -1;
++ }
++
++ if (!check_extension(extensions, "EGL_EXT_device_base")) {
++ weston_log("EGL_EXT_device_base not supported\n");
++ return -1;
++ }
++
++ query_devices = (void *) eglGetProcAddress("eglQueryDevicesEXT");
++ if (!query_devices) {
++ weston_log("Failed to get eglQueryDevicesEXT function\n");
++ return -1;
++ }
++
++ if (query_devices(max_devices, devices, num_devices) != EGL_TRUE) {
++ weston_log("Failed to query EGL Devices\n");
++ gl_renderer_print_egl_error_state();
++ return -1;
++ }
++
++ return 0;
++}
++
++static int
++gl_renderer_get_drm_device_file(EGLDeviceEXT device,
++ const char **drm_device_file)
++{
++ const char *extensions;
++ PFNEGLQUERYDEVICESTRINGEXTPROC query_device_string;
++
++ extensions = (const char *)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
++ if (!extensions) {
++ weston_log("Retrieving EGL extension string failed.\n");
++ return -1;
++ }
++
++ if (!check_extension(extensions, "EGL_EXT_device_base")) {
++ weston_log("EGL_EXT_device_base not supported.\n");
++ return -1;
++ }
++
++ query_device_string = (void *) eglGetProcAddress("eglQueryDeviceStringEXT");
++ if (!query_device_string) {
++ weston_log("Failed to get eglQueryDeviceStringEXT function\n");
++ return -1;
++ }
++
++ extensions = query_device_string(device, EGL_EXTENSIONS);
++ if (!extensions) {
++ weston_log("Retrieving EGL extension string failed.\n");
++ return -1;
++ }
++
++ if (!check_extension(extensions, "EGL_EXT_device_drm")) {
++ weston_log("EGL_EXT_device_drm not supported.\n");
++ return -1;
++ }
++
++ (*drm_device_file) = query_device_string(device, EGL_DRM_DEVICE_FILE_EXT);
++ if (*drm_device_file == NULL) {
++ weston_log("Failed to query DRM device name.\n");
++ gl_renderer_print_egl_error_state();
++ return -1;
++ }
++
++ return 0;
++}
++
+ WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
+ .opaque_attribs = gl_renderer_opaque_attribs,
+ .alpha_attribs = gl_renderer_alpha_attribs,
++ .opaque_stream_attribs = gl_renderer_opaque_stream_attribs,
+
+ .create = gl_renderer_create,
+ .display = gl_renderer_display,
+ .output_window_create = gl_renderer_output_window_create,
++ .output_stream_create = gl_renderer_output_stream_create,
+ .output_destroy = gl_renderer_output_destroy,
+ .output_surface = gl_renderer_output_surface,
+ .output_set_border = gl_renderer_output_set_border,
+- .print_egl_error_state = gl_renderer_print_egl_error_state
++ .print_egl_error_state = gl_renderer_print_egl_error_state,
++
++ .get_devices = gl_renderer_get_devices,
++ .get_drm_device_file = gl_renderer_get_drm_device_file,
++
++ .output_stream_flip = gl_renderer_output_stream_flip
+ };
+diff --git a/src/gl-renderer.h b/src/gl-renderer.h
+index af8dd267e700..d1dc009b2f5e 100644
+--- a/src/gl-renderer.h
++++ b/src/gl-renderer.h
+@@ -62,6 +62,10 @@ typedef EGLSurface (*PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy,
+ #define EGL_PLATFORM_X11_KHR 0x31D5
+ #endif
+
++#ifndef EGL_PLATFORM_DEVICE_EXT
++#define EGL_PLATFORM_DEVICE_EXT 0x313F
++#endif
++
+ #define NO_EGL_PLATFORM 0
+
+ enum gl_renderer_border_side {
+@@ -74,6 +78,7 @@ enum gl_renderer_border_side {
+ struct gl_renderer_interface {
+ const EGLint *opaque_attribs;
+ const EGLint *alpha_attribs;
++ const EGLint *opaque_stream_attribs;
+
+ int (*create)(struct weston_compositor *ec,
+ EGLenum platform,
+@@ -92,6 +97,9 @@ struct gl_renderer_interface {
+ const EGLint *visual_id,
+ const int n_ids);
+
++ int (*output_stream_create)(struct weston_output *output,
++ uint32_t plane_id, uint32_t crtc_id);
++
+ void (*output_destroy)(struct weston_output *output);
+
+ EGLSurface (*output_surface)(struct weston_output *output);
+@@ -129,5 +137,23 @@ struct gl_renderer_interface {
+ int32_t tex_width, unsigned char *data);
+
+ void (*print_egl_error_state)(void);
++
++ int (*get_devices)(EGLint max_devices,
++ EGLDeviceEXT *devices,
++ EGLint *num_devices);
++
++ int (*get_drm_device_file)(EGLDeviceEXT device,
++ const char **drm_device_file);
++
++ /*
++ * output_stream_flip() makes the EGLOutput consumer attached to the
++ * corresponding <output> stream acquire the new available frame
++ * (repaint_output() has been called previously) and queue a page flip.
++ * Whenever DRM is the underlying API and EGL_NV_output_drm_flip_event is
++ * supported, page flip notification can be requested by passing a non-NULL
++ * <flip_data> pointer. Otherwise, compositors should rely on a different
++ * mechanism in order to re-schedule output repaints.
++ */
++ int (*output_stream_flip)(struct weston_output *output, void *flip_data);
+ };
+
+diff --git a/src/weston-egl-ext.h b/src/weston-egl-ext.h
+index 32f6108fbb83..2faab1567c77 100644
+--- a/src/weston-egl-ext.h
++++ b/src/weston-egl-ext.h
+@@ -116,5 +116,24 @@ typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (
+ #define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+ #endif
+
++/*
++ * FIXME: Remove both EGL_EXT_stream_acquire_mode and
++ * EGL_NV_output_drm_flip_event definitions below once both extensions
++ * get published by Khronos and incorportated into Khronos' header files
++ */
++#ifndef EGL_EXT_stream_acquire_mode
++#define EGL_EXT_stream_acquire_mode 1
++#define EGL_CONSUMER_AUTO_ACQUIRE_EXT 0x332B
++typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
++#ifdef EGL_EGLEXT_PROTOTYPES
++EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribEXT (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
++#endif
++#endif /* EGL_EXT_stream_acquire_mode */
++
++#ifndef EGL_NV_output_drm_flip_event
++#define EGL_NV_output_drm_flip_event 1
++#define EGL_DRM_FLIP_EVENT_DATA_NV 0x333E
++#endif /* EGL_NV_output_drm_flip_event */
++
+
+ #endif
+--
+2.7.4
+