diff options
Diffstat (limited to '0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch')
-rw-r--r-- | 0004-gl-renderer-Add-support-for-EGLDevice-EGLOutput.patch | 820 |
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 000000000000..f720cef9b67c --- /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 + |