New script and API description file to enable generate of GLX protocol
authorIan Romanick <idr@us.ibm.com>
Wed, 23 Aug 2006 20:32:48 +0000 (20:32 +0000)
committerIan Romanick <idr@us.ibm.com>
Wed, 23 Aug 2006 20:32:48 +0000 (20:32 +0000)
decode tables in the server.

src/mesa/glapi/Makefile
src/mesa/glapi/glX_API.xml [new file with mode: 0644]
src/mesa/glapi/glX_server_table.py [new file with mode: 0644]
src/mesa/glapi/gl_and_glX_API.xml [new file with mode: 0644]

index 4eba897..6e8ed15 100644 (file)
@@ -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 (file)
index 0000000..3f2fbd1
--- /dev/null
@@ -0,0 +1,215 @@
+<?xml version="1.0"?>
+<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
+
+<OpenGLAPI>
+
+<!-- Right now this file is just used to generate the GLX protocol
+     decode tables on the server.  The only information that is needed
+     for that purpose is the name of the function (or pseudo-function
+     in the case of Render of VendorPrivate) and its opcode.  Once
+     this file is used for other purposes, additional information will
+     need to be added.
+  -->
+
+<category name="1.0" window_system="glX">
+    <function name="Render">
+        <glx sop="1"/>
+    </function>
+
+    <function name="RenderLarge">
+        <glx sop="2"/>
+    </function>
+
+    <function name="CreateContext">
+        <glx sop="3"/>
+    </function>
+
+    <function name="DestroyContext">
+        <glx sop="4"/>
+    </function>
+
+    <function name="MakeCurrent">
+        <glx sop="5"/>
+    </function>
+
+    <function name="IsDirect">
+        <glx sop="6"/>
+    </function>
+
+    <function name="QueryVersion">
+        <glx sop="7"/>
+    </function>
+
+    <function name="WaitGL">
+        <glx sop="8"/>
+    </function>
+
+    <function name="WaitX">
+        <glx sop="9"/>
+    </function>
+
+    <function name="CopyContext">
+        <glx sop="10"/>
+    </function>
+
+    <function name="SwapBuffers">
+        <glx sop="11"/>
+    </function>
+
+    <function name="UseXFont">
+        <glx sop="12"/>
+    </function>
+
+    <function name="CreateGLXPixmap">
+        <glx sop="13"/>
+    </function>
+
+    <function name="GetVisualConfigs">
+        <glx sop="14"/>
+    </function>
+
+    <function name="DestroyGLXPixmap">
+        <glx sop="15"/>
+    </function>
+
+    <function name="VendorPrivate">
+        <glx sop="16"/>
+    </function>
+
+    <function name="VendorPrivateWithReply">
+        <glx sop="17"/>
+    </function>
+
+    <function name="QueryExtensionsString">
+        <glx sop="18"/>
+    </function>
+</category>
+
+<category name="1.1" window_system="glX">
+    <function name="QueryServerString">
+        <glx sop="19"/>
+    </function>
+
+    <function name="ClientInfo">
+        <glx sop="20"/>
+    </function>
+</category>
+
+<category name="1.3" window_system="glX">
+    <function name="GetFBConfigs">
+        <glx sop="21"/>
+    </function>
+
+    <function name="CreatePixmap">
+        <glx sop="22"/>
+    </function>
+
+    <function name="DestroyPixmap">
+        <glx sop="23"/>
+    </function>
+
+    <function name="CreateNewContext">
+        <glx sop="24"/>
+    </function>
+
+    <function name="QueryContext">
+        <glx sop="25"/>
+    </function>
+
+    <function name="MakeContextCurrent">
+        <glx sop="26"/>
+    </function>
+
+    <function name="CreatePbuffer">
+        <glx sop="27"/>
+    </function>
+
+    <function name="DestroyPbuffer">
+        <glx sop="28"/>
+    </function>
+
+    <function name="GetDrawableAttributes">
+        <glx sop="29"/>
+    </function>
+
+    <function name="ChangeDrawableAttributes">
+        <glx sop="30"/>
+    </function>
+
+    <function name="CreateWindow">
+        <glx sop="31"/>
+    </function>
+
+    <function name="DestroyWindow">
+        <glx sop="32"/>
+    </function>
+</category>
+
+<category name="GLX_SGI_make_current_read" number="42" window_system="glX">
+    <function name="MakeCurrentReadSGI">
+<!--        <param name="dpy" type="Display *"/>
+       <param name="draw" type="GLXDrawable"/>
+       <param name="read" type="GLXDrawable"/>
+       <param name="ctx" type="GLXContext"/> -->
+        <return type="Bool"/>
+        <glx vendorpriv="65537"/>
+    </function>
+</category>
+
+<category name="GLX_EXT_import_context" number="47" window_system="glX">
+    <function name="QueryContextInfoEXT">
+        <glx vendorpriv="1024"/>
+    </function>
+</category>
+
+<category name="GLX_SGIX_fbconfig" number="49" window_system="glX">
+    <function name="GetFBConfigsSGIX">
+        <glx vendorpriv="65540"/>
+    </function>
+
+    <function name="CreateContextWithConfigSGIX">
+        <glx vendorpriv="65541"/>
+    </function>
+
+    <function name="CreateGLXPixmapWithConfigSGIX">
+        <glx vendorpriv="65542"/>
+    </function>
+</category>
+
+<!--
+<category name="GLX_SGIX_pbuffer" number="50" window_system="glX">
+    <function name="CreateGLXPbufferSGIX">
+        <glx vendorpriv="65543"/>
+    </function>
+
+    <function name="DestroyGLXPbufferSGIX">
+        <glx vendorpriv="65544"/>
+    </function>
+
+    <function name="ChangeDrawableAttributesSGIX">
+        <glx vendorpriv="65545"/>
+    </function>
+
+    <function name="GetDrawableAttributesSGIX">
+        <glx vendorpriv="65546"/>
+    </function>
+</category>
+-->
+
+<category name="GLX_MESA_copy_sub_buffer" number="215">
+    <function name="CopySubBufferMESA">
+        <glx vendorpriv="5154"/>
+    </function>
+</category>
+
+<category name="GLX_EXT_texture_from_pixmap">
+    <function name="BindTexImageEXT">
+        <glx vendorpriv="5152"/>
+    </function>
+
+    <function name="ReleaseTexImageEXT">
+        <glx vendorpriv="5153"/>
+    </function>
+</category>
+
+</OpenGLAPI>
diff --git a/src/mesa/glapi/glX_server_table.py b/src/mesa/glapi/glX_server_table.py
new file mode 100644 (file)
index 0000000..2535b48
--- /dev/null
@@ -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 <idr@us.ibm.com>
+
+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 <inttypes.h>'
+               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 (file)
index 0000000..34c977e
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
+
+<OpenGLAPI>
+<xi:include href="glX_API.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+<xi:include href="gl_API.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+</OpenGLAPI>
\ No newline at end of file