glapi: Harden GLX request size processing (v2)
[mesa.git] / src / mapi / glapi / gen / glX_proto_send.py
1 #!/usr/bin/env python
2
3 # (C) Copyright IBM Corporation 2004, 2005
4 # All Rights Reserved.
5 # Copyright (c) 2015 Intel Corporation
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the "Software"),
9 # to deal in the Software without restriction, including without limitation
10 # on the rights to use, copy, modify, merge, publish, distribute, sub
11 # license, and/or sell copies of the Software, and to permit persons to whom
12 # the Software is furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice (including the next
15 # paragraph) shall be included in all copies or substantial portions of the
16 # Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 # IN THE SOFTWARE.
25 #
26 # Authors:
27 # Ian Romanick <idr@us.ibm.com>
28 # Jeremy Kolb <jkolb@brandeis.edu>
29
30 import argparse
31
32 import gl_XML, glX_XML, glX_proto_common, license
33 import copy, string
34
35 def convertStringForXCB(str):
36 tmp = ""
37 special = [ "ARB" ]
38 i = 0
39 while i < len(str):
40 if str[i:i+3] in special:
41 tmp = '%s_%s' % (tmp, string.lower(str[i:i+3]))
42 i = i + 2;
43 elif str[i].isupper():
44 tmp = '%s_%s' % (tmp, string.lower(str[i]))
45 else:
46 tmp = '%s%s' % (tmp, str[i])
47 i += 1
48 return tmp
49
50 def hash_pixel_function(func):
51 """Generate a 'unique' key for a pixel function. The key is based on
52 the parameters written in the command packet. This includes any
53 padding that might be added for the original function and the 'NULL
54 image' flag."""
55
56
57 h = ""
58 hash_pre = ""
59 hash_suf = ""
60 for param in func.parameterIterateGlxSend():
61 if param.is_image():
62 [dim, junk, junk, junk, junk] = param.get_dimensions()
63
64 d = (dim + 1) & ~1
65 hash_pre = "%uD%uD_" % (d - 1, d)
66
67 if param.img_null_flag:
68 hash_suf = "_NF"
69
70 h += "%u" % (param.size())
71
72 if func.pad_after(param):
73 h += "4"
74
75
76 n = func.name.replace("%uD" % (dim), "")
77 n = "__glx_%s_%uD%uD" % (n, d - 1, d)
78
79 h = hash_pre + h + hash_suf
80 return [h, n]
81
82
83 class glx_pixel_function_stub(glX_XML.glx_function):
84 """Dummy class used to generate pixel "utility" functions that are
85 shared by multiple dimension image functions. For example, these
86 objects are used to generate shared functions used to send GLX
87 protocol for TexImage1D and TexImage2D, TexSubImage1D and
88 TexSubImage2D, etc."""
89
90 def __init__(self, func, name):
91 # The parameters to the utility function are the same as the
92 # parameters to the real function except for the added "pad"
93 # parameters.
94
95 self.name = name
96 self.images = []
97 self.parameters = []
98 self.parameters_by_name = {}
99 for _p in func.parameterIterator():
100 p = copy.copy(_p)
101 self.parameters.append(p)
102 self.parameters_by_name[ p.name ] = p
103
104
105 if p.is_image():
106 self.images.append(p)
107 p.height = "height"
108
109 if p.img_yoff == None:
110 p.img_yoff = "yoffset"
111
112 if p.depth:
113 if p.extent == None:
114 p.extent = "extent"
115
116 if p.img_woff == None:
117 p.img_woff = "woffset"
118
119
120 pad_name = func.pad_after(p)
121 if pad_name:
122 pad = copy.copy(p)
123 pad.name = pad_name
124 self.parameters.append(pad)
125 self.parameters_by_name[ pad.name ] = pad
126
127
128 self.return_type = func.return_type
129
130 self.glx_rop = ~0
131 self.glx_sop = 0
132 self.glx_vendorpriv = 0
133
134 self.glx_doubles_in_order = func.glx_doubles_in_order
135
136 self.vectorequiv = None
137 self.output = None
138 self.can_be_large = func.can_be_large
139 self.reply_always_array = func.reply_always_array
140 self.dimensions_in_reply = func.dimensions_in_reply
141 self.img_reset = None
142
143 self.server_handcode = 0
144 self.client_handcode = 0
145 self.ignore = 0
146
147 self.count_parameter_list = func.count_parameter_list
148 self.counter_list = func.counter_list
149 self.offsets_calculated = 0
150 return
151
152
153 class PrintGlxProtoStubs(glX_proto_common.glx_print_proto):
154 def __init__(self):
155 glX_proto_common.glx_print_proto.__init__(self)
156 self.name = "glX_proto_send.py (from Mesa)"
157 self.license = license.bsd_license_template % ( "(C) Copyright IBM Corporation 2004, 2005", "IBM")
158
159
160 self.last_category = ""
161 self.generic_sizes = [3, 4, 6, 8, 12, 16, 24, 32]
162 self.pixel_stubs = {}
163 self.debug = 0
164 return
165
166 def printRealHeader(self):
167 print ''
168 print '#include <GL/gl.h>'
169 print '#include "indirect.h"'
170 print '#include "glxclient.h"'
171 print '#include "indirect_size.h"'
172 print '#include "glapi.h"'
173 print '#include <GL/glxproto.h>'
174 print '#include <X11/Xlib-xcb.h>'
175 print '#include <xcb/xcb.h>'
176 print '#include <xcb/glx.h>'
177 print '#include <limits.h>'
178
179 print ''
180 self.printFastcall()
181 self.printNoinline()
182 print ''
183
184 print 'static _X_INLINE int safe_add(int a, int b)'
185 print '{'
186 print ' if (a < 0 || b < 0) return -1;'
187 print ' if (INT_MAX - a < b) return -1;'
188 print ' return a + b;'
189 print '}'
190 print 'static _X_INLINE int safe_mul(int a, int b)'
191 print '{'
192 print ' if (a < 0 || b < 0) return -1;'
193 print ' if (a == 0 || b == 0) return 0;'
194 print ' if (a > INT_MAX / b) return -1;'
195 print ' return a * b;'
196 print '}'
197 print 'static _X_INLINE int safe_pad(int a)'
198 print '{'
199 print ' int ret;'
200 print ' if (a < 0) return -1;'
201 print ' if ((ret = safe_add(a, 3)) < 0) return -1;'
202 print ' return ret & (GLuint)~3;'
203 print '}'
204 print ''
205
206 print '#ifndef __GNUC__'
207 print '# define __builtin_expect(x, y) x'
208 print '#endif'
209 print ''
210 print '/* If the size and opcode values are known at compile-time, this will, on'
211 print ' * x86 at least, emit them with a single instruction.'
212 print ' */'
213 print '#define emit_header(dest, op, size) \\'
214 print ' do { union { short s[2]; int i; } temp; \\'
215 print ' temp.s[0] = (size); temp.s[1] = (op); \\'
216 print ' *((int *)(dest)) = temp.i; } while(0)'
217 print ''
218 print """NOINLINE CARD32
219 __glXReadReply( Display *dpy, size_t size, void * dest, GLboolean reply_is_always_array )
220 {
221 xGLXSingleReply reply;
222
223 (void) _XReply(dpy, (xReply *) & reply, 0, False);
224 if (size != 0) {
225 if ((reply.length > 0) || reply_is_always_array) {
226 const GLint bytes = (reply_is_always_array)
227 ? (4 * reply.length) : (reply.size * size);
228 const GLint extra = 4 - (bytes & 3);
229
230 _XRead(dpy, dest, bytes);
231 if ( extra < 4 ) {
232 _XEatData(dpy, extra);
233 }
234 }
235 else {
236 (void) memcpy( dest, &(reply.pad3), size);
237 }
238 }
239
240 return reply.retval;
241 }
242
243 NOINLINE void
244 __glXReadPixelReply( Display *dpy, struct glx_context * gc, unsigned max_dim,
245 GLint width, GLint height, GLint depth, GLenum format, GLenum type,
246 void * dest, GLboolean dimensions_in_reply )
247 {
248 xGLXSingleReply reply;
249 GLint size;
250
251 (void) _XReply(dpy, (xReply *) & reply, 0, False);
252
253 if ( dimensions_in_reply ) {
254 width = reply.pad3;
255 height = reply.pad4;
256 depth = reply.pad5;
257
258 if ((height == 0) || (max_dim < 2)) { height = 1; }
259 if ((depth == 0) || (max_dim < 3)) { depth = 1; }
260 }
261
262 size = reply.length * 4;
263 if (size != 0) {
264 void * buf = malloc( size );
265
266 if ( buf == NULL ) {
267 _XEatData(dpy, size);
268 __glXSetError(gc, GL_OUT_OF_MEMORY);
269 }
270 else {
271 const GLint extra = 4 - (size & 3);
272
273 _XRead(dpy, buf, size);
274 if ( extra < 4 ) {
275 _XEatData(dpy, extra);
276 }
277
278 __glEmptyImage(gc, 3, width, height, depth, format, type,
279 buf, dest);
280 free(buf);
281 }
282 }
283 }
284
285 #define X_GLXSingle 0
286
287 NOINLINE FASTCALL GLubyte *
288 __glXSetupSingleRequest( struct glx_context * gc, GLint sop, GLint cmdlen )
289 {
290 xGLXSingleReq * req;
291 Display * const dpy = gc->currentDpy;
292
293 (void) __glXFlushRenderBuffer(gc, gc->pc);
294 LockDisplay(dpy);
295 GetReqExtra(GLXSingle, cmdlen, req);
296 req->reqType = gc->majorOpcode;
297 req->contextTag = gc->currentContextTag;
298 req->glxCode = sop;
299 return (GLubyte *)(req) + sz_xGLXSingleReq;
300 }
301
302 NOINLINE FASTCALL GLubyte *
303 __glXSetupVendorRequest( struct glx_context * gc, GLint code, GLint vop, GLint cmdlen )
304 {
305 xGLXVendorPrivateReq * req;
306 Display * const dpy = gc->currentDpy;
307
308 (void) __glXFlushRenderBuffer(gc, gc->pc);
309 LockDisplay(dpy);
310 GetReqExtra(GLXVendorPrivate, cmdlen, req);
311 req->reqType = gc->majorOpcode;
312 req->glxCode = code;
313 req->vendorCode = vop;
314 req->contextTag = gc->currentContextTag;
315 return (GLubyte *)(req) + sz_xGLXVendorPrivateReq;
316 }
317
318 const GLuint __glXDefaultPixelStore[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 1 };
319
320 #define zero (__glXDefaultPixelStore+0)
321 #define one (__glXDefaultPixelStore+8)
322 #define default_pixel_store_1D (__glXDefaultPixelStore+4)
323 #define default_pixel_store_1D_size 20
324 #define default_pixel_store_2D (__glXDefaultPixelStore+4)
325 #define default_pixel_store_2D_size 20
326 #define default_pixel_store_3D (__glXDefaultPixelStore+0)
327 #define default_pixel_store_3D_size 36
328 #define default_pixel_store_4D (__glXDefaultPixelStore+0)
329 #define default_pixel_store_4D_size 36
330 """
331
332 for size in self.generic_sizes:
333 self.print_generic_function(size)
334 return
335
336
337 def printBody(self, api):
338
339 self.pixel_stubs = {}
340 generated_stubs = []
341
342 for func in api.functionIterateGlx():
343 if func.client_handcode: continue
344
345 # If the function is a pixel function with a certain
346 # GLX protocol signature, create a fake stub function
347 # for it. For example, create a single stub function
348 # that is used to implement both glTexImage1D and
349 # glTexImage2D.
350
351 if func.glx_rop != 0:
352 do_it = 0
353 for image in func.get_images():
354 if image.img_pad_dimensions:
355 do_it = 1
356 break
357
358
359 if do_it:
360 [h, n] = hash_pixel_function(func)
361
362
363 self.pixel_stubs[ func.name ] = n
364 if h not in generated_stubs:
365 generated_stubs.append(h)
366
367 fake_func = glx_pixel_function_stub( func, n )
368 self.printFunction(fake_func, fake_func.name)
369
370
371 self.printFunction(func, func.name)
372 if func.glx_sop and func.glx_vendorpriv:
373 self.printFunction(func, func.glx_vendorpriv_names[0])
374
375 self.printGetProcAddress(api)
376 return
377
378 def printGetProcAddress(self, api):
379 procs = {}
380 for func in api.functionIterateGlx():
381 for n in func.entry_points:
382 if func.has_different_protocol(n):
383 procs[n] = func.static_glx_name(n)
384
385 print """
386 #ifdef GLX_SHARED_GLAPI
387
388 static const struct proc_pair
389 {
390 const char *name;
391 _glapi_proc proc;
392 } proc_pairs[%d] = {""" % len(procs)
393 names = procs.keys()
394 names.sort()
395 for i in xrange(len(names)):
396 comma = ',' if i < len(names) - 1 else ''
397 print ' { "%s", (_glapi_proc) gl%s }%s' % (names[i], procs[names[i]], comma)
398 print """};
399
400 static int
401 __indirect_get_proc_compare(const void *key, const void *memb)
402 {
403 const struct proc_pair *pair = (const struct proc_pair *) memb;
404 return strcmp((const char *) key, pair->name);
405 }
406
407 _glapi_proc
408 __indirect_get_proc_address(const char *name)
409 {
410 const struct proc_pair *pair;
411
412 /* skip "gl" */
413 name += 2;
414
415 pair = (const struct proc_pair *) bsearch((const void *) name,
416 (const void *) proc_pairs, ARRAY_SIZE(proc_pairs), sizeof(proc_pairs[0]),
417 __indirect_get_proc_compare);
418
419 return (pair) ? pair->proc : NULL;
420 }
421
422 #endif /* GLX_SHARED_GLAPI */
423 """
424 return
425
426
427 def printFunction(self, func, name):
428 footer = '}\n'
429 if func.glx_rop == ~0:
430 print 'static %s' % (func.return_type)
431 print '%s( unsigned opcode, unsigned dim, %s )' % (func.name, func.get_parameter_string())
432 print '{'
433 else:
434 if func.has_different_protocol(name):
435 if func.return_type == "void":
436 ret_string = ''
437 else:
438 ret_string = "return "
439
440 func_name = func.static_glx_name(name)
441 print '#define %s %d' % (func.opcode_vendor_name(name), func.glx_vendorpriv)
442 print '%s gl%s(%s)' % (func.return_type, func_name, func.get_parameter_string())
443 print '{'
444 print ' struct glx_context * const gc = __glXGetCurrentContext();'
445 print ''
446 print '#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)'
447 print ' if (gc->isDirect) {'
448 print ' const _glapi_proc *const disp_table = (_glapi_proc *)GET_DISPATCH();'
449 print ' PFNGL%sPROC p =' % (name.upper())
450 print ' (PFNGL%sPROC) disp_table[%d];' % (name.upper(), func.offset)
451 print ' %sp(%s);' % (ret_string, func.get_called_parameter_string())
452 print ' } else'
453 print '#endif'
454 print ' {'
455
456 footer = '}\n}\n'
457 else:
458 print '#define %s %d' % (func.opcode_name(), func.opcode_value())
459
460 print '%s __indirect_gl%s(%s)' % (func.return_type, name, func.get_parameter_string())
461 print '{'
462
463
464 if func.glx_rop != 0 or func.vectorequiv != None:
465 if len(func.images):
466 self.printPixelFunction(func)
467 else:
468 self.printRenderFunction(func)
469 elif func.glx_sop != 0 or func.glx_vendorpriv != 0:
470 self.printSingleFunction(func, name)
471 pass
472 else:
473 print "/* Missing GLX protocol for %s. */" % (name)
474
475 print footer
476 return
477
478
479 def print_generic_function(self, n):
480 size = (n + 3) & ~3
481 print """static FASTCALL NOINLINE void
482 generic_%u_byte( GLint rop, const void * ptr )
483 {
484 struct glx_context * const gc = __glXGetCurrentContext();
485 const GLuint cmdlen = %u;
486
487 emit_header(gc->pc, rop, cmdlen);
488 (void) memcpy((void *)(gc->pc + 4), ptr, %u);
489 gc->pc += cmdlen;
490 if (__builtin_expect(gc->pc > gc->limit, 0)) { (void) __glXFlushRenderBuffer(gc, gc->pc); }
491 }
492 """ % (n, size + 4, size)
493 return
494
495
496 def common_emit_one_arg(self, p, pc, adjust, extra_offset):
497 if p.is_array():
498 src_ptr = p.name
499 else:
500 src_ptr = "&" + p.name
501
502 if p.is_padding:
503 print '(void) memset((void *)(%s + %u), 0, %s);' \
504 % (pc, p.offset + adjust, p.size_string() )
505 elif not extra_offset:
506 print '(void) memcpy((void *)(%s + %u), (void *)(%s), %s);' \
507 % (pc, p.offset + adjust, src_ptr, p.size_string() )
508 else:
509 print '(void) memcpy((void *)(%s + %u + %s), (void *)(%s), %s);' \
510 % (pc, p.offset + adjust, extra_offset, src_ptr, p.size_string() )
511
512 def common_emit_args(self, f, pc, adjust, skip_vla):
513 extra_offset = None
514
515 for p in f.parameterIterateGlxSend( not skip_vla ):
516 if p.name != f.img_reset:
517 self.common_emit_one_arg(p, pc, adjust, extra_offset)
518
519 if p.is_variable_length():
520 temp = p.size_string()
521 if extra_offset:
522 extra_offset += " + %s" % (temp)
523 else:
524 extra_offset = temp
525
526 return
527
528
529 def pixel_emit_args(self, f, pc, large):
530 """Emit the arguments for a pixel function. This differs from
531 common_emit_args in that pixel functions may require padding
532 be inserted (i.e., for the missing width field for
533 TexImage1D), and they may also require a 'NULL image' flag
534 be inserted before the image data."""
535
536 if large:
537 adjust = 8
538 else:
539 adjust = 4
540
541 for param in f.parameterIterateGlxSend():
542 if not param.is_image():
543 self.common_emit_one_arg(param, pc, adjust, None)
544
545 if f.pad_after(param):
546 print '(void) memcpy((void *)(%s + %u), zero, 4);' % (pc, (param.offset + param.size()) + adjust)
547
548 else:
549 [dim, width, height, depth, extent] = param.get_dimensions()
550 if f.glx_rop == ~0:
551 dim_str = "dim"
552 else:
553 dim_str = str(dim)
554
555 if param.is_padding:
556 print '(void) memset((void *)(%s + %u), 0, %s);' \
557 % (pc, (param.offset - 4) + adjust, param.size_string() )
558
559 if param.img_null_flag:
560 if large:
561 print '(void) memcpy((void *)(%s + %u), zero, 4);' % (pc, (param.offset - 4) + adjust)
562 else:
563 print '(void) memcpy((void *)(%s + %u), (void *)((%s == NULL) ? one : zero), 4);' % (pc, (param.offset - 4) + adjust, param.name)
564
565
566 pixHeaderPtr = "%s + %u" % (pc, adjust)
567 pcPtr = "%s + %u" % (pc, param.offset + adjust)
568
569 if not large:
570 if param.img_send_null:
571 condition = '(compsize > 0) && (%s != NULL)' % (param.name)
572 else:
573 condition = 'compsize > 0'
574
575 print 'if (%s) {' % (condition)
576 print ' (*gc->fillImage)(gc, %s, %s, %s, %s, %s, %s, %s, %s, %s);' % (dim_str, width, height, depth, param.img_format, param.img_type, param.name, pcPtr, pixHeaderPtr)
577 print '} else {'
578 print ' (void) memcpy( %s, default_pixel_store_%uD, default_pixel_store_%uD_size );' % (pixHeaderPtr, dim, dim)
579 print '}'
580 else:
581 print '__glXSendLargeImage(gc, compsize, %s, %s, %s, %s, %s, %s, %s, %s, %s);' % (dim_str, width, height, depth, param.img_format, param.img_type, param.name, pcPtr, pixHeaderPtr)
582
583 return
584
585
586 def large_emit_begin(self, f, op_name = None):
587 if not op_name:
588 op_name = f.opcode_real_name()
589
590 print 'const GLint op = %s;' % (op_name)
591 print 'const GLuint cmdlenLarge = cmdlen + 4;'
592 print 'GLubyte * const pc = __glXFlushRenderBuffer(gc, gc->pc);'
593 print '(void) memcpy((void *)(pc + 0), (void *)(&cmdlenLarge), 4);'
594 print '(void) memcpy((void *)(pc + 4), (void *)(&op), 4);'
595 return
596
597
598 def common_func_print_just_start(self, f, name):
599 print ' struct glx_context * const gc = __glXGetCurrentContext();'
600
601 # The only reason that single and vendor private commands need
602 # a variable called 'dpy' is because they use the SyncHandle
603 # macro. For whatever brain-dead reason, that macro is hard-
604 # coded to use a variable called 'dpy' instead of taking a
605 # parameter.
606
607 # FIXME Simplify the logic related to skip_condition and
608 # FIXME condition_list in this function. Basically, remove
609 # FIXME skip_condition, and just append the "dpy != NULL" type
610 # FIXME condition to condition_list from the start. The only
611 # FIXME reason it's done in this confusing way now is to
612 # FIXME minimize the diffs in the generated code.
613
614 if not f.glx_rop:
615 for p in f.parameterIterateOutputs():
616 if p.is_image() and (p.img_format != "GL_COLOR_INDEX" or p.img_type != "GL_BITMAP"):
617 print ' const __GLXattribute * const state = gc->client_state_private;'
618 break
619
620 print ' Display * const dpy = gc->currentDpy;'
621 skip_condition = "dpy != NULL"
622 elif f.can_be_large:
623 skip_condition = "gc->currentDpy != NULL"
624 else:
625 skip_condition = None
626
627
628 if f.return_type != 'void':
629 print ' %s retval = (%s) 0;' % (f.return_type, f.return_type)
630
631
632 if name != None and name not in f.glx_vendorpriv_names:
633 print '#ifndef USE_XCB'
634 self.emit_packet_size_calculation(f, 0)
635 if name != None and name not in f.glx_vendorpriv_names:
636 print '#endif'
637
638 condition_list = []
639 for p in f.parameterIterateCounters():
640 condition_list.append( "%s >= 0" % (p.name) )
641 # 'counter' parameters cannot be negative
642 print " if (%s < 0) {" % p.name
643 print " __glXSetError(gc, GL_INVALID_VALUE);"
644 if f.return_type != 'void':
645 print " return 0;"
646 else:
647 print " return;"
648 print " }"
649
650 if skip_condition:
651 condition_list.append( skip_condition )
652
653 if len( condition_list ) > 0:
654 if len( condition_list ) > 1:
655 skip_condition = "(%s)" % (string.join( condition_list, ") && (" ))
656 else:
657 skip_condition = "%s" % (condition_list.pop(0))
658
659 print ' if (__builtin_expect(%s, 1)) {' % (skip_condition)
660 return 1
661 else:
662 return 0
663
664
665 def printSingleFunction(self, f, name):
666 self.common_func_print_just_start(f, name)
667
668 if self.debug:
669 print ' printf( "Enter %%s...\\n", "gl%s" );' % (f.name)
670
671 if name not in f.glx_vendorpriv_names:
672
673 # XCB specific:
674 print '#ifdef USE_XCB'
675 if self.debug:
676 print ' printf("\\tUsing XCB.\\n");'
677 print ' xcb_connection_t *c = XGetXCBConnection(dpy);'
678 print ' (void) __glXFlushRenderBuffer(gc, gc->pc);'
679 xcb_name = 'xcb_glx%s' % convertStringForXCB(name)
680
681 iparams=[]
682 extra_iparams = []
683 output = None
684 for p in f.parameterIterator():
685 if p.is_output:
686 output = p
687
688 if p.is_image():
689 if p.img_format != "GL_COLOR_INDEX" or p.img_type != "GL_BITMAP":
690 extra_iparams.append("state->storePack.swapEndian")
691 else:
692 extra_iparams.append("0")
693
694 # Hardcode this in. lsb_first param (apparently always GL_FALSE)
695 # also present in GetPolygonStipple, but taken care of above.
696 if xcb_name == "xcb_glx_read_pixels":
697 extra_iparams.append("0")
698 else:
699 iparams.append(p.name)
700
701
702 xcb_request = '%s(%s)' % (xcb_name, ", ".join(["c", "gc->currentContextTag"] + iparams + extra_iparams))
703
704 if f.needs_reply():
705 print ' %s_reply_t *reply = %s_reply(c, %s, NULL);' % (xcb_name, xcb_name, xcb_request)
706 if output:
707 if output.is_image():
708 [dim, w, h, d, junk] = output.get_dimensions()
709 if f.dimensions_in_reply:
710 w = "reply->width"
711 h = "reply->height"
712 d = "reply->depth"
713 if dim < 2:
714 h = "1"
715 else:
716 print ' if (%s == 0) { %s = 1; }' % (h, h)
717 if dim < 3:
718 d = "1"
719 else:
720 print ' if (%s == 0) { %s = 1; }' % (d, d)
721
722 print ' __glEmptyImage(gc, 3, %s, %s, %s, %s, %s, %s_data(reply), %s);' % (w, h, d, output.img_format, output.img_type, xcb_name, output.name)
723 else:
724 if f.reply_always_array:
725 print ' (void)memcpy(%s, %s_data(reply), %s_data_length(reply) * sizeof(%s));' % (output.name, xcb_name, xcb_name, output.get_base_type_string())
726 else:
727 print ' /* the XXX_data_length() xcb function name is misleading, it returns the number */'
728 print ' /* of elements, not the length of the data part. A single element is embedded. */'
729 print ' if (%s_data_length(reply) == 1)' % (xcb_name)
730 print ' (void)memcpy(%s, &reply->datum, sizeof(reply->datum));' % (output.name)
731 print ' else'
732 print ' (void)memcpy(%s, %s_data(reply), %s_data_length(reply) * sizeof(%s));' % (output.name, xcb_name, xcb_name, output.get_base_type_string())
733
734 if f.return_type != 'void':
735 print ' retval = reply->ret_val;'
736 print ' free(reply);'
737 else:
738 print ' ' + xcb_request + ';'
739 print '#else'
740 # End of XCB specific.
741
742
743 if f.parameters != []:
744 pc_decl = "GLubyte const * pc ="
745 else:
746 pc_decl = "(void)"
747
748 if name in f.glx_vendorpriv_names:
749 print ' %s __glXSetupVendorRequest(gc, %s, %s, cmdlen);' % (pc_decl, f.opcode_real_name(), f.opcode_vendor_name(name))
750 else:
751 print ' %s __glXSetupSingleRequest(gc, %s, cmdlen);' % (pc_decl, f.opcode_name())
752
753 self.common_emit_args(f, "pc", 0, 0)
754
755 images = f.get_images()
756
757 for img in images:
758 if img.is_output:
759 o = f.command_fixed_length() - 4
760 print ' *(int32_t *)(pc + %u) = 0;' % (o)
761 if img.img_format != "GL_COLOR_INDEX" or img.img_type != "GL_BITMAP":
762 print ' * (int8_t *)(pc + %u) = state->storePack.swapEndian;' % (o)
763
764 if f.img_reset:
765 print ' * (int8_t *)(pc + %u) = %s;' % (o + 1, f.img_reset)
766
767
768 return_name = ''
769 if f.needs_reply():
770 if f.return_type != 'void':
771 return_name = " retval"
772 return_str = " retval = (%s)" % (f.return_type)
773 else:
774 return_str = " (void)"
775
776 got_reply = 0
777
778 for p in f.parameterIterateOutputs():
779 if p.is_image():
780 [dim, w, h, d, junk] = p.get_dimensions()
781 if f.dimensions_in_reply:
782 print " __glXReadPixelReply(dpy, gc, %u, 0, 0, 0, %s, %s, %s, GL_TRUE);" % (dim, p.img_format, p.img_type, p.name)
783 else:
784 print " __glXReadPixelReply(dpy, gc, %u, %s, %s, %s, %s, %s, %s, GL_FALSE);" % (dim, w, h, d, p.img_format, p.img_type, p.name)
785
786 got_reply = 1
787 else:
788 if f.reply_always_array:
789 aa = "GL_TRUE"
790 else:
791 aa = "GL_FALSE"
792
793 # gl_parameter.size() returns the size
794 # of the entire data item. If the
795 # item is a fixed-size array, this is
796 # the size of the whole array. This
797 # is not what __glXReadReply wants. It
798 # wants the size of a single data
799 # element in the reply packet.
800 # Dividing by the array size (1 for
801 # non-arrays) gives us this.
802
803 s = p.size() / p.get_element_count()
804 print " %s __glXReadReply(dpy, %s, %s, %s);" % (return_str, s, p.name, aa)
805 got_reply = 1
806
807
808 # If a reply wasn't read to fill an output parameter,
809 # read a NULL reply to get the return value.
810
811 if not got_reply:
812 print " %s __glXReadReply(dpy, 0, NULL, GL_FALSE);" % (return_str)
813
814
815 elif self.debug:
816 # Only emit the extra glFinish call for functions
817 # that don't already require a reply from the server.
818 print ' __indirect_glFinish();'
819
820 if self.debug:
821 print ' printf( "Exit %%s.\\n", "gl%s" );' % (name)
822
823
824 print ' UnlockDisplay(dpy); SyncHandle();'
825
826 if name not in f.glx_vendorpriv_names:
827 print '#endif /* USE_XCB */'
828
829 print ' }'
830 print ' return%s;' % (return_name)
831 return
832
833
834 def printPixelFunction(self, f):
835 if self.pixel_stubs.has_key( f.name ):
836 # Normally gl_function::get_parameter_string could be
837 # used. However, this call needs to have the missing
838 # dimensions (e.g., a fake height value for
839 # glTexImage1D) added in.
840
841 p_string = ""
842 for param in f.parameterIterateGlxSend():
843 if param.is_padding:
844 continue
845
846 p_string += ", " + param.name
847
848 if param.is_image():
849 [dim, junk, junk, junk, junk] = param.get_dimensions()
850
851 if f.pad_after(param):
852 p_string += ", 1"
853
854 print ' %s(%s, %u%s );' % (self.pixel_stubs[f.name] , f.opcode_name(), dim, p_string)
855 return
856
857
858 if self.common_func_print_just_start(f, None):
859 trailer = " }"
860 else:
861 trailer = None
862
863
864 if f.can_be_large:
865 print 'if (cmdlen <= gc->maxSmallRenderCommandSize) {'
866 print ' if ( (gc->pc + cmdlen) > gc->bufEnd ) {'
867 print ' (void) __glXFlushRenderBuffer(gc, gc->pc);'
868 print ' }'
869
870 if f.glx_rop == ~0:
871 opcode = "opcode"
872 else:
873 opcode = f.opcode_real_name()
874
875 print 'emit_header(gc->pc, %s, cmdlen);' % (opcode)
876
877 self.pixel_emit_args( f, "gc->pc", 0 )
878 print 'gc->pc += cmdlen;'
879 print 'if (gc->pc > gc->limit) { (void) __glXFlushRenderBuffer(gc, gc->pc); }'
880
881 if f.can_be_large:
882 print '}'
883 print 'else {'
884
885 self.large_emit_begin(f, opcode)
886 self.pixel_emit_args(f, "pc", 1)
887
888 print '}'
889
890 if trailer: print trailer
891 return
892
893
894 def printRenderFunction(self, f):
895 # There is a class of GL functions that take a single pointer
896 # as a parameter. This pointer points to a fixed-size chunk
897 # of data, and the protocol for this functions is very
898 # regular. Since they are so regular and there are so many
899 # of them, special case them with generic functions. On
900 # x86, this saves about 26KB in the libGL.so binary.
901
902 if f.variable_length_parameter() == None and len(f.parameters) == 1:
903 p = f.parameters[0]
904 if p.is_pointer():
905 cmdlen = f.command_fixed_length()
906 if cmdlen in self.generic_sizes:
907 print ' generic_%u_byte( %s, %s );' % (cmdlen, f.opcode_real_name(), p.name)
908 return
909
910 if self.common_func_print_just_start(f, None):
911 trailer = " }"
912 else:
913 trailer = None
914
915 if self.debug:
916 print 'printf( "Enter %%s...\\n", "gl%s" );' % (f.name)
917
918 if f.can_be_large:
919 print 'if (cmdlen <= gc->maxSmallRenderCommandSize) {'
920 print ' if ( (gc->pc + cmdlen) > gc->bufEnd ) {'
921 print ' (void) __glXFlushRenderBuffer(gc, gc->pc);'
922 print ' }'
923
924 print 'emit_header(gc->pc, %s, cmdlen);' % (f.opcode_real_name())
925
926 self.common_emit_args(f, "gc->pc", 4, 0)
927 print 'gc->pc += cmdlen;'
928 print 'if (__builtin_expect(gc->pc > gc->limit, 0)) { (void) __glXFlushRenderBuffer(gc, gc->pc); }'
929
930 if f.can_be_large:
931 print '}'
932 print 'else {'
933
934 self.large_emit_begin(f)
935 self.common_emit_args(f, "pc", 8, 1)
936
937 p = f.variable_length_parameter()
938 print ' __glXSendLargeCommand(gc, pc, %u, %s, %s);' % (p.offset + 8, p.name, p.size_string())
939 print '}'
940
941 if self.debug:
942 print '__indirect_glFinish();'
943 print 'printf( "Exit %%s.\\n", "gl%s" );' % (f.name)
944
945 if trailer: print trailer
946 return
947
948
949 class PrintGlxProtoInit_c(gl_XML.gl_print_base):
950 def __init__(self):
951 gl_XML.gl_print_base.__init__(self)
952
953 self.name = "glX_proto_send.py (from Mesa)"
954 self.license = license.bsd_license_template % ( \
955 """Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
956 (C) Copyright IBM Corporation 2004""", "PRECISION INSIGHT, IBM")
957 return
958
959
960 def printRealHeader(self):
961 print """/**
962 * \\file indirect_init.c
963 * Initialize indirect rendering dispatch table.
964 *
965 * \\author Kevin E. Martin <kevin@precisioninsight.com>
966 * \\author Brian Paul <brian@precisioninsight.com>
967 * \\author Ian Romanick <idr@us.ibm.com>
968 */
969
970 #include "indirect_init.h"
971 #include "indirect.h"
972 #include "glapi.h"
973 #include <assert.h>
974
975 #ifndef GLX_USE_APPLEGL
976
977 /**
978 * No-op function used to initialize functions that have no GLX protocol
979 * support.
980 */
981 static int NoOp(void)
982 {
983 return 0;
984 }
985
986 /**
987 * Create and initialize a new GL dispatch table. The table is initialized
988 * with GLX indirect rendering protocol functions.
989 */
990 struct _glapi_table * __glXNewIndirectAPI( void )
991 {
992 _glapi_proc *table;
993 unsigned entries;
994 unsigned i;
995 int o;
996
997 entries = _glapi_get_dispatch_table_size();
998 table = malloc(entries * sizeof(_glapi_proc));
999 if (table == NULL)
1000 return NULL;
1001
1002 /* first, set all entries to point to no-op functions */
1003 for (i = 0; i < entries; i++) {
1004 table[i] = (_glapi_proc) NoOp;
1005 }
1006
1007 /* now, initialize the entries we understand */"""
1008
1009 def printRealFooter(self):
1010 print """
1011 return (struct _glapi_table *) table;
1012 }
1013
1014 #endif
1015 """
1016 return
1017
1018
1019 def printBody(self, api):
1020 for [name, number] in api.categoryIterate():
1021 if number != None:
1022 preamble = '\n /* %3u. %s */\n' % (int(number), name)
1023 else:
1024 preamble = '\n /* %s */\n' % (name)
1025
1026 for func in api.functionIterateByCategory(name):
1027 if func.client_supported_for_indirect():
1028 if preamble:
1029 print preamble
1030 preamble = None
1031
1032 if func.is_abi():
1033 print ' table[{offset}] = (_glapi_proc) __indirect_gl{name};'.format(name = func.name, offset = func.offset)
1034 else:
1035 print ' o = _glapi_get_proc_offset("gl{0}");'.format(func.name)
1036 print ' assert(o > 0);'
1037 print ' table[o] = (_glapi_proc) __indirect_gl{0};'.format(func.name)
1038
1039 return
1040
1041
1042 class PrintGlxProtoInit_h(gl_XML.gl_print_base):
1043 def __init__(self):
1044 gl_XML.gl_print_base.__init__(self)
1045
1046 self.name = "glX_proto_send.py (from Mesa)"
1047 self.license = license.bsd_license_template % ( \
1048 """Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
1049 (C) Copyright IBM Corporation 2004""", "PRECISION INSIGHT, IBM")
1050 self.header_tag = "_INDIRECT_H_"
1051
1052 self.last_category = ""
1053 return
1054
1055
1056 def printRealHeader(self):
1057 print """/**
1058 * \\file
1059 * Prototypes for indirect rendering functions.
1060 *
1061 * \\author Kevin E. Martin <kevin@precisioninsight.com>
1062 * \\author Ian Romanick <idr@us.ibm.com>
1063 */
1064 """
1065 self.printFastcall()
1066 self.printNoinline()
1067
1068 print """
1069 #include <X11/Xfuncproto.h>
1070 #include "glxclient.h"
1071
1072 extern _X_HIDDEN NOINLINE CARD32 __glXReadReply( Display *dpy, size_t size,
1073 void * dest, GLboolean reply_is_always_array );
1074
1075 extern _X_HIDDEN NOINLINE void __glXReadPixelReply( Display *dpy,
1076 struct glx_context * gc, unsigned max_dim, GLint width, GLint height,
1077 GLint depth, GLenum format, GLenum type, void * dest,
1078 GLboolean dimensions_in_reply );
1079
1080 extern _X_HIDDEN NOINLINE FASTCALL GLubyte * __glXSetupSingleRequest(
1081 struct glx_context * gc, GLint sop, GLint cmdlen );
1082
1083 extern _X_HIDDEN NOINLINE FASTCALL GLubyte * __glXSetupVendorRequest(
1084 struct glx_context * gc, GLint code, GLint vop, GLint cmdlen );
1085 """
1086
1087
1088 def printBody(self, api):
1089 for func in api.functionIterateGlx():
1090 params = func.get_parameter_string()
1091
1092 print 'extern _X_HIDDEN %s __indirect_gl%s(%s);' % (func.return_type, func.name, params)
1093
1094 for n in func.entry_points:
1095 if func.has_different_protocol(n):
1096 asdf = func.static_glx_name(n)
1097 if asdf not in func.static_entry_points:
1098 print 'extern _X_HIDDEN %s gl%s(%s);' % (func.return_type, asdf, params)
1099 # give it a easy-to-remember name
1100 if func.client_handcode:
1101 print '#define gl_dispatch_stub_%s gl%s' % (n, asdf)
1102 else:
1103 print 'GLAPI %s GLAPIENTRY gl%s(%s);' % (func.return_type, asdf, params)
1104
1105 break
1106
1107 print ''
1108 print '#ifdef GLX_SHARED_GLAPI'
1109 print 'extern _X_HIDDEN void (*__indirect_get_proc_address(const char *name))(void);'
1110 print '#endif'
1111
1112
1113 def _parser():
1114 """Parse input and returned a parsed namespace."""
1115 parser = argparse.ArgumentParser()
1116 parser.add_argument('-f',
1117 default='gl_API.xml',
1118 dest='filename',
1119 help='An XML file describing an API')
1120 parser.add_argument('-m',
1121 required=True,
1122 dest='mode',
1123 choices=frozenset(['proto', 'init_c', 'init_h']),
1124 help='which file to generate')
1125 parser.add_argument('-d',
1126 action='store_true',
1127 dest='debug',
1128 help='turn debug mode on.')
1129 return parser.parse_args()
1130
1131
1132 def main():
1133 """Main function."""
1134 args = _parser()
1135
1136 if args.mode == "proto":
1137 printer = PrintGlxProtoStubs()
1138 elif args.mode == "init_c":
1139 printer = PrintGlxProtoInit_c()
1140 elif args.mode == "init_h":
1141 printer = PrintGlxProtoInit_h()
1142
1143 printer.debug = args.debug
1144 api = gl_XML.parse_GL_API(args.filename, glX_XML.glx_item_factory())
1145
1146 printer.Print( api )
1147
1148
1149 if __name__ == '__main__':
1150 main()