Merge commit 'origin/gallium-master-merge'
[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 parser
36
37
38 def make_image(surface):
39 pixels = gallium.FloatArray(surface.height*surface.width*4)
40 surface.get_tile_rgba(0, 0, surface.width, surface.height, pixels)
41
42 import Image
43 outimage = Image.new(
44 mode='RGB',
45 size=(surface.width, surface.height),
46 color=(0,0,0))
47 outpixels = outimage.load()
48 for y in range(0, surface.height):
49 for x in range(0, surface.width):
50 offset = (y*surface.width + x)*4
51 r, g, b, a = [int(pixels[offset + ch]*255) for ch in range(4)]
52 outpixels[x, y] = r, g, b
53 return outimage
54
55 def save_image(filename, surface):
56 outimage = make_image(surface)
57 outimage.save(filename, "PNG")
58
59 def show_image(surface):
60 outimage = make_image(surface)
61
62 import Tkinter as tk
63 from PIL import Image, ImageTk
64 root = tk.Tk()
65
66 root.title('background image')
67
68 image1 = ImageTk.PhotoImage(outimage)
69 w = image1.width()
70 h = image1.height()
71 x = 100
72 y = 100
73 root.geometry("%dx%d+%d+%d" % (w, h, x, y))
74 panel1 = tk.Label(root, image=image1)
75 panel1.pack(side='top', fill='both', expand='yes')
76 panel1.image = image1
77 root.mainloop()
78
79
80
81
82 class Struct:
83 """C-like struct"""
84
85 # A basic Python class can pass as a C-like structure
86 pass
87
88
89 struct_factories = {
90 "pipe_blend_color": gallium.BlendColor,
91 "pipe_blend_state": gallium.Blend,
92 #"pipe_clip_state": gallium.Clip,
93 #"pipe_constant_buffer": gallium.ConstantBuffer,
94 "pipe_depth_state": gallium.Depth,
95 "pipe_stencil_state": gallium.Stencil,
96 "pipe_alpha_state": gallium.Alpha,
97 "pipe_depth_stencil_alpha_state": gallium.DepthStencilAlpha,
98 "pipe_format_block": gallium.FormatBlock,
99 #"pipe_framebuffer_state": gallium.Framebuffer,
100 "pipe_poly_stipple": gallium.PolyStipple,
101 "pipe_rasterizer_state": gallium.Rasterizer,
102 "pipe_sampler_state": gallium.Sampler,
103 "pipe_scissor_state": gallium.Scissor,
104 #"pipe_shader_state": gallium.Shader,
105 #"pipe_vertex_buffer": gallium.VertexBuffer,
106 "pipe_vertex_element": gallium.VertexElement,
107 "pipe_viewport_state": gallium.Viewport,
108 #"pipe_texture": gallium.Texture,
109 }
110
111
112 member_array_factories = {
113 "pipe_rasterizer_state": {"sprite_coord_mode": gallium.ByteArray},
114 "pipe_poly_stipple": {"stipple": gallium.UnsignedArray},
115 "pipe_viewport_state": {"scale": gallium.FloatArray, "translate": gallium.FloatArray},
116 #"pipe_clip_state": {"ucp": gallium.FloatArray},
117 "pipe_depth_stencil_alpha_state": {"stencil": gallium.StencilArray},
118 "pipe_blend_color": {"color": gallium.FloatArray},
119 "pipe_sampler_state": {"border_color": gallium.FloatArray},
120 }
121
122
123 class Translator(model.Visitor):
124 """Translate model arguments into regular Python objects"""
125
126 def __init__(self, interpreter):
127 self.interpreter = interpreter
128 self.result = None
129
130 def visit(self, node):
131 self.result = None
132 node.visit(self)
133 return self.result
134
135 def visit_literal(self, node):
136 self.result = node.value
137
138 def visit_named_constant(self, node):
139 # lookup the named constant in the gallium module
140 self.result = getattr(gallium, node.name)
141
142 def visit_array(self, node):
143 array = []
144 for element in node.elements:
145 array.append(self.visit(element))
146 self.result = array
147
148 def visit_struct(self, node):
149 struct_factory = struct_factories.get(node.name, Struct)
150 struct = struct_factory()
151 for member_name, member_node in node.members:
152 member_value = self.visit(member_node)
153 try:
154 array_factory = member_array_factories[node.name][member_name]
155 except KeyError:
156 pass
157 else:
158 assert isinstance(member_value, list)
159 array = array_factory(len(member_value))
160 for i in range(len(member_value)):
161 array[i] = member_value[i]
162 member_value = array
163 #print node.name, member_name, member_value
164 assert isinstance(struct, Struct) or hasattr(struct, member_name)
165 setattr(struct, member_name, member_value)
166 self.result = struct
167
168 def visit_pointer(self, node):
169 self.result = self.interpreter.lookup_object(node.address)
170
171
172 class Object:
173
174 def __init__(self, interpreter, real):
175 self.interpreter = interpreter
176 self.real = real
177
178
179 class Global(Object):
180
181 def __init__(self, interpreter, real):
182 self.interpreter = interpreter
183 self.real = real
184
185 def pipe_winsys_create(self):
186 return Winsys(self.interpreter, gallium.Device())
187
188 def pipe_screen_create(self, winsys):
189 return Screen(self.interpreter, winsys.real)
190
191 def pipe_context_create(self, screen):
192 context = screen.real.context_create()
193 return Context(self.interpreter, context)
194
195
196 class Winsys(Object):
197
198 def __init__(self, interpreter, real):
199 self.interpreter = interpreter
200 self.real = real
201
202 def get_name(self):
203 pass
204
205 def user_buffer_create(self, data, size):
206 # We don't really care to distinguish between user and regular buffers
207 buffer = self.real.buffer_create(size,
208 4,
209 gallium.PIPE_BUFFER_USAGE_CPU_READ |
210 gallium.PIPE_BUFFER_USAGE_CPU_WRITE )
211 assert size == len(data)
212 buffer.write(data)
213 return buffer
214
215 def buffer_create(self, alignment, usage, size):
216 return self.real.buffer_create(size, alignment, usage)
217
218 def buffer_destroy(self, buffer):
219 pass
220
221 def buffer_write(self, buffer, data, size):
222 assert size == len(data)
223 buffer.write(data)
224
225 def fence_finish(self, fence, flags):
226 pass
227
228 def fence_reference(self, dst, src):
229 pass
230
231 def flush_frontbuffer(self, surface):
232 pass
233
234 def surface_alloc(self):
235 return None
236
237 def surface_release(self, surface):
238 pass
239
240
241 class Screen(Object):
242
243 def destroy(self):
244 pass
245
246 def get_name(self):
247 pass
248
249 def get_vendor(self):
250 pass
251
252 def get_param(self, param):
253 pass
254
255 def get_paramf(self, param):
256 pass
257
258 def is_format_supported(self, format, target, tex_usage, geom_flags):
259 return self.real.is_format_supported(format, target, tex_usage, geom_flags)
260
261 def texture_create(self, template):
262 return self.real.texture_create(
263 format = template.format,
264 width = template.width[0],
265 height = template.height[0],
266 depth = template.depth[0],
267 last_level = template.last_level,
268 target = template.target,
269 tex_usage = template.tex_usage,
270 )
271
272 def texture_destroy(self, texture):
273 self.interpreter.unregister_object(texture)
274
275 def texture_release(self, surface):
276 pass
277
278 def get_tex_surface(self, texture, face, level, zslice, usage):
279 return texture.get_surface(face, level, zslice, usage)
280
281 def tex_surface_destroy(self, surface):
282 self.interpreter.unregister_object(surface)
283
284 def tex_surface_release(self, surface):
285 pass
286
287 def surface_write(self, surface, data, stride, size):
288 assert surface.nblocksy * stride == size
289 surface.put_tile_raw(0, 0, surface.width, surface.height, data, stride)
290
291
292 class Context(Object):
293
294 def __init__(self, interpreter, real):
295 Object.__init__(self, interpreter, real)
296 self.cbufs = []
297 self.zsbuf = None
298 self.vbufs = []
299 self.velems = []
300
301 def destroy(self):
302 pass
303
304 def create_blend_state(self, state):
305 return state
306
307 def bind_blend_state(self, state):
308 if state is not None:
309 self.real.set_blend(state)
310
311 def delete_blend_state(self, state):
312 pass
313
314 def create_sampler_state(self, state):
315 return state
316
317 def delete_sampler_state(self, state):
318 pass
319
320 def bind_sampler_states(self, n, states):
321 for i in range(n):
322 self.real.set_sampler(i, states[i])
323
324 def create_rasterizer_state(self, state):
325 return state
326
327 def bind_rasterizer_state(self, state):
328 if state is not None:
329 self.real.set_rasterizer(state)
330
331 def delete_rasterizer_state(self, state):
332 pass
333
334 def create_depth_stencil_alpha_state(self, state):
335 return state
336
337 def bind_depth_stencil_alpha_state(self, state):
338 if state is not None:
339 self.real.set_depth_stencil_alpha(state)
340
341 def delete_depth_stencil_alpha_state(self, state):
342 pass
343
344 def create_fs_state(self, state):
345 tokens = str(state.tokens)
346 shader = gallium.Shader(tokens)
347 return shader
348
349 create_vs_state = create_fs_state
350
351 def bind_fs_state(self, state):
352 self.real.set_fragment_shader(state)
353
354 def bind_vs_state(self, state):
355 self.real.set_vertex_shader(state)
356
357 def delete_fs_state(self, state):
358 pass
359
360 delete_vs_state = delete_fs_state
361
362 def set_blend_color(self, state):
363 self.real.set_blend_color(state)
364
365 def set_clip_state(self, state):
366 _state = gallium.Clip()
367 _state.nr = state.nr
368 if state.nr:
369 # FIXME
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]
374 _state.ucp = ucp
375 self.real.set_clip(_state)
376
377 def set_constant_buffer(self, shader, index, state):
378 if state is not None:
379 self.real.set_constant_buffer(shader, index, state.buffer)
380
381 if 1:
382 data = state.buffer.read()
383 format = '4f'
384 index = 0
385 for offset in range(0, len(data), struct.calcsize(format)):
386 x, y, z, w = struct.unpack_from(format, data, offset)
387 sys.stdout.write('\tCONST[%2u] = {%10.4f, %10.4f, %10.4f, %10.4f}\n' % (index, x, y, z, w))
388 index += 1
389
390 def set_framebuffer_state(self, state):
391 _state = gallium.Framebuffer()
392 _state.width = state.width
393 _state.height = state.height
394 _state.num_cbufs = state.num_cbufs
395 for i in range(len(state.cbufs)):
396 _state.set_cbuf(i, state.cbufs[i])
397 _state.set_zsbuf(state.zsbuf)
398 self.real.set_framebuffer(_state)
399
400 self.cbufs = state.cbufs
401 self.zsbuf = state.zsbuf
402
403 def set_polygon_stipple(self, state):
404 self.real.set_polygon_stipple(state)
405
406 def set_scissor_state(self, state):
407 self.real.set_scissor(state)
408
409 def set_viewport_state(self, state):
410 self.real.set_viewport(state)
411
412 def set_sampler_textures(self, n, textures):
413 for i in range(n):
414 self.real.set_sampler_texture(i, textures[i])
415
416 def set_vertex_buffers(self, n, vbufs):
417 self.vbufs = vbufs[0:n]
418 for i in range(n):
419 vbuf = vbufs[i]
420 self.real.set_vertex_buffer(
421 i,
422 pitch = vbuf.pitch,
423 max_index = vbuf.max_index,
424 buffer_offset = vbuf.buffer_offset,
425 buffer = vbuf.buffer,
426 )
427
428 def set_vertex_elements(self, n, elements):
429 self.velems = elements[0:n]
430 for i in range(n):
431 self.real.set_vertex_element(i, elements[i])
432 self.real.set_vertex_elements(n)
433
434 def set_edgeflags(self, bitfield):
435 # FIXME
436 pass
437
438 def dump_vertices(self, start, count):
439 for index in range(start, start + count):
440 if index >= start + 16:
441 sys.stdout.write('\t...\n')
442 break
443 sys.stdout.write('\t{\n')
444 for velem in self.velems:
445 vbuf = self.vbufs[velem.vertex_buffer_index]
446
447 offset = vbuf.buffer_offset + velem.src_offset + vbuf.pitch*index
448 format = {
449 gallium.PIPE_FORMAT_R32_FLOAT: 'f',
450 gallium.PIPE_FORMAT_R32G32_FLOAT: '2f',
451 gallium.PIPE_FORMAT_R32G32B32_FLOAT: '3f',
452 gallium.PIPE_FORMAT_R32G32B32A32_FLOAT: '4f',
453 gallium.PIPE_FORMAT_B8G8R8A8_UNORM: '4B',
454 }[velem.src_format]
455
456 data = vbuf.buffer.read()
457 values = struct.unpack_from(format, data, offset)
458 sys.stdout.write('\t\t{' + ', '.join(map(str, values)) + '},\n')
459 assert len(values) == velem.nr_components
460 sys.stdout.write('\t},\n')
461
462 def dump_indices(self, ibuf, isize, start, count):
463 format = {
464 1: 'B',
465 2: 'H',
466 4: 'I',
467 }[isize]
468
469 assert struct.calcsize(format) == isize
470
471 data = ibuf.read()
472 maxindex, minindex = 0, 0xffffffff
473
474 sys.stdout.write('\t{\n')
475 for i in range(start, start + count):
476 if i >= start + 16:
477 sys.stdout.write('\t...\n')
478 break
479 offset = i*isize
480 index, = struct.unpack_from(format, data, offset)
481 sys.stdout.write('\t\t%u,\n' % index)
482 minindex = min(minindex, index)
483 maxindex = max(maxindex, index)
484 sys.stdout.write('\t},\n')
485
486 return minindex, maxindex
487
488 def draw_arrays(self, mode, start, count):
489 self.dump_vertices(start, count)
490
491 self.real.draw_arrays(mode, start, count)
492
493 def draw_elements(self, indexBuffer, indexSize, mode, start, count):
494 minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count)
495 self.dump_vertices(minindex, maxindex - minindex)
496
497 self.real.draw_elements(indexBuffer, indexSize, mode, start, count)
498
499 def draw_range_elements(self, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count):
500 minindex, maxindex = self.dump_indices(indexBuffer, indexSize, start, count)
501 minindex = min(minindex, minIndex)
502 maxindex = min(maxindex, maxIndex)
503 self.dump_vertices(minindex, maxindex - minindex)
504
505 self.real.draw_range_elements(indexBuffer, indexSize, minIndex, maxIndex, mode, start, count)
506
507 def flush(self, flags):
508 self.real.flush(flags)
509 if flags & gallium.PIPE_FLUSH_FRAME:
510 self._update()
511 return None
512
513 def clear(self, surface, value):
514 self.real.surface_clear(surface, value)
515
516 def _update(self):
517 self.real.flush()
518
519 if self.cbufs and self.cbufs[0]:
520 show_image(self.cbufs[0])
521
522
523 class Interpreter(parser.TraceDumper):
524
525 ignore_calls = set((
526 ('pipe_screen', 'is_format_supported'),
527 ('pipe_screen', 'get_param'),
528 ('pipe_screen', 'get_paramf'),
529 ))
530
531 def __init__(self, stream):
532 parser.TraceDumper.__init__(self, stream)
533 self.objects = {}
534 self.result = None
535 self.globl = Global(self, None)
536
537 def register_object(self, address, object):
538 self.objects[address] = object
539
540 def unregister_object(self, object):
541 # FIXME:
542 pass
543
544 def lookup_object(self, address):
545 return self.objects[address]
546
547 def interpret(self, trace):
548 for call in trace.calls:
549 self.interpret_call(call)
550
551 def handle_call(self, call):
552
553 if (call.klass, call.method) in self.ignore_calls:
554 return
555
556 parser.TraceDumper.handle_call(self, call)
557
558 args = [self.interpret_arg(arg) for name, arg in call.args]
559
560 if call.klass:
561 obj = args[0]
562 args = args[1:]
563 else:
564 obj = self.globl
565
566 method = getattr(obj, call.method)
567 ret = method(*args)
568
569 if call.ret and isinstance(call.ret, model.Pointer):
570 self.register_object(call.ret.address, ret)
571
572 def interpret_arg(self, node):
573 translator = Translator(self)
574 return translator.visit(node)
575
576
577 if __name__ == '__main__':
578 parser.main(Interpreter)