Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 
27
 
28
import gl_XML
29
import license
30
import sys, getopt, string
31
 
32
 
33
class glx_item_factory(gl_XML.gl_item_factory):
34
    """Factory to create GLX protocol oriented objects derived from gl_item."""
35
 
36
    def create_item(self, name, element, context):
37
        if name == "function":
38
            return glx_function(element, context)
39
        elif name == "enum":
40
            return glx_enum(element, context)
41
        elif name == "api":
42
            return glx_api(self)
43
        else:
44
            return gl_XML.gl_item_factory.create_item(self, name, element, context)
45
 
46
 
47
class glx_enum(gl_XML.gl_enum):
48
    def __init__(self, element, context):
49
        gl_XML.gl_enum.__init__(self, element, context)
50
 
51
        self.functions = {}
52
 
53
        child = element.children
54
        while child:
55
            if child.type == "element" and child.name == "size":
56
                n = child.nsProp( "name", None )
57
                c = child.nsProp( "count", None )
58
                m = child.nsProp( "mode", None )
59
 
60
                if not c:
61
                    c = self.default_count
62
                else:
63
                    c = int(c)
64
 
65
                if m == "get":
66
                    mode = 0
67
                else:
68
                    mode = 1
69
 
70
                if not self.functions.has_key(n):
71
                    self.functions[ n ] = [c, mode]
72
 
73
            child = child.next
74
 
75
        return
76
 
77
 
78
class glx_function(gl_XML.gl_function):
79
    def __init__(self, element, context):
80
        self.glx_rop = 0
81
        self.glx_sop = 0
82
        self.glx_vendorpriv = 0
83
 
84
        self.glx_vendorpriv_names = []
85
 
86
        # If this is set to true, it means that GLdouble parameters should be
87
        # written to the GLX protocol packet in the order they appear in the
88
        # prototype.  This is different from the "classic" ordering.  In the
89
        # classic ordering GLdoubles are written to the protocol packet first,
90
        # followed by non-doubles.  NV_vertex_program was the first extension
91
        # to break with this tradition.
92
 
93
        self.glx_doubles_in_order = 0
94
 
95
        self.vectorequiv = None
96
        self.output = None
97
        self.can_be_large = 0
98
        self.reply_always_array = 0
99
        self.dimensions_in_reply = 0
100
        self.img_reset = None
101
 
102
        self.server_handcode = 0
103
        self.client_handcode = 0
104
        self.ignore = 0
105
 
106
        self.count_parameter_list = []
107
        self.counter_list = []
108
        self.parameters_by_name = {}
109
        self.offsets_calculated = 0
110
 
111
        gl_XML.gl_function.__init__(self, element, context)
112
        return
113
 
114
 
115
    def process_element(self, element):
116
        gl_XML.gl_function.process_element(self, element)
117
 
118
        # If the function already has a vector equivalent set, don't
119
        # set it again.  This can happen if an alias to a function
120
        # appears after the function that it aliases.
121
 
122
        if not self.vectorequiv:
123
            self.vectorequiv = element.nsProp("vectorequiv", None)
124
 
125
 
126
        name = element.nsProp("name", None)
127
        if name == self.name:
128
            for param in self.parameters:
129
                self.parameters_by_name[ param.name ] = param
130
 
131
                if len(param.count_parameter_list):
132
                    self.count_parameter_list.extend( param.count_parameter_list )
133
 
134
                if param.counter and param.counter not in self.counter_list:
135
                    self.counter_list.append(param.counter)
136
 
137
 
138
        child = element.children
139
        while child:
140
            if child.type == "element" and child.name == "glx":
141
                rop = child.nsProp( 'rop', None )
142
                sop = child.nsProp( 'sop', None )
143
                vop = child.nsProp( 'vendorpriv', None )
144
 
145
                if rop:
146
                    self.glx_rop = int(rop)
147
 
148
                if sop:
149
                    self.glx_sop = int(sop)
150
 
151
                if vop:
152
                    self.glx_vendorpriv = int(vop)
153
                    self.glx_vendorpriv_names.append(name)
154
 
155
                self.img_reset = child.nsProp( 'img_reset', None )
156
 
157
                # The 'handcode' attribute can be one of 'true',
158
                # 'false', 'client', or 'server'.
159
 
160
                handcode = child.nsProp( 'handcode', None )
161
                if handcode == "false":
162
                    self.server_handcode = 0
163
                    self.client_handcode = 0
164
                elif handcode == "true":
