2 ##########################################################################
4 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
15 # The above copyright notice and this permission notice (including the
16 # next paragraph) shall be included in all copies or substantial portions
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.
27 ##########################################################################
35 import parse
as parser
39 from struct
import unpack_from
41 def unpack_from(fmt
, buf
, offset
=0):
42 size
= struct
.calcsize(fmt
)
43 return struct
.unpack(fmt
, buf
[offset
:offset
+ size
])
46 def make_image(ctx
, surface
, x
=None, y
=None, w
=None, h
=None):
54 h
= surface
.height
- y
55 data
= ctx
.surface_read_rgba8(surface
, x
, y
, surface
.width
, surface
.height
)
58 outimage
= Image
.fromstring('RGBA', (w
, h
), data
, "raw", 'RGBA', 0, 1)
61 def save_image(ctx
, filename
, surface
, x
=None, y
=None, w
=None, h
=None):
62 outimage
= make_image(ctx
, surface
, x
, y
, w
, h
)
63 outimage
.save(filename
, "PNG")
65 def show_image(ctx
, surface
, title
, x
=None, y
=None, w
=None, h
=None):
66 outimage
= make_image(ctx
, surface
, x
, y
, w
, h
)
69 from PIL
import Image
, ImageTk
74 image1
= ImageTk
.PhotoImage(outimage
)
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')
89 # A basic Python class can pass as a C-like structure
94 "pipe_blend_color": gallium
.BlendColor
,
95 "pipe_blend_state": gallium
.Blend
,
96 #"pipe_clip_state": gallium.Clip,
97 #"pipe_buffer": gallium.Buffer,
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_framebuffer_state": gallium.Framebuffer,
103 "pipe_poly_stipple": gallium
.PolyStipple
,
104 "pipe_rasterizer_state": gallium
.Rasterizer
,
105 "pipe_sampler_state": gallium
.Sampler
,
106 "pipe_scissor_state": gallium
.Scissor
,
107 #"pipe_shader_state": gallium.Shader,
108 #"pipe_vertex_buffer": gallium.VertexBuffer,
109 "pipe_vertex_element": gallium
.VertexElement
,
110 "pipe_viewport_state": gallium
.Viewport
,
111 #"pipe_texture": gallium.Texture,
112 'pipe_subresource': gallium
.pipe_subresource
,
113 'pipe_box': gallium
.pipe_box
,
114 'pipe_draw_info': gallium
.pipe_draw_info
,
118 member_array_factories
= {
119 #"pipe_rasterizer_state": {"sprite_coord_mode": gallium.ByteArray},
120 "pipe_poly_stipple": {"stipple": gallium
.UnsignedArray
},
121 "pipe_viewport_state": {"scale": gallium
.FloatArray
, "translate": gallium
.FloatArray
},
122 #"pipe_clip_state": {"ucp": gallium.FloatArray},
123 "pipe_depth_stencil_alpha_state": {"stencil": gallium
.StencilArray
},
124 "pipe_blend_color": {"color": gallium
.FloatArray
},
125 "pipe_sampler_state": {"border_color": gallium
.FloatArray
},
129 class Translator(model
.Visitor
):
130 """Translate model arguments into regular Python objects"""
132 def __init__(self
, interpreter
):
133 self
.interpreter
= interpreter
136 def visit(self
, node
):
141 def visit_literal(self
, node
):
142 self
.result
= node
.value
144 def visit_named_constant(self
, node
):
145 # lookup the named constant in the gallium module
146 self
.result
= getattr(gallium
, node
.name
)
148 def visit_array(self
, node
):
150 for element
in node
.elements
:
151 array
.append(self
.visit(element
))
154 def visit_struct(self
, node
):
155 struct_factory
= struct_factories
.get(node
.name
, Struct
)
156 struct
= struct_factory()
157 for member_name
, member_node
in node
.members
:
158 member_value
= self
.visit(member_node
)
160 array_factory
= member_array_factories
[node
.name
][member_name
]
164 assert isinstance(member_value
, list)
165 array
= array_factory(len(member_value
))
166 for i
in range(len(member_value
)):
167 array
[i
] = member_value
[i
]
169 #print node.name, member_name, member_value
170 assert isinstance(struct
, Struct
) or hasattr(struct
, member_name
)
171 setattr(struct
, member_name
, member_value
)
174 def visit_pointer(self
, node
):
175 self
.result
= self
.interpreter
.lookup_object(node
.address
)
180 def __init__(self
, interpreter
, real
):
181 self
.interpreter
= interpreter
185 class Global(Object
):
187 def __init__(self
, interpreter
, real
):
188 self
.interpreter
= interpreter
191 def pipe_screen_create(self
):
192 real
= gallium
.Device()
193 return Screen(self
.interpreter
, real
)
195 def pipe_context_create(self
, screen
):
196 context
= screen
.real
.context_create()
197 return Context(self
.interpreter
, context
)
202 def __init__(self
, resource
, usage
, subresource
, box
):
203 self
.resource
= resource
205 self
.subresource
= subresource
209 class Screen(Object
):
211 def __init__(self
, interpreter
, real
):
212 Object
.__init
__(self
, interpreter
, real
)
213 self
.context
= self
.real
.context_create()
221 def get_vendor(self
):
224 def get_param(self
, param
):
227 def get_paramf(self
, param
):
230 def context_create(self
):
231 context
= self
.real
.context_create()
232 return Context(self
.interpreter
, context
)
234 def is_format_supported(self
, format
, target
, sample_count
, bind
, geom_flags
):
235 return self
.real
.is_format_supported(format
, target
, sample_count
, bind
, geom_flags
)
237 def resource_create(self
, templat
):
238 return self
.real
.resource_create(
239 format
= templat
.format
,
240 width
= templat
.width
,
241 height
= templat
.height
,
242 depth
= templat
.depth
,
243 last_level
= templat
.last_level
,
244 target
= templat
.target
,
248 def texture_destroy(self
, texture
):
249 self
.interpreter
.unregister_object(texture
)
251 def texture_release(self
, surface
):
254 def tex_surface_release(self
, surface
):
257 def user_buffer_create(self
, data
, size
, usage
):
259 # We don't really care to distinguish between user and regular buffers
260 buffer = self
.real
.buffer_create(size
, bind
)
261 assert size
== len(data
)
262 self
.context
.buffer_write(buffer, data
)
265 def buffer_create(self
, alignment
, usage
, size
):
266 return self
.real
.buffer_create(size
, alignment
, usage
)
268 def buffer_destroy(self
, buffer):
271 def fence_finish(self
, fence
, flags
):
274 def fence_reference(self
, dst
, src
):
277 def flush_frontbuffer(self
, resource
):
281 class Context(Object
):
283 def __init__(self
, interpreter
, real
):
284 Object
.__init
__(self
, interpreter
, real
)
294 def create_blend_state(self
, state
):
295 if isinstance(state
, str):
296 state
= gallium
.Blend(state
)
297 sys
.stdout
.write('\t%s\n' % state
)
300 def bind_blend_state(self
, state
):
301 if state
is not None:
302 self
.real
.set_blend(state
)
304 def delete_blend_state(self
, state
):
307 def create_sampler_state(self
, state
):
310 def delete_sampler_state(self
, state
):
313 def bind_vertex_sampler_states(self
, num_states
, states
):
314 for i
in range(num_states
):
315 self
.real
.set_vertex_sampler(i
, states
[i
])
317 def bind_fragment_sampler_states(self
, num_states
, states
):
318 for i
in range(num_states
):
319 self
.real
.set_fragment_sampler(i
, states
[i
])
321 def create_rasterizer_state(self
, state
):
324 def bind_rasterizer_state(self
, state
):
325 if state
is not None:
326 self
.real
.set_rasterizer(state
)
328 def delete_rasterizer_state(self
, state
):
331 def create_depth_stencil_alpha_state(self
, state
):
334 def bind_depth_stencil_alpha_state(self
, state
):
335 if state
is not None:
336 self
.real
.set_depth_stencil_alpha(state
)
338 def delete_depth_stencil_alpha_state(self
, state
):
341 def create_fs_state(self
, state
):
342 tokens
= str(state
.tokens
)
343 shader
= gallium
.Shader(tokens
)
346 create_vs_state
= create_fs_state
348 def bind_fs_state(self
, state
):
349 self
.real
.set_fragment_shader(state
)
351 def bind_vs_state(self
, state
):
352 self
.real
.set_vertex_shader(state
)
354 def delete_fs_state(self
, state
):
357 delete_vs_state
= delete_fs_state
359 def set_blend_color(self
, state
):
360 self
.real
.set_blend_color(state
)
362 def set_stencil_ref(self
, state
):
363 self
.real
.set_stencil_ref(state
)
365 def set_clip_state(self
, state
):
366 _state
= gallium
.Clip()
370 ucp
= gallium
.FloatArray(gallium
.PIPE_MAX_CLIP_PLANES
*4)
371 for i
in range(len(state
.ucp
)):
372 for j
in range(len(state
.ucp
[i
])):
373 ucp
[i
*4 + j
] = state
.ucp
[i
][j
]
375 self
.real
.set_clip(_state
)
377 def dump_constant_buffer(self
, buffer):
378 if not self
.interpreter
.verbosity(2):
381 data
= self
.real
.buffer_read(buffer)
384 for offset
in range(0, len(data
), struct
.calcsize(format
)):
385 x
, y
, z
, w
= unpack_from(format
, data
, offset
)
386 sys
.stdout
.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index
, x
, y
, z
, w
))
390 def set_constant_buffer(self
, shader
, index
, buffer):
391 if buffer is not None:
392 self
.real
.set_constant_buffer(shader
, index
, buffer)
394 self
.dump_constant_buffer(buffer)
396 def set_framebuffer_state(self
, state
):
397 _state
= gallium
.Framebuffer()
398 _state
.width
= state
.width
399 _state
.height
= state
.height
400 _state
.nr_cbufs
= state
.nr_cbufs
401 for i
in range(len(state
.cbufs
)):
402 _state
.set_cbuf(i
, state
.cbufs
[i
])
403 _state
.set_zsbuf(state
.zsbuf
)
404 self
.real
.set_framebuffer(_state
)
406 self
.cbufs
= state
.cbufs
407 self
.zsbuf
= state
.zsbuf
409 def set_polygon_stipple(self
, state
):
410 self
.real
.set_polygon_stipple(state
)
412 def set_scissor_state(self
, state
):
413 self
.real
.set_scissor(state
)
415 def set_viewport_state(self
, state
):
416 self
.real
.set_viewport(state
)
418 def create_sampler_view(self
, texture
, templ
):
419 return self
.real
.create_sampler_view(texture
,
420 format
= templ
.format
,
421 first_level
= templ
.first_level
,
422 last_level
= templ
.last_level
,
423 swizzle_r
= templ
.swizzle_r
,
424 swizzle_g
= templ
.swizzle_r
,
425 swizzle_b
= templ
.swizzle_g
,
426 swizzle_a
= templ
.swizzle_a
)
428 def sampler_view_destroy(self
, view
):
431 def set_fragment_sampler_views(self
, num
, views
):
433 self
.real
.set_fragment_sampler_view(i
, views
[i
])
435 def set_vertex_sampler_views(self
, num
, views
):
437 self
.real
.set_vertex_sampler_view(i
, views
[i
])
439 def set_vertex_buffers(self
, num_buffers
, buffers
):
440 self
.vbufs
= buffers
[0:num_buffers
]
441 for i
in range(num_buffers
):
443 self
.real
.set_vertex_buffer(
445 stride
= vbuf
.stride
,
446 max_index
= vbuf
.max_index
,
447 buffer_offset
= vbuf
.buffer_offset
,
448 buffer = vbuf
.buffer,
451 def create_vertex_elements_state(self
, num_elements
, elements
):
452 return elements
[0:num_elements
]
454 def bind_vertex_elements_state(self
, state
):
456 self
.real
.set_vertex_elements(0)
460 num_elements
= len(elements
)
461 self
.velems
= elements
462 for i
in range(num_elements
):
463 self
.real
.set_vertex_element(i
, elements
[i
])
464 self
.real
.set_vertex_elements(num_elements
)
466 def delete_vertex_elements_state(self
, state
):
469 def dump_vertices(self
, start
, count
):
470 if not self
.interpreter
.verbosity(2):
473 for index
in range(start
, start
+ count
):
474 if index
>= start
+ 16:
475 sys
.stdout
.write('\t...\n')
477 sys
.stdout
.write('\t{\n')
478 for velem
in self
.velems
:
479 vbuf
= self
.vbufs
[velem
.vertex_buffer_index
]
481 offset
= vbuf
.buffer_offset
+ velem
.src_offset
+ vbuf
.stride
*index
483 gallium
.PIPE_FORMAT_R32_FLOAT
: 'f',
484 gallium
.PIPE_FORMAT_R32G32_FLOAT
: '2f',
485 gallium
.PIPE_FORMAT_R32G32B32_FLOAT
: '3f',
486 gallium
.PIPE_FORMAT_R32G32B32A32_FLOAT
: '4f',
487 gallium
.PIPE_FORMAT_A8R8G8B8_UNORM
: '4B',
488 gallium
.PIPE_FORMAT_R8G8B8A8_UNORM
: '4B',
489 gallium
.PIPE_FORMAT_B8G8R8A8_UNORM
: '4B',
490 gallium
.PIPE_FORMAT_R16G16B16_SNORM
: '3h',
493 data
= self
.real
.buffer_read(vbuf
.buffer)
494 values
= unpack_from(format
, data
, offset
)
495 sys
.stdout
.write('\t\t{' + ', '.join(map(str, values
)) + '},\n')
496 sys
.stdout
.write('\t},\n')
499 def dump_indices(self
, ibuf
, isize
, ibias
, start
, count
):
500 if not self
.interpreter
.verbosity(2):
509 assert struct
.calcsize(format
) == isize
511 data
= self
.real
.buffer_read(ibuf
)
512 maxindex
, minindex
= 0, 0xffffffff
514 sys
.stdout
.write('\t{\n')
515 for i
in range(start
, start
+ count
):
516 if i
>= start
+ 16 and not self
.interpreter
.verbosity(3):
517 sys
.stdout
.write('\t...\n')
520 index
, = unpack_from(format
, data
, offset
)
521 sys
.stdout
.write('\t\t%u,\n' % index
)
522 minindex
= min(minindex
, index
)
523 maxindex
= max(maxindex
, index
)
524 sys
.stdout
.write('\t},\n')
527 return minindex
+ ibias
, maxindex
+ ibias
529 def set_index_buffer(self
, ib
):
531 self
.real
.set_index_buffer(ib
.index_size
, ib
.offset
, ib
.buffer)
533 self
.real
.set_index_buffer(0, 0, None)
535 def draw_vbo(self
, info
):
536 if self
.interpreter
.verbosity(2):
538 minindex
, maxindex
= self
.dump_indices(indexBuffer
, indexSize
, indexBias
, start
, count
)
540 self
.dump_vertices(info
.minindex
, info
.maxindex
+ 1 - info
.minindex
)
542 self
.real
.draw_vbo(info
)
545 def resource_copy_region(self
, dst
, subdst
, dstx
, dsty
, dstz
, src
, subsrc
, srcx
, srcy
, srcz
, width
, height
):
546 if dst
is not None and src
is not None:
547 if self
.interpreter
.options
.all
:
548 self
.interpreter
.present(self
.real
, src
, 'resource_copy_src', srcx
, srcy
, width
, height
)
549 self
.real
.resource_copy_region(dst
, subdst
, dstx
, dsty
, dstx
, src
, subsrc
, srcx
, srcy
, srcz
, width
, height
)
552 if self
.interpreter
.options
.all
:
553 self
.interpreter
.present(self
.real
, dst
, 'resource_copy_dst', dstx
, dsty
, width
, height
)
555 def is_resource_referenced(self
, texture
, face
, level
):
556 #return self.real.is_resource_referenced(format, texture, face, level)
559 def buffer_write(self
, buffer, data
, size
, offset
=0):
560 assert size
== len(data
)
561 self
.buffer_write(buffer, data
)
563 def surface_write(self
, surface
, data
, stride
, size
):
566 # assert surface.nblocksy * stride == size
567 surface
.put_tile_raw(0, 0, surface
.width
, surface
.height
, data
, stride
)
569 def get_transfer(self
, texture
, sr
, usage
, box
):
572 transfer
= Transfer(texture
, sr
, usage
, box
)
573 if transfer
and usage
& gallium
.PIPE_TRANSFER_READ
:
574 if self
.interpreter
.options
.all
:
575 surface
= texture
.get_surface(sr
.face
, sr
.level
, box
.z
)
576 self
.interpreter
.present(self
.real
, transfer
.surface
, 'transf_read', box
.x
, box
.y
, box
.width
, box
.height
)
579 def tex_transfer_destroy(self
, transfer
):
580 self
.interpreter
.unregister_object(transfer
)
582 def transfer_inline_write(self
, resource
, sr
, usage
, box
, stride
, slice_stride
, data
):
583 self
.real
.transfer_inline_write(resource
, sr
, usage
, box
, data
, stride
, slice_stride
)
584 if self
.interpreter
.options
.all
:
585 for z
in range(box
.z
, box
.z
+ box
.depth
):
586 surface
= resource
.get_surface(sr
.face
, sr
.level
, box
.z
)
587 self
.interpreter
.present(self
.real
, surface
, 'transf_inline_write%u' % z
, box
.x
, box
.y
, box
.width
, box
.height
)
589 def _set_dirty(self
):
590 if self
.interpreter
.options
.step
:
595 def flush(self
, flags
):
596 self
.real
.flush(flags
)
598 if flags
& gallium
.PIPE_FLUSH_FRAME
:
603 def clear(self
, buffers
, rgba
, depth
, stencil
):
604 _rgba
= gallium
.FloatArray(4)
607 self
.real
.clear(buffers
, _rgba
, depth
, stencil
)
609 def clear_render_target(self
, dst
, rgba
, dstx
, dsty
, width
, height
):
610 _rgba
= gallium
.FloatArray(4)
613 self
.real
.clear_render_target(dst
, _rgba
, dstx
, dsty
, width
, height
)
615 def clear_depth_stencil(self
, dst
, clear_flags
, depth
, stencil
, dstx
, dsty
, width
, height
):
616 self
.real
.clear_depth_stencil(dst
, clear_flags
, depth
, stencil
, dstx
, dsty
, width
, height
)
621 if self
.cbufs
and self
.cbufs
[0]:
622 self
.interpreter
.present(self
.real
, self
.cbufs
[0], "cbuf")
624 if self
.interpreter
.options
.all
:
625 self
.interpreter
.present(self
.real
, self
.zsbuf
, "zsbuf")
626 def create_surface(self
, texture
, level
, layer
, usage
):
629 return texture
.get_surface(level
, layer
)
631 def surface_destroy(self
, surface
):
632 self
.interpreter
.unregister_object(surface
)
634 class Interpreter(parser
.TraceDumper
):
637 ('pipe_screen', 'is_format_supported'),
638 ('pipe_screen', 'get_param'),
639 ('pipe_screen', 'get_paramf'),
642 def __init__(self
, stream
, options
):
643 parser
.TraceDumper
.__init
__(self
, stream
)
644 self
.options
= options
647 self
.globl
= Global(self
, None)
650 def register_object(self
, address
, object):
651 self
.objects
[address
] = object
653 def unregister_object(self
, object):
657 def lookup_object(self
, address
):
658 return self
.objects
[address
]
660 def interpret(self
, trace
):
661 for call
in trace
.calls
:
662 self
.interpret_call(call
)
664 def handle_call(self
, call
):
665 if self
.options
.stop
and call
.no
> self
.options
.stop
:
668 if (call
.klass
, call
.method
) in self
.ignore_calls
:
671 self
.call_no
= call
.no
673 if self
.verbosity(1):
674 parser
.TraceDumper
.handle_call(self
, call
)
677 args
= [(str(name
), self
.interpret_arg(arg
)) for name
, arg
in call
.args
]
685 method
= getattr(obj
, call
.method
)
686 ret
= method(**dict(args
))
688 if call
.ret
and isinstance(call
.ret
, model
.Pointer
):
690 sys
.stderr
.write('warning: NULL returned\n')
691 self
.register_object(call
.ret
.address
, ret
)
695 def interpret_arg(self
, node
):
696 translator
= Translator(self
)
697 return translator
.visit(node
)
699 def verbosity(self
, level
):
700 return self
.options
.verbosity
>= level
702 def present(self
, ctx
, surface
, description
, x
=None, y
=None, w
=None, h
=None):
703 if self
.call_no
< self
.options
.start
:
706 if self
.options
.images
:
707 filename
= '%04u_%s.png' % (self
.call_no
, description
)
708 save_image(ctx
, filename
, surface
, x
, y
, w
, h
)
710 title
= '%u. %s' % (self
.call_no
, description
)
711 show_image(ctx
, surface
, title
, x
, y
, w
, h
)
714 class Main(parser
.Main
):
716 def get_optparser(self
):
717 optparser
= parser
.Main
.get_optparser(self
)
718 optparser
.add_option("-q", "--quiet", action
="store_const", const
=0, dest
="verbosity", help="no messages")
719 optparser
.add_option("-v", "--verbose", action
="count", dest
="verbosity", default
=1, help="increase verbosity level")
720 optparser
.add_option("-i", "--images", action
="store_true", dest
="images", default
=False, help="save images instead of showing them")
721 optparser
.add_option("-a", "--all", action
="store_true", dest
="all", default
=False, help="show depth, stencil, and transfers")
722 optparser
.add_option("-s", "--step", action
="store_true", dest
="step", default
=False, help="step trhough every draw")
723 optparser
.add_option("-f", "--from", action
="store", type="int", dest
="start", default
=0, help="from call no")
724 optparser
.add_option("-t", "--to", action
="store", type="int", dest
="stop", default
=0, help="until call no")
727 def process_arg(self
, stream
, options
):
728 parser
= Interpreter(stream
, options
)
732 if __name__
== '__main__':