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); diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index bdfef2f35c..ca84d04774 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++) @@ -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; 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 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 ();