[GTK3] Improve VRAM viewer performance

– Fixed `g_idle_add`ed functions not returning `false` to signal that they are done and don’t want to get called again automatically
– Fixed memory leaks: `gtk_list_store_insert_with_values` *copies* string arguments and doesn’t take ownership
– Monospaced numeric values in the status bar and palette viewer
This commit is contained in:
Maximilian Mader 2020-05-17 22:51:27 +02:00
parent 825786210a
commit f74b1cd3d9
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
4 changed files with 170 additions and 96 deletions

View File

@ -354,10 +354,12 @@ static void rumble_callback(GB_gameboy_t *gb, double amp) {
}
}
static void clear_sidebar(void) {
static gboolean clear_sidebar(void) {
GtkTextView *sidebar_output = builder_get(GTK_TEXT_VIEW, "console_sidebar_output");
GtkTextBuffer *sidebar_output_text_buf = gtk_text_view_get_buffer(sidebar_output);
gtk_text_buffer_set_text(sidebar_output_text_buf, "", -1);
return false;
}
static gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark) {
@ -375,7 +377,7 @@ static gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark) {
return true;
}
static void append_pending_output(void) {
static gboolean append_pending_output(void) {
g_rec_mutex_lock(&gui_data.console_output_lock);
if (gui_data.should_clear_sidebar) {
@ -401,16 +403,18 @@ static void append_pending_output(void) {
}
g_rec_mutex_unlock(&gui_data.console_output_lock);
return false;
}
static void update_debugger_sidebar(GB_gameboy_t *gb) {
static gboolean update_debugger_sidebar(GB_gameboy_t *gb) {
if (!GB_debugger_is_stopped(gb)) {
return;
return false;
}
if (gui_data.main_thread != g_thread_self()) {
g_idle_add((GSourceFunc) update_debugger_sidebar, gb);
return;
return false;
}
g_rec_mutex_lock(&gui_data.console_output_lock);
@ -459,6 +463,8 @@ static void update_debugger_sidebar(GB_gameboy_t *gb) {
append_pending_output();
gui_data.log_to_sidebar = false;
g_rec_mutex_unlock(&gui_data.console_output_lock);
return false;
}
static void console_log(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes) {
@ -781,7 +787,7 @@ static void stop(void) {
gui_data.stopped = true;
}
static void on_vblank(GB_gameboy_t *gb) {
static gboolean on_vblank(GB_gameboy_t *gb) {
// Queue drawing of the current frame
if (gui_data.fallback_canvas) {
gtk_widget_queue_draw(GTK_WIDGET(gui_data.main_window));
@ -791,6 +797,8 @@ static void on_vblank(GB_gameboy_t *gb) {
}
gtk_widget_queue_draw(GTK_WIDGET(gui_data.vram_viewer));
return false;
}
static void vblank(GB_gameboy_t *gb) {

View File

@ -43,3 +43,6 @@
border-bottom: 1px solid #3d4548;
}
.monospace {
font-family: monospace;
}

View File

@ -49,6 +49,8 @@ Author: Maximilian Mader
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="stack">stack</property>
</object>
<packing>
@ -65,7 +67,7 @@ Author: Maximilian Mader
<property name="vhomogeneous">False</property>
<property name="transition_type">slide-left-right</property>
<property name="interpolate_size">True</property>
<signal name="notify::visible-child" handler="visible_tab_changed"/>
<signal name="notify::visible-child" handler="visible_tab_changed" swapped="no"/>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@ -75,8 +77,8 @@ Author: Maximilian Mader
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_start">6</property>
<property name="margin_end">6</property>
<property name="margin_bottom">3</property>
<child>
<object class="GtkComboBoxText" id="tileset_palette_selector">
@ -142,8 +144,8 @@ Author: Maximilian Mader
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<signal name="draw" handler="draw_tileset_canvas"/>
<signal name="motion_notify_event" handler="tileset_canvas_motion"/>
<signal name="draw" handler="draw_tileset_canvas" swapped="no"/>
<signal name="motion-notify-event" handler="tileset_canvas_motion" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
@ -166,8 +168,8 @@ Author: Maximilian Mader
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_start">6</property>
<property name="margin_end">6</property>
<property name="spacing">3</property>
<child>
<object class="GtkComboBoxText" id="tilemap_palette_selector">
@ -228,7 +230,7 @@ Author: Maximilian Mader
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">2</property>
<property name="margin_start">2</property>
</object>
<packing>
<property name="expand">False</property>
@ -243,8 +245,8 @@ Author: Maximilian Mader
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="margin_start">2</property>
<property name="margin_end">2</property>
</object>
<packing>
<property name="expand">False</property>
@ -293,8 +295,8 @@ Author: Maximilian Mader
<property name="valign">start</property>
<property name="hexpand">False</property>
<property name="vexpand">False</property>
<signal name="draw" handler="draw_tilemap_canvas"/>
<signal name="motion_notify_event" handler="tilemap_canvas_motion"/>
<signal name="draw" handler="draw_tilemap_canvas" swapped="no"/>
<signal name="motion-notify-event" handler="tilemap_canvas_motion" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
@ -420,6 +422,9 @@ Author: Maximilian Mader
<property name="headers_clickable">False</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<style>
<class name="monospace"/>
</style>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
@ -437,6 +442,7 @@ Author: Maximilian Mader
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Color 0</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="palette_cell_renderer_0"/>
<attributes>
@ -448,6 +454,7 @@ Author: Maximilian Mader
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Color 1</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="palette_cell_renderer_1"/>
<attributes>
@ -459,6 +466,7 @@ Author: Maximilian Mader
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Color 2</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="palette_cell_renderer_2"/>
<attributes>
@ -470,6 +478,7 @@ Author: Maximilian Mader
<child>
<object class="GtkTreeViewColumn">
<property name="title" translatable="yes">Color 3</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="palette_cell_renderer_3"/>
<attributes>

View File

@ -188,7 +188,19 @@ static gboolean tileset_canvas_motion(GtkWidget *widget, GdkEventMotion *event,
x &= 127;
uint16_t tile = x / 8 + y / 8 * 16;
gtk_label_set_text(window->status, g_strdup_printf("Tile number $%02x at %d:$%04x", tile & 0xFF, bank, 0x8000 + tile * 0x10));
const char *format =
"Tile number"
" <span font_family=\"monospace\">$%02x</span>"
" at"
" <span font_family=\"monospace\">%d:$%04x</span>";
g_autofree char *markup = g_markup_printf_escaped(
format,
tile & 0xFF,
bank, 0x8000 + tile * 0x10
);
gtk_label_set_markup(window->status, markup);
return true;
}
@ -213,8 +225,6 @@ static gboolean tilemap_canvas_motion(GtkWidget *widget, GdkEventMotion *event,
x /= 2;
y /= 2;
GtkLabel *status = window->status;
uint16_t map_offset = x / 8 + y / 8 * 32;
uint16_t map_base = 0x1800;
@ -249,7 +259,17 @@ static gboolean tilemap_canvas_motion(GtkWidget *widget, GdkEventMotion *event,
if (window->is_cgb) {
uint8_t attributes = window->gb_vram[map_base + map_offset + 0x2000];
gtk_label_set_text(status, g_strdup_printf("Tile number $%02x (%d:$%04x) at map address $%04x (Attributes: %c%c%c%d%d)",
const char *format =
"Tile number"
" <span font_family=\"monospace\">$%02x</span>"
" <span font_family=\"monospace\">(%d:$%04x)</span>"
" at map address"
" <span font_family=\"monospace\">$%04x</span>"
" (Attributes: <span font_family=\"monospace\">%c%c%c%d%d</span>)";
g_autofree char *markup = g_markup_printf_escaped(
format,
tile,
attributes & 0x8? 1 : 0,
tile_address,
@ -259,14 +279,25 @@ static gboolean tilemap_canvas_motion(GtkWidget *widget, GdkEventMotion *event,
(attributes & 0x20) ? 'H' : '-',
attributes & 0x8? 1 : 0,
attributes & 0x7
));
);
gtk_label_set_markup(window->status, markup);
}
else {
gtk_label_set_text(status, g_strdup_printf("Tile number $%02x ($%04x) at map address $%04x",
const char *format =
"Tile number"
" <span font_family=\"monospace\">$%02x ($%04x)</span>"
" at map address"
" <span font_family=\"monospace\">$%04x</span>";
g_autofree char *markup = g_markup_printf_escaped(
format,
tile,
tile_address,
0x8000 + map_base + map_offset
));
);
gtk_label_set_markup(window->status, markup);
}
return true;
@ -338,30 +369,40 @@ const gchar *vram_viewer_get_tileset_type_id(VramViewerWindow *window) {
return gtk_combo_box_get_active_id(GTK_COMBO_BOX(window->tilemap_tileset_selector));
}
static void update_sprite_list(VramViewerWindow *window) {
static gboolean update_sprite_list(VramViewerWindow *window) {
GtkTreeIter iter;
GtkTreeModel *model = gtk_tree_view_get_model(window->sprites);
GtkListStore *store;
GtkListStore *store = gtk_list_store_new(7,
GDK_TYPE_PIXBUF, // Preview image
G_TYPE_STRING, // X position
G_TYPE_STRING, // Y position
G_TYPE_STRING, // Tile
G_TYPE_STRING, // Tile Address
G_TYPE_STRING, // OAM Address
G_TYPE_STRING // Attributes
);
if (!model) {
g_autoptr(GtkListStore) new_store = gtk_list_store_new(7,
GDK_TYPE_PIXBUF, // Preview image
G_TYPE_STRING, // X position
G_TYPE_STRING, // Y position
G_TYPE_STRING, // Tile
G_TYPE_STRING, // Tile Address
G_TYPE_STRING, // OAM Address
G_TYPE_STRING // Attributes
);
gtk_tree_view_set_model(window->sprites, GTK_TREE_MODEL(new_store));
store = new_store;
}
else {
store = GTK_LIST_STORE(model);
gtk_list_store_clear(store);
}
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
GB_oam_info_t *oam_info = window->oam_info;
for (unsigned row = 0; row < window->oam_count; ++row) {
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_bytes(
g_bytes_new(oam_info[row].image, 128 * sizeof(uint32_t)),
g_autoptr(GBytes) bytes = g_bytes_new(window->oam_info[row].image, 128 * sizeof(uint32_t));
g_autoptr(GdkPixbuf) pixbuf = gdk_pixbuf_new_from_bytes(
bytes,
GDK_COLORSPACE_RGB, true, 8, 8, window->oam_height, 8 * sizeof(uint32_t)
);
GdkPixbuf *dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, 8 * 2, window->oam_height * 2);
g_autoptr(GdkPixbuf) dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, 8 * 2, window->oam_height * 2);
gdk_pixbuf_scale(pixbuf, dest,
0, 0, 8 * 2, window->oam_height * 2,
@ -369,34 +410,37 @@ static void update_sprite_list(VramViewerWindow *window) {
GDK_INTERP_NEAREST
);
g_autofree gchar *str_1 = g_strdup_printf("%i", window->oam_info[row].x - 8);
g_autofree gchar *str_2 = g_strdup_printf("%i", window->oam_info[row].y - 16);
g_autofree gchar *str_3 = g_strdup_printf("$%02x", window->oam_info[row].tile);
g_autofree gchar *str_4 = g_strdup_printf("$%04x", 0x8000 + window->oam_info[row].tile * 0x10);
g_autofree gchar *str_5 = g_strdup_printf("$%04x", window->oam_info[row].oam_addr);
g_autofree gchar *str_6 = window->is_cgb
? g_strdup_printf("%c%c%c%d%d",
window->oam_info[row].flags & 0x80? 'P' : '-',
window->oam_info[row].flags & 0x40? 'Y' : '-',
window->oam_info[row].flags & 0x20? 'X' : '-',
window->oam_info[row].flags & 0x08? 1 : 0,
window->oam_info[row].flags & 0x07)
: g_strdup_printf("%c%c%c%d",
window->oam_info[row].flags & 0x80? 'P' : '-',
window->oam_info[row].flags & 0x40? 'Y' : '-',
window->oam_info[row].flags & 0x20? 'X' : '-',
window->oam_info[row].flags & 0x10? 1 : 0);
gtk_list_store_insert_with_values(store, &iter, -1,
0, dest,
1, g_strdup_printf("%i", oam_info[row].x - 8),
2, g_strdup_printf("%i", oam_info[row].y - 16),
3, g_strdup_printf("$%02x", oam_info[row].tile),
4, g_strdup_printf("$%04x", 0x8000 + oam_info[row].tile * 0x10),
5, g_strdup_printf("$%04x", oam_info[row].oam_addr),
6, window->is_cgb
? g_strdup_printf("%c%c%c%d%d",
oam_info[row].flags & 0x80? 'P' : '-',
oam_info[row].flags & 0x40? 'Y' : '-',
oam_info[row].flags & 0x20? 'X' : '-',
oam_info[row].flags & 0x08? 1 : 0,
oam_info[row].flags & 0x07)
: g_strdup_printf("%c%c%c%d",
oam_info[row].flags & 0x80? 'P' : '-',
oam_info[row].flags & 0x40? 'Y' : '-',
oam_info[row].flags & 0x20? 'X' : '-',
oam_info[row].flags & 0x10? 1 : 0),
1, str_1,
2, str_2,
3, str_3,
4, str_4,
5, str_5,
6, str_6,
-1
);
g_object_unref(pixbuf);
g_object_unref(dest);
}
gtk_tree_view_set_model(window->sprites, GTK_TREE_MODEL(store));
g_object_unref(store);
return false;
}
static void palette_color_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data_ptr) {
@ -427,24 +471,44 @@ static void palette_color_data_func(GtkTreeViewColumn *col, GtkCellRenderer *ren
g_free(color_string);
}
static void update_palettes(VramViewerWindow *window) {
static gboolean update_palettes(VramViewerWindow *window) {
GtkTreeIter iter;
GtkTreeModel *model = gtk_tree_view_get_model(window->palettes);
GtkListStore *store;
GtkListStore *store = gtk_list_store_new(9,
G_TYPE_STRING, // Name
if (!model) {
g_autoptr(GtkListStore) new_store = gtk_list_store_new(9,
G_TYPE_STRING, // Name
G_TYPE_STRING, // Color 0 string
G_TYPE_INT, // Color 0 integer
G_TYPE_STRING, // Color 0 string
G_TYPE_INT, // Color 0 integer
G_TYPE_STRING, // Color 1 string
G_TYPE_INT, // Color 1 integer
G_TYPE_STRING, // Color 1 string
G_TYPE_INT, // Color 1 integer
G_TYPE_STRING, // Color 2 string
G_TYPE_INT, // Color 2 integer
G_TYPE_STRING, // Color 2 string
G_TYPE_INT, // Color 2 integer
G_TYPE_STRING, // Color 3 string
G_TYPE_INT // Color 3 integer
);
G_TYPE_STRING, // Color 3 string
G_TYPE_INT // Color 3 integer
);
gtk_tree_view_set_model(window->palettes, GTK_TREE_MODEL(new_store));
store = new_store;
GtkTreeViewColumn *column_0 = gtk_tree_view_get_column(window->palettes, 1);
GtkTreeViewColumn *column_1 = gtk_tree_view_get_column(window->palettes, 2);
GtkTreeViewColumn *column_2 = gtk_tree_view_get_column(window->palettes, 3);
GtkTreeViewColumn *column_3 = gtk_tree_view_get_column(window->palettes, 4);
gtk_tree_view_column_set_cell_data_func(column_0, GTK_CELL_RENDERER(window->palette_cell_renderer_0), palette_color_data_func, NULL, NULL);
gtk_tree_view_column_set_cell_data_func(column_1, GTK_CELL_RENDERER(window->palette_cell_renderer_1), palette_color_data_func, NULL, NULL);
gtk_tree_view_column_set_cell_data_func(column_2, GTK_CELL_RENDERER(window->palette_cell_renderer_2), palette_color_data_func, NULL, NULL);
gtk_tree_view_column_set_cell_data_func(column_3, GTK_CELL_RENDERER(window->palette_cell_renderer_3), palette_color_data_func, NULL, NULL);
}
else {
store = GTK_LIST_STORE(model);
gtk_list_store_clear(store);
}
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
@ -456,37 +520,27 @@ static void update_palettes(VramViewerWindow *window) {
uint16_t color_2 = (window->palette_data[row][((2 + offset) << 1) + 1] << 8) | window->palette_data[row][((2 + offset) << 1)];
uint16_t color_3 = (window->palette_data[row][((3 + offset) << 1) + 1] << 8) | window->palette_data[row][((3 + offset) << 1)];
g_autofree gchar *str_0 = g_strdup_printf("%s %d", row >=8 ? "Object" : "Background", row & 7);
g_autofree gchar *str_1 = g_strdup_printf("$%04x", color_0 & 0x7FFF);
g_autofree gchar *str_3 = g_strdup_printf("$%04x", color_1 & 0x7FFF);
g_autofree gchar *str_5 = g_strdup_printf("$%04x", color_2 & 0x7FFF);
g_autofree gchar *str_7 = g_strdup_printf("$%04x", color_3 & 0x7FFF);
gtk_list_store_insert_with_values(store, &iter, -1,
0, g_strdup_printf("%s %d", row >=8 ? "Object" : "Background", row & 7),
1, g_strdup_printf("$%04x", color_0 & 0x7FFF),
0, str_0,
1, str_1,
2, convert_color(color_0),
3, g_strdup_printf("$%04x", color_1 & 0x7FFF),
3, str_3,
4, convert_color(color_1),
5, g_strdup_printf("$%04x", color_2 & 0x7FFF),
5, str_5,
6, convert_color(color_2),
7, g_strdup_printf("$%04x", color_3 & 0x7FFF),
7, str_7,
8, convert_color(color_3),
-1
);
}
GtkTreeViewColumn *column_0 = gtk_tree_view_get_column(window->palettes, 1);
GtkTreeViewColumn *column_1 = gtk_tree_view_get_column(window->palettes, 2);
GtkTreeViewColumn *column_2 = gtk_tree_view_get_column(window->palettes, 3);
GtkTreeViewColumn *column_3 = gtk_tree_view_get_column(window->palettes, 4);
GtkCellRendererText *cell_renderer_0 = window->palette_cell_renderer_0;
GtkCellRendererText *cell_renderer_1 = window->palette_cell_renderer_1;
GtkCellRendererText *cell_renderer_2 = window->palette_cell_renderer_2;
GtkCellRendererText *cell_renderer_3 = window->palette_cell_renderer_3;
gtk_tree_view_column_set_cell_data_func(column_0, GTK_CELL_RENDERER(cell_renderer_0), palette_color_data_func, NULL, NULL);
gtk_tree_view_column_set_cell_data_func(column_1, GTK_CELL_RENDERER(cell_renderer_1), palette_color_data_func, NULL, NULL);
gtk_tree_view_column_set_cell_data_func(column_2, GTK_CELL_RENDERER(cell_renderer_2), palette_color_data_func, NULL, NULL);
gtk_tree_view_column_set_cell_data_func(column_3, GTK_CELL_RENDERER(cell_renderer_3), palette_color_data_func, NULL, NULL);
gtk_tree_view_set_model(window->palettes, GTK_TREE_MODEL(store));
g_object_unref(store);
return false;
}
void vram_viewer_update(VramViewerWindow *window, GB_gameboy_t *gb) {