165
                    self.server_handcode = 1
166
                    self.client_handcode = 1
167
                elif handcode == "client":
168
                    self.server_handcode = 0
169
                    self.client_handcode = 1
170
                elif handcode == "server":
171
                    self.server_handcode = 1
172
                    self.client_handcode = 0
173
                else:
174
                    raise RuntimeError('Invalid handcode mode "%s" in function "%s".' % (handcode, self.name))
175
 
176
                self.ignore               = gl_XML.is_attr_true( child, 'ignore' )
177
                self.can_be_large         = gl_XML.is_attr_true( child, 'large' )
178
                self.glx_doubles_in_order = gl_XML.is_attr_true( child, 'doubles_in_order' )
179
                self.reply_always_array   = gl_XML.is_attr_true( child, 'always_array' )
180
                self.dimensions_in_reply  = gl_XML.is_attr_true( child, 'dimensions_in_reply' )
181
 
182
            child = child.next
183
 
184
 
185
        # Do some validation of the GLX protocol information.  As
186
        # new tests are discovered, they should be added here.
187
 
188
        for param in self.parameters:
189
            if param.is_output and self.glx_rop != 0:
190
                raise RuntimeError("Render / RenderLarge commands cannot have outputs (%s)." % (self.name))
191
 
192
        return
193
 
194
 
195
    def has_variable_size_request(self):
196
        """Determine if the GLX request packet is variable sized.
197
 
198
        The GLX request packet is variable sized in several common
199
        situations.
200
 
201
        1. The function has a non-output parameter that is counted
202
           by another parameter (e.g., the 'textures' parameter of
203
           glDeleteTextures).
204
 
205
        2. The function has a non-output parameter whose count is
206
           determined by another parameter that is an enum (e.g., the
207
           'params' parameter of glLightfv).
208
 
209
        3. The function has a non-output parameter that is an
210
           image.
211
 
212
        4. The function must be hand-coded on the server.
213
        """
214
 
215
        if self.glx_rop == 0:
216
            return 0
217
 
218
        if self.server_handcode or self.images:
219
            return 1
220
 
221
        for param in self.parameters:
222
            if not param.is_output:
223
                if param.counter or len(param.count_parameter_list):
224
                    return 1
225
 
226
        return 0
227
 
228
 
229
    def variable_length_parameter(self):
230
        for param in self.parameters:
231
            if not param.is_output:
232
                if param.counter or len(param.count_parameter_list):
233
                    return param
234
 
235
        return None
236
 
237
 
238
    def calculate_offsets(self):
239
        if not self.offsets_calculated:
240
            # Calculate the offset of the first function parameter
241
            # in the GLX command packet.  This byte offset is
242
            # measured from the end of the Render / RenderLarge
243
            # header.  The offset for all non-pixel commends is
244
            # zero.  The offset for pixel commands depends on the
245
            # number of dimensions of the pixel data.
246
 
247
            if len(self.images) and not self.images[0].is_output:
248
                [dim, junk, junk, junk, junk] = self.images[0].get_dimensions()
249
 
250
                # The base size is the size of the pixel pack info
251
                # header used by images with the specified number
252
                # of dimensions.
253
 
254
                if dim <=  2:
255
                    offset = 20
256
                elif dim <= 4:
257
                    offset = 36
258
                else:
259
                    raise RuntimeError('Invalid number of dimensions %u for parameter "%s" in function "%s".' % (dim, self.image.name, self.name))
260
            else:
261
                offset = 0
262
 
263
            for param in self.parameterIterateGlxSend():
264
                if param.img_null_flag:
265
                    offset += 4
266
 
267
                if param.name != self.img_reset:
268
                    param.offset = offset
269
                    if not param.is_variable_length() and not param.is_client_only:
270
                        offset += param.size()
271
 
272
                if self.pad_after( param ):
273
                    offset += 4
274
 
275
 
276
            self.offsets_calculated = 1
277
        return
278
 
279
 
280
    def offset_of(self, param_name):
281
        self.calculate_offsets()
282
        return self.parameters_by_name[ param_name ].offset
283
 
284
 
285
    def parameterIterateGlxSend(self, include_variable_parameters = 1):
286
        """Create an iterator for parameters in GLX request order."""
287
 
288
        # The parameter lists are usually quite short, so it's easier
289
        # (i.e., less code) to just generate a new list with the
290
        # required elements than it is to create a new iterator class.
291
 
292
        temp = [ [],  [], [] ]
