From df94fb92bd6e1be4522a352e520ce0565a4499b9 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 1 Jun 2009 11:33:07 +0100 Subject: Initial commit --- .gitignore | 8 + Makefile.in | 74 ++++++ README | 36 +++ autogen.sh | 5 + configure.ac | 21 ++ res/argb.png | Bin 0 -> 180 bytes res/ask.xml | 94 ++++++++ res/bgr.png | Bin 0 -> 183 bytes res/main.xml | 267 +++++++++++++++++++++ res/rgb.png | Bin 0 -> 175 bytes res/rgba.png | Bin 0 -> 176 bytes res/rgbx.png | Bin 0 -> 175 bytes res/s8z24.png | Bin 0 -> 181 bytes res/screen.png | Bin 0 -> 471 bytes res/shader_off_normal.png | Bin 0 -> 207 bytes res/shader_off_replaced.png | Bin 0 -> 707 bytes res/shader_on_normal.png | Bin 0 -> 207 bytes res/shader_on_replaced.png | Bin 0 -> 705 bytes res/x8z24.png | Bin 0 -> 181 bytes res/xbgr.png | Bin 0 -> 182 bytes res/xrgb.png | Bin 0 -> 175 bytes res/z24s8.png | Bin 0 -> 180 bytes res/z24x8.png | Bin 0 -> 181 bytes src/ask.c | 93 ++++++++ src/context.c | 27 +++ src/draw.c | 155 +++++++++++++ src/main.c | 341 +++++++++++++++++++++++++++ src/program.h | 166 +++++++++++++ src/rbug.c | 119 ++++++++++ src/shader.c | 352 ++++++++++++++++++++++++++++ src/texture.c | 550 ++++++++++++++++++++++++++++++++++++++++++++ 31 files changed, 2308 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile.in create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 res/argb.png create mode 100644 res/ask.xml create mode 100644 res/bgr.png create mode 100644 res/main.xml create mode 100644 res/rgb.png create mode 100644 res/rgba.png create mode 100644 res/rgbx.png create mode 100644 res/s8z24.png create mode 100644 res/screen.png create mode 100644 res/shader_off_normal.png create mode 100644 res/shader_off_replaced.png create mode 100644 res/shader_on_normal.png create mode 100644 res/shader_on_replaced.png create mode 100644 res/x8z24.png create mode 100644 res/xbgr.png create mode 100644 res/xrgb.png create mode 100644 res/z24s8.png create mode 100644 res/z24x8.png create mode 100644 src/ask.c create mode 100644 src/context.c create mode 100644 src/draw.c create mode 100644 src/main.c create mode 100644 src/program.h create mode 100644 src/rbug.c create mode 100644 src/shader.c create mode 100644 src/texture.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..472c399 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.obj +Makefile +aclocal.m4 +autom4te.cache +config.log +config.status +configure +rbug-gui diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..1d39e8b --- /dev/null +++ b/Makefile.in @@ -0,0 +1,74 @@ +# autoconf directories +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir = @libdir@ +includedir = @includedir@ + +# autoconf variables +CC = @CC@ +MESA = @MESA_DIR@ +CFLAGS = @CFLAGS@ -Isrc @GTK_CFLAGS@ $(MESA_INCLUDES) -DDEBUG +LDFLAGS = @LDFLAGS@ @GTK_LIBS@ $(MESA_LIBS) + +# Makefile hardcoded +MESA_INCLUDES = \ + -I$(MESA)src/gallium/include \ + -I$(MESA)src/gallium/auxiliary \ + -I$(MESA)src/gallium/drivers + +MESA_LIBS = \ + $(MESA)src/gallium/auxiliary/rbug/librbug.a \ + $(MESA)src/gallium/auxiliary/tgsi/libtgsi.a \ + $(MESA)src/gallium/auxiliary/util/libutil.a + + + +TARGET := rbug-gui +ODIR := .obj +CDIR := src + +CFILES := $(wildcard $(CDIR)/*.c) +OFILES := $(patsubst $(CDIR)/%.c,$(ODIR)/%.o,$(CFILES)) +DFILES := $(patsubst $(CDIR)/%.c,$(ODIR)/%.d,$(CFILES)) + +all: $(TARGET) + +run: $(TARGET) + @./$(TARGET) localhost + +debug: $(TARGET) + @gdb ./$(TARGET) + +valgrind: $(TARGET) + @valgrind --leak-check=full --track-origins=yes ./$(TARGET) + +$(ODIR): + @echo " :: creating $@ directory" + @mkdir -p $@ + +$(TARGET): $(OFILES) + @echo " :: linking $@" + @$(CC) $^ $(LDFLAGS) -o $@ + +$(OFILES): $(ODIR)/%.o: $(CDIR)/%.c Makefile + @echo " :: compiling $<" + @$(CC) $(CFLAGS) -o $@ -c $< -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" + +clean: + @echo " :: cleaning" + @-rm -rf $(ODIR) $(TARGET) + +distclean: clean + @-rm -rf aclocal.m4 autoscan.log autom4te.cache Makefile + @-rm -rf config.status config.log configure configure.scan + +install: + @echo " :: installing" + @install -d @exec_prefix@/bin + @install $(TARGET) @exec_prefix@/bin + +$(CFILES): $(ODIR) + +.PHONY: clean distclean run debug valgrind + +sinclude $(DFILES) diff --git a/README b/README new file mode 100644 index 0000000..3ebb100 --- /dev/null +++ b/README @@ -0,0 +1,36 @@ + GALLIUM REMOTE DEBUGGING GUI + += About = + +This is the gui interface to the Gallium Remote Debugger. +It is written in C and uses gtk, gtkglext and Gallium. + + +For information about protocol (de)marshaling see: +$(MESA)src/gallium/auxiliary/rbug/README + +for information about driver integration look in: +$(MESA)src/gallium/drivers/trace/README + +for information about applications look in: +$(MESA)progs/rbug/README + + += Building = + +You need to have checked out a mesa repository in a sibling directory to this +directory called mesa, as currently the build looks for mesa in ../mesa/. +You also need to build a debug build of mesa with with gallium so that the +needed libraries excist: + + $(MESA)src/gallium/auxiliary/rbug/librbug.a + $(MESA)src/gallium/auxiliary/tgsi/libtgsi.a + $(MESA)src/gallium/auxiliary/util/libutil.a + +Then just do + ./autogen.sh + make + + +-- +Jakob Bornecrantz diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..e584d21 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,5 @@ +#! /bin/sh + +autoreconf -v || exit 1 + +./configure "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..e76feab --- /dev/null +++ b/configure.ac @@ -0,0 +1,21 @@ +AC_INIT(rbug-gui, 1) +AC_PROG_CC + +PKG_PROG_PKG_CONFIG() +PKG_CHECK_MODULES(GTK,[gtkglext-1.0]) + +if test $CC = gcc; then + GCC_CFLAGS+=" -Wall -W -Werror -Wstrict-prototypes -Wmissing-prototypes" + GCC_CFLAGS+=" -fvisibility=hidden -fPIC" + GCC_LDFLAGS="" + + CFLAGS+=$GCC_CFLAGS + LDFLAGS+=$GCC_LDFLAGS +fi + +# Add option for this +MESA_DIR="../mesa/" +AC_SUBST([MESA_DIR]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/res/argb.png b/res/argb.png new file mode 100644 index 0000000..b0b8cf8 Binary files /dev/null and b/res/argb.png differ diff --git a/res/ask.xml b/res/ask.xml new file mode 100644 index 0000000..a3055cc --- /dev/null +++ b/res/ask.xml @@ -0,0 +1,94 @@ + + + + + + 5 + + + True + vertical + 2 + + + True + 4 + + + True + True + + localhost + + + 0 + + + + + True + True + + adjustment_port + True + + + 1 + + + + + 0 + + + + + True + 4 + end + + + gtk-connect + True + True + True + True + + + False + False + 0 + + + + + gtk-quit + True + True + True + True + + + False + False + 1 + + + + + False + end + 1 + + + + + + + 13370 + 13370 + 13379 + 1 + 1 + + diff --git a/res/bgr.png b/res/bgr.png new file mode 100644 index 0000000..13fd779 Binary files /dev/null and b/res/bgr.png differ diff --git a/res/main.xml b/res/main.xml new file mode 100644 index 0000000..7772398 --- /dev/null +++ b/res/main.xml @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + 600 + 600 + + + True + vertical + + + True + + + True + Rerfresh + gtk-refresh + + + False + True + + + + + True + + + False + True + + + + + Back + True + gtk-go-back + + + False + True + + + + + Forward + gtk-go-forward + + + False + True + + + + + Background + True + gtk-select-color + + + False + True + + + + + Alpha Blend + True + format-text-bold + + + False + True + + + + + Auto + True + gtk-execute + + + False + True + + + + + Disable + True + gtk-no + + + False + True + + + + + Enable + True + gtk-yes + + + False + True + + + + + Save + True + gtk-save + + + False + True + + + + + Revert + True + gtk-revert-to-saved + + + False + True + + + + + True + False + + + True + True + + + + + True + Quit + True + gtk-quit + + + False + True + + + + + False + 0 + + + + + True + True + 250 + True + + + True + True + automatic + automatic + + + True + True + treestore + False + 0 + + + Name + + + + + ID + + + + + autosize + + + + + + + False + True + + + + + True + vertical + + + True + True + automatic + automatic + + + True + + + + + 0 + + + + + + 1 + + + + + + + + True + True + + + + + 1 + + + + + True + + + False + 2 + + + + + + diff --git a/res/rgb.png b/res/rgb.png new file mode 100644 index 0000000..fb74e4f Binary files /dev/null and b/res/rgb.png differ diff --git a/res/rgba.png b/res/rgba.png new file mode 100644 index 0000000..362ebf7 Binary files /dev/null and b/res/rgba.png differ diff --git a/res/rgbx.png b/res/rgbx.png new file mode 100644 index 0000000..2d06698 Binary files /dev/null and b/res/rgbx.png differ diff --git a/res/s8z24.png b/res/s8z24.png new file mode 100644 index 0000000..4df4bd8 Binary files /dev/null and b/res/s8z24.png differ diff --git a/res/screen.png b/res/screen.png new file mode 100644 index 0000000..bb4c73d Binary files /dev/null and b/res/screen.png differ diff --git a/res/shader_off_normal.png b/res/shader_off_normal.png new file mode 100644 index 0000000..a5d6f64 Binary files /dev/null and b/res/shader_off_normal.png differ diff --git a/res/shader_off_replaced.png b/res/shader_off_replaced.png new file mode 100644 index 0000000..1424703 Binary files /dev/null and b/res/shader_off_replaced.png differ diff --git a/res/shader_on_normal.png b/res/shader_on_normal.png new file mode 100644 index 0000000..b09addf Binary files /dev/null and b/res/shader_on_normal.png differ diff --git a/res/shader_on_replaced.png b/res/shader_on_replaced.png new file mode 100644 index 0000000..2b3d8cd Binary files /dev/null and b/res/shader_on_replaced.png differ diff --git a/res/x8z24.png b/res/x8z24.png new file mode 100644 index 0000000..850cb99 Binary files /dev/null and b/res/x8z24.png differ diff --git a/res/xbgr.png b/res/xbgr.png new file mode 100644 index 0000000..c8173f0 Binary files /dev/null and b/res/xbgr.png differ diff --git a/res/xrgb.png b/res/xrgb.png new file mode 100644 index 0000000..cc80a5b Binary files /dev/null and b/res/xrgb.png differ diff --git a/res/z24s8.png b/res/z24s8.png new file mode 100644 index 0000000..f8a14dd Binary files /dev/null and b/res/z24s8.png differ diff --git a/res/z24x8.png b/res/z24x8.png new file mode 100644 index 0000000..c76ae2a Binary files /dev/null and b/res/z24x8.png differ diff --git a/src/ask.c b/src/ask.c new file mode 100644 index 0000000..8e17649 --- /dev/null +++ b/src/ask.c @@ -0,0 +1,93 @@ + +#include "program.h" +#include "util/u_network.h" + + +gboolean ask_connect(struct program *p) +{ + int socket; + + socket = u_socket_connect(p->ask.host, p->ask.port); + + if (socket < 0) + return false; + + p->rbug.socket = socket; + p->rbug.con = rbug_from_socket(socket); + + rbug_glib_io_watch(p); + + main_window_create(p); + + return true; +} + +static void connect(GtkWidget *widget, gpointer data) +{ + struct program *p = (struct program *)data; + char *host; + uint16_t port; + + (void)widget; + + host = gtk_editable_get_chars(GTK_EDITABLE(p->ask.entry_host), 0, -1); + port = (uint16_t)gtk_adjustment_get_value(p->ask.adjustment_port); + + p->ask.host = host; + p->ask.port = port; + + if (!ask_connect(p)) + return; + + gtk_widget_destroy(p->ask.window); + + p->ask.window = NULL; + p->ask.entry_host = NULL; + p->ask.entry_port = NULL; +} + +static void destroy(GtkWidget *widget, gpointer data) +{ + struct program *p = (struct program *)data; + (void)widget; + + if (!p->main.window) + main_quit(p); +} + +void ask_window_create(struct program *p) +{ + GtkBuilder *builder; + GtkWidget *window; + GtkWidget *button; + GtkWidget *quit; + GtkWidget *entry_host; + GtkWidget *entry_port; + GtkAdjustment *adjustment_port; + + builder = gtk_builder_new(); + + gtk_builder_add_from_file(builder, "res/ask.xml", NULL); + gtk_builder_connect_signals(builder, NULL); + + window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); + button = GTK_WIDGET(gtk_builder_get_object(builder, "connect")); + quit = GTK_WIDGET(gtk_builder_get_object(builder, "quit")); + entry_host = GTK_WIDGET(gtk_builder_get_object(builder, "entry_host")); + entry_port = GTK_WIDGET(gtk_builder_get_object(builder, "entry_port")); + adjustment_port = GTK_ADJUSTMENT(gtk_builder_get_object(builder, "adjustment_port")); + + /* manualy set up signals */ + g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(connect), p); + g_signal_connect(G_OBJECT(quit), "clicked", G_CALLBACK(destroy), p); + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), p); + + gtk_widget_show(window); + + p->ask.window = window; + p->ask.entry_host = entry_host; + p->ask.entry_port = entry_port; + p->ask.adjustment_port = adjustment_port; + + gtk_adjustment_set_value(adjustment_port, 13370); +} diff --git a/src/context.c b/src/context.c new file mode 100644 index 0000000..73e572b --- /dev/null +++ b/src/context.c @@ -0,0 +1,27 @@ + +#include "program.h" + +void context_list(GtkTreeStore *store, GtkTreeIter *parent, struct program *p) +{ + struct rbug_proto_context_list_reply *list; + struct rbug_connection *con = p->rbug.con; + struct rbug_header *header; + uint32_t i; + + rbug_send_context_list(con, NULL); + header = rbug_get_message(con, NULL); + list = (struct rbug_proto_context_list_reply *)header; + + for (i = 0; i < list->contexts_len; i++) { + GtkTreeIter iter; + gtk_tree_store_insert_with_values(store, &iter, parent, -1, + COLUMN_ID, list->contexts[i], + COLUMN_TYPE, TYPE_CONTEXT, + COLUMN_TYPENAME, "context", + -1); + + shader_list(store, &iter, list->contexts[i], p); + } + + rbug_free_header(header); +} diff --git a/src/draw.c b/src/draw.c new file mode 100644 index 0000000..9765978 --- /dev/null +++ b/src/draw.c @@ -0,0 +1,155 @@ + + +#include "program.h" +#include + +static void realize(GtkWidget* widget, gpointer data) +{ +#if 0 + GdkGLContext* context = gtk_widget_get_gl_context(widget); + GdkGLDrawable* drawable = gtk_widget_get_gl_drawable(widget); + (void)data; + + if (!gdk_gl_drawable_gl_begin(drawable, context)) + return; + + gdk_gl_drawable_gl_end(drawable); +#else + (void)widget; + (void)data; +#endif +} + +static gboolean configure(GtkWidget* widget, GdkEventConfigure* e, gpointer data) +{ +#if 0 + GdkGLContext* context = gtk_widget_get_gl_context(widget); + GdkGLDrawable* drawable = gtk_widget_get_gl_drawable(widget); + (void)data; + (void)e; + + if (!gdk_gl_drawable_gl_begin(drawable, context)) + return FALSE; + + gdk_gl_drawable_gl_end (drawable); +#else + (void)widget; + (void)data; + (void)e; +#endif + return TRUE; +} + +static void draw_tri(struct program *p) +{ + glClearColor(0.3, 0.1, 0.3, 0.5); + glViewport(0, 0, (GLint)p->draw.width, (GLint)p->draw.height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0); + glMatrixMode(GL_MODELVIEW); + + glClear(GL_COLOR_BUFFER_BIT); + + glBegin(GL_TRIANGLES); + glColor3f(.8,0,0); + glVertex3f(-0.9, -0.9, -30.0); + glColor3f(0,.9,0); + glVertex3f( 0.9, -0.9, -30.0); + glColor3f(0,0,.7); + glVertex3f( 0.0, 0.9, -30.0); + glEnd(); +} + +gboolean draw_gl_begin(struct program *p) +{ + GtkWidget *widget = GTK_WIDGET(p->main.draw); + GdkGLContext* context = gtk_widget_get_gl_context(widget); + GdkGLDrawable* drawable = gtk_widget_get_gl_drawable(widget); + + return gdk_gl_drawable_gl_begin(drawable, context); +} + +void draw_gl_end(struct program *p) +{ + GtkWidget *widget = GTK_WIDGET(p->main.draw); + GdkGLDrawable* drawable = gtk_widget_get_gl_drawable(widget); + + gdk_gl_drawable_gl_end(drawable); +} + +void draw_ortho_top_left(struct program *p) +{ + glViewport(0, 0, (GLint)p->draw.width, (GLint)p->draw.height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, p->draw.width, p->draw.height, 0.0, -0.5, 1000.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void draw_checker(guint width, guint height, struct program *p) +{ + int x; + int y; + int i; + + glClearColor(0.3, 0.3, 0.3, 0.5); + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(.8,.8,.8); + glBegin(GL_QUADS); + for (i = 0, x = 0; x < (int)p->draw.width; i++) { + x = (width * i) - (width / 2); + y = ((i % 2) * height) - (height / 2); + for (; y < (int)p->draw.height; y += height * 2) { + glVertex3f( x + 0.0, y + height, -30.0); + glVertex3f( x + width, y + height, -30.0); + glVertex3f( x + width, y + 0.0, -30.0); + glVertex3f( x + 0.0, y + 0.0, -30.0); + } + } + glEnd(); +} + +static gboolean expose(GtkWidget* widget, GdkEventExpose* e, gpointer data) +{ + struct program *p = (struct program *)data; + GdkGLContext* context = gtk_widget_get_gl_context(widget); + GdkGLDrawable* drawable = gtk_widget_get_gl_drawable(widget); + (void)e; + + p->draw.width = widget->allocation.width; + p->draw.height = widget->allocation.height; + + if (!gdk_gl_drawable_gl_begin(drawable, context)) + return FALSE; + + if (p->selected.type == TYPE_TEXTURE) + texture_draw(p); + else + draw_tri(p); + + if (gdk_gl_drawable_is_double_buffered (drawable)) + gdk_gl_drawable_swap_buffers(drawable); + else + glFlush(); + + gdk_gl_drawable_gl_end(drawable); + + return TRUE; +} + +void draw_setup(GtkDrawingArea *draw, struct program *p) +{ + GObject *obj = G_OBJECT(draw); + + gtk_widget_set_gl_capability(GTK_WIDGET(draw), p->draw.config, NULL, + TRUE, GDK_GL_RGBA_TYPE); + + g_signal_connect_after(obj, "realize", G_CALLBACK(realize), p); + g_signal_connect(obj, "configure-event", G_CALLBACK(configure), p); + g_signal_connect(obj, "expose-event", G_CALLBACK(expose), p); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6cd6839 --- /dev/null +++ b/src/main.c @@ -0,0 +1,341 @@ + +#include "program.h" +#include "pipe/p_format.h" + +static gboolean main_idle(gpointer data) +{ + struct program *p = (struct program *)data; + + if (!ask_connect(p)) + main_quit(p); + + return false; +} + +int main(int argc, char *argv[]) +{ + struct program *p = g_malloc(sizeof(*p)); + memset(p, 0, sizeof(*p)); + + gtk_init(&argc, &argv); + gtk_gl_init(&argc, &argv); + + p->draw.config = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | + GDK_GL_MODE_ALPHA | + GDK_GL_MODE_DEPTH | + GDK_GL_MODE_DOUBLE); + + /* connect to first non gnome argument */ + if (argc > 1) { + int len = strlen(argv[1]) + 1; + p->ask.host = g_malloc(len); + memcpy(p->ask.host, argv[1], len); + p->ask.port = 13370; + gtk_idle_add(main_idle, p); + } else { + ask_window_create(p); + } + + gtk_main(); + + g_free(p); + + return 0; +} + +static void destroy(GtkWidget *widget, gpointer data) +{ + struct program *p = (struct program *)data; + (void)widget; + + main_quit(p); +} + +static void foreach(GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + struct program *p = (struct program *)data; + GtkTreeIter parent; + GValue id; + GValue type; + GValue typename; + (void)path; + (void)data; + + memset(&id, 0, sizeof(id)); + memset(&type, 0, sizeof(type)); + memset(&typename, 0, sizeof(typename)); + + gtk_tree_model_get_value(model, iter, COLUMN_ID, &id); + gtk_tree_model_get_value(model, iter, COLUMN_TYPE, &type); + gtk_tree_model_get_value(model, iter, COLUMN_TYPENAME, &typename); + + g_assert(G_VALUE_HOLDS_UINT64(&id)); + g_assert(G_VALUE_HOLDS_INT(&type)); + g_assert(G_VALUE_HOLDS_STRING(&typename)); + + p->selected.iter = *iter; + p->selected.id = g_value_get_uint64(&id); + p->selected.type = g_value_get_int(&type); + + if (gtk_tree_model_iter_parent(model, &parent, iter)) { + g_value_unset(&id); + gtk_tree_model_get_value(model, &parent, COLUMN_ID, &id); + g_assert(G_VALUE_HOLDS_UINT64(&id)); + + p->selected.parent = g_value_get_uint64(&id); + } +} + +static void changed(GtkTreeSelection *s, gpointer data) +{ + struct program *p = (struct program *)data; + enum types old_type; + uint64_t old_id; + (void)s; + (void)p; + + old_id = p->selected.id; + old_type = p->selected.type; + + /* reset selected data */ + memset(&p->selected, 0, sizeof(p->selected)); + + gtk_tree_selection_selected_foreach(s, foreach, p); + + if (p->selected.id != old_id || + p->selected.type != old_type) { + if (old_id) { + if (old_type == TYPE_SHADER) + shader_unselected(p); + else if (old_type == TYPE_TEXTURE) + texture_unselected(p); + } + if (p->selected.id) { + if (p->selected.type == TYPE_SHADER) + shader_selected(p); + else if (p->selected.type == TYPE_TEXTURE) + texture_selected(p); + } + } +} + +static void refresh(GtkWidget *widget, gpointer data) +{ + struct program *p = (struct program *)data; + GtkTreeStore *store = p->main.treestore; + (void)widget; + + if (p->selected.id != 0) { + if (p->selected.type == TYPE_TEXTURE) + texture_refresh(p); + + return; + } + + gtk_tree_store_clear(p->main.treestore); + + gtk_tree_store_insert_with_values(store, &p->main.top, NULL, -1, + COLUMN_ID, 0, + COLUMN_TYPE, TYPE_SCREEN, + COLUMN_TYPENAME, "screen", + COLUMN_PIXBUF, icon_get("screen", p), + -1); + + /* contexts */ + context_list(store, &p->main.top, p); + + /* textures */ + texture_list(store, &p->main.top, p); + + /* expend all rows */ + gtk_tree_view_expand_all(p->main.treeview); +} + +static void setup_cols(GtkBuilder *builder, GtkTreeView *view, struct program *p) +{ + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + (void)view; + (void)p; + + /* column id */ + col = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "col_id")); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_add_attribute(col, renderer, "text", COLUMN_ID); + + /* column format */ + col = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "col_string")); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_add_attribute(col, renderer, "text", COLUMN_TYPENAME); + + /* column format */ + col = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "col_icon")); + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_add_attribute(col, renderer, "pixbuf", COLUMN_PIXBUF); + + g_object_set(G_OBJECT(renderer), "xalign", (gfloat)0.0f, NULL); +} + +static void icon_setup(struct program *p) +{ + p->icon.hash = g_hash_table_new(g_str_hash, g_str_equal); + + icon_add("res/rgba.png", "rgba", p); + icon_add("res/rgbx.png", "rgbx", p); + icon_add("res/argb.png", "argb", p); + icon_add("res/xrgb.png", "xrgb", p); + + icon_add("res/s8z24.png", "s8z24", p); + icon_add("res/x8z24.png", "x8z24", p); + icon_add("res/z24s8.png", "z24s8", p); + icon_add("res/z24x8.png", "z24x8", p); + + icon_add("res/rgb.png", "rgb", p); + icon_add("res/rgb.png", "bgr", p); + + icon_add("res/screen.png", "screen", p); + + icon_add("res/shader_on_normal.png", "shader_on_normal", p); + icon_add("res/shader_on_replaced.png", "shader_on_replaced", p); + icon_add("res/shader_off_normal.png", "shader_off_normal", p); + icon_add("res/shader_off_replaced.png", "shader_off_replaced", p); +} + +void main_window_create(struct program *p) +{ + GtkBuilder *builder; + + GtkWidget *window; + GObject *selection; + GtkDrawingArea *draw; + GtkTextView *textview; + GtkWidget *textview_scrolled; + GtkTreeView *treeview; + GtkTreeStore *treestore; + + GObject *tool_quit; + GObject *tool_refresh; + + GObject *tool_back; + GObject *tool_forward; + GObject *tool_background; + GObject *tool_alpha; + GObject *tool_automatic; + + GObject *tool_disable; + GObject *tool_enable; + GObject *tool_save; + GObject *tool_revert; + + builder = gtk_builder_new(); + + gtk_builder_add_from_file(builder, "res/main.xml", NULL); + gtk_builder_connect_signals(builder, NULL); + + draw = GTK_DRAWING_AREA(gtk_builder_get_object(builder, "draw")); + window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); + textview = GTK_TEXT_VIEW(gtk_builder_get_object(builder, "textview")); + treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "treeview")); + treestore = GTK_TREE_STORE(gtk_builder_get_object(builder, "treestore")); + selection = G_OBJECT(gtk_tree_view_get_selection(treeview)); + textview_scrolled = GTK_WIDGET(gtk_builder_get_object(builder, "textview_scrolled")); + + + tool_quit = gtk_builder_get_object(builder, "tool_quit"); + tool_refresh = gtk_builder_get_object(builder, "tool_refresh"); + + tool_back = gtk_builder_get_object(builder, "tool_back"); + tool_forward = gtk_builder_get_object(builder, "tool_forward"); + tool_background = gtk_builder_get_object(builder, "tool_background"); + tool_alpha = gtk_builder_get_object(builder, "tool_alpha"); + tool_automatic = gtk_builder_get_object(builder, "tool_auto"); + + tool_disable = gtk_builder_get_object(builder, "tool_disable"); + tool_enable = gtk_builder_get_object(builder, "tool_enable"); + tool_save = gtk_builder_get_object(builder, "tool_save"); + tool_revert = gtk_builder_get_object(builder, "tool_revert"); + + setup_cols(builder, treeview, p); + + /* manualy set up signals */ + g_signal_connect(selection, "changed", G_CALLBACK(changed), p); + g_signal_connect(tool_quit, "clicked", G_CALLBACK(destroy), p); + g_signal_connect(tool_refresh, "clicked", G_CALLBACK(refresh), p); + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), p); + + p->main.draw = draw; + p->main.window = window; + p->main.textview = textview; + p->main.treeview = treeview; + p->main.treestore = treestore; + p->main.textview_scrolled = textview_scrolled; + + p->tool.back = GTK_WIDGET(tool_back); + p->tool.forward = GTK_WIDGET(tool_forward); + p->tool.background = GTK_WIDGET(tool_background); + p->tool.alpha = GTK_WIDGET(tool_alpha); + p->tool.automatic = GTK_WIDGET(tool_automatic); + + p->tool.disable = GTK_WIDGET(tool_disable); + p->tool.enable = GTK_WIDGET(tool_enable); + p->tool.save = GTK_WIDGET(tool_save); + p->tool.revert = GTK_WIDGET(tool_revert); + + draw_setup(draw, p); + + gtk_widget_hide(p->tool.back); + gtk_widget_hide(p->tool.forward); + gtk_widget_hide(p->tool.background); + gtk_widget_hide(p->tool.alpha); + + gtk_widget_hide(p->tool.disable); + gtk_widget_hide(p->tool.enable); + gtk_widget_hide(p->tool.save); + gtk_widget_hide(p->tool.revert); + + gtk_widget_hide(p->main.textview_scrolled); + gtk_widget_hide(GTK_WIDGET(p->main.textview)); + gtk_widget_hide(GTK_WIDGET(p->main.draw)); + + gtk_widget_show(window); + + icon_setup(p); + + /* do a refresh */ + refresh(GTK_WIDGET(tool_refresh), p); +} + +void main_quit(struct program *p) +{ + if (p->rbug.con) { + rbug_disconnect(p->rbug.con); + g_io_channel_unref(p->rbug.channel); + g_source_remove(p->rbug.event); + g_hash_table_unref(p->rbug.hash); + } + + g_free(p->ask.host); + + gtk_main_quit(); +} + +void icon_add(const char *filename, const char *name, struct program *p) +{ + GdkPixbuf *icon = gdk_pixbuf_new_from_file(filename, NULL); + + if (!icon) + return; + + g_hash_table_insert(p->icon.hash, (char*)name, icon); +} + +GdkPixbuf * icon_get(const char *name, struct program *p) +{ + return (GdkPixbuf *)g_hash_table_lookup(p->icon.hash, name); +} diff --git a/src/program.h b/src/program.h new file mode 100644 index 0000000..d8b8180 --- /dev/null +++ b/src/program.h @@ -0,0 +1,166 @@ + +#ifndef _RBUG_GUI_PROGRAM_H_ +#define _RBUG_GUI_PROGRAM_H_ + +#include +#include + +#include "rbug/rbug.h" + +struct texture_action_read; +struct shader_action_info; + +enum columns { + COLUMN_ID = 0, + COLUMN_TYPE, + COLUMN_TYPENAME, + COLUMN_PIXBUF, +}; + +enum types { + TYPE_NONE = 0, + TYPE_SCREEN, + TYPE_CONTEXT, + TYPE_TEXTURE, + TYPE_SHADER, +}; + +struct program +{ + struct { + GtkWidget *window; + GtkWidget *entry_host; + GtkWidget *entry_port; + GtkAdjustment *adjustment_port; + + char *host; + uint16_t port; + } ask; + + struct { + uint32_t width; + uint32_t height; + GdkGLConfig *config; + } draw; + + struct { + GtkWidget *window; + GtkTextView *textview; + GtkWidget *textview_scrolled; + GtkTreeView *treeview; + GtkTreeStore *treestore; + GtkDrawingArea *draw; + + GtkTreeIter top; + } main; + + struct { + GtkTreeIter iter; + enum types type; + guint64 parent; + guint64 id; + } selected; + + struct { + GtkWidget *back; + GtkWidget *forward; + GtkWidget *background; + GtkWidget *alpha; + GtkWidget *automatic; + + GtkWidget *enable; + GtkWidget *disable; + GtkWidget *save; + GtkWidget *revert; + } tool; + + struct { + gulong id[8]; + + struct shader_action_info *info; + } shader; + + struct { + struct texture_action_read *read; + + /* current texture loaded */ + gboolean alpha; + rbug_texture_t id; + unsigned width; + unsigned height; + + gulong tid[3]; + gboolean automatic; + int back; + + int levels[16]; + } texture; + + struct { + int socket; + struct rbug_connection *con; + GIOChannel *channel; + gint event; + GHashTable *hash; + } rbug; + + struct { + GHashTable *hash; + } icon; +}; + +struct rbug_event +{ + void (*func)(struct rbug_event *, struct rbug_header *, struct program *); +}; + + +/* src/ask.c */ +void ask_window_create(struct program *p); +gboolean ask_connect(struct program *p); + + +/* src/main.c */ +void main_window_create(struct program *p); +void main_quit(struct program *p); +void icon_add(const char *filename, const char *name, struct program *p); +GdkPixbuf* icon_get(const char *name, struct program *p); + + +/* src/rbug.c */ +void rbug_add_event(struct rbug_event *e, uint32_t serial, struct program *p); +void rbug_glib_io_watch(struct program *p); +void rbug_finish_and_emit_events(struct program *p); + + +/* src/context.c */ +void context_list(GtkTreeStore *store, + GtkTreeIter *parent, + struct program *p); + +/* src/texture.c */ +void texture_list(GtkTreeStore *store, GtkTreeIter *parent, struct program *p); +void texture_unselected(struct program *p); +void texture_selected(struct program *p); +void texture_refresh(struct program *p); +void texture_draw(struct program *p); + + +/* src/shader.c */ +void shader_unselected(struct program *p); +void shader_selected(struct program *p); +void shader_list(GtkTreeStore *store, + GtkTreeIter *parent, + rbug_context_t ctx, + struct program *p); + + +/* src/draw.c */ +void draw_setup(GtkDrawingArea *draw, struct program *p); +gboolean draw_gl_begin(struct program *p); +void draw_gl_end(struct program *p); +void draw_checker(guint width, guint height, struct program *p); +void draw_ortho_top_left(struct program *p); + + +#endif diff --git a/src/rbug.c b/src/rbug.c new file mode 100644 index 0000000..27d70d0 --- /dev/null +++ b/src/rbug.c @@ -0,0 +1,119 @@ + +#include "program.h" + +#define SERIAL2KEY(s) ((void*)(unsigned long)s) +#define KEY2SERIAL(k) ((uint32_t)(unsigned long)k) + +static guint hash_func(gconstpointer key) +{ + return KEY2SERIAL(key); +} + +static gboolean equal_func(gconstpointer a, gconstpointer b) +{ + return KEY2SERIAL(a) == KEY2SERIAL(b); +} + +static void rbug_handle_header(struct rbug_header *header, struct program *p) +{ + struct rbug_event *e; + uint32_t serial; + void *ptr; + + g_assert(header->opcode < 0); + serial = *(uint32_t*)&header[1]; + + ptr = g_hash_table_lookup(p->rbug.hash, SERIAL2KEY(serial)); + g_hash_table_remove(p->rbug.hash, SERIAL2KEY(serial)); + + if (!ptr) { + g_print("lost message with id %u\n", serial); + return; + } + + e = (struct rbug_event *)ptr; + e->func(e, header, p); + + rbug_free_header(header); +} + +static gboolean rbug_event(GIOChannel *channel, GIOCondition c, gpointer data) +{ + struct program *p = (struct program *)data; + struct rbug_connection *con = p->rbug.con; + struct rbug_header *header; + (void)channel; + + if (c & (G_IO_IN | G_IO_PRI)) { + header = rbug_get_message(con, NULL); + if (!header) { + main_quit(p); + return false; + } + + rbug_handle_header(header, p); + } + + if (c & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { + main_quit(p); + return false; + } + + return true; +} + +/* + * exported + */ + +void rbug_finish_and_emit_events(struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct rbug_header *header; + uint32_t serial; + + rbug_send_ping(con, &serial); + + do { + header = rbug_get_message(con, NULL); + + if (!header) { + g_print("Connection problems\n"); + break; + } + + if (header->opcode < 0) { + uint32_t s =*(uint32_t*)(&header[1]); + if (s == serial) { + break; + } else if (s > serial) { + g_print("Bad bad bad lost message that we waited for\n"); + break; + } + } + + rbug_handle_header(header, p); + header = NULL; + } while (1); + + if (header && header->opcode != RBUG_OP_PING_REPLY) { + g_print("Bad bad bad reply which we waited for was not ping\n"); + } + + rbug_free_header(header); +} + +void rbug_add_event(struct rbug_event *e, uint32_t serial, struct program *p) +{ + g_hash_table_insert(p->rbug.hash, SERIAL2KEY(serial), e); +} + +void rbug_glib_io_watch(struct program *p) +{ + gint mask = (G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL); + + p->rbug.channel = g_io_channel_unix_new(p->rbug.socket); + p->rbug.event = g_io_add_watch(p->rbug.channel, mask, rbug_event, p); + g_io_channel_set_encoding(p->rbug.channel, NULL, NULL); + p->rbug.hash = g_hash_table_new(hash_func, equal_func); +} diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..88b3ada --- /dev/null +++ b/src/shader.c @@ -0,0 +1,352 @@ + +#include "program.h" + +#include "tgsi/tgsi_text.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_parse.h" + + + +/* + * Actions + */ + + +static struct shader_action_info * +shader_start_info_action(rbug_context_t c, + rbug_shader_t s, + GtkTreeIter *iter, + struct program *p); +static void shader_stop_info_action(struct shader_action_info *info, struct program *p); + +static void shader_start_list_action(GtkTreeStore *store, GtkTreeIter *parent, + rbug_context_t ctx, struct program *p); + + +/* + * Internal + */ + + +static void disable(GtkWidget *widget, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + (void)widget; + + g_assert(p->selected.type == TYPE_SHADER); + + rbug_finish_and_emit_events(p); + rbug_send_shader_disable(con, p->selected.parent, p->selected.id, true, NULL); + rbug_finish_and_emit_events(p); + + gtk_widget_hide(p->tool.disable); + gtk_widget_show(p->tool.enable); + + shader_start_info_action(p->selected.parent, p->selected.id, &p->selected.iter, p); +} + +static void enable(GtkWidget *widget, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + (void)widget; + + g_assert(p->selected.type == TYPE_SHADER); + + rbug_finish_and_emit_events(p); + rbug_send_shader_disable(con, p->selected.parent, p->selected.id, false, NULL); + rbug_finish_and_emit_events(p); + + gtk_widget_show(p->tool.disable); + gtk_widget_hide(p->tool.enable); + + shader_start_info_action(p->selected.parent, p->selected.id, &p->selected.iter, p); +} + +static void update_text(struct rbug_proto_shader_info_reply *info, struct program *p) +{ + GtkTextBuffer *buffer; + gchar text[2048]; + + /* just in case */ + g_assert(sizeof(struct tgsi_token) == 4); + + if (info->replaced_len > 0) + tgsi_dump_str((struct tgsi_token *)info->replaced, 0, text, 2048); + else + tgsi_dump_str((struct tgsi_token *)info->original, 0, text, 2048); + + /* just in case */ + text[2047] = 0; + + buffer = gtk_text_view_get_buffer(p->main.textview); + gtk_text_buffer_set_text(buffer, text, -1); +} + +static void revert(GtkWidget *widget, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + (void)widget; + + g_assert(p->selected.type == TYPE_SHADER); + + rbug_finish_and_emit_events(p); + rbug_send_shader_replace(con, p->selected.parent, p->selected.id, NULL, 0, NULL); + rbug_finish_and_emit_events(p); + + shader_start_info_action(p->selected.parent, p->selected.id, &p->selected.iter, p); +} + +static void save(GtkWidget *widget, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct tgsi_token tokens[300]; + GtkTextBuffer *buffer; + GtkTextIter start; + GtkTextIter end; + gboolean result; + char *text = 0; + unsigned num; + (void)widget; + + g_assert(p->selected.type == TYPE_SHADER); + g_assert(sizeof(struct tgsi_token) == 4); + + rbug_finish_and_emit_events(p); + + buffer = gtk_text_view_get_buffer(p->main.textview); + gtk_text_buffer_get_start_iter(buffer, &start); + gtk_text_buffer_get_end_iter(buffer, &end); + text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); + result = tgsi_text_translate(text, tokens, 300); + + if (!result) { + goto out; + } + + num = tgsi_num_tokens(tokens); + + rbug_send_shader_replace(con, p->selected.parent, p->selected.id, + (uint32_t*)tokens, num, NULL); + + gtk_widget_show(p->tool.revert); + + rbug_finish_and_emit_events(p); + + shader_start_info_action(p->selected.parent, p->selected.id, &p->selected.iter, p); + +out: + g_free(text); +} + +void shader_selected(struct program *p) +{ + g_assert(p->selected.type == TYPE_SHADER); + + p->shader.id[0] = g_signal_connect(p->tool.save, "clicked", G_CALLBACK(save), p); + p->shader.id[1] = g_signal_connect(p->tool.revert, "clicked", G_CALLBACK(revert), p); + p->shader.id[2] = g_signal_connect(p->tool.enable, "clicked", G_CALLBACK(enable), p); + p->shader.id[3] = g_signal_connect(p->tool.disable, "clicked", G_CALLBACK(disable), p); + + gtk_widget_show(GTK_WIDGET(p->main.textview)); + gtk_widget_show(p->main.textview_scrolled); + + if (p->shader.info) + shader_stop_info_action(p->shader.info, p); + + shader_start_info_action(p->selected.parent, p->selected.id, &p->selected.iter, p); +} + +void shader_unselected(struct program *p) +{ + g_signal_handler_disconnect(p->tool.save, p->shader.id[0]); + g_signal_handler_disconnect(p->tool.revert, p->shader.id[1]); + g_signal_handler_disconnect(p->tool.enable, p->shader.id[2]); + g_signal_handler_disconnect(p->tool.disable, p->shader.id[3]); + + gtk_widget_hide(p->tool.enable); + gtk_widget_hide(p->tool.disable); + gtk_widget_hide(p->tool.save); + gtk_widget_hide(p->tool.revert); + gtk_widget_hide(GTK_WIDGET(p->main.textview)); + gtk_widget_hide(p->main.textview_scrolled); +} + +void shader_list(GtkTreeStore *store, GtkTreeIter *parent, + rbug_context_t ctx, struct program *p) +{ + shader_start_list_action(store, parent, ctx, p); +} + + +/* + * Action fuctions + */ + +struct shader_action_info +{ + struct rbug_event e; + + rbug_context_t cid; + rbug_shader_t sid; + + GtkTreeIter iter; + + gboolean running; + gboolean pending; +}; + +static void shader_action_info_clean(struct shader_action_info *action, struct program *p) +{ + if (!action) + return; + + if (p->shader.info == action) + p->shader.info = NULL; + + g_free(action); +} + +static void shader_action_info_info(struct rbug_event *e, + struct rbug_header *header, + struct program *p) +{ + struct rbug_proto_shader_info_reply *info; + struct shader_action_info *action; + GdkPixbuf *buf = NULL; + + info = (struct rbug_proto_shader_info_reply *)header; + action = (struct shader_action_info *)e; + + /* ack pending message */ + action->pending = FALSE; + + if (info->disabled) { + if (info->replaced_len == 0) + buf = icon_get("shader_off_normal", p); + else + buf = icon_get("shader_off_replaced", p); + } else { + if (info->replaced_len == 0) + buf = icon_get("shader_on_normal", p); + else + buf = icon_get("shader_on_replaced", p); + } + gtk_tree_store_set(p->main.treestore, &action->iter, COLUMN_PIXBUF, buf, -1); + + if (p->selected.id != action->sid) + goto out; + + update_text(info, p); + + if (info->disabled) { + gtk_widget_hide(p->tool.disable); + gtk_widget_show(p->tool.enable); + } else { + gtk_widget_show(p->tool.disable); + gtk_widget_hide(p->tool.enable); + } + gtk_widget_show(p->tool.save); + if (info->replaced_len > 0) + gtk_widget_show(p->tool.revert); + +out: + shader_action_info_clean(action, p); +} + +static struct shader_action_info * +shader_start_info_action(rbug_context_t c, + rbug_shader_t s, + GtkTreeIter *iter, + struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct shader_action_info *action; + uint32_t serial = 0; + + action = g_malloc(sizeof(*action)); + memset(action, 0, sizeof(*action)); + + rbug_send_shader_info(con, c, s, &serial); + + action->e.func = shader_action_info_info; + action->cid = c; + action->sid = s; + action->iter = *iter; + action->pending = TRUE; + action->running = TRUE; + + rbug_add_event(&action->e, serial, p); + + return action; +} + +static void shader_stop_info_action(struct shader_action_info *action, struct program *p) +{ + action->running = FALSE; + + if (p->shader.info == action) + p->shader.info = NULL; + + if (!action->pending) + shader_action_info_clean(action, p); +} + +struct shader_action_list +{ + struct rbug_event e; + + rbug_context_t ctx; + + GtkTreeStore *store; + GtkTreeIter parent; +}; + +static void shader_action_list_list(struct rbug_event *e, + struct rbug_header *header, + struct program *p) +{ + + struct rbug_proto_shader_list_reply *list; + struct shader_action_list *action; + GtkTreeStore *store; + GtkTreeIter *parent; + uint32_t i; + + action = (struct shader_action_list *)e; + list = (struct rbug_proto_shader_list_reply *)header; + parent = &action->parent; + store = action->store; + + for (i = 0; i < list->shaders_len; i++) { + GtkTreeIter iter; + gtk_tree_store_insert_with_values(store, &iter, parent, -1, + COLUMN_ID, list->shaders[i], + COLUMN_TYPE, TYPE_SHADER, + COLUMN_TYPENAME, "shader", + -1); + + shader_start_info_action(action->ctx, list->shaders[i], &iter, p); + } + + g_free(action); +} + +static void shader_start_list_action(GtkTreeStore *store, GtkTreeIter *parent, + rbug_context_t ctx, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct shader_action_list *action; + uint32_t serial = 0; + + action = g_malloc(sizeof(*action)); + memset(action, 0, sizeof(*action)); + + rbug_send_shader_list(con, ctx, &serial); + + action->e.func = shader_action_list_list; + action->ctx = ctx; + action->store = store; + action->parent = *parent; + + rbug_add_event(&action->e, serial, p); +} diff --git a/src/texture.c b/src/texture.c new file mode 100644 index 0000000..d9e7237 --- /dev/null +++ b/src/texture.c @@ -0,0 +1,550 @@ + +#include "program.h" + +#include "GL/gl.h" + +#include "pipe/p_format.h" + +/* needed for u_tile */ +#include "pipe/p_state.h" +#include "util/u_tile.h" + +enum { + BACK_MIN = 0, + BACK_CHECKER = 0, + BACK_BLACK, + BACK_WHITE, + BACK_MAX, +}; + + +/* + * Actions + */ + + +static void texture_stop_read_action(struct texture_action_read *action, + struct program *p); +static void texture_start_if_new_read_action(rbug_texture_t t, + GtkTreeIter *iter, + struct program *p); +static struct texture_action_read * +texture_start_read_action(rbug_texture_t t, + GtkTreeIter *iter, + struct program *p); + +static void texture_start_list_action(GtkTreeStore *store, + GtkTreeIter *parent, + struct program *p); + + +/* + * Private + */ + + +static void alpha(GtkWidget *widget, struct program *p) +{ + (void)widget; + + p->texture.alpha = !p->texture.alpha; + + gtk_widget_queue_draw(GTK_WIDGET(p->main.draw)); +} + +static void automatic(GtkWidget *widget, struct program *p) +{ + (void)widget; + + p->texture.automatic = !p->texture.automatic; + + if (p->texture.automatic) + texture_start_if_new_read_action(p->selected.id, &p->selected.iter, p); +} + +static void background(GtkWidget *widget, struct program *p) +{ + (void)widget; + (void)p; + + if (++p->texture.back >= BACK_MAX) + p->texture.back = BACK_MIN; + + gtk_widget_queue_draw(GTK_WIDGET(p->main.draw)); +} + + +/* + * Exported + */ + + +void texture_list(GtkTreeStore *store, GtkTreeIter *parent, struct program *p) +{ + texture_start_list_action(store, parent, p); +} + +void texture_refresh(struct program *p) +{ + texture_start_if_new_read_action(p->selected.id, &p->selected.iter, p); +} + +void texture_draw(struct program *p) +{ + uint32_t w, h; + + draw_ortho_top_left(p); + + switch (p->texture.back) { + case BACK_CHECKER: + draw_checker(60, 60, p); + break; + case BACK_BLACK: + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + break; + case BACK_WHITE: + glClearColor(1.0, 1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + break; + default: + break; + } + + if (p->texture.id != p->selected.id) + return; + + w = p->texture.width; + h = p->texture.height; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if (p->texture.alpha) + glEnable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + + glColor3f(1.0, 1.0, 1.0); + glBegin(GL_QUADS); + glTexCoord2f( 0, 1); + glVertex2f (10 , 10 + h); + glTexCoord2f( 1, 1); + glVertex2f (10 + w, 10 + h); + glTexCoord2f( 1, 0); + glVertex2f (10 + w, 10 ); + glTexCoord2f( 0, 0); + glVertex2f (10 , 10 ); + glEnd(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + if (p->texture.automatic) + texture_start_if_new_read_action(p->selected.id, &p->selected.iter, p); +} + +void texture_unselected(struct program *p) +{ + (void)p; + + gtk_widget_hide(p->tool.alpha); + gtk_widget_hide(p->tool.automatic); + gtk_widget_hide(p->tool.background); + gtk_widget_hide(GTK_WIDGET(p->main.draw)); + + p->texture.alpha = TRUE; + p->texture.automatic = FALSE; + p->texture.back = BACK_CHECKER; + + g_signal_handler_disconnect(p->tool.alpha, p->texture.tid[0]); + g_signal_handler_disconnect(p->tool.automatic, p->texture.tid[1]); + g_signal_handler_disconnect(p->tool.background, p->texture.tid[2]); +} + +void texture_selected(struct program *p) +{ + g_assert(p->selected.type == TYPE_TEXTURE); + + texture_start_if_new_read_action(p->selected.id, &p->selected.iter, p); + + gtk_widget_show(p->tool.alpha); + gtk_widget_show(p->tool.automatic); + gtk_widget_show(p->tool.background); + gtk_widget_show(GTK_WIDGET(p->main.draw)); + + p->texture.alpha = TRUE; + p->texture.automatic = FALSE; + p->texture.back = BACK_CHECKER; + + p->texture.tid[0] = g_signal_connect(p->tool.alpha, "clicked", G_CALLBACK(alpha), p); + p->texture.tid[1] = g_signal_connect(p->tool.automatic, "clicked", G_CALLBACK(automatic), p); + p->texture.tid[2] = g_signal_connect(p->tool.background, "clicked", G_CALLBACK(background), p); +} + +/* + * Actions + */ + +struct texture_action_read +{ + struct rbug_event e; + + rbug_texture_t id; + + GtkTreeIter iter; + + gboolean running; + gboolean pending; + + unsigned width; + unsigned height; + unsigned stride; + enum pipe_format format; + struct pipe_format_block block; + void *data; +}; + +static void texture_action_read_clean(struct texture_action_read *action, + struct program *p) +{ + if (!action) + return; + + if (p->texture.read == action) + p->texture.read = NULL; + + g_free(action->data); + g_free(action); +} + +static void texture_action_read_upload(struct texture_action_read *action, + struct program *p) +{ +#if 0 + GLint format, internal_format, type; + unsigned needed_stride; + uint32_t w, h, i; + + if (!action) + return; + + w = action->width; + h = action->height; + + if (action->block.size != 4) + return; + + if (pf_has_alpha(action->format)) { + internal_format = 4; + format = GL_BGRA; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + } else { + internal_format = 3; + format = GL_BGR; + type = GL_UNSIGNED_INT_8_8_8_8_REV; + } + + needed_stride = pf_get_nblocksx(&action->block, w) * action->block.size; + + if (action->stride % action->block.size) + g_print("warning stride not mupltiple of block.size\n"); + if (w % action->block.width) + g_print("warning width not multiple of block.width\n"); + if (h % action->block.height) + g_print("warning height not multiple of block.height\n"); + + /* bad stride */ + if (action->stride > needed_stride) { + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, + w, h, 0, + format, type, NULL); + + for (i = 0; i < h; i += action->block.height) { + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, i, w, action->block.height, + format, type, action->data + action->stride * i); + } + } else if (action->stride == needed_stride) { + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, + w, h, 0, + format, type, action->data); + } else { + g_assert(0); + } +#endif + GLint format, internal_format, type; + uint32_t w, h, step_h, i; + uint32_t dst_stride, src_stride; + float *rgba; + void *data; + + if (!action) + return; + + data = action->data; + w = action->width; + h = action->height; + step_h = action->block.height; + src_stride = action->stride; + dst_stride = 4 * 4 * w; + rgba = g_malloc(dst_stride * h); + + for (i = 0; i < h; i += step_h) { + pipe_tile_raw_to_rgba(action->format, data + src_stride * i, + w, step_h, + &rgba[w * 4 * i], dst_stride); + } + + internal_format = 4; + format = GL_RGBA; + type = GL_FLOAT; + + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, + w, h, 0, + format, type, rgba); + + g_free(rgba); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + p->texture.id = action->id; + p->texture.width = action->width; + p->texture.height = action->height; +} + +static void texture_action_read_read(struct rbug_event *e, + struct rbug_header *header, + struct program *p) +{ + struct rbug_proto_texture_read_reply *read; + struct texture_action_read *action; + size_t size; + + read = (struct rbug_proto_texture_read_reply *)header; + action = (struct texture_action_read *)e; + + /* ack pending message */ + action->pending = FALSE; + + if (header->opcode != RBUG_OP_TEXTURE_READ_REPLY) { + g_print("warning failed to read from texture\n"); + goto error; + } + + /* no longer interested in this action */ + if (!action->running) + goto error; + + /* calculate needed size */ + size = pf_get_nblocksy(&action->block, action->height) * read->stride; + + if (read->data_len < size) + goto error; + + action->stride = read->stride; + action->data = g_malloc(size); + memcpy(action->data, read->data, size); + + if (draw_gl_begin(p)) { + texture_action_read_upload(action, p); + draw_gl_end(p); + gtk_widget_queue_draw(GTK_WIDGET(p->main.draw)); + + texture_action_read_clean(action, p); + } else { + g_assert(0); + texture_action_read_clean(action, p); + } + + return; + +error: + texture_stop_read_action(action, p); +} + +static void texture_action_read_info(struct rbug_event *e, + struct rbug_header *header, + struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct rbug_proto_texture_info_reply *info; + struct texture_action_read *action; + uint32_t serial = 0; + + info = (struct rbug_proto_texture_info_reply *)header; + action = (struct texture_action_read *)e; + + /* ack pending message */ + action->pending = FALSE; + + if (header->opcode != RBUG_OP_TEXTURE_INFO_REPLY) { + g_print("warning failed to get info from texture\n"); + goto error; + } + + if (pf_layout(info->format) == PIPE_FORMAT_LAYOUT_RGBAZS) { + GdkPixbuf *buf = NULL; + + int swz = (info->format >> 2) & 0xFFF; + if (!swz) + ; + else if (swz == _PIPE_FORMAT_RGBA) + buf = icon_get("rgba", p); + else if (swz == _PIPE_FORMAT_RGB1) + buf = icon_get("rgbx", p); + else if (swz == _PIPE_FORMAT_ARGB) + buf = icon_get("argb", p); + else if (swz == _PIPE_FORMAT_1RGB) + buf = icon_get("xrgb", p); + else if (swz == _PIPE_FORMAT_000R) + buf = icon_get("rgba", p); + + else if (swz == _PIPE_FORMAT_SZ00) + buf = icon_get("s8z24", p); + else if (swz == _PIPE_FORMAT_0Z00) + buf = icon_get("x8z24", p); + else if (swz == _PIPE_FORMAT_ZS00) + buf = icon_get("z24s8", p); + else if (swz == _PIPE_FORMAT_Z000) + buf = icon_get("z24x8", p); + + gtk_tree_store_set(p->main.treestore, &action->iter, COLUMN_PIXBUF, buf, -1); + } + + /* no longer interested in this action */ + if (!action->running || p->texture.read != action) + goto error; + + action->width = info->width[0]; + action->height = info->height[0]; + action->block.width = info->blockw; + action->block.height = info->blockh; + action->block.size = info->blocksize; + action->format = info->format; + + rbug_send_texture_read(con, action->id, + 0, 0, 0, + 0, 0, action->width, action->height, + &serial); + /* new message pending */ + action->pending = TRUE; + + /* hock up event callback */ + action->e.func = texture_action_read_read; + rbug_add_event(&action->e, serial, p); + + return; + +error: + texture_stop_read_action(action, p); +} + +static void texture_stop_read_action(struct texture_action_read *action, struct program *p) +{ + if (p->texture.read == action) + p->texture.read = NULL; + + action->running = FALSE; + + /* no actions pending that will call into this action clean it */ + if (!action->pending) + texture_action_read_clean(action, p); +} + +static void texture_start_if_new_read_action(rbug_texture_t t, + GtkTreeIter *iter, + struct program *p) +{ + /* are we currently trying download anything? */ + if (p->texture.read) { + /* ok we are downloading something, but is it the one we want? */ + if (p->texture.read->id == p->selected.id) { + /* don't need to do anything */ + return; + } else { + texture_stop_read_action(p->texture.read, p); + } + } + + p->texture.read = texture_start_read_action(t, iter, p); +} + +static struct texture_action_read * +texture_start_read_action(rbug_texture_t t, GtkTreeIter *iter, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct texture_action_read *action; + uint32_t serial = 0; + + action = g_malloc(sizeof(*action)); + memset(action, 0, sizeof(*action)); + + rbug_send_texture_info(con, t, &serial); + + action->e.func = texture_action_read_info; + action->id = t; + action->iter = *iter; + action->pending = TRUE; + action->running = TRUE; + + rbug_add_event(&action->e, serial, p); + + return action; +} + +struct texture_action_list +{ + struct rbug_event e; + + GtkTreeStore *store; + GtkTreeIter parent; +}; + +static void texture_action_list_list(struct rbug_event *e, + struct rbug_header *header, + struct program *p) +{ + + struct rbug_proto_texture_list_reply *list; + struct texture_action_list *action; + GtkTreeStore *store; + GtkTreeIter *parent; + uint32_t i; + + action = (struct texture_action_list *)e; + list = (struct rbug_proto_texture_list_reply *)header; + parent = &action->parent; + store = action->store; + + for (i = 0; i < list->textures_len; i++) { + GtkTreeIter iter; + gtk_tree_store_insert_with_values(store, &iter, parent, -1, + COLUMN_ID, list->textures[i], + COLUMN_TYPE, TYPE_TEXTURE, + COLUMN_TYPENAME, "texture", + -1); + + texture_start_read_action(list->textures[i], &iter, p); + } + + g_free(action); +} + +static void texture_start_list_action(GtkTreeStore *store, GtkTreeIter *parent, struct program *p) +{ + struct rbug_connection *con = p->rbug.con; + struct texture_action_list *action; + uint32_t serial = 0; + + action = g_malloc(sizeof(*action)); + memset(action, 0, sizeof(*action)); + + rbug_send_texture_list(con, &serial); + + action->e.func = texture_action_list_list; + action->store = store; + action->parent = *parent; + + rbug_add_event(&action->e, serial, p); +} -- cgit v1.2.3