Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. #!/bin/env python
  2.  
  3. # (C) Copyright IBM Corporation 2005, 2006
  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@us.ibm.com>
  27.  
  28. import gl_XML, glX_XML, glX_proto_common, license
  29. import sys, getopt
  30.  
  31.  
  32. def 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.  
  41. def 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.  
  52. class 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.  
  347. class 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.  
  386. if __name__ == '__main__':
  387.     file_name = "gl_API.xml"
  388.  
  389.     try:
  390.         (args, trail) = getopt.getopt(sys.argv[1:], "f:m")
  391.     except Exception,e:
  392.         show_usage()
  393.  
  394.     mode = "table_c"
  395.     for (arg,val) in args:
  396.         if arg == "-f":
  397.             file_name = val
  398.         elif arg == "-m":
  399.             mode = val
  400.  
  401.     if mode == "table_c":
  402.         printer = PrintGlxDispatchTables()
  403.     else:
  404.         show_usage()
  405.  
  406.  
  407.     api = gl_XML.parse_GL_API( file_name, glX_XML.glx_item_factory() )
  408.  
  409.  
  410.     printer.Print( api )
  411.