293
        for param in self.parameters:
294
            if param.is_output: continue
295
 
296
            if param.is_variable_length():
297
                temp[2].append( param )
298
            elif not self.glx_doubles_in_order and param.is_64_bit():
299
                temp[0].append( param )
300
            else:
301
                temp[1].append( param )
302
 
303
        parameters = temp[0]
304
        parameters.extend( temp[1] )
305
        if include_variable_parameters:
306
            parameters.extend( temp[2] )
307
        return parameters.__iter__()
308
 
309
 
310
    def parameterIterateCounters(self):
311
        temp = []
312
        for name in self.counter_list:
313
            temp.append( self.parameters_by_name[ name ] )
314
 
315
        return temp.__iter__()
316
 
317
 
318
    def parameterIterateOutputs(self):
319
        temp = []
320
        for p in self.parameters:
321
            if p.is_output:
322
                temp.append( p )
323
 
324
        return temp
325
 
326
 
327
    def command_fixed_length(self):
328
        """Return the length, in bytes as an integer, of the
329
        fixed-size portion of the command."""
330
 
331
        if len(self.parameters) == 0:
332
            return 0
333
 
334
        self.calculate_offsets()
335
 
336
        size = 0
337
        for param in self.parameterIterateGlxSend(0):
338
            if param.name != self.img_reset and not param.is_client_only:
339
                if size == 0:
340
                    size = param.offset + param.size()
341
                else:
342
                    size += param.size()
343
 
344
                if self.pad_after( param ):
345
                    size += 4
346
 
347
        for param in self.images:
348
            if param.img_null_flag or param.is_output:
349
                size += 4
350
 
351
        return size
352
 
353
 
354
    def command_variable_length(self):
355
        """Return the length, as a string, of the variable-sized
356
        portion of the command."""
357
 
358
        size_string = ""
359
        for p in self.parameterIterateGlxSend():
360
            if (not p.is_output) and (p.is_variable_length() or p.is_image()):
361
                # FIXME Replace the 1 in the size_string call
362
                # FIXME w/0 to eliminate some un-needed parnes
363
                # FIXME This would already be done, but it
364
                # FIXME adds some extra diffs to the generated
365
                # FIXME code.
366
 
367
                size_string = size_string + " + __GLX_PAD(%s)" % (p.size_string(1))
368
 
369
        return size_string
370
 
371
 
372
    def command_length(self):
373
        size = self.command_fixed_length()
374
 
375
        if self.glx_rop != 0:
376
            size += 4
377
 
378
        size = ((size + 3) & ~3)
379
        return "%u%s" % (size, self.command_variable_length())
380
 
381
 
382
    def opcode_real_value(self):
383
        """Get the true numeric value of the GLX opcode
384
 
385
        Behaves similarly to opcode_value, except for
386
        X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
387
        In these cases the value for the GLX opcode field (i.e.,
388
        16 for X_GLXVendorPrivate or 17 for
389
        X_GLXVendorPrivateWithReply) is returned.  For other 'single'
390
        commands, the opcode for the command (e.g., 101 for
391
        X_GLsop_NewList) is returned."""
392
 
393
        if self.glx_vendorpriv != 0:
394
            if self.needs_reply():
395
                return 17
396
            else:
397
                return 16
398
        else:
399
            return self.opcode_value()
400
 
401
 
402
    def opcode_value(self):
403
        """Get the unique protocol opcode for the glXFunction"""
404
 
405
        if (self.glx_rop == 0) and self.vectorequiv:
406
            equiv = self.context.functions_by_name[ self.vectorequiv ]
407
            self.glx_rop = equiv.glx_rop
408
 
409
 
410
        if self.glx_rop != 0:
411
            return self.glx_rop
412
        elif self.glx_sop != 0:
413
            return self.glx_sop
414
        elif self.glx_vendorpriv != 0:
415
            return self.glx_vendorpriv
416
        else:
417
            return -1
418
 
419
 
420
    def opcode_rop_basename(self):
421
        """Return either the name to be used for GLX protocol enum.
422
 
423
        Returns either the name of the function or the name of the
424
        name of the equivalent vector (e.g., glVertex3fv for
425
        glVertex3f) function."""
426
 
427
        if self.vectorequiv == None:
428
            return self.name
429
        else:
430
            return self.vectorequiv
431
 
432
 
433
    def opcode_name(self):
434
        """Get the unique protocol enum name for the glXFunction"""
435
 
