3 # (C) Copyright IBM Corporation 2005, 2006
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:
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
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
26 # Ian Romanick <idr@us.ibm.com>
30 import gl_XML
, glX_XML
, glX_proto_common
, license
34 for i
in range(0, 30):
42 def round_down_to_power_of_two(n
):
43 """Returns the nearest power-of-two less than or equal to n."""
45 for i
in range(30, 0, -1):
54 def __init__(self
, name
, do_size_check
):
56 self
.do_size_check
= do_size_check
60 self
.next_opcode_threshold
= (1 << self
.max_bits
)
64 self
.lookup_table
= []
66 # Minimum number of opcodes in a leaf node.
68 self
.min_op_count
= (1 << self
.min_op_bits
)
72 def append(self
, opcode
, func
):
73 self
.functions
[opcode
] = func
75 if opcode
> self
.max_opcode
:
76 self
.max_opcode
= opcode
78 if opcode
> self
.next_opcode_threshold
:
80 if (1 << bits
) <= opcode
:
84 self
.next_opcode_threshold
= 1 << bits
88 def divide_group(self
, min_opcode
, total
):
89 """Divide the group starting min_opcode into subgroups.
90 Returns a tuple containing the number of bits consumed by
91 the node, the list of the children's tuple, and the number
92 of entries in the final array used by this node and its
93 children, and the depth of the subtree rooted at the node."""
95 remaining_bits
= self
.max_bits
- total
96 next_opcode
= min_opcode
+ (1 << remaining_bits
)
99 for M
in range(0, remaining_bits
):
100 op_count
= 1 << (remaining_bits
- M
);
101 child_count
= 1 << M
;
105 for i
in range(min_opcode
, next_opcode
, op_count
):
109 for j
in range(i
, i
+ op_count
):
110 if self
.functions
.has_key(j
):
116 if empty
== op_count
:
122 if (empty_children
> 0) or (full_children
== child_count
) or (op_count
<= self
.min_op_count
):
126 # If all the remaining bits are used by this node, as is the
127 # case when M is 0 or remaining_bits, the node is a leaf.
129 if (M
== 0) or (M
== remaining_bits
):
130 return [remaining_bits
, [], 0, 0]
135 all_children_are_nonempty_leaf_nodes
= 1
136 for i
in range(min_opcode
, next_opcode
, op_count
):
137 n
= self
.divide_group(i
, total
+ M
)
139 if not (n
[1] == [] and not self
.is_empty_leaf(i
, n
[0])):
140 all_children_are_nonempty_leaf_nodes
= 0
148 # If all of the child nodes are non-empty leaf nodes, pull
149 # them up and make this node a leaf.
151 if all_children_are_nonempty_leaf_nodes
:
152 return [remaining_bits
, [], 0, 0]
154 return [M
, children
, count
, depth
]
157 def is_empty_leaf(self
, base_opcode
, M
):
158 for op
in range(base_opcode
, base_opcode
+ (1 << M
)):
159 if self
.functions
.has_key(op
):
166 def dump_tree(self
, node
, base_opcode
, remaining_bits
, base_entry
, depth
):
169 child_M
= remaining_bits
- M
172 # This actually an error condition.
176 print ' /* [%u] -> opcode range [%u, %u], node depth %u */' % (base_entry
, base_opcode
, base_opcode
+ (1 << remaining_bits
), depth
)
179 base_entry
+= (1 << M
) + 1
181 child_index
= base_entry
182 child_base_opcode
= base_opcode
183 for child
in children
:
185 if self
.is_empty_leaf(child_base_opcode
, child_M
):
188 # Emit the index of the next dispatch
189 # function. Then add all the
190 # dispatch functions for this leaf
191 # node to the dispatch function
194 print ' LEAF(%u),' % (len(self
.lookup_table
))
196 for op
in range(child_base_opcode
, child_base_opcode
+ (1 << child_M
)):
197 if self
.functions
.has_key(op
):
198 func
= self
.functions
[op
]
199 size
= func
.command_fixed_length()
201 if func
.glx_rop
!= 0:
204 size
= ((size
+ 3) & ~
3)
206 if func
.has_variable_size_request():
207 size_name
= "__glX%sReqSize" % (func
.name
)
211 if func
.glx_vendorpriv
== op
:
212 func_name
= func
.glx_vendorpriv_names
[0]
214 func_name
= func
.name
216 temp
= [op
, "__glXDisp_%s" % (func_name
), "__glXDispSwap_%s" % (func_name
), size
, size_name
]
218 temp
= [op
, "NULL", "NULL", 0, ""]
220 self
.lookup_table
.append(temp
)
222 print ' %u,' % (child_index
)
223 child_index
+= child
[2]
225 child_base_opcode
+= 1 << child_M
229 child_index
= base_entry
230 for child
in children
:
232 self
.dump_tree(child
, base_opcode
, remaining_bits
- M
, child_index
, depth
+ 1)
233 child_index
+= child
[2]
235 base_opcode
+= 1 << (remaining_bits
- M
)
239 # Each dispatch table consists of two data structures.
241 # The first structure is an N-way tree where the opcode for
242 # the function is the key. Each node switches on a range of
243 # bits from the opcode. M bits are extracted from the opcde
244 # and are used as an index to select one of the N, where
247 # The tree is stored as a flat array. The first value is the
248 # number of bits, M, used by the node. For inner nodes, the
249 # following 2^M values are indexes into the array for the
250 # child nodes. For leaf nodes, the followign 2^M values are
251 # indexes into the second data structure.
253 # If an inner node's child index is 0, the child is an empty
254 # leaf node. That is, none of the opcodes selectable from
255 # that child exist. Since most of the possible opcode space
256 # is unused, this allows compact data storage.
258 # The second data structure is an array of pairs of function
259 # pointers. Each function contains a pointer to a protocol
260 # decode function and a pointer to a byte-swapped protocol
261 # decode function. Elements in this array are selected by the
262 # leaf nodes of the first data structure.
264 # As the tree is traversed, an accumulator is kept. This
265 # accumulator counts the bits of the opcode consumed by the
266 # traversal. When accumulator + M = B, where B is the
267 # maximum number of bits in an opcode, the traversal has
268 # reached a leaf node. The traversal starts with the most
269 # significant bits and works down to the least significant
272 # Creation of the tree is the most complicated part. At
273 # each node the elements are divided into groups of 2^M
274 # elements. The value of M selected is the smallest possible
275 # value where all of the groups are either empty or full, or
276 # the groups are a preset minimum size. If all the children
277 # of a node are non-empty leaf nodes, the children are merged
278 # to create a single leaf node that replaces the parent.
280 tree
= self
.divide_group(0, 0)
282 print '/*****************************************************************/'
283 print '/* tree depth = %u */' % (tree
[3])
284 print 'static const int_fast16_t %s_dispatch_tree[%u] = {' % (self
.name_base
, tree
[2])
285 self
.dump_tree(tree
, 0, self
.max_bits
, 0, 1)
288 # After dumping the tree, dump the function lookup table.
290 print 'static const void *%s_function_table[%u][2] = {' % (self
.name_base
, len(self
.lookup_table
))
292 for func
in self
.lookup_table
:
297 print ' /* [% 3u] = %5u */ {%s, %s},' % (index
, opcode
, name
, name_swap
)
303 if self
.do_size_check
:
306 print 'static const int_fast16_t %s_size_table[%u][2] = {' % (self
.name_base
, len(self
.lookup_table
))
309 for func
in self
.lookup_table
:
315 var_offset
= "%2u" % (len(var_table
))
316 var_table
.append(var
)
320 print ' /* [%3u] = %5u */ {%3u, %s},' % (index
, opcode
, fixed
, var_offset
)
327 print 'static const gl_proto_size_func %s_size_func_table[%u] = {' % (self
.name_base
, len(var_table
))
328 for func
in var_table
:
329 print ' %s,' % (func
)
334 print 'const struct __glXDispatchInfo %s_dispatch_info = {' % (self
.name_base
)
335 print ' %u,' % (self
.max_bits
)
336 print ' %s_dispatch_tree,' % (self
.name_base
)
337 print ' %s_function_table,' % (self
.name_base
)
338 if self
.do_size_check
:
339 print ' %s_size_table,' % (self
.name_base
)
340 print ' %s_size_func_table' % (self
.name_base
)
348 class PrintGlxDispatchTables(glX_proto_common
.glx_print_proto
):
350 gl_XML
.gl_print_base
.__init
__(self
)
351 self
.name
= "glX_server_table.py (from Mesa)"
352 self
.license
= license
.bsd_license_template
% ( "(C) Copyright IBM Corporation 2005, 2006", "IBM")
354 self
.rop_functions
= function_table("Render", 1)
355 self
.sop_functions
= function_table("Single", 0)
356 self
.vop_functions
= function_table("VendorPriv", 0)
360 def printRealHeader(self
):
361 print '#include <inttypes.h>'
362 print '#include "glxserver.h"'
363 print '#include "glxext.h"'
364 print '#include "indirect_dispatch.h"'
365 print '#include "indirect_reqsize.h"'
366 print '#include "indirect_table.h"'
371 def printBody(self
, api
):
372 for f
in api
.functionIterateAll():
373 if not f
.ignore
and f
.vectorequiv
== None:
375 self
.rop_functions
.append(f
.glx_rop
, f
)
377 self
.sop_functions
.append(f
.glx_sop
, f
)
378 if f
.glx_vendorpriv
!= 0:
379 self
.vop_functions
.append(f
.glx_vendorpriv
, f
)
381 self
.sop_functions
.Print()
382 self
.rop_functions
.Print()
383 self
.vop_functions
.Print()
388 """Parse arguments and return namespace."""
389 parser
= argparse
.ArgumentParser()
390 parser
.add_argument('-f',
392 default
='gl_API.xml',
393 help='An XML file describing an API.')
394 return parser
.parse_args()
397 if __name__
== '__main__':
399 printer
= PrintGlxDispatchTables()
400 api
= gl_XML
.parse_GL_API(args
.filename
, glX_XML
.glx_item_factory())