From e4a6101ae067a1b0e6577e12a4c5bebc20e64a88 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 8 Apr 2021 23:09:14 -0400 Subject: gtk-demo: Make one text scroll benchmark harder Add underlines into the mix with the Emoji heavy text, to see if we can optimize lines. --- demos/gtk-demo/iconscroll.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/demos/gtk-demo/iconscroll.c b/demos/gtk-demo/iconscroll.c index 2eb9aa6e92..8212818516 100644 --- a/demos/gtk-demo/iconscroll.c +++ b/demos/gtk-demo/iconscroll.c @@ -116,20 +116,25 @@ populate_emoji_text (void) GtkWidget *textview; GtkTextBuffer *buffer; GString *s; + GtkTextIter iter; - s = g_string_sized_new (1000 * 30 * 4); + s = g_string_sized_new (500 * 30 * 4); - for (int i = 0; i < 1000; i++) + for (int i = 0; i < 500; i++) { if (i % 2) - g_string_append (s, "x"); + g_string_append (s, "x"); for (int j = 0; j < 30; j++) - g_string_append (s, "💓x"); + { + g_string_append (s, "💓"); + g_string_append (s, "x"); + } g_string_append (s, "\n"); } buffer = gtk_text_buffer_new (NULL); - gtk_text_buffer_set_text (buffer, s->str, s->len); + gtk_text_buffer_get_start_iter (buffer, &iter); + gtk_text_buffer_insert_markup (buffer, &iter, s->str, s->len); g_string_free (s, TRUE); -- cgit v1.2.1 From e7963945bbb096f7ac5cbd3665d75e7cfc465b7d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 8 Apr 2021 23:10:10 -0400 Subject: ngl: Fix an oversight All the rest of debug spew goes to stderr here. --- gsk/ngl/gsknglcommandqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index bdfef2f35c..4ce1628e2f 100644 --- a/gsk/ngl/gsknglcommandqueue.c +++ b/gsk/ngl/gsknglcommandqueue.c @@ -169,7 +169,7 @@ gsk_ngl_command_queue_print_batch (GskNglCommandQueue *self, for (guint i = 0; i < batch->draw.bind_count; i++) { const GskNglCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset + i]; - g_print (" Bind[%d]: %u\n", bind->texture, bind->id); + g_printerr (" Bind[%d]: %u\n", bind->texture, bind->id); } for (guint i = 0; i < batch->draw.uniform_count; i++) -- cgit v1.2.1 From d8ba4b4114b523ca86676692731b5f9247b8596f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 8 Apr 2021 22:28:40 -0400 Subject: ngl: Reserve a pixel in texture atlases This will be used for coloring from the texture. --- gsk/ngl/gskngltexturelibrary.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/gsk/ngl/gskngltexturelibrary.c b/gsk/ngl/gskngltexturelibrary.c index 85449b3fa2..2de6e492c5 100644 --- a/gsk/ngl/gskngltexturelibrary.c +++ b/gsk/ngl/gskngltexturelibrary.c @@ -20,6 +20,7 @@ #include "config.h" +#include #include #include "gsknglcommandqueueprivate.h" @@ -239,6 +240,51 @@ gsk_ngl_texture_atlas_pack (GskNglTextureAtlas *self, return rect.was_packed; } +static void +gsk_ngl_texture_atlas_initialize (GskNglDriver *driver, + GskNglTextureAtlas *atlas) +{ + /* Insert a single pixel at 0,0 for use in coloring */ + + gboolean packed; + int x, y; + guint gl_format; + guint gl_type; + guint8 pixel_data[4 * 3 * 3]; + + gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), + "Initializing Atlas"); + + packed = gsk_ngl_texture_atlas_pack (atlas, 3, 3, &x, &y); + g_assert (packed); + g_assert (x == 0 && y == 0); + + memset (pixel_data, 255, sizeof pixel_data); + + if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) + { + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + } + else + { + gl_format = GL_BGRA; + gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; + } + + glBindTexture (GL_TEXTURE_2D, atlas->texture_id); + + glTexSubImage2D (GL_TEXTURE_2D, 0, + 0, 0, + 3, 3, + gl_format, gl_type, + pixel_data); + + gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); + + driver->command_queue->n_uploads++; +} + static void gsk_ngl_texture_atlases_pack (GskNglDriver *driver, int width, @@ -265,6 +311,8 @@ gsk_ngl_texture_atlases_pack (GskNglDriver *driver, /* No atlas has enough space, so create a new one... */ atlas = gsk_ngl_driver_create_atlas (driver); + gsk_ngl_texture_atlas_initialize (driver, atlas); + /* Pack it onto that one, which surely has enough space... */ if (!gsk_ngl_texture_atlas_pack (atlas, width, height, &x, &y)) g_assert_not_reached (); -- cgit v1.2.1 From 0caa28c1dee734fc42411f61d96171d2621b9062 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 8 Apr 2021 23:11:06 -0400 Subject: ngl: Optimize underlines in text Opportunistically use the coloring program for drawing underlines instead of the color program. This avoids program changes in the middle of text. For the Emoji text scrolling benchmark, this reduces the program changes per frame from > 1000 to around 100. --- gsk/ngl/gsknglrenderjob.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index b1bda44790..69c92ac80f 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -1360,16 +1360,54 @@ blur_node (GskNglRenderJob *job, *max_y = job->offset_y + node->bounds.origin.y + node->bounds.size.height + half_blur_extra; } +#define ATLAS_SIZE 512 + static inline void gsk_ngl_render_job_visit_color_node (GskNglRenderJob *job, const GskRenderNode *node) { guint16 color[4]; + GskNglProgram *program; + GskNglCommandBatch *batch; rgba_to_half (gsk_color_node_get_color (node), color); - gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color)); - gsk_ngl_render_job_draw_rect_with_color (job, &node->bounds, color); - gsk_ngl_render_job_end_draw (job); + + /* Avoid switching away from the coloring program for + * rendering a solid color. + */ + program = CHOOSE_PROGRAM (job, coloring); + batch = gsk_ngl_command_queue_get_batch (job->command_queue); + + if (batch->any.kind == GSK_NGL_COMMAND_KIND_DRAW && + batch->any.program == program->id) + { + GskNglRenderOffscreen offscreen = {0}; + + gsk_ngl_render_job_begin_draw (job, program); + + /* The top left few pixels in our atlases are always + * solid white, so we can use it here, without + * having to choose any particular atlas texture. + */ + offscreen.was_offscreen = FALSE; + offscreen.area.x = 1.f / ATLAS_SIZE; + offscreen.area.y = 1.f / ATLAS_SIZE; + offscreen.area.x2 = 2.f / ATLAS_SIZE; + offscreen.area.y2 = 2.f / ATLAS_SIZE; + + gsk_ngl_render_job_draw_offscreen_with_color (job, + &node->bounds, + &offscreen, + color); + + gsk_ngl_render_job_end_draw (job); + } + else + { + gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color)); + gsk_ngl_render_job_draw_rect_with_color (job, &node->bounds, color); + gsk_ngl_render_job_end_draw (job); + } } static inline void -- cgit v1.2.1 From bfe4aea981b225ad5e4f4daf5902b6a4e30e90fc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 9 Apr 2021 00:52:18 -0400 Subject: ngl: Add a program change counter Count how often we change programs during a frame. --- gsk/ngl/gsknglcommandqueue.c | 5 +++++ gsk/ngl/gsknglcommandqueueprivate.h | 1 + 2 files changed, 6 insertions(+) diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index 4ce1628e2f..ca84d04774 100644 --- a/gsk/ngl/gsknglcommandqueue.c +++ b/gsk/ngl/gsknglcommandqueue.c @@ -951,6 +951,7 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue *self, guint n_binds = 0; guint n_fbos = 0; guint n_uniforms = 0; + guint n_programs = 0; guint vao_id; guint vbo_id; int textures[4]; @@ -1062,6 +1063,8 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue *self, { program = batch->any.program; glUseProgram (program); + + n_programs++; } if (apply_framebuffer (&framebuffer, batch->draw.framebuffer)) @@ -1144,6 +1147,7 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue *self, gdk_profiler_set_int_counter (self->metrics.n_binds, n_binds); gdk_profiler_set_int_counter (self->metrics.n_uniforms, n_uniforms); gdk_profiler_set_int_counter (self->metrics.n_fbos, n_fbos); + gdk_profiler_set_int_counter (self->metrics.n_programs, n_programs); gdk_profiler_set_int_counter (self->metrics.n_uploads, self->n_uploads); gdk_profiler_set_int_counter (self->metrics.queue_depth, self->batches.len); @@ -1415,6 +1419,7 @@ gsk_ngl_command_queue_set_profiler (GskNglCommandQueue *self, self->metrics.n_fbos = gdk_profiler_define_int_counter ("fbos", "Number of framebuffers attached"); self->metrics.n_uniforms = gdk_profiler_define_int_counter ("uniforms", "Number of uniforms changed"); self->metrics.n_uploads = gdk_profiler_define_int_counter ("uploads", "Number of texture uploads"); + self->metrics.n_programs = gdk_profiler_define_int_counter ("programs", "Number of program changes"); self->metrics.queue_depth = gdk_profiler_define_int_counter ("gl-queue-depth", "Depth of GL command batches"); } #endif diff --git a/gsk/ngl/gsknglcommandqueueprivate.h b/gsk/ngl/gsknglcommandqueueprivate.h index bcd7c8312d..a05095dbf0 100644 --- a/gsk/ngl/gsknglcommandqueueprivate.h +++ b/gsk/ngl/gsknglcommandqueueprivate.h @@ -250,6 +250,7 @@ struct _GskNglCommandQueue guint n_fbos; guint n_uniforms; guint n_uploads; + guint n_programs; guint queue_depth; } metrics; -- cgit v1.2.1