OSDN Git Service

e018a6e96b1e5a251d5117377eebd4f0e72adc56
[android-x86/external-mesa.git] / src / gallium / state_trackers / python / retrace / interpreter.py
1 #!/usr/bin/env python
2 ##########################################################################
3
4 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5 # All Rights Reserved.
6
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sub license, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
14
15 # The above copyright notice and this permission notice (including the
16 # next paragraph) shall be included in all copies or substantial portions
17 # of the Software.
18
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 # IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 ##########################################################################
28
29
30 import sys
31 import struct
32
33 import gallium
34 import model
35 import parse as parser
36
37
38 try:
39     from struct import unpack_from
40 except ImportError:
41     def unpack_from(fmt, buf, offset=0):
42         size = struct.calcsize(fmt)
43         return struct.unpack(fmt, buf[offset:offset + size])
44
45
46 def make_image(surface, x=None, y=None, w=None, h=None):
47     if x is None:
48         x = 0
49     if y is None:
50         y = 0
51     if w is None:
52         w = surface.width - x
53     if h is None:
54         h = surface.height - y
55     data = surface.get_tile_rgba8(0, 0, surface.width, surface.height)
56
57     import Image
58     outimage = Image.fromstring('RGBA', (surface.width, surface.height), data, "raw", 'RGBA', 0, 1)
59     return outimage
60
61 def save_image(filename, surface, x=None, y=None, w=None, h=None):
62     outimage = make_image(surface, x, y, w, h)
63     outimage.save(filename, "PNG")
64
65 def show_image(surface, title, x=None, y=None, w=None, h=None):
66     outimage = make_image(surface, x, y, w, h)
67     
68     import Tkinter as tk
69     from PIL import Image, ImageTk
70     root = tk.Tk()
71     
72     root.title(title)
73     
74     image1 = ImageTk.PhotoImage(outimage)
75     w = image1.width()
76     h = image1.height()
77     x = 100
78     y = 100
79     root.geometry("%dx%d+%d+%d" % (w, h, x, y))
80     panel1 = tk.Label(root, image=image1)
81     panel1.pack(side='top', fill='both', expand='yes')
82     panel1.image = image1
83     root.mainloop()
84
85
86 class Struct:
87     """C-like struct"""
88
89     # A basic Python class can pass as a C-like structure
90     pass
91
92
93 struct_factories = {
94     "pipe_blend_color": gallium.BlendColor,
95     "pipe_blend_state": gallium.Blend,
96     #"pipe_clip_state": gallium.Clip,
97     #"pipe_constant_buffer": gallium.ConstantBuffer,
98     "pipe_depth_state": gallium.Depth,
99     "pipe_stencil_state": gallium.Stencil,
100     "pipe_alpha_state": gallium.Alpha,
101     "pipe_depth_stencil_alpha_state": gallium.DepthStencilAlpha,
102     "pipe_format_block": gallium.FormatBlock,
103     #"pipe_framebuffer_state": gallium.Framebuffer,
104     "pipe_poly_stipple": gallium.PolyStipple,
105     "pipe_rasterizer_state": gallium.Rasterizer,
106     "pipe_sampler_state": gallium.Sampler,
107     "pipe_scissor_state": gallium.Scissor,
108     #"pipe_shader_state": gallium.Shader,
109     #"pipe_vertex_buffer": gallium.VertexBuffer,
110     "pipe_vertex_element": gallium.VertexElement,
111     "pipe_viewport_state": gallium.Viewport,
112     #"pipe_texture": gallium.Texture,
113 }
114
115
116 member_array_factories = {
117     "pipe_rasterizer_state": {"sprite_coord_mode": gallium.ByteArray},                          
118     "pipe_poly_stipple": {"stipple": gallium.UnsignedArray},                          
119     "pipe_viewport_state": {"scale": gallium.FloatArray, "translate": gallium.FloatArray},                          
120     #"pipe_clip_state": {"ucp": gallium.FloatArray},
121     "pipe_depth_stencil_alpha_state": {"stencil": gallium.StencilArray},
122     "pipe_blend_color": {"color": gallium.FloatArray},
123     "pipe_sampler_state": {"border_color": gallium.FloatArray},              
124 }
125
126
127 class Translator(model.Visitor):
128     """Translate model arguments into regular Python objects"""
129
130     def __init__(self, interpreter):
131         self.interpreter = interpreter
132         self.result = None
133
134     def visit(self, node):
135         self.result = None
136         node.visit(self)
137         return self.result
138         
139     def visit_literal(self, node):
140         self.result = node.value
141     
142     def visit_named_constant(self, node):
143         # lookup the named constant in the gallium module
144         self.result = getattr(gallium, node.name)
145     
146     def visit_array(self, node):
147         array = []
148         for element in node.elements:
149             array.append(self.visit(element))
150         self.result = array
151     
152     def visit_struct(self, node):
153         struct_factory = struct_factories.get(node.name, Struct)
154         struct = struct_factory()
155         for member_name, member_node in node.members:
156             member_value = self.visit(member_node)
157             try:
158                 array_factory = member_array_factories[node.name][member_name]
159             except KeyError:
160                 pass
161             else:
162                 assert isinstance(member_value, list)
163                 array = array_factory(len(member_value))
164                 for i in range(len(member_value)):
165                     array[i] = member_value[i]
166                 member_value = array
167             #print node.name, member_name, member_value
168             assert isinstance(struct, Struct) or hasattr(struct, member_name)
169             setattr(struct, member_name, member_value)
170         self.result = struct
171     
172     def visit_pointer(self, node):
173         self.result = self.interpreter.lookup_object(node.address)
174
175
176 class Object:
177     
178     def __init__(self, interpreter, real):
179         self.interpreter = interpreter
180         self.real = real
181         
182
183 class Global(Object):
184
185     def __init__(self, interpreter, real):
186         self.interpreter = interpreter
187         self.real = real
188         
189     def pipe_winsys_create(self):
190         return Winsys(self.interpreter, gallium.Device())
191
192     def pipe_screen_create(self, winsys=None):
193         if winsys is None:
194             real = gallium.Device()
195         else:
196             real = winsys.real
197         return Screen(self.interpreter, real)
198     
199     def pipe_context_create(self, screen):
200         context = screen.real.context_create()
201         return Context(self.interpreter, context)
202
203     
204 class Winsys(Object):
205     
206     def __init__(self, interpreter, real):
207         self.interpreter = interpreter
208         self.real = real
209
210     def get_name(self):
211         pass
212     
213     def user_buffer_create(self, data, size):
214         # We don't really care to distinguish between user and regular buffers
215         buffer = self.real.buffer_create(size, 
216                                          4, 
217                                          gallium.PIPE_BUFFER_USAGE_CPU_READ |
218                                          gallium.PIPE_BUFFER_USAGE_CPU_WRITE )
219         assert size == len(data)
220         buffer.write(data)
221         return buffer
222     
223     def buffer_create(self, alignment, usage, size):
224         return self.real.buffer_create(size, alignment, usage)
225     
226     def buffer_destroy(self, buffer):
227         pass
228     
229     def buffer_write(self, buffer, data, size):
230         assert size == len(data)
231         buffer.write(data)
232         
233     def fence_finish(self, fence, flags):
234         pass
235     
236     def fence_reference(self, dst, src):
237         pass
238     
239     def flush_frontbuffer(self, surface):
240         pass
241
242     def surface_alloc(self):
243         return None
244     
245     def surface_release(self, surface):
246         pass
247
248
249 class Transfer:
250
251     def __init__(self, surface, x, y, w, h):
252         self.surface = surface
253         self.x = x
254         self.y = y
255         self.w = w
256         self.h = h
257
258
259 class Screen(Object):
260     
261     def destroy(self):
262         pass
263
264     def get_name(self):
265         pass
266     
267     def get_vendor(self):
268         pass
269     
270     def get_param(self, param):
271         pass
272     
273     def get_paramf(self, param):
274         pass
275     
276     def is_format_supported(self, format, target, tex_usage, geom_flags):
277         return self.real.is_format_supported(format, target, tex_usage, geom_flags)
278     
279     def texture_create(self, templat):
280         return self.real.texture_create(
281             format = templat.format,
282             width = templat.width[0],
283             height = templat.height[0],
284             depth = templat.depth[0],
285             last_level = templat.last_level,
286             target = templat.target,
287             tex_usage = templat.tex_usage,
288         )
289
290     def texture_destroy(self, texture):
291         self.interpreter.unregister_object(texture)
292
293     def texture_release(self, surface):
294         pass
295
296     def get_tex_surface(self, texture, face, level, zslice, usage):
297         if texture is None:
298             return None
299         return texture.get_surface(face, level, zslice)
300     
301     def tex_surface_destroy(self, surface):
302         self.interpreter.unregister_object(surface)
303
304     def tex_surface_release(self, surface):
305         pass
306
307     def surface_write(self, surface, data, stride, size):
308         if surface is None:
309             return
310         assert surface.nblocksy * stride == size 
311         surface.put_tile_raw(0, 0, surface.width, surface.height, data, stride)
312
313     def get_tex_transfer(self, texture, face, level, zslice, usage, x, y, w, h):
314         if texture is None:
315             return None
316         transfer = Transfer(texture.get_surface(face, level, zslice), x, y, w, h)
317         if transfer and usage != gallium.PIPE_TRANSFER_WRITE:
318             if self.interpreter.options.all:
319                 self.interpreter.present(transfer.surface, 'transf_read', x, y, w, h)
320         return transfer
321     
322     def tex_transfer_destroy(self, transfer):
323         self.interpreter.unregister_object(transfer)
324
325     def transfer_write(self, transfer, stride, data, size):
326         if transfer is None:
327             return
328         transfer.surface.put_tile_raw(transfer.x, transfer.y, transfer.w, transfer.h, data, stride)
329         if self.interpreter.options.all:
330             self.interpreter.present(transfer.surface, 'transf_write', transfer.x, transfer.y, transfer.w, transfer.h)
331
332     def user_buffer_create(self, data, size):
333         # We don't really care to distinguish between user and regular buffers
334         buffer = self.real.buffer_create(size, 
335                                          4, 
336                                          gallium.PIPE_BUFFER_USAGE_CPU_READ |
337                                          gallium.PIPE_BUFFER_USAGE_CPU_WRITE )
338         assert size == len(data)
339         buffer.write(data)
340         return buffer
341     
342     def buffer_create(self, alignment, usage, size):
343         return self.real.buffer_create(size, alignment, usage)
344     
345     def buffer_destroy(self, buffer):
346         pass
347     
348     def buffer_write(self, buffer, data, size, offset=0):
349         assert size == len(data)
350         buffer.write(data)
351         
352     def fence_finish(self, fence, flags):
353         pass
354     
355     def fence_reference(self, dst, src):
356         pass
357     
358     def flush_frontbuffer(self, surface):
359         pass
360
361
362 class Context(Object):
363     
364     def __init__(self, interpreter, real):
365         Object.__init__(self, interpreter, real)
366         self.cbufs = []
367         self.zsbuf = None
368         self.vbufs = []
369         self.velems = []
370         self.dirty = False
371
372     def destroy(self):
373         pass
374     
375     def create_blend_state(self, state):
376         return state
377
378     def bind_blend_state(self, state):
379         if state is not None:
380             self.real.set_blend(state)
381
382     def delete_blend_state(self, state):
383         pass
384     
385     def create_sampler_state(self, state):
386         return state
387
388     def delete_sampler_state(self, state):
389         pass
390
391     def bind_sampler_states(self, num_states, states):
392         for i in range(num_states):
393             self.real.set_sampler(i, states[i])
394         
395     def create_rasterizer_state(self, state):
396         return state
397
398     def bind_rasterizer_state(self, state):
399         if state is not None:
400             self.real.set_rasterizer(state)
401         
402     def delete_rasterizer_state(self, state):
403         pass
404     
405     def create_depth_stencil_alpha_state(self, state):
406         return state
407
408     def bind_depth_stencil_alpha_state(self, state):
409         if state is not None:
410             self.real.set_depth_stencil_alpha(state)
411             
412     def delete_depth_stencil_alpha_state(self, state):
413         pass
414
415     def create_fs_state(self, state):
416         tokens = str(state.tokens)
417         shader = gallium.Shader(tokens)
418         return shader
419
420     create_vs_state = create_fs_state
421     
422     def bind_fs_state(self, state):
423         self.real.set_fragment_shader(state)
424         
425     def bind_vs_state(self, state):
426         self.real.set_vertex_shader(state)
427
428     def delete_fs_state(self, state):
429         pass
430     
431     delete_vs_state = delete_fs_state
432     
433     def set_blend_color(self, state):
434         self.real.set_blend_color(state)
435
436     def set_clip_state(self, state):
437         _state = gallium.Clip()
438         _state.nr = state.nr
439         if state.nr:
440             # FIXME
441             ucp = gallium.FloatArray(gallium.PIPE_MAX_CLIP_PLANES*4)
442             for i in range(len(state.ucp)):
443                 for j in range(len(state.ucp[i])):
444                     ucp[i*4 + j] = state.ucp[i][j]
445             _state.ucp = ucp
446         self.real.set_clip(_state)
447
448     def dump_constant_buffer(self, buffer):
449         if not self.interpreter.verbosity(2):
450             return
451
452         data = buffer.read()
453         format = '4f'
454         index = 0
455         for offset in range(0, len(data), struct.calcsize(format)):
456             x, y, z, w = unpack_from(format, data, offset)
457             sys.stdout.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index, x, y, z, w))
458             index += 1
459
460     def set_constant_buffer(self, shader, index, buffer):
461         if buffer is not None:
462             self.real.set_constant_buffer(shader, index, buffer.buffer)
463
464             self.dump_constant_buffer(buffer.buffer)
465
466     def set_framebuffer_state(self, state):
467         _state = gallium.Framebuffer()
468         _state.width = state.width
469         _state.height = state.height
470         _state.nr_cbufs = state.nr_cbufs
471         for i in range(len(state.cbufs)):
472             _state.set_cbuf(i, state.cbufs[i])
473         _state.set_zsbuf(state.zsbuf)    
474         self.real.set_framebuffer(_state)
475         
476         self.cbufs = state.cbufs
477         self.zsbuf = state.zsbuf
478
479     def set_polygon_stipple(self, state):
480         self.real.set_polygon_stipple(state)
481
482     def set_scissor_state(self, state):
483         self.real.set_scissor(state)
484
485     def set_viewport_state(self, state):
486         self.real.set_viewport(state)
487
488     def set_sampler_textures(self, num_textures, textures):
489         for i in range(num_textures):
490             self.real.set_sampler_texture(i, textures[i])
491
492     def set_vertex_buffers(self, num_buffers, buffers):
493         self.vbufs = buffers[0:num_buffers]
494         for i in range(num_buffers):
495             vbuf = buffers[i]
496             self.real.set_vertex_buffer(
497                 i,
498                 stride = vbuf.stride,
499                 max_index = vbuf.max_index,
500                 buffer_offset = vbuf.buffer_offset,
501                 buffer = vbuf.buffer,
502             )
503
504     def set_vertex_elements(self, num_elements, elements):
505         self.velems = elements[0:num_elements]
506         for i in range(num_elements):
507             self.real.set_vertex_element(i, elements[i])
508         self.real.set_vertex_elements(num_elements)
509
510     def set_edgeflags(self, bitfield):
511         # FIXME
512         pass
513     
514     def dump_vertices(self, start, count):
515         if not self.interpreter.verbosity(2):
516             return
517
518         for index in range(start, start + count):
519             if index >= start + 16:
520                 sys.stdout.write('\t...\n')
521                 break
522             sys.stdout.write('\t{\n')
523             for velem in self.velems:
524                 vbuf = self.vbufs[velem.vertex_buffer_index]
525
526                 offset = vbuf.buffer_offset + velem.src_offset + vbuf.stride*index
527                 format = {
528                     gallium.PIPE_FORMAT_R32_FLOAT: 'f',
529                     gallium.PIPE_FORMAT_R32G32_FLOAT: '2f',
530                     gallium.PIPE_FORMAT_R32G32B32_FLOAT: '3f',
531                     gallium.PIPE_FORMAT_R32G32B32A32_FLOAT: '4f',
532                     gallium.PIPE_FORMAT_B8G8R8A8_UNORM: '4B',
533                 }[velem.src_format]
534
535                 data = vbuf.buffer.read()
536                 values = unpack_from(format, data, offset)
537                 sys.stdout.write('\t\t{' + ', '.join(map(str, values)) + '},\n')
538                 assert len(values) == velem.nr_components
539             sys.stdout.write('\t},\n')
540
541     def dump_indices(self, ibuf, isize, start, count):
542         if not self.interpreter.verbosity(2):
543             return
544
545         format = {
546             1: 'B',
547             2: 'H',
548             4: 'I',
549         }[isize]
550
551         assert struct.calcsize(format) == isize
552
553         data = ibuf.read()
554         maxindex, minindex = 0, 0xffffffff
555
556         sys.stdout.write('\t{\n')
557         for i in range(start, start + count):
558             if i >= start + 16:
559                 sys.stdout.write('\t...\n')
560                 break
561             offset = i*isize
562             index, = unpack_from(format, data, offset)
563             sys.stdout.write('\t\t%u,\n' % index)
564             minindex = min(minindex, index)
565             maxindex = max(maxindex, index)
566         sys.stdout.write('\t},\n')
567
568         return minindex, maxindex
569
570     def draw_arrays(self, mode, start, count):
571         self.dump_vertices(start, count)
572             
573         self.real.draw_arrays(mode, start, count)
574         self._set_dirty()
575     
576     def draw_elements(self, indexBuffer, indexSize, mode, start, count):
577         if self.interpreter.verbosity(2):
578             minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count)
579             self.dump_vertices(minindex, maxindex - minindex)
580
581         self.real.draw_elements(indexBuffer, indexSize, mode, start, count)
582         self._set_dirty()
583         
584     def draw_range_elements(self, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count):
585         if self.interpreter.verbosity(2):
586             minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count)
587             minindex = min(minindex, minIndex)
588             maxindex = min(maxindex, maxIndex)
589             self.dump_vertices(minindex, maxindex - minindex)
590
591         self.real.draw_range_elements(indexBuffer, indexSize, minIndex, maxIndex, mode, start, count)
592         self._set_dirty()
593         
594     def surface_copy(self, dest, destx, desty, src, srcx, srcy, width, height):
595         if dest is not None and src is not None:
596             self.real.surface_copy(dest, destx, desty, src, srcx, srcy, width, height)
597
598     def is_texture_referenced(self, texture, face, level):
599         #return self.real.is_texture_referenced(format, texture, face, level)
600         pass
601     
602     def is_buffer_referenced(self, buf):
603         #return self.real.is_buffer_referenced(format, buf)
604         pass
605     
606     def _set_dirty(self):
607         if self.interpreter.options.step:
608             self._present()
609         else:
610             self.dirty = True
611
612     def flush(self, flags):
613         self.real.flush(flags)
614         if self.dirty:
615             if flags & gallium.PIPE_FLUSH_FRAME:
616                 self._present()
617             self.dirty = False
618         return None
619
620     def clear(self, buffers, rgba, depth, stencil):
621         _rgba = gallium.FloatArray(4)
622         for i in range(4):
623             _rgba[i] = rgba[i]
624         self.real.clear(buffers, _rgba, depth, stencil)
625         
626     def _present(self):
627         self.real.flush()
628     
629         if self.cbufs and self.cbufs[0]:
630             self.interpreter.present(self.cbufs[0], "cbuf")
631         if self.zsbuf:
632             if self.interpreter.options.all:
633                 self.interpreter.present(self.zsbuf, "zsbuf")
634     
635
636 class Interpreter(parser.TraceDumper):
637     
638     ignore_calls = set((
639             ('pipe_screen', 'is_format_supported'),
640             ('pipe_screen', 'get_param'),
641             ('pipe_screen', 'get_paramf'),
642     ))
643
644     def __init__(self, stream, options):
645         parser.TraceDumper.__init__(self, stream)
646         self.options = options
647         self.objects = {}
648         self.result = None
649         self.globl = Global(self, None)
650         self.call_no = None
651
652     def register_object(self, address, object):
653         self.objects[address] = object
654         
655     def unregister_object(self, object):
656         # FIXME:
657         pass
658
659     def lookup_object(self, address):
660         return self.objects[address]
661     
662     def interpret(self, trace):
663         for call in trace.calls:
664             self.interpret_call(call)
665
666     def handle_call(self, call):
667         if self.options.stop and call.no >= self.options.stop:
668             sys.exit(0)
669
670         if (call.klass, call.method) in self.ignore_calls:
671             return
672
673         self.call_no = call.no
674
675         if self.verbosity(1):
676             parser.TraceDumper.handle_call(self, call)
677         
678         args = [(str(name), self.interpret_arg(arg)) for name, arg in call.args] 
679         
680         if call.klass:
681             name, obj = args[0]
682             args = args[1:]
683         else:
684             obj = self.globl
685             
686         method = getattr(obj, call.method)
687         ret = method(**dict(args))
688         
689         if call.ret and isinstance(call.ret, model.Pointer):
690             if ret is None:
691                 sys.stderr.write('warning: NULL returned\n')
692             self.register_object(call.ret.address, ret)
693
694         self.call_no = None
695
696     def interpret_arg(self, node):
697         translator = Translator(self)
698         return translator.visit(node)
699
700     def verbosity(self, level):
701         return self.options.verbosity >= level
702
703     def present(self, surface, description, x=None, y=None, w=None, h=None):
704         if self.call_no < self.options.start:
705             return
706
707         if self.options.images:
708             filename = '%04u_%s.png' % (self.call_no, description)
709             save_image(filename, surface, x, y, w, h)
710         else:
711             title = '%u. %s' % (self.call_no, description)
712             show_image(surface, title, x, y, w, h)
713     
714
715 class Main(parser.Main):
716
717     def get_optparser(self):
718         optparser = parser.Main.get_optparser(self)
719         optparser.add_option("-q", "--quiet", action="store_const", const=0, dest="verbosity", help="no messages")
720         optparser.add_option("-v", "--verbose", action="count", dest="verbosity", default=1, help="increase verbosity level")
721         optparser.add_option("-i", "--images", action="store_true", dest="images", default=False, help="save images instead of showing them")
722         optparser.add_option("-a", "--all", action="store_true", dest="all", default=False, help="show depth, stencil, and transfers")
723         optparser.add_option("-s", "--step", action="store_true", dest="step", default=False, help="step trhough every draw")
724         optparser.add_option("-f", "--from", action="store", type="int", dest="start", default=0, help="from call no")
725         optparser.add_option("-t", "--to", action="store", type="int", dest="stop", default=0, help="until call no")
726         return optparser
727
728     def process_arg(self, stream, options):
729         parser = Interpreter(stream, options)
730         parser.parse()
731
732
733 if __name__ == '__main__':
734     Main().main()