diff --git a/src/common/guac_surface.c b/src/common/guac_surface.c index 09f8223f..2be765f7 100644 --- a/src/common/guac_surface.c +++ b/src/common/guac_surface.c @@ -29,7 +29,6 @@ #include #include -#include #include @@ -252,6 +251,7 @@ static void __guac_common_surface_flush_to_queue(guac_common_surface* surface) { rect->y = surface->dirty_y; rect->width = surface->dirty_width; rect->height = surface->dirty_height; + rect->flushed = 0; /* Surface now flushed */ surface->dirty = 0; @@ -822,8 +822,8 @@ static int __guac_common_surface_png_rect_compare(const void* a, const void* b) guac_common_surface_png_rect* rb = (guac_common_surface_png_rect*) b; /* Order roughly top to bottom, left to right */ - if (ra->y >> 6 != rb->y >> 6) return ra->y - rb->y; - if (ra->x != rb->x) return ra->x - rb->x; + if (ra->y != rb->y) return ra->y - rb->y; + if (ra->x != rb->x) return ra->x - rb->x; /* Wider updates should come first (more likely to intersect later) */ if (ra->width != rb->width) return rb->width - ra->width; @@ -837,11 +837,13 @@ void guac_common_surface_flush(guac_common_surface* surface) { guac_common_surface_png_rect* current = surface->png_queue; - int i; + int i, j; + int original_queue_length; int flushed = 0; /* Flush final dirty rect to queue */ __guac_common_surface_flush_to_queue(surface); + original_queue_length = surface->png_queue_length; /* Sort updates to make combination less costly */ qsort(surface->png_queue, surface->png_queue_length, sizeof(guac_common_surface_png_rect), @@ -850,30 +852,53 @@ void guac_common_surface_flush(guac_common_surface* surface) { /* Flush all rects in queue */ for (i=0; i < surface->png_queue_length; i++) { - int x = current->x; - int y = current->y; - int w = current->width; - int h = current->height; + /* Get next unflushed candidate */ + guac_common_surface_png_rect* candidate = current; + if (!candidate->flushed) { + + int combined = 0; + + /* Build up rect as much as possible */ + for (j=i; j < surface->png_queue_length; j++) { + + if (!candidate->flushed) { + + int x = candidate->x; + int y = candidate->y; + int w = candidate->width; + int h = candidate->height; + + /* Combine if reasonable */ + if (__guac_common_should_combine(surface, x, y, w, h, 0) || !surface->dirty) { + __guac_common_mark_dirty(surface, x, y, w, h); + candidate->flushed = 1; + combined++; + } + + } + + candidate++; + + } + + /* Re-add to queue if there's room and this update was modified or we expect others might be */ + if ((combined > 1 || i < original_queue_length) + && surface->png_queue_length < GUAC_COMMON_SURFACE_QUEUE_SIZE) + __guac_common_surface_flush_to_queue(surface); + + /* Flush as PNG otherwise */ + else { + if (surface->dirty) flushed++; + __guac_common_surface_flush_to_png(surface); + } - /* Flush if not combining */ - if (!__guac_common_should_combine(surface, x, y, w, h, 0)) { - if (surface->dirty) flushed++; - __guac_common_surface_flush_to_png(surface); } - /* Defer, attempt to combine with next rect */ - __guac_common_mark_dirty(surface, x, y, w, h); current++; } - /* Flush the final png */ - if (surface->dirty) flushed++; - __guac_common_surface_flush_to_png(surface); - /* Flush complete */ - if (flushed < surface->png_queue_length) - fprintf(stderr, "IMPROVEMENT: Flushed %i (originally %i) updates.\n", flushed, surface->png_queue_length); surface->png_queue_length = 0; } diff --git a/src/common/guac_surface.h b/src/common/guac_surface.h index 28e7485e..2c13007d 100644 --- a/src/common/guac_surface.h +++ b/src/common/guac_surface.h @@ -42,6 +42,11 @@ */ typedef struct guac_common_surface_png_rect { + /** + * Whether this rectangle has been flushed. + */ + int flushed; + /** * The X coordinate of the upper-left corner of this rectangle. */