Package glitter :: Package shaders :: Module shaderprogram
[hide private]
[frames] | no frames]

Source Code for Module glitter.shaders.shaderprogram

  1  """Shader program class. 
  2   
  3  @todo: wrap C{glGetProgramStage}, C{glGetActiveSubroutineName}, 
  4  C{glGetActiveSubroutineUniform}, C{glGetActiveSubroutineUniformName}, 
  5  C{glGetSubroutineIndex}, C{glGetSubroutineUniformLocation}, 
  6  C{glGetTransformFeedbackVarying}, C{glTransformFeedbackVarying}, 
  7  C{glGetUniformBlockIndex}, C{glGetUniformIndices}, C{glGetActiveUniformBlock}, 
  8  C{glGetActiveUniformBlockName}, C{glUniformBlockBinding}, and 
  9  C{glUniformSubroutine}. 
 10   
 11  @author: Stephan Wenger 
 12  @date: 2012-02-29 
 13  """ 
 14   
 15  from collections import OrderedDict as _odict 
 16  import re as _re 
 17   
 18  import glitter.raw as _gl 
 19  from glitter.utils import transform_feedback_buffer_modes, int32, ShaderDatatype, ManagedObject, BindableObject, ShaderLinkError, ShaderValidateError, ListProxy, InstanceDescriptorMixin, Proxy 
 20  from glitter.shaders.shader import Shader, VertexShader, TesselationControlShader, TesselationEvaluationShader, GeometryShader, FragmentShader 
 21  from glitter.shaders.attribute import Attribute, AttributeStruct, AttributeStructArray 
 22  from glitter.shaders.uniform import Uniform, UniformStruct, UniformStructArray 
