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