summaryrefslogtreecommitdiff
path: root/wrappers/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wrappers/config.cpp')
-rw-r--r--wrappers/config.cpp463
1 files changed, 463 insertions, 0 deletions
diff --git a/wrappers/config.cpp b/wrappers/config.cpp
new file mode 100644
index 00000000..dfdfafee
--- /dev/null
+++ b/wrappers/config.cpp
@@ -0,0 +1,463 @@
+/**************************************************************************
+ *
+ * Copyright 2015 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 THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ **************************************************************************/
+
+
+/*
+ * Configuration file support.
+ *
+ * Used to override glGetString/Integer/etc queries.
+ */
+
+
+/*
+ * The format of the file is extremely simple.
+ * Here's an example config file showing some variables:
+
+# comment line
+GL_VERSION = "2.0"
+GL_VENDOR = "Acme, Inc."
+GL_EXTENSIONS = "GL_EXT_texture_swizzle GL_ARB_multitexture"
+GL_RENDERER = "Acme rasterizer"
+GL_SHADING_LANGUAGE_VERSION = "1.30"
+GL_MAX_TEXTURE_SIZE = 1024
+
+ * Basically, override the glGetString() targets and the max 2D
+ * texture size. String values are contained inside "" pairs and may
+ * span multiple lines. Integer values are given without quotes.
+ *
+ * Future improvements:
+ * - An option to simply turn off specific extensions
+ *
+ */
+
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <iostream>
+
+#include "os.hpp"
+#include "config.hpp"
+
+
+static const char *DefaultConfigFilename = "gltrace.conf";
+
+
+namespace gltrace {
+
+
+/**
+ * Parse the conf->extensions string to generate an array of individual
+ * extension strings which can be queried with glGetStringi().
+ */
+static void
+create_extensions_list(configuration *conf)
+{
+ // count extensions
+ const char *ext = conf->extensions;
+ conf->numExtensions = 0;
+ while (1) {
+ ext = strstr(ext, "GL_");
+ if (!ext)
+ break;
+
+ conf->numExtensions++;
+ // advance extensions pointer
+ while (*ext && *ext != ' ')
+ ext++;
+ }
+
+ conf->extensionsList =
+ (char **) malloc(conf->numExtensions * sizeof(char *));
+
+ // extract individual extension names
+ int count = 0;
+ const char *extStart = conf->extensions, *extEnd;
+ while (1) {
+ extStart = strstr(extStart, "GL_");
+ if (!extStart)
+ break;
+
+ // find end of the name
+ extEnd = extStart;
+ while (*extEnd && *extEnd != ' ')
+ extEnd++;
+
+ // copy extension string name
+ int extLen = extEnd - extStart;
+ conf->extensionsList[count] = (char *) malloc(extLen + 1);
+ memcpy(conf->extensionsList[count], extStart, extLen);
+ conf->extensionsList[count][extLen] = 0;
+ count++;
+
+ // advance to next
+ extStart = extEnd;
+ }
+
+ assert(count == conf->numExtensions);
+}
+
+
+
+static bool
+matchKeyword(const char *string, const char *keyword)
+{
+ if (strncmp(string, keyword, strlen(keyword)) == 0)
+ return true;
+ else
+ return false;
+}
+
+
+static char buffer[10*1000];
+
+static char
+getChar(FILE *f, const char **buf)
+{
+ if (feof(f))
+ return 0;
+
+ if (buf[0][0]) {
+ char c = buf[0][0];
+ (*buf)++;
+ return c;
+ }
+
+ while (1) {
+ // read another line
+ *buf = fgets(buffer, sizeof(buffer), f);
+ if (!buf || !buf[0]) {
+ return 0;
+ }
+ else if (buf[0][0]) {
+ char c = buf[0][0];
+ (*buf)++;
+ return c;
+ }
+ else if (feof(f)) {
+ return 0;
+ }
+ }
+}
+
+
+// Scan 'buf' for a string value of the form: "string" (double-quoted string)
+// Return the string in newly malloc'd memory
+static char *
+stringValue(FILE *f, const char *buf)
+{
+ int resultLen = 100;
+ char *result = (char *) malloc(resultLen);
+ int outLen = 0;
+ char c;
+
+ // look for =
+ do {
+ c = getChar(f, &buf);
+ } while (c && c != '=');
+
+ if (!c)
+ return 0;
+
+ // look for opening "
+ do {
+ c = getChar(f, &buf);
+ } while (c && c != '\"');
+
+ if (!c)
+ return NULL;
+
+ // scan characters in the string
+ while (1) {
+ c = getChar(f, &buf);
+ if (!c) {
+ std::cerr << "Error: didn't find closing \" in config file!\n";
+ return NULL;
+ }
+
+ if (c == '\n') {
+ // convert newlines inside a string into spaces
+ c = ' ';
+ }
+
+ if (c == '\"') {
+ // end of string
+ result[outLen] = 0;
+ return result;
+ }
+ else if (outLen >= resultLen) {
+ // grow output buffer
+ resultLen *= 2;
+ result = (char *) realloc(result, resultLen);
+ result[outLen++] = c;
+ }
+ else {
+ result[outLen++] = c;
+ }
+ }
+}
+
+
+// Scan integer value of the form: 12345
+static int
+intValue(FILE *f, const char *buf)
+{
+ char valBuf[100];
+ int valLen = 0;
+ char c;
+
+ // look for =
+ do {
+ c = getChar(f, &buf);
+ } while (c && c != '=');
+
+ if (!c)
+ return 0;
+
+ // scan digits
+ while (1) {
+ c = getChar(f, &buf);
+ if (isdigit(c)) {
+ valBuf[valLen++] = c;
+ }
+ else if (c != ' ') {
+ break;
+ }
+ }
+
+ valBuf[valLen] = 0;
+
+ return atoi(valBuf);
+}
+
+
+
+static void
+parse_file(FILE *f, configuration *conf)
+{
+ do {
+ // read a line
+ char *b = fgets(buffer, sizeof(buffer), f);
+
+ if (!b) {
+ break;
+ }
+ else if (b[0] == '#') {
+ // comment - skip line
+ }
+ else if (b[0] == '\n') {
+ // empty line
+ }
+ else if (matchKeyword(b, "GL_VENDOR")) {
+ conf->vendor = stringValue(f, b + 10);
+ }
+ else if (matchKeyword(b, "GL_VERSION")) {
+ conf->version = stringValue(f, b + 11);
+ }
+ else if (matchKeyword(b, "GL_EXTENSIONS")) {
+ conf->extensions = stringValue(f, b + 14);
+ }
+ else if (matchKeyword(b, "GL_RENDERER")) {
+ conf->renderer = stringValue(f, b + 12);
+ }
+ else if (matchKeyword(b, "GL_SHADING_LANGUAGE_VERSION")) {
+ conf->glslVersion = stringValue(f, b + 28);
+ }
+ else if (matchKeyword(b, "GL_MAX_TEXTURE_SIZE")) {
+ conf->maxTextureSize = intValue(f, b + 20);
+ }
+ else if (matchKeyword(b, "GL_MAJOR_VERSION")) {
+ conf->versionMajor = intValue(f, b + 17);
+ }
+ else if (matchKeyword(b, "GL_MINOR_VERSION")) {
+ conf->versionMinor = intValue(f, b + 17);
+ }
+ else if (matchKeyword(b, "GL_CONTEXT_PROFILE_MASK")) {
+ char *maskStr = stringValue(f, b + 24);
+ conf->profileMask = 0x0;
+ if (strstr(maskStr, "GL_CONTEXT_CORE_PROFILE_BIT"))
+ conf->profileMask |= GL_CONTEXT_CORE_PROFILE_BIT;
+ if (strstr(maskStr, "GL_CONTEXT_COMPATIBILITY_PROFILE_BIT"))
+ conf->profileMask |= GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+ free(maskStr);
+ }
+ else {
+ std::cerr << "Unexpected config variable: " << b << ".\n";
+ break;
+ }
+ } while (!feof(f));
+
+ if (conf->version) {
+ // String version was specified, compute integer major/minor versions
+ conf->versionMajor = conf->version[0] - '0';
+ conf->versionMinor = conf->version[2] - '0';
+ assert(conf->versionMajor >= 1 && conf->versionMajor <= 4);
+ assert(conf->versionMinor >= 0 && conf->versionMinor <= 9);
+ }
+ else if (conf->versionMajor) {
+ // Numeric version was specified, update the string
+ if (conf->version) {
+ // if version string was specified too, override it
+ conf->version[0] = '0' + conf->versionMajor;
+ conf->version[2] = '0' + conf->versionMinor;
+ }
+ else {
+ // allocate new version string
+ conf->version = (char *) malloc(4);
+ assert(conf->version);
+ conf->version[0] = '0' + conf->versionMajor;
+ conf->version[1] = '.';
+ conf->version[2] = '0' + conf->versionMinor;
+ conf->version[3] = 0;
+ }
+ }
+
+ if (conf->extensions) {
+ create_extensions_list(conf);
+ }
+}
+
+
+// Read the given configuration file and return a new configuration object.
+// Return NULL if anything goes wrong
+static configuration *
+readConfigFile(const char *filename)
+{
+ FILE *f = fopen(filename, "r");
+ if (!f)
+ return NULL;
+
+ os::log("apitrace: using configuration file: %s\n", filename);
+
+ configuration *conf = new configuration;
+
+ memset(conf, 0, sizeof(*conf));
+
+ parse_file(f, conf);
+
+ fclose(f);
+
+ if (1) {
+ // debug
+ os::log("apitrace: config GL_VENDOR = %s\n", conf->vendor);
+ os::log("apitrace: config GL_VERSION = %s\n", conf->version);
+ os::log("apitrace: config GL_EXTENSIONS = %s\n", conf->extensions);
+ os::log("apitrace: config GL_NUM_EXTENSIONS = %d\n", conf->numExtensions);
+ os::log("apitrace: config GL_RENDERER = %s\n", conf->renderer);
+ os::log("apitrace: config GL_SHADING_LANGUAGE_VERSION = %s\n", conf->glslVersion);
+ os::log("apitrace: config GL_MAX_TEXTURE_SIZE = %d\n", conf->maxTextureSize);
+ os::log("apitrace: config GL_MAJOR_VERSION = %d\n", conf->versionMajor);
+ os::log("apitrace: config GL_MINOR_VERSION = %d\n", conf->versionMinor);
+ os::log("apitrace: config GL_CONTEXT_PROFILE_MASK = 0x%x\n", conf->profileMask);
+ }
+
+ return conf;
+}
+
+
+// Get pointer to configuration object or NULL if there was no config file.
+const configuration *
+getConfig(void)
+{
+ static bool configured = false;
+ static configuration *config = NULL;
+
+ if (!configured) {
+ config = gltrace::readConfigFile(DefaultConfigFilename);
+ configured = true;
+ }
+
+ return config;
+}
+
+
+// Return the named string value in the config object, or NULL.
+const GLubyte *
+getConfigString(const configuration *config, GLenum pname)
+{
+ if (!config)
+ return NULL;
+
+ switch (pname) {
+ case GL_VERSION:
+ return (const GLubyte *) config->version;
+ case GL_VENDOR:
+ return (const GLubyte *) config->vendor;
+ case GL_EXTENSIONS:
+ return (const GLubyte *) config->extensions;
+ case GL_RENDERER:
+ return (const GLubyte *) config->renderer;
+ case GL_SHADING_LANGUAGE_VERSION:
+ return (const GLubyte *) config->glslVersion;
+ default:
+ return NULL;
+ }
+}
+
+
+// Return named indexed string value from config object, or NULL.
+const GLubyte *
+getConfigStringi(const configuration *config, GLenum pname, GLuint index)
+{
+ if (!config ||
+ pname != GL_EXTENSIONS ||
+ !config->extensions ||
+ index >= config->numExtensions) {
+ return NULL;
+ }
+
+ return (const GLubyte *) config->extensionsList[index];
+}
+
+
+
+// Return named integer value from config object, or 0.
+GLint
+getConfigInteger(const configuration *config, GLenum pname)
+{
+ if (!config)
+ return 0;
+
+ switch (pname) {
+ case GL_MAJOR_VERSION:
+ return config->versionMajor;
+ case GL_MINOR_VERSION:
+ return config->versionMinor;
+ case GL_CONTEXT_PROFILE_MASK:
+ return config->profileMask;
+ case GL_MAX_TEXTURE_SIZE:
+ return config->maxTextureSize;
+ case GL_NUM_EXTENSIONS:
+ return config->numExtensions;
+ default:
+ return 0;
+ }
+}
+
+
+
+} /* namespace gltrace */