• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2# (C) Copyright IBM Corporation 2005, 2006
3# All Rights Reserved.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# on the rights to use, copy, modify, merge, publish, distribute, sub
9# license, and/or sell copies of the Software, and to permit persons to whom
10# the Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice (including the next
13# paragraph) shall be included in all copies or substantial portions of the
14# Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23#
24# Authors:
25#    Ian Romanick <idr@us.ibm.com>
26
27import argparse
28
29import gl_XML, glX_XML, glX_proto_common, license
30
31
32def log2(value):
33    for i in range(0, 30):
34        p = 1 << i
35        if p >= value:
36            return i
37
38    return -1
39
40
41def round_down_to_power_of_two(n):
42    """Returns the nearest power-of-two less than or equal to n."""
43
44    for i in range(30, 0, -1):
45        p = 1 << i
46        if p <= n:
47            return p
48
49    return -1
50
51
52class function_table:
53    def __init__(self, name, do_size_check):
54        self.name_base = name
55        self.do_size_check = do_size_check
56
57
58        self.max_bits = 1
59        self.next_opcode_threshold = (1 << self.max_bits)
60        self.max_opcode = 0
61
62        self.functions = {}
63        self.lookup_table = []
64
65        # Minimum number of opcodes in a leaf node.
66        self.min_op_bits = 3
67        self.min_op_count = (1 << self.min_op_bits)
68        return
69
70
71    def append(self, opcode, func):
72        self.functions[opcode] = func
73
74        if opcode > self.max_opcode:
75            self.max_opcode = opcode
76
77            if opcode > self.next_opcode_threshold:
78                bits = log2(opcode)
79                if (1 << bits) <= opcode:
80                    bits += 1
81
82                self.max_bits = bits
83                self.next_opcode_threshold = 1 << bits
84        return
85
86
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."""
93
94        remaining_bits = self.max_bits - total
95        next_opcode = min_opcode + (1 << remaining_bits)
96        empty_children = 0
97
98        for M in range(0, remaining_bits):
99            op_count = 1 << (remaining_bits - M);
100            child_count = 1 << M;
101
102            empty_children = 0
103            full_children = 0
104            for i in range(min_opcode, next_opcode, op_count):
105                used = 0
106                empty = 0
107
108                for j in range(i, i + op_count):
109                    if self.functions.has_key(j):
110                        used += 1;
111                    else:
112                        empty += 1;
113
114
115                if empty == op_count:
116                    empty_children += 1
117
118                if used == op_count:
119                    full_children += 1
120
121            if (empty_children > 0) or (full_children == child_count) or (op_count <= self.min_op_count):
122                break
123
124
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.
127
128        if (M == 0) or (M == remaining_bits):
129            return [remaining_bits, [], 0, 0]
130        else:
131            children = []
132            count = 1
133            depth = 1
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)
137
138                if not (n[1] == [] and not self.is_empty_leaf(i, n[0])):
139                    all_children_are_nonempty_leaf_nodes = 0
140
141                children.append(n)
142                count += n[2] + 1
143
144                if n[3] >= depth:
145                    depth = n[3] + 1
146
147            # If all of the child nodes are non-empty leaf nodes, pull
148            # them up and make this node a leaf.
149
150            if all_children_are_nonempty_leaf_nodes:
151                return [remaining_bits, [], 0, 0]
152            else:
153                return [M, children, count, depth]
154
155
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):
159                return 0
160                break
161
162        return 1
163
164
165    def dump_tree(self, node, base_opcode, remaining_bits, base_entry, depth):
166        M = node[0]
167        children = node[1]
168        child_M = remaining_bits - M
169
170
171        # This actually an error condition.
172        if children == []:
173            return
174
175        print '    /* [%u] -> opcode range [%u, %u], node depth %u */' % (base_entry, base_opcode, base_opcode + (1 << remaining_bits), depth)
176        print '    %u,' % (M)
177
178        base_entry += (1 << M) + 1
179
180        child_index = base_entry
181        child_base_opcode = base_opcode
182        for child in children:
183            if child[1] == []:
184                if self.is_empty_leaf(child_base_opcode, child_M):
185                    print '    EMPTY_LEAF,'
186                else:
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
191                    # lookup table.
192
193                    print '    LEAF(%u),' % (len(self.lookup_table))
194
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()
199
200                            if func.glx_rop != 0:
201                                size += 4
202
203                            size = ((size + 3) & ~3)
204
205                            if func.has_variable_size_request():
206                                size_name = "__glX%sReqSize" % (func.name)
207                            else:
208                                size_name = ""
209
210                            if func.glx_vendorpriv == op:
211                                func_name = func.glx_vendorpriv_names[0]
212                            else:
213                                func_name = func.name
214
215                            temp = [op, "__glXDisp_%s" % (func_name), "__glXDispSwap_%s" % (func_name), size, size_name]
216                        else:
217                            temp = [op, "NULL", "NULL", 0, ""]
218
219                        self.lookup_table.append(temp)
220            else:
221                print '    %u,' % (child_index)
222                child_index += child[2]
223
224            child_base_opcode += 1 << child_M
225
226        print ''
227
228        child_index = base_entry
229        for child in children:
230            if child[1] != []:
231                self.dump_tree(child, base_opcode, remaining_bits - M, child_index, depth + 1)
232                child_index += child[2]
233
234            base_opcode += 1 << (remaining_bits - M)
235
236
237    def Print(self):
238        # Each dispatch table consists of two data structures.
239        #
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
244        # N = 2^M, children.
245        #
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.
251        #
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.
256        #
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.
262        #
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
269        # bits.
270        #
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.
278
279        tree = self.divide_group(0, 0)
280
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)
285        print '};\n'
286
287        # After dumping the tree, dump the function lookup table.
288
289        print 'static const void *%s_function_table[%u][2] = {' % (self.name_base, len(self.lookup_table))
290        index = 0
291        for func in self.lookup_table:
292            opcode = func[0]
293            name = func[1]
294            name_swap = func[2]
295
296            print '    /* [% 3u] = %5u */ {%s, %s},' % (index, opcode, name, name_swap)
297
298            index += 1
299
300        print '};\n'
301
302        if self.do_size_check:
303            var_table = []
304
305            print 'static const int_fast16_t %s_size_table[%u][2] = {' % (self.name_base, len(self.lookup_table))
306            index = 0
307            var_table = []
308            for func in self.lookup_table:
309                opcode = func[0]
310                fixed = func[3]
311                var = func[4]
312
313                if var != "":
314                    var_offset = "%2u" % (len(var_table))
315                    var_table.append(var)
316                else:
317                    var_offset = "~0"
318
319                print '    /* [%3u] = %5u */ {%3u, %s},' % (index, opcode, fixed, var_offset)
320                index += 1
321
322
323            print '};\n'
324
325
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)
329
330            print '};\n'
331
332
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)
340        else:
341            print '    NULL,'
342            print '    NULL'
343        print '};\n'
344        return
345
346
347class PrintGlxDispatchTables(glX_proto_common.glx_print_proto):
348    def __init__(self):
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")
352
353        self.rop_functions = function_table("Render", 1)
354        self.sop_functions = function_table("Single", 0)
355        self.vop_functions = function_table("VendorPriv", 0)
356        return
357
358
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 "indirect_table.h"'
366        print ''
367        return
368
369
370    def printBody(self, api):
371        for f in api.functionIterateAll():
372            if not f.ignore and f.vectorequiv == None:
373                if f.glx_rop != 0:
374                    self.rop_functions.append(f.glx_rop, f)
375                if f.glx_sop != 0:
376                    self.sop_functions.append(f.glx_sop, f)
377                if f.glx_vendorpriv != 0:
378                    self.vop_functions.append(f.glx_vendorpriv, f)
379
380        self.sop_functions.Print()
381        self.rop_functions.Print()
382        self.vop_functions.Print()
383        return
384
385
386def _parser():
387    """Parse arguments and return namespace."""
388    parser = argparse.ArgumentParser()
389    parser.add_argument('-f',
390                        dest='filename',
391                        default='gl_API.xml',
392                        help='An XML file describing an API.')
393    return parser.parse_args()
394
395
396if __name__ == '__main__':
397    args = _parser()
398    printer = PrintGlxDispatchTables()
399    api = gl_XML.parse_GL_API(args.filename, glX_XML.glx_item_factory())
400
401    printer.Print(api)
402