1/*
2 * Copyright 2019 Imagination Technologies.
3 * All Rights Reserved.
4 *
5 * Based on eglinfo, which has copyright:
6 * Copyright (C) 2005  Brian Paul   All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
29#include <stdarg.h>
30
31#include "eglarray.h"
32#include "eglconfig.h"
33#include "eglconfigdebug.h"
34#include "egldisplay.h"
35#include "egllog.h"
36#include "egltypedefs.h"
37#include "util/macros.h"
38
39/* Max debug message length */
40#define CONFIG_DEBUG_MSG_MAX 1000
41
42/*
43 * These are X visual types, so if you're running eglinfo under
44 * something not X, they probably don't make sense.
45 */
46static const char *const vnames[] = { "SG", "GS", "SC", "PC", "TC", "DC" };
47
48static void
49_printHeaderFormat(void)
50{
51   /*
52    * EGL configuration output legend:
53    *
54    * chosen --------------- eglChooseConfig returned config priority,
55    *                        only relevant when eglChooseConfig is called.
56    * id ------------------- EGL_CONFIG_ID
57    * bfsz ----------------- EGL_BUFFER_SIZE
58    * lvl ------------------ EGL_LEVEL
59    *
60    * colourbuffer
61    * r -------------------- EGL_RED_SIZE
62    * g -------------------- EGL_GREEN_SIZE
63    * b -------------------- EGL_BLUE_SIZE
64    * a -------------------- EGL_ALPHA_SIZE
65    * dpth ----------------- EGL_DEPTH_SIZE
66    * stcl ----------------- EGL_STENCIL_SIZE
67    *
68    * multisample
69    * ns ------------------- EGL_SAMPLES
70    * b -------------------- EGL_SAMPLE_BUFFERS
71    * visid ---------------- EGL_NATIVE_VISUAL_ID/EGL_NATIVE_VISUAL_TYPE
72    * caveat --------------- EGL_CONFIG_CAVEAT
73    * bind ----------------- EGL_BIND_TO_TEXTURE_RGB/EGL_BIND_TO_TEXTURE_RGBA
74    *
75    * renderable
76    * gl, es, es2, es3, vg - EGL_RENDERABLE_TYPE
77    *
78    * supported
79    * surfaces ------------- EGL_SURFACE_TYPE
80    */
81   _eglLog(_EGL_DEBUG, "---------------");
82   _eglLog(_EGL_DEBUG, "Configurations:");
83   _eglLog(_EGL_DEBUG, "cho       bf lv colourbuffer dp st  ms           vis  cav  bi     renderable           supported");
84   _eglLog(_EGL_DEBUG, "sen    id sz  l  r  g  b  a  th cl ns b           id  eat  nd  gl es es2 es3 vg         surfaces");
85   _eglLog(_EGL_DEBUG, "---------------");
86}
87
88/* Append a formatted string to the buffer, up to the buffer size */
89static inline void
90_strnAppend(char *const buf, const int bufSize, const char *fmt, ...)
91{
92   int maxAllowed;
93   va_list args;
94   size_t bufLen = strlen(buf);
95
96   maxAllowed = bufSize - bufLen;
97   assert(maxAllowed >= 0);
98
99   va_start(args, fmt);
100   (void) vsnprintf(&buf[bufLen], maxAllowed, fmt, args);
101   va_end(args);
102}
103
104static void
105_eglPrintConfig(_EGLConfig *const conf, const int chosenIndex)
106{
107   const char padding[] = "   ";
108   char printMsg[CONFIG_DEBUG_MSG_MAX] = "";
109   char surfString[32] = "";
110   EGLint renderable, surfaces, vtype, bindRgb, bindRgba;
111
112   vtype = conf->NativeVisualType;
113   surfaces = conf->SurfaceType;
114
115   STATIC_ASSERT(sizeof(surfString) >= sizeof("win,pb,pix,str,prsv"));
116
117   if (surfaces & EGL_WINDOW_BIT)
118      strcat(surfString, "win,");
119   if (surfaces & EGL_PBUFFER_BIT)
120      strcat(surfString, "pb,");
121   if (surfaces & EGL_PIXMAP_BIT)
122      strcat(surfString, "pix,");
123   if (surfaces & EGL_STREAM_BIT_KHR)
124      strcat(surfString, "str,");
125   if (surfaces & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
126      strcat(surfString, "prsv");
127
128   /* If one of chosen configs, print its index in the returned config array */
129   if (chosenIndex >= 0)
130      _strnAppend(printMsg, sizeof(printMsg), "%*d ", strlen(padding),
131                  chosenIndex);
132   else
133      _strnAppend(printMsg, sizeof(printMsg), "%s ", &padding[0]);
134
135   _strnAppend(printMsg, sizeof(printMsg),
136               "0x%03x %2d %2d %2d %2d %2d %2d  %2d %2d %2d%2d 0x%08x%2s     ",
137               conf->ConfigID, conf->BufferSize, conf->Level,
138               conf->RedSize, conf->GreenSize, conf->BlueSize, conf->AlphaSize,
139               conf->DepthSize, conf->StencilSize,
140               conf->Samples, conf->SampleBuffers, conf->NativeVisualID,
141               vtype < 6 ? vnames[vtype] : "--");
142
143   bindRgb = conf->BindToTextureRGB;
144   bindRgba = conf->BindToTextureRGBA;
145   renderable = conf->RenderableType;
146
147   _strnAppend(printMsg, sizeof(printMsg),
148               "%c  %c   %c  %c   %c   %c   %c %15s",
149               (conf->ConfigCaveat != EGL_NONE) ? 'y' : ' ',
150               (bindRgba) ? 'a' : (bindRgb) ? 'y' : ' ',
151               (renderable & EGL_OPENGL_BIT) ? 'y' : ' ',
152               (renderable & EGL_OPENGL_ES_BIT) ? 'y' : ' ',
153               (renderable & EGL_OPENGL_ES2_BIT) ? 'y' : ' ',
154               (renderable & EGL_OPENGL_ES3_BIT) ? 'y' : ' ',
155               (renderable & EGL_OPENVG_BIT) ? 'y' : ' ',
156               surfString);
157
158   _eglLog(_EGL_DEBUG, printMsg);
159}
160
161void eglPrintConfigDebug(const _EGLDisplay *const disp,
162                         const EGLConfig *const configs,
163                         const EGLint numConfigs, const EGLBoolean printChosen)
164{
165   EGLint numConfigsToPrint;
166   _EGLConfig **configsToPrint;
167   _EGLConfig **chosenConfigs;
168
169   if (!numConfigs || !configs) {
170      _eglLog(_EGL_DEBUG, "%s: nothing to print", __func__);
171      return;
172   }
173
174   /*
175    * If the printout request came from the 'eglChooseConfig', all
176    * configs are printed, and the "chosen" configs are marked.
177    */
178   if (printChosen) {
179      configsToPrint = (_EGLConfig **) disp->Configs->Elements;
180      numConfigsToPrint = disp->Configs->Size;
181      chosenConfigs = (_EGLConfig **) configs;
182   } else {
183      configsToPrint = (_EGLConfig **) configs;
184      numConfigsToPrint = numConfigs;
185      chosenConfigs = NULL;
186   }
187
188   _printHeaderFormat();
189   for (EGLint i = 0; i < numConfigsToPrint; i++) {
190      _EGLConfig *configToPrint = configsToPrint[i];
191      EGLint chosenIndex = -1;
192
193      /* See if the current config to print is one of the chosen configs */
194      if (chosenConfigs)
195         for (EGLint j = 0; j < numConfigs; j++)
196            if (configToPrint == chosenConfigs[j])
197               chosenIndex = j;
198
199      _eglPrintConfig(configToPrint, chosenIndex);
200   }
201}
202