GUACAMOLE-249: Defer draws to unrealized (server-side) buffers until they are actually needed client-side.
Though deferred creation of buffers is already intended, creation was
not actually being deferred in practice as the act of initializing the
buffer with a solid rect of color was causing the buffer to be realized,
even if that initialization process is the only drawing operation that
will ever occur to that buffer.
diff --git a/src/common/surface.c b/src/common/surface.c
index c31dfbf..ccac11d 100644
--- a/src/common/surface.c
+++ b/src/common/surface.c
@@ -260,58 +260,67 @@
/**
* Returns whether the given rectangle should be combined into the existing
- * dirty rectangle, to be eventually flushed as a "png" instruction.
+ * dirty rectangle, to be eventually flushed as image data, or would be best
+ * kept independent of the current rectangle.
*
- * @param surface The surface to be queried.
- * @param rect The update rectangle.
- * @param rect_only Non-zero if this update, by its nature, contains only
- * metainformation about the update's rectangle, zero if
- * the update also contains image data.
- * @return Non-zero if the update should be combined with any existing update,
- * zero otherwise.
+ * @param surface
+ * The surface being updated.
+ *
+ * @param rect
+ * The bounding rectangle of the updating being made to the surface.
+ *
+ * @param rect_only
+ * Non-zero if this update, by its nature, contains only metainformation
+ * about the update's bounding rectangle, zero if the update also contains
+ * image data.
+ *
+ * @return
+ * Non-zero if the update should be combined with any existing update, zero
+ * otherwise.
*/
static int __guac_common_should_combine(guac_common_surface* surface, const guac_common_rect* rect, int rect_only) {
- if (surface->dirty) {
+ int combined_cost, dirty_cost, update_cost;
- int combined_cost, dirty_cost, update_cost;
+ /* Always favor combining updates if surface is currently a purely
+ * server-side scratch area */
+ if (!surface->realized)
+ return 1;
- /* Simulate combination */
- guac_common_rect combined = surface->dirty_rect;
- guac_common_rect_extend(&combined, rect);
+ /* Simulate combination */
+ guac_common_rect combined = surface->dirty_rect;
+ guac_common_rect_extend(&combined, rect);
- /* Combine if result is still small */
- if (combined.width <= GUAC_SURFACE_NEGLIGIBLE_WIDTH && combined.height <= GUAC_SURFACE_NEGLIGIBLE_HEIGHT)
+ /* Combine if result is still small */
+ if (combined.width <= GUAC_SURFACE_NEGLIGIBLE_WIDTH && combined.height <= GUAC_SURFACE_NEGLIGIBLE_HEIGHT)
+ return 1;
+
+ /* Estimate costs of the existing update, new update, and both combined */
+ combined_cost = GUAC_SURFACE_BASE_COST + combined.width * combined.height;
+ dirty_cost = GUAC_SURFACE_BASE_COST + surface->dirty_rect.width * surface->dirty_rect.height;
+ update_cost = GUAC_SURFACE_BASE_COST + rect->width * rect->height;
+
+ /* Reduce cost if no image data */
+ if (rect_only)
+ update_cost /= GUAC_SURFACE_DATA_FACTOR;
+
+ /* Combine if cost estimate shows benefit */
+ if (combined_cost <= update_cost + dirty_cost)
+ return 1;
+
+ /* Combine if increase in cost is negligible */
+ if (combined_cost - dirty_cost <= dirty_cost / GUAC_SURFACE_NEGLIGIBLE_INCREASE)
+ return 1;
+
+ if (combined_cost - update_cost <= update_cost / GUAC_SURFACE_NEGLIGIBLE_INCREASE)
+ return 1;
+
+ /* Combine if we anticipate further updates, as this update follows a common fill pattern */
+ if (rect->x == surface->dirty_rect.x && rect->y == surface->dirty_rect.y + surface->dirty_rect.height) {
+ if (combined_cost <= (dirty_cost + update_cost) * GUAC_SURFACE_FILL_PATTERN_FACTOR)
return 1;
-
- /* Estimate costs of the existing update, new update, and both combined */
- combined_cost = GUAC_SURFACE_BASE_COST + combined.width * combined.height;
- dirty_cost = GUAC_SURFACE_BASE_COST + surface->dirty_rect.width * surface->dirty_rect.height;
- update_cost = GUAC_SURFACE_BASE_COST + rect->width * rect->height;
-
- /* Reduce cost if no image data */
- if (rect_only)
- update_cost /= GUAC_SURFACE_DATA_FACTOR;
-
- /* Combine if cost estimate shows benefit */
- if (combined_cost <= update_cost + dirty_cost)
- return 1;
-
- /* Combine if increase in cost is negligible */
- if (combined_cost - dirty_cost <= dirty_cost / GUAC_SURFACE_NEGLIGIBLE_INCREASE)
- return 1;
-
- if (combined_cost - update_cost <= update_cost / GUAC_SURFACE_NEGLIGIBLE_INCREASE)
- return 1;
-
- /* Combine if we anticipate further updates, as this update follows a common fill pattern */
- if (rect->x == surface->dirty_rect.x && rect->y == surface->dirty_rect.y + surface->dirty_rect.height) {
- if (combined_cost <= (dirty_cost + update_cost) * GUAC_SURFACE_FILL_PATTERN_FACTOR)
- return 1;
- }
-
}
-
+
/* Otherwise, do not combine */
return 0;