[Mesa-dev] [PATCH mesa 4/7] Add the EGL_MESA_configless_context extension

John Kåre Alsaker john.kare.alsaker at gmail.com
Sat May 3 05:40:25 PDT 2014


This commit results in garbage output for r600g when building with
OpenGL (not ES) as enabled by my patches:
https://github.com/Zoxc/weston/commits/gl-rebase. (--enable-opengl on
configure)

It works on i965 so I was wondering how well tested this is on Gallium drivers?

On Fri, Mar 7, 2014 at 7:05 PM, Neil Roberts <neil at linux.intel.com> wrote:
> This extension provides a way for an application to render to multiple
> surfaces with different buffer formats without having to use multiple
> contexts. An EGLContext can be created without an EGLConfig by passing
> EGL_NO_CONFIG_MESA. In that case there are no restrictions on the surfaces
> that can be used with the context apart from that they must be using the same
> EGLDisplay.
>
> _mesa_initialze_context can now take a NULL gl_config which will mark the
> context as ‘configless’. It will memset the visual to zero in that case.
> Previously the i965 and i915 drivers were explicitly creating a zeroed visual
> whenever 0 is passed for the EGLConfig. Mesa needs to be aware that the
> context is configless because it affects the initial value to use for
> glDrawBuffer. The first time the context is bound it will set the initial
> value for configless contexts depending on whether the framebuffer used is
> double-buffered.
> ---
>  docs/specs/MESA_configless_context.spec   | 120 ++++++++++++++++++++++++++++++
>  include/EGL/eglext.h                      |   5 ++
>  src/egl/drivers/dri2/egl_dri2.c           |   1 +
>  src/egl/main/eglapi.c                     |   2 +-
>  src/egl/main/eglcontext.c                 |  20 ++++-
>  src/egl/main/egldisplay.h                 |   1 +
>  src/egl/main/eglmisc.c                    |   1 +
>  src/mesa/drivers/dri/i915/intel_context.c |   6 --
>  src/mesa/drivers/dri/i965/brw_context.c   |   6 --
>  src/mesa/main/context.c                   |  82 +++++++++++++++-----
>  src/mesa/main/mtypes.h                    |   6 ++
>  11 files changed, 213 insertions(+), 37 deletions(-)
>  create mode 100644 docs/specs/MESA_configless_context.spec
>
> diff --git a/docs/specs/MESA_configless_context.spec b/docs/specs/MESA_configless_context.spec
> new file mode 100644
> index 0000000..8bed90d
> --- /dev/null
> +++ b/docs/specs/MESA_configless_context.spec
> @@ -0,0 +1,120 @@
> +Name
> +
> +    MESA_configless_context
> +
> +Name Strings
> +
> +    EGL_MESA_configless_context
> +
> +Contact
> +
> +    Neil Roberts <neil.s.roberts at intel.com>
> +
> +Status
> +
> +    Proposal
> +
> +Version
> +
> +    Version 1, February 28, 2014
> +
> +Number
> +
> +    EGL Extension #not assigned
> +
> +Dependencies
> +
> +    Requires EGL 1.4 or later.  This extension is written against the
> +    wording of the EGL 1.4 specification.
> +
> +Overview
> +
> +    This extension provides a means to use a single context to render to
> +    multiple surfaces which have different EGLConfigs. Without this extension
> +    the EGLConfig for every surface used by the context must be compatible
> +    with the one used by the context. The only way to render to surfaces with
> +    different formats would be to create multiple contexts but this is
> +    inefficient with modern GPUs where this restriction is unnecessary.
> +
> +IP Status
> +
> +    Open-source; freely implementable.
> +
> +New Procedures and Functions
> +
> +    None.
> +
> +New Tokens
> +
> +    Accepted as <config> in eglCreateContext
> +
> +        EGL_NO_CONFIG_MESA                  ((EGLConfig)0)
> +
> +Additions to the EGL Specification section "2.2 Rendering Contexts and Drawing
> +Surfaces"
> +
> +    Add the following to the 3rd paragraph:
> +
> +   "EGLContexts can also optionally be created with respect to an EGLConfig
> +    depending on the parameters used at creation time. If a config is provided
> +    then additional restrictions apply on what surfaces can be used with the
> +    context."
> +
> +    Replace the last sentence of the 6th paragraph with:
> +
> +   "In order for a context to be compatible with a surface they both must have
> +    been created with respect to the same EGLDisplay. If the context was
> +    created without respect to an EGLConfig then there are no further
> +    constraints. Otherwise they are only compatible if:"
> +
> +    Remove the last bullet point in the list of constraints.
> +
> +Additions to the EGL Specification section "3.7.1 Creating Rendering Contexts"
> +
> +    Replace the paragraph starting "If config is not a valid EGLConfig..."
> +    with
> +
> +   "The config argument can either be a valid EGLConfig or EGL_NO_CONFIG_MESA.
> +    If it is neither of these then an EGL_BAD_CONFIG error is generated. If a
> +    valid config is passed then the error will also be generated if the config
> +    does not support the requested client API (this includes requesting
> +    creation of an OpenGL ES 1.x context when the EGL_RENDERABLE_TYPE
> +    attribute of config does not contain EGL_OPENGL_ES_BIT, or creation of an
> +    OpenGL ES 2.x context when the attribute does not contain
> +    EGL_OPENGL_ES2_BIT).
> +
> +    Passing EGL_NO_CONFIG_MESA will create a configless context. When a
> +    configless context is used with the OpenGL API it can be assumed that the
> +    initial values of the context's state will be decided when the context is
> +    first made current. In particular this means that the decision of whether
> +    to use GL_BACK or GL_FRONT for the initial value of the first output in
> +    glDrawBuffers will be decided based on the config of the draw surface when
> +    it is first bound. If the context is later bound to another surface with a
> +    different config it will not alter the context's state. This means that is
> +    possible to have the draw buffer set to GL_BACK with a single-buffered
> +    surface. The results of drawing in this case are undefined. The OpenGL ES
> +    3.0 API does not have this problem and instead the default is always
> +    GL_BACK which has a special interpretation depending on how many buffers
> +    the surface has."
> +
> +Additions to the EGL Specification section "3.7.3 Binding Contexts and
> +Drawables"
> +
> +    Replace the first bullet point with the following:
> +
> +   "* If draw or read are not compatible with ctx as described in section 2.2,
> +      then an EGL_BAD_MATCH error is generated."
> +
> +    Add a second bullet point after that:
> +
> +   "* If draw and read are not compatible with each other as described in
> +      section 2.2, then an EGL_BAD_MATCH error is generated."
> +
> +Issues
> +
> +    None.
> +
> +Revision History
> +
> +    Version 1, February 28, 2014
> +        Initial draft (Neil Roberts)
> diff --git a/include/EGL/eglext.h b/include/EGL/eglext.h
> index 1d68178..fc53914 100644
> --- a/include/EGL/eglext.h
> +++ b/include/EGL/eglext.h
> @@ -571,6 +571,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT( EGLDisplay dpy, EGLSu
>  typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
>  #endif
>
> +#ifndef EGL_MESA_configless_context
> +#define EGL_MESA_configless_context 1
> +#define EGL_NO_CONFIG_MESA                     ((EGLConfig)0)
> +#endif
> +
>  #include <EGL/eglmesaext.h>
>
>  #ifdef __cplusplus
> diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
> index 892f1f4..f304075 100644
> --- a/src/egl/drivers/dri2/egl_dri2.c
> +++ b/src/egl/drivers/dri2/egl_dri2.c
> @@ -508,6 +508,7 @@ dri2_setup_screen(_EGLDisplay *disp)
>
>     assert(dri2_dpy->dri2 || dri2_dpy->swrast);
>     disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
> +   disp->Extensions.MESA_configless_context = EGL_TRUE;
>
>     if (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) {
>        disp->Extensions.KHR_create_context = EGL_TRUE;
> diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
> index 42bcb72..950c447 100644
> --- a/src/egl/main/eglapi.c
> +++ b/src/egl/main/eglapi.c
> @@ -431,7 +431,7 @@ eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list,
>
>     _EGL_CHECK_DISPLAY(disp, EGL_NO_CONTEXT, drv);
>
> -   if (!config)
> +   if (!config && !disp->Extensions.MESA_configless_context)
>        RETURN_EGL_ERROR(disp, EGL_BAD_CONFIG, EGL_NO_CONTEXT);
>
>     if (!share && share_list != EGL_NO_CONTEXT)
> diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c
> index 79a92c7..70277ab 100644
> --- a/src/egl/main/eglcontext.c
> +++ b/src/egl/main/eglcontext.c
> @@ -523,10 +523,22 @@ _eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read)
>           return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent");
>     }
>
> -   /* simply require the configs to be equal */
> -   if ((draw && draw->Config != ctx->Config) ||
> -       (read && read->Config != ctx->Config))
> -      return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
> +   /* If the context has a config then it must match that of the two
> +    * surfaces */
> +   if (ctx->Config) {
> +      if ((draw && draw->Config != ctx->Config) ||
> +          (read && read->Config != ctx->Config))
> +         return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
> +   } else {
> +      /* Otherwise we must be using the EGL_MESA_configless_context
> +       * extension */
> +      assert(dpy->Extensions.MESA_configless_context);
> +
> +      /* The extension doesn't permit binding draw and read buffers with
> +       * differing contexts */
> +      if (draw && read && draw->Config != read->Config)
> +         return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
> +   }
>
>     switch (ctx->ClientAPI) {
>     /* OpenGL and OpenGL ES are conflicting */
> diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
> index 66aaff5..0952bc9 100644
> --- a/src/egl/main/egldisplay.h
> +++ b/src/egl/main/egldisplay.h
> @@ -89,6 +89,7 @@ struct _egl_extensions
>     EGLBoolean MESA_copy_context;
>     EGLBoolean MESA_drm_display;
>     EGLBoolean MESA_drm_image;
> +   EGLBoolean MESA_configless_context;
>
>     EGLBoolean WL_bind_wayland_display;
>     EGLBoolean WL_create_wayland_buffer_from_image;
> diff --git a/src/egl/main/eglmisc.c b/src/egl/main/eglmisc.c
> index 341a723..65669d8 100644
> --- a/src/egl/main/eglmisc.c
> +++ b/src/egl/main/eglmisc.c
> @@ -90,6 +90,7 @@ _eglUpdateExtensionsString(_EGLDisplay *dpy)
>     _EGL_CHECK_EXTENSION(MESA_copy_context);
>     _EGL_CHECK_EXTENSION(MESA_drm_display);
>     _EGL_CHECK_EXTENSION(MESA_drm_image);
> +   _EGL_CHECK_EXTENSION(MESA_configless_context);
>
>     _EGL_CHECK_EXTENSION(WL_bind_wayland_display);
>     _EGL_CHECK_EXTENSION(WL_create_wayland_buffer_from_image);
> diff --git a/src/mesa/drivers/dri/i915/intel_context.c b/src/mesa/drivers/dri/i915/intel_context.c
> index 0cb1fea..a6057d3 100644
> --- a/src/mesa/drivers/dri/i915/intel_context.c
> +++ b/src/mesa/drivers/dri/i915/intel_context.c
> @@ -410,7 +410,6 @@ intelInitContext(struct intel_context *intel,
>     __DRIscreen *sPriv = driContextPriv->driScreenPriv;
>     struct intel_screen *intelScreen = sPriv->driverPrivate;
>     int bo_reuse_mode;
> -   struct gl_config visual;
>
>     /* Can't rely on invalidate events, fall back to glViewport hack */
>     if (!driContextPriv->driScreenPriv->dri2.useInvalidate)
> @@ -418,11 +417,6 @@ intelInitContext(struct intel_context *intel,
>     else
>        functions->Viewport = intel_viewport;
>
> -   if (mesaVis == NULL) {
> -      memset(&visual, 0, sizeof visual);
> -      mesaVis = &visual;
> -   }
> -
>     intel->intelScreen = intelScreen;
>
>     if (!_mesa_initialize_context(&intel->ctx, api, mesaVis, shareCtx,
> diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
> index 1441b46..ad5e729 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.c
> +++ b/src/mesa/drivers/dri/i965/brw_context.c
> @@ -584,7 +584,6 @@ brwCreateContext(gl_api api,
>     struct intel_screen *screen = sPriv->driverPrivate;
>     const struct brw_device_info *devinfo = screen->devinfo;
>     struct dd_function_table functions;
> -   struct gl_config visual;
>
>     /* Only allow the __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS flag if the kernel
>      * provides us with context reset notifications.
> @@ -651,11 +650,6 @@ brwCreateContext(gl_api api,
>
>     struct gl_context *ctx = &brw->ctx;
>
> -   if (mesaVis == NULL) {
> -      memset(&visual, 0, sizeof visual);
> -      mesaVis = &visual;
> -   }
> -
>     if (!_mesa_initialize_context(ctx, api, mesaVis, shareCtx, &functions)) {
>        *dri_ctx_error = __DRI_CTX_ERROR_NO_MEMORY;
>        fprintf(stderr, "%s: failed to init mesa context\n", __FUNCTION__);
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index 5b77ce1..cd009c1 100644
> --- a/src/mesa/main/context.c
> +++ b/src/mesa/main/context.c
> @@ -1013,7 +1013,8 @@ _mesa_initialize_dispatch_tables(struct gl_context *ctx)
>   *
>   * \param ctx the context to initialize
>   * \param api the GL API type to create the context for
> - * \param visual describes the visual attributes for this context
> + * \param visual describes the visual attributes for this context or NULL to
> + *               create a configless context
>   * \param share_list points to context to share textures, display lists,
>   *        etc with, or NULL
>   * \param driverFunctions table of device driver functions for this context
> @@ -1033,12 +1034,20 @@ _mesa_initialize_context(struct gl_context *ctx,
>     assert(driverFunctions->FreeTextureImageBuffer);
>
>     ctx->API = api;
> -   ctx->Visual = *visual;
>     ctx->DrawBuffer = NULL;
>     ctx->ReadBuffer = NULL;
>     ctx->WinSysDrawBuffer = NULL;
>     ctx->WinSysReadBuffer = NULL;
>
> +   if (visual) {
> +      ctx->Visual = *visual;
> +      ctx->HasConfig = GL_TRUE;
> +   }
> +   else {
> +      memset(&ctx->Visual, 0, sizeof ctx->Visual);
> +      ctx->HasConfig = GL_FALSE;
> +   }
> +
>     if (_mesa_is_desktop_gl(ctx)) {
>        _mesa_override_gl_version(ctx);
>     }
> @@ -1145,7 +1154,8 @@ fail:
>   * the rendering context.
>   *
>   * \param api the GL API type to create the context for
> - * \param visual a struct gl_config pointer (we copy the struct contents)
> + * \param visual a struct gl_config pointer (we copy the struct contents) or
> + *               NULL to create a configless context
>   * \param share_list another context to share display lists with or NULL
>   * \param driverFunctions points to the dd_function_table into which the
>   *        driver has plugged in all its special functions.
> @@ -1160,8 +1170,6 @@ _mesa_create_context(gl_api api,
>  {
>     struct gl_context *ctx;
>
> -   ASSERT(visual);
> -
>     ctx = calloc(1, sizeof(struct gl_context));
>     if (!ctx)
>        return NULL;
> @@ -1475,6 +1483,54 @@ _mesa_check_init_viewport(struct gl_context *ctx, GLuint width, GLuint height)
>     }
>  }
>
> +static void
> +handle_first_current(struct gl_context *ctx)
> +{
> +   GLenum buffer;
> +   GLint bufferIndex;
> +
> +   assert(ctx->Version > 0);
> +
> +   ctx->Extensions.String = _mesa_make_extension_string(ctx);
> +
> +   check_context_limits(ctx);
> +
> +   /* According to GL_MESA_configless_context the default value of
> +    * glDrawBuffers depends on the config of the first surface it is bound to.
> +    * For GLES it is always GL_BACK which has a magic interpretation */
> +   if (!ctx->HasConfig && _mesa_is_desktop_gl(ctx)) {
> +      if (ctx->DrawBuffer != _mesa_get_incomplete_framebuffer()) {
> +         if (ctx->DrawBuffer->Visual.doubleBufferMode)
> +            buffer = GL_BACK;
> +         else
> +            buffer = GL_FRONT;
> +
> +         _mesa_drawbuffers(ctx, 1, &buffer, NULL /* destMask */);
> +      }
> +
> +      if (ctx->ReadBuffer != _mesa_get_incomplete_framebuffer()) {
> +         if (ctx->ReadBuffer->Visual.doubleBufferMode) {
> +            buffer = GL_BACK;
> +            bufferIndex = BUFFER_BACK_LEFT;
> +         }
> +         else {
> +            buffer = GL_FRONT;
> +            bufferIndex = BUFFER_FRONT_LEFT;
> +         }
> +
> +         _mesa_readbuffer(ctx, buffer, bufferIndex);
> +      }
> +   }
> +
> +   /* We can use this to help debug user's problems.  Tell them to set
> +    * the MESA_INFO env variable before running their app.  Then the
> +    * first time each context is made current we'll print some useful
> +    * information.
> +    */
> +   if (_mesa_getenv("MESA_INFO")) {
> +      _mesa_print_info(ctx);
> +   }
> +}
>
>  /**
>   * Bind the given context to the given drawBuffer and readBuffer and
> @@ -1567,21 +1623,7 @@ _mesa_make_current( struct gl_context *newCtx,
>        }
>
>        if (newCtx->FirstTimeCurrent) {
> -         assert(newCtx->Version > 0);
> -
> -         newCtx->Extensions.String = _mesa_make_extension_string(newCtx);
> -
> -         check_context_limits(newCtx);
> -
> -         /* We can use this to help debug user's problems.  Tell them to set
> -          * the MESA_INFO env variable before running their app.  Then the
> -          * first time each context is made current we'll print some useful
> -          * information.
> -          */
> -        if (_mesa_getenv("MESA_INFO")) {
> -           _mesa_print_info(newCtx);
> -        }
> -
> +         handle_first_current(newCtx);
>          newCtx->FirstTimeCurrent = GL_FALSE;
>        }
>     }
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index d05649c..d18082f 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -4220,6 +4220,12 @@ struct gl_context
>     GLboolean FirstTimeCurrent;
>     /*@}*/
>
> +   /**
> +    * False if this context was created without a config. This is needed
> +    * because the initial state of glDrawBuffers depends on this
> +    */
> +   GLboolean HasConfig;
> +
>     /** software compression/decompression supported or not */
>     GLboolean Mesa_DXTn;
>
> --
> 1.8.5.3
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the mesa-dev mailing list