[Mesa-dev] [PATCH v3 3/3] egl: add config debug printout (v3)

Silvestrs Timofejevs silvestrs.timofejevs at imgtec.com
Mon Apr 1 14:33:48 UTC 2019


On Mon, Jan 14, 2019 at 08:20:09PM +0000, Emil Velikov wrote:
>  e aOn Fri, 11 Jan 2019 at 16:34, Silvestrs Timofejevs
> <silvestrs.timofejevs at imgtec.com> wrote:
> >
> > Feature to print out EGL returned configs for debug purposes.
> >
> > 'eglChooseConfig' and 'eglGetConfigs' debug information printout is
> > enabled when the log level equals '_EGL_DEBUG'. The configs are
> > printed, and if any of them are "chosen" they are marked with their
> > index in the chosen configs array.
> >
> > v2:
> >    a) refactor the code in line with Eric's comments
> >    b) rename function _snprintfStrcat, split it out and put into the
> >       src/util/u_string.h, make it a separate patch.
> > v3:
> >    remove unnecessary 'const' qualifiers from the function prototype
> >
> > Signed-off-by: Silvestrs Timofejevs <silvestrs.timofejevs at imgtec.com>
> > Reviewed-by: Eric Engestrom <eric.engestrom at intel.com>
> > ---
> >  src/egl/Makefile.sources      |   4 +-
> >  src/egl/main/eglconfig.c      |  20 +++-
> >  src/egl/main/eglconfigdebug.c | 265 ++++++++++++++++++++++++++++++++++++++++++
> >  src/egl/main/eglconfigdebug.h |  55 +++++++++
> >  src/egl/meson.build           |   2 +
> >  5 files changed, 341 insertions(+), 5 deletions(-)
> >  create mode 100644 src/egl/main/eglconfigdebug.c
> >  create mode 100644 src/egl/main/eglconfigdebug.h
> >
> > diff --git a/src/egl/Makefile.sources b/src/egl/Makefile.sources
> > index 0cc5f1b..353a848 100644
> > --- a/src/egl/Makefile.sources
> > +++ b/src/egl/Makefile.sources
> > @@ -28,7 +28,9 @@ LIBEGL_C_FILES := \
> >         main/eglsync.c \
> >         main/eglsync.h \
> >         main/eglentrypoint.h \
> > -       main/egltypedefs.h
> > +       main/egltypedefs.h \
> > +       main/eglconfigdebug.h \
> > +       main/eglconfigdebug.c
> >
> >  dri2_backend_core_FILES := \
> >         drivers/dri2/egl_dri2.c \
> > diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c
> > index a346f93..0095dc2 100644
> > --- a/src/egl/main/eglconfig.c
> > +++ b/src/egl/main/eglconfig.c
> > @@ -40,6 +40,7 @@
> >  #include "util/macros.h"
> >
> >  #include "eglconfig.h"
> > +#include "eglconfigdebug.h"
> >  #include "egldisplay.h"
> >  #include "eglcurrent.h"
> >  #include "egllog.h"
> > @@ -797,14 +798,21 @@ _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
> >                   EGLConfig *configs, EGLint config_size, EGLint *num_configs)
> >  {
> >     _EGLConfig criteria;
> > +   EGLBoolean result;
> >
> >     if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
> >        return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
> >
> > -   return _eglFilterConfigArray(disp->Configs,
> > -         configs, config_size, num_configs,
> > -         _eglFallbackMatch, _eglFallbackCompare,
> > -         (void *) &criteria);
> > +   result = _eglFilterConfigArray(disp->Configs,
> > +                                  configs, config_size, num_configs,
> > +                                  _eglFallbackMatch, _eglFallbackCompare,
> > +                                  (void *) &criteria);
> > +
> > +   if (result && (_eglGetLogLevel() == _EGL_DEBUG))
> > +      eglPrintConfigDebug(drv, disp, configs, *num_configs,
> > +                          EGL_CONFIG_DEBUG_CHOOSE);
> > +
> > +   return result;
> >  }
> >
> >
> > @@ -857,5 +865,9 @@ _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
> >     *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
> >           sizeof(configs[0]), config_size, _eglFlattenConfig);
> >
> > +   if (_eglGetLogLevel() == _EGL_DEBUG)
> > +      eglPrintConfigDebug(drv, disp, configs, *num_config,
> > +                          EGL_CONFIG_DEBUG_GET);
> > +
> >     return EGL_TRUE;
> >  }
> > diff --git a/src/egl/main/eglconfigdebug.c b/src/egl/main/eglconfigdebug.c
> > new file mode 100644
> > index 0000000..0617c99
> > --- /dev/null
> > +++ b/src/egl/main/eglconfigdebug.c
> > @@ -0,0 +1,265 @@
> > +/*
> > + * Copyright 2017 Imagination Technologies.
> > + * All Rights Reserved.
> > + *
> > + * Based on eglinfo, which has copyright:
> > + * Copyright (C) 2005  Brian Paul   All Rights Reserved.
> > + *
> > + * Permission is hereby granted, free of charge, to any person obtaining a
> > + * copy of this software and associated documentation files (the "Software"),
> > + * to deal in the Software without restriction, including without limitation
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> > + * and/or sell copies of the Software, and to permit persons to whom the
> > + * Software is furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be included
> > + * in all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> > + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> > + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
> > + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
> > + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> > + */
> > +
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <stdio.h>
> > +#include <stdarg.h>
> > +
> > +#include "eglarray.h"
> > +#include "eglconfig.h"
> > +#include "eglconfigdebug.h"
> > +#include "egldisplay.h"
> > +#include "egllog.h"
> > +#include "egltypedefs.h"
> > +#include "util/macros.h"
> > +#include "util/u_string.h"
> > +
> > +/* Max debug message length */
> > +#define CONFIG_DEBUG_MSG_MAX 1000
> > +
> > +/*
> > + * These are X visual types, so if you're running eglinfo under
> > + * something not X, they probably don't make sense.
> > + */
> > +static const char *const vnames[] = { "SG", "GS", "SC", "PC", "TC", "DC" };
> > +
> > +struct _printAttributes {
> > +   EGLint id, size, level;
> > +   EGLint red, green, blue, alpha;
> > +   EGLint depth, stencil;
> > +   EGLint renderable, surfaces;
> > +   EGLint vid, vtype, caveat, bindRgb, bindRgba;
> > +   EGLint samples, sampleBuffers;
> > +   char surfString[32];
> > +};
> > +
> > +static void
> > +_printHeaderFormat(void)
> > +{
> > +   /*
> > +    * EGL configuration output legend:
> > +    *
> > +    * chosen --------------- eglChooseConfig returned config priority,
> > +    *                        only relevant when eglChooseConfig is called.
> > +    * id ------------------- EGL_CONFIG_ID
> > +    * bfsz ----------------- EGL_BUFFER_SIZE
> > +    * lvl ------------------ EGL_LEVEL
> > +    *
> > +    * colourbuffer
> > +    * r -------------------- EGL_RED_SIZE
> > +    * g -------------------- EGL_GREEN_SIZE
> > +    * b -------------------- EGL_BLUE_SIZE
> > +    * a -------------------- EGL_ALPHA_SIZE
> > +    * dpth ----------------- EGL_DEPTH_SIZE
> > +    * stcl ----------------- EGL_STENCIL_SIZE
> > +    *
> > +    * multisample
> > +    * ns ------------------- EGL_SAMPLES
> > +    * b -------------------- EGL_SAMPLE_BUFFERS
> > +    * visid ---------------- EGL_NATIVE_VISUAL_ID/EGL_NATIVE_VISUAL_TYPE
> > +    * caveat --------------- EGL_CONFIG_CAVEAT
> > +    * bind ----------------- EGL_BIND_TO_TEXTURE_RGB/EGL_BIND_TO_TEXTURE_RGBA
> > +    *
> > +    * renderable
> > +    * gl, es, es2, es3, vg - EGL_RENDERABLE_TYPE
> > +    *
> > +    * supported
> > +    * surfaces ------------- EGL_SURFACE_TYPE
> > +    */
> > +   _eglLog(_EGL_DEBUG, "---------------");
> > +   _eglLog(_EGL_DEBUG, "Configurations:");
> > +   _eglLog(_EGL_DEBUG, "cho       bf lv colourbuffer dp st  ms           vis  cav  bi     renderable           supported");
> > +   _eglLog(_EGL_DEBUG, "sen    id sz  l  r  g  b  a  th cl ns b           id  eat  nd  gl es es2 es3 vg         surfaces");
> > +   _eglLog(_EGL_DEBUG, "---------------");
> > +}
> > +
> > +static void
> > +_eglGetConfigAttrs(_EGLDriver *const drv, _EGLDisplay *const dpy,
> > +                   _EGLConfig *const conf, struct _printAttributes *const attr)
> > +{
> > +   EGLBoolean success = EGL_TRUE;
> > +
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_CONFIG_ID, &attr->id);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_BUFFER_SIZE, &attr->size);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_LEVEL, &attr->level);
> > +
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_RED_SIZE, &attr->red);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_GREEN_SIZE, &attr->green);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_BLUE_SIZE, &attr->blue);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_ALPHA_SIZE, &attr->alpha);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_DEPTH_SIZE, &attr->depth);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_STENCIL_SIZE, &attr->stencil);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_NATIVE_VISUAL_ID, &attr->vid);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_NATIVE_VISUAL_TYPE, &attr->vtype);
> > +
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_CONFIG_CAVEAT, &attr->caveat);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_BIND_TO_TEXTURE_RGB, &attr->bindRgb);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_BIND_TO_TEXTURE_RGBA, &attr->bindRgba);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_RENDERABLE_TYPE, &attr->renderable);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_SURFACE_TYPE, &attr->surfaces);
> > +
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_SAMPLES, &attr->samples);
> > +   success &= _eglGetConfigAttrib(drv, dpy, conf, EGL_SAMPLE_BUFFERS, &attr->sampleBuffers);
> > +
> 
> _eglGetConfigAttrib is for API level usage. Since we know the attribs
> are valid we can use _eglGetConfigKey().
> Thus all the validation (as done in the former) and error checking
> here can be dropped.
> 
> Taking it a step further I'd drop the struct and directly use the
> values from _eglGetConfigKey().
> 
> > +   if (!success)
> > +      _eglLog(_EGL_DEBUG, "%s: config ID = %d, could not obtain all attributes",
> > +              __func__, conf->ConfigID);
> > +}
> > +
> > +static void
> > +_eglPrintConfig(_EGLDriver *const drv, _EGLDisplay *const dpy,
> > +                _EGLConfig *const conf, char *const printMsg)
> > +{
> > +   struct _printAttributes attr = { 0 };
> > +
> char surfstring[32];
> 
> > +   _eglGetConfigAttrs(drv, dpy, conf, &attr);
> > +
> > +   if (attr.surfaces & EGL_WINDOW_BIT)
> > +      strcat(attr.surfString, "win,");
> > +   if (attr.surfaces & EGL_PBUFFER_BIT)
> > +      strcat(attr.surfString, "pb,");
> > +   if (attr.surfaces & EGL_PIXMAP_BIT)
> > +      strcat(attr.surfString, "pix,");
> > +   if (attr.surfaces & EGL_STREAM_BIT_KHR)
> > +      strcat(attr.surfString, "str,");
> > +   if (attr.surfaces & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
> > +      strcat(attr.surfString, "prsv");
> > +   if (strlen(attr.surfString) > 0)
> > +      attr.surfString[strlen(attr.surfString) - 1] = 0;
> > +
> > +   STATIC_ASSERT(sizeof(attr.surfString) >= sizeof("win,pb,pix,str,prsv"));
> > +
> 
> 
> > +   util_strnappend(printMsg, CONFIG_DEBUG_MSG_MAX,
> > +                   "0x%03x %2d %2d %2d %2d %2d %2d  %2d %2d %2d%2d 0x%08x%2s     ",
> > +                   attr.id, attr.size, attr.level,
> > +                   attr.red, attr.green, attr.blue, attr.alpha,
> > +                   attr.depth, attr.stencil,
> > +                   attr.samples, attr.sampleBuffers, attr.vid,
> > +                   attr.vtype < 6 ? vnames[attr.vtype] : "--");
> > +
> > +   util_strnappend(printMsg, CONFIG_DEBUG_MSG_MAX,
> > +                   "%c  %c   %c  %c   %c   %c   %c %15s",
> > +                   (attr.caveat != EGL_NONE) ? 'y' : ' ',
> > +                   (attr.bindRgba) ? 'a' : (attr.bindRgb) ? 'y' : ' ',
> > +                   (attr.renderable & EGL_OPENGL_BIT) ? 'y' : ' ',
> > +                   (attr.renderable & EGL_OPENGL_ES_BIT) ? 'y' : ' ',
> > +                   (attr.renderable & EGL_OPENGL_ES2_BIT) ? 'y' : ' ',
> > +                   (attr.renderable & EGL_OPENGL_ES3_BIT) ? 'y' : ' ',
> > +                   (attr.renderable & EGL_OPENVG_BIT) ? 'y' : ' ',
> > +                   attr.surfString);
> > +
> > +   _eglLog(_EGL_DEBUG, printMsg);
> > +}
> > +
> > +static void
> > +_eglWriteChosenConfigOrderNum(_EGLConfig *const config,
> > +                              _EGLConfig *const *const chosenConfigs,
> > +                              const EGLint numConfigs, char *const printMsg)
> > +{
> > +   const char padding[] = "   ";
> > +
> > +   if (chosenConfigs == NULL) {
> > +      util_strnappend(printMsg, CONFIG_DEBUG_MSG_MAX, "%s ", &padding[0]);
> > +      return;
> > +   }
> > +
> > +   /* Find a match, write its order number and return */
> > +   for (EGLint i = 0; i < numConfigs; i++) {
> > +      if (config == chosenConfigs[i]) {
> > +         util_strnappend(printMsg, CONFIG_DEBUG_MSG_MAX, "%*d ",
> > +                         strlen(padding), i);
> > +         return;
> > +      }
> > +   }
> > +
> > +   util_strnappend(printMsg, CONFIG_DEBUG_MSG_MAX, "%s ", &padding[0]);
> > +}
> > +
> > +static void
> > +_eglPrintConfigs(_EGLDriver *const drv, _EGLDisplay *const dpy,
> > +                 EGLConfig *const configs, const EGLint numConfigs,
> > +                 const enum EGL_CONFIG_DEBUG_OPTION printOption)
> > +{
> > +   EGLint numConfigsToPrint;
> > +   _EGLConfig **configsToPrint;
> > +   _EGLConfig **chosenConfigs;
> > +   char *printMsg;
> > +
> > +   printMsg = malloc(CONFIG_DEBUG_MSG_MAX);
> > +   if (!printMsg) {
> > +      _eglLog(_EGL_DEBUG, "%s: failed to allocate the print message", __func__);
> > +      return;
> > +   }
> > +
> > +   /*
> > +    * If the printout request came from the 'eglChooseConfig', all
> > +    * configs are printed, and the "chosen" configs are marked.
> > +    */
> > +   if (printOption == EGL_CONFIG_DEBUG_CHOOSE) {
> > +      configsToPrint = (_EGLConfig **) dpy->Configs->Elements;
> > +      numConfigsToPrint = dpy->Configs->Size;
> > +      chosenConfigs = (_EGLConfig **) configs;
> > +   } else {
> > +      assert(printOption == EGL_CONFIG_DEBUG_GET);
> > +      configsToPrint = (_EGLConfig **) configs;
> > +      numConfigsToPrint = numConfigs;
> > +      chosenConfigs = NULL;
> > +   }
> > +
> > +   _printHeaderFormat();
> > +   for (EGLint i = 0; i < numConfigsToPrint; i++) {
> > +      _EGLConfig *configToPrint = configsToPrint[i];
> > +
> > +      /* "clear" message */
> > +      printMsg[0] = '\0';
> > +
> > +      _eglWriteChosenConfigOrderNum(configToPrint, chosenConfigs, numConfigs,
> > +                                    printMsg);
> > +
> > +      _eglPrintConfig(drv, dpy, configToPrint, printMsg);
> We don't need to walk through the list twice. Simply pass the config
> (to be printed) to _eglPrintConfig()?
> Plus we can drop the temporary printMsg all together.
The idea is when the _eglChooseConfig function is called, we print all of the
configs. If a config is "chosen", then we print its index number at the
beginning of the printout string. Example:

all configs:         chosen configs:
conf0                conf1
conf1                conf4
conf2
conf3
conf4

output:
  ......................
0 ......................
  ......................
  ......................
1 ......................

To do that we would have to walk the array twice (to print all of the configs,
and find out which are chosen to mark them). That seems a little wasteful, but
on the other hand this is a debug feature, so being more descriptive is more
important (in my opinion).

What do you think?
> 
> > +
> > +   free(printMsg);
> > +}
> > +
> > +void eglPrintConfigDebug(_EGLDriver *const drv, _EGLDisplay *const dpy,
> > +                         EGLConfig *const configs, const EGLint numConfigs,
> > +                         const enum EGL_CONFIG_DEBUG_OPTION printOption)
> > +{
> > +   if (!numConfigs || !configs) {
> > +      _eglLog(_EGL_DEBUG, "%s: nothing to print", __func__);
> > +      return;
> > +   }
> > +
> > +   switch (printOption) {
> > +   case EGL_CONFIG_DEBUG_CHOOSE:
> > +   case EGL_CONFIG_DEBUG_GET:
> > +      _eglPrintConfigs(drv, dpy, configs, numConfigs, printOption);
> > +      return;
> I'd fold the two functions _eglPrintConfigs and eglPrintConfigDebug.
> Might even swap the EGL_CONFIG_DEBUG_OPTION enum with "print_chosen"
> or equivalent bool.
> 
> With my nitpicking, the resulting code should be around half the size ;-)
> 
> HTH
> Emil

Thanks,
Silvestrs


More information about the mesa-dev mailing list