From: Ian Romanick Date: Wed, 23 Aug 2006 20:32:48 +0000 (+0000) Subject: New script and API description file to enable generate of GLX protocol X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=261a806f9e26347d756bddeae81f4e98325b8e84;p=mesa.git New script and API description file to enable generate of GLX protocol decode tables in the server. --- diff --git a/src/mesa/glapi/Makefile b/src/mesa/glapi/Makefile index 4eba897e4bf..6e8ed1508ac 100644 --- a/src/mesa/glapi/Makefile +++ b/src/mesa/glapi/Makefile @@ -27,7 +27,8 @@ SERVER_OUTPUTS = $(GLX_DIR)/indirect_dispatch.c \ $(GLX_DIR)/indirect_dispatch_swap.c \ $(GLX_DIR)/indirect_dispatch.h \ $(GLX_DIR)/indirect_size_get.c \ - $(GLX_DIR)/indirect_size_get.h + $(GLX_DIR)/indirect_size_get.h \ + $(GLX_DIR)/indirect_table.c COMMON = gl_XML.py license.py gl_API.xml typeexpr.py COMMON_GLX = $(COMMON) glX_XML.py glX_proto_common.py @@ -88,8 +89,8 @@ $(GLX_DIR)/indirect_dispatch.c: $(COMMON_GLX) glX_proto_recv.py $(GLX_DIR)/indirect_dispatch_swap.c: $(COMMON_GLX) glX_proto_recv.py $(PYTHON2) $(PYTHON_FLAGS) glX_proto_recv.py -m dispatch_c -s > $@ -$(GLX_DIR)/indirect_dispatch.h: $(COMMON_GLX) glX_proto_recv.py - $(PYTHON2) $(PYTHON_FLAGS) glX_proto_recv.py -m dispatch_h -s > $@ +$(GLX_DIR)/indirect_dispatch.h: $(COMMON_GLX) glX_proto_recv.py glX_API.xml + $(PYTHON2) $(PYTHON_FLAGS) glX_proto_recv.py -m dispatch_h -f gl_and_glX_API.xml -s > $@ $(GLX_DIR)/indirect_size_get.h: $(COMMON_GLX) glX_proto_size.py $(PYTHON2) $(PYTHON_FLAGS) glX_proto_size.py -m size_h --only-get -h '_INDIRECT_SIZE_GET_H_' > $@ @@ -97,6 +98,9 @@ $(GLX_DIR)/indirect_size_get.h: $(COMMON_GLX) glX_proto_size.py $(GLX_DIR)/indirect_size_get.c: $(COMMON_GLX) glX_proto_size.py $(PYTHON2) $(PYTHON_FLAGS) glX_proto_size.py -m size_c > $@ +$(GLX_DIR)/indirect_table.c: $(COMMON_GLX) glX_server_table.py glX_API.xml + $(PYTHON2) $(PYTHON_FLAGS) glX_server_table.py -f gl_and_glX_API.xml > $@ + clean: rm -f *~ *.pyo rm -f $(OUTPUTS) diff --git a/src/mesa/glapi/glX_API.xml b/src/mesa/glapi/glX_API.xml new file mode 100644 index 00000000000..3f2fbd1163c --- /dev/null +++ b/src/mesa/glapi/glX_API.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mesa/glapi/glX_server_table.py b/src/mesa/glapi/glX_server_table.py new file mode 100644 index 00000000000..2535b480145 --- /dev/null +++ b/src/mesa/glapi/glX_server_table.py @@ -0,0 +1,400 @@ +#!/bin/env python + +# (C) Copyright IBM Corporation 2005, 2006 +# All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, and/or sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# Authors: +# Ian Romanick + +import gl_XML, glX_XML, license +import sys, getopt + + +def log2(value): + for i in range(0, 30): + p = 1 << i + if p >= value: + return i + + return -1 + + +def round_down_to_power_of_two(n): + """Returns the nearest power-of-two less than or equal to n.""" + + for i in range(30, 0, -1): + p = 1 << i + if p <= n: + return p + + return -1 + + +class function_table: + def __init__(self, name, do_size_check): + self.name_base = name + self.do_size_check = do_size_check + + + self.max_bits = 1 + self.next_opcode_threshold = (1 << self.max_bits) + self.max_opcode = 0 + + self.functions = {} + self.lookup_table = [] + + # Minimum number of opcodes in a leaf node. + self.min_op_bits = 3 + self.min_op_count = (1 << self.min_op_bits) + return + + + def append(self, opcode, func): + self.functions[opcode] = func + + if opcode > self.max_opcode: + self.max_opcode = opcode + + if opcode > self.next_opcode_threshold: + bits = log2(opcode) + if (1 << bits) <= opcode: + bits += 1 + + self.max_bits = bits + self.next_opcode_threshold = 1 << bits + return + + + def divide_group(self, min_opcode, total): + """Divide the group starting min_opcode into subgroups. + Returns a tuple containing the number of bits consumed by + the node, the list of the children's tuple, and the number + of entries in the final array used by this node and its + children, and the depth of the subtree rooted at the node.""" + + remaining_bits = self.max_bits - total + next_opcode = min_opcode + (1 << remaining_bits) + empty_children = 0 + + for M in range(0, remaining_bits): + op_count = 1 << (remaining_bits - M); + child_count = 1 << M; + + empty_children = 0 + full_children = 0 + for i in range(min_opcode, next_opcode, op_count): + used = 0 + empty = 0 + + for j in range(i, i + op_count): + if self.functions.has_key(j): + used += 1; + else: + empty += 1; + + + if empty == op_count: + empty_children += 1 + + if used == op_count: + full_children += 1 + + if (empty_children > 0) or (full_children == child_count) or (op_count <= self.min_op_count): + break + + + # If all the remaining bits are used by this node, as is the + # case when M is 0 or remaining_bits, the node is a leaf. + + if (M == 0) or (M == remaining_bits): + return [remaining_bits, [], 0, 0] + else: + children = [] + count = 1 + depth = 1 + all_children_are_nonempty_leaf_nodes = 1 + for i in range(min_opcode, next_opcode, op_count): + n = self.divide_group(i, total + M) + + if not (n[1] == [] and not self.is_empty_leaf(i, n[0])): + all_children_are_nonempty_leaf_nodes = 0 + + children.append(n) + count += n[2] + 1 + + if n[3] >= depth: + depth = n[3] + 1 + + # If all of the child nodes are non-empty leaf nodes, pull + # them up and make this node a leaf. + + if all_children_are_nonempty_leaf_nodes: + return [remaining_bits, [], 0, 0] + else: + return [M, children, count, depth] + + + def is_empty_leaf(self, base_opcode, M): + for op in range(base_opcode, base_opcode + (1 << M)): + if self.functions.has_key(op): + return 0 + break + + return 1 + + + def dump_tree(self, node, base_opcode, remaining_bits, base_entry, depth): + M = node[0] + children = node[1] + child_M = remaining_bits - M + + + # This actually an error condition. + if children == []: + return + + print ' /* [%u] -> opcode range [%u, %u], node depth %u */' % (base_entry, base_opcode, base_opcode + (1 << remaining_bits), depth) + print ' %u,' % (M) + + base_entry += (1 << M) + 1 + + child_index = base_entry + child_base_opcode = base_opcode + for child in children: + if child[1] == []: + if self.is_empty_leaf(child_base_opcode, child_M): + print ' EMPTY_LEAF,' + else: + # Emit the index of the next dispatch + # function. Then add all the + # dispatch functions for this leaf + # node to the dispatch function + # lookup table. + + print ' LEAF(%u),' % (len(self.lookup_table)) + + for op in range(child_base_opcode, child_base_opcode + (1 << child_M)): + if self.functions.has_key(op): + func = self.functions[op] + size = func.command_fixed_length() + if func.has_variable_size_request(): + size_name = "__glX%sReqSize" % (func.name) + else: + size_name = "" + + temp = [op, "__glXDisp_%s" % (func.name), "__glXDispSwap_%s" % (func.name), size, size_name] + else: + temp = [op, "NULL", "NULL", 0, ""] + + self.lookup_table.append(temp) + else: + print ' %u,' % (child_index) + child_index += child[2] + + child_base_opcode += 1 << child_M + + print '' + + child_index = base_entry + for child in children: + if child[1] != []: + self.dump_tree(child, base_opcode, remaining_bits - M, child_index, depth + 1) + child_index += child[2] + + base_opcode += 1 << (remaining_bits - M) + + + def Print(self): + # Each dispatch table consists of two data structures. + # + # The first structure is an N-way tree where the opcode for + # the function is the key. Each node switches on a range of + # bits from the opcode. M bits are extracted from the opcde + # and are used as an index to select one of the N, where + # N = 2^M, children. + # + # The tree is stored as a flat array. The first value is the + # number of bits, M, used by the node. For inner nodes, the + # following 2^M values are indexes into the array for the + # child nodes. For leaf nodes, the followign 2^M values are + # indexes into the second data structure. + # + # If an inner node's child index is 0, the child is an empty + # leaf node. That is, none of the opcodes selectable from + # that child exist. Since most of the possible opcode space + # is unused, this allows compact data storage. + # + # The second data structure is an array of pairs of function + # pointers. Each function contains a pointer to a protocol + # decode function and a pointer to a byte-swapped protocol + # decode function. Elements in this array are selected by the + # leaf nodes of the first data structure. + # + # As the tree is traversed, an accumulator is kept. This + # accumulator counts the bits of the opcode consumed by the + # traversal. When accumulator + M = B, where B is the + # maximum number of bits in an opcode, the traversal has + # reached a leaf node. The traversal starts with the most + # significant bits and works down to the least significant + # bits. + # + # Creation of the tree is the most complicated part. At + # each node the elements are divided into groups of 2^M + # elements. The value of M selected is the smallest possible + # value where all of the groups are either empty or full, or + # the groups are a preset minimum size. If all the children + # of a node are non-empty leaf nodes, the children are merged + # to create a single leaf node that replaces the parent. + + tree = self.divide_group(0, 0) + + print '/*****************************************************************/' + print '/* tree depth = %u */' % (tree[3]) + print 'static const int_fast16_t %s_dispatch_tree[%u] = {' % (self.name_base, tree[2]) + self.dump_tree(tree, 0, self.max_bits, 0, 1) + print '};\n' + + # After dumping the tree, dump the function lookup table. + + print 'static const __GLXdispatch%sProcPtr %s_function_table[%u][2] = {' % (self.name_base, self.name_base, len(self.lookup_table)) + index = 0 + for func in self.lookup_table: + opcode = func[0] + name = func[1] + name_swap = func[2] + + print ' /* [% 3u] = %5u */ {%s, %s},' % (index, opcode, name, name_swap) + + index += 1 + + print '};\n' + + if self.do_size_check: + var_table = [] + + print 'static const int_fast16_t %s_size_table[%u][2] = {' % (self.name_base, len(self.lookup_table)) + index = 0 + var_table = [] + for func in self.lookup_table: + opcode = func[0] + fixed = func[3] + var = func[4] + + if var != "": + var_offset = "%u" % (len(var)) + var_table.append(var) + else: + var_offset = "~0" + + print ' /* [% 3u] = %5u */ {%u, %s},' % (index, opcode, fixed, var_offset) + index += 1 + + + print '};\n' + + + print 'static const size_func %s_size_func_table[%u] = {' % (self.name_base, len(var_table)) + for func in var_table: + print ' %s,' % (func) + + print '};\n' + + + print 'const struct __glXDispatchInfo %s_dispatch_info = {' % (self.name_base) + print ' %u,' % (self.max_bits) + print ' %s_dispatch_tree,' % (self.name_base) + print ' %s_function_table,' % (self.name_base) + if self.do_size_check: + print ' %s_size_table,' % (self.name_base) + print ' %s_size_func_table' % (self.name_base) + else: + print ' NULL,' + print ' NULL' + print '};\n' + return + + +class PrintGlxDispatchTables(gl_XML.gl_print_base): + def __init__(self): + gl_XML.gl_print_base.__init__(self) + self.name = "glX_server_table.py (from Mesa)" + self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2005, 2006", "IBM") + + self.rop_functions = function_table("Render", 1) + self.sop_functions = function_table("Single", 0) + self.vop_functions = function_table("VendorPriv", 0) + return + + + def printRealHeader(self): + print '#include ' + print '#include "glxserver.h"' + print '#include "glxext.h"' + print '#include "indirect_dispatch.h"' + print '#include "indirect_reqsize.h"' + print '#include "g_disptab.h"' + print '#include "indirect_table.h"' + print '' + return + + + def printBody(self, api): + for f in api.functionIterateAll(): + if not f.ignore and f.vectorequiv == None: + if f.glx_rop != 0: + self.rop_functions.append(f.glx_rop, f) + elif f.glx_sop != 0: + self.sop_functions.append(f.glx_sop, f) + elif f.glx_vendorpriv != 0: + self.vop_functions.append(f.glx_vendorpriv, f) + + self.sop_functions.Print() + #self.rop_functions.Print() + self.vop_functions.Print() + return + + +if __name__ == '__main__': + file_name = "gl_API.xml" + + try: + (args, trail) = getopt.getopt(sys.argv[1:], "f:m") + except Exception,e: + show_usage() + + mode = "table_c" + for (arg,val) in args: + if arg == "-f": + file_name = val + elif arg == "-m": + mode = val + + if mode == "table_c": + printer = PrintGlxDispatchTables() + else: + show_usage() + + + api = gl_XML.parse_GL_API( file_name, glX_XML.glx_item_factory() ) + + + printer.Print( api ) diff --git a/src/mesa/glapi/gl_and_glX_API.xml b/src/mesa/glapi/gl_and_glX_API.xml new file mode 100644 index 00000000000..34c977e9c0c --- /dev/null +++ b/src/mesa/glapi/gl_and_glX_API.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file