| """Extension module support methods |
| |
| This module provides the tools required to check whether |
| an extension is available |
| """ |
| from OpenGL.latebind import LateBind |
| from OpenGL._bytes import bytes,unicode,as_8_bit |
| import OpenGL as root |
| import sys |
| import logging |
| _log = logging.getLogger( 'OpenGL.extensions' ) |
| VERSION_PREFIX = as_8_bit('GL_VERSION_GL_') |
| CURRENT_GL_VERSION = None |
| AVAILABLE_GL_EXTENSIONS = [] |
| AVAILABLE_GLU_EXTENSIONS = [] |
|
|
| |
| VERSION_EXTENSIONS = [ |
| ((3,0), [ |
| as_8_bit('GL_ARB_vertex_array_object'), |
| as_8_bit('GL_ARB_texture_buffer_object'), |
| as_8_bit('GL_ARB_framebuffer_object'), |
| as_8_bit('GL_ARB_map_buffer_range'), |
| ]), |
| ((3,1), [ |
| as_8_bit('GL_ARB_copy_buffer'), |
| as_8_bit('GL_ARB_uniform_buffer_object'), |
| ]), |
| ((3,2), [ |
| as_8_bit('GL_ARB_draw_elements_base_vertex'), |
| as_8_bit('GL_ARB_provoking_vertex'), |
| as_8_bit('GL_ARB_sync'), |
| as_8_bit('GL_ARB_texture_multisample'), |
| ]), |
| ((3,3), [ |
| as_8_bit('GL_ARB_texture_multisample'), |
| as_8_bit('GL_ARB_blend_func_extended'), |
| as_8_bit('GL_ARB_sampler_objects'), |
| as_8_bit('GL_ARB_explicit_attrib_location'), |
| as_8_bit('GL_ARB_occlusion_query2'), |
| as_8_bit('GL_ARB_shader_bit_encoding'), |
| as_8_bit('GL_ARB_texture_rgb10_a2ui'), |
| as_8_bit('GL_ARB_texture_swizzle'), |
| as_8_bit('GL_ARB_timer_query'), |
| as_8_bit('GL_ARB_vertex_type_2_10_10_10_rev'), |
| ]), |
| ((4,0), [ |
| as_8_bit('GL_ARB_texture_query_lod'), |
| as_8_bit('GL_ARB_draw_indirect'), |
| as_8_bit('GL_ARB_gpu_shader5'), |
| as_8_bit('GL_ARB_gpu_shader_fp64'), |
| as_8_bit('GL_ARB_shader_subroutine'), |
| as_8_bit('GL_ARB_tessellation_shader'), |
| as_8_bit('GL_ARB_texture_buffer_object_rgb32'), |
| as_8_bit('GL_ARB_texture_cube_map_array'), |
| as_8_bit('GL_ARB_texture_gather'), |
| as_8_bit('GL_ARB_transform_feedback2'), |
| as_8_bit('GL_ARB_transform_feedback3'), |
| ]), |
| ((4,1), [ |
| as_8_bit('GL_ARB_ES2_compatibility'), |
| as_8_bit('GL_ARB_get_program_binary'), |
| as_8_bit('GL_ARB_separate_shader_objects'), |
| as_8_bit('GL_ARB_shader_precision'), |
| as_8_bit('GL_ARB_vertex_attrib_64bit'), |
| as_8_bit('GL_ARB_viewport_array'), |
| ]), |
| ((4,2), [ |
| as_8_bit('GL_ARB_base_instance'), |
| as_8_bit('GL_ARB_shading_language_420pack'), |
| as_8_bit('GL_ARB_transform_feedback_instanced'), |
| as_8_bit('GL_ARB_compressed_texture_pixel_storage'), |
| as_8_bit('GL_ARB_conservative_depth'), |
| as_8_bit('GL_ARB_internalformat_query'), |
| as_8_bit('GL_ARB_map_buffer_alignment'), |
| as_8_bit('GL_ARB_shader_atomic_counters'), |
| as_8_bit('GL_ARB_shader_image_load_store'), |
| as_8_bit('GL_ARB_shading_language_packing'), |
| as_8_bit('GL_ARB_texture_storage'), |
| ]), |
| ] |
|
|
| class ExtensionQuerier( object ): |
| prefix = None |
| version_prefix = None |
| assumed_version = [1,0] |
| |
| version = extensions = None |
| version_string = extensions_string = None |
| |
| registered = [] |
| def __init__( self ): |
| self.registered.append( self ) |
| |
| @classmethod |
| def hasExtension( self, specifier ): |
| for registered in self.registered: |
| result = registered( specifier ) |
| if result: |
| return result |
| return False |
| |
| def __call__( self, specifier ): |
| specifier = as_8_bit(specifier).replace(as_8_bit('.'),as_8_bit('_')) |
| if not specifier.startswith( as_8_bit(self.prefix) ): |
| return None |
| |
| if specifier.startswith( as_8_bit(self.version_prefix) ): |
| specifier = [ |
| int(x) |
| for x in specifier[ len(self.version_prefix):].split(as_8_bit('_')) |
| ] |
| if specifier[:2] <= self.assumed_version: |
| return True |
| version = self.getVersion() |
| if not version: |
| return version |
| return specifier <= version |
| else: |
| extensions = self.getExtensions() |
| return extensions and specifier in extensions |
| def getVersion( self ): |
| if not self.version: |
| self.version = self.pullVersion() |
| return self.version |
| def getExtensions( self ): |
| if not self.extensions: |
| self.extensions = self.pullExtensions() |
| return self.extensions |
|
|
| class _GLQuerier( ExtensionQuerier ): |
| prefix = as_8_bit('GL_') |
| version_prefix = as_8_bit('GL_VERSION_GL_') |
| assumed_version = [1,1] |
| def pullVersion( self ): |
| """Retrieve 2-int declaration of major/minor GL version |
| |
| returns [int(major),int(minor)] or False if not loaded |
| """ |
| from OpenGL import platform |
| if not platform.PLATFORM.CurrentContextIsValid(): |
| return False |
| from OpenGL.raw.GL.VERSION.GL_1_1 import glGetString |
| from OpenGL.raw.GL.VERSION.GL_1_1 import GL_VERSION |
| new = glGetString( GL_VERSION ) |
| |
| self.version_string = new |
| if new: |
| return [ |
| int(x) for x in new.split(as_8_bit(' '),1)[0].split( as_8_bit('.') ) |
| ] |
| else: |
| return False |
| def pullExtensions( self ): |
| from OpenGL import platform |
| if not platform.PLATFORM.CurrentContextIsValid(): |
| return False |
| from OpenGL.raw.GL._types import GLint |
| from OpenGL.raw.GL.VERSION.GL_1_1 import glGetString, glGetError |
| from OpenGL.raw.GL.VERSION.GL_1_1 import GL_EXTENSIONS |
| from OpenGL import error |
| try: |
| extensions = glGetString( GL_EXTENSIONS ) |
| if glGetError(): |
| raise error.GLError() |
| if extensions: |
| extensions = extensions.split() |
| else: |
| return False |
| except (AttributeError, error.GLError): |
| |
| from OpenGL.raw.GL.VERSION.GL_3_0 import GL_NUM_EXTENSIONS, glGetStringi |
| from OpenGL.raw.GL.VERSION.GL_1_1 import glGetIntegerv |
| count = GLint() |
| glGetIntegerv( GL_NUM_EXTENSIONS, count ) |
| extensions = [] |
| for i in range( count.value ): |
| extension = glGetStringi( GL_EXTENSIONS, i ) |
| extensions.append( |
| extension |
| ) |
| |
| version = self.getVersion() |
| if not version: |
| |
| return version |
| check = tuple( version[:2] ) |
| for (v,v_exts) in VERSION_EXTENSIONS: |
| if v <= check: |
| for v_ext in v_exts: |
| if v_ext not in extensions: |
| extensions.append( as_8_bit(v_ext) ) |
| else: |
| break |
| return extensions |
| GLQuerier = _GLQuerier() |
| class _GLUQuerier( ExtensionQuerier ): |
| prefix = as_8_bit('GLU_') |
| version_prefix = as_8_bit('GLU_VERSION_GL_') |
| def pullVersion( self ): |
| from OpenGL.GLU import gluGetString,GLU_VERSION |
| return [ |
| int(x) for x in gluGetString( GLU_VERSION ).split(as_8_bit('_')) |
| if x.isdigit() |
| ] |
| def pullExtensions( self ): |
| from OpenGL.GLU import gluGetString,GLU_EXTENSIONS |
| return gluGetString( GLU_EXTENSIONS ).split() |
| GLUQuerier = _GLUQuerier() |
|
|
| def hasExtension( specifier ): |
| return ExtensionQuerier.hasExtension( specifier ) |
| hasGLExtension = hasGLUExtension = hasExtension |
|
|
| class _Alternate( LateBind ): |
| def __init__( self, name, *alternates ): |
| """Initialize set of alternative implementations of the same function""" |
| self.__name__ = name |
| self._alternatives = alternates |
| if root.MODULE_ANNOTATIONS: |
| frame = sys._getframe().f_back |
| if frame and frame.f_back and '__name__' in frame.f_back.f_globals: |
| self.__module__ = frame.f_back.f_globals['__name__'] |
| def __bool__( self ): |
| from OpenGL import error |
| try: |
| return bool( self.getFinalCall()) |
| except error.NullFunctionError as err: |
| return False |
| __nonzero__ = __bool__ |
| def finalise( self ): |
| """Call, doing a late lookup and bind to find an implementation""" |
| for alternate in self._alternatives: |
| if alternate: |
| |
| |
| |
| |
| |
| return alternate |
| from OpenGL import error |
| raise error.NullFunctionError( |
| """Attempt to call an undefined alternate function (%s), check for bool(%s) before calling"""%( |
| ', '.join([x.__name__ for x in self._alternatives]), |
| self.__name__, |
| ) |
| ) |
| def alternate( name, *functions ): |
| """Construct a callable that functions as the first implementation found of given set of alternatives |
| |
| if name is a function then its name will be used.... |
| """ |
| if not isinstance( name, (bytes,unicode)): |
| functions = (name,)+functions |
| name = name.__name__ |
| return type( name, (_Alternate,), {} )( name, *functions ) |
|
|