[Mesa-dev] [RFC 07/13] mapi/glapi/gen: Add python module with abstractions from Khronos XML

Dylan Baker dylan at pnwbakers.com
Fri Nov 23 22:27:56 UTC 2018


These helpers form an abstraction over the krhonos XML and help deal
with some of the warts of the XML format, as well as generally making
the XML easier to work with.
---
 src/mapi/glapi/gen/Makefile.am |   3 +-
 src/mapi/glapi/gen/khr_xml.py  | 180 +++++++++++++++++++++++++++++++++
 2 files changed, 182 insertions(+), 1 deletion(-)
 create mode 100644 src/mapi/glapi/gen/khr_xml.py

diff --git a/src/mapi/glapi/gen/Makefile.am b/src/mapi/glapi/gen/Makefile.am
index 8158dffd719..2e37060da95 100644
--- a/src/mapi/glapi/gen/Makefile.am
+++ b/src/mapi/glapi/gen/Makefile.am
@@ -92,7 +92,8 @@ EXTRA_DIST= \
 	SConscript \
 	gl_API.dtd \
 	meson.build \
-	mesa_data.py
+	mesa_data.py \
+	khr_xml.py
 
 ######################################################################
 
diff --git a/src/mapi/glapi/gen/khr_xml.py b/src/mapi/glapi/gen/khr_xml.py
new file mode 100644
index 00000000000..784931b5059
--- /dev/null
+++ b/src/mapi/glapi/gen/khr_xml.py
@@ -0,0 +1,180 @@
+# encoding=utf-8
+# Copyright © 2018 Intel Corporation
+
+# 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 the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS 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.
+
+"""Representations of the Khronos XML.
+
+This module contains classes to represent the data encoded in the Khronos XML,
+and to work around some less than optimal representations
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import attr
+import six
+
+import mesa_data
+
+
+ at attr.s
+class Length(object):
+
+    """Represents the length parameter in the Khronos XML.
+
+    This is a non-trivial parameter, it can be a number, an anonymous function,
+    a declared function, or a string referencing another parameter.
+
+    :param int value: If the length of the parameter is static, this is the number
+    :param str count: If the length of the parameter is is based on another
+        parameter, this is the name of that parameter
+    :param int scale: If there is a scaling factor for count, this is that
+        factor. Note that this means nothing if count is None
+    :param List[str] computed: If the value is computed from one or more
+        paramters this list is those parameters
+    """
+
+    value = attr.ib(default=None)     # type: Optional[int]
+    count = attr.ib(default=None)     # type: Optional[str]
+    scale = attr.ib(default=None)     # type: Optional[int]
+    computed = attr.ib(default=None)  # type: Optional[List[str]]
+
+    def is_static(self):
+        return self.value is not None
+
+    def is_dynamic(self):
+        return bool(self.count or self.computed)
+
+    def __nonzero__(self):
+        return bool(self.value or self.count or self.computed)
+
+    @classmethod
+    def from_xml(cls, string):
+        """Converts a string from the Khronos XML into a Length instance.
+
+        :param Optional[str] string: A string or None to be converted.
+        """
+        if string is None:
+            return cls()
+        elif string.isdigit():
+            return cls(value=int(string))
+        elif string.startswith('COMPSIZE'):
+            string = string.lstrip('COMPSIZE(').rstrip(')')
+            return cls(computed=string.split(','))
+        elif '*' in string:
+            count, scale = string.split('*')
+            return cls(count=count, scale=int(scale))
+        assert string, 'Wat?'
+        return cls(count=string, scale=1)
+
+
+ at attr.s(str=False)
+class Param(object):
+
+    """Represents an function parameter."""
+
+    name = attr.ib(type=six.text_type)
+    type = attr.ib(type=six.text_type)
+    prefix = attr.ib()  # type: Optional[six.text_type]
+    suffix = attr.ib()  # type: Optional[six.text_type]
+    len = attr.ib()     # type: Optional[six.text_type]
+
+    def is_pointer(self):
+        if self.suffix is not None:
+            return '*' in self.suffix
+        return False
+
+    def __str__(self):
+        vals = []
+        if self.prefix:
+            vals.append(self.prefix)
+        vals.append(self.type)
+        if self.suffix:
+            vals.append(self.suffix)
+        vals.append(self.name)
+        return ' '.join(vals)
+
+
+ at attr.s
+class Proto(object):
+
+    """Represents a function prototype."""
+
+    name = attr.ib(type=six.text_type)
+    return_type = attr.ib(type=six.text_type)
+
+
+ at attr.s
+class Function(object):
+
+    """Represents an OpenGL function."""
+
+    proto = attr.ib(type=Proto)
+    params = attr.ib()            # type: List[Param]
+    mesa = attr.ib(default=None)  # type: Optional[mesa_data.GLFunction]
+
+    @property
+    def name(self):
+        return self.proto.name
+
+    @property
+    def return_type(self):
+        return self.proto.return_type
+
+    def is_implemented(self):
+        return self.mesa is not None
+
+
+def make_functions(xml):
+    """Generator that converts xml into Function objects.
+
+    :param xml.etree.ElementTree.Element xml: The khronos XML in etree format
+    """
+    for elem in xml.findall('.//commands/command'):
+        p = elem.find('./proto')
+        if p.text:
+            ptype = p.text.strip()
+        else:
+            ptype = p.find('./ptype').text
+        proto = Proto(p.find('./name').text[2:], ptype)
+
+        params = []
+        for param in elem.findall('.//param'):
+            t = param.find('./ptype')
+            name = param.find('./name').text.strip()
+            type_ = t.text.strip() if t is not None else None
+            prefix = param.text.strip() if param.text else None
+            suffix = t.tail.strip() if t is not None else None
+            len_ = Length.from_xml(param.attrib.get('len'))
+
+            if not type_:
+
+                split = prefix.split(' ')
+                assert 1 < len(split) <= 3
+                if len(split) == 3:
+                    prefix, type_, suffix = split
+                if len(split) == 2:
+                    if split[-1] == '*':
+                        type_, suffix = split
+                    else:
+                        prefix, type_ = split
+
+            params.append(Param(name, type_, prefix, suffix, len_))
+
+        yield Function(proto, params, mesa_data.FUNCTIONS.get(proto.name))
-- 
2.19.2



More information about the mesa-dev mailing list