~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/mapi/new/genCommon.py

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python3
2
 
 
3
 
# (C) Copyright 2015, NVIDIA CORPORATION.
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
 
#    Kyle Brenneman <kbrenneman@nvidia.com>
27
 
 
28
 
import collections
29
 
import re
30
 
import sys
31
 
import xml.etree.ElementTree as etree
32
 
 
33
 
import os
34
 
GLAPI = os.path.join(os.path.dirname(__file__), "..", "glapi", "gen")
35
 
sys.path.insert(0, GLAPI)
36
 
import static_data
37
 
 
38
 
MAPI_TABLE_NUM_DYNAMIC = 4096
39
 
 
40
 
_LIBRARY_FEATURE_NAMES = {
41
 
    # libGL and libGLdiapatch both include every function.
42
 
    "gl" : None,
43
 
    "gldispatch" : None,
44
 
    "opengl" : frozenset(( "GL_VERSION_1_0", "GL_VERSION_1_1",
45
 
        "GL_VERSION_1_2", "GL_VERSION_1_3", "GL_VERSION_1_4", "GL_VERSION_1_5",
46
 
        "GL_VERSION_2_0", "GL_VERSION_2_1", "GL_VERSION_3_0", "GL_VERSION_3_1",
47
 
        "GL_VERSION_3_2", "GL_VERSION_3_3", "GL_VERSION_4_0", "GL_VERSION_4_1",
48
 
        "GL_VERSION_4_2", "GL_VERSION_4_3", "GL_VERSION_4_4", "GL_VERSION_4_5",
49
 
    )),
50
 
    "glesv1" : frozenset(("GL_VERSION_ES_CM_1_0", "GL_OES_point_size_array")),
51
 
    "glesv2" : frozenset(("GL_ES_VERSION_2_0", "GL_ES_VERSION_3_0",
52
 
            "GL_ES_VERSION_3_1", "GL_ES_VERSION_3_2",
53
 
    )),
54
 
}
55
 
 
56
 
def getFunctions(xmlFiles):
57
 
    """
58
 
    Reads an XML file and returns all of the functions defined in it.
59
 
 
60
 
    xmlFile should be the path to Khronos's gl.xml file. The return value is a
61
 
    sequence of FunctionDesc objects, ordered by slot number.
62
 
    """
63
 
    roots = [ etree.parse(xmlFile).getroot() for xmlFile in xmlFiles ]
64
 
    return getFunctionsFromRoots(roots)
65
 
 
66
 
def getFunctionsFromRoots(roots):
67
 
    functions = {}
68
 
    for root in roots:
69
 
        for func in _getFunctionList(root):
70
 
            functions[func.name] = func
71
 
    functions = functions.values()
72
 
 
73
 
    # Sort the function list by name.
74
 
    functions = sorted(functions, key=lambda f: f.name)
75
 
 
76
 
    # Lookup for fixed offset/slot functions and use it if available.
77
 
    # Assign a slot number to each function. This isn't strictly necessary,
78
 
    # since you can just look at the index in the list, but it makes it easier
79
 
    # to include the slot when formatting output.
80
 
 
81
 
    next_slot = 0
82
 
    for i in range(len(functions)):
83
 
        name = functions[i].name[2:]
84
 
 
85
 
        if name in static_data.offsets:
86
 
            functions[i] = functions[i]._replace(slot=static_data.offsets[name])
87
 
        elif not name.endswith("ARB") and name + "ARB" in static_data.offsets:
88
 
            functions[i] = functions[i]._replace(slot=static_data.offsets[name + "ARB"])
89
 
        elif not name.endswith("EXT") and name + "EXT" in static_data.offsets:
90
 
            functions[i] = functions[i]._replace(slot=static_data.offsets[name + "EXT"])
91
 
        else:
92
 
            functions[i] = functions[i]._replace(slot=next_slot)
93
 
            next_slot += 1
94
 
 
95
 
    return functions
96
 
 
97
 
def getExportNamesFromRoots(target, roots):
98
 
    """
99
 
    Goes through the <feature> tags from gl.xml and returns a set of OpenGL
100
 
    functions that a library should export.
101
 
 
102
 
    target should be one of "gl", "gldispatch", "opengl", "glesv1", or
103
 
    "glesv2".
104
 
    """
105
 
    featureNames = _LIBRARY_FEATURE_NAMES[target]
106
 
    if featureNames is None:
107
 
        return set(func.name for func in getFunctionsFromRoots(roots))
108
 
 
109
 
    names = set()
110
 
    for root in roots:
111
 
        features = []
112
 
        for featElem in root.findall("feature"):
113
 
            if featElem.get("name") in featureNames:
114
 
                features.append(featElem)
115
 
        for featElem in root.findall("extensions/extension"):
116
 
            if featElem.get("name") in featureNames:
117
 
                features.append(featElem)
118
 
        for featElem in features:
