• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding=utf-8
2# -*- Mode: Python; py-indent-offset: 4 -*-
3#
4# Copyright © 2012 Intel Corporation
5#
6# Based on code by Kristian Høgsberg <krh@bitplanet.net>,
7#   extracted from mesa/main/get.c
8#
9# Permission is hereby granted, free of charge, to any person obtaining a
10# copy of this software and associated documentation files (the "Software"),
11# to deal in the Software without restriction, including without limitation
12# on the rights to use, copy, modify, merge, publish, distribute, sub
13# license, and/or sell copies of the Software, and to permit persons to whom
14# the Software is furnished to do so, subject to the following conditions:
15#
16# The above copyright notice and this permission notice (including the next
17# paragraph) shall be included in all copies or substantial portions of the
18# Software.
19#
20# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
23# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26# IN THE SOFTWARE.
27
28# Generate a C header file containing hash tables of glGet parameter
29# names for each GL API. The generated file is to be included by glGet.c
30
31import os, sys, getopt
32from collections import defaultdict
33import get_hash_params
34
35param_desc_file = os.path.join(os.path.dirname(__file__), "get_hash_params.py")
36
37GLAPI = os.path.join(os.path.dirname(__file__), "..", "..", "mapi", "glapi", "gen")
38sys.path.insert(0, GLAPI)
39import gl_XML
40
41prime_factor = 89
42prime_step = 281
43hash_table_size = 1024
44
45gl_apis=set(["GL", "GL_CORE", "GLES", "GLES2", "GLES3", "GLES31", "GLES32"])
46
47def print_header():
48   print("typedef const unsigned short table_t[%d];\n" % (hash_table_size))
49   print("static const int prime_factor = %d, prime_step = %d;\n" % \
50          (prime_factor, prime_step))
51
52def print_params(params):
53   print("static const struct value_desc values[] = {")
54   for p in params:
55      print("    { %s, %s }," % (p[0], p[1]))
56
57   print("};\n")
58
59def api_name(api):
60   return "API_OPEN%s" % api
61
62# This must match gl_api enum in src/mesa/main/mtypes.h
63api_enum = [
64   'GL',
65   'GLES',
66   'GLES2',
67   'GL_CORE',
68   'GLES3', # Not in gl_api enum in mtypes.h
69   'GLES31', # Not in gl_api enum in mtypes.h
70   'GLES32', # Not in gl_api enum in mtypes.h
71]
72
73def api_index(api):
74    return api_enum.index(api)
75
76def table_name(api):
77   return "table_" + api_name(api)
78
79def print_table(api, table):
80   print("static table_t %s = {" % (table_name(api)))
81
82   # convert sparse (index, value) table into a dense table
83   dense_table = [0] * hash_table_size
84   for i, v in table:
85      dense_table[i] = v
86
87   row_size = 4
88   for i in range(0, hash_table_size, row_size):
89      row = dense_table[i : i + row_size]
90      idx_val = ["%4d" % v for v in row]
91      print(" " * 4 + ", ".join(idx_val) + ",")
92
93   print("};\n")
94
95def print_tables(tables):
96   for table in tables:
97      print_table(table["apis"][0], table["indices"])
98
99   dense_tables = ['NULL'] * len(api_enum)
100   for table in tables:
101      tname = table_name(table["apis"][0])
102      for api in table["apis"]:
103         i = api_index(api)
104         dense_tables[i] = "&%s" % (tname)
105
106   print("static table_t *table_set[] = {")
107   for expr in dense_tables:
108      print("   %s," % expr)
109   print("};\n")
110
111   print("#define table(api) (*table_set[api])")
112
113# Merge tables with matching parameter lists (i.e. GL and GL_CORE)
114def merge_tables(tables):
115   merged_tables = []
116   for api, indices in sorted(tables.items()):
117      matching_table = list(filter(lambda mt:mt["indices"] == indices,
118                              merged_tables))
119      if matching_table:
120         matching_table[0]["apis"].append(api)
121      else:
122         merged_tables.append({"apis": [api], "indices": indices})
123
124   return merged_tables
125
126def add_to_hash_table(table, hash_val, value):
127   while True:
128      index = hash_val & (hash_table_size - 1)
129      if index not in table:
130         table[index] = value
131         break
132      hash_val += prime_step
133
134def die(msg):
135   sys.stderr.write("%s: %s\n" % (program, msg))
136   exit(1)
137
138program = os.path.basename(sys.argv[0])
139
140def generate_hash_tables(enum_list, enabled_apis, param_descriptors):
141   tables = defaultdict(lambda:{})
142
143   # the first entry should be invalid, so that get.c:find_value can use
144   # its index for the 'enum not found' condition.
145   params = [[0, ""]]
146
147   for param_block in param_descriptors:
148      if set(["apis", "params"]) != set(param_block):
149         die("missing fields (%s) in param descriptor file (%s)" %
150               (", ".join(set(["apis", "params"]) - set(param_block)),
151                param_desc_file))
152
153      valid_apis = set(param_block["apis"])
154      if valid_apis - gl_apis:
155         die("unknown API(s) in param descriptor file (%s): %s\n" %
156               (param_desc_file, ",".join(valid_apis - gl_apis)))
157
158      if not (valid_apis & enabled_apis):
159         continue
160
161      valid_apis &= enabled_apis
162
163      for param in param_block["params"]:
164         enum_name = param[0]
165         enum_val = enum_list[enum_name].value
166         hash_val = enum_val * prime_factor
167
168         for api in valid_apis:
169            add_to_hash_table(tables[api], hash_val, len(params))
170            # Also add GLES2 items to the GLES3+ hash tables
171            if api == "GLES2":
172               add_to_hash_table(tables["GLES3"], hash_val, len(params))
173               add_to_hash_table(tables["GLES31"], hash_val, len(params))
174               add_to_hash_table(tables["GLES32"], hash_val, len(params))
175            # Also add GLES3 items to the GLES31+ hash tables
176            if api == "GLES3":
177               add_to_hash_table(tables["GLES31"], hash_val, len(params))
178               add_to_hash_table(tables["GLES32"], hash_val, len(params))
179            # Also add GLES31 items to the GLES32+ hash tables
180            if api == "GLES31":
181               add_to_hash_table(tables["GLES32"], hash_val, len(params))
182         params.append(["GL_" + enum_name, param[1]])
183
184   sorted_tables={}
185   for api, indices in tables.items():
186      sorted_tables[api] = sorted(indices.items())
187
188   return params, merge_tables(sorted_tables)
189
190
191def show_usage():
192   sys.stderr.write(
193"""Usage: %s [OPTIONS]
194  -f <file>          specify GL API XML file
195""" % (program))
196   exit(1)
197
198if __name__ == '__main__':
199   try:
200      (opts, args) = getopt.getopt(sys.argv[1:], "f:")
201   except Exception:
202      show_usage()
203
204   if len(args) != 0:
205      show_usage()
206
207   api_desc_file = ""
208
209   for opt_name, opt_val in opts:
210      if opt_name == "-f":
211         api_desc_file = opt_val
212
213   if not api_desc_file:
214      die("missing descriptor file (-f)\n")
215
216   # generate the code for all APIs
217   enabled_apis = set(["GLES", "GLES2", "GLES3", "GLES31", "GLES32",
218                       "GL", "GL_CORE"])
219
220   try:
221      api_desc = gl_XML.parse_GL_API(api_desc_file)
222   except Exception:
223      die("couldn't parse API specification file %s\n" % api_desc_file)
224
225   (params, hash_tables) = generate_hash_tables(api_desc.enums_by_name,
226                              enabled_apis, get_hash_params.descriptor)
227
228   print_header()
229   print_params(params)
230   print_tables(hash_tables)
231