Home | History | Annotate | Download | only in gen
      1 #!/usr/bin/env python
      2 
      3 # (C) Copyright IBM Corporation 2004, 2005
      4 # All Rights Reserved.
      5 #
      6 # Permission is hereby granted, free of charge, to any person obtaining a
      7 # copy of this software and associated documentation files (the "Software"),
      8 # to deal in the Software without restriction, including without limitation
      9 # on the rights to use, copy, modify, merge, publish, distribute, sub
     10 # license, and/or sell copies of the Software, and to permit persons to whom
     11 # the Software is furnished to do so, subject to the following conditions:
     12 #
     13 # The above copyright notice and this permission notice (including the next
     14 # paragraph) shall be included in all copies or substantial portions of the
     15 # Software.
     16 #
     17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
     20 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     23 # IN THE SOFTWARE.
     24 #
     25 # Authors:
     26 #    Ian Romanick <idr (at] us.ibm.com>
     27 
     28 import gl_XML
     29 import license
     30 import sys, getopt, string
     31 
     32 
     33 class glx_item_factory(gl_XML.gl_item_factory):
     34 	"""Factory to create GLX protocol oriented objects derived from gl_item."""
     35     
     36 	def create_item(self, name, element, context):
     37 		if name == "function":
     38 			return glx_function(element, context)
     39 		elif name == "enum":
     40 			return glx_enum(element, context)
     41 		elif name == "api":
     42 			return glx_api(self)
     43 		else:
     44 			return gl_XML.gl_item_factory.create_item(self, name, element, context)
     45 
     46 
     47 class glx_enum(gl_XML.gl_enum):
     48 	def __init__(self, element, context):
     49 		gl_XML.gl_enum.__init__(self, element, context)
     50 		
     51 		self.functions = {}
     52 
     53 		child = element.children
     54 		while child:
     55 			if child.type == "element" and child.name == "size":
     56 				n = child.nsProp( "name", None )
     57 				c = child.nsProp( "count", None )
     58 				m = child.nsProp( "mode", None )
     59 				
     60 				if not c:
     61 					c = self.default_count
     62 				else:
     63 					c = int(c)
     64 
     65 				if m == "get":
     66 					mode = 0
     67 				else:
     68 					mode = 1
     69 
     70 				if not self.functions.has_key(n):
     71 					self.functions[ n ] = [c, mode]
     72 
     73 			child = child.next
     74 
     75 		return
     76 
     77 
     78 class glx_function(gl_XML.gl_function):
     79 	def __init__(self, element, context):
     80 		self.glx_rop = 0
     81 		self.glx_sop = 0
     82 		self.glx_vendorpriv = 0
     83 
     84 		self.glx_vendorpriv_names = []
     85 
     86 		# If this is set to true, it means that GLdouble parameters should be
     87 		# written to the GLX protocol packet in the order they appear in the
     88 		# prototype.  This is different from the "classic" ordering.  In the
     89 		# classic ordering GLdoubles are written to the protocol packet first,
     90 		# followed by non-doubles.  NV_vertex_program was the first extension
     91 		# to break with this tradition.
     92 
     93 		self.glx_doubles_in_order = 0
     94 
     95 		self.vectorequiv = None
     96 		self.output = None
     97 		self.can_be_large = 0
     98 		self.reply_always_array = 0
     99 		self.dimensions_in_reply = 0
    100 		self.img_reset = None
    101 
    102 		self.server_handcode = 0
    103 		self.client_handcode = 0
    104 		self.ignore = 0
    105 
    106 		self.count_parameter_list = []
    107 		self.counter_list = []
    108 		self.parameters_by_name = {}
    109 		self.offsets_calculated = 0
    110 
    111 		gl_XML.gl_function.__init__(self, element, context)
    112 		return
    113 
    114 
    115 	def process_element(self, element):
    116 		gl_XML.gl_function.process_element(self, element)
    117 
    118 		# If the function already has a vector equivalent set, don't
    119 		# set it again.  This can happen if an alias to a function
    120 		# appears after the function that it aliases.
    121 
    122 		if not self.vectorequiv:
    123 			self.vectorequiv = element.nsProp("vectorequiv", None)
    124 
    125 
    126 		name = element.nsProp("name", None)
    127 		if name == self.name:
    128 			for param in self.parameters:
    129 				self.parameters_by_name[ param.name ] = param
    130 				
    131 				if len(param.count_parameter_list):
    132 					self.count_parameter_list.extend( param.count_parameter_list )
    133 				
    134 				if param.counter and param.counter not in self.counter_list:
    135 					self.counter_list.append(param.counter)
    136 
    137 
    138 		child = element.children
    139 		while child:
    140 			if child.type == "element" and child.name == "glx":
    141 				rop = child.nsProp( 'rop', None )
    142 				sop = child.nsProp( 'sop', None )
    143 				vop = child.nsProp( 'vendorpriv', None )
    144 
    145 				if rop:
    146 					self.glx_rop = int(rop)
    147 
    148 				if sop:
    149 					self.glx_sop = int(sop)
    150 
    151 				if vop:
    152 					self.glx_vendorpriv = int(vop)
    153 					self.glx_vendorpriv_names.append(name)
    154 
    155 				self.img_reset = child.nsProp( 'img_reset', None )
    156 
    157 				# The 'handcode' attribute can be one of 'true',
    158 				# 'false', 'client', or 'server'.
    159 
    160 				handcode = child.nsProp( 'handcode', None )
    161 				if handcode == "false":
    162 					self.server_handcode = 0
    163 					self.client_handcode = 0
    164 				elif handcode == "true":
    165 					self.server_handcode = 1
    166 					self.client_handcode = 1
    167 				elif handcode == "client":
    168 					self.server_handcode = 0
    169 					self.client_handcode = 1
    170 				elif handcode == "server":
    171 					self.server_handcode = 1
    172 					self.client_handcode = 0
    173 				else:
    174 					raise RuntimeError('Invalid handcode mode "%s" in function "%s".' % (handcode, self.name))
    175 
    176 				self.ignore               = gl_XML.is_attr_true( child, 'ignore' )
    177 				self.can_be_large         = gl_XML.is_attr_true( child, 'large' )
    178 				self.glx_doubles_in_order = gl_XML.is_attr_true( child, 'doubles_in_order' )
    179 				self.reply_always_array   = gl_XML.is_attr_true( child, 'always_array' )
    180 				self.dimensions_in_reply  = gl_XML.is_attr_true( child, 'dimensions_in_reply' )
    181 
    182 			child = child.next
    183 
    184 
    185 		# Do some validation of the GLX protocol information.  As
    186 		# new tests are discovered, they should be added here.
    187 
    188 		for param in self.parameters:
    189 			if param.is_output and self.glx_rop != 0:
    190 				raise RuntimeError("Render / RenderLarge commands cannot have outputs (%s)." % (self.name))
    191 
    192 		return
    193 
    194 
    195 	def has_variable_size_request(self):
    196 		"""Determine if the GLX request packet is variable sized.
    197 
    198 		The GLX request packet is variable sized in several common
    199 		situations.
    200 		
    201 		1. The function has a non-output parameter that is counted
    202 		   by another parameter (e.g., the 'textures' parameter of
    203 		   glDeleteTextures).
    204 		   
    205 		2. The function has a non-output parameter whose count is
    206 		   determined by another parameter that is an enum (e.g., the
    207 		   'params' parameter of glLightfv).
    208 		   
    209 		3. The function has a non-output parameter that is an
    210 		   image.
    211 
    212 		4. The function must be hand-coded on the server.
    213 		"""
    214 
    215 		if self.glx_rop == 0:
    216 			return 0
    217 
    218 		if self.server_handcode or self.images:
    219 			return 1
    220 
    221 		for param in self.parameters:
    222 			if not param.is_output:
    223 				if param.counter or len(param.count_parameter_list):
    224 					return 1
    225 
    226 		return 0
    227 
    228 
    229 	def variable_length_parameter(self):
    230 		for param in self.parameters:
    231 			if not param.is_output:
    232 				if param.counter or len(param.count_parameter_list):
    233 					return param
    234 				
    235 		return None
    236 
    237 
    238 	def calculate_offsets(self):
    239 		if not self.offsets_calculated:
    240 			# Calculate the offset of the first function parameter
    241 			# in the GLX command packet.  This byte offset is
    242 			# measured from the end of the Render / RenderLarge
    243 			# header.  The offset for all non-pixel commends is
    244 			# zero.  The offset for pixel commands depends on the
    245 			# number of dimensions of the pixel data.
    246 
    247 			if len(self.images) and not self.images[0].is_output:
    248 				[dim, junk, junk, junk, junk] = self.images[0].get_dimensions()
    249 
    250 				# The base size is the size of the pixel pack info
    251 				# header used by images with the specified number
    252 				# of dimensions.
    253 
    254 				if dim <=  2:
    255 					offset = 20
    256 				elif dim <= 4:
    257 					offset = 36
    258 				else:
    259 					raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim, self.image.name, self.name))
    260 			else:
    261 				offset = 0
    262 
    263 			for param in self.parameterIterateGlxSend():
    264 				if param.img_null_flag:
    265 					offset += 4
    266 
    267 				if param.name != self.img_reset:
    268 					param.offset = offset
    269 					if not param.is_variable_length() and not param.is_client_only:
    270 						offset += param.size()
    271 					
    272 				if self.pad_after( param ):
    273 					offset += 4
    274 
    275 
    276 			self.offsets_calculated = 1
    277 		return
    278 
    279 
    280 	def offset_of(self, param_name):
    281 		self.calculate_offsets()
    282 		return self.parameters_by_name[ param_name ].offset
    283 
    284 
    285 	def parameterIterateGlxSend(self, include_variable_parameters = 1):
    286 		"""Create an iterator for parameters in GLX request order."""
    287 
    288 		# The parameter lists are usually quite short, so it's easier
    289 		# (i.e., less code) to just generate a new list with the
    290 		# required elements than it is to create a new iterator class.
    291 		
    292 		temp = [ [],  [], [] ]
    293 		for param in self.parameters:
    294 			if param.is_output: continue
    295 
    296 			if param.is_variable_length():
    297 				temp[2].append( param )
    298 			elif not self.glx_doubles_in_order and param.is_64_bit():
    299 				temp[0].append( param )
    300 			else:
    301 				temp[1].append( param )
    302 
    303 		parameters = temp[0]
    304 		parameters.extend( temp[1] )
    305 		if include_variable_parameters:
    306 			parameters.extend( temp[2] )
    307 		return parameters.__iter__()
    308 
    309 
    310 	def parameterIterateCounters(self):
    311 		temp = []
    312 		for name in self.counter_list:
    313 			temp.append( self.parameters_by_name[ name ] )
    314 
    315 		return temp.__iter__()
    316 
    317 
    318 	def parameterIterateOutputs(self):
    319 		temp = []
    320 		for p in self.parameters:
    321 			if p.is_output:
    322 				temp.append( p )
    323 
    324 		return temp
    325 
    326 
    327 	def command_fixed_length(self):
    328 		"""Return the length, in bytes as an integer, of the
    329 		fixed-size portion of the command."""
    330 
    331 		if len(self.parameters) == 0:
    332 			return 0
    333 		
    334 		self.calculate_offsets()
    335 
    336 		size = 0
    337 		for param in self.parameterIterateGlxSend(0):
    338 			if param.name != self.img_reset and not param.is_client_only:
    339 				if size == 0:
    340 					size = param.offset + param.size()
    341 				else:
    342 					size += param.size()
    343 
    344 				if self.pad_after( param ):
    345 					size += 4
    346 
    347 		for param in self.images:
    348 			if param.img_null_flag or param.is_output:
    349 				size += 4
    350 
    351 		return size
    352 
    353 
    354 	def command_variable_length(self):
    355 		"""Return the length, as a string, of the variable-sized
    356 		portion of the command."""
    357 
    358 		size_string = ""
    359 		for p in self.parameterIterateGlxSend():
    360 			if (not p.is_output) and (p.is_variable_length() or p.is_image()):
    361 				# FIXME Replace the 1 in the size_string call
    362 				# FIXME w/0 to eliminate some un-needed parnes
    363 				# FIXME This would already be done, but it
    364 				# FIXME adds some extra diffs to the generated
    365 				# FIXME code.
    366 
    367 				size_string = size_string + " + __GLX_PAD(%s)" % (p.size_string(1))
    368 
    369 		return size_string
    370 
    371 
    372 	def command_length(self):
    373 		size = self.command_fixed_length()
    374 
    375 		if self.glx_rop != 0:
    376 			size += 4
    377 
    378 		size = ((size + 3) & ~3)
    379 		return "%u%s" % (size, self.command_variable_length())
    380 
    381 
    382 	def opcode_real_value(self):
    383 		"""Get the true numeric value of the GLX opcode
    384 		
    385 		Behaves similarly to opcode_value, except for
    386 		X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
    387 		In these cases the value for the GLX opcode field (i.e.,
    388 		16 for X_GLXVendorPrivate or 17 for
    389 		X_GLXVendorPrivateWithReply) is returned.  For other 'single'
    390 		commands, the opcode for the command (e.g., 101 for
    391 		X_GLsop_NewList) is returned."""
    392 
    393 		if self.glx_vendorpriv != 0:
    394 			if self.needs_reply():
    395 				return 17
    396 			else:
    397 				return 16
    398 		else:
    399 			return self.opcode_value()
    400 
    401 
    402 	def opcode_value(self):
    403 		"""Get the unique protocol opcode for the glXFunction"""
    404 
    405 		if (self.glx_rop == 0) and self.vectorequiv:
    406 			equiv = self.context.functions_by_name[ self.vectorequiv ]
    407 			self.glx_rop = equiv.glx_rop
    408 
    409 
    410 		if self.glx_rop != 0:
    411 			return self.glx_rop
    412 		elif self.glx_sop != 0:
    413 			return self.glx_sop
    414 		elif self.glx_vendorpriv != 0:
    415 			return self.glx_vendorpriv
    416 		else:
    417 			return -1
    418 	
    419 
    420 	def opcode_rop_basename(self):
    421 		"""Return either the name to be used for GLX protocol enum.
    422 		
    423 		Returns either the name of the function or the name of the
    424 		name of the equivalent vector (e.g., glVertex3fv for
    425 		glVertex3f) function."""
    426 
    427 		if self.vectorequiv == None:
    428 			return self.name
    429 		else:
    430 			return self.vectorequiv
    431 
    432 
    433 	def opcode_name(self):
    434 		"""Get the unique protocol enum name for the glXFunction"""
    435 
    436 		if (self.glx_rop == 0) and self.vectorequiv:
    437 			equiv = self.context.functions_by_name[ self.vectorequiv ]
    438 			self.glx_rop = equiv.glx_rop
    439 			self.glx_doubles_in_order = equiv.glx_doubles_in_order
    440 
    441 
    442 		if self.glx_rop != 0:
    443 			return "X_GLrop_%s" % (self.opcode_rop_basename())
    444 		elif self.glx_sop != 0:
    445 			return "X_GLsop_%s" % (self.name)
    446 		elif self.glx_vendorpriv != 0:
    447 			return "X_GLvop_%s" % (self.name)
    448 		else:
    449 			raise RuntimeError('Function "%s" has no opcode.' % (self.name))
    450 
    451 
    452 	def opcode_vendor_name(self, name):
    453 		if name in self.glx_vendorpriv_names:
    454 			return "X_GLvop_%s" % (name)
    455 		else:
    456 			raise RuntimeError('Function "%s" has no VendorPrivate opcode.' % (name))
    457 
    458 
    459 	def opcode_real_name(self):
    460 		"""Get the true protocol enum name for the GLX opcode
    461 		
    462 		Behaves similarly to opcode_name, except for
    463 		X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
    464 		In these cases the string 'X_GLXVendorPrivate' or
    465 		'X_GLXVendorPrivateWithReply' is returned.  For other
    466 		single or render commands 'X_GLsop' or 'X_GLrop' plus the
    467 		name of the function returned."""
    468 
    469 		if self.glx_vendorpriv != 0:
    470 			if self.needs_reply():
    471 				return "X_GLXVendorPrivateWithReply"
    472 			else:
    473 				return "X_GLXVendorPrivate"
    474 		else:
    475 			return self.opcode_name()
    476 
    477 
    478 	def needs_reply(self):
    479 		try:
    480 			x = self._needs_reply
    481 		except Exception, e:
    482 			x = 0
    483 			if self.return_type != 'void':
    484 				x = 1
    485 
    486 			for param in self.parameters:
    487 				if param.is_output:
    488 					x = 1
    489 					break
    490 
    491 			self._needs_reply = x
    492 
    493 		return x
    494 
    495 
    496 	def pad_after(self, p):
    497 		"""Returns the name of the field inserted after the
    498 		specified field to pad out the command header."""
    499 
    500 		for image in self.images:
    501 			if image.img_pad_dimensions:
    502 				if not image.height:
    503 					if p.name == image.width:
    504 						return "height"
    505 					elif p.name == image.img_xoff:
    506 						return "yoffset"
    507 				elif not image.extent:
    508 					if p.name == image.depth:
    509 						# Should this be "size4d"?
    510 						return "extent"
    511 					elif p.name == image.img_zoff:
    512 						return "woffset"
    513 
    514 		return None
    515 
    516 
    517 	def has_different_protocol(self, name):
    518 		"""Returns true if the named version of the function uses different protocol from the other versions.
    519 		
    520 		Some functions, such as glDeleteTextures and
    521 		glDeleteTexturesEXT are functionally identical, but have
    522 		different protocol.  This function returns true if the
    523 		named function is an alias name and that named version uses
    524 		different protocol from the function that is aliased.
    525 		"""
    526 
    527 		return (name in self.glx_vendorpriv_names) and self.glx_sop
    528 
    529 
    530 	def static_glx_name(self, name):
    531 		if self.has_different_protocol(name):
    532 			for n in self.glx_vendorpriv_names:
    533 				if n in self.static_entry_points:
    534 					return n
    535 				
    536 		return self.static_name(name)
    537 
    538 
    539 	def client_supported_for_indirect(self):
    540 		"""Returns true if the function is supported on the client
    541 		side for indirect rendering."""
    542 
    543 		return not self.ignore and (self.offset != -1) and (self.glx_rop or self.glx_sop or self.glx_vendorpriv or self.vectorequiv or self.client_handcode)
    544 
    545 
    546 class glx_function_iterator:
    547 	"""Class to iterate over a list of glXFunctions"""
    548 
    549 	def __init__(self, context):
    550 		self.iterator = context.functionIterateByOffset()
    551 		return
    552 
    553 
    554 	def __iter__(self):
    555 		return self
    556 
    557 
    558 	def next(self):
    559 		f = self.iterator.next()
    560 
    561 		if f.client_supported_for_indirect():
    562 			return f
    563 		else:
    564 			return self.next()
    565 
    566 
    567 class glx_api(gl_XML.gl_api):
    568 	def functionIterateGlx(self):
    569 		return glx_function_iterator(self)
    570 
    571