119
 
            for commandElem in featElem.findall("require/command"):
120
 
                names.add(commandElem.get("name"))
121
 
    return names
122
 
 
123
 
class FunctionArg(collections.namedtuple("FunctionArg", "type name")):
124
 
    @property
125
 
    def dec(self):
126
 
        """
127
 
        Returns a "TYPE NAME" string, suitable for a function prototype.
128
 
        """
129
 
        rv = str(self.type)
130
 
        if not rv.endswith("*"):
131
 
            rv += " "
132
 
        rv += self.name
133
 
        return rv
134
 
 
135
 
class FunctionDesc(collections.namedtuple("FunctionDesc", "name rt args slot")):
136
 
    def hasReturn(self):
137
 
        """
138
 
        Returns true if the function returns a value.
139
 
        """
140
 
        return (self.rt != "void")
141
 
 
142
 
    @property
143
 
    def decArgs(self):
144
 
        """
145
 
        Returns a string with the types and names of the arguments, as you
146
 
        would use in a function declaration.
147
 
        """
148
 
        if not self.args:
149
 
            return "void"
150
 
        else:
151
 
            return ", ".join(arg.dec for arg in self.args)
152
 
 
153
 
    @property
154
 
    def callArgs(self):
155
 
        """
156
 
        Returns a string with the names of the arguments, as you would use in a
157
 
        function call.
158
 
        """
159
 
        return ", ".join(arg.name for arg in self.args)
160
 
 
161
 
    @property
162
 
    def basename(self):
163
 
        assert self.name.startswith("gl")
164
 
        return self.name[2:]
165
 
 
166
 
def _getFunctionList(root):
167
 
    for elem in root.findall("commands/command"):
168
 
        yield _parseCommandElem(elem)
169
 
 
170
 
def _parseCommandElem(elem):
171
 
    protoElem = elem.find("proto")
172
 
    (rt, name) = _parseProtoElem(protoElem)
173
 
 
174
 
    args = []
175
 
    for ch in elem.findall("param"):
176
 
        # <param> tags have the same format as a <proto> tag.
177
 
        args.append(FunctionArg(*_parseProtoElem(ch)))
178
 
    func = FunctionDesc(name, rt, tuple(args), slot=None)
179
 
 
180
 
    return func
181
 
 
182
 
def _parseProtoElem(elem):
183
 
    # If I just remove the tags and string the text together, I'll get valid C code.
184
 
    text = _flattenText(elem)
185
 
    text = text.strip()
186
 
    m = re.match(r"^(.+)\b(\w+)(?:\s*\[\s*(\d*)\s*\])?$", text, re.S)
187
 
    if m:
188
 
        typename = _fixupTypeName(m.group(1))
189
 
        name = m.group(2)
190
 
        if m.group(3):
191
 
            # HACK: glPathGlyphIndexRangeNV defines an argument like this:
192
 
            # GLuint baseAndCount[2]
193
 
            # Convert it to a pointer and hope for the best.
194
 
            typename += "*"
195
 
        return (typename, name)
196
 
    else:
197
 
        raise ValueError("Can't parse element %r -> %r" % (elem, text))
198
 
 
199
 
def _flattenText(elem):
200
 
    """
201
 
    Returns the text in an element and all child elements, with the tags
202
 
    removed.
203
 
    """
204
 
    text = ""
205
 
    if elem.text is not None:
206
 
        text = elem.text
207
 
    for ch in elem:
208
 
        text += _flattenText(ch)
209
 
        if ch.tail is not None:
210
 
            text += ch.tail
211
 
    return text
212
 
 
213
 
def _fixupTypeName(typeName):
214
 
    """
215
 
    Converts a typename into a more consistent format.
216
 
    """
217
 
 
218
 
    rv = typeName.strip()
219
 
 
220
 
    # Replace "GLvoid" with just plain "void".
221
 
    rv = re.sub(r"\bGLvoid\b", "void", rv)
222
 
 
223
 
    # Remove the vendor suffixes from types that have a suffix-less version.
224
 
    rv = re.sub(r"\b(GLhalf|GLintptr|GLsizeiptr|GLint64|GLuint64)(?:ARB|EXT|NV|ATI)\b", r"\1", rv)
225
 
 
226
 
    rv = re.sub(r"\bGLDEBUGPROCKHR\b", "GLDEBUGPROC", rv)
227
 
 
228
 
    # Clear out any leading and trailing whitespace.
229
 
    rv = rv.strip()
230
 
 
231
 
    # Remove any whitespace before a '*'
232
 
    rv = re.sub(r"\s+\*", r"*", rv)
233
 
 
234
 
    # Change "foo*" to "foo *"
235
 
    rv = re.sub(r"([^\*])\*", r"\1 *", rv)
236
 
 
237
 
    # Condense all whitespace into a single space.
238
 
    rv = re.sub(r"\s+", " ", rv)
239
 
 
240
 
    return rv
241