Repository: vispy/vispy

Issue:
Need to remove #version directive in shader composition system for the WebGL backend
The shader composition system currently does not work in the WebGL backend, because `#version` is invalid in WebGL. It works if I remove [this](https://github.com/vispy/vispy/blob/master/vispy/visuals/shaders/compiler.py#L98-L99), but I guess it may break things on the desktop! What's the best way to tackle this @almarklein @lcampagn ?



Discussion:
I assume we can detect whether or not the GL backend is ES? If so, it should be sufficient to disable that line conditionally.

Yes, I think we can remove it, because it's added by GLIR in the process of tweaking the GLSL for the implementation in use.


Resolving patch:
diff --git a/vispy/visuals/shaders/compiler.py b/vispy/visuals/shaders/compiler.py
--- a/vispy/visuals/shaders/compiler.py
+++ b/vispy/visuals/shaders/compiler.py
@@ -11,27 +11,27 @@
 
 class Compiler(object):
     """
-    Compiler is used to convert Function and Variable instances into 
+    Compiler is used to convert Function and Variable instances into
     ready-to-use GLSL code. This class handles name mangling to ensure that
     there are no name collisions amongst global objects. The final name of
     each object may be retrieved using ``Compiler.__getitem__(obj)``.
-    
+
     Accepts multiple root Functions as keyword arguments. ``compile()`` then
     returns a dict of GLSL strings with the same keys.
-    
+
     Example::
-    
+
         # initialize with two main functions
         compiler = Compiler(vert=v_func, frag=f_func)
-        
+
         # compile and extract shaders
         code = compiler.compile()
         v_code = code['vert']
         f_code = code['frag']
-        
+
         # look up name of some object
         name = compiler[obj]
-    
+
     """
     def __init__(self, **shaders):
         # cache of compilation results for each function and variable
@@ -40,38 +40,38 @@ def __init__(self, **shaders):
 
     def __getitem__(self, item):
         """
-        Return the name of the specified object, if it has been assigned one.        
+        Return the name of the specified object, if it has been assigned one.
         """
         return self._object_names[item]
 
     def compile(self, pretty=True):
-        """ Compile all code and return a dict {name: code} where the keys 
+        """ Compile all code and return a dict {name: code} where the keys
         are determined by the keyword arguments passed to __init__().
-        
+
         Parameters
         ----------
         pretty : bool
             If True, use a slower method to mangle object names. This produces
             GLSL that is more readable.
-            If False, then the output is mostly unreadable GLSL, but is about 
+            If False, then the output is mostly unreadable GLSL, but is about
             10x faster to compile.
-        
+
         """
         # Authoritative mapping of {obj: name}
         self._object_names = {}
-        
+
         #
         # 1. collect list of dependencies for each shader
         #
-        
+
         # maps {shader_name: [deps]}
         self._shader_deps = {}
-        
+
         for shader_name, shader in self.shaders.items():
             this_shader_deps = []
             self._shader_deps[shader_name] = this_shader_deps
             dep_set = set()
-            
+
             for dep in shader.dependencies(sort=True):
                 # visit each object no more than once per shader
                 if dep.name is None or dep in dep_set:
@@ -86,21 +86,20 @@ def compile(self, pretty=True):
             self._rename_objects_pretty()
         else:
             self._rename_objects_fast()
-        
+
         #
         # 3. Now we have a complete namespace; concatenate all definitions
         # together in topological order.
         #
         compiled = {}
         obj_names = self._object_names
-        
+
         for shader_name, shader in self.shaders.items():
-            code = ['// Generated code by function composition', 
-                    '#version 120', '']
+            code = []
             for dep in self._shader_deps[shader_name]:
                 dep_code = dep.definition(obj_names)
                 if dep_code is not None:
-                    # strip out version pragma if present; 
+                    # strip out version pragma if present;
                     regex = r'#version (\d+)'
                     m = re.search(regex, dep_code)
                     if m is not None:
@@ -110,17 +109,17 @@ def compile(self, pretty=True):
                                                "120 is supported.")
                         dep_code = re.sub(regex, '', dep_code)
                     code.append(dep_code)
-                
+
             compiled[shader_name] = '\n'.join(code)
-            
+
         self.code = compiled
         return compiled
 
     def _rename_objects_fast(self):
-        """ Rename all objects quickly to guaranteed-unique names using the 
+        """ Rename all objects quickly to guaranteed-unique names using the
         id() of each object.
-        
-        This produces mostly unreadable GLSL, but is about 10x faster to 
+
+        This produces mostly unreadable GLSL, but is about 10x faster to
         compile.
         """
         for shader_name, deps in self._shader_deps.items():
@@ -130,18 +129,18 @@ def _rename_objects_fast(self):
                     ext = '_%x' % id(dep)
                     name = name[:32-len(ext)] + ext
                 self._object_names[dep] = name
-            
+
     def _rename_objects_pretty(self):
         """ Rename all objects like "name_1" to avoid conflicts. Objects are
-        only renamed if necessary. 
-        
+        only renamed if necessary.
+
         This method produces more readable GLSL, but is rather slow.
         """
         #
         # 1. For each object, add its static names to the global namespace
         #    and make a list of the shaders used by the object.
         #
-        
+
         # {name: obj} mapping for finding unique names
         # initialize with reserved keywords.
         self._global_ns = dict([(kwd, None) for kwd in gloo.util.KEYWORDS])
@@ -150,15 +149,15 @@ def _rename_objects_pretty(self):
 
         # for each object, keep a list of shaders the object appears in
         obj_shaders = {}
-        
+
         for shader_name, deps in self._shader_deps.items():
             for dep in deps:
                 # Add static names to namespace
                 for name in dep.static_names():
                     self._global_ns[name] = None
-                    
+
                 obj_shaders.setdefault(dep, []).append(shader_name)
-                
+
         #
         # 2. Assign new object names
         #
@@ -178,15 +177,15 @@ def _rename_objects_pretty(self):
                     if self._name_available(obj, new_name, shaders):
                         self._assign_name(obj, new_name, shaders)
                         break
-        
+
     def _is_global(self, obj):
-        """ Return True if *obj* should be declared in the global namespace. 
-        
+        """ Return True if *obj* should be declared in the global namespace.
+
         Some objects need to be declared only in per-shader namespaces:
         functions, static variables, and const variables may all be given
         different definitions in each shader.
         """
-        # todo: right now we assume all Variables are global, and all 
+        # todo: right now we assume all Variables are global, and all
         # Functions are local. Is this actually correct? Are there any
         # global functions? Are there any local variables?
         from .function import Variable


Test patch: