def get_max_texture_size(): from OpenGL.GL import glGetInteger, GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) log("GL_MAX_TEXTURE_SIZE=%s", texture_size) #this one may be missing? rect_texture_size = texture_size try: from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) except ImportError as e: log("OpenGL: %s", e) log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size) else: log("Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE=%s", rect_texture_size) return min(rect_texture_size, texture_size)
def from_matrix(cls, matrix): """Creates a texture from given matrix file. :param matrix: The matrix. :type matrix: list :returns: The texture instance. :rtype: :class:`renderer.Texture` """ w, h = len(matrix[0]), len(matrix) grid = bytes(chain.from_iterable(reversed(matrix))) tex = glGenTextures(1) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, tex) # This code is necessary to handle non-power-of-two textures with small # sizes. # TODO: refactor this param_ids = [ GL_UNPACK_ALIGNMENT, GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_ROWS, GL_UNPACK_SKIP_PIXELS, ] old_params = { p: glGetInteger(p) for p in param_ids } glPixelStorei(GL_UNPACK_ALIGNMENT, 1) glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) glPixelStorei(GL_UNPACK_SKIP_ROWS, 0) glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0) glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, w, h) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RED, GL_UNSIGNED_BYTE, grid) for p, v in old_params.items(): glPixelStorei(p, v) glBindTexture(GL_TEXTURE_2D, 0) return Texture(tex, w, h, GL_TEXTURE_2D)
def get_gl_info_string(glpane): # grantham 20051129 """ Return a string containing some useful information about the OpenGL implementation. Use the GL context from the given QGLWidget glpane (by calling glpane.makeCurrent()). """ glpane.makeCurrent() #bruce 070308 added glpane arg and makeCurrent call gl_info_string = '' gl_info_string += 'GL_VENDOR : "%s"\n' % glGetString(GL_VENDOR) gl_info_string += 'GL_VERSION : "%s"\n' % glGetString(GL_VERSION) gl_info_string += 'GL_RENDERER : "%s"\n' % glGetString(GL_RENDERER) gl_extensions = glGetString(GL_EXTENSIONS) gl_extensions = gl_extensions.strip() gl_extensions = gl_extensions.replace(" ", "\n* ") gl_info_string += 'GL_EXTENSIONS : \n* %s\n' % gl_extensions if debug_pref("Graphics Card Info: call glAreTexturesResident?", Choice_boolean_False): # Give a practical indication of how much video memory is available. # Should also do this with VBOs. # I'm pretty sure this code is right, but PyOpenGL seg faults in # glAreTexturesResident, so it's disabled until I can figure that # out. [grantham] [bruce 070308 added the debug_pref] all_tex_in = True tex_bytes = '\0' * (512 * 512 * 4) tex_names = [] tex_count = 0 tex_names = glGenTextures(1024) glEnable(GL_TEXTURE_2D) while all_tex_in: glBindTexture(GL_TEXTURE_2D, tex_names[tex_count]) gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, tex_bytes) tex_count += 1 glTexCoord2f(0.0, 0.0) glBegin(GL_QUADS) glVertex2f(0.0, 0.0) glVertex2f(1.0, 0.0) glVertex2f(1.0, 1.0) glVertex2f(0.0, 1.0) glEnd() glFinish() residences = glAreTexturesResident(tex_names[:tex_count]) all_tex_in = reduce(lambda a, b: a and b, residences) # bruce 070308 sees this exception from this line: # TypeError: reduce() arg 2 must support iteration glDisable(GL_TEXTURE_2D) glDeleteTextures(tex_names) gl_info_string += "Could create %d 512x512 RGBA resident textures\n" \ % tex_count pass if True: ## or could be a debug_pref("Graphics Card Info: get all GL_MAX symbols?") #bruce 090314 new feature import OpenGL.GL symbols = [x for x in dir(OpenGL.GL) if x.startswith('GL_MAX_')] symbols.sort() gl_info_string += '\n' for symbol in symbols: try: numeric_symbol = getattr(OpenGL.GL, symbol) intval = glGetInteger(numeric_symbol) except: # this happens to most symbols, not sure why if debug_flags.atom_debug: print_compact_traceback("%s = ??: " % symbol) # overkill, only the exception itself matters # typical output (on Bruce's MacBookPro, 090314): ## GL_MAX_4D_TEXTURE_SIZE_SGIS = ??: ## <type 'exceptions.KeyError'>: ## ('Unknown specifier GL_MAX_4D_TEXTURE_SIZE_SGIS (33080)', ## 'Failure in cConverter <OpenGL.converters.SizedOutput object at 0x1457fab0>', ## [GL_MAX_4D_TEXTURE_SIZE_SGIS], 1, <OpenGL.wrapper.glGetIntegerv object at 0x1458aa30>) ## [graphics_card_info.py:122] [wrapper.py:676] [converters.py:195] [converters.py:234] pass pass ## gl_info_string += "%s = ??\n" % symbol else: gl_info_string += "%s = %r\n" % (symbol, intval) continue pass return gl_info_string
def check_GL_support(gldrawable, glcontext, min_texture_size=0, force_enable=False): if not gldrawable.gl_begin(glcontext): raise ImportError("gl_begin failed on %s" % gldrawable) props = {} try: if SILENCE_FORMAT_HANDLER_LOGGER: logging.getLogger('OpenGL.formathandler').setLevel(logging.WARN) import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger gl_major = int(glGetString(GL_VERSION)[0]) gl_minor = int(glGetString(GL_VERSION)[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1, 1) if (gl_major, gl_minor) < MIN_VERSION: gl_check_error( "OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: log("found valid OpenGL version: %s.%s", gl_major, gl_minor) try: extensions = glGetString(GL_EXTENSIONS).split(" ") except: gl_check_error( "OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?" ) log("OpenGL extensions found: %s", ", ".join(extensions)) props["extensions"] = extensions from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION for d, s in { "vendor": GL_VENDOR, "renderer": GL_RENDERER, "shading language version": GL_SHADING_LANGUAGE_VERSION }.items(): try: v = glGetString(s) log("%s: %s", d, v) except: gl_check_error("OpenGL property '%s' is missing" % d) v = "" props[d] = v from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d, s in { "GLU version": GLU_VERSION, "GLU extensions": GLU_EXTENSIONS }.items(): v = gluGetString(s) log("%s: %s", d, v) props[d] = v for k, vlist in BLACKLIST.items(): v = props.get(k) if v in vlist: if force_enable: log.warn("Warning: %s '%s' is blacklisted!", k, v) else: gl_check_error("%s '%s' is blacklisted!" % (k, v)) #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) for ext in required_extensions: if ext not in extensions: gl_check_error( "OpenGL driver lacks support for extension: %s" % ext) else: log("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): gl_check_error("OpenGL output requires glInitFragmentProgramARB") else: log("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): gl_check_error("OpenGL output requires glInitTextureRectangleARB") else: log("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) if min_texture_size > texture_size: gl_check_error("The texture size is too small: %s" % texture_size) else: log("Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB=%s", texture_size) return props finally: if SILENCE_FORMAT_HANDLER_LOGGER: try: logging.getLogger('OpenGL.formathandler').setLevel( logging.INFO) except: pass gldrawable.gl_end()
def check_PyOpenGL_support(force_enable): props = {} try: if CRASH: import ctypes ctypes.string_at(0) raise Exception("should have crashed!") elif TIMEOUT > 0: import time time.sleep(TIMEOUT) #log redirection: def redirect_log(logger_name): logger = logging.getLogger(logger_name) assert logger is not None logger.saved_handlers = logger.handlers logger.saved_propagate = logger.propagate logger.handlers = [CaptureHandler()] logger.propagate = 0 return logger fhlogger = redirect_log('OpenGL.formathandler') elogger = redirect_log('OpenGL.extensions') alogger = redirect_log('OpenGL.acceleratesupport') arlogger = redirect_log('OpenGL.arrays') clogger = redirect_log('OpenGL.converters') import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger, glGetIntegerv gl_version_str = glGetString(GL_VERSION) if gl_version_str is None: raise_fatal_error("OpenGL version is missing - cannot continue") return {} gl_major = int(bytestostr(gl_version_str)[0]) gl_minor = int(bytestostr(gl_version_str)[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1, 1) if (gl_major, gl_minor) < MIN_VERSION: raise_fatal_error( "OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: log("found valid OpenGL version: %s.%s", gl_major, gl_minor) from OpenGL import version as OpenGL_version pyopengl_version = OpenGL_version.__version__ try: import OpenGL_accelerate #@UnresolvedImport accel_version = OpenGL_accelerate.__version__ props["accelerate"] = accel_version log("OpenGL_accelerate version %s", accel_version) except: log("OpenGL_accelerate not found") OpenGL_accelerate = None accel_version = None if accel_version is not None and pyopengl_version != accel_version: global _version_warning_shown if not _version_warning_shown: log.warn( "Warning: version mismatch between PyOpenGL and PyOpenGL-accelerate" ) log.warn(" %s vs %s", pyopengl_version, accel_version) log.warn(" this may cause crashes") _version_warning_shown = True gl_check_error( "PyOpenGL vs accelerate version mismatch: %s vs %s" % (pyopengl_version, accel_version)) vsplit = pyopengl_version.split('.') #we now require PyOpenGL 3.1 or later if vsplit[:3] < ['3', '1'] and not force_enable: raise_fatal_error("PyOpenGL version %s is too old and buggy" % pyopengl_version) return {} props["zerocopy"] = bool( OpenGL_accelerate) and is_pyopengl_memoryview_safe( pyopengl_version, accel_version) try: extensions = glGetString(GL_EXTENSIONS).decode().split(" ") except: log("error querying extensions", exc_info=True) extensions = [] raise_fatal_error( "OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?" ) log("OpenGL extensions found: %s", csv(extensions)) props["extensions"] = extensions from OpenGL.arrays.arraydatatype import ArrayDatatype try: log("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values())) except: pass from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION def fixstring(v): try: return str(v).strip() except: return str(v) for d, s, fatal in (("vendor", GL_VENDOR, True), ("renderer", GL_RENDERER, True), ("shading-language-version", GL_SHADING_LANGUAGE_VERSION, False)): try: v = glGetString(s) v = fixstring(v.decode()) log("%s: %s", d, v) except: if fatal: gl_check_error("OpenGL property '%s' is missing" % d) else: log("OpenGL property '%s' is missing", d) v = "" props[d] = v vendor = props["vendor"] version_req = VERSION_REQ.get(vendor) if version_req: req_maj, req_min = version_req if gl_major < req_maj or (gl_major == req_maj and gl_minor < req_min): if force_enable: log.warn( "Warning: '%s' OpenGL driver requires version %i.%i", vendor, req_maj, req_min) log.warn(" version %i.%i was found", gl_major, gl_minor) else: gl_check_error( "OpenGL version %i.%i is too old, %i.%i is required for %s" % (gl_major, gl_minor, req_maj, req_min, vendor)) from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d, s in { "GLU.version": GLU_VERSION, "GLU.extensions": GLU_EXTENSIONS }.items(): v = gluGetString(s) v = v.decode() log("%s: %s", d, v) props[d] = v def match_list(thelist, listname): for k, vlist in thelist.items(): v = props.get(k) matches = [x for x in vlist if v.find(x) >= 0] if matches: log("%s '%s' found in %s: %s", k, v, listname, vlist) return (k, v) log("%s '%s' not found in %s: %s", k, v, listname, vlist) return None blacklisted = match_list(BLACKLIST, "blacklist") greylisted = match_list(GREYLIST, "greylist") whitelisted = match_list(WHITELIST, "whitelist") if blacklisted: if whitelisted: log.info( "%s '%s' enabled (found in both blacklist and whitelist)", *whitelisted) elif force_enable: log.warn("Warning: %s '%s' is blacklisted!", *blacklisted) log.warn(" force enabled by option") else: raise_fatal_error("%s '%s' is blacklisted!" % (blacklisted)) safe = bool(whitelisted) or not bool(blacklisted) if greylisted and not whitelisted: log.warn("Warning: %s '%s' is greylisted,", *greylisted) log.warn(" you may want to turn off OpenGL if you encounter bugs") props["safe"] = safe #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) glEnablei = None try: from OpenGL.GL import glEnablei except: pass if not bool(glEnablei): log.warn( "OpenGL glEnablei is not available, disabling transparency") global GL_ALPHA_SUPPORTED GL_ALPHA_SUPPORTED = False props["transparency"] = GL_ALPHA_SUPPORTED for ext in required_extensions: if ext not in extensions: raise_fatal_error( "OpenGL driver lacks support for extension: %s" % ext) else: log("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): raise_fatal_error( "OpenGL output requires glInitFragmentProgramARB") else: log("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): raise_fatal_error( "OpenGL output requires glInitTextureRectangleARB") else: log("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) try: from OpenGL.GL import GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) #this one may be missing? rect_texture_size = texture_size try: from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) except ImportError as e: log("OpenGL: %s", e) log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size) except Exception as e: emsg = str(e) if hasattr(e, "description"): emsg = e.description gl_check_error("unable to query max texture size: %s" % emsg) return props log( "Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size) texture_size_limit = min(rect_texture_size, texture_size) props["texture-size-limit"] = int(texture_size_limit) try: from OpenGL.GL import GL_MAX_VIEWPORT_DIMS v = glGetIntegerv(GL_MAX_VIEWPORT_DIMS) max_viewport_dims = int(v[0]), int(v[1]) assert max_viewport_dims[ 0] >= texture_size_limit and max_viewport_dims[ 1] >= texture_size_limit log("GL_MAX_VIEWPORT_DIMS=%s", max_viewport_dims) except ImportError as e: log.error("Error querying max viewport dims: %s", e) max_viewport_dims = texture_size_limit, texture_size_limit props["max-viewport-dims"] = max_viewport_dims return props finally: for x in alogger.handlers[0].records: #strip default message prefix: msg = x.getMessage().replace( "No OpenGL_accelerate module loaded: ", "") if msg == "No module named OpenGL_accelerate": msg = "missing accelerate module" if msg == "OpenGL_accelerate module loaded": log.info(msg) else: log.warn("PyOpenGL warning: %s", msg) #format handler messages: STRIP_LOG_MESSAGE = "Unable to load registered array format handler " missing_handlers = [] for x in fhlogger.handlers[0].records: msg = x.getMessage() p = msg.find(STRIP_LOG_MESSAGE) if p < 0: #unknown message, log it: log.info(msg) continue format_handler = msg[p + len(STRIP_LOG_MESSAGE):] p = format_handler.find(":") if p > 0: format_handler = format_handler[:p] missing_handlers.append(format_handler) if len(missing_handlers) > 0: log.warn("PyOpenGL warning: missing array format handlers: %s", csv(missing_handlers)) for x in elogger.handlers[0].records: msg = x.getMessage() #ignore extension messages: p = msg.startswith("GL Extension ") and msg.endswith("available") if not p: log.info(msg) missing_accelerators = [] STRIP_AR_HEAD = "Unable to load" STRIP_AR_TAIL = "from OpenGL_accelerate" for x in arlogger.handlers[0].records + clogger.handlers[0].records: msg = x.getMessage() if msg.startswith(STRIP_AR_HEAD) and msg.endswith(STRIP_AR_TAIL): m = msg[len(STRIP_AR_HEAD):-len(STRIP_AR_TAIL)].strip() m = m.replace("accelerators", "").replace("accelerator", "").strip() missing_accelerators.append(m) continue elif msg.startswith("Using accelerated"): log(msg) else: log.info(msg) if missing_accelerators: log.info("OpenGL accelerate missing: %s", csv(missing_accelerators)) def restore_logger(logger): logger.handlers = logger.saved_handlers logger.propagate = logger.saved_propagate restore_logger(fhlogger) restore_logger(elogger) restore_logger(alogger) restore_logger(arlogger) restore_logger(clogger)
def __init__(self, shaderName, shaderVertSrc, shaderFragSrc): # note: on any error, we set self.error, print a message, and return. # exceptions will be caught by caller and also set self.error, # but result in less specific printed error messages. # Configure the max constant RAM used for a "uniform" transforms block. if UNIFORM_XFORMS: global N_CONST_XFORMS oldNCX = N_CONST_XFORMS maxComponents = glGetInteger(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB) N_CONST_XFORMS = min( N_CONST_XFORMS, # Each matrix has 16 components. Leave slack for other vars too. (maxComponents - _VERTEX_SHADER_GPU_VAR_SLACK) / 16) if N_CONST_XFORMS <= 0: print ( "N_CONST_XFORMS not positive, is %d. %d max components." % (N_CONST_XFORMS, maxComponents)) # Now, we think this means we should use display lists instead. print "error: not enough shader constant memory" self.error = True return elif N_CONST_XFORMS == oldNCX: print ("N_CONST_XFORMS unchanged at %d. %d max components." % (N_CONST_XFORMS, maxComponents)) else: print ( "N_CONST_XFORMS changed to %d, was %d. %d max components." % (N_CONST_XFORMS, oldNCX, maxComponents)) pass pass # Version statement has to come first in GLSL source. prefix = """// requires GLSL version 1.20 #version 120 """ # Insert preprocessor constants before both shader source code strings # (using a constant number of lines, to preserve GLSL line numbers) if UNIFORM_XFORMS: prefix += "#define UNIFORM_XFORMS\n" prefix += "#define N_CONST_XFORMS %d\n" % N_CONST_XFORMS elif TEXTURE_XFORMS: prefix += "#define TEXTURE_XFORMS\n" prefix += "\n" else: prefix += "\n\n" pass # GLSL on the nVidia GeForce 7000 only supports constant array # subscripts, and subscripting by a loop index variable. if not debug_pref("GLPane: shaders with only constant subscripts?", Choice_boolean_True, prefs_key = True): prefix += "#define FULL_SUBSCRIPTING\n" else: prefix += "\n" # To keep the shader line numbers unchanged. pass if debug_pref("GLPane: simulate GLSL syntax error (next session)", Choice_boolean_False, prefs_key = True): prefix += "}\n" # remove whitespace before and after each prefix line [bruce 090306] prefix = '\n'.join( [line.strip() for line in prefix.split('\n')] ) assert prefix[-1] == '\n' # Pass the source strings to the shader compiler. self.vertShader = self.createShader(shaderName, GL_VERTEX_SHADER, prefix + shaderVertSrc) self.fragShader = self.createShader(shaderName, GL_FRAGMENT_SHADER, prefix + shaderFragSrc) if self.error: # May be set by createShader. return # Can't do anything good after an error. # Link the compiled shaders into a shader program. self.progObj = glCreateProgramObjectARB() glAttachObjectARB(self.progObj, self.vertShader) glAttachObjectARB(self.progObj, self.fragShader) try: glLinkProgramARB(self.progObj) # Checks status, raises error if bad. except: self.error = True print shaderName, "shader program link error" print glGetInfoLogARB(self.progObj) return # Can't do anything good after an error. # Optional, may be useful for debugging. glValidateProgramARB(self.progObj) status = glGetObjectParameterivARB(self.progObj, GL_VALIDATE_STATUS) if (not status): self.error = True print "Shader program validation error" print glGetInfoLogARB(self.progObj) return # Can't do anything good after an error. return
def check_GL_support(gldrawable, glcontext, min_texture_size=0, force_enable=False): if not gldrawable.gl_begin(glcontext): raise ImportError("gl_begin failed on %s" % gldrawable) props = {} try: if SILENCE_FORMAT_HANDLER_LOGGER: debug("silencing formathandler warnings") logging.getLogger('OpenGL.formathandler').setLevel(logging.WARN) import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger gl_version_str = glGetString(GL_VERSION) if gl_version_str is None: gl_check_error("OpenGL version is missing - cannot continue") return {} gl_major = int(gl_version_str[0]) gl_minor = int(gl_version_str[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1,1) if (gl_major, gl_minor) < MIN_VERSION: gl_check_error("OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: debug("found valid OpenGL version: %s.%s", gl_major, gl_minor) try: extensions = glGetString(GL_EXTENSIONS).split(" ") except: gl_check_error("OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?") debug("OpenGL extensions found: %s", ", ".join(extensions)) props["extensions"] = extensions from OpenGL.arrays.arraydatatype import ArrayDatatype try: debug("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values())) except: pass from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION for d,s,fatal in (("vendor", GL_VENDOR, True), ("renderer", GL_RENDERER, True), ("shading language version", GL_SHADING_LANGUAGE_VERSION, False)): try: v = glGetString(s) debug("%s: %s", d, v) except: if fatal: gl_check_error("OpenGL property '%s' is missing" % d) else: log.warn("OpenGL property '%s' is missing" % d) v = "" props[d] = v from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d,s in {"GLU version": GLU_VERSION, "GLU extensions":GLU_EXTENSIONS}.items(): v = gluGetString(s) debug("%s: %s", d, v) props[d] = v for k,vlist in BLACKLIST.items(): v = props.get(k) if v in vlist: if force_enable: log.warn("Warning: %s '%s' is blacklisted!", k, v) else: gl_check_error("%s '%s' is blacklisted!" % (k, v)) #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) for ext in required_extensions: if ext not in extensions: gl_check_error("OpenGL driver lacks support for extension: %s" % ext) else: debug("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): gl_check_error("OpenGL output requires glInitFragmentProgramARB") else: debug("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): gl_check_error("OpenGL output requires glInitTextureRectangleARB") else: debug("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE, GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) if min_texture_size>texture_size or min_texture_size>rect_texture_size: gl_check_error("The texture size is too small: %s" % texture_size) else: debug("Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size) return props finally: if SILENCE_FORMAT_HANDLER_LOGGER: try: logging.getLogger('OpenGL.formathandler').setLevel(logging.INFO) except: pass gldrawable.gl_end()
def do_glselect_if_wanted(self): # bruce 070919 split this out """ Do the glRenderMode(GL_SELECT) drawing, and/or the glname-color drawing for shader primitives, used to guess which object might be under the mouse, for one drawing frame, if desired for this frame. Report results by storing candidate mouseover objects in self.glselect_dict. The depth buffer is initially clear, and must be clear when we're done as well. @note: does not do related individual object depth/stencil buffer drawing -- caller must do that on some or all of the objects we store into self.glselect_dict. """ if self.glselect_wanted: # note: this will be reset below. ###@@@ WARNING: The original code for this, here in GLPane, has been duplicated and slightly modified # in at least three other places (search for glRenderMode to find them). This is bad; common code # should be used. Furthermore, I suspect it's sometimes needlessly called more than once per frame; # that should be fixed too. [bruce 060721 comment] wX, wY, self.targetdepth = self.glselect_wanted # wX, wY is the point to do the hit-test at # targetdepth is the depth buffer value to look for at that point, during ordinary drawing phase # (could also be used to set up clipping planes to further restrict hit-test, but this isn't yet done) # (Warning: targetdepth could in theory be out of date, if more events come between bareMotion # and the one caused by its gl_update, whose paintGL is what's running now, and if those events # move what's drawn. Maybe that could happen with mousewheel events or (someday) with keypresses # having a graphical effect. Ideally we'd count intentional redraws, and disable this picking in that case.) self.wX, self.wY = wX, wY self.glselect_wanted = 0 pwSize = 1 # Pick window size. Russ 081128: Was 3. # Bruce: Replace 3, 3 with 1, 1? 5, 5? not sure whether this will # matter... in principle should have no effect except speed. # Russ: For glname rendering, 1x1 is better because it doesn't # have window boundary issues. We get the coords of a single # pixel in the window for the mouse position. # bruce 050615 for use by nodes which want to set up their own projection matrix. self.current_glselect = (wX, wY, pwSize, pwSize) self._setup_projection(glselect=self.current_glselect) # option makes it use gluPickMatrix # Russ 081209: Added. debugPicking = debug_pref("GLPane: debug mouseover picking?", Choice_boolean_False, prefs_key=True) if self.enabled_shaders(): # TODO: optimization: find an appropriate place to call # _compute_frustum_planes. [bruce 090105 comment] # Russ 081122: There seems to be no way to access the GL name # stack in shaders. Instead, for mouseover, draw shader # primitives with glnames as colors in glRenderMode(GL_RENDER), # then read back the pixel color (glname) and depth value. # Temporarily replace the full-size viewport with a little one # at the mouse location, matching the pick matrix location. # Otherwise, we will draw a closeup of that area into the whole # window, rather than a few pixels. (This wasn't needed when we # only used GL_SELECT rendering mode here, because that doesn't # modify the frame buffer -- it just returns hits by graphics # primitives when they are inside the clipping boundaries.) # # (Don't set the viewport *before* _setup_projection(), since # that method needs to read the current whole-window viewport # to set up glselect. See explanation in its docstring.) savedViewport = glGetIntegerv(GL_VIEWPORT) glViewport(wX, wY, pwSize, pwSize) # Same as current_glselect. # First, clear the pixel RGBA to zeros and a depth of 1.0 (far), # so we won't confuse a color with a glname if there are # no shader primitives drawn over this pixel. saveDepthFunc = glGetInteger(GL_DEPTH_FUNC) glDepthFunc(GL_ALWAYS) glWindowPos3i(wX, wY, 1) # Note the Z coord. gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0)) glDepthFunc(saveDepthFunc) # needed, though we'll change it again # We must be in glRenderMode(GL_RENDER) (as usual) when this is called. # Note: _setup_projection leaves the matrix mode as GL_PROJECTION. glMatrixMode(GL_MODELVIEW) shaders = self.enabled_shaders() try: # Set flags so that we will use glnames-as-color mode # in shaders, and draw only shader primitives. # (Ideally we would also draw all non-shader primitives # as some other color, unequal to all glname colors # (or derived from a fake glname for that purpose), # in order to obscure shader primitives where appropriate. # This is intended to be done but is not yet implemented. # [bruce 090105 addendum]) for shader in shaders: shader.setPicking(True) self.set_drawing_phase("glselect_glname_color") for stereo_image in self.stereo_images_to_draw: self._enable_stereo(stereo_image) try: self._do_graphicsMode_Draw(for_mouseover_highlighting=True) # note: we can't disable depth writing here, # since we need it to make sure the correct # shader object comes out on top, or is # obscured by a DL object. Instead, we'll # clear the depth buffer again (at this pixel) # below. [bruce 090105] finally: self._disable_stereo() except: print_compact_traceback( "exception in or around _do_graphicsMode_Draw() during glname_color;" "drawing ignored; restoring modelview matrix: " ) # REVIEW: what does "drawing ignored" mean, in that message? [bruce 090105 question] glMatrixMode(GL_MODELVIEW) self._setup_modelview() ### REVIEW: correctness of this is unreviewed! # now it's important to continue, at least enough to restore other gl state pass for shader in shaders: shader.setPicking(False) self.set_drawing_phase("?") # Restore the viewport. glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]) # Read pixel value from the back buffer and re-assemble glname. glFinish() # Make sure the drawing has completed. # REVIEW: is this glFinish needed? [bruce 090105 comment] rgba = glReadPixels(wX, wY, 1, 1, gl_format, gl_type)[0][0] pixZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT)[0][0] # Clear our depth pixel to 1.0 (far), so we won't mess up the # subsequent call of preDraw_glselect_dict. # (The following is not the most direct way, but it ought to work. # Note that we also clear the color pixel, since (being a glname) # it has no purpose remaining in the color buffer -- either it's # changed later, or, if not, that's a bug, but we'd rather have # it black than a random color.) [bruce 090105 bugfix] glDepthFunc(GL_ALWAYS) glWindowPos3i(wX, wY, 1) # Note the Z coord. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0)) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) glDepthFunc(saveDepthFunc) # Comes back sign-wrapped, in spite of specifying UNSIGNED_BYTE. def us(b): if b < 0: return 256 + b return b bytes = tuple([us(b) for b in rgba]) ##glname = (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]) ## Temp fix: Ignore the last byte, which always comes back 255 on Windows. glname = bytes[0] << 16 | bytes[1] << 8 | bytes[2] if debugPicking: print ( "shader mouseover xy %d %d, " % (wX, wY) + "rgba bytes (0x%x, 0x%x, 0x%x, 0x%x), " % bytes + "Z %f, glname 0x%x" % (pixZ, glname) ) pass ### XXX This ought to be better-merged with the DL selection below. if glname: obj = self.object_for_glselect_name(glname) if debugPicking: print "shader mouseover glname=%r, obj=%r." % (glname, obj) if obj is None: # REVIEW: does this happen for mouse over a non-shader primitive? # [bruce 090105 question] #### Note: this bug is common. Guess: we are still drawing # ordinary colors for some primitives and/or for the # background, and they are showing up here and confusing # us. To help debug this, print the color too. But testing # shows it's not so simple -- e.g. for rung bonds it happens # where shader sphere and cylinder overlap, but not on either # one alone; for strand bonds it also happens on the bonds alone # (tested in Build DNA, in or not in Insert DNA). # [bruce 090218] # # Update: Since it's so common, I need to turn it off by default. # Q: is the situation safe? # A: if a color looks like a real glname by accident, # we'll get some random candidate object -- perhaps a killed one # or from a different Part or even a closed assy -- # and try to draw it. That doesn't sound very safe. Unfortunately # there is no perfect way to filter selobjs for safety, in the # current still-informal Selobj_API. The best approximation is # selobj_still_ok, and it should always say yes for the usual kinds, # so I'll add it as a check in the 'else' clause below. # [bruce 090311] if debug_flags.atom_debug: print "bug: object_for_glselect_name returns None for glname %r (color %r)" % ( glname, bytes, ) else: if self.graphicsMode.selobj_still_ok(obj): # bruce 090311 added condition, explained above self.glselect_dict[id(obj)] = obj else: # This should be rare but possible. Leave it on briefly and see # if it's ever common. If possible, gate it by atom_debug before # the release. [bruce 090311] print "fyi: glname-color selobj %r rejected since not selobj_still_ok" % obj pass pass pass if self._use_frustum_culling: self._compute_frustum_planes() # piotr 080331 - the frustum planes have to be setup after the # projection matrix is setup. I'm not sure if there may # be any side effects - see the comment below about # possible optimization. glSelectBuffer(self.SIZE_FOR_glSelectBuffer) # Note: this allocates a new select buffer, # and glRenderMode(GL_RENDER) returns it and forgets it, # so it's required before *each* call of glRenderMode(GL_SELECT) + # glRenderMode(GL_RENDER), not just once to set the size. # Ref: http://pyopengl.sourceforge.net/documentation/opengl_diffs.html # [bruce 080923 comment] glInitNames() # REVIEW: should we also set up a clipping plane just behind the # hit point, as (I think) is done in ThumbView, to reduce the # number of candidate objects? This might be a significant # optimization, though I don't think it eliminates the chance # of having multiple candidates. [bruce 080917 comment] glRenderMode(GL_SELECT) glMatrixMode(GL_MODELVIEW) try: self.set_drawing_phase("glselect") # bruce 070124 for stereo_image in self.stereo_images_to_draw: self._enable_stereo(stereo_image) try: self._do_graphicsMode_Draw(for_mouseover_highlighting=True) finally: self._disable_stereo() except: print_compact_traceback( "exception in or around _do_graphicsMode_Draw() during GL_SELECT; " "ignored; restoring modelview matrix: " ) glMatrixMode(GL_MODELVIEW) self._setup_modelview() ### REVIEW: correctness of this is unreviewed! # now it's important to continue, at least enough to restore other gl state self._frustum_planes_available = False # piotr 080331 # just to be safe and not use the frustum planes computed for # the pick matrix self.set_drawing_phase("?") self.current_glselect = False # REVIEW: On systems with no stencil buffer, I think we'd also need # to draw selobj here in highlighted form (in case that form is # bigger than when it's not highlighted), or (easier & faster) # just always pretend it passes the hit test and add it to # glselect_dict -- and, make sure to give it "first dibs" for being # the next selobj. I'll implement some of this now (untested when # no stencil buffer) but not yet all. [bruce 050612] selobj = self.selobj if selobj is not None: self.glselect_dict[id(selobj)] = selobj # (review: is the following note correct?) # note: unneeded, if the func that looks at this dict always # tries selobj first (except for a kluge near # "if self.glselect_dict", commented on below) glFlush() hit_records = list(glRenderMode(GL_RENDER)) if debugPicking: print "DLs %d hits" % len(hit_records) for (near, far, names) in hit_records: # see example code, renderpass.py ## print "hit record: near, far, names:", near, far, names # e.g. hit record: near, far, names: 1439181696 1453030144 (1638426L,) # which proves that near/far are too far apart to give actual depth, # in spite of the 1- or 3-pixel drawing window (presumably they're vertices # taken from unclipped primitives, not clipped ones). del near, far if 1: # partial workaround for bug 1527. This can be removed once that bug (in drawer.py) # is properly fixed. This exists in two places -- GLPane.py and modes.py. [bruce 060217] if names and names[-1] == 0: print "%d(g) partial workaround for bug 1527: removing 0 from end of namestack:" % env.redraw_counter, names names = names[:-1] if names: # For now, we only use the last element of names, # though (as of long before 080917) it is often longer: # - some code pushes the same name twice (directly and # via ColorSorter) (see 060725 debug print below); # - chunks push a name even when they draw atoms/bonds # which push their own names (see 080411 comment below). # # Someday: if we ever support "name/subname paths" we'll # probably let first name interpret the remaining ones. # In fact, if nodes change projection or viewport for # their kids, and/or share their kids, they'd need to # push their own names on the stack, so we'd know how # to redraw the kids, or which ones are meant when they # are shared. if debug_flags.atom_debug and len(names) > 1: # bruce 060725 if len(names) == 2 and names[0] == names[1]: if not env.seen_before("dual-names bug"): # this happens for Atoms (colorsorter bug??) print "debug (once-per-session message): why are some glnames duplicated on the namestack?", names else: # Note: as of sometime before 080411, this became common -- # I guess that chunks (which recently acquired glselect names) # are pushing their names even while drawing their atoms and bonds. # I am not sure if this can cause any problems -- almost surely not # directly, but maybe the nestedness of highlighted appearances could # violate some assumptions made by the highlight code... anyway, # to reduce verbosity I need to not print this when the deeper name # is that of a chunk, and there are exactly two names. [bruce 080411] if len(names) == 2 and isinstance(self.object_for_glselect_name(names[0]), self.assy.Chunk): if not env.seen_before("nested names for Chunk"): print "debug (once-per-session message): nested glnames for a Chunk: ", names else: print "debug fyi: len(names) == %d (names = %r)" % (len(names), names) obj = self.object_for_glselect_name(names[-1]) # k should always return an obj if obj is None: print "bug: object_for_glselect_name returns None for name %r at end of namestack %r" % ( names[-1], names, ) else: self.glselect_dict[id(obj)] = obj # note: outside of this method, one of these will be # chosen to be saved as self.selobj and rerendered # in "highlighted" form ##if 0: ## # this debug print was useful for debugging bug 2945, ## # and when it happens it's usually a bug, ## # but not always: ## # - it's predicted to happen for ChunkDrawer._renderOverlayText ## # - and whenever we're using a whole-chunk display style ## # so we can't leave it in permanently. [bruce 081211] ## if isinstance( obj, self.assy.Chunk ): ## print "\n*** namestack topped with a chunk:", obj pass continue # next hit_record # e maybe we should now sort glselect_dict by "hit priority" # (for depth-tiebreaking), or at least put selobj first. # (or this could be done lower down, where it's used.) # [I think we do this now...] return # from do_glselect_if_wanted
def get_gl_info_string(glpane): # grantham 20051129 """ Return a string containing some useful information about the OpenGL implementation. Use the GL context from the given QGLWidget glpane (by calling glpane.makeCurrent()). """ glpane.makeCurrent() #bruce 070308 added glpane arg and makeCurrent call gl_info_string = '' gl_info_string += 'GL_VENDOR : "%s"\n' % glGetString(GL_VENDOR) gl_info_string += 'GL_VERSION : "%s"\n' % glGetString(GL_VERSION) gl_info_string += 'GL_RENDERER : "%s"\n' % glGetString(GL_RENDERER) gl_extensions = glGetString(GL_EXTENSIONS) gl_extensions = gl_extensions.strip() gl_extensions = gl_extensions.replace(" ", "\n* ") gl_info_string += 'GL_EXTENSIONS : \n* %s\n' % gl_extensions if debug_pref("Graphics Card Info: call glAreTexturesResident?", Choice_boolean_False): # Give a practical indication of how much video memory is available. # Should also do this with VBOs. # I'm pretty sure this code is right, but PyOpenGL seg faults in # glAreTexturesResident, so it's disabled until I can figure that # out. [grantham] [bruce 070308 added the debug_pref] all_tex_in = True tex_bytes = '\0' * (512 * 512 * 4) tex_names = [] tex_count = 0 tex_names = glGenTextures(1024) glEnable(GL_TEXTURE_2D) while all_tex_in: glBindTexture(GL_TEXTURE_2D, tex_names[tex_count]) gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, tex_bytes) tex_count += 1 glTexCoord2f(0.0, 0.0) glBegin(GL_QUADS) glVertex2f(0.0, 0.0) glVertex2f(1.0, 0.0) glVertex2f(1.0, 1.0) glVertex2f(0.0, 1.0) glEnd() glFinish() residences = glAreTexturesResident(tex_names[:tex_count]) all_tex_in = reduce(lambda a,b: a and b, residences) # bruce 070308 sees this exception from this line: # TypeError: reduce() arg 2 must support iteration glDisable(GL_TEXTURE_2D) glDeleteTextures(tex_names) gl_info_string += "Could create %d 512x512 RGBA resident textures\n" \ % tex_count pass if True: ## or could be a debug_pref("Graphics Card Info: get all GL_MAX symbols?") #bruce 090314 new feature import OpenGL.GL symbols = [x for x in dir(OpenGL.GL) if x.startswith('GL_MAX_')] symbols.sort() gl_info_string += '\n' for symbol in symbols: try: numeric_symbol = getattr(OpenGL.GL, symbol) intval = glGetInteger(numeric_symbol) except: # this happens to most symbols, not sure why if debug_flags.atom_debug: print_compact_traceback( "%s = ??: " % symbol ) # overkill, only the exception itself matters # typical output (on Bruce's MacBookPro, 090314): ## GL_MAX_4D_TEXTURE_SIZE_SGIS = ??: ## <type 'exceptions.KeyError'>: ## ('Unknown specifier GL_MAX_4D_TEXTURE_SIZE_SGIS (33080)', ## 'Failure in cConverter <OpenGL.converters.SizedOutput object at 0x1457fab0>', ## [GL_MAX_4D_TEXTURE_SIZE_SGIS], 1, <OpenGL.wrapper.glGetIntegerv object at 0x1458aa30>) ## [graphics_card_info.py:122] [wrapper.py:676] [converters.py:195] [converters.py:234] pass pass ## gl_info_string += "%s = ??\n" % symbol else: gl_info_string += "%s = %r\n" % (symbol, intval) continue pass return gl_info_string
def check_GL_support(gldrawable, glcontext, min_texture_size=0, force_enable=False): if not gldrawable.gl_begin(glcontext): raise ImportError("gl_begin failed on %s" % gldrawable) props = {} try: #log redirection: def redirect_log(logger_name): logger = logging.getLogger(logger_name) assert logger is not None logger.saved_handlers = logger.handlers logger.saved_propagate = logger.propagate logger.handlers = [CaptureHandler()] logger.propagate = 0 return logger fhlogger = redirect_log('OpenGL.formathandler') elogger = redirect_log('OpenGL.extensions') alogger = redirect_log('OpenGL.acceleratesupport') arlogger = redirect_log('OpenGL.arrays') clogger = redirect_log('OpenGL.converters') import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger gl_version_str = glGetString(GL_VERSION) if gl_version_str is None: gl_check_error("OpenGL version is missing - cannot continue") return {} gl_major = int(gl_version_str[0]) gl_minor = int(gl_version_str[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1,1) if (gl_major, gl_minor) < MIN_VERSION: gl_check_error("OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: log("found valid OpenGL version: %s.%s", gl_major, gl_minor) from OpenGL import version as OpenGL_version try: import OpenGL_accelerate except: OpenGL_accelerate = None props["zerocopy"] = is_pyopengl_memoryview_safe(OpenGL_version.__version__) and bool(OpenGL_accelerate) try: extensions = glGetString(GL_EXTENSIONS).split(" ") except: extensions = [] gl_check_error("OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?") log("OpenGL extensions found: %s", ", ".join(extensions)) props["extensions"] = extensions from OpenGL.arrays.arraydatatype import ArrayDatatype try: log("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values())) except: pass from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION for d,s,fatal in (("vendor", GL_VENDOR, True), ("renderer", GL_RENDERER, True), ("shading language version", GL_SHADING_LANGUAGE_VERSION, False)): try: v = glGetString(s) log("%s: %s", d, v) except: if fatal: gl_check_error("OpenGL property '%s' is missing" % d) else: log("OpenGL property '%s' is missing", d) v = "" props[d] = v from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d,s in {"GLU version": GLU_VERSION, "GLU extensions":GLU_EXTENSIONS}.items(): v = gluGetString(s) log("%s: %s", d, v) props[d] = v blacklisted = None whitelisted = None for k,vlist in BLACKLIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in blacklist: %s", k, v, vlist) blacklisted = k, v for k,vlist in WHITELIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in whitelist: %s", k, v, vlist) whitelisted = k, v if blacklisted: if whitelisted: log.info("%s '%s' enabled (found in both blacklist and whitelist)", *whitelisted) elif force_enable: log.warn("Warning: %s '%s' is blacklisted!", *blacklisted) else: gl_check_error("%s '%s' is blacklisted!" % (blacklisted)) #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) glEnablei = None try: from OpenGL.GL import glEnablei except: pass if not bool(glEnablei): log.warn("OpenGL glEnablei is not available, disabling transparency") global GL_ALPHA_SUPPORTED GL_ALPHA_SUPPORTED = False #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) for ext in required_extensions: if ext not in extensions: gl_check_error("OpenGL driver lacks support for extension: %s" % ext) else: log("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): gl_check_error("OpenGL output requires glInitFragmentProgramARB") else: log("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): gl_check_error("OpenGL output requires glInitTextureRectangleARB") else: log("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) try: from OpenGL.GL import GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) #this one may be missing? rect_texture_size = texture_size try: from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) except ImportError, e: log("OpenGL: %s", e) log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size) except Exception, e: emsg = str(e) if hasattr(e, "description"): emsg = e.description gl_check_error("unable to query max texture size: %s" % emsg) return props if min_texture_size>texture_size or min_texture_size>rect_texture_size: gl_check_error("The texture size is too small: %s" % texture_size) else: log("Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size) props["texture-size-limit"] = min(rect_texture_size, texture_size) return props
def do_check_GL_support(force_enable): props = {} try: #log redirection: def redirect_log(logger_name): logger = logging.getLogger(logger_name) assert logger is not None logger.saved_handlers = logger.handlers logger.saved_propagate = logger.propagate logger.handlers = [CaptureHandler()] logger.propagate = 0 return logger fhlogger = redirect_log('OpenGL.formathandler') elogger = redirect_log('OpenGL.extensions') alogger = redirect_log('OpenGL.acceleratesupport') arlogger = redirect_log('OpenGL.arrays') clogger = redirect_log('OpenGL.converters') import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger gl_version_str = glGetString(GL_VERSION) if gl_version_str is None: gl_check_error("OpenGL version is missing - cannot continue") return {} gl_major = int(gl_version_str[0]) gl_minor = int(gl_version_str[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1, 1) if (gl_major, gl_minor) < MIN_VERSION: gl_check_error( "OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: log("found valid OpenGL version: %s.%s", gl_major, gl_minor) from OpenGL import version as OpenGL_version try: import OpenGL_accelerate except: OpenGL_accelerate = None props["zerocopy"] = is_pyopengl_memoryview_safe( OpenGL_version.__version__) and bool(OpenGL_accelerate) try: extensions = glGetString(GL_EXTENSIONS).decode().split(" ") except: log("error querying extensions", exc_info=True) extensions = [] gl_check_error( "OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?" ) log("OpenGL extensions found: %s", ", ".join(extensions)) props["extensions"] = extensions from OpenGL.arrays.arraydatatype import ArrayDatatype try: log("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values())) except: pass from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION for d, s, fatal in (("vendor", GL_VENDOR, True), ("renderer", GL_RENDERER, True), ("shading language version", GL_SHADING_LANGUAGE_VERSION, False)): try: v = glGetString(s) v = v.decode() log("%s: %s", d, v) except: if fatal: gl_check_error("OpenGL property '%s' is missing" % d) else: log("OpenGL property '%s' is missing", d) v = "" props[d] = v from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d, s in { "GLU version": GLU_VERSION, "GLU extensions": GLU_EXTENSIONS }.items(): v = gluGetString(s) v = v.decode() log("%s: %s", d, v) props[d] = v blacklisted = None whitelisted = None greylisted = None for k, vlist in BLACKLIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in blacklist: %s", k, v, vlist) blacklisted = k, v for k, vlist in GREYLIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in greylist: %s", k, v, vlist) greylisted = k, v for k, vlist in WHITELIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in whitelist: %s", k, v, vlist) whitelisted = k, v if blacklisted: if whitelisted: log.info( "%s '%s' enabled (found in both blacklist and whitelist)", *whitelisted) elif force_enable: log.warn("Warning: %s '%s' is blacklisted!", *blacklisted) else: gl_check_error("%s '%s' is blacklisted!" % (blacklisted)) safe = bool(whitelisted) or not (bool(greylisted) or bool(blacklisted)) if safe and sys.version_info[0] > 2: log.warn( "Warning: OpenGL python3 support is not enabled by default") safe = False props["safe"] = safe #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) glEnablei = None try: from OpenGL.GL import glEnablei except: pass if not bool(glEnablei): log.warn( "OpenGL glEnablei is not available, disabling transparency") global GL_ALPHA_SUPPORTED GL_ALPHA_SUPPORTED = False #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) for ext in required_extensions: if ext not in extensions: gl_check_error( "OpenGL driver lacks support for extension: %s" % ext) else: log("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): gl_check_error("OpenGL output requires glInitFragmentProgramARB") else: log("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): gl_check_error("OpenGL output requires glInitTextureRectangleARB") else: log("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) try: from OpenGL.GL import GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) #this one may be missing? rect_texture_size = texture_size try: from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) except ImportError as e: log("OpenGL: %s", e) log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size) except Exception as e: emsg = str(e) if hasattr(e, "description"): emsg = e.description gl_check_error("unable to query max texture size: %s" % emsg) return props log( "Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size) props["texture-size-limit"] = min(rect_texture_size, texture_size) return props finally: for x in alogger.handlers[0].records: #strip default message prefix: msg = x.getMessage().replace( "No OpenGL_accelerate module loaded: ", "") if msg == "No module named OpenGL_accelerate": msg = "missing accelerate module" if msg != "OpenGL_accelerate module loaded": msg = "PyOpenGL warning: %s" % msg log.info(msg) #format handler messages: STRIP_LOG_MESSAGE = "Unable to load registered array format handler " missing_handlers = [] for x in fhlogger.handlers[0].records: msg = x.getMessage() p = msg.find(STRIP_LOG_MESSAGE) if p < 0: #unknown message, log it: log.info(msg) continue format_handler = msg[p + len(STRIP_LOG_MESSAGE):] p = format_handler.find(":") if p > 0: format_handler = format_handler[:p] missing_handlers.append(format_handler) if len(missing_handlers) > 0: log.warn("PyOpenGL warning: missing array format handlers: %s", ", ".join(missing_handlers)) for x in elogger.handlers[0].records: msg = x.getMessage() #ignore extension messages: p = msg.startswith("GL Extension ") and msg.endswith("available") if not p: log.info(msg) missing_accelerators = [] STRIP_AR_HEAD = "Unable to load" STRIP_AR_TAIL = "from OpenGL_accelerate" for x in arlogger.handlers[0].records + clogger.handlers[0].records: msg = x.getMessage() if msg.startswith(STRIP_AR_HEAD) and msg.endswith(STRIP_AR_TAIL): m = msg[len(STRIP_AR_HEAD):-len(STRIP_AR_TAIL)].strip() m = m.replace("accelerators", "").replace("accelerator", "").strip() missing_accelerators.append(m) continue log.info(msg) if missing_accelerators: log.info("OpenGL accelerate missing: %s", ", ".join(missing_accelerators)) def restore_logger(logger): logger.handlers = logger.saved_handlers logger.propagate = logger.saved_propagate restore_logger(fhlogger) restore_logger(elogger) restore_logger(alogger) restore_logger(arlogger) restore_logger(clogger)
def maybeTip(self, helpEvent): """ Determines if this tooltip should be displayed. The tooltip will be displayed at helpEvent.globalPos() if an object is highlighted and the mouse hasn't moved for some period of time, called the "wake up delay" period, which is a user pref (not yet implemented in the Preferences dialog) currently set to 1 second. maybeTip() is called by GLPane.timerEvent() whenever the cursor is not moving to determine if the tooltip should be displayed. @param helpEvent: a QHelpEvent constructed by the caller @type helpEvent: QHelpEvent """ # docstring used to also say: ## For more details about this member, see Qt documentation on QToolTip.maybeTip(). # but this is unclear to me (since this class does not inherit from # QToolTip), so I removed it. [bruce 081208] debug = debug_pref("GLPane: graphics debug tooltip?", Choice_boolean_False, prefs_key = True ) glpane = self.glpane selobj = glpane.selobj if debug: # russ 080715: Graphics debug tooltip. # bruce 081208/081211: revised, moved out of _getToolTipText, # made debug_pref. # note: we don't use glpane.MousePos since it's not reliable -- # only some graphicsModes store it, and only in mouse press events. # Note: double buffering applies only to the color buffer, # not the stencil or depth buffers, which have only one copy. # The setting of GL_READ_BUFFER should have no effect on # glReadPixelsf from those buffers. # [bruce 081211 comment, based on Russ report of OpenGL doc] pos = helpEvent.pos() wX = pos.x() wY = glpane.height - pos.y() #review: off by 1?? wZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT)[0][0] stencil = glReadPixelsi(wX, wY, 1, 1, GL_STENCIL_INDEX)[0][0] savebuff = glGetInteger(GL_READ_BUFFER) whichbuff = {GL_FRONT:"front", GL_BACK:"back"}.get(savebuff, "unknown") redraw_counter = env.redraw_counter # Pixel data is sign-wrapped, in spite of specifying unsigned_byte. def us(b): if b < 0: return 256 + b else: return b def pixvals(buff): glReadBuffer(buff) gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE rgba = glReadPixels( wX, wY, 1, 1, gl_format, gl_type )[0][0] return ( "rgba %u, %u, %u, %u" % (us(rgba[0]), us(rgba[1]), us(rgba[2]), us(rgba[3])) ) def redifnot(v1, v2, text): if v1 != v2: return redmsg(text) else: return text front_pixvals = pixvals(GL_FRONT) back_pixvals = pixvals(GL_BACK) glReadBuffer(savebuff) # restore the saved value tipText = ( "env.redraw = %d; selobj = %s<br>" % (redraw_counter, quote_html(str(selobj)),) + # note: sometimes selobj is an instance of _UNKNOWN_SELOBJ_class... relates to testmode bug from renderText # (confirmed that renderText zaps stencil and that that alone causes no bug in other graphicsmodes) # TODO: I suspect this can be printed even during rendering... need to print glpane variables # which indicate whether we're doing rendering now, e.g. current_glselect, drawing_phase; # also modkeys (sp?), glselect_wanted "mouse position (xy): %d, %d<br>" % (wX, wY,) + "depth %f, stencil %d<br>" % (wZ, stencil) + redifnot(whichbuff, "back", "current read buffer: %s<br>" % whichbuff ) + redifnot(glpane.glselect_wanted, 0, "glselect_wanted: %s<br>" % (glpane.glselect_wanted,) ) + redifnot(glpane.current_glselect, False, "current_glselect: %s<br>" % (glpane.current_glselect,) ) + redifnot(glpane.drawing_phase, "?", "drawing_phase: %s<br>" % (glpane.drawing_phase,) ) + "front: " + front_pixvals + "<br>" + redifnot(back_pixvals, front_pixvals, "back: " + back_pixvals ) ) global _last_tipText if tipText != _last_tipText: print print tipText _last_tipText = tipText pass # use tipText below else: # <motionlessCursorDuration> is the amount of time the cursor (mouse) has been motionless. motionlessCursorDuration = time.time() - glpane.cursorMotionlessStartTime # Don't display the tooltip yet if <motionlessCursorDuration> hasn't exceeded the "wake up delay". # The wake up delay is currently set to 1 second in prefs_constants.py. Mark 060818. if motionlessCursorDuration < env.prefs[dynamicToolTipWakeUpDelay_prefs_key]: self.toolTipShown = False return # If an object is not currently highlighted, don't display a tooltip. if not selobj: return # If the highlighted object is a singlet, # don't display a tooltip for it. if isinstance(selobj, Atom) and (selobj.element is Singlet): return if self.toolTipShown: # The tooltip is already displayed, so return. # Do not allow tip() to be called again or it will "flash". return tipText = self._getToolTipText() pass # show the tipText if not tipText: tipText = "" # This makes sure that dynamic tip is not displayed when # the highlightable object is 'unknown' to the dynamic tip class. # (From QToolTip.showText doc: "If text is empty the tool tip is hidden.") showpos = helpEvent.globalPos() if debug: # show it a little lower to avoid the cursor obscuring the tooltip. # (might be useful even when not debugging, depending on the cursor) # [bruce 081208] showpos = showpos + QPoint(0, 10) QToolTip.showText(showpos, tipText) #@@@ ninad061107 works fine but need code review self.toolTipShown = True
def GetMaxTextureSize(): maxTxtrSize = glGetInteger(GL_MAX_TEXTURE_SIZE); # print "MAX_TEXTURE_SIZE:", maxTxtrSize if maxTxtrSize == 0: maxTxtrSize = 4096 return maxTxtrSize
def do_check_GL_support(force_enable): props = {} try: #log redirection: def redirect_log(logger_name): logger = logging.getLogger(logger_name) assert logger is not None logger.saved_handlers = logger.handlers logger.saved_propagate = logger.propagate logger.handlers = [CaptureHandler()] logger.propagate = 0 return logger fhlogger = redirect_log('OpenGL.formathandler') elogger = redirect_log('OpenGL.extensions') alogger = redirect_log('OpenGL.acceleratesupport') arlogger = redirect_log('OpenGL.arrays') clogger = redirect_log('OpenGL.converters') import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger, glGetIntegerv gl_version_str = glGetString(GL_VERSION) if gl_version_str is None: gl_check_error("OpenGL version is missing - cannot continue") return {} gl_major = int(gl_version_str[0]) gl_minor = int(gl_version_str[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1,1) if (gl_major, gl_minor) < MIN_VERSION: gl_check_error("OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: log("found valid OpenGL version: %s.%s", gl_major, gl_minor) from OpenGL import version as OpenGL_version pyopengl_version = OpenGL_version.__version__ try: import OpenGL_accelerate accel_version = OpenGL_accelerate.__version__ props["accelerate"] = accel_version log("OpenGL_accelerate version %s", accel_version) except: log("OpenGL_accelerate not found") OpenGL_accelerate = None accel_version = None if accel_version is not None and pyopengl_version!=accel_version: global _version_warning_shown if not _version_warning_shown: log.warn("Warning: version mismatch between PyOpenGL and PyOpenGL-accelerate") log.warn(" this may cause crashes") _version_warning_shown = True vsplit = pyopengl_version.split('.') #we now require PyOpenGL 3.1 or later if vsplit[:2]<['3','1'] and not force_enable: gl_check_error("PyOpenGL version 3.1 or later is required (found version %s)" % pyopengl_version) return {} props["zerocopy"] = bool(OpenGL_accelerate) and is_pyopengl_memoryview_safe(pyopengl_version, accel_version) try: extensions = glGetString(GL_EXTENSIONS).decode().split(" ") except: log("error querying extensions", exc_info=True) extensions = [] gl_check_error("OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?") log("OpenGL extensions found: %s", ", ".join(extensions)) props["extensions"] = extensions from OpenGL.arrays.arraydatatype import ArrayDatatype try: log("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values())) except: pass from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION def fixstring(v): try: return str(v).strip() except: return str(v) for d,s,fatal in (("vendor", GL_VENDOR, True), ("renderer", GL_RENDERER, True), ("shading language version", GL_SHADING_LANGUAGE_VERSION, False)): try: v = glGetString(s) v = fixstring(v.decode()) log("%s: %s", d, v) except: if fatal: gl_check_error("OpenGL property '%s' is missing" % d) else: log("OpenGL property '%s' is missing", d) v = "" props[d] = v vendor = props["vendor"] version_req = VERSION_REQ.get(vendor) if version_req: req_maj, req_min = version_req if gl_major<req_maj or (gl_major==req_maj and gl_minor<req_min): if force_enable: log.warn("Warning: '%s' OpenGL driver requires version %i.%i", vendor, req_maj, req_min) log.warn(" version %i.%i was found", gl_major, gl_minor) else: gl_check_error("OpenGL version %i.%i is too old, %i.%i is required for %s" % (gl_major, gl_minor, req_maj, req_min, vendor)) from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d,s in {"GLU version": GLU_VERSION, "GLU extensions":GLU_EXTENSIONS}.items(): v = gluGetString(s) v = v.decode() log("%s: %s", d, v) props[d] = v blacklisted = None whitelisted = None greylisted = None for k,vlist in BLACKLIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in blacklist: %s", k, v, vlist) blacklisted = k, v for k,vlist in GREYLIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in greylist: %s", k, v, vlist) greylisted = k, v for k,vlist in WHITELIST.items(): v = props.get(k) if v in vlist: log("%s '%s' found in whitelist: %s", k, v, vlist) whitelisted = k, v if blacklisted: if whitelisted: log.info("%s '%s' enabled (found in both blacklist and whitelist)", *whitelisted) elif force_enable: log.warn("Warning: %s '%s' is blacklisted!", *blacklisted) else: gl_check_error("%s '%s' is blacklisted!" % (blacklisted)) safe = bool(whitelisted) or not (bool(greylisted) or bool(blacklisted)) if safe and sys.version_info[0]>2: log.warn("Warning: OpenGL python3 support is not enabled by default") safe = False props["safe"] = safe #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) glEnablei = None try: from OpenGL.GL import glEnablei except: pass if not bool(glEnablei): log.warn("OpenGL glEnablei is not available, disabling transparency") global GL_ALPHA_SUPPORTED GL_ALPHA_SUPPORTED = False props["transparency"] = GL_ALPHA_SUPPORTED #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) for ext in required_extensions: if ext not in extensions: gl_check_error("OpenGL driver lacks support for extension: %s" % ext) else: log("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): gl_check_error("OpenGL output requires glInitFragmentProgramARB") else: log("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): gl_check_error("OpenGL output requires glInitTextureRectangleARB") else: log("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) try: from OpenGL.GL import GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) #this one may be missing? rect_texture_size = texture_size try: from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) except ImportError as e: log("OpenGL: %s", e) log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size) except Exception as e: emsg = str(e) if hasattr(e, "description"): emsg = e.description gl_check_error("unable to query max texture size: %s" % emsg) return props log("Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size) texture_size_limit = min(rect_texture_size, texture_size) props["texture-size-limit"] = texture_size_limit try: from OpenGL.GL import GL_MAX_VIEWPORT_DIMS v = glGetIntegerv(GL_MAX_VIEWPORT_DIMS) max_viewport_dims = v[0], v[1] assert max_viewport_dims[0]>=texture_size_limit and max_viewport_dims[1]>=texture_size_limit log("GL_MAX_VIEWPORT_DIMS=%s", max_viewport_dims) except ImportError as e: log.error("Error querying max viewport dims: %s", e) max_viewport_dims = texture_size_limit, texture_size_limit props["max-viewport-dims"] = max_viewport_dims return props finally: for x in alogger.handlers[0].records: #strip default message prefix: msg = x.getMessage().replace("No OpenGL_accelerate module loaded: ", "") if msg=="No module named OpenGL_accelerate": msg = "missing accelerate module" if msg!="OpenGL_accelerate module loaded": msg = "PyOpenGL warning: %s" % msg log.info(msg) #format handler messages: STRIP_LOG_MESSAGE = "Unable to load registered array format handler " missing_handlers = [] for x in fhlogger.handlers[0].records: msg = x.getMessage() p = msg.find(STRIP_LOG_MESSAGE) if p<0: #unknown message, log it: log.info(msg) continue format_handler = msg[p+len(STRIP_LOG_MESSAGE):] p = format_handler.find(":") if p>0: format_handler = format_handler[:p] missing_handlers.append(format_handler) if len(missing_handlers)>0: log.warn("PyOpenGL warning: missing array format handlers: %s", ", ".join(missing_handlers)) for x in elogger.handlers[0].records: msg = x.getMessage() #ignore extension messages: p = msg.startswith("GL Extension ") and msg.endswith("available") if not p: log.info(msg) missing_accelerators = [] STRIP_AR_HEAD = "Unable to load" STRIP_AR_TAIL = "from OpenGL_accelerate" for x in arlogger.handlers[0].records+clogger.handlers[0].records: msg = x.getMessage() if msg.startswith(STRIP_AR_HEAD) and msg.endswith(STRIP_AR_TAIL): m = msg[len(STRIP_AR_HEAD):-len(STRIP_AR_TAIL)].strip() m = m.replace("accelerators", "").replace("accelerator", "").strip() missing_accelerators.append(m) continue elif msg.startswith("Using accelerated"): log(msg) else: log.info(msg) if missing_accelerators: log.info("OpenGL accelerate missing: %s", ", ".join(missing_accelerators)) def restore_logger(logger): logger.handlers = logger.saved_handlers logger.propagate = logger.saved_propagate restore_logger(fhlogger) restore_logger(elogger) restore_logger(alogger) restore_logger(arlogger) restore_logger(clogger)
def check_GL_support(gldrawable, glcontext, min_texture_size=0, force_enable=False): if not gldrawable.gl_begin(glcontext): raise ImportError("gl_begin failed on %s" % gldrawable) props = {} try: #log redirection: def redirect_log(logger_name): logger = logging.getLogger(logger_name) assert logger is not None logger.saved_handlers = logger.handlers logger.saved_propagate = logger.propagate logger.handlers = [CaptureHandler()] logger.propagate = 0 return logger fhlogger = redirect_log('OpenGL.formathandler') elogger = redirect_log('OpenGL.extensions') alogger = redirect_log('OpenGL.acceleratesupport') arlogger = redirect_log('OpenGL.arrays') clogger = redirect_log('OpenGL.converters') import OpenGL props["pyopengl"] = OpenGL.__version__ from OpenGL.GL import GL_VERSION, GL_EXTENSIONS from OpenGL.GL import glGetString, glGetInteger gl_version_str = glGetString(GL_VERSION) if gl_version_str is None: gl_check_error("OpenGL version is missing - cannot continue") return {} gl_major = int(gl_version_str[0]) gl_minor = int(gl_version_str[2]) props["opengl"] = gl_major, gl_minor MIN_VERSION = (1, 1) if (gl_major, gl_minor) < MIN_VERSION: gl_check_error( "OpenGL output requires version %s or greater, not %s.%s" % (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor)) else: log("found valid OpenGL version: %s.%s", gl_major, gl_minor) try: extensions = glGetString(GL_EXTENSIONS).split(" ") except: gl_check_error( "OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?" ) log("OpenGL extensions found: %s", ", ".join(extensions)) props["extensions"] = extensions from OpenGL.arrays.arraydatatype import ArrayDatatype try: log("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values())) except: pass from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION for d, s, fatal in (("vendor", GL_VENDOR, True), ("renderer", GL_RENDERER, True), ("shading language version", GL_SHADING_LANGUAGE_VERSION, False)): try: v = glGetString(s) log("%s: %s", d, v) except: if fatal: gl_check_error("OpenGL property '%s' is missing" % d) else: log.warn("OpenGL property '%s' is missing" % d) v = "" props[d] = v from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS for d, s in { "GLU version": GLU_VERSION, "GLU extensions": GLU_EXTENSIONS }.items(): v = gluGetString(s) log("%s: %s", d, v) props[d] = v for k, vlist in BLACKLIST.items(): v = props.get(k) if v in vlist: if force_enable: log.warn("Warning: %s '%s' is blacklisted!", k, v) else: gl_check_error("%s '%s' is blacklisted!" % (k, v)) #check for specific functions we need: from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \ glViewport, glMatrixMode, glLoadIdentity, glOrtho, \ glEnableClientState, glGenTextures, glDisable, \ glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \ glTexParameteri, \ glTexImage2D, \ glMultiTexCoord2i, \ glVertex2i, glEnd) glEnablei = None try: from OpenGL.GL import glEnablei except: pass if not bool(glEnablei): log.warn( "OpenGL glEnablei is not available, disabling transparency") global GL_ALPHA_SUPPORTED GL_ALPHA_SUPPORTED = False #check for framebuffer functions we need: from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D check_functions(GL_FRAMEBUFFER, \ GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D) for ext in required_extensions: if ext not in extensions: gl_check_error( "OpenGL driver lacks support for extension: %s" % ext) else: log("Extension %s is present", ext) #this allows us to do CSC via OpenGL: #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB if not glInitFragmentProgramARB(): gl_check_error("OpenGL output requires glInitFragmentProgramARB") else: log("glInitFragmentProgramARB works") from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB if not glInitTextureRectangleARB(): gl_check_error("OpenGL output requires glInitTextureRectangleARB") else: log("glInitTextureRectangleARB works") from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \ glBindProgramARB, glProgramStringARB check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB) try: from OpenGL.GL import GL_MAX_TEXTURE_SIZE texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE) #this one may be missing? rect_texture_size = texture_size try: from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE) except ImportError, e: log("OpenGL: %s", e) log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size) except Exception, e: emsg = str(e) if hasattr(e, "description"): emsg = e.description gl_check_error("unable to query max texture size: %s" % emsg) return props if min_texture_size > texture_size or min_texture_size > rect_texture_size: gl_check_error("The texture size is too small: %s" % texture_size) else: log( "Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size) return props
def do_glselect_if_wanted(self): #bruce 070919 split this out """ Do the glRenderMode(GL_SELECT) drawing, and/or the glname-color drawing for shader primitives, used to guess which object might be under the mouse, for one drawing frame, if desired for this frame. Report results by storing candidate mouseover objects in self.glselect_dict. The depth buffer is initially clear, and must be clear when we're done as well. @note: does not do related individual object depth/stencil buffer drawing -- caller must do that on some or all of the objects we store into self.glselect_dict. """ if self.glselect_wanted: # note: this will be reset below. ###@@@ WARNING: The original code for this, here in GLPane, has been duplicated and slightly modified # in at least three other places (search for glRenderMode to find them). This is bad; common code # should be used. Furthermore, I suspect it's sometimes needlessly called more than once per frame; # that should be fixed too. [bruce 060721 comment] wX, wY, self.targetdepth = self.glselect_wanted # wX, wY is the point to do the hit-test at # targetdepth is the depth buffer value to look for at that point, during ordinary drawing phase # (could also be used to set up clipping planes to further restrict hit-test, but this isn't yet done) # (Warning: targetdepth could in theory be out of date, if more events come between bareMotion # and the one caused by its gl_update, whose paintGL is what's running now, and if those events # move what's drawn. Maybe that could happen with mousewheel events or (someday) with keypresses # having a graphical effect. Ideally we'd count intentional redraws, and disable this picking in that case.) self.wX, self.wY = wX, wY self.glselect_wanted = 0 pwSize = 1 # Pick window size. Russ 081128: Was 3. # Bruce: Replace 3, 3 with 1, 1? 5, 5? not sure whether this will # matter... in principle should have no effect except speed. # Russ: For glname rendering, 1x1 is better because it doesn't # have window boundary issues. We get the coords of a single # pixel in the window for the mouse position. #bruce 050615 for use by nodes which want to set up their own projection matrix. self.current_glselect = (wX, wY, pwSize, pwSize) self._setup_projection(glselect=self.current_glselect ) # option makes it use gluPickMatrix # Russ 081209: Added. debugPicking = debug_pref("GLPane: debug mouseover picking?", Choice_boolean_False, prefs_key=True) if self.enabled_shaders(): # TODO: optimization: find an appropriate place to call # _compute_frustum_planes. [bruce 090105 comment] # Russ 081122: There seems to be no way to access the GL name # stack in shaders. Instead, for mouseover, draw shader # primitives with glnames as colors in glRenderMode(GL_RENDER), # then read back the pixel color (glname) and depth value. # Temporarily replace the full-size viewport with a little one # at the mouse location, matching the pick matrix location. # Otherwise, we will draw a closeup of that area into the whole # window, rather than a few pixels. (This wasn't needed when we # only used GL_SELECT rendering mode here, because that doesn't # modify the frame buffer -- it just returns hits by graphics # primitives when they are inside the clipping boundaries.) # # (Don't set the viewport *before* _setup_projection(), since # that method needs to read the current whole-window viewport # to set up glselect. See explanation in its docstring.) savedViewport = glGetIntegerv(GL_VIEWPORT) glViewport(wX, wY, pwSize, pwSize) # Same as current_glselect. # First, clear the pixel RGBA to zeros and a depth of 1.0 (far), # so we won't confuse a color with a glname if there are # no shader primitives drawn over this pixel. saveDepthFunc = glGetInteger(GL_DEPTH_FUNC) glDepthFunc(GL_ALWAYS) glWindowPos3i(wX, wY, 1) # Note the Z coord. gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0)) glDepthFunc( saveDepthFunc) # needed, though we'll change it again # We must be in glRenderMode(GL_RENDER) (as usual) when this is called. # Note: _setup_projection leaves the matrix mode as GL_PROJECTION. glMatrixMode(GL_MODELVIEW) shaders = self.enabled_shaders() try: # Set flags so that we will use glnames-as-color mode # in shaders, and draw only shader primitives. # (Ideally we would also draw all non-shader primitives # as some other color, unequal to all glname colors # (or derived from a fake glname for that purpose), # in order to obscure shader primitives where appropriate. # This is intended to be done but is not yet implemented. # [bruce 090105 addendum]) for shader in shaders: shader.setPicking(True) self.set_drawing_phase("glselect_glname_color") for stereo_image in self.stereo_images_to_draw: self._enable_stereo(stereo_image) try: self._do_graphicsMode_Draw( for_mouseover_highlighting=True) # note: we can't disable depth writing here, # since we need it to make sure the correct # shader object comes out on top, or is # obscured by a DL object. Instead, we'll # clear the depth buffer again (at this pixel) # below. [bruce 090105] finally: self._disable_stereo() except: print_compact_traceback( "exception in or around _do_graphicsMode_Draw() during glname_color;" "drawing ignored; restoring modelview matrix: ") # REVIEW: what does "drawing ignored" mean, in that message? [bruce 090105 question] glMatrixMode(GL_MODELVIEW) self._setup_modelview( ) ### REVIEW: correctness of this is unreviewed! # now it's important to continue, at least enough to restore other gl state pass for shader in shaders: shader.setPicking(False) self.set_drawing_phase('?') # Restore the viewport. glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]) # Read pixel value from the back buffer and re-assemble glname. glFinish() # Make sure the drawing has completed. # REVIEW: is this glFinish needed? [bruce 090105 comment] rgba = glReadPixels(wX, wY, 1, 1, gl_format, gl_type)[0][0] pixZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT)[0][0] # Clear our depth pixel to 1.0 (far), so we won't mess up the # subsequent call of preDraw_glselect_dict. # (The following is not the most direct way, but it ought to work. # Note that we also clear the color pixel, since (being a glname) # it has no purpose remaining in the color buffer -- either it's # changed later, or, if not, that's a bug, but we'd rather have # it black than a random color.) [bruce 090105 bugfix] glDepthFunc(GL_ALWAYS) glWindowPos3i(wX, wY, 1) # Note the Z coord. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0)) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) glDepthFunc(saveDepthFunc) # Comes back sign-wrapped, in spite of specifying UNSIGNED_BYTE. def us(b): if b < 0: return 256 + b return b bytes = tuple([us(b) for b in rgba]) ##glname = (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]) ## Temp fix: Ignore the last byte, which always comes back 255 on Windows. glname = (bytes[0] << 16 | bytes[1] << 8 | bytes[2]) if debugPicking: print("shader mouseover xy %d %d, " % (wX, wY) + "rgba bytes (0x%x, 0x%x, 0x%x, 0x%x), " % bytes + "Z %f, glname 0x%x" % (pixZ, glname)) pass ### XXX This ought to be better-merged with the DL selection below. if glname: obj = self.object_for_glselect_name(glname) if debugPicking: print "shader mouseover glname=%r, obj=%r." % (glname, obj) if obj is None: # REVIEW: does this happen for mouse over a non-shader primitive? # [bruce 090105 question] #### Note: this bug is common. Guess: we are still drawing # ordinary colors for some primitives and/or for the # background, and they are showing up here and confusing # us. To help debug this, print the color too. But testing # shows it's not so simple -- e.g. for rung bonds it happens # where shader sphere and cylinder overlap, but not on either # one alone; for strand bonds it also happens on the bonds alone # (tested in Build DNA, in or not in Insert DNA). # [bruce 090218] # # Update: Since it's so common, I need to turn it off by default. # Q: is the situation safe? # A: if a color looks like a real glname by accident, # we'll get some random candidate object -- perhaps a killed one # or from a different Part or even a closed assy -- # and try to draw it. That doesn't sound very safe. Unfortunately # there is no perfect way to filter selobjs for safety, in the # current still-informal Selobj_API. The best approximation is # selobj_still_ok, and it should always say yes for the usual kinds, # so I'll add it as a check in the 'else' clause below. # [bruce 090311] if debug_flags.atom_debug: print "bug: object_for_glselect_name returns None for glname %r (color %r)" % ( glname, bytes) else: if self.graphicsMode.selobj_still_ok(obj): #bruce 090311 added condition, explained above self.glselect_dict[id(obj)] = obj else: # This should be rare but possible. Leave it on briefly and see # if it's ever common. If possible, gate it by atom_debug before # the release. [bruce 090311] print "fyi: glname-color selobj %r rejected since not selobj_still_ok" % obj pass pass pass if self._use_frustum_culling: self._compute_frustum_planes() # piotr 080331 - the frustum planes have to be setup after the # projection matrix is setup. I'm not sure if there may # be any side effects - see the comment below about # possible optimization. glSelectBuffer(self.SIZE_FOR_glSelectBuffer) # Note: this allocates a new select buffer, # and glRenderMode(GL_RENDER) returns it and forgets it, # so it's required before *each* call of glRenderMode(GL_SELECT) + # glRenderMode(GL_RENDER), not just once to set the size. # Ref: http://pyopengl.sourceforge.net/documentation/opengl_diffs.html # [bruce 080923 comment] glInitNames() # REVIEW: should we also set up a clipping plane just behind the # hit point, as (I think) is done in ThumbView, to reduce the # number of candidate objects? This might be a significant # optimization, though I don't think it eliminates the chance # of having multiple candidates. [bruce 080917 comment] glRenderMode(GL_SELECT) glMatrixMode(GL_MODELVIEW) try: self.set_drawing_phase('glselect') #bruce 070124 for stereo_image in self.stereo_images_to_draw: self._enable_stereo(stereo_image) try: self._do_graphicsMode_Draw( for_mouseover_highlighting=True) finally: self._disable_stereo() except: print_compact_traceback( "exception in or around _do_graphicsMode_Draw() during GL_SELECT; " "ignored; restoring modelview matrix: ") glMatrixMode(GL_MODELVIEW) self._setup_modelview( ) ### REVIEW: correctness of this is unreviewed! # now it's important to continue, at least enough to restore other gl state self._frustum_planes_available = False # piotr 080331 # just to be safe and not use the frustum planes computed for # the pick matrix self.set_drawing_phase('?') self.current_glselect = False # REVIEW: On systems with no stencil buffer, I think we'd also need # to draw selobj here in highlighted form (in case that form is # bigger than when it's not highlighted), or (easier & faster) # just always pretend it passes the hit test and add it to # glselect_dict -- and, make sure to give it "first dibs" for being # the next selobj. I'll implement some of this now (untested when # no stencil buffer) but not yet all. [bruce 050612] selobj = self.selobj if selobj is not None: self.glselect_dict[id(selobj)] = selobj # (review: is the following note correct?) # note: unneeded, if the func that looks at this dict always # tries selobj first (except for a kluge near # "if self.glselect_dict", commented on below) glFlush() hit_records = list(glRenderMode(GL_RENDER)) if debugPicking: print "DLs %d hits" % len(hit_records) for (near, far, names) in hit_records: # see example code, renderpass.py ## print "hit record: near, far, names:", near, far, names # e.g. hit record: near, far, names: 1439181696 1453030144 (1638426L,) # which proves that near/far are too far apart to give actual depth, # in spite of the 1- or 3-pixel drawing window (presumably they're vertices # taken from unclipped primitives, not clipped ones). del near, far if 1: # partial workaround for bug 1527. This can be removed once that bug (in drawer.py) # is properly fixed. This exists in two places -- GLPane.py and modes.py. [bruce 060217] if names and names[-1] == 0: print "%d(g) partial workaround for bug 1527: removing 0 from end of namestack:" % env.redraw_counter, names names = names[:-1] if names: # For now, we only use the last element of names, # though (as of long before 080917) it is often longer: # - some code pushes the same name twice (directly and # via ColorSorter) (see 060725 debug print below); # - chunks push a name even when they draw atoms/bonds # which push their own names (see 080411 comment below). # # Someday: if we ever support "name/subname paths" we'll # probably let first name interpret the remaining ones. # In fact, if nodes change projection or viewport for # their kids, and/or share their kids, they'd need to # push their own names on the stack, so we'd know how # to redraw the kids, or which ones are meant when they # are shared. if debug_flags.atom_debug and len( names) > 1: # bruce 060725 if len(names) == 2 and names[0] == names[1]: if not env.seen_before( "dual-names bug" ): # this happens for Atoms (colorsorter bug??) print "debug (once-per-session message): why are some glnames duplicated on the namestack?", names else: # Note: as of sometime before 080411, this became common -- # I guess that chunks (which recently acquired glselect names) # are pushing their names even while drawing their atoms and bonds. # I am not sure if this can cause any problems -- almost surely not # directly, but maybe the nestedness of highlighted appearances could # violate some assumptions made by the highlight code... anyway, # to reduce verbosity I need to not print this when the deeper name # is that of a chunk, and there are exactly two names. [bruce 080411] if len(names) == 2 and \ isinstance( self.object_for_glselect_name(names[0]), self.assy.Chunk ): if not env.seen_before( "nested names for Chunk"): print "debug (once-per-session message): nested glnames for a Chunk: ", names else: print "debug fyi: len(names) == %d (names = %r)" % ( len(names), names) obj = self.object_for_glselect_name( names[-1]) #k should always return an obj if obj is None: print "bug: object_for_glselect_name returns None for name %r at end of namestack %r" % ( names[-1], names) else: self.glselect_dict[id(obj)] = obj # note: outside of this method, one of these will be # chosen to be saved as self.selobj and rerendered # in "highlighted" form ##if 0: ## # this debug print was useful for debugging bug 2945, ## # and when it happens it's usually a bug, ## # but not always: ## # - it's predicted to happen for ChunkDrawer._renderOverlayText ## # - and whenever we're using a whole-chunk display style ## # so we can't leave it in permanently. [bruce 081211] ## if isinstance( obj, self.assy.Chunk ): ## print "\n*** namestack topped with a chunk:", obj pass continue # next hit_record #e maybe we should now sort glselect_dict by "hit priority" # (for depth-tiebreaking), or at least put selobj first. # (or this could be done lower down, where it's used.) # [I think we do this now...] return # from do_glselect_if_wanted
def GetMaxTextureSize(): maxTxtrSize = glGetInteger(GL_MAX_TEXTURE_SIZE) # print "MAX_TEXTURE_SIZE:", maxTxtrSize if maxTxtrSize == 0: maxTxtrSize = 4096 return maxTxtrSize