diff options
Diffstat (limited to 'src/gallium/state_trackers/python')
17 files changed, 1135 insertions, 93 deletions
diff --git a/src/gallium/state_trackers/python/README b/src/gallium/state_trackers/python/README index 8ab88ab2f81..8f45fb6d1b7 100644 --- a/src/gallium/state_trackers/python/README +++ b/src/gallium/state_trackers/python/README @@ -24,9 +24,10 @@ and then try running which should show a triangle. -This is still in experimental phase, and there many limitations to what you can -do with from Python. - +This is still work in progress: +- errors are not handled properly and almost always result in crash +- state atoms with array members are awkward to set +- there no efficient way to view images -- Jose Fonseca <[email protected]> diff --git a/src/gallium/state_trackers/python/SConscript b/src/gallium/state_trackers/python/SConscript index 973d96d55a1..1581182aec2 100644 --- a/src/gallium/state_trackers/python/SConscript +++ b/src/gallium/state_trackers/python/SConscript @@ -30,5 +30,5 @@ if 'python' in env['statetrackers']: source = [ 'st_hardpipe_winsys.c', ], - LIBS = [pyst, softpipe] + auxiliaries + env['LIBS'], + LIBS = [pyst, softpipe, trace] + auxiliaries + env['LIBS'], ) diff --git a/src/gallium/state_trackers/python/gallium.i b/src/gallium/state_trackers/python/gallium.i index 8d7a49cee7d..68d2db3325a 100644 --- a/src/gallium/state_trackers/python/gallium.i +++ b/src/gallium/state_trackers/python/gallium.i @@ -42,11 +42,11 @@ #include "pipe/p_screen.h" #include "pipe/p_context.h" #include "pipe/p_inlines.h" -#include "pipe/p_util.h" +#include "util/u_memory.h" #include "pipe/p_shader_tokens.h" #include "cso_cache/cso_context.h" #include "util/u_draw_quad.h" -#include "util/p_tile.h" +#include "util/u_tile.h" #include "tgsi/tgsi_text.h" #include "tgsi/tgsi_dump.h" @@ -55,6 +55,8 @@ %} +%include "typemaps.i" + %include "carrays.i" %array_class(unsigned char, ByteArray); %array_class(int, IntArray); diff --git a/src/gallium/state_trackers/python/p_context.i b/src/gallium/state_trackers/python/p_context.i index 521a2dee075..1fdcec639f7 100644 --- a/src/gallium/state_trackers/python/p_context.i +++ b/src/gallium/state_trackers/python/p_context.i @@ -68,6 +68,11 @@ struct st_context { void set_fragment_shader( const struct pipe_shader_state *state ) { void *fs; + if(!state) { + cso_set_fragment_shader_handle($self->cso, NULL); + return; + } + fs = $self->pipe->create_fs_state($self->pipe, state); if(!fs) return; @@ -82,6 +87,11 @@ struct st_context { void set_vertex_shader( const struct pipe_shader_state *state ) { void *vs; + if(!state) { + cso_set_vertex_shader_handle($self->cso, NULL); + return; + } + vs = $self->pipe->create_vs_state($self->pipe, state); if(!vs) return; @@ -110,7 +120,7 @@ struct st_context { { struct pipe_constant_buffer state; memset(&state, 0, sizeof(state)); - state.buffer = buffer->buffer; + state.buffer = buffer ? buffer->buffer : NULL; state.size = buffer->buffer->size; $self->pipe->set_constant_buffer($self->pipe, shader, index, &state); } @@ -147,30 +157,38 @@ struct st_context { unsigned buffer_offset, struct st_buffer *buffer) { - unsigned i, num_vertex_buffers; + unsigned i; struct pipe_vertex_buffer state; memset(&state, 0, sizeof(state)); state.pitch = pitch; state.max_index = max_index; state.buffer_offset = buffer_offset; - state.buffer = buffer->buffer; + state.buffer = buffer ? buffer->buffer : NULL; memcpy(&$self->vertex_buffers[index], &state, sizeof(state)); for(i = 0; i < PIPE_MAX_ATTRIBS; ++i) if(self->vertex_buffers[i].buffer) - num_vertex_buffers = i + 1; + $self->num_vertex_buffers = i + 1; $self->pipe->set_vertex_buffers($self->pipe, - num_vertex_buffers, + $self->num_vertex_buffers, $self->vertex_buffers); } void set_vertex_element(unsigned index, - const struct pipe_vertex_element *element) { + const struct pipe_vertex_element *element) + { memcpy(&$self->vertex_elements[index], element, sizeof(*element)); - $self->pipe->set_vertex_elements($self->pipe, PIPE_MAX_ATTRIBS, $self->vertex_elements); + } + + void set_vertex_elements(unsigned num) + { + $self->num_vertex_elements = num; + $self->pipe->set_vertex_elements($self->pipe, + $self->num_vertex_elements, + $self->vertex_elements); } /* @@ -183,8 +201,22 @@ struct st_context { void draw_elements( struct st_buffer *indexBuffer, unsigned indexSize, - unsigned mode, unsigned start, unsigned count) { - $self->pipe->draw_elements($self->pipe, indexBuffer->buffer, indexSize, mode, start, count); + unsigned mode, unsigned start, unsigned count) + { + $self->pipe->draw_elements($self->pipe, + indexBuffer->buffer, + indexSize, + mode, start, count); + } + + void draw_range_elements( struct st_buffer *indexBuffer, + unsigned indexSize, unsigned minIndex, unsigned maxIndex, + unsigned mode, unsigned start, unsigned count) + { + $self->pipe->draw_range_elements($self->pipe, + indexBuffer->buffer, + indexSize, minIndex, maxIndex, + mode, start, count); } void draw_vertices(unsigned prim, @@ -193,38 +225,38 @@ struct st_context { const float *vertices) { struct pipe_context *pipe = $self->pipe; - struct pipe_winsys *winsys = pipe->winsys; + struct pipe_screen *screen = pipe->screen; struct pipe_buffer *vbuf; float *map; unsigned size; size = num_verts * num_attribs * 4 * sizeof(float); - vbuf = winsys->buffer_create(winsys, - 32, - PIPE_BUFFER_USAGE_VERTEX, - size); + vbuf = pipe_buffer_create(screen, + 32, + PIPE_BUFFER_USAGE_VERTEX, + size); if(!vbuf) goto error1; - map = winsys->buffer_map(winsys, vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); + map = pipe_buffer_map(screen, vbuf, PIPE_BUFFER_USAGE_CPU_WRITE); if (!map) goto error2; memcpy(map, vertices, size); - pipe->winsys->buffer_unmap(pipe->winsys, vbuf); + pipe_buffer_unmap(screen, vbuf); util_draw_vertex_buffer(pipe, vbuf, prim, num_verts, num_attribs); error2: - pipe_buffer_reference(pipe->winsys, &vbuf, NULL); + pipe_buffer_reference(screen, &vbuf, NULL); error1: ; } void - flush(void) { + flush(unsigned flags = 0) { struct pipe_fence_handle *fence = NULL; - $self->pipe->flush($self->pipe, PIPE_FLUSH_RENDER_CACHE, &fence); + $self->pipe->flush($self->pipe, flags | PIPE_FLUSH_RENDER_CACHE, &fence); /* TODO: allow asynchronous operation */ $self->pipe->winsys->fence_finish( $self->pipe->winsys, fence, 0 ); $self->pipe->winsys->fence_reference( $self->pipe->winsys, &fence, NULL ); diff --git a/src/gallium/state_trackers/python/p_state.i b/src/gallium/state_trackers/python/p_state.i index 9834229b4b5..7f5760b3b66 100644 --- a/src/gallium/state_trackers/python/p_state.i +++ b/src/gallium/state_trackers/python/p_state.i @@ -34,9 +34,15 @@ %module gallium; +%ignore winsys; +%ignore pipe_vertex_buffer::buffer; + %include "pipe/p_state.h"; +%array_class(struct pipe_stencil_state, StencilArray); + + %extend pipe_framebuffer_state { pipe_framebuffer_state(void) { diff --git a/src/gallium/state_trackers/python/p_texture.i b/src/gallium/state_trackers/python/p_texture.i index fd38e0733fb..33fb3743cce 100644 --- a/src/gallium/state_trackers/python/p_texture.i +++ b/src/gallium/state_trackers/python/p_texture.i @@ -102,12 +102,12 @@ void unmap( void ); void - get_tile_raw(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char *raw, unsigned stride) { + get_tile_raw(unsigned x, unsigned y, unsigned w, unsigned h, char *raw, unsigned stride) { pipe_get_tile_raw($self, x, y, w, h, raw, stride); } void - put_tile_raw(unsigned x, unsigned y, unsigned w, unsigned h, const unsigned char *raw, unsigned stride) { + put_tile_raw(unsigned x, unsigned y, unsigned w, unsigned h, const char *raw, unsigned stride) { pipe_put_tile_raw($self, x, y, w, h, raw, stride); } @@ -180,13 +180,25 @@ struct st_buffer { } void write( const char *STRING, unsigned LENGTH, unsigned offset = 0) { - struct pipe_winsys *winsys = $self->st_dev->screen->winsys; + struct pipe_screen *screen = $self->st_dev->screen; char *map; - map = winsys->buffer_map(winsys, $self->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); - if(!map) { + assert($self->buffer->refcount); + + if(offset > $self->buffer->size) { + PyErr_SetString(PyExc_ValueError, "offset must be smaller than buffer size"); + return; + } + + if(offset + LENGTH > $self->buffer->size) { + PyErr_SetString(PyExc_ValueError, "data length must fit inside the buffer"); + return; + } + + map = pipe_buffer_map(screen, $self->buffer, PIPE_BUFFER_USAGE_CPU_WRITE); + if(map) { memcpy(map + offset, STRING, LENGTH); - winsys->buffer_unmap(winsys, $self->buffer); + pipe_buffer_unmap(screen, $self->buffer); } } }; diff --git a/src/gallium/state_trackers/python/retrace/README b/src/gallium/state_trackers/python/retrace/README new file mode 100644 index 00000000000..822cd114044 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/README @@ -0,0 +1,17 @@ +This is an application written in python to replay the traces captured by the + trace pipe driver. + + +To use it follow the instructions in src/gallium/drivers/trace/README and +src/gallium/state_trackers/python/README, and then do + + python src/gallium/state_trackers/python/samples/retrace/interpreter.py filename.trace + + +This is still work in progress: +- not everything is captured/replayed + - surface/textures contents +- any tiny error will result in a crash + +-- +Jose Fonseca <[email protected]> diff --git a/src/gallium/state_trackers/python/retrace/interpreter.py b/src/gallium/state_trackers/python/retrace/interpreter.py new file mode 100755 index 00000000000..351a6e739be --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/interpreter.py @@ -0,0 +1,480 @@ +#!/usr/bin/env python +############################################################################# +# +# Copyright 2008 Tungsten Graphics, Inc. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################# + + +import sys +import gallium +import model +import parser + + +def make_image(surface): + pixels = gallium.FloatArray(surface.height*surface.width*4) + surface.get_tile_rgba(0, 0, surface.width, surface.height, pixels) + + import Image + outimage = Image.new( + mode='RGB', + size=(surface.width, surface.height), + color=(0,0,0)) + outpixels = outimage.load() + for y in range(0, surface.height): + for x in range(0, surface.width): + offset = (y*surface.width + x)*4 + r, g, b, a = [int(pixels[offset + ch]*255) for ch in range(4)] + outpixels[x, y] = r, g, b + return outimage + +def save_image(filename, surface): + outimage = make_image(surface) + outimage.save(filename, "PNG") + +def show_image(surface): + outimage = make_image(surface) + + import Tkinter as tk + from PIL import Image, ImageTk + root = tk.Tk() + + root.title('background image') + + image1 = ImageTk.PhotoImage(outimage) + w = image1.width() + h = image1.height() + x = 100 + y = 100 + root.geometry("%dx%d+%d+%d" % (w, h, x, y)) + panel1 = tk.Label(root, image=image1) + panel1.pack(side='top', fill='both', expand='yes') + panel1.image = image1 + root.mainloop() + + + + +class Struct: + """C-like struct""" + + # A basic Python class can pass as a C-like structure + pass + + +struct_factories = { + "pipe_blend_color": gallium.BlendColor, + "pipe_blend_state": gallium.Blend, + #"pipe_clip_state": gallium.Clip, + #"pipe_constant_buffer": gallium.ConstantBuffer, + "pipe_depth_state": gallium.Depth, + "pipe_stencil_state": gallium.Stencil, + "pipe_alpha_state": gallium.Alpha, + "pipe_depth_stencil_alpha_state": gallium.DepthStencilAlpha, + "pipe_format_block": gallium.FormatBlock, + #"pipe_framebuffer_state": gallium.Framebuffer, + "pipe_poly_stipple": gallium.PolyStipple, + "pipe_rasterizer_state": gallium.Rasterizer, + "pipe_sampler_state": gallium.Sampler, + "pipe_scissor_state": gallium.Scissor, + #"pipe_shader_state": gallium.Shader, + #"pipe_vertex_buffer": gallium.VertexBuffer, + "pipe_vertex_element": gallium.VertexElement, + "pipe_viewport_state": gallium.Viewport, + #"pipe_texture": gallium.Texture, +} + + +member_array_factories = { + "pipe_rasterizer_state": {"sprite_coord_mode": gallium.ByteArray}, + "pipe_poly_stipple": {"stipple": gallium.UnsignedArray}, + "pipe_viewport_state": {"scale": gallium.FloatArray, "translate": gallium.FloatArray}, + #"pipe_clip_state": {"ucp": gallium.FloatArray}, + "pipe_depth_stencil_alpha_state": {"stencil": gallium.StencilArray}, + "pipe_blend_color": {"color": gallium.FloatArray}, + "pipe_sampler_state": {"border_color": gallium.FloatArray}, +} + + +class Translator(model.Visitor): + """Translate model arguments into regular Python objects""" + + def __init__(self, interpreter): + self.interpreter = interpreter + self.result = None + + def visit(self, node): + self.result = None + node.visit(self) + return self.result + + def visit_literal(self, node): + self.result = node.value + + def visit_named_constant(self, node): + # lookup the named constant in the gallium module + self.result = getattr(gallium, node.name) + + def visit_array(self, node): + array = [] + for element in node.elements: + array.append(self.visit(element)) + self.result = array + + def visit_struct(self, node): + struct_factory = struct_factories.get(node.name, Struct) + struct = struct_factory() + for member_name, member_node in node.members: + member_value = self.visit(member_node) + try: + array_factory = member_array_factories[node.name][member_name] + except KeyError: + pass + else: + assert isinstance(member_value, list) + array = array_factory(len(member_value)) + for i in range(len(member_value)): + array[i] = member_value[i] + member_value = array + #print node.name, member_name, member_value + assert isinstance(struct, Struct) or hasattr(struct, member_name) + setattr(struct, member_name, member_value) + self.result = struct + + def visit_pointer(self, node): + self.result = self.interpreter.lookup_object(node.address) + + +class Object: + + def __init__(self, interpreter, real): + self.interpreter = interpreter + self.real = real + + +class Global(Object): + + def __init__(self, interpreter, real): + self.interpreter = interpreter + self.real = real + + def pipe_winsys_create(self): + return Winsys(self.interpreter, gallium.Device()) + + def pipe_screen_create(self, winsys): + return Screen(self.interpreter, winsys.real) + + def pipe_context_create(self, screen): + context = screen.real.context_create() + return Context(self.interpreter, context) + + +class Winsys(Object): + + def __init__(self, interpreter, real): + self.interpreter = interpreter + self.real = real + + def get_name(self): + pass + + def user_buffer_create(self, data, size): + # We don't really care to distinguish between user and regular buffers + buffer = self.real.buffer_create(size, + 4, + gallium.PIPE_BUFFER_USAGE_CPU_READ | + gallium.PIPE_BUFFER_USAGE_CPU_WRITE ) + buffer.write(data, size) + return buffer + + def buffer_create(self, alignment, usage, size): + return self.real.buffer_create(size, alignment, usage) + + def buffer_destroy(self, buffer): + pass + + def buffer_write(self, buffer, data, size): + buffer.write(data, size) + + def fence_finish(self, fence, flags): + pass + + def fence_reference(self, dst, src): + pass + + def flush_frontbuffer(self, surface): + pass + + def surface_alloc(self): + return None + + def surface_release(self, surface): + pass + + +class Screen(Object): + + def get_name(self): + pass + + def get_vendor(self): + pass + + def get_param(self, param): + pass + + def get_paramf(self, param): + pass + + def is_format_supported(self, format, target, tex_usage, geom_flags): + return self.real.is_format_supported(format, target, tex_usage, geom_flags) + + def texture_create(self, template): + return self.real.texture_create( + format = template.format, + width = template.width[0], + height = template.height[0], + depth = template.depth[0], + last_level = template.last_level, + target = template.target, + tex_usage = template.tex_usage, + ) + + def texture_destroy(self, texture): + self.interpreter.unregister_object(texture) + + def texture_release(self, surface): + pass + + def get_tex_surface(self, texture, face, level, zslice, usage): + return texture.get_surface(face, level, zslice, usage) + + def tex_surface_destroy(self, surface): + self.interpreter.unregister_object(surface) + + def tex_surface_release(self, surface): + pass + + def surface_write(self, surface, data, stride, size): + assert surface.nblocksy * stride == size + surface.put_tile_raw(0, 0, surface.width, surface.height, data, stride) + + +class Context(Object): + + def __init__(self, interpreter, real): + Object.__init__(self, interpreter, real) + self.cbufs = [] + self.zsbuf = None + + def destroy(self): + pass + + def create_blend_state(self, state): + return state + + def bind_blend_state(self, state): + if state is not None: + self.real.set_blend(state) + + def delete_blend_state(self, state): + pass + + def create_sampler_state(self, state): + return state + + def delete_sampler_state(self, state): + pass + + def bind_sampler_states(self, n, states): + for i in range(n): + self.real.set_sampler(i, states[i]) + + def create_rasterizer_state(self, state): + return state + + def bind_rasterizer_state(self, state): + if state is not None: + self.real.set_rasterizer(state) + + def delete_rasterizer_state(self, state): + pass + + def create_depth_stencil_alpha_state(self, state): + return state + + def bind_depth_stencil_alpha_state(self, state): + if state is not None: + self.real.set_depth_stencil_alpha(state) + + def delete_depth_stencil_alpha_state(self, state): + pass + + def create_fs_state(self, state): + tokens = str(state.tokens) + shader = gallium.Shader(tokens) + return shader + + create_vs_state = create_fs_state + + def bind_fs_state(self, state): + self.real.set_fragment_shader(state) + + def bind_vs_state(self, state): + self.real.set_vertex_shader(state) + + def delete_fs_state(self, state): + pass + + delete_vs_state = delete_fs_state + + def set_blend_color(self, state): + self.real.set_blend_color(state) + + def set_clip_state(self, state): + _state = gallium.Clip() + _state.nr = state.nr + if state.nr: + # FIXME + ucp = gallium.FloatArray(gallium.PIPE_MAX_CLIP_PLANES*4) + for i in range(len(state.ucp)): + for j in range(len(state.ucp[i])): + ucp[i*4 + j] = state.ucp[i][j] + _state.ucp = ucp + self.real.set_clip(_state) + + def set_constant_buffer(self, shader, index, state): + if state is not None: + self.real.set_constant_buffer(shader, index, state.buffer) + + def set_framebuffer_state(self, state): + _state = gallium.Framebuffer() + _state.width = state.width + _state.height = state.height + _state.num_cbufs = state.num_cbufs + for i in range(len(state.cbufs)): + _state.set_cbuf(i, state.cbufs[i]) + _state.set_zsbuf(state.zsbuf) + self.real.set_framebuffer(_state) + + self.cbufs = state.cbufs + self.zsbuf = state.zsbuf + + def set_polygon_stipple(self, state): + self.real.set_polygon_stipple(state) + + def set_scissor_state(self, state): + self.real.set_scissor(state) + + def set_viewport_state(self, state): + self.real.set_viewport(state) + + def set_sampler_textures(self, n, textures): + for i in range(n): + self.real.set_sampler_texture(i, textures[i]) + + def set_vertex_buffers(self, n, vbufs): + for i in range(n): + vbuf = vbufs[i] + self.real.set_vertex_buffer( + i, + pitch = vbuf.pitch, + max_index = vbuf.max_index, + buffer_offset = vbuf.buffer_offset, + buffer = vbuf.buffer, + ) + + def set_vertex_elements(self, n, elements): + for i in range(n): + self.real.set_vertex_element(i, elements[i]) + self.real.set_vertex_elements(n) + + def set_edgeflags(self, bitfield): + # FIXME + pass + + def draw_arrays(self, mode, start, count): + self.real.draw_arrays(mode, start, count) + + def draw_elements(self, indexBuffer, indexSize, mode, start, count): + self.real.draw_elements(indexBuffer, indexSize, mode, start, count) + + def draw_range_elements(self, indexBuffer, indexSize, minIndex, maxIndex, mode, start, count): + self.real.draw_range_elements(indexBuffer, indexSize, minIndex, maxIndex, mode, start, count) + + def flush(self, flags): + self.real.flush(flags) + if flags & gallium.PIPE_FLUSH_FRAME: + self._update() + return None + + def clear(self, surface, value): + self.real.surface_clear(surface, value) + + def _update(self): + self.real.flush() + + if self.cbufs and self.cbufs[0]: + show_image(self.cbufs[0]) + + +class Interpreter(parser.TraceParser): + + def __init__(self, stream): + parser.TraceParser.__init__(self, stream) + self.objects = {} + self.result = None + self.globl = Global(self, None) + + def register_object(self, address, object): + self.objects[address] = object + + def unregister_object(self, object): + # FIXME: + pass + + def lookup_object(self, address): + return self.objects[address] + + def interpret(self, trace): + for call in trace.calls: + self.interpret_call(call) + + def handle_call(self, call): + sys.stderr.write("%s\n" % call) + + args = [self.interpret_arg(arg) for name, arg in call.args] + + if call.klass: + obj = args[0] + args = args[1:] + else: + obj = self.globl + + method = getattr(obj, call.method) + ret = method(*args) + + if call.ret and isinstance(call.ret, model.Pointer): + self.register_object(call.ret.address, ret) + + def interpret_arg(self, node): + translator = Translator(self) + return translator.visit(node) + + +if __name__ == '__main__': + parser.main(Interpreter) diff --git a/src/gallium/state_trackers/python/retrace/model.py b/src/gallium/state_trackers/python/retrace/model.py new file mode 100755 index 00000000000..a17a7659145 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/model.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +############################################################################# +# +# Copyright 2008 Tungsten Graphics, Inc. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################# + + +'''Trace data model.''' + + +class Node: + + def visit(self, visitor): + raise NotImplementedError + + +class Literal(Node): + + def __init__(self, value): + self.value = value + + def visit(self, visitor): + visitor.visit_literal(self) + + def __str__(self): + if isinstance(self.value, str) and len(self.value) > 32: + return '...' + else: + return repr(self.value) + + +class NamedConstant(Node): + + def __init__(self, name): + self.name = name + + def visit(self, visitor): + visitor.visit_named_constant(self) + + def __str__(self): + return self.name + + +class Array(Node): + + def __init__(self, elements): + self.elements = elements + + def visit(self, visitor): + visitor.visit_array(self) + + def __str__(self): + return '{' + ', '.join([str(value) for value in self.elements]) + '}' + + +class Struct(Node): + + def __init__(self, name, members): + self.name = name + self.members = members + + def visit(self, visitor): + visitor.visit_struct(self) + + def __str__(self): + return '{' + ', '.join([name + ' = ' + str(value) for name, value in self.members]) + '}' + + +class Pointer(Node): + + def __init__(self, address): + self.address = address + + def visit(self, visitor): + visitor.visit_pointer(self) + + def __str__(self): + return self.address + + +class Call: + + def __init__(self, klass, method, args, ret): + self.klass = klass + self.method = method + self.args = args + self.ret = ret + + def visit(self, visitor): + visitor.visit_call(self) + + def __str__(self): + s = self.method + if self.klass: + s = self.klass + '::' + s + s += '(' + ', '.join([name + ' = ' + str(value) for name, value in self.args]) + ')' + if self.ret is not None: + s += ' = ' + str(self.ret) + return s + + +class Trace: + + def __init__(self, calls): + self.calls = calls + + def visit(self, visitor): + visitor.visit_trace(self) + + def __str__(self): + return '\n'.join([str(call) for call in self.calls]) + + +class Visitor: + + def visit_literal(self, node): + raise NotImplementedError + + def visit_named_constant(self, node): + raise NotImplementedError + + def visit_array(self, node): + raise NotImplementedError + + def visit_struct(self, node): + raise NotImplementedError + + def visit_pointer(self, node): + raise NotImplementedError + + def visit_call(self, node): + raise NotImplementedError + + def visit_trace(self, node): + raise NotImplementedError + + diff --git a/src/gallium/state_trackers/python/retrace/parser.py b/src/gallium/state_trackers/python/retrace/parser.py new file mode 100755 index 00000000000..6bc75ad6852 --- /dev/null +++ b/src/gallium/state_trackers/python/retrace/parser.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python +############################################################################# +# +# Copyright 2008 Tungsten Graphics, Inc. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################# + + +import sys +import xml.parsers.expat +import binascii + +from model import * + + +ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4) + + +class XmlToken: + + def __init__(self, type, name_or_data, attrs = None, line = None, column = None): + assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF) + self.type = type + self.name_or_data = name_or_data + self.attrs = attrs + self.line = line + self.column = column + + def __str__(self): + if self.type == ELEMENT_START: + return '<' + self.name_or_data + ' ...>' + if self.type == ELEMENT_END: + return '</' + self.name_or_data + '>' + if self.type == CHARACTER_DATA: + return self.name_or_data + if self.type == EOF: + return 'end of file' + assert 0 + + +class XmlTokenizer: + """Expat based XML tokenizer.""" + + def __init__(self, fp, skip_ws = True): + self.fp = fp + self.tokens = [] + self.index = 0 + self.final = False + self.skip_ws = skip_ws + + self.character_pos = 0, 0 + self.character_data = '' + + self.parser = xml.parsers.expat.ParserCreate() + self.parser.StartElementHandler = self.handle_element_start + self.parser.EndElementHandler = self.handle_element_end + self.parser.CharacterDataHandler = self.handle_character_data + + def handle_element_start(self, name, attributes): + self.finish_character_data() + line, column = self.pos() + token = XmlToken(ELEMENT_START, name, attributes, line, column) + self.tokens.append(token) + + def handle_element_end(self, name): + self.finish_character_data() + line, column = self.pos() + token = XmlToken(ELEMENT_END, name, None, line, column) + self.tokens.append(token) + + def handle_character_data(self, data): + if not self.character_data: + self.character_pos = self.pos() + self.character_data += data + + def finish_character_data(self): + if self.character_data: + if not self.skip_ws or not self.character_data.isspace(): + line, column = self.character_pos + token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column) + self.tokens.append(token) + self.character_data = '' + + def next(self): + size = 16*1024 + while self.index >= len(self.tokens) and not self.final: + self.tokens = [] + self.index = 0 + data = self.fp.read(size) + self.final = len(data) < size + data = data.rstrip('\0') + try: + self.parser.Parse(data, self.final) + except xml.parsers.expat.ExpatError, e: + #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS: + if e.code == 3: + pass + else: + raise e + if self.index >= len(self.tokens): + line, column = self.pos() + token = XmlToken(EOF, None, None, line, column) + else: + token = self.tokens[self.index] + self.index += 1 + return token + + def pos(self): + return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber + + +class TokenMismatch(Exception): + + def __init__(self, expected, found): + self.expected = expected + self.found = found + + def __str__(self): + return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found)) + + + +class XmlParser: + """Base XML document parser.""" + + def __init__(self, fp): + self.tokenizer = XmlTokenizer(fp) + self.consume() + + def consume(self): + self.token = self.tokenizer.next() + + def match_element_start(self, name): + return self.token.type == ELEMENT_START and self.token.name_or_data == name + + def match_element_end(self, name): + return self.token.type == ELEMENT_END and self.token.name_or_data == name + + def element_start(self, name): + while self.token.type == CHARACTER_DATA: + self.consume() + if self.token.type != ELEMENT_START: + raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) + if self.token.name_or_data != name: + raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token) + attrs = self.token.attrs + self.consume() + return attrs + + def element_end(self, name): + while self.token.type == CHARACTER_DATA: + self.consume() + if self.token.type != ELEMENT_END: + raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) + if self.token.name_or_data != name: + raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token) + self.consume() + + def character_data(self, strip = True): + data = '' + while self.token.type == CHARACTER_DATA: + data += self.token.name_or_data + self.consume() + if strip: + data = data.strip() + return data + + +class TraceParser(XmlParser): + + def parse(self): + self.element_start('trace') + while self.token.type not in (ELEMENT_END, EOF): + call = self.parse_call() + self.handle_call(call) + if self.token.type != EOF: + self.element_end('trace') + + def parse_call(self): + attrs = self.element_start('call') + klass = attrs['class'] + method = attrs['method'] + args = [] + ret = None + while self.token.type == ELEMENT_START: + if self.token.name_or_data == 'arg': + arg = self.parse_arg() + args.append(arg) + elif self.token.name_or_data == 'ret': + ret = self.parse_ret() + elif self.token.name_or_data == 'call': + # ignore nested function calls + self.parse_call() + else: + raise TokenMismatch("<arg ...> or <ret ...>", self.token) + self.element_end('call') + + return Call(klass, method, args, ret) + + def parse_arg(self): + attrs = self.element_start('arg') + name = attrs['name'] + value = self.parse_value() + self.element_end('arg') + + return name, value + + def parse_ret(self): + attrs = self.element_start('ret') + value = self.parse_value() + self.element_end('ret') + + return value + + def parse_value(self): + expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes') + if self.token.type == ELEMENT_START: + if self.token.name_or_data in expected_tokens: + method = getattr(self, 'parse_' + self.token.name_or_data) + return method() + raise TokenMismatch(" or " .join(expected_tokens), self.token) + + def parse_null(self): + self.element_start('null') + self.element_end('null') + return Literal(None) + + def parse_bool(self): + self.element_start('bool') + value = int(self.character_data()) + self.element_end('bool') + return Literal(value) + + def parse_int(self): + self.element_start('int') + value = int(self.character_data()) + self.element_end('int') + return Literal(value) + + def parse_uint(self): + self.element_start('uint') + value = int(self.character_data()) + self.element_end('uint') + return Literal(value) + + def parse_float(self): + self.element_start('float') + value = float(self.character_data()) + self.element_end('float') + return Literal(value) + + def parse_enum(self): + self.element_start('enum') + name = self.character_data() + self.element_end('enum') + return NamedConstant(name) + + def parse_string(self): + self.element_start('string') + value = self.character_data() + self.element_end('string') + return Literal(value) + + def parse_bytes(self): + self.element_start('bytes') + value = binascii.a2b_hex(self.character_data()) + self.element_end('bytes') + return Literal(value) + + def parse_array(self): + self.element_start('array') + elems = [] + while self.token.type != ELEMENT_END: + elems.append(self.parse_elem()) + self.element_end('array') + return Array(elems) + + def parse_elem(self): + self.element_start('elem') + value = self.parse_value() + self.element_end('elem') + return value + + def parse_struct(self): + attrs = self.element_start('struct') + name = attrs['name'] + members = [] + while self.token.type != ELEMENT_END: + members.append(self.parse_member()) + self.element_end('struct') + return Struct(name, members) + + def parse_member(self): + attrs = self.element_start('member') + name = attrs['name'] + value = self.parse_value() + self.element_end('member') + + return name, value + + def parse_ptr(self): + self.element_start('ptr') + address = self.character_data() + self.element_end('ptr') + + return Pointer(address) + + def handle_call(self, call): + + pass + + +class TraceDumper(TraceParser): + + + def handle_call(self, call): + print call + + +def main(ParserFactory): + for arg in sys.argv[1:]: + if arg.endswith('.gz'): + import gzip + stream = gzip.GzipFile(arg, 'rt') + else: + stream = open(arg, 'rt') + parser = ParserFactory(stream) + parser.parse() + + +if __name__ == '__main__': + main(TraceDumper) diff --git a/src/gallium/state_trackers/python/samples/tri.py b/src/gallium/state_trackers/python/samples/tri.py index 1271c67627d..193479f7d6c 100644 --- a/src/gallium/state_trackers/python/samples/tri.py +++ b/src/gallium/state_trackers/python/samples/tri.py @@ -167,7 +167,6 @@ def test(dev): 1:MOV OUT[1], IN[1] 2:END ''') - #vs.dump() ctx.set_vertex_shader(vs) # fragment shader @@ -178,7 +177,6 @@ def test(dev): 0:MOV OUT[0], IN[0] 1:END ''') - #fs.dump() ctx.set_fragment_shader(fs) nverts = 3 @@ -218,6 +216,7 @@ def test(dev): ctx.flush() show_image(cbuf.get_surface(usage = PIPE_BUFFER_USAGE_CPU_READ|PIPE_BUFFER_USAGE_CPU_WRITE)) + #save_image('tri.png', cbuf.get_surface(usage = PIPE_BUFFER_USAGE_CPU_READ|PIPE_BUFFER_USAGE_CPU_WRITE)) diff --git a/src/gallium/state_trackers/python/st_device.c b/src/gallium/state_trackers/python/st_device.c index fbd56712e01..95c1378a032 100644 --- a/src/gallium/state_trackers/python/st_device.c +++ b/src/gallium/state_trackers/python/st_device.c @@ -26,13 +26,17 @@ **************************************************************************/ -#include "pipe/p_util.h" #include "pipe/p_winsys.h" #include "pipe/p_context.h" #include "pipe/p_shader_tokens.h" #include "pipe/p_inlines.h" #include "cso_cache/cso_context.h" +#include "util/u_math.h" +#include "util/u_memory.h" #include "util/u_simple_shaders.h" +#include "trace/tr_screen.h" +#include "trace/tr_context.h" + #include "st_device.h" #include "st_winsys.h" @@ -41,7 +45,7 @@ static void st_device_really_destroy(struct st_device *st_dev) { if(st_dev->screen) - st_dev->st_ws->screen_destroy(st_dev->screen); + st_dev->screen->destroy(st_dev->screen); FREE(st_dev); } @@ -61,9 +65,7 @@ st_device_create_from_st_winsys(const struct st_winsys *st_ws) struct st_device *st_dev; if(!st_ws->screen_create || - !st_ws->screen_destroy || - !st_ws->context_create || - !st_ws->context_destroy) + !st_ws->context_create) return NULL; st_dev = CALLOC_STRUCT(st_device); @@ -73,9 +75,17 @@ st_device_create_from_st_winsys(const struct st_winsys *st_ws) st_dev->refcount = 1; st_dev->st_ws = st_ws; - st_dev->screen = st_ws->screen_create(); - if(!st_dev->screen) + st_dev->real_screen = st_ws->screen_create(); + if(!st_dev->real_screen) { + st_device_destroy(st_dev); + return NULL; + } + + st_dev->screen = trace_screen_create(st_dev->real_screen); + if(!st_dev->screen) { st_device_destroy(st_dev); + return NULL; + } return st_dev; } @@ -106,7 +116,7 @@ st_context_destroy(struct st_context *st_ctx) } if(st_ctx->pipe) - st_ctx->st_dev->st_ws->context_destroy(st_ctx->pipe); + st_ctx->pipe->destroy(st_ctx->pipe); for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) pipe_texture_reference(&st_ctx->sampler_textures[i], NULL); @@ -132,13 +142,23 @@ st_context_create(struct st_device *st_dev) st_ctx->st_dev = st_dev; ++st_dev->refcount; - st_ctx->pipe = st_dev->st_ws->context_create(st_dev->screen); - if(!st_ctx->pipe) + st_ctx->real_pipe = st_dev->st_ws->context_create(st_dev->real_screen); + if(!st_ctx->real_pipe) { st_context_destroy(st_ctx); + return NULL; + } + st_ctx->pipe = trace_context_create(st_dev->screen, st_ctx->real_pipe); + if(!st_ctx->pipe) { + st_context_destroy(st_ctx); + return NULL; + } + st_ctx->cso = cso_create_context(st_ctx->pipe); - if(!st_ctx->cso) + if(!st_ctx->cso) { st_context_destroy(st_ctx); + return NULL; + } /* disabled blending/masking */ { @@ -272,8 +292,8 @@ void st_buffer_destroy(struct st_buffer *st_buf) { if(st_buf) { - struct pipe_winsys *winsys = st_buf->st_dev->screen->winsys; - pipe_buffer_reference(winsys, &st_buf->buffer, NULL); + struct pipe_screen *screen = st_buf->st_dev->screen; + pipe_buffer_reference(screen, &st_buf->buffer, NULL); FREE(st_buf); } } @@ -283,7 +303,7 @@ struct st_buffer * st_buffer_create(struct st_device *st_dev, unsigned alignment, unsigned usage, unsigned size) { - struct pipe_winsys *winsys = st_dev->screen->winsys; + struct pipe_screen *screen = st_dev->screen; struct st_buffer *st_buf; st_buf = CALLOC_STRUCT(st_buffer); @@ -292,9 +312,11 @@ st_buffer_create(struct st_device *st_dev, st_buf->st_dev = st_dev; - st_buf->buffer = winsys->buffer_create(winsys, alignment, usage, size); - if(!st_buf->buffer) + st_buf->buffer = pipe_buffer_create(screen, alignment, usage, size); + if(!st_buf->buffer) { st_buffer_destroy(st_buf); + return NULL; + } return st_buf; } diff --git a/src/gallium/state_trackers/python/st_device.h b/src/gallium/state_trackers/python/st_device.h index 5b7adbe1a0b..7cfe6de9f6a 100644 --- a/src/gallium/state_trackers/python/st_device.h +++ b/src/gallium/state_trackers/python/st_device.h @@ -48,6 +48,7 @@ struct st_buffer { struct st_context { struct st_device *st_dev; + struct pipe_context *real_pipe; struct pipe_context *pipe; struct cso_context *cso; @@ -57,14 +58,19 @@ struct st_context { struct pipe_texture *default_texture; struct pipe_texture *sampler_textures[PIPE_MAX_SAMPLERS]; + + unsigned num_vertex_buffers; struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS]; + + unsigned num_vertex_elements; struct pipe_vertex_element vertex_elements[PIPE_MAX_ATTRIBS]; }; struct st_device { const struct st_winsys *st_ws; - + + struct pipe_screen *real_screen; struct pipe_screen *screen; /* FIXME: we also need to refcount for textures and surfaces... */ diff --git a/src/gallium/state_trackers/python/st_hardpipe_winsys.c b/src/gallium/state_trackers/python/st_hardpipe_winsys.c index 1e049982329..8b33c70fd71 100644 --- a/src/gallium/state_trackers/python/st_hardpipe_winsys.c +++ b/src/gallium/state_trackers/python/st_hardpipe_winsys.c @@ -42,13 +42,6 @@ extern void init_gallium(void); void (*force_init_gallium_linkage)(void) = &init_gallium; -static void -st_hardpipe_screen_destroy(struct pipe_screen *screen) -{ - st_softpipe_winsys.screen_destroy(screen); -} - - static struct pipe_screen * st_hardpipe_screen_create(void) { @@ -56,13 +49,6 @@ st_hardpipe_screen_create(void) } -static void -st_hardpipe_context_destroy(struct pipe_context *pipe) -{ - st_softpipe_winsys.context_destroy(pipe); -} - - static struct pipe_context * st_hardpipe_context_create(struct pipe_screen *screen) { @@ -72,7 +58,5 @@ st_hardpipe_context_create(struct pipe_screen *screen) const struct st_winsys st_hardpipe_winsys = { &st_hardpipe_screen_create, - &st_hardpipe_screen_destroy, - &st_hardpipe_context_create, - &st_hardpipe_context_destroy + &st_hardpipe_context_create }; diff --git a/src/gallium/state_trackers/python/st_sample.c b/src/gallium/state_trackers/python/st_sample.c index b47c7be2933..7765df3c4a4 100644 --- a/src/gallium/state_trackers/python/st_sample.c +++ b/src/gallium/state_trackers/python/st_sample.c @@ -29,9 +29,10 @@ #include "pipe/p_compiler.h" #include "pipe/p_format.h" #include "pipe/p_state.h" -#include "pipe/p_util.h" #include "pipe/p_inlines.h" -#include "util/p_tile.h" +#include "util/u_tile.h" +#include "util/u_math.h" +#include "util/u_memory.h" #include "st_sample.h" diff --git a/src/gallium/state_trackers/python/st_softpipe_winsys.c b/src/gallium/state_trackers/python/st_softpipe_winsys.c index 1fda70ca00f..f62113a4691 100644 --- a/src/gallium/state_trackers/python/st_softpipe_winsys.c +++ b/src/gallium/state_trackers/python/st_softpipe_winsys.c @@ -39,8 +39,9 @@ #include "pipe/p_winsys.h" #include "pipe/p_format.h" #include "pipe/p_context.h" -#include "pipe/p_util.h" #include "pipe/p_inlines.h" +#include "util/u_math.h" +#include "util/u_memory.h" #include "softpipe/sp_winsys.h" #include "st_winsys.h" @@ -220,7 +221,7 @@ st_softpipe_surface_release(struct pipe_winsys *winsys, surf->refcount--; if (surf->refcount == 0) { if (surf->buffer) - pipe_buffer_reference(winsys, &surf->buffer, NULL); + winsys_buffer_reference(winsys, &surf->buffer, NULL); free(surf); } *s = NULL; @@ -253,13 +254,9 @@ st_softpipe_fence_finish(struct pipe_winsys *winsys, } -static void -st_softpipe_screen_destroy(struct pipe_screen *screen) +static void +st_softpipe_destroy(struct pipe_winsys *winsys) { - struct pipe_winsys *winsys = screen->winsys; - - screen->destroy(screen); - FREE(winsys); } @@ -274,6 +271,8 @@ st_softpipe_screen_create(void) if(!winsys) return NULL; + winsys->destroy = st_softpipe_destroy; + winsys->buffer_create = st_softpipe_buffer_create; winsys->user_buffer_create = st_softpipe_user_buffer_create; winsys->buffer_map = st_softpipe_buffer_map; @@ -293,19 +292,12 @@ st_softpipe_screen_create(void) screen = softpipe_create_screen(winsys); if(!screen) - FREE(winsys); + st_softpipe_destroy(winsys); return screen; } -static void -st_softpipe_context_destroy(struct pipe_context *pipe) -{ - pipe->destroy(pipe); -} - - static struct pipe_context * st_softpipe_context_create(struct pipe_screen *screen) { @@ -315,7 +307,5 @@ st_softpipe_context_create(struct pipe_screen *screen) const struct st_winsys st_softpipe_winsys = { &st_softpipe_screen_create, - &st_softpipe_screen_destroy, &st_softpipe_context_create, - &st_softpipe_context_destroy }; diff --git a/src/gallium/state_trackers/python/st_winsys.h b/src/gallium/state_trackers/python/st_winsys.h index 43db8b6bff1..b8cb612d863 100644 --- a/src/gallium/state_trackers/python/st_winsys.h +++ b/src/gallium/state_trackers/python/st_winsys.h @@ -39,14 +39,8 @@ struct st_winsys struct pipe_screen * (*screen_create)(void); - void - (*screen_destroy)(struct pipe_screen *screen); - struct pipe_context * (*context_create)(struct pipe_screen *screen); - - void - (*context_destroy)(struct pipe_context *pipe); }; |