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>
28 import gl_XML
, glX_XML
, glX_proto_common
, license
33 for i
in range(0, 30):
41 def round_down_to_power_of_two(n
):
42 """Returns the nearest power-of-two less than or equal to n."""
44 for i
in range(30, 0, -1):
53 def __init__(self
, name
, do_size_check
):
55 self
.do_size_check
= do_size_check
59 self
.next_opcode_threshold
= (1 << self
.max_bits
)
63 self
.lookup_table
= []
65 # Minimum number of opcodes in a leaf node.
67 self
.min_op_count
= (1 << self
.min_op_bits
)
71 def append(self
, opcode
, func
):
72 self
.functions
[opcode
] = func
74 if opcode
> self
.max_opcode
:
75 self
.max_opcode
= opcode
77 if opcode
> self
.next_opcode_threshold
:
79 if (1 << bits
) <= opcode
:
83 self
.next_opcode_threshold
= 1 << bits
87 def divide_group(self
, min_opcode
, total
):
88 """Divide the group starting min_opcode into subgroups.
89 Returns a tuple containing the number of bits consumed by
90 the node, the list of the children's tuple, and the number
91 of entries in the final array used by this node and its
92 children, and the depth of the subtree rooted at the node."""
94 remaining_bits
= self
.max_bits
- total
95 next_opcode
= min_opcode
+ (1 << remaining_bits
)
98 for M
in range(0, remaining_bits
):
99 op_count
= 1 << (remaining_bits
- M
);
100 child_count
= 1 << M
;
104 for i
in range(min_opcode
, next_opcode
, op_count
):
108 for j
in range(i
, i
+ op_count
):
109 if self
.functions
.has_key(j
):
115 if empty
== op_count
:
121 if (empty_children
> 0) or (full_children
== child_count
) or (op_count
<= self
.min_op_count
):
125 # If all the remaining bits are used by this node, as is the
126 # case when M is 0 or remaining_bits, the node is a leaf.
128 if (M
== 0) or (M
== remaining_bits
):
129 return [remaining_bits
, [], 0, 0]
134 all_children_are_nonempty_leaf_nodes
= 1
135 for i
in range(min_opcode
, next_opcode
, op_count
):
136 n
= self
.divide_group(i
, total
+ M
)
138 if not (n
[1] == [] and not self
.is_empty_leaf(i
, n
[0])):
139 all_children_are_nonempty_leaf_nodes
= 0
147 # If all of the child nodes are non-empty leaf nodes, pull
148 # them up and make this node a leaf.
150 if all_children_are_nonempty_leaf_nodes
:
151 return [remaining_bits
, [], 0, 0]
153 return [M
, children
, count
, depth
]
156 def is_empty_leaf(self
, base_opcode
, M
):
157 for op
in range(base_opcode
, base_opcode
+ (1 << M
)):
158 if self
.functions
.has_key(op
):
165 def dump_tree(self
, node
, base_opcode
, remaining_bits
, base_entry
, depth
):
168 child_M
= remaining_bits
- M
171 # This actually an error condition.
175 print ' /* [%u] -> opcode range [%u, %u], node depth %u */' % (base_entry
, base_opcode
, base_opcode
+ (1 << remaining_bits
), depth
)
178 base_entry
+= (1 << M
) + 1
180 child_index
= base_entry
181 child_base_opcode
= base_opcode
182 for child
in children
:
184 if self
.is_empty_leaf(child_base_opcode
, child_M
):
187 # Emit the index of the next dispatch
188 # function. Then add all the
189 # dispatch functions for this leaf
190 # node to the dispatch function
193 print ' LEAF(%u),' % (len(self
.lookup_table
))
195 for op
in range(child_base_opcode
, child_base_opcode
+ (1 << child_M
)):
196 if self
.functions
.has_key(op
):
197 func
= self
.functions
[op
]
198 size
= func
.command_fixed_length()
200 if func
.glx_rop
!= 0:
203 size
= ((size
+ 3) & ~
3)
205 if func
.has_variable_size_request():
206 size_name
= "__glX%sReqSize" % (func
.name
)
210 if func
.glx_vendorpriv
== op
:
211 func_name
= func
.glx_vendorpriv_names
[0]
213 func_name
= func
.name
215 temp
= [op
, "__glXDisp_%s" % (func_name
), "__glXDispSwap_%s" % (func_name
), size
, size_name
]
217 temp
= [op
, "NULL", "NULL", 0, ""]
219 self
.lookup_table
.append(temp
)
221 print ' %u,' % (child_index
)
222 child_index
+= child
[2]
224 child_base_opcode
+= 1 << child_M
228 child_index
= base_entry
229 for child
in children
:
231 self
.dump_tree(child
, base_opcode
, remaining_bits
- M
, child_index
, depth
+ 1)
232 child_index
+= child
[2]
234 base_opcode
+= 1 << (remaining_bits
- M
)
238 # Each dispatch table consists of two data structures.
240 # The first structure is an N-way tree where the opcode for
241 # the function is the key. Each node switches on a range of
242 # bits from the opcode. M bits are extracted from the opcde
243 # and are used as an index to select one of the N, where
246 # The tree is stored as a flat array. The first value is the
247 # number of bits, M, used by the node. For inner nodes, the
248 # following 2^M values are indexes into the array for the
249 # child nodes. For leaf nodes, the followign 2^M values are
250 # indexes into the second data structure.
252 # If an inner node's child index is 0, the child is an empty
253 # leaf node. That is, none of the opcodes selectable from
254 # that child exist. Since most of the possible opcode space
255 # is unused, this allows compact data storage.
257 # The second data structure is an array of pairs of function
258 # pointers. Each function contains a pointer to a protocol
259 # decode function and a pointer to a byte-swapped protocol
260 # decode function. Elements in this array are selected by the
261 # leaf nodes of the first data structure.
263 # As the tree is traversed, an accumulator is kept. This
264 # accumulator counts the bits of the opcode consumed by the
265 # traversal. When accumulator + M = B, where B is the
266 # maximum number of bits in an opcode, the traversal has
267 # reached a leaf node. The traversal starts with the most
268 # significant bits and works down to the least significant
271 # Creation of the tree is the most complicated part. At
272 # each node the elements are divided into groups of 2^M
273 # elements. The value of M selected is the smallest possible
274 # value where all of the groups are either empty or full, or
275 # the groups are a preset minimum size. If all the children
276 # of a node are non-empty leaf nodes, the children are merged
277 # to create a single leaf node that replaces the parent.
279 tree
= self
.divide_group(0, 0)
281 print '/*****************************************************************/'
282 print '/* tree depth = %u */' % (tree
[3])
283 print 'static const int_fast16_t %s_dispatch_tree[%u] = {' % (self
.name_base
, tree
[2])
284 self
.dump_tree(tree
, 0, self
.max_bits
, 0, 1)
287 # After dumping the tree, dump the function lookup table.
289 print 'static const void *%s_function_table[%u][2] = {' % (self
.name_base
, len(self
.lookup_table
))
291 for func
in self
.lookup_table
:
296 print ' /* [% 3u] = %5u */ {%s, %s},' % (index
, opcode
, name
, name_swap
)
302 if self
.do_size_check
:
305 print 'static const int_fast16_t %s_size_table[%u][2] = {' % (self
.name_base
, len(self
.lookup_table
))
308 for func
in self
.lookup_table
:
314 var_offset
= "%2u" % (len(var_table
))
315 var_table
.append(var
)
319 print ' /* [%3u] = %5u */ {%3u, %s},' % (index
, opcode
, fixed
, var_offset
)
326 print 'static const gl_proto_size_func %s_size_func_table[%u] = {' % (self
.name_base
, len(var_table
))
327 for func
in var_table
:
328 print ' %s,' % (func
)
333 print 'const struct __glXDispatchInfo %s_dispatch_info = {' % (self
.name_base
)
334 print ' %u,' % (self
.max_bits
)
335 print ' %s_dispatch_tree,' % (self
.name_base
)
336 print ' %s_function_table,' % (self
.name_base
)
337 if self
.do_size_check
:
338 print ' %s_size_table,' % (self
.name_base
)
339 print ' %s_size_func_table' % (self
.name_base
)
347 class PrintGlxDispatchTables(glX_proto_common
.glx_print_proto
):
349 gl_XML
.gl_print_base
.__init
__(self
)
350 self
.name
= "glX_server_table.py (from Mesa)"
351 self
.license
= license
.bsd_license_template
% ( "(C) Copyright IBM Corporation 2005, 2006", "IBM")
353 self
.rop_functions
= function_table("Render", 1)
354 self
.sop_functions
= function_table("Single", 0)
355 self
.vop_functions
= function_table("VendorPriv", 0)
359 def printRealHeader(self
):
360 print '#include <inttypes.h>'
361 print '#include "glxserver.h"'
362 print '#include "glxext.h"'
363 print '#include "indirect_dispatch.h"'
364 print '#include "indirect_reqsize.h"'
365 print '#include "g_disptab.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()
387 if __name__
== '__main__':
388 file_name
= "gl_API.xml"
391 (args
, trail
) = getopt
.getopt(sys
.argv
[1:], "f:m")
396 for (arg
,val
) in args
:
402 if mode
== "table_c":
403 printer
= PrintGlxDispatchTables()
408 api
= gl_XML
.parse_GL_API( file_name
, glX_XML
.glx_item_factory() )