23 24 -class ProgramProxy(Proxy):
25 - def __init__(self, _id, arg, enum=None):
26 super(ProgramProxy, self).__init__(_gl.glGetProgramiv, [_id, arg], dtype=int32, enum=enum)
27
28 -class ShaderProgram(ManagedObject, BindableObject, InstanceDescriptorMixin):
29 _generate_id = _gl.glCreateProgram 30 _delete_id = _gl.glDeleteProgram 31 _db = "shader_programs" 32 _binding = "current_program" 33 34 transform_feedback_buffer_modes = transform_feedback_buffer_modes 35 _frozen = False 36
37 - def __init__(self, shaders=[], vertex=[], tess_control=[], tess_evaluation=[], geometry=[], fragment=[], link=None, context=None, **variables):
38 super(ShaderProgram, self).__init__(context=context) 39 self._shaders = [] 40 self._variable_proxies = [] 41 42 self._delete_status = ProgramProxy(self._id, _gl.GL_DELETE_STATUS) 43 self._link_status = ProgramProxy(self._id, _gl.GL_LINK_STATUS) 44 self._validate_status = ProgramProxy(self._id, _gl.GL_VALIDATE_STATUS) 45 self._info_log_length = ProgramProxy(self._id, _gl.GL_INFO_LOG_LENGTH) 46 self._attached_shaders = ProgramProxy(self._id, _gl.GL_ATTACHED_SHADERS) 47 self._active_attributes = ProgramProxy(self._id, _gl.GL_ACTIVE_ATTRIBUTES) 48 self._active_attribute_max_length = ProgramProxy(self._id, _gl.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) 49 self._active_uniforms = ProgramProxy(self._id, _gl.GL_ACTIVE_UNIFORMS) 50 self._active_uniform_max_length = ProgramProxy(self._id, _gl.GL_ACTIVE_UNIFORM_MAX_LENGTH) 51 self._program_binary_length = ProgramProxy(self._id, _gl.GL_PROGRAM_BINARY_LENGTH) 52 self._transform_feedback_buffer_mode = ProgramProxy(self._id, _gl.GL_TRANSFORM_FEEDBACK_BUFFER_MODE, self.transform_feedback_buffer_modes) 53 self._transform_feedback_varyings = ProgramProxy(self._id, _gl.GL_TRANSFORM_FEEDBACK_VARYINGS) 54 self._transform_feedback_varying_max_length = ProgramProxy(self._id, _gl.GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH) 55 56 shaders = list(shaders) if hasattr(shaders, "__iter__") else [shaders] 57 if not all(isinstance(x, Shader) for x in shaders): 58 raise TypeError("expected Shader instance") 59 shaders += [x if isinstance(x, VertexShader) else VertexShader(x, context=context) 60 for x in (vertex if hasattr(vertex, "__iter__") else [vertex])] 61 shaders += [x if isinstance(x, TesselationControlShader) else TesselationControlShader(x, context=context) 62 for x in (tess_control if hasattr(tess_control, "__iter__") else [tess_control])] 63 shaders += [x if isinstance(x, TesselationEvaluationShader) else TesselationEvaluationShader(x, context=context) 64 for x in (tess_evaluation if hasattr(tess_evaluation, "__iter__") else [tess_evaluation])] 65 shaders += [x if isinstance(x, GeometryShader) else GeometryShader(x, context=context) 66 for x in (geometry if hasattr(geometry, "__iter__") else [geometry])] 67 shaders += [x if isinstance(x, FragmentShader) else FragmentShader(x, context=context) 68 for x in (fragment if hasattr(fragment, "__iter__") else [fragment])] 69 self.shaders.extend(shaders) 70 71 if link is None: 72 link = bool(shaders) 73 if link: 74 self.link() 75 76 for name, proxy in self._get_active_attributes().items(): 77 setattr(self, name, proxy) 78 self._variable_proxies.append(proxy) 79 for name, proxy in self._get_active_uniforms().items(): 80 setattr(self, name, proxy) 81 self._variable_proxies.append(proxy) 82 83 self._frozen = True 84 85 for key, value in variables.items(): 86 setattr(self, key, value)
87
88 - def __setattr__(self, name, value):
89 if self._frozen and not name.startswith("_") and not hasattr(self, name): 90 raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name)) 91 return super(ShaderProgram, self).__setattr__(name, value)
92
93 - def _on_bind(self):
94 for proxy in self._variable_proxies: 95 proxy._on_bind()
96
97 - def _on_release(self):
98 for proxy in self._variable_proxies: 99 proxy._on_release()
100
101 - def _attach(self, shader):
102 with self._context: 103 _gl.glAttachShader(self._id, shader._id)
104
105 - def _detach(self, shader):
106 with self._context: 107 _gl.glDetachShader(self._id, shader._id)
108
109 - def _get_texture_unit(self, name):
110 candidates = [x for x in self._variable_proxies if x.name == name] 111 if candidates: 112 return candidates[0].__get__(self, get_texture_unit_instead_of_object=True) 113 else: 114 return None
115
116 - def _get_active_X(self, getter, location_getter, max_length, index):
117 _size = _gl.GLint() 118 _type = _gl.GLenum() 119 _name = _gl.create_string_buffer(max_length) 120 with self._context: 121 getter(self._id, index, max_length, None, _gl.pointer(_size), _gl.pointer(_type), _name) 122 location = location_getter(self._id, _name) 123 return location, _size.value, ShaderDatatype._from_gl(_type.value), _name.value
124
125 - def _get_active_attribute(self, index):
126 with self._context: 127 return self._get_active_X(_gl.glGetActiveAttrib, _gl.glGetAttribLocation, self._active_attribute_max_length, index)
128
129 - def _get_active_attributes(self):
130 return self._group_structs((self._get_active_attribute(i) for i in range(self._active_attributes)), 131 Attribute, AttributeStruct, AttributeStructArray)
132
133 - def _get_active_uniform(self, index):
134 with self._context: 135 return self._get_active_X(_gl.glGetActiveUniform, _gl.glGetUniformLocation, self._active_uniform_max_length, index)
136
137 - def _get_active_uniforms(self):
138 return self._group_structs((self._get_active_uniform(i) for i in range(self._active_uniforms)), 139 Uniform, UniformStruct, UniformStructArray)
140
141 - def _group_structs(self, lst, make_variable, make_struct, coerce_array):
142 array_of_structs_re = _re.compile("^([a-zA-Z_][a-zA-Z_0-9]*)\[([0-9]+)\]\.([a-zA-Z_][a-zA-Z_0-9]*)$") 143 struct_re = _re.compile("^([a-zA-Z_][a-zA-Z_0-9]*)\.([a-zA-Z_][a-zA-Z_0-9]*)$") 144 basic_re = _re.compile("^([a-zA-Z_][a-zA-Z_0-9]*)$") 145 names = _odict() 146 for location, size, dtype, name in lst: 147 m = array_of_structs_re.match(name) 148 if m is not None: 149 name, index, field = m.groups() 150 index = int(index) 151 array = names.setdefault(name, coerce_array(name, parent=self)) 152 array[index, field] = make_variable(field, location, dtype, size, parent=self) 153 continue 154 m = struct_re.match(name) 155 if m is not None: 156 name, field = m.groups() 157 struct = names.setdefault(name, make_struct(name, parent=self)) 158 struct[field] = make_variable(field, location, dtype, size, parent=self) 159 continue 160 m = basic_re.match(name) 161 if m is not None: 162 name, = m.groups() 163 names[name] = make_variable(name, location, dtype, size, parent=self) 164 continue 165 raise NameError("shader variable '%s' could not be parsed" % name) 166 return names
167 168 @property
169 - def shaders(self):
170 """The list of currently attached shaders. 171 172 @rtype: L{ListProxy} 173 """ 174 175 return ListProxy(self._shaders, self._attach, self._detach)
176 191
192 - def validate(self):
193 with self._context: 194 self._on_bind() 195 _gl.glValidateProgram(self._id) 196 self._on_release() 197 if self._validate_status != _gl.GL_TRUE: 198 raise ShaderValidateError(self._log) 199 return self._log or None
200
201 - def has_attribute_location(self, name):
202 with self._context: 203 return _gl.glGetAttribLocation(self._id, name) >= 0
204
205 - def get_attribute_location(self, name):
206 with self._context: 207 loc = _gl.glGetAttribLocation(self._id, name) 208 if loc == -1: 209 raise NameError("shader has no attribute '%s'" % name) 210 return loc
211
212 - def has_frag_data_location(self, name):
213 with self._context: 214 return _gl.glGetFragDataLocation(self._id, name) >= 0
215
216 - def get_frag_data_location(self, name):
217 with self._context: 218 loc = _gl.glGetFragDataLocation(self._id, name) 219 if loc == -1: 220 raise NameError("shader has no frag data '%s'" % name) 221 return loc
222 223 @property
224 - def _log(self):
225 """The current shader info log. 226 227 @rtype: C{string} 228 """ 229 230 _info_log = _gl.create_string_buffer(self._info_log_length) 231 with self._context: 232 _gl.glGetProgramInfoLog(self._id, self._info_log_length, _gl.POINTER(_gl.GLint)(), _info_log) 233 return _info_log.value
234 235 __all__ = ["ShaderProgram"] 236