<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 6, 2016 at 2:06 PM, Emil Velikov <span dir="ltr"><<a href="mailto:emil.l.velikov@gmail.com" target="_blank">emil.l.velikov@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Dylan,<br>
<br>
Perhaps I'm not the best person to comment on the JSON side of things<br>
(esp since Frank sent related series a few hours ago), then again a<br>
few things, that might be interesting.<br>
<div><div class="h5"><br>
On 5 January 2016 at 19:46,  <<a href="mailto:baker.dylan.c@gmail.com">baker.dylan.c@gmail.com</a>> wrote:<br>
> From: Dylan Baker <<a href="mailto:baker.dylan.c@gmail.com">baker.dylan.c@gmail.com</a>><br>
><br>
> This adds some code to print a JSON formatted version of data provided<br>
> by wflinfo.<br>
><br>
> Signed-off-by: Dylan Baker <<a href="mailto:dylanx.c.baker@intel.com">dylanx.c.baker@intel.com</a>><br>
><br>
> v2: - Add -j short options (Frank)<br>
>     - Make context flags always an array (Chad)<br>
>     - Remove explicit returns from void functions (Chad)<br>
>     - Fix spaces around "*" in variable definitions<br>
>     - Nest waffle specific information in a waffle hash and OpenGL<br>
>       specific information in an OpenGL hash<br>
>     - use ARRAY_SIZE macro<br>
>     - rebase on previous changes<br>
> ---<br>
>  src/utils/wflinfo.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++-<br>
>  1 file changed, 176 insertions(+), 2 deletions(-)<br>
><br>
> diff --git a/src/utils/wflinfo.c b/src/utils/wflinfo.c<br>
> index 8ee95c6..456f91b 100644<br>
> --- a/src/utils/wflinfo.c<br>
> +++ b/src/utils/wflinfo.c<br>
> @@ -85,6 +85,9 @@ static const char *usage_message =<br>
>      "    --debug-context\n"<br>
>      "        Create a debug context.\n"<br>
>      "\n"<br>
> +    "    -j, --json\n"<br>
> +    "        Print a JSON formatted summary.\n"<br>
> +    "\n"<br>
>      "    -h, --help\n"<br>
>      "        Print wflinfo usage information.\n"<br>
>      "\n"<br>
> @@ -104,6 +107,7 @@ enum {<br>
>      OPT_VERBOSE = 'v',<br>
>      OPT_DEBUG_CONTEXT,<br>
>      OPT_FORWARD_COMPATIBLE,<br>
> +    OPT_JSON = 'j',<br>
>      OPT_HELP = 'h',<br>
>  };<br>
><br>
> @@ -115,6 +119,7 @@ static const struct option get_opts[] = {<br>
>      { .name = "verbose",        .has_arg = no_argument,           .val = OPT_VERBOSE },<br>
>      { .name = "debug-context",  .has_arg = no_argument,           .val = OPT_DEBUG_CONTEXT },<br>
>      { .name = "forward-compatible", .has_arg = no_argument,       .val = OPT_FORWARD_COMPATIBLE },<br>
> +    { .name = "json",           .has_arg = no_argument,           .val = OPT_JSON },<br>
>      { .name = "help",           .has_arg = no_argument,           .val = OPT_HELP },<br>
>      { 0 },<br>
>  };<br>
> @@ -252,6 +257,8 @@ struct options {<br>
><br>
>      bool verbose;<br>
><br>
> +    bool json;<br>
> +<br>
>      bool context_forward_compatible;<br>
>      bool context_debug;<br>
><br>
> @@ -337,7 +344,7 @@ parse_args(int argc, char *argv[], struct options *opts)<br>
>      opterr = 0;<br>
><br>
>      while (loop_get_opt) {<br>
> -        int opt = getopt_long(argc, argv, "a:hp:vV:", get_opts, NULL);<br>
> +        int opt = getopt_long(argc, argv, "a:hp:vV:j", get_opts, NULL);<br>
>          switch (opt) {<br>
>              case -1:<br>
>                  loop_get_opt = false;<br>
> @@ -395,6 +402,9 @@ parse_args(int argc, char *argv[], struct options *opts)<br>
>              case OPT_DEBUG_CONTEXT:<br>
>                  opts->context_debug = true;<br>
>                  break;<br>
> +            case OPT_JSON:<br>
> +                opts->json = true;<br>
> +                break;<br>
>              case OPT_HELP:<br>
>                  write_usage_and_exit(stdout, EXIT_SUCCESS);<br>
>                  break;<br>
> @@ -563,6 +573,165 @@ print_context_flags(void)<br>
>      printf("\n");<br>
>  }<br>
><br>
> +static void<br>
> +json_print_context_flags(void)<br>
> +{<br>
> +    const int flag_count = ARRAY_SIZE(context_flags);<br>
</div></div>const unsigned flag_count ?<br>
<span class=""><br>
> +    GLint gl_context_flags = 0;<br>
> +<br>
> +    printf("        \"context flags\": ");<br>
> +<br>
> +    glGetIntegerv(GL_CONTEXT_FLAGS, &gl_context_flags);<br>
> +    if (glGetError() != GL_NO_ERROR) {<br>
> +        printf("\"WFLINFO_GL_ERROR\"\n");<br>
> +        return;<br>
> +    }<br>
> +<br>
> +    if (gl_context_flags == 0) {<br>
> +        printf("[]");<br>
</span>Missing \n ?<br>
<span class=""><br></span></blockquote><div><br></div><div>Nope, gets covered later. This is a little odd to look at because that \n gets added later, because of the comma/no-comma madness that JSON enforces.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="">
> +        return;<br>
> +    }<br>
> +<br>
> +    printf("[\n");<br>
> +    for (int i = 0; i < flag_count; i++) {<br>
</span>unsigned i ?<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span class=""><br>
> +        if ((context_flags[i].flag & gl_context_flags) != 0) {<br>
> +            printf("        \"%s\"", context_flags[i].str);<br>
> +            gl_context_flags = gl_context_flags & ~context_flags[i].flag;<br>
> +            if (i != flag_count) {<br>
</span>This always evaluates to true, doesn't it ?<br></blockquote><div><br></div><div>Doesn't it evaluate to true in every case but the last iteration?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span class=""><br>
> +                printf(",\n");<br>
> +            }<br>
> +        }<br>
> +    }<br>
> +    for (int i = 0; gl_context_flags != 0; gl_context_flags >>= 1, i++) {<br>
> +        if ((gl_context_flags & 1) != 0) {<br>
> +            printf(",\n");<br>
</span>We'll get two consecutive ",\n" considering the one above ?<br></blockquote><div><br></div><div>nope, because you don't get ",\n" in the last iteration of the above loop.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span class=""><br>
> +            printf("        0x%x", 1 << i);<br>
</span>... and we're missing the \n for the last entry.<br>
<br>
Easier way might be to do "leading" \n's ?<br>
<span class=""><br>
> +        }<br>
> +    }<br>
> +    printf("    ]");<br>
> +}<br>
> +<br>
> +static void<br>
> +json_print_extensions(bool use_stringi)<br>
> +{<br>
> +    // Print extensions in JSON format<br>
> +    printf("        \"extensions\": [\n");<br>
> +    if (use_stringi) {<br>
> +        GLint count = 0, i;<br>
> +        const char *ext;<br>
> +<br>
> +        glGetIntegerv(GL_NUM_EXTENSIONS, &count);<br>
> +        if (glGetError() != GL_NO_ERROR) {<br>
> +            printf("\"WFLINFO_GL_ERROR\"");<br>
</span>Intentional difference in tabulation between previous function, here<br>
and else statement ?<br></blockquote><div><br></div><div>nope, I'll fix that.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span class=""><br>
> +        } else {<br>
> +            for (i = 0; i < count; i++) {<br>
> +                ext = (const char *) glGetStringi(GL_EXTENSIONS, i);<br>
> +                if (glGetError() != GL_NO_ERROR)<br>
> +                    ext = "WFLINFO_GL_ERROR";<br>
> +                printf("            \"%s\"%s\n", ext, (i + 1) < count ? "," : "");<br>
> +            }<br>
> +        }<br>
> +    } else {<br>
> +        char *extensions = (char *) glGetString(GL_EXTENSIONS);<br>
> +        if (glGetError() != GL_NO_ERROR) {<br>
> +            printf("            \"WFLINFO_GL_ERROR\"");<br>
> +        } else {<br>
> +            char *splitter = strtok(extensions, " ");<br>
> +<br>
</span>Note to self: do we care if a driver returns a single extension<br>
(and/or empty extensions string) ?<br>
<span class=""><br>
> +            // The JSON doesn't strictly need to be newline seperated, but<br>
> +            // it makes it much easier to read. Split the lines and add commas correctly<br>
> +            while(true) {<br>
> +                printf("       \"%s\"", splitter);<br>
> +                splitter = strtok(NULL, " ");<br>
> +<br>
> +                if (splitter != NULL) {<br>
> +                    printf(",\n");<br>
> +                } else {<br>
> +                    break;<br>
> +                }<br>
> +            }<br>
> +        }<br>
> +        printf("\n");<br>
> +    }<br>
> +    printf("        ]\n");<br>
> +}<br>
> +<br>
> +/// @brief Print JSON formatted OpenGL (ES) information<br>
> +static bool<br>
> +print_json(const struct options *opts)<br>
> +{<br>
> +    while(glGetError() != GL_NO_ERROR) {<br>
> +        /* Clear all errors */<br>
</span>Space between while and (... then again why the while loop ?<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div class="h5"><br>
> +    }<br>
> +<br>
> +    const char *vendor =  get_vendor();<br>
> +    const char *renderer = get_renderer();<br>
> +    const char *version_str = get_version();<br>
> +<br>
> +    const char *platform = enum_map_to_str(platform_map, opts->platform);<br>
> +    assert(platform != NULL);<br>
> +<br>
> +    const char *api = enum_map_to_str(context_api_map, opts->context_api);<br>
> +    assert(api != NULL);<br>
> +<br>
> +    printf("{\n");<br>
> +    printf("    \"waffle\": {\n");<br>
> +    printf("        \"platform\": \"%s\",\n", platform);<br>
> +    printf("        \"api\": \"%s\"\n", api);<br>
> +    printf("    },\n");<br>
> +    printf("    \"OpenGL\": {\n");<br>
> +    printf("        \"vendor\": \"%s\",\n", vendor);<br>
> +    printf("        \"renderer\": \"%s\",\n", renderer);<br>
> +    printf("        \"version\": \"%s\"", version_str);<br>
> +    // No comma is allowed on the last element.  If this context doesn't have<br>
> +    // context flags or verbose is not requested this will be the last element.<br>
> +<br>
> +    int version = parse_version(version_str);<br>
> +<br>
> +    if (opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 31) {<br>
> +        // Add the comma and newline before the context flags.<br>
> +        printf(",\n");<br>
> +        json_print_context_flags();<br>
> +    }<br>
> +<br>
> +    // OpenGL and OpenGL ES >= 3.0 support glGetStringi(GL_EXTENSION, i).<br>
> +    const bool use_getstringi = version >= 30;<br>
> +<br>
> +    if (!glGetStringi && use_getstringi)<br>
> +        error_get_gl_symbol("glGetStringi");<br>
> +<br>
> +    if (opts->verbose) {<br>
> +        // Add the command and newline<br>
> +        printf(",\n");<br>
> +<br>
> +        // See the equivalent section in print_wflinfo() for information about<br>
> +        // this hunk<br>
> +        const char *language_str = "None";<br>
> +        if ((opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 20) ||<br>
> +                opts->context_api == WAFFLE_CONTEXT_OPENGL_ES2 ||<br>
> +                opts->context_api == WAFFLE_CONTEXT_OPENGL_ES3) {<br>
</div></div>Align the last two ones - o (in opts) should be the same column as the (<br></blockquote><div><br></div><div>that looks like a readability nightmare:<br><br>if ((opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 20) ||<br>     opts->context_api == WAFFLE_CONTEXT_OPENGL_ES2 ||<br>     opts->context_api == WAFFLE_CONTEXT_OPENGL_ES3) {<br><span class="">     language_str = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);<br>     if (glGetError() != GL_NO_ERROR || language_str == NULL) {<br>          language_str = "WFLINFO_GL_ERROR";<br>     }<br>}</span><br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span class=""><br>
> +            language_str = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);<br>
> +            if (glGetError() != GL_NO_ERROR || language_str == NULL) {<br>
> +                language_str = "WFLINFO_GL_ERROR";<br>
> +            }<br>
> +        }<br>
> +<br>
> +        printf("        \"shading language version\": \"%s\",\n", language_str);<br>
> +<br>
> +        json_print_extensions(use_getstringi);<br>
> +<br>
> +    } else {<br>
> +        // If verbose isn't being used, add a newline so that the closing curly<br>
> +        // brace will be nicely formatted<br>
> +        printf("\n");<br>
> +    }<br>
> +<br>
> +    printf("    }\n");<br>
> +    printf("}\n");<br>
> +<br>
> +    return true;<br>
</span>Afaict you can make the function return void ?<br>
<br>
Seems that most (all?) of the comments here apply to the existing code<br>
in wflinfo.c where this was inspired/copied from. As mentioned by<br>
others - pondering on reusing the existing functions... I'll give it a<br>
quick test tomorrow.<br>
<br>
A bit tired so do take my comments with a grain of salt.<br>
<br>
That said (with or without the suggestions in 1 and 3) patches 1-3 are<br>
Reviewed-by: Emil Velikov <<a href="mailto:emil.velikov@collabora.com">emil.velikov@collabora.com</a>><br>
<span class=""><font color="#888888"><br>
-Emil<br>
</font></span></blockquote></div><br></div><div class="gmail_extra">I'll talk to Frank, but I think his series covers everything mine set out to do, if does, I'll just withdraw mine.<br></div></div>