from django.db import models from django.utils import simplejson import re class UserReport(models.Model): uploader = models.IPAddressField(editable = False) # Hex SHA-1 digest of user's reported ID # (The hashing means that publishing the database won't let people upload # faked reports under someone else's user ID, and also ensures a simple # consistent structure) user_id_hash = models.CharField(max_length = 40, db_index = True, editable = False) # When the server received the upload upload_date = models.DateTimeField(auto_now_add = True, db_index = True, editable = False) # When the user claims to have generated the report generation_date = models.DateTimeField(editable = False) data_type = models.CharField(max_length = 16, db_index = True, editable = False) data_version = models.IntegerField(editable = False) data = models.TextField(editable = False) def data_json(self): if not hasattr(self, 'cached_json'): try: self.cached_json = simplejson.loads(self.data) except: self.cached_json = None return self.cached_json def data_json_nocache(self): try: return simplejson.loads(self.data) except: return None def clear_cache(self): delattr(self, 'cached_json') def downcast(self): if self.data_type == 'hwdetect': return UserReport_hwdetect.objects.get(id = self.id) else: return self class UserReport_hwdetect(UserReport): class Meta: proxy = True def os(self): os = 'Unknown' json = self.data_json() if json: if json['os_win']: os = 'Windows' elif json['os_linux']: os = 'Linux' elif json['os_macosx']: os = 'OS X' return os def gl_renderer(self): json = self.data_json() if json is None or 'GL_RENDERER' not in json: return None # The renderer string should typically be interpreted as UTF-8 try: return json['GL_RENDERER'].encode('iso-8859-1').decode('utf-8').strip() except UnicodeError: return json['GL_RENDERER'].strip() def gl_extensions(self): json = self.data_json() if json is None or 'GL_EXTENSIONS' not in json: return None vals = re.split(r'\s+', json['GL_EXTENSIONS']) return frozenset(v for v in vals if len(v)) # skip empty strings (e.g. no extensions at all, or leading/trailing space) def gl_limits(self): json = self.data_json() if json is None: return None limits = {} for (k, v) in json.items(): if not k.startswith('GL_'): continue if k == 'GL_VERSION': m = re.match(r'^(\d+\.\d+).*', v) if m: limits[k] = '%s [...]' % m.group(1) continue if k in ('GL_RENDERER', 'GL_EXTENSIONS'): continue # Hide some values that got deleted from the report in r8953, for consistency if k in ('GL_MAX_COLOR_MATRIX_STACK_DEPTH', 'GL_FRAGMENT_PROGRAM_ARB.GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB', 'GL_FRAGMENT_PROGRAM_ARB.GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB'): continue # Hide some pixel depth values that are not really correlated with device if k in ('GL_RED_BITS', 'GL_GREEN_BITS', 'GL_BLUE_BITS', 'GL_ALPHA_BITS', 'GL_INDEX_BITS', 'GL_DEPTH_BITS', 'GL_STENCIL_BITS', 'GL_ACCUM_RED_BITS', 'GL_ACCUM_GREEN_BITS', 'GL_ACCUM_BLUE_BITS', 'GL_ACCUM_ALPHA_BITS'): continue limits[k] = v return limits # Construct a nice-looking concise graphics device identifier # (skipping boring hardware/driver details) def gl_device_identifier(self): r = self.gl_renderer() m = re.match(r'^(?:AMD |ATI |NVIDIA |Mesa DRI )?(.*?)\s*(?:GEM 20100328 2010Q1|GEM 20100330 DEVELOPMENT|GEM 20091221 2009Q4|20090101|Series)?\s*(?:x86|/AGP|/PCI|/MMX|/MMX\+|/SSE|/SSE2|/3DNOW!|/3DNow!|/3DNow!\+)*(?: TCL| NO-TCL)?(?: DRI2)?(?: \(Microsoft Corporation - WDDM\))?(?: OpenGL Engine)?\s*$', r) if m: r = m.group(1) return r.strip() def gl_vendor(self): json = self.data_json() return json['GL_VENDOR'].strip() # Construct a nice string identifying the driver def gl_driver(self): json = self.data_json() gfx_drv_ver = json['gfx_drv_ver'] # Try the Mesa git style first m = re.match(r'^OpenGL \d+\.\d+(?:\.\d+)? (Mesa \d+\.\d+)-devel \(git-([a-f0-9]+)', gfx_drv_ver) if m: return '%s-git-%s' % (m.group(1), m.group(2)) # Try the normal Mesa style m = re.match(r'^OpenGL \d+\.\d+(?:\.\d+)? (Mesa .*)$', gfx_drv_ver) if m: return m.group(1) # Try the NVIDIA Linux style m = re.match(r'^OpenGL \d+\.\d+(?:\.\d+)? NVIDIA (.*)$', gfx_drv_ver) if m: return m.group(1) # Try the ATI Catalyst Linux style m = re.match(r'^OpenGL (\d+\.\d+\.\d+) Compatibility Profile Context(?: FireGL)?$', gfx_drv_ver) if m: return m.group(1) # Try the non-direct-rendering ATI Catalyst Linux style m = re.match(r'^OpenGL 1\.4 \((\d+\.\d+\.\d+) Compatibility Profile Context(?: FireGL)?\)$', gfx_drv_ver) if m: return '%s (indirect)' % m.group(1) # Try to guess the relevant Windows driver # (These are the ones listed in lib/sysdep/os/win/wgfx.cpp) if json['GL_VENDOR'] == 'NVIDIA Corporation': # Assume 64-bit takes precedence m = re.search(r'nvoglv64.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'nvoglv32.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'nvoglnt.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) if json['GL_VENDOR'] in ('ATI Technologies Inc.', 'Advanced Micro Devices, Inc.'): m = re.search(r'atioglxx.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'atioglx2.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'atioglaa.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) if json['GL_VENDOR'] == 'Intel': # Assume 64-bit takes precedence m = re.search(r'ig4icd64.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'ig4icd32.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) # Legacy 32-bit m = re.search(r'iglicd32.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'ialmgicd32.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) m = re.search(r'ialmgicd.dll \((.*?)\)', gfx_drv_ver) if m: return m.group(1) return gfx_drv_ver class GraphicsDevice(models.Model): device_name = models.CharField(max_length = 128, db_index = True) vendor = models.CharField(max_length = 64) renderer = models.CharField(max_length = 128) os = models.CharField(max_length = 16) driver = models.CharField(max_length = 128) usercount = models.IntegerField() class GraphicsExtension(models.Model): device = models.ForeignKey(GraphicsDevice) name = models.CharField(max_length = 128, db_index = True) class GraphicsLimit(models.Model): device = models.ForeignKey(GraphicsDevice) name = models.CharField(max_length = 128, db_index = True) value = models.CharField(max_length = 64)