gl_marshal.py revision 9f464c52
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 "context.h" 35#include "dispatch.h" 36#include "glthread.h" 37#include "marshal.h" 38#include "marshal_generated.h" 39""" 40 41 42current_indent = 0 43 44 45def out(str): 46 if str: 47 print(' '*current_indent + str) 48 else: 49 print('') 50 51 52@contextlib.contextmanager 53def indent(delta = 3): 54 global current_indent 55 current_indent += delta 56 yield 57 current_indent -= delta 58 59 60class PrintCode(gl_XML.gl_print_base): 61 def __init__(self): 62 super(PrintCode, self).__init__() 63 64 self.name = 'gl_marshal.py' 65 self.license = license.bsd_license_template % ( 66 'Copyright (C) 2012 Intel Corporation', 'INTEL CORPORATION') 67 68 def printRealHeader(self): 69 print(header) 70 print('static inline int safe_mul(int a, int b)') 71 print('{') 72 print(' if (a < 0 || b < 0) return -1;') 73 print(' if (a == 0 || b == 0) return 0;') 74 print(' if (a > INT_MAX / b) return -1;') 75 print(' return a * b;') 76 print('}') 77 print() 78 79 def printRealFooter(self): 80 pass 81 82 def print_sync_call(self, func): 83 call = 'CALL_{0}(ctx->CurrentServerDispatch, ({1}))'.format( 84 func.name, func.get_called_parameter_string()) 85 if func.return_type == 'void': 86 out('{0};'.format(call)) 87 else: 88 out('return {0};'.format(call)) 89 90 def print_sync_dispatch(self, func): 91 out('debug_print_sync_fallback("{0}");'.format(func.name)) 92 self.print_sync_call(func) 93 94 def print_sync_body(self, func): 95 out('/* {0}: marshalled synchronously */'.format(func.name)) 96 out('static {0} GLAPIENTRY'.format(func.return_type)) 97 out('_mesa_marshal_{0}({1})'.format(func.name, func.get_parameter_string())) 98 out('{') 99 with indent(): 100 out('GET_CURRENT_CONTEXT(ctx);') 101 out('_mesa_glthread_finish(ctx);') 102 out('debug_print_sync("{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 for p in func.variable_params: 120 if p.img_null_flag: 121 out('cmd->{0}_null = !{0};'.format(p.name)) 122 out('if (!cmd->{0}_null) {{'.format(p.name)) 123 with indent(): 124 out(('memcpy(variable_data, {0}, {1});').format( 125 p.name, p.size_string(False))) 126 out('variable_data += {0};'.format( 127 p.size_string(False))) 128 out('}') 129 else: 130 out(('memcpy(variable_data, {0}, {1});').format( 131 p.name, p.size_string(False))) 132 out('variable_data += {0};'.format( 133 p.size_string(False))) 134 135 if not func.fixed_params and not func.variable_params: 136 out('(void) cmd;\n') 137 out('_mesa_post_marshal_hook(ctx);') 138 139 def print_async_struct(self, func): 140 out('struct marshal_cmd_{0}'.format(func.name)) 141 out('{') 142 with indent(): 143 out('struct marshal_cmd_base cmd_base;') 144 for p in func.fixed_params: 145 if p.count: 146 out('{0} {1}[{2}];'.format( 147 p.get_base_type_string(), p.name, p.count)) 148 else: 149 out('{0} {1};'.format(p.type_string(), p.name)) 150 151 for p in func.variable_params: 152 if p.img_null_flag: 153 out('bool {0}_null; /* If set, no data follows ' 154 'for "{0}" */'.format(p.name)) 155 156 for p in func.variable_params: 157 if p.count_scale != 1: 158 out(('/* Next {0} bytes are ' 159 '{1} {2}[{3}][{4}] */').format( 160 p.size_string(), p.get_base_type_string(), 161 p.name, p.counter, p.count_scale)) 162 else: 163 out(('/* Next {0} bytes are ' 164 '{1} {2}[{3}] */').format( 165 p.size_string(), p.get_base_type_string(), 166 p.name, p.counter)) 167 out('};') 168 169 def print_async_unmarshal(self, func): 170 out('static inline void') 171 out(('_mesa_unmarshal_{0}(struct gl_context *ctx, ' 172 'const struct marshal_cmd_{0} *cmd)').format(func.name)) 173 out('{') 174 with indent(): 175 for p in func.fixed_params: 176 if p.count: 177 p_decl = '{0} * {1} = cmd->{1};'.format( 178 p.get_base_type_string(), p.name) 179 else: 180 p_decl = '{0} {1} = cmd->{1};'.format( 181 p.type_string(), p.name) 182 183 if not p_decl.startswith('const '): 184 # Declare all local function variables as const, even if 185 # the original parameter is not const. 186 p_decl = 'const ' + p_decl 187 188 out(p_decl) 189 190 if func.variable_params: 191 for p in func.variable_params: 192 out('const {0} * {1};'.format( 193 p.get_base_type_string(), p.name)) 194 out('const char *variable_data = (const char *) (cmd + 1);') 195 for p in func.variable_params: 196 out('{0} = (const {1} *) variable_data;'.format( 197 p.name, p.get_base_type_string())) 198 199 if p.img_null_flag: 200 out('if (cmd->{0}_null)'.format(p.name)) 201 with indent(): 202 out('{0} = NULL;'.format(p.name)) 203 out('else') 204 with indent(): 205 out('variable_data += {0};'.format(p.size_string(False))) 206 else: 207 out('variable_data += {0};'.format(p.size_string(False))) 208 209 self.print_sync_call(func) 210 out('}') 211 212 def validate_count_or_fallback(self, func): 213 # Check that any counts for variable-length arguments might be < 0, in 214 # which case the command alloc or the memcpy would blow up before we 215 # get to the validation in Mesa core. 216 for p in func.parameters: 217 if p.is_variable_length(): 218 out('if (unlikely({0} < 0)) {{'.format(p.size_string())) 219 with indent(): 220 out('goto fallback_to_sync;') 221 out('}') 222 return True 223 return False 224 225 226 def print_async_marshal(self, func): 227 need_fallback_sync = False 228 out('static void GLAPIENTRY') 229 out('_mesa_marshal_{0}({1})'.format( 230 func.name, func.get_parameter_string())) 231 out('{') 232 with indent(): 233 out('GET_CURRENT_CONTEXT(ctx);') 234 struct = 'struct marshal_cmd_{0}'.format(func.name) 235 size_terms = ['sizeof({0})'.format(struct)] 236 for p in func.variable_params: 237 size = p.size_string() 238 if p.img_null_flag: 239 size = '({0} ? {1} : 0)'.format(p.name, size) 240 size_terms.append(size) 241 out('size_t cmd_size = {0};'.format(' + '.join(size_terms))) 242 out('{0} *cmd;'.format(struct)) 243 244 out('debug_print_marshal("{0}");'.format(func.name)) 245 246 need_fallback_sync = self.validate_count_or_fallback(func) 247 248 if func.marshal_fail: 249 out('if ({0}) {{'.format(func.marshal_fail)) 250 with indent(): 251 out('_mesa_glthread_finish(ctx);') 252 out('_mesa_glthread_restore_dispatch(ctx, __func__);') 253 self.print_sync_dispatch(func) 254 out('return;') 255 out('}') 256 257 out('if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {') 258 with indent(): 259 self.print_async_dispatch(func) 260 out('return;') 261 out('}') 262 263 out('') 264 if need_fallback_sync: 265 out('fallback_to_sync:') 266 with indent(): 267 out('_mesa_glthread_finish(ctx);') 268 self.print_sync_dispatch(func) 269 270 out('}') 271 272 def print_async_body(self, func): 273 out('/* {0}: marshalled asynchronously */'.format(func.name)) 274 self.print_async_struct(func) 275 self.print_async_unmarshal(func) 276 self.print_async_marshal(func) 277 out('') 278 out('') 279 280 def print_unmarshal_dispatch_cmd(self, api): 281 out('size_t') 282 out('_mesa_unmarshal_dispatch_cmd(struct gl_context *ctx, ' 283 'const void *cmd)') 284 out('{') 285 with indent(): 286 out('const struct marshal_cmd_base *cmd_base = cmd;') 287 out('switch (cmd_base->cmd_id) {') 288 for func in api.functionIterateAll(): 289 flavor = func.marshal_flavor() 290 if flavor in ('skip', 'sync'): 291 continue 292 out('case DISPATCH_CMD_{0}:'.format(func.name)) 293 with indent(): 294 out('debug_print_unmarshal("{0}");'.format(func.name)) 295 out(('_mesa_unmarshal_{0}(ctx, (const struct marshal_cmd_{0} *)' 296 ' cmd);').format(func.name)) 297 out('break;') 298 out('default:') 299 with indent(): 300 out('assert(!"Unrecognized command ID");') 301 out('break;') 302 out('}') 303 out('') 304 out('return cmd_base->cmd_size;') 305 out('}') 306 out('') 307 out('') 308 309 def print_create_marshal_table(self, api): 310 out('struct _glapi_table *') 311 out('_mesa_create_marshal_table(const struct gl_context *ctx)') 312 out('{') 313 with indent(): 314 out('struct _glapi_table *table;') 315 out('') 316 out('table = _mesa_alloc_dispatch_table();') 317 out('if (table == NULL)') 318 with indent(): 319 out('return NULL;') 320 out('') 321 for func in api.functionIterateAll(): 322 if func.marshal_flavor() == 'skip': 323 continue 324 out('SET_{0}(table, _mesa_marshal_{0});'.format(func.name)) 325 out('') 326 out('return table;') 327 out('}') 328 out('') 329 out('') 330 331 def printBody(self, api): 332 async_funcs = [] 333 for func in api.functionIterateAll(): 334 flavor = func.marshal_flavor() 335 if flavor in ('skip', 'custom'): 336 continue 337 elif flavor == 'async': 338 self.print_async_body(func) 339 async_funcs.append(func) 340 elif flavor == 'sync': 341 self.print_sync_body(func) 342 self.print_unmarshal_dispatch_cmd(api) 343 self.print_create_marshal_table(api) 344 345 346def show_usage(): 347 print('Usage: %s [-f input_file_name]' % sys.argv[0]) 348 sys.exit(1) 349 350 351if __name__ == '__main__': 352 file_name = 'gl_API.xml' 353 354 try: 355 (args, trail) = getopt.getopt(sys.argv[1:], 'm:f:') 356 except Exception: 357 show_usage() 358 359 for (arg,val) in args: 360 if arg == '-f': 361 file_name = val 362 363 printer = PrintCode() 364 365 api = gl_XML.parse_GL_API(file_name, marshal_XML.marshal_item_factory()) 366 printer.Print(api) 367