1 2# Copyright (C) 2012 Intel Corporation 3# 4# Permission is hereby granted, free of charge, to any person obtaining a 5# copy of this software and associated documentation files (the "Software"), 6# to deal in the Software without restriction, including without limitation 7# the rights to use, copy, modify, merge, publish, distribute, sublicense, 8# and/or sell copies of the Software, and to permit persons to whom the 9# Software is furnished to do so, subject to the following conditions: 10# 11# The above copyright notice and this permission notice (including the next 12# paragraph) shall be included in all copies or substantial portions of the 13# Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21# IN THE SOFTWARE. 22 23from __future__ import print_function 24 25import contextlib 26import getopt 27import gl_XML 28import license 29import marshal_XML 30import sys 31 32header = """ 33#include "api_exec.h" 34#include "glthread_marshal.h" 35#include "bufferobj.h" 36#include "dispatch.h" 37 38#define COMPAT (ctx->API != API_OPENGL_CORE) 39 40UNUSED static inline int safe_mul(int a, int b) 41{ 42 if (a < 0 || b < 0) return -1; 43 if (a == 0 || b == 0) return 0; 44 if (a > INT_MAX / b) return -1; 45 return a * b; 46} 47""" 48 49 50file_index = 0 51file_count = 1 52current_indent = 0 53 54 55def out(str): 56 if str: 57 print(' '*current_indent + str) 58 else: 59 print('') 60 61 62@contextlib.contextmanager 63def indent(delta = 3): 64 global current_indent 65 current_indent += delta 66 yield 67 current_indent -= delta 68 69 70class PrintCode(gl_XML.gl_print_base): 71 def __init__(self): 72 super(PrintCode, self).__init__() 73 74 self.name = 'gl_marshal.py' 75 self.license = license.bsd_license_template % ( 76 'Copyright (C) 2012 Intel Corporation', 'INTEL CORPORATION') 77 78 def printRealHeader(self): 79 print(header) 80 81 def printRealFooter(self): 82 pass 83 84 def print_sync_call(self, func, unmarshal = 0): 85 call = 'CALL_{0}(ctx->CurrentServerDispatch, ({1}))'.format( 86 func.name, func.get_called_parameter_string()) 87 if func.return_type == 'void': 88 out('{0};'.format(call)) 89 if func.marshal_call_after and not unmarshal: 90 out(func.marshal_call_after); 91 else: 92 out('return {0};'.format(call)) 93 assert not func.marshal_call_after 94 95 def print_sync_body(self, func): 96 out('/* {0}: marshalled synchronously */'.format(func.name)) 97 out('{0} GLAPIENTRY'.format(func.return_type)) 98 out('_mesa_marshal_{0}({1})'.format(func.name, func.get_parameter_string())) 99 out('{') 100 with indent(): 101 out('GET_CURRENT_CONTEXT(ctx);') 102 out('_mesa_glthread_finish_before(ctx, "{0}");'.format(func.name)) 103 self.print_sync_call(func) 104 out('}') 105 out('') 106 out('') 107 108 def print_async_dispatch(self, func): 109 out('cmd = _mesa_glthread_allocate_command(ctx, ' 110 'DISPATCH_CMD_{0}, cmd_size);'.format(func.name)) 111 for p in func.fixed_params: 112 if p.count: 113 out('memcpy(cmd->{0}, {0}, {1});'.format( 114 p.name, p.size_string())) 115 else: 116 out('cmd->{0} = {0};'.format(p.name)) 117 if func.variable_params: 118 out('char *variable_data = (char *) (cmd + 1);') 119 i = 1 120 for p in func.variable_params: 121 if p.img_null_flag: 122 out('cmd->{0}_null = !{0};'.format(p.name)) 123 out('if (!cmd->{0}_null) {{'.format(p.name)) 124 with indent(): 125 out(('memcpy(variable_data, {0}, {0}_size);').format(p.name)) 126 if i < len(func.variable_params): 127 out('variable_data += {0}_size;'.format(p.name)) 128 out('}') 129 else: 130 out(('memcpy(variable_data, {0}, {0}_size);').format(p.name)) 131 if i < len(func.variable_params): 132 out('variable_data += {0}_size;'.format(p.name)) 133 i += 1 134 135 if not func.fixed_params and not func.variable_params: 136 out('(void) cmd;') 137 138 if func.marshal_call_after: 139 out(func.marshal_call_after); 140 141 # Uncomment this if you want to call _mesa_glthread_finish for debugging 142 #out('_mesa_glthread_finish(ctx);') 143 144 def get_type_size(self, str): 145 if str.find('*') != -1: 146 return 8; 147 148 mapping = { 149 'GLboolean': 1, 150 'GLbyte': 1, 151 'GLubyte': 1, 152 'GLshort': 2, 153 'GLushort': 2, 154 'GLhalfNV': 2, 155 'GLenum': 4, 156 'GLint': 4, 157 'GLuint': 4, 158 'GLbitfield': 4, 159 'GLsizei': 4, 160 'GLfloat': 4, 161 'GLclampf': 4, 162 'GLfixed': 4, 163 'GLclampx': 4, 164 'GLhandleARB': 4, 165 'int': 4, 166 'float': 4, 167 'GLdouble': 8, 168 'GLclampd': 8, 169 'GLintptr': 8, 170 'GLsizeiptr': 8, 171 'GLint64': 8, 172 'GLuint64': 8, 173 'GLuint64EXT': 8, 174 'GLsync': 8, 175 } 176 val = mapping.get(str, 9999) 177 if val == 9999: 178 print('Unhandled type in gl_marshal.py.get_type_size: ' + str, file=sys.stderr) 179 return val 180 181 def print_async_struct(self, func): 182 out('struct marshal_cmd_{0}'.format(func.name)) 183 out('{') 184 with indent(): 185 out('struct marshal_cmd_base cmd_base;') 186 187 # Sort the parameters according to their size to pack the structure optimally 188 for p in sorted(func.fixed_params, key=lambda p: self.get_type_size(p.type_string())): 189 if p.count: 190 out('{0} {1}[{2}];'.format( 191 p.get_base_type_string(), p.name, p.count)) 192 else: 193 out('{0} {1};'.format(p.type_string(), p.name)) 194 195 for p in func.variable_params: 196 if p.img_null_flag: 197 out('bool {0}_null; /* If set, no data follows ' 198 'for "{0}" */'.format(p.name)) 199 200 for p in func.variable_params: 201 if p.count_scale != 1: 202 out(('/* Next {0} bytes are ' 203 '{1} {2}[{3}][{4}] */').format( 204 p.size_string(marshal = 1), p.get_base_type_string(), 205 p.name, p.counter, p.count_scale)) 206 else: 207 out(('/* Next {0} bytes are ' 208 '{1} {2}[{3}] */').format( 209 p.size_string(marshal = 1), p.get_base_type_string(), 210 p.name, p.counter)) 211 out('};') 212 213 def print_async_unmarshal(self, func): 214 out('void') 215 out(('_mesa_unmarshal_{0}(struct gl_context *ctx, ' 216 'const struct marshal_cmd_{0} *cmd)').format(func.name)) 217 out('{') 218 with indent(): 219 for p in func.fixed_params: 220 if p.count: 221 p_decl = '{0} * {1} = cmd->{1};'.format( 222 p.get_base_type_string(), p.name) 223 else: 224 p_decl = '{0} {1} = cmd->{1};'.format( 225 p.type_string(), p.name) 226 227 if not p_decl.startswith('const '): 228 # Declare all local function variables as const, even if 229 # the original parameter is not const. 230 p_decl = 'const ' + p_decl 231 232 out(p_decl) 233 234 if func.variable_params: 235 for p in func.variable_params: 236 out('{0} * {1};'.format( 237 p.get_base_type_string(), p.name)) 238 out('const char *variable_data = (const char *) (cmd + 1);') 239 i = 1 240 for p in func.variable_params: 241 out('{0} = ({1} *) variable_data;'.format( 242 p.name, p.get_base_type_string())) 243 244 if p.img_null_flag: 245 out('if (cmd->{0}_null)'.format(p.name)) 246 with indent(): 247 out('{0} = NULL;'.format(p.name)) 248 if i < len(func.variable_params): 249 out('else') 250 with indent(): 251 out('variable_data += {0};'.format(p.size_string(False, marshal = 1))) 252 elif i < len(func.variable_params): 253 out('variable_data += {0};'.format(p.size_string(False, marshal = 1))) 254 i += 1 255 256 self.print_sync_call(func, unmarshal = 1) 257 out('}') 258 259 def validate_count_or_fallback(self, func): 260 # Check that any counts for variable-length arguments might be < 0, in 261 # which case the command alloc or the memcpy would blow up before we 262 # get to the validation in Mesa core. 263 list = [] 264 for p in func.parameters: 265 if p.is_variable_length(): 266 list.append('{0}_size < 0'.format(p.name)) 267 list.append('({0}_size > 0 && !{0})'.format(p.name)) 268 269 if len(list) == 0: 270 return 271 272 list.append('(unsigned)cmd_size > MARSHAL_MAX_CMD_SIZE') 273 274 out('if (unlikely({0})) {{'.format(' || '.join(list))) 275 with indent(): 276 out('_mesa_glthread_finish_before(ctx, "{0}");'.format(func.name)) 277 self.print_sync_call(func) 278 out('return;') 279 out('}') 280 281 def print_async_marshal(self, func): 282 out('void GLAPIENTRY') 283 out('_mesa_marshal_{0}({1})'.format( 284 func.name, func.get_parameter_string())) 285 out('{') 286 with indent(): 287 out('GET_CURRENT_CONTEXT(ctx);') 288 for p in func.variable_params: 289 out('int {0}_size = {1};'.format(p.name, p.size_string(marshal = 1))) 290 291 struct = 'struct marshal_cmd_{0}'.format(func.name) 292 size_terms = ['sizeof({0})'.format(struct)] 293 for p in func.variable_params: 294 if p.img_null_flag: 295 size_terms.append('({0} ? {0}_size : 0)'.format(p.name)) 296 else: 297 size_terms.append('{0}_size'.format(p.name)) 298 out('int cmd_size = {0};'.format(' + '.join(size_terms))) 299 out('{0} *cmd;'.format(struct)) 300 301 self.validate_count_or_fallback(func) 302 303 if func.marshal_sync: 304 out('if ({0}) {{'.format(func.marshal_sync)) 305 with indent(): 306 out('_mesa_glthread_finish_before(ctx, "{0}");'.format(func.name)) 307 self.print_sync_call(func) 308 out('return;') 309 out('}') 310 311 with indent(): 312 self.print_async_dispatch(func) 313 out('}') 314 315 def print_async_body(self, func): 316 out('/* {0}: marshalled asynchronously */'.format(func.name)) 317 self.print_async_struct(func) 318 self.print_async_unmarshal(func) 319 self.print_async_marshal(func) 320 out('') 321 out('') 322 323 def print_unmarshal_dispatch_cmd(self, api): 324 out('const _mesa_unmarshal_func _mesa_unmarshal_dispatch[NUM_DISPATCH_CMD] = {') 325 with indent(): 326 for func in api.functionIterateAll(): 327 flavor = func.marshal_flavor() 328 if flavor in ('skip', 'sync'): 329 continue 330 out('[DISPATCH_CMD_{0}] = (_mesa_unmarshal_func)_mesa_unmarshal_{0},'.format(func.name)) 331 out('};') 332 out('') 333 out('') 334 335 def print_create_marshal_table(self, api): 336 out('/* _mesa_create_marshal_table takes a long time to compile with -O2 */') 337 out('#if defined(__GNUC__) && !defined(__clang__)') 338 out('__attribute__((optimize("O1")))') 339 out('#endif') 340 out('struct _glapi_table *') 341 out('_mesa_create_marshal_table(const struct gl_context *ctx)') 342 out('{') 343 with indent(): 344 out('struct _glapi_table *table;') 345 out('') 346 out('table = _mesa_alloc_dispatch_table();') 347 out('if (table == NULL)') 348 with indent(): 349 out('return NULL;') 350 out('') 351 for func in api.functionIterateAll(): 352 if func.marshal_flavor() == 'skip': 353 continue 354 # Don't use the SET_* functions, because they increase compile time 355 # by 20 seconds (on Ryzen 1700X). 356 out('if (_gloffset_{0} >= 0)'.format(func.name)) 357 out(' ((_glapi_proc *)(table))[_gloffset_{0}] = (_glapi_proc)_mesa_marshal_{0};' 358 .format(func.name)) 359 out('') 360 out('return table;') 361 out('}') 362 out('') 363 out('') 364 365 def printBody(self, api): 366 # The first file only contains the dispatch tables 367 if file_index == 0: 368 self.print_unmarshal_dispatch_cmd(api) 369 self.print_create_marshal_table(api) 370 return 371 372 # The remaining files contain the marshal and unmarshal functions 373 func_per_file = (len(api.functionIterateAll()) // (file_count - 1)) + 1 374 i = -1 375 for func in api.functionIterateAll(): 376 i += 1 377 if i // func_per_file != (file_index - 1): 378 continue 379 380 flavor = func.marshal_flavor() 381 if flavor in ('skip', 'custom'): 382 continue 383 elif flavor == 'async': 384 self.print_async_body(func) 385 elif flavor == 'sync': 386 self.print_sync_body(func) 387 388 389def show_usage(): 390 print('Usage: %s [-f input_file_name]' % sys.argv[0]) 391 sys.exit(1) 392 393 394if __name__ == '__main__': 395 file_name = 'gl_API.xml' 396 397 try: 398 (args, trail) = getopt.getopt(sys.argv[1:], 'm:f:i:n:') 399 except Exception: 400 show_usage() 401 402 for (arg,val) in args: 403 if arg == '-f': 404 file_name = val 405 elif arg == '-i': 406 file_index = int(val) 407 elif arg == '-n': 408 file_count = int(val) 409 410 assert file_index < file_count 411 printer = PrintCode() 412 413 api = gl_XML.parse_GL_API(file_name, marshal_XML.marshal_item_factory()) 414 printer.Print(api) 415