|
"""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 ) |
|
|