diff --git a/LICENSES/BSD-2-Clause.txt b/LICENSES/BSD-2-Clause.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f662b354cd40cd5339d5aa05d74b15405138230 --- /dev/null +++ b/LICENSES/BSD-2-Clause.txt @@ -0,0 +1,9 @@ +Copyright (c) <year> <owner> + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/debian/control b/debian/control index c72e4b41e246614ee44ce028fa54ecd251b5deed..0c03a9433208fe685c09959097ed2e778cd3fd16 100644 --- a/debian/control +++ b/debian/control @@ -89,7 +89,6 @@ Section: misc Depends: ${misc:Depends}, ${shlibs:Depends}, - waffle-utils-multiarch, Description: The Steam Runtime is the library stack used to run the Steam client on Linux. The Steam Runtime Tools utility library contains open-source @@ -156,7 +155,6 @@ Architecture: amd64 Multi-Arch: foreign Depends: libsteam-runtime-tools-0-helpers, - waffle-utils-multiarch, ${misc:Depends}, ${shlibs:Depends}, Description: Steam container launcher - cross-architecture dependencies @@ -170,7 +168,6 @@ Architecture: i386 Multi-Arch: foreign Depends: libsteam-runtime-tools-0-helpers, - waffle-utils-multiarch, ${misc:Depends}, ${shlibs:Depends}, Description: Steam container launcher - cross-architecture dependencies diff --git a/debian/copyright b/debian/copyright index 456c93453ffe49c2679400f37132c1005f633cd6..77da1736fad23b71388a5d74a49d44dc9f3493b3 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,7 +1,7 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: Steam Runtime tools -License: Expat and Apache-2.0 and LGPL-2.1+ and Zlib -Comment: SPDX-License-Identifier: MIT and Apache-2.0 and LGPL-2.1-or-later and Zlib +License: BSD-2-clause and Expat and Apache-2.0 and LGPL-2.1+ and Zlib +Comment: SPDX-License-Identifier: BSD-2-Clause and MIT and Apache-2.0 and LGPL-2.1-or-later and Zlib Files: * @@ -35,6 +35,12 @@ Copyright: 2019-2021 Collabora Ltd. License: Apache-2.0 +Files: + helpers/wflinfo.c +Copyright: + 2014 Intel Corporation +License: BSD-2-clause + Files: subprojects/libcapsule/tests/CapsuleTestDpkg.pm Copyright: @@ -77,6 +83,30 @@ License: Autoconf-permissive permitted in any medium without royalty provided the copyright notice and this notice are preserved. +License: BSD-2-clause + All rights reserved. + . + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + . + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml index 75a3fe6a0a827ebb93e509dc7332939bf56bcaf0..c22aec7e8bddb2b446a4ad264f4bb821182b96f3 100644 --- a/debian/gitlab-ci.yml +++ b/debian/gitlab-ci.yml @@ -20,6 +20,7 @@ variables: libva-dev libvdpau-dev libvulkan-dev + libwaffle-dev libx11-dev libxau-dev libxcb1-dev diff --git a/debian/rules b/debian/rules index 345e306861a197e421a88ba5228e3919c9f48f05..a2eb8cc26c38d4d25e1183271700615de27e4c51 100755 --- a/debian/rules +++ b/debian/rules @@ -79,8 +79,6 @@ endif override_dh_auto_install: DESTDIR=$(DESTDIR) ninja -C _build install - ln -s ../../bin/$(DEB_HOST_MULTIARCH)-wflinfo \ - $(DESTDIR)/usr/$(pkglibexecdir)/ set -e; for x in $(DESTDIR)/usr/libexec/installed-tests/steam-runtime-tools-0/*; do \ if [ -f "$$x" ] \ && cmp -s "$$x" \ diff --git a/helpers/meson.build b/helpers/meson.build index 3fa747a03f682a51acfbd39501550126964c739c..403fbb499ca8929d3aefe94b36b55b227b4c9b6e 100644 --- a/helpers/meson.build +++ b/helpers/meson.build @@ -123,6 +123,19 @@ executable( ) ) +executable( + multiarch + '-wflinfo', + 'wflinfo.c', + c_args : silence_wflinfo_warnings, + dependencies : [waffle_dep], + include_directories : project_include_dirs, + install : true, + install_dir : pkglibexecdir, + # Use the adjacent libwaffle + build_rpath : pkglibexec_rpath, + install_rpath : pkglibexec_rpath, +) + executable( multiarch + '-check-xdg-portal', 'check-xdg-portal.c', diff --git a/helpers/wflinfo.c b/helpers/wflinfo.c new file mode 100644 index 0000000000000000000000000000000000000000..15c58c219396c54760b478e81deb62915c964431 --- /dev/null +++ b/helpers/wflinfo.c @@ -0,0 +1,1352 @@ +// Modified from waffle, last update: 1.7.0 +// Changes are marked with SRT.../SRT +// SPDX-License-Identifier: BSD-2-Clause +// +// Copyright 2014 Intel Corporation +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// @file +/// @brief Print OpenGL info using Waffle. +/// +/// This program does the following: +/// 1. Dynamically choose the platform and OpenGL API according to +/// command line arguments. +/// 2. Create an OpenGL context. +/// 3. Print information about the context. + +#define WAFFLE_API_VERSION 0x0106 + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef __APPLE__ +# import <Foundation/NSAutoreleasePool.h> +# import <AppKit/NSApplication.h> + +static void +removeXcodeArgs(int *argc, char **argv); +#endif + +#include "waffle.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static const char *usage_message = + "Usage:\n" + " wflinfo <Required Parameters> [Options]\n" + "\n" + "Description:\n" + " Create an OpenGL or OpenGL ES context and print information about it.\n" + "\n" + "Required Parameters:\n" + " -p, --platform <platform>\n" + " One of: android, cgl, gbm, glx, surfaceless_egl (or short\n" + " alias 'sl'), wayland, wgl, or x11_egl.\n" + "\n" + " -a, --api <api>\n" + " One of: gl, gles1, gles2 or gles3\n" + "\n" + "Options:\n" + " -V, --version <version>\n" + " For example --api=gl --version=3.2 would request OpenGL 3.2.\n" + "\n" + " --profile <profile>\n" + " One of: core, compat or none\n" + "\n" + " -v, --verbose\n" + " Print more information.\n" + "\n" + " --forward-compatible\n" + " Create a forward-compatible context.\n" + "\n" + " --debug-context\n" + " Create a debug context.\n" + "\n" + " -f, --format <format>\n" + " One of: original (default) or json.\n" + "\n" + " -h, --help\n" + " Print wflinfo usage information.\n" + "\n" + "Examples:\n" + " wflinfo --platform=glx --api=gl\n" + " wflinfo --platform=x11_egl --api=gl --version=3.2 --profile=core\n" + " wflinfo --platform=wayland --api=gles3\n" + " wflinfo --platform=gbm --api=gl --version=3.2 --verbose\n" + " wflinfo -p gbm -a gl -V 3.2 -v\n" + ; + +enum { + OPT_PLATFORM = 'p', + OPT_API = 'a', + OPT_VERSION = 'V', + OPT_PROFILE, + OPT_VERBOSE = 'v', + OPT_DEBUG_CONTEXT, + OPT_FORWARD_COMPATIBLE, + OPT_FORMAT = 'f', + OPT_HELP = 'h', +}; + +static const struct option get_opts[] = { + { .name = "platform", .has_arg = required_argument, .val = OPT_PLATFORM }, + { .name = "api", .has_arg = required_argument, .val = OPT_API }, + { .name = "version", .has_arg = required_argument, .val = OPT_VERSION }, + { .name = "profile", .has_arg = required_argument, .val = OPT_PROFILE }, + { .name = "verbose", .has_arg = no_argument, .val = OPT_VERBOSE }, + { .name = "debug-context", .has_arg = no_argument, .val = OPT_DEBUG_CONTEXT }, + { .name = "forward-compatible", .has_arg = no_argument, .val = OPT_FORWARD_COMPATIBLE }, + { .name = "format", .has_arg = required_argument, .val = OPT_FORMAT }, + { .name = "help", .has_arg = no_argument, .val = OPT_HELP }, + { 0 }, +}; + +static bool +strneq(const char *a, const char *b, size_t n) +{ + return strncmp(a, b, n) == 0; +} + +#if defined(__GNUC__) +#define NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define NORETURN __declspec(noreturn) +#else +#define NORETURN +#endif + +// SRT: https://gitlab.freedesktop.org/mesa/waffle/-/merge_requests/100 +// (Unmarked uses of PRINTFLIKE, below, are also changes) +#if defined(__GNUC__) +#define PRINTFLIKE(f, a) __attribute__((__format__(__printf__, f, a))) +#else +#define PRINTFLIKE(f, a) +#endif +// /SRT + +static void NORETURN +error_oom(void) +{ + fprintf(stderr, "out of memory\n"); + exit(EXIT_FAILURE); +} + +static void NORETURN PRINTFLIKE(2, 3) + error_printf(const char *module, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s error: ", module); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + + exit(EXIT_FAILURE); +} + +static void NORETURN +write_usage_and_exit(FILE *f, int exit_code) +{ + fprintf(f, "%s", usage_message); + exit(exit_code); +} + +static void NORETURN PRINTFLIKE(1, 2) usage_error_printf(const char *fmt, ...) +{ + fprintf(stderr, "Wflinfo usage error: "); + + if (fmt) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, " "); + } + + fprintf(stderr, "(see wflinfo --help)\n"); + exit(EXIT_FAILURE); +} + +// SRT: https://gitlab.freedesktop.org/mesa/waffle/-/merge_requests/100 +static void NORETURN +error_waffle(void) +{ + const struct waffle_error_info *info = waffle_error_get_info(); + const char *code = waffle_error_to_string(info->code); + + if (info->message_length > 0) + error_printf("Waffle", "0x%x %s: %s", info->code, code, info->message); + else + error_printf("Waffle", "0x%x %s", info->code, code); +} + +static void NORETURN +error_get_gl_symbol(const char *name) +{ + error_printf("Wflinfo", "failed to get function pointer for %s", name); +} +// /SRT + +typedef float GLclampf; +typedef unsigned int GLbitfield; +typedef unsigned int GLint; +typedef int GLsizei; +typedef unsigned int GLenum; +typedef void GLvoid; +typedef unsigned char GLubyte; + +enum { + // Copied from <GL/gl*.h>. + GL_NO_ERROR = 0, + + GL_CONTEXT_FLAGS = 0x821e, + GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001, + GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002, + GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB = 0x00000004, + + GL_VENDOR = 0x1F00, + GL_RENDERER = 0x1F01, + GL_VERSION = 0x1F02, + GL_EXTENSIONS = 0x1F03, + GL_NUM_EXTENSIONS = 0x821D, + GL_SHADING_LANGUAGE_VERSION = 0x8B8C, +}; + +#define WINDOW_WIDTH 320 +#define WINDOW_HEIGHT 240 + +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 + +#ifndef _WIN32 +#define APIENTRY +#else +#ifndef APIENTRY +#define APIENTRY __stdcall +#endif +#endif + +static GLenum (APIENTRY *glGetError)(void); +static void (APIENTRY *glGetIntegerv)(GLenum pname, GLint *params); +static const GLubyte * (APIENTRY *glGetString)(GLenum name); +static const GLubyte * (APIENTRY *glGetStringi)(GLenum name, GLint i); + +/// @brief Command line options. +struct options { + /// @brief One of `WAFFLE_PLATFORM_*`. + int platform; + + /// @brief One of `WAFFLE_CONTEXT_OPENGL_*`. + int context_api; + + /// @brief One of `WAFFLE_CONTEXT_PROFILE_*` or `WAFFLE_NONE`. + int context_profile; + + int context_major; + int context_minor; + + bool verbose; + + enum format { + FORMAT_ORIGINAL, + FORMAT_JSON, + } format; + + bool context_forward_compatible; + bool context_debug; + + /// @brief One of `WAFFLE_DL_*`. + int dl; +}; + +struct enum_map { + int i; + const char *s; +}; + +static const struct enum_map platform_map[] = { + {WAFFLE_PLATFORM_ANDROID, "android" }, + {WAFFLE_PLATFORM_CGL, "cgl", }, + {WAFFLE_PLATFORM_GBM, "gbm" }, + {WAFFLE_PLATFORM_GLX, "glx" }, + {WAFFLE_PLATFORM_WAYLAND, "wayland" }, + {WAFFLE_PLATFORM_WGL, "wgl" }, + {WAFFLE_PLATFORM_X11_EGL, "x11_egl" }, +// SRT: Make it possible to link with older waffle +#ifdef HAVE_WAFFLE_SURFACELESS_EGL + {WAFFLE_PLATFORM_SURFACELESS_EGL, "surfaceless_egl" }, + {WAFFLE_PLATFORM_SURFACELESS_EGL, "sl" }, +#endif +// /SRT + {0, 0 }, +}; + +static const struct enum_map context_api_map[] = { + {WAFFLE_CONTEXT_OPENGL, "gl" }, + {WAFFLE_CONTEXT_OPENGL_ES1, "gles1" }, + {WAFFLE_CONTEXT_OPENGL_ES2, "gles2" }, + {WAFFLE_CONTEXT_OPENGL_ES3, "gles3" }, + {0, 0 }, +}; + +/// @brief Translate string to `enum waffle_enum`. +/// +/// @param self is a list of map items. The last item must be zero-filled. +/// @param result is altered only if @a s if found. +/// @return true if @a s was found in @a map. +static bool +enum_map_translate_str( + const struct enum_map *self, + const char *s, + int *result) +{ + for (const struct enum_map *i = self; i->i != 0; ++i) { + if (!strncmp(s, i->s, strlen(i->s) + 1)) { + *result = i->i; + return true; + } + } + + return false; +} + +static const char * +enum_map_to_str(const struct enum_map *self, + int val) +{ + for (const struct enum_map *i = self; i->i != 0; ++i) { + if (i->i == val) { + return i->s; + } + } + + return NULL; +} + +/// @return true on success. +static bool +parse_args(int argc, char *argv[], struct options *opts) +{ + bool ok; + bool loop_get_opt = true; + +#ifdef __APPLE__ + removeXcodeArgs(&argc, argv); +#endif + + // Set options to default values. + opts->context_profile = WAFFLE_NONE; + opts->context_major = WAFFLE_DONT_CARE; + opts->context_minor = WAFFLE_DONT_CARE; + opts->format = FORMAT_ORIGINAL; + + // prevent getopt_long from printing an error message + opterr = 0; + + while (loop_get_opt) { + int opt = getopt_long(argc, argv, "a:f:hp:vV:", get_opts, NULL); + switch (opt) { + case -1: + loop_get_opt = false; + break; + case '?': + goto error_unrecognized_arg; + case OPT_PLATFORM: + ok = enum_map_translate_str(platform_map, optarg, + &opts->platform); + if (!ok) { + usage_error_printf("'%s' is not a valid platform", + optarg); + } + break; + case OPT_API: + ok = enum_map_translate_str(context_api_map, optarg, + &opts->context_api); + if (!ok) { + usage_error_printf("'%s' is not a valid API for an OpenGL " + "context", optarg); + } + break; + case OPT_VERSION: { + int major; + int minor; + int match_count; + + match_count = sscanf(optarg, "%d.%d", &major, &minor); + if (match_count != 2 || major < 0 || minor < 0) { + usage_error_printf("'%s' is not a valid OpenGL version", + optarg); + } + opts->context_major = major; + opts->context_minor = minor; + break; + } + case OPT_PROFILE: + if (strcmp(optarg, "none") == 0) { + opts->context_profile = WAFFLE_NONE; + } else if (strcmp(optarg, "core") == 0) { + opts->context_profile = WAFFLE_CONTEXT_CORE_PROFILE; + } else if (strcmp(optarg, "compat") == 0) { + opts->context_profile = WAFFLE_CONTEXT_COMPATIBILITY_PROFILE; + } else { + usage_error_printf("'%s' is not a valid OpenGL profile", + optarg); + } + break; + case OPT_FORMAT: + if (strcmp(optarg, "original") == 0) { + opts->format = FORMAT_ORIGINAL; + } else if (strcmp(optarg, "json") == 0) { + opts->format = FORMAT_JSON; + } else { + usage_error_printf("'%s' is not a valid format", optarg); + } + break; + case OPT_VERBOSE: + opts->verbose = true; + break; + case OPT_FORWARD_COMPATIBLE: + opts->context_forward_compatible = true; + break; + case OPT_DEBUG_CONTEXT: + opts->context_debug = true; + break; + case OPT_HELP: + write_usage_and_exit(stdout, EXIT_SUCCESS); + break; + default: + abort(); + loop_get_opt = false; + break; + } + } + + if (optind < argc) { + goto error_unrecognized_arg; + } + + if (!opts->platform) { + usage_error_printf("--platform is required"); + } + + if (!opts->context_api) { + usage_error_printf("--api is required"); + } + + // Set dl. + switch (opts->context_api) { + case WAFFLE_CONTEXT_OPENGL: opts->dl = WAFFLE_DL_OPENGL; break; + case WAFFLE_CONTEXT_OPENGL_ES1: opts->dl = WAFFLE_DL_OPENGL_ES1; break; + case WAFFLE_CONTEXT_OPENGL_ES2: opts->dl = WAFFLE_DL_OPENGL_ES2; break; + case WAFFLE_CONTEXT_OPENGL_ES3: opts->dl = WAFFLE_DL_OPENGL_ES3; break; + default: + abort(); + break; + } + + return true; + +error_unrecognized_arg: + if (optarg) + usage_error_printf("unrecognized option '%s'", optarg); + else if (optopt) + usage_error_printf("unrecognized option '-%c'", optopt); + else + usage_error_printf("unrecognized option"); +} + +static int +parse_version(const char *version) +{ + int count, major, minor; + + if (version == NULL) + return 0; + + while (*version != '\0' && !isdigit(*version)) + version++; + + count = sscanf(version, "%d.%d", &major, &minor); + if (count != 2) + return 0; + + if (minor > 9) + return 0; + + return (major * 10) + minor; +} + +static const char * +get_vendor(void) +{ + const char *vendor = (const char *) glGetString(GL_VENDOR); + if (glGetError() != GL_NO_ERROR || vendor == NULL) { + vendor = "WFLINFO_GL_ERROR"; + } + + return vendor; +} + +static const char * +get_renderer(void) +{ + const char *renderer = (const char *) glGetString(GL_RENDERER); + if (glGetError() != GL_NO_ERROR || renderer == NULL) { + renderer = "WFLINFO_GL_ERROR"; + } + + return renderer; +} + +static const char * +get_version(void) +{ + const char *version_str = (const char *) glGetString(GL_VERSION); + if (glGetError() != GL_NO_ERROR || version_str == NULL) { + version_str = "WFLINFO_GL_ERROR"; + } + + return version_str; +} + +static void +print_extensions(bool use_stringi) +{ + GLint count = 0, i; + const char *ext; + + printf("OpenGL extensions: "); + if (use_stringi) { + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + if (glGetError() != GL_NO_ERROR) { + printf("WFLINFO_GL_ERROR"); + } else { + for (i = 0; i < count; i++) { + ext = (const char *) glGetStringi(GL_EXTENSIONS, i); + if (glGetError() != GL_NO_ERROR) + ext = "WFLINFO_GL_ERROR"; + printf("%s%s", ext, (i + 1) < count ? " " : ""); + } + } + } else { + const char *extensions = (const char *) glGetString(GL_EXTENSIONS); + if (glGetError() != GL_NO_ERROR) + printf("WFLINFO_GL_ERROR"); + else + printf("%s", extensions); + } + printf("\n"); +} + +// SRT: https://gitlab.freedesktop.org/mesa/waffle/-/merge_requests/102 +static const struct { + GLint flag; + const char *str; +// /SRT +} context_flags[] = { + { GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT, "FORWARD_COMPATIBLE" }, + { GL_CONTEXT_FLAG_DEBUG_BIT, "DEBUG" }, + { GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB, "ROBUST_ACCESS" }, +}; + +static void +print_context_flags(void) +{ + GLint gl_context_flags = 0; + + printf("OpenGL context flags:"); + + glGetIntegerv(GL_CONTEXT_FLAGS, &gl_context_flags); + if (glGetError() != GL_NO_ERROR) { + printf(" WFLINFO_GL_ERROR\n"); + return; + } + +// SRT: https://gitlab.freedesktop.org/mesa/waffle/-/merge_requests/101 + if (gl_context_flags == 0) { + printf(" 0x0\n"); + return; + } +// /SRT + + for (int i = 0; i < ARRAY_SIZE(context_flags); i++) { + if ((context_flags[i].flag & gl_context_flags) != 0) { + printf(" %s", context_flags[i].str); + gl_context_flags = gl_context_flags & ~context_flags[i].flag; + } + } + for (int i = 0; gl_context_flags != 0; gl_context_flags >>= 1, i++) { + if ((gl_context_flags & 1) != 0) { + printf(" 0x%x", 1 << i); + } + } + printf("\n"); +} + +static void +json_print_extensions(bool use_stringi) +{ + // Print extensions in JSON format + printf(" \"extensions\": [\n"); + if (use_stringi) { + GLint count = 0; + const char *ext; + + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + if (glGetError() != GL_NO_ERROR) { + printf(" \"WFLINFO_GL_ERROR\""); + } else { + for (int i = 0; i < count; i++) { + ext = (const char *) glGetStringi(GL_EXTENSIONS, i); + if (glGetError() != GL_NO_ERROR) + ext = "WFLINFO_GL_ERROR"; + printf(" \"%s\"%s\n", ext, (i + 1) < count ? "," : ""); + } + } + } else { + const char *extensions = (const char *) glGetString(GL_EXTENSIONS); + + if (glGetError() != GL_NO_ERROR || !extensions) { + printf(" \"WFLINFO_GL_ERROR\""); + } else { + // Copy the string because strtok() is destructive. + char *splitter = strdup(extensions); + if (!splitter) + error_oom(); + + splitter = strtok(splitter, " "); + + // The JSON doesn't strictly need to be newline seperated, but it + // makes it much easier to read. Split the lines and add commas + // correctly. + while (splitter) { + printf(" \"%s\"", splitter); + splitter = strtok(NULL, " "); + if (splitter) { + printf(",\n"); + } + } + } + + printf("\n"); + } + + printf(" ]\n"); +} + +/// @brief Print JSON formatted OpenGL (ES) information +static bool +print_json(const struct options *opts) +{ + while (glGetError() != GL_NO_ERROR) { + /* Clear all errors */ + } + + const char *vendor = get_vendor(); + const char *renderer = get_renderer(); + const char *version_str = get_version(); + + const char *platform = enum_map_to_str(platform_map, opts->platform); + assert(platform != NULL); + + const char *api = enum_map_to_str(context_api_map, opts->context_api); + assert(api != NULL); + + // OpenGL and OpenGL ES >= 3.0 support glGetStringi(GL_EXTENSION, i). + const int version = parse_version(version_str); + const bool use_getstringi = version >= 30; + + if (!glGetStringi && use_getstringi) { + error_get_gl_symbol("glGetStringi"); + } + + // See the equivalent section in print_wflinfo() for more info + const char *language_str = "None"; + if ((opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 20) + || opts->context_api == WAFFLE_CONTEXT_OPENGL_ES2 + || opts->context_api == WAFFLE_CONTEXT_OPENGL_ES3) { + language_str = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); + if (glGetError() != GL_NO_ERROR || language_str == NULL) { + language_str = "WFLINFO_GL_ERROR"; + } + } + + printf("{\n"); + printf(" \"waffle\": {\n"); + printf(" \"platform\": \"%s\",\n", platform); + printf(" \"api\": \"%s\"\n", api); + printf(" },\n"); + printf(" \"OpenGL\": {\n"); + printf(" \"vendor string\": \"%s\",\n", vendor); + printf(" \"renderer string\": \"%s\",\n", renderer); + printf(" \"version string\": \"%s\",\n", version_str); + printf(" \"shading language version string\": \"%s\",\n", language_str); + + json_print_extensions(use_getstringi); + + printf(" }\n"); + printf("}\n"); + + return true; +} + +/// @brief Print out information about the context that was created. +static bool +print_wflinfo(const struct options *opts) +{ + while (glGetError() != GL_NO_ERROR) { + /* Clear all errors */ + } + + const char *vendor = get_vendor(); + const char *renderer = get_renderer(); + const char *version_str = get_version(); + + const char *platform = enum_map_to_str(platform_map, opts->platform); + assert(platform != NULL); + printf("Waffle platform: %s\n", platform); + + const char *api = enum_map_to_str(context_api_map, opts->context_api); + assert(api != NULL); + printf("Waffle api: %s\n", api); + + printf("OpenGL vendor string: %s\n", vendor); + printf("OpenGL renderer string: %s\n", renderer); + printf("OpenGL version string: %s\n", version_str); + + int version = parse_version(version_str); + + if (opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 31) { + print_context_flags(); + } + + // OpenGL and OpenGL ES >= 3.0 support glGetStringi(GL_EXTENSION, i). + const bool use_getstringi = version >= 30; + + if (!glGetStringi && use_getstringi) + error_get_gl_symbol("glGetStringi"); + + if (opts->verbose) { + // There are two exceptional cases where wflinfo may not get a + // version (or a valid version): one is in gles1 and the other + // is GL < 2.0. In these cases do not return WFLINFO_GL_ERROR, + // return None. This is preferable to returning WFLINFO_GL_ERROR + // because it creates a consistant interface for parsers + const char *language_str = "None"; + if ((opts->context_api == WAFFLE_CONTEXT_OPENGL && version >= 20) || + opts->context_api == WAFFLE_CONTEXT_OPENGL_ES2 || + opts->context_api == WAFFLE_CONTEXT_OPENGL_ES3) { + language_str = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); + if (glGetError() != GL_NO_ERROR || language_str == NULL) { + language_str = "WFLINFO_GL_ERROR"; + } + } + + printf("OpenGL shading language version string: %s\n", language_str); + print_extensions(use_getstringi); + } + + return true; +} + +#ifdef __APPLE__ + +static NSAutoreleasePool *pool; + +static void +cocoa_init(void) +{ + // From the NSApplication Class Reference: + // [...] if you do need to use Cocoa classes within the main() + // function itself (other than to load nib files or to instantiate + // NSApplication), you should create an autorelease pool before using + // the classes and then release the pool when you’re done. + pool = [[NSAutoreleasePool alloc] init]; + + // From the NSApplication Class Reference: + // The sharedApplication class method initializes the display + // environment and connects your program to the window server and the + // display server. + // + // It also creates the singleton NSApp if it does not yet exist. + [NSApplication sharedApplication]; +} + +static void +cocoa_finish(void) +{ + [pool drain]; +} + +static void +removeArg(int index, int *argc, char **argv) +{ + --*argc; + for (; index < *argc; ++index) + argv[index] = argv[index + 1]; +} + +static void +removeXcodeArgs(int *argc, char **argv) +{ + // Xcode sometimes adds additional arguments. + for (int i = 1; i < *argc; ) + { + if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0 || + strcmp(argv[i], "-ApplePersistenceIgnoreState" ) == 0) + { + removeArg(i, argc, argv); + removeArg(i, argc, argv); + } else + ++i; + } +} + +#endif // __APPLE__ + +/// @brief Attributes for waffle_choose_config(). +struct wflinfo_config_attrs { + /// @brief One of `WAFFLE_CONTEXT_OPENGL_*`. + enum waffle_enum api; + + /// @brief One of `WAFFLE_CONTEXT_PROFILE_*` or `WAFFLE_NONE`. + enum waffle_enum profile; + + /// @brief The version major number. + int32_t major; + + /// @brief The version minor number. + int32_t minor; + + /// @brief Create a forward-compatible context. + bool forward_compat; + + /// @brief Create a debug context. + bool debug; +}; + +static bool +wflinfo_try_create_context(struct waffle_display *dpy, + struct wflinfo_config_attrs attrs, + struct waffle_context **out_ctx, + struct waffle_config **out_config, + bool exit_on_fail) +{ + int i; + int32_t config_attrib_list[64]; + struct waffle_context *ctx = NULL; + struct waffle_config *config = NULL; + + i = 0; + config_attrib_list[i++] = WAFFLE_CONTEXT_API; + config_attrib_list[i++] = attrs.api; + + if (attrs.profile != WAFFLE_DONT_CARE) { + config_attrib_list[i++] = WAFFLE_CONTEXT_PROFILE; + config_attrib_list[i++] = attrs.profile; + } + + if (attrs.major != WAFFLE_DONT_CARE && attrs.minor != WAFFLE_DONT_CARE) { + config_attrib_list[i++] = WAFFLE_CONTEXT_MAJOR_VERSION; + config_attrib_list[i++] = attrs.major; + config_attrib_list[i++] = WAFFLE_CONTEXT_MINOR_VERSION; + config_attrib_list[i++] = attrs.minor; + } + + if (attrs.forward_compat) { + config_attrib_list[i++] = WAFFLE_CONTEXT_FORWARD_COMPATIBLE; + config_attrib_list[i++] = true; + } + + if (attrs.debug) { + config_attrib_list[i++] = WAFFLE_CONTEXT_DEBUG; + config_attrib_list[i++] = true; + } + + static int32_t dont_care_attribs[] = { + WAFFLE_RED_SIZE, + WAFFLE_GREEN_SIZE, + WAFFLE_BLUE_SIZE, + WAFFLE_ALPHA_SIZE, + WAFFLE_DEPTH_SIZE, + WAFFLE_STENCIL_SIZE, + WAFFLE_DOUBLE_BUFFERED, + }; + int dont_care_attribs_count = + sizeof(dont_care_attribs) / sizeof(dont_care_attribs[0]); + + for (int j = 0; j < dont_care_attribs_count; j++) { + config_attrib_list[i++] = dont_care_attribs[j]; + config_attrib_list[i++] = WAFFLE_DONT_CARE; + } + + config_attrib_list[i++] = 0; + + config = waffle_config_choose(dpy, config_attrib_list); + if (!config) { + goto fail; + } + + ctx = waffle_context_create(config, NULL); + if (!ctx) { + goto fail; + } + + *out_ctx = ctx; + *out_config = config; + return true; + +fail: + if (exit_on_fail) { + error_waffle(); + } + if (ctx) { + waffle_context_destroy(ctx); + } + if (config) { + waffle_config_destroy(config); + } + + return false; +} + +/// @brief Return 10 * version of the current OpenGL context. +static int +gl_get_version(void) +{ + GLint major_version = 0; + GLint minor_version = 0; + + glGetIntegerv(GL_MAJOR_VERSION, &major_version); + if (glGetError()) { + error_printf("Wflinfo", "glGetIntegerv(GL_MAJOR_VERSION) failed"); + } + + glGetIntegerv(GL_MINOR_VERSION, &minor_version); + if (glGetError()) { + error_printf("Wflinfo", "glGetIntegerv(GL_MINOR_VERSION) failed"); + } + return 10 * major_version + minor_version; +} + +/// @brief Check if current context has an extension using glGetString(). +static bool +gl_has_extension_GetString(const char *name) +{ +#define BUF_LEN 4096 + char exts[BUF_LEN]; + + const uint8_t *exts_orig = glGetString(GL_EXTENSIONS); + if (glGetError()) { + error_printf("Wflinfo", "glGetInteger(GL_EXTENSIONS) failed"); + } + + memcpy(exts, exts_orig, BUF_LEN); + exts[BUF_LEN - 1] = 0; + + char *ext = strtok(exts, " "); + do { + if (strneq(ext, name, BUF_LEN)) { + return true; + } + ext = strtok(NULL, " "); + } while (ext); + + return false; +#undef BUF_LEN +} + +/// @brief Check if current context has an extension using glGetStringi(). +static bool +gl_has_extension_GetStringi(const char *name) +{ + const size_t max_ext_len = 128; + uint32_t num_exts = 0; + + glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts); + if (glGetError()) { + error_printf("Wflinfo", "glGetIntegerv(GL_NUM_EXTENSIONS) failed"); + } + + for (uint32_t i = 0; i < num_exts; i++) { + const uint8_t *ext = glGetStringi(GL_EXTENSIONS, i); + if (!ext || glGetError()) { + error_printf("Wflinfo", "glGetStringi(GL_EXTENSIONS) failed"); + } else if (strneq((const char*) ext, name, max_ext_len)) { + return true; + } + } + + return false; +} + +/// @brief Check if current context has an extension. +static bool +gl_has_extension(const char *name) +{ + // Use the new glGetStringi when possible. + // + // Due to the funky semantics of obtaining the function pointer, we can + // get here, even when it is NULL. + if (glGetStringi && gl_get_version() >= 30) { + return gl_has_extension_GetStringi(name); + } else { + return gl_has_extension_GetString(name); + } +} + +/// @brief Get the profile of a desktop OpenGL context. +/// +/// Return one of WAFFLE_CONTEXT_CORE_PROFILE, +/// WAFFLE_CONTEXT_COMPATIBILITY_PROFILE, or WAFFLE_NONE. +/// +/// Even though an OpenGL 3.1 context strictly has no profile, according to +/// this function a 3.1 context belongs to the core profile if and only if it +/// lacks the GL_ARB_compatibility extension. +/// +/// According to this function, a context has no profile if and only if its +/// version is 3.0 or lower. +static enum waffle_enum +gl_get_profile(void) +{ + int version = gl_get_version(); + + if (version >= 32) { + uint32_t profile_mask = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile_mask); + if (glGetError()) { + error_printf("Wflinfo", "glGetIntegerv(GL_CONTEXT_PROFILE_MASK) " + "failed"); + } else if (profile_mask & GL_CONTEXT_CORE_PROFILE_BIT) { + return WAFFLE_CONTEXT_CORE_PROFILE; + } else if (profile_mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) { + return WAFFLE_CONTEXT_COMPATIBILITY_PROFILE; + } else { + error_printf("Wflinfo", "glGetIntegerv(GL_CONTEXT_PROFILE_MASK) " + "return a mask with no profile bit: 0x%x", + profile_mask); + } + } else if (version == 31) { + if (gl_has_extension("GL_ARB_compatibility")) { + return WAFFLE_CONTEXT_CORE_PROFILE; + } else { + return WAFFLE_CONTEXT_COMPATIBILITY_PROFILE; + } + } else { + return WAFFLE_NONE; + } +} + +/// @brief Create an OpenGL >= 3.1 context. +/// +/// If the requested profile is WAFFLE_NONE or WAFFLE_DONT_CARE and context +/// creation succeeds, then return true. +/// +/// If a specific profile of OpenGL 3.1 is requested, then this function tries +/// to honor the intent of that request even though, strictly speaking, an +/// OpenGL 3.1 context has no profile. (See gl_get_profile() for a description +/// of how wflinfo determines the profile of a context). If context creation +/// succeeds but its profile is incorrect, then return false. +/// +/// On failure, @a out_ctx and @out_config remain unmodified. +/// +static bool +wflinfo_try_create_context_gl31(struct waffle_display *dpy, + struct wflinfo_config_attrs attrs, + struct waffle_context **out_ctx, + struct waffle_config **out_config, + bool exit_if_ctx_creation_fails) +{ + struct waffle_config *config = NULL; + struct waffle_context *ctx = NULL; + bool ok; + + // It's illegal to request a waffle_config with WAFFLE_CONTEXT_PROFILE + // != WAFFLE_NONE. Therefore, request an OpenGL 3.1 config without + // a profile and later verify that the desired and actual profile + // agree. + const enum waffle_enum desired_profile = attrs.profile; + attrs.major = 3; + attrs.minor = 1; + attrs.profile = WAFFLE_NONE; + wflinfo_try_create_context(dpy, attrs, &ctx, &config, + exit_if_ctx_creation_fails); + + if (desired_profile == WAFFLE_NONE || + desired_profile == WAFFLE_DONT_CARE) { + goto success; + } + + // The user cares about the profile. We must bind the context to inspect + // its profile. + // + // Skip window creation. No window is needed when binding an OpenGL >= 3.0 + // context. + ok = waffle_make_current(dpy, NULL, ctx); + if (!ok) { + error_waffle(); + } + + const enum waffle_enum actual_profile = gl_get_profile(); + waffle_make_current(dpy, NULL, NULL); + if (actual_profile == desired_profile) { + goto success; + } + + return false; + +success: + *out_ctx = ctx; + *out_config = config; + return true; +} + +/// Exit on failure. +static void +wflinfo_create_context(struct waffle_display *dpy, + struct wflinfo_config_attrs attrs, + struct waffle_context **out_ctx, + struct waffle_config **out_config) +{ + bool ok = false; + + if (attrs.api == WAFFLE_CONTEXT_OPENGL && + attrs.profile != WAFFLE_NONE && + attrs.major == WAFFLE_DONT_CARE) { + + // If the user requested OpenGL and a CORE or COMPAT profile, + // but they didn't specify a version, then we'll try a set + // of known versions from highest to lowest. + + static int known_gl_profile_versions[] = + { 32, 33, 40, 41, 42, 43, 44 }; + + for (int i = ARRAY_SIZE(known_gl_profile_versions) - 1; i >= 0; i--) { + attrs.major = known_gl_profile_versions[i] / 10; + attrs.minor = known_gl_profile_versions[i] % 10; + ok = wflinfo_try_create_context(dpy, attrs, + out_ctx, out_config, false); + if (ok) { + return; + } + } + + // Handle OpenGL 3.1 separately because profiles are weird in 3.1. + ok = wflinfo_try_create_context_gl31( + dpy, attrs, out_ctx, out_config, + /*exit_if_ctx_creation_fails*/ false); + if (ok) { + return; + } + + error_printf("Wflinfo", "Failed to create context; Try choosing a " + "specific context version with --version"); + } else if (attrs.api == WAFFLE_CONTEXT_OPENGL && + attrs.major == 3 && + attrs.minor == 1) { + // The user requested a specific profile of an OpenGL 3.1 context. + // Strictly speaking, an OpenGL 3.1 context has no profile, but let's + // do what the user wants. + ok = wflinfo_try_create_context_gl31( + dpy, attrs, out_ctx, out_config, + /*exit_if_ctx_creation_fails*/ true); + if (ok) { + return; + } + + printf("Wflinfo warn: Successfully requested an OpenGL 3.1 context, but returned\n" + "Wflinfo warn: context had the wrong profile. Fallback to requesting an\n" + "Wflinfo warn: OpenGL 3.2 context, which is guaranteed to have the correct\n" + "Wflinfo warn: profile if context creation succeeds.\n"); + attrs.major = 3; + attrs.minor = 2; + assert(attrs.profile == WAFFLE_CONTEXT_CORE_PROFILE || + attrs.profile == WAFFLE_CONTEXT_COMPATIBILITY_PROFILE); + ok = wflinfo_try_create_context(dpy, attrs, out_ctx, out_config, + /*exit_on_fail*/ false); + if (ok) { + return; + } + + error_printf("Wflinfo", "Failed to create an OpenGL 3.1 or later " + "context with requested profile"); + } else { + wflinfo_try_create_context(dpy, attrs, out_ctx, out_config, + /*exit_on_fail*/ true); + } +} + +int +main(int argc, char **argv) +{ + bool ok; + int i; + + struct options opts = {0}; + + int32_t init_attrib_list[3]; + + struct waffle_display *dpy; + struct waffle_config *config; + struct waffle_context *ctx; + struct waffle_window *window; + + #ifdef __APPLE__ + cocoa_init(); + #endif + + ok = parse_args(argc, argv, &opts); + if (!ok) + exit(EXIT_FAILURE); + + i = 0; + init_attrib_list[i++] = WAFFLE_PLATFORM; + init_attrib_list[i++] = opts.platform; + init_attrib_list[i++] = WAFFLE_NONE; + + ok = waffle_init(init_attrib_list); + if (!ok) + error_waffle(); + + dpy = waffle_display_connect(NULL); + if (!dpy) + error_waffle(); + + if (!waffle_display_supports_context_api(dpy, opts.context_api)) { + error_printf("Wflinfo", "Display does not support %s", + waffle_enum_to_string(opts.context_api)); + } + + glGetError = waffle_dl_sym(opts.dl, "glGetError"); + if (!glGetError) + error_get_gl_symbol("glGetError"); + + glGetIntegerv = waffle_dl_sym(opts.dl, "glGetIntegerv"); + if (!glGetIntegerv) + error_get_gl_symbol("glGetIntegerv"); + + glGetString = waffle_dl_sym(opts.dl, "glGetString"); + if (!glGetString) { + error_get_gl_symbol("glGetString"); + } + + const struct wflinfo_config_attrs config_attrs = { + .api = opts.context_api, + .profile = opts.context_profile, + .major = opts.context_major, + .minor = opts.context_minor, + .forward_compat = opts.context_forward_compatible, + .debug = opts.context_debug, + }; + + wflinfo_create_context(dpy, config_attrs, &ctx, &config); + + window = waffle_window_create(config, WINDOW_WIDTH, WINDOW_HEIGHT); + if (!window) + error_waffle(); + + ok = waffle_make_current(dpy, window, ctx); + if (!ok) + error_waffle(); + + // Retrieving GL functions is tricky. When glGetStringi is supported, here + // are some boggling variations as of 2014-11-19: + // - Mali drivers on EGL 1.4 expose glGetStringi statically from + // libGLESv2 but not dynamically from eglGetProcAddress. The EGL 1.4 spec + // permits this behavior. + // - EGL 1.5 requires that eglGetStringi be exposed dynamically through + // eglGetProcAddress. Exposing statically with dlsym is optional. + // - Windows requires that glGetStringi be exposed dynamically from + // wglGetProcAddress. Exposing statically from GetProcAddress (Window's + // dlsym equivalent) is optional. + // - Mesa drivers expose glGetStringi statically from libGL and libGLESv2 + // and dynamically from eglGetProcAddress and glxGetProcAddress. + // - Mac exposes glGetStringi only statically. + // + // Try waffle_dl_sym before waffle_get_proc_address because + // (1) egl/glXProcAddress can return invalid non-null pointers for + // unsupported functions and (2) dlsym returns non-null if and only if the + // library exposes the symbol. + glGetStringi = waffle_dl_sym(opts.dl, "glGetStringi"); + if (!glGetStringi) { + glGetStringi = waffle_get_proc_address("glGetStringi"); + } + + switch (opts.format) { + case FORMAT_ORIGINAL: + ok = print_wflinfo(&opts); + break; + case FORMAT_JSON: + ok = print_json(&opts); + break; + } + + if (!ok) + error_waffle(); + + ok = waffle_make_current(dpy, NULL, NULL); + if (!ok) + error_waffle(); + + ok = waffle_window_destroy(window); + if (!ok) + error_waffle(); + + ok = waffle_context_destroy(ctx); + if (!ok) + error_waffle(); + + ok = waffle_config_destroy(config); + if (!ok) + error_waffle(); + + ok = waffle_display_disconnect(dpy); + if (!ok) + error_waffle(); + +// SRT: Make it possible to link with older waffle +#ifdef HAVE_WAFFLE_TEARDOWN + ok = waffle_teardown(); + if (!ok) + error_waffle(); +#endif +// /SRT + + #ifdef __APPLE__ + cocoa_finish(); + #endif + + return EXIT_SUCCESS; +} diff --git a/meson.build b/meson.build index eb9910513e69d3ce1558c5fa7c863b24ee114281..d9ffe89c148789aef7cd210b4d5c62111b9120a3 100644 --- a/meson.build +++ b/meson.build @@ -169,6 +169,14 @@ silence_gdbus_codegen_warnings = c_compiler.get_supported_arguments([ '-Wno-write-strings', ]) +# Our vendored copy of wflinfo is not completely warnings-clean either +silence_wflinfo_warnings = c_compiler.get_supported_arguments([ + '-Wno-error=jump-misses-init', + '-Wno-error=switch-default', + '-Wno-jump-misses-init', + '-Wno-switch-default', +]) + add_project_link_arguments( c_compiler.get_supported_link_arguments( '-Wl,-z,origin', @@ -198,6 +206,10 @@ if not libcap_dep.found() ) endif +waffle_dep = dependency( + 'waffle-1', +) + conf_data = configuration_data() conf_data.set_quoted('VERSION', version) conf_data.set('HAVE_SELINUX', libselinux_dep.found()) @@ -207,6 +219,14 @@ conf_data.set( ) conf_data.set('api_major', api_major) conf_data.set('abi_major', abi_major) +conf_data.set( + 'HAVE_WAFFLE_SURFACELESS_EGL', + waffle_dep.found() and waffle_dep.version().version_compare('>=1.6'), +) +conf_data.set( + 'HAVE_WAFFLE_TEARDOWN', + waffle_dep.found() and waffle_dep.version().version_compare('>=1.6'), +) if get_option('multiarch_tuple') != '' multiarch = get_option('multiarch_tuple') diff --git a/pressure-vessel/THIRD-PARTY.md b/pressure-vessel/THIRD-PARTY.md index 37cb96436955ef611096320c1337faf633b22573..52ce3caab1a241cef245ed1549d16b169fe7e50b 100644 --- a/pressure-vessel/THIRD-PARTY.md +++ b/pressure-vessel/THIRD-PARTY.md @@ -28,10 +28,11 @@ same place as pressure-vessel, or from <https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/>. pressure-vessel includes the steam-runtime-tools library and utilities, -which contain code licensed under the [Apache-2.0][], [LGPL-2.1-or-later][] -and [MIT][] licenses. See steam-runtime-tools.txt. -Complete source code can be obtained from the same place as pressure-vessel, -or from <https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/>. +which contain code licensed under the [Apache-2.0][], [BSD-2-Clause][], +[LGPL-2.1-or-later][], [MIT][] and [Zlib][] licenses. See +steam-runtime-tools.txt. Complete source code can be obtained from the +same place as pressure-vessel, or from +<https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/>. Binary releases of pressure-vessel include the following third-party programs and libraries: @@ -65,7 +66,7 @@ programs and libraries: - libjson-glib-1.0.so.0 from json-glib: [LGPL-2.0-or-later][]. See json-glib.txt. -- wflinfo from waffle: [BSD-2-clause][]. See waffle.txt. +- libwaffle-1.so.0 from waffle: [BSD-2-Clause][]. See waffle.txt. Complete source code can be obtained from the same place as pressure-vessel, or from <https://repo.steampowered.com/steamrt/> diff --git a/pressure-vessel/build-relocatable-install.py b/pressure-vessel/build-relocatable-install.py index 28bd263cc9e57d35f2dee9ca29b991e695f1c05a..973c03a320f1bf3b3c16baed43ad4db4a38489f9 100755 --- a/pressure-vessel/build-relocatable-install.py +++ b/pressure-vessel/build-relocatable-install.py @@ -78,7 +78,7 @@ ARCHS = [ # package to install from => source package for copyright information DEPENDENCIES = { 'libelf1': 'elfutils', - 'waffle-utils-multiarch': 'waffle', + 'libwaffle-1-0': 'waffle', 'zlib1g': 'zlib', } # same as DEPENDENCIES @@ -93,10 +93,6 @@ PRIMARY_ARCH_DEPENDENCIES = { 'libselinux1': 'libselinux', 'libxau6': 'libxau', } -# executable => binary package in DEPENDENCIES -HELPERS = { - 'wflinfo': 'waffle-utils-multiarch', -} # Packages where different binary packages can have different copyright # files DIFFERENT_COPYRIGHT_FILES = [ @@ -365,6 +361,7 @@ def main(): ), '--no-glibc', 'soname:libelf.so.1', + 'soname:libwaffle-1.so.0', 'soname:libz.so.1', ]) @@ -423,35 +420,6 @@ def main(): ) ) - for helper, package in HELPERS.items(): - exe = arch.multiarch + '-' + helper - path = os.path.join(args.prefix, 'bin', exe) - - if not os.path.exists(path): - path = '/usr/bin/{}'.format(exe) - - if not os.path.exists(path): - v_check_call([ - 'apt-get', - 'download', - package, - ], cwd=tmpdir) - v_check_call( - 'dpkg-deb -x {}_*.deb build-relocatable'.format( - quote(package), - ), - cwd=tmpdir, - shell=True, - ) - path = '{}/build-relocatable/usr/bin/{}'.format( - tmpdir, exe, - ) - - install_exe( - path, - os.path.join(inst_pkglibexecdir, exe) - ) - source_to_download = set() # type: typing.Set[str] installed_binaries = set() # type: typing.Set[str] diff --git a/steam-runtime-tools/utils.c b/steam-runtime-tools/utils.c index 074d158acbc7a8564ee28f49227dbcb2c18ffc08..ab8082e09948789d8ca1fbdbf01400ce8cef69e8 100644 --- a/steam-runtime-tools/utils.c +++ b/steam-runtime-tools/utils.c @@ -398,8 +398,8 @@ _srt_get_helper (const char *helpers_path, return NULL; } - /* For helpers that are not part of steam-runtime-tools, such as - * *-wflinfo, we fall back to searching $PATH */ + /* For helpers that are not part of steam-runtime-tools + * (historically this included *-wflinfo), we fall back to searching $PATH */ g_free (path); if (multiarch == NULL)