diff options
-rw-r--r-- | src/gl-renderer.c | 257 | ||||
-rw-r--r-- | src/gl-renderer.h | 19 | ||||
-rw-r--r-- | src/weston-egl-ext.h | 34 |
3 files changed, 307 insertions, 3 deletions
diff --git a/src/gl-renderer.c b/src/gl-renderer.c index 098440ce..9380371a 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -84,6 +84,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; }; @@ -202,6 +204,28 @@ struct gl_renderer { int has_configless_context; + PFNEGLGETOUTPUTLAYERSEXTPROC get_output_layers; + PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC query_output_layer_attrib; + int has_egl_output_base; + int has_egl_output_drm; + int has_egl_output_drm_flip_event; + + PFNEGLCREATESTREAMKHRPROC create_stream; + PFNEGLDESTROYSTREAMKHRPROC destroy_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; + +#ifdef EGL_NV_stream_attrib + PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC stream_consumer_acquire_attrib; +#endif + int has_egl_stream_attrib; + int has_egl_stream_acquire_mode; + int has_dmabuf_import; struct wl_list dmabuf_images; @@ -1193,6 +1217,37 @@ gl_renderer_repaint_output(struct weston_output *output, } static int +gl_renderer_output_stream_flip(struct weston_output *output, + void *flip_data) +{ +#if defined(EGL_NV_stream_attrib) && defined(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, @@ -2587,9 +2642,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); @@ -2606,6 +2744,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]); @@ -2638,13 +2777,41 @@ gl_renderer_output_window_create(struct weston_output *output, return -1; } - ret = gl_renderer_output_create(output, egl_surface); + ret = gl_renderer_output_create(output, egl_surface, EGL_NO_STREAM_KHR); if (ret < 0) 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); + if (egl_surface == EGL_NO_SURFACE) + return -1; + + ret = gl_renderer_output_create(output, egl_surface, egl_stream); + if (ret < 0) { + eglDestroySurface(gr->egl_display, egl_surface); + gr->destroy_stream(gr->egl_display, egl_stream); + } + + return ret; +} + static void gl_renderer_output_destroy(struct weston_output *output) { @@ -2657,6 +2824,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); } @@ -2761,6 +2931,19 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec) (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL"); gr->query_buffer = (void *) eglGetProcAddress("eglQueryWaylandBufferWL"); + gr->get_output_layers = (void *) eglGetProcAddress("eglGetOutputLayersEXT"); + gr->query_output_layer_attrib = + (void *) eglGetProcAddress("eglQueryOutputLayerAttribEXT"); + gr->create_stream = (void *) eglGetProcAddress("eglCreateStreamKHR"); + gr->destroy_stream = (void *) eglGetProcAddress("eglDestroyStreamKHR"); + gr->create_stream_producer_surface = + (void *) eglGetProcAddress("eglCreateStreamProducerSurfaceKHR"); + gr->stream_consumer_output = + (void *) eglGetProcAddress("eglStreamConsumerOutputEXT"); +#ifdef EGL_NV_stream_attrib + gr->stream_consumer_acquire_attrib = + (void *) eglGetProcAddress("eglStreamConsumerAcquireAttribNV"); +#endif extensions = (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS); @@ -2802,6 +2985,30 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec) gr->has_dmabuf_import = 1; #endif + 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")) + 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_NV_stream_attrib")) + gr->has_egl_stream_attrib = 1; + + if (check_extension(extensions, "EGL_EXT_stream_acquire_mode")) + gr->has_egl_stream_acquire_mode = 1; + renderer_setup_egl_client_extensions(gr); return 0; @@ -2827,6 +3034,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 @@ -2899,6 +3116,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"); } @@ -2984,6 +3203,34 @@ gl_renderer_display_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_attrib || + !gr->has_egl_stream_acquire_mode) { + weston_log("following required extensions not supported:\n" + "%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_attrib ? "" : " EGL_NV_stream_attrib\n"), + (gr->has_egl_stream_acquire_mode ? + "" : " EGL_EXT_stream_acquire_mode\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; @@ -3260,15 +3507,19 @@ gl_renderer_get_drm_device_file(EGLDeviceEXT device, 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, .display_create = gl_renderer_display_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, .get_devices = gl_renderer_get_devices, - .get_drm_device_file = gl_renderer_get_drm_device_file + .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 f376edd8..958caa19 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 (*display_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); @@ -136,5 +144,16 @@ struct gl_renderer_interface { 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 32f6108f..ab010303 100644 --- a/src/weston-egl-ext.h +++ b/src/weston-egl-ext.h @@ -116,5 +116,39 @@ 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_NV_stream_attrib +#define EGL_NV_stream_attrib 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribNV(EGLDisplay dpy, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamAttribNV(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamAttribNV(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribNV(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseAttribNV(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +#endif +typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBNVPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list); +#endif /* EGL_NV_stream_attrib */ + +#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 |