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.
This commit is contained in:
Michael Jumper 2020-01-03 16:35:34 -08:00
parent 2d4412316f
commit 36f227586e

View File

@ -260,58 +260,67 @@ static int __guac_common_surface_is_opaque(guac_common_surface* surface,
/**
* 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;