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