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