Пример #1
0
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)
Пример #2
0
    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)
Пример #3
0
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
Пример #4
0
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()
Пример #5
0
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)
Пример #6
0
    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
Пример #7
0
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()
Пример #8
0
    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
Пример #9
0
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
Пример #10
0
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
Пример #11
0
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)
Пример #12
0
    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
Пример #13
0
def GetMaxTextureSize():
    maxTxtrSize = glGetInteger(GL_MAX_TEXTURE_SIZE);
    # print "MAX_TEXTURE_SIZE:", maxTxtrSize
    if maxTxtrSize == 0:
        maxTxtrSize = 4096
    return maxTxtrSize
Пример #14
0
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)
Пример #15
0
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
Пример #16
0
    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
Пример #17
0
    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
Пример #18
0
def GetMaxTextureSize():
    maxTxtrSize = glGetInteger(GL_MAX_TEXTURE_SIZE)
    # print "MAX_TEXTURE_SIZE:", maxTxtrSize
    if maxTxtrSize == 0:
        maxTxtrSize = 4096
    return maxTxtrSize
Пример #19
0
    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