diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 8b11e7647..1e39005fd 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -181,6 +181,8 @@ cogl_sources_c = \ $(srcdir)/cogl-private.h \ $(srcdir)/cogl-debug.h \ $(srcdir)/cogl-debug-options.h \ + $(srcdir)/cogl-gpu-info.c \ + $(srcdir)/cogl-gpu-info-private.h \ $(srcdir)/cogl-handle.h \ $(srcdir)/cogl-context-private.h \ $(srcdir)/cogl-context.c \ diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index ccc5b6d24..333235bb4 100644 --- a/cogl/cogl-context-private.h +++ b/cogl/cogl-context-private.h @@ -48,6 +48,7 @@ #include "cogl-texture-3d.h" #include "cogl-texture-rectangle.h" #include "cogl-sampler-cache-private.h" +#include "cogl-gpu-info-private.h" typedef struct { @@ -64,6 +65,10 @@ struct _CoglContext CoglDriver driver; + /* Information about the GPU and driver which we can use to + determine certain workarounds */ + CoglGpuInfo gpu; + /* vtables for the driver functions */ const CoglDriverVtable *driver_vtable; const CoglTextureDriver *texture_driver; diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 930f4b83b..c15e2db17 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -47,6 +47,7 @@ #include "cogl2-path.h" #include "cogl-attribute-private.h" #include "cogl1-context.h" +#include "cogl-gpu-info-private.h" #include @@ -234,6 +235,8 @@ cogl_context_new (CoglDisplay *display, return NULL; } + _cogl_gpu_info_init (context, &context->gpu); + context->attribute_name_states_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); context->attribute_name_index_map = NULL; diff --git a/cogl/cogl-gpu-info-private.h b/cogl/cogl-gpu-info-private.h new file mode 100644 index 000000000..2930d6bd1 --- /dev/null +++ b/cogl/cogl-gpu-info-private.h @@ -0,0 +1,74 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifndef __COGL_GPU_INFO_PRIVATE_H +#define __COGL_GPU_INFO_PRIVATE_H + +#include "cogl-context.h" + +typedef enum +{ + COGL_GPU_INFO_VENDOR_UNKNOWN, + COGL_GPU_INFO_VENDOR_INTEL +} CoglGpuInfoVendor; + +typedef enum +{ + COGL_GPU_INFO_DRIVER_PACKAGE_UNKNOWN, + COGL_GPU_INFO_DRIVER_PACKAGE_MESA +} CoglGpuInfoDriverPackage; + +typedef enum +{ + COGL_GPU_INFO_DRIVER_STUB +} CoglGpuInfoDriverBug; + +typedef struct _CoglGpuInfoVersion CoglGpuInfoVersion; + +typedef struct _CoglGpuInfo CoglGpuInfo; + +struct _CoglGpuInfo +{ + CoglGpuInfoVendor vendor; + const char *vendor_name; + + CoglGpuInfoDriverPackage driver_package; + const char *driver_package_name; + int driver_package_version; + + CoglGpuInfoDriverBug driver_bugs; +}; + +/* + * _cogl_gpu_info_init: + * @ctx: A #CoglContext + * @gpu: A return location for the GPU information + * + * Determines information about the GPU and driver from the given + * context. + */ +void +_cogl_gpu_info_init (CoglContext *ctx, + CoglGpuInfo *gpu); + +#endif /* __COGL_GPU_INFO_PRIVATE_H */ diff --git a/cogl/cogl-gpu-info.c b/cogl/cogl-gpu-info.c new file mode 100644 index 000000000..f62bbc330 --- /dev/null +++ b/cogl/cogl-gpu-info.c @@ -0,0 +1,254 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "cogl-gpu-info-private.h" +#include "cogl-context-private.h" +#include "cogl-util.h" + +typedef struct +{ + const char *renderer_string; + const char *version_string; + const char *vendor_string; +} CoglGpuInfoStrings; + +typedef struct +{ + CoglGpuInfoVendor vendor; + const char *name; + gboolean (* check_function) (const CoglGpuInfoStrings *strings); +} CoglGpuInfoVendorDescription; + +typedef struct +{ + CoglGpuInfoDriverPackage driver_package; + const char *name; + gboolean (* check_function) (const CoglGpuInfoStrings *strings, + int *version_out); +} CoglGpuInfoDriverPackageDescription; + +static gboolean +_cogl_gpu_info_parse_version_string (const char *version_string, + int n_components, + const char **tail, + int *version_ret) +{ + int version = 0; + guint64 part; + int i; + + for (i = 0; ; i++) + { + errno = 0; + part = g_ascii_strtoull (version_string, + (char **) &version_string, + 10); + + if (errno || part > COGL_VERSION_MAX_COMPONENT_VALUE) + return FALSE; + + version |= part << ((2 - i) * COGL_VERSION_COMPONENT_BITS); + + if (i + 1 >= n_components) + break; + + if (*version_string != '.') + return FALSE; + + version_string++; + } + + if (version_ret) + *version_ret = version; + if (tail) + *tail = version_string; + + return TRUE; +} + +static gboolean +check_intel_vendor (const CoglGpuInfoStrings *strings) +{ + const char *intel_part = strstr (strings->renderer_string, "Intel(R)"); + + if (intel_part == NULL) + return FALSE; + + /* The match must either be at the beginning of the string or + preceded by a space. Just in case there's a company called + IAmNotIntel (R) or something */ + if (intel_part > strings->renderer_string && intel_part[-1] != ' ') + return FALSE; + + return TRUE; +} + +static gboolean +check_unknown_vendor (const CoglGpuInfoStrings *strings) +{ + /* This is a last resort so it always matches */ + return TRUE; +} + +static const CoglGpuInfoVendorDescription +_cogl_gpu_info_vendors[] = + { + { + COGL_GPU_INFO_VENDOR_INTEL, + "Intel", + check_intel_vendor + }, + /* Must be last */ + { + COGL_GPU_INFO_VENDOR_UNKNOWN, + "Unknown", + check_unknown_vendor + } + }; + +static gboolean +check_mesa_driver_package (const CoglGpuInfoStrings *strings, + int *version_ret) +{ + guint64 micro_part; + const char *v; + + /* The version string should always begin a two-part GL version + number */ + if (!_cogl_gpu_info_parse_version_string (strings->version_string, + 2, /* n_components */ + &v, /* tail */ + NULL /* version_ret */)) + return FALSE; + + /* In mesa this will be followed by a space and the name "Mesa" */ + if (!g_str_has_prefix (v, " Mesa ")) + return FALSE; + + v += 6; + + /* Next there will be a version string that is at least two + components. On a git devel build the version will be something + like "-devel" instead */ + if (!_cogl_gpu_info_parse_version_string (v, + 2, /* n_components */ + &v, /* tail */ + version_ret)) + return FALSE; + + /* If it is a development build then we'll just leave the micro + number as 0 */ + if (g_str_has_prefix (v, "-devel")) + return TRUE; + + /* Otherwise there should be a micro version number */ + if (*v != '.') + return FALSE; + + errno = 0; + micro_part = g_ascii_strtoull (v + 1, NULL /* endptr */, 10 /* base */); + if (errno || micro_part > COGL_VERSION_MAX_COMPONENT_VALUE) + return FALSE; + + *version_ret = COGL_VERSION_ENCODE (COGL_VERSION_GET_MAJOR (*version_ret), + COGL_VERSION_GET_MINOR (*version_ret), + micro_part); + + return TRUE; +} + +static gboolean +check_unknown_driver_package (const CoglGpuInfoStrings *strings, + int *version_out) +{ + *version_out = 0; + + /* This is a last resort so it always matches */ + return TRUE; +} + +static const CoglGpuInfoDriverPackageDescription +_cogl_gpu_info_driver_packages[] = + { + { + COGL_GPU_INFO_DRIVER_PACKAGE_MESA, + "Mesa", + check_mesa_driver_package + }, + /* Must be last */ + { + COGL_GPU_INFO_DRIVER_PACKAGE_UNKNOWN, + "Unknown", + check_unknown_driver_package + } + }; + +void +_cogl_gpu_info_init (CoglContext *ctx, + CoglGpuInfo *gpu) +{ + CoglGpuInfoStrings strings; + int i; + + strings.renderer_string = (const char *) ctx->glGetString (GL_RENDERER); + strings.version_string = (const char *) ctx->glGetString (GL_VERSION); + strings.vendor_string = (const char *) ctx->glGetString (GL_VENDOR); + + /* Determine the driver package */ + for (i = 0; ; i++) + { + const CoglGpuInfoDriverPackageDescription *description = + _cogl_gpu_info_driver_packages + i; + + if (description->check_function (&strings, &gpu->driver_package_version)) + { + gpu->driver_package = description->driver_package; + gpu->driver_package_name = description->name; + break; + } + } + + /* Determine the GPU vendor */ + for (i = 0; ; i++) + { + const CoglGpuInfoVendorDescription *description = + _cogl_gpu_info_vendors + i; + + if (description->check_function (&strings)) + { + gpu->vendor = description->vendor; + gpu->vendor_name = description->name; + break; + } + } + + /* Determine the driver bugs */ + gpu->driver_bugs = 0; +} diff --git a/cogl/cogl-util.h b/cogl/cogl-util.h index 2ad3f2666..199a11b35 100644 --- a/cogl/cogl-util.h +++ b/cogl/cogl-util.h @@ -47,6 +47,27 @@ #define COGL_EXPORT #endif +/* Macros to handle compacting a 3-component version number into an + int for quick comparison. This assumes all of the components are + <= 1023 */ +#define COGL_VERSION_COMPONENT_BITS 10 +#define COGL_VERSION_MAX_COMPONENT_VALUE \ + ((1 << COGL_VERSION_COMPONENT_BITS) - 1) + +#define COGL_VERSION_ENCODE(major, minor, micro) \ + (((major) << (COGL_VERSION_COMPONENT_BITS * 2)) | \ + ((minor) << COGL_VERSION_COMPONENT_BITS) \ + | (micro)) + +#define COGL_VERSION_GET_MAJOR(version) \ + (((version) >> 20) & COGL_VERSION_MAX_COMPONENT_VALUE) + +#define COGL_VERSION_GET_MINOR(version) \ + (((version) >> 10) & COGL_VERSION_MAX_COMPONENT_VALUE) + +#define COGL_VERSION_GET_MICRO(version) \ + ((version) & COGL_VERSION_MAX_COMPONENT_VALUE) + int _cogl_util_next_p2 (int a);