436
        if (self.glx_rop == 0) and self.vectorequiv:
437
            equiv = self.context.functions_by_name[ self.vectorequiv ]
438
            self.glx_rop = equiv.glx_rop
439
            self.glx_doubles_in_order = equiv.glx_doubles_in_order
440
 
441
 
442
        if self.glx_rop != 0:
443
            return "X_GLrop_%s" % (self.opcode_rop_basename())
444
        elif self.glx_sop != 0:
445
            return "X_GLsop_%s" % (self.name)
446
        elif self.glx_vendorpriv != 0:
447
            return "X_GLvop_%s" % (self.name)
448
        else:
449
            raise RuntimeError('Function "%s" has no opcode.' % (self.name))
450
 
451
 
452
    def opcode_vendor_name(self, name):
453
        if name in self.glx_vendorpriv_names:
454
            return "X_GLvop_%s" % (name)
455
        else:
456
            raise RuntimeError('Function "%s" has no VendorPrivate opcode.' % (name))
457
 
458
 
459
    def opcode_real_name(self):
460
        """Get the true protocol enum name for the GLX opcode
461
 
462
        Behaves similarly to opcode_name, except for
463
        X_GLXVendorPrivate and X_GLXVendorPrivateWithReply commands.
464
        In these cases the string 'X_GLXVendorPrivate' or
465
        'X_GLXVendorPrivateWithReply' is returned.  For other
466
        single or render commands 'X_GLsop' or 'X_GLrop' plus the
467
        name of the function returned."""
468
 
469
        if self.glx_vendorpriv != 0:
470
            if self.needs_reply():
471
                return "X_GLXVendorPrivateWithReply"
472
            else:
473
                return "X_GLXVendorPrivate"
474
        else:
475
            return self.opcode_name()
476
 
477
 
478
    def needs_reply(self):
479
        try:
480
            x = self._needs_reply
481
        except Exception, e:
482
            x = 0
483
            if self.return_type != 'void':
484
                x = 1
485
 
486
            for param in self.parameters:
487
                if param.is_output:
488
                    x = 1
489
                    break
490
 
491
            self._needs_reply = x
492
 
493
        return x
494
 
495
 
496
    def pad_after(self, p):
497
        """Returns the name of the field inserted after the
498
        specified field to pad out the command header."""
499
 
500
        for image in self.images:
501
            if image.img_pad_dimensions:
502
                if not image.height:
503
                    if p.name == image.width:
504
                        return "height"
505
                    elif p.name == image.img_xoff:
506
                        return "yoffset"
507
                elif not image.extent:
508
                    if p.name == image.depth:
509
                        # Should this be "size4d"?
510
                        return "extent"
511
                    elif p.name == image.img_zoff:
512
                        return "woffset"
513
 
514
        return None
515
 
516
 
517
    def has_different_protocol(self, name):
518
        """Returns true if the named version of the function uses different protocol from the other versions.
519
 
520
        Some functions, such as glDeleteTextures and
521
        glDeleteTexturesEXT are functionally identical, but have
522
        different protocol.  This function returns true if the
523
        named function is an alias name and that named version uses
524
        different protocol from the function that is aliased.
525
        """
526
 
527
        return (name in self.glx_vendorpriv_names) and self.glx_sop
528
 
529
 
530
    def static_glx_name(self, name):
531
        if self.has_different_protocol(name):
532
            for n in self.glx_vendorpriv_names:
533
                if n in self.static_entry_points:
534
                    return n
535
 
536
        return self.static_name(name)
537
 
538
 
539
    def client_supported_for_indirect(self):
540
        """Returns true if the function is supported on the client
541
        side for indirect rendering."""
542
 
543
        return not self.ignore and (self.offset != -1) and (self.glx_rop or self.glx_sop or self.glx_vendorpriv or self.vectorequiv or self.client_handcode)
544
 
545
 
546
class glx_function_iterator(object):
547
    """Class to iterate over a list of glXFunctions"""
548
 
549
    def __init__(self, context):
550
        self.iterator = context.functionIterateByOffset()
551
        return
552
 
553
 
554
    def __iter__(self):
555
        return self
556
 
557
 
558
    def next(self):
559
        f = self.iterator.next()
560
 
561
        if f.client_supported_for_indirect():
562
            return f
563
        else:
564
            return self.next()
565
 
566
 
567
class glx_api(gl_XML.gl_api):
568
    def functionIterateGlx(self):
569
        return glx_function_iterator(self)
570