diff options
author | Miguel A. Vico | 2019-03-26 17:54:58 -0700 |
---|---|---|
committer | Miguel A. Vico | 2019-03-27 22:04:18 -0700 |
commit | 6270174bd71c83185112d299fbc842293b7ffb2c (patch) | |
tree | ca801657abff728d5f55c31b55db438fb686053b /0002-gl-renderer-Add-support-for-EGLDevice-composited-fra.patch | |
parent | 1ec939fa1774fe9bfa98f601f90a1b0669b267ba (diff) | |
download | aur-6270174bd71c83185112d299fbc842293b7ffb2c.tar.gz |
Update to weston 6.0.0
Diffstat (limited to '0002-gl-renderer-Add-support-for-EGLDevice-composited-fra.patch')
-rw-r--r-- | 0002-gl-renderer-Add-support-for-EGLDevice-composited-fra.patch | 522 |
1 files changed, 0 insertions, 522 deletions
diff --git a/0002-gl-renderer-Add-support-for-EGLDevice-composited-fra.patch b/0002-gl-renderer-Add-support-for-EGLDevice-composited-fra.patch deleted file mode 100644 index fd5b7e19261d..000000000000 --- a/0002-gl-renderer-Add-support-for-EGLDevice-composited-fra.patch +++ /dev/null @@ -1,522 +0,0 @@ -From db0add622cd4f8594222e493e164bfb3224230e5 Mon Sep 17 00:00:00 2001 -From: "Miguel A. Vico" <mvicomoya@nvidia.com> -Date: Mon, 2 May 2016 16:34:01 +0200 -Subject: [PATCH 2/9] gl-renderer: Add support for EGLDevice composited frame - presentation -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. - -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 - -Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com> -Reviewed-by: Andy Ritger <aritger@nvidia.com> -Reviewed-by: Adam Cheney <acheney@nvidia.com> -Reviewed-by: James Jones <jajones@nvidia.com> ---- - libweston/gl-renderer.c | 262 +++++++++++++++++++++++++++++++++++++++- - libweston/gl-renderer.h | 16 +++ - shared/weston-egl-ext.h | 40 ++++++ - 3 files changed, 315 insertions(+), 3 deletions(-) - -diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c -index b681668b..27794b60 100644 ---- a/libweston/gl-renderer.c -+++ b/libweston/gl-renderer.c -@@ -103,6 +103,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; - - /* struct timeline_render_point::link */ -@@ -233,6 +235,28 @@ struct gl_renderer { - - int has_surfaceless_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; - -@@ -1365,6 +1389,38 @@ gl_renderer_repaint_output(struct weston_output *output, - TIMELINE_RENDER_POINT_TYPE_END); - } - -+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 (gr->stream_consumer_acquire_attrib( -+ gr->egl_display, -+ go->egl_stream, -+ acquire_attribs) != EGL_TRUE) -+ 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, -@@ -3011,9 +3067,93 @@ 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 gl_output_state *go; - int i; -@@ -3023,6 +3163,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]); -@@ -3057,13 +3198,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) - weston_platform_destroy_egl_surface(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) - { -@@ -3088,6 +3257,9 @@ gl_renderer_output_destroy(struct weston_output *output) - wl_list_for_each_safe(trp, tmp, &go->timeline_render_point_list, link) - timeline_render_point_destroy(trp); - -+ if (go->egl_stream != EGL_NO_STREAM_KHR) -+ gr->destroy_stream(gr->egl_display, go->egl_stream); -+ - free(go); - } - -@@ -3184,6 +3356,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); -@@ -3257,6 +3442,30 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec) - "missing EGL_ANDROID_native_fence_sync extension\n"); - } - -+ if (weston_check_egl_extension(extensions, "EGL_EXT_output_base")) -+ gr->has_egl_output_base = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_EXT_output_drm")) -+ gr->has_egl_output_drm = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_NV_output_drm_flip_event")) -+ gr->has_egl_output_drm_flip_event = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_KHR_stream")) -+ gr->has_egl_stream = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_KHR_stream_producer_eglsurface")) -+ gr->has_egl_stream_producer_eglsurface = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_EXT_stream_consumer_egloutput")) -+ gr->has_egl_stream_consumer_egloutput = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_NV_stream_attrib")) -+ gr->has_egl_stream_attrib = 1; -+ -+ if (weston_check_egl_extension(extensions, "EGL_EXT_stream_acquire_mode")) -+ gr->has_egl_stream_acquire_mode = 1; -+ - renderer_setup_egl_client_extensions(gr); - - return 0; -@@ -3282,6 +3491,15 @@ 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 - * -@@ -3355,6 +3573,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"); - } -@@ -3491,6 +3711,38 @@ 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; -@@ -3862,15 +4114,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/libweston/gl-renderer.h b/libweston/gl-renderer.h -index 9ff4e21e..39ea3b42 100644 ---- a/libweston/gl-renderer.h -+++ b/libweston/gl-renderer.h -@@ -60,6 +60,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, -@@ -78,6 +79,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); -@@ -122,5 +126,17 @@ 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/shared/weston-egl-ext.h b/shared/weston-egl-ext.h -index 0784ea2d..f39990ed 100644 ---- a/shared/weston-egl-ext.h -+++ b/shared/weston-egl-ext.h -@@ -204,12 +204,52 @@ typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, - #define EGL_NO_NATIVE_FENCE_FD_ANDROID -1 - #endif - -+#ifndef EGL_PLATFORM_DEVICE_EXT -+#define EGL_PLATFORM_DEVICE_EXT 0x313F -+#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 */ -+ - #else /* ENABLE_EGL */ - - /* EGL platform definition are keept to allow compositor-xx.c to build */ - #define EGL_PLATFORM_GBM_KHR 0x31D7 - #define EGL_PLATFORM_WAYLAND_KHR 0x31D8 - #define EGL_PLATFORM_X11_KHR 0x31D5 -+#define EGL_PLATFORM_DEVICE_EXT 0x313F - - #endif /* ENABLE_EGL */ - --- -2.18.0 - |