summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarc Jeanmougin <marc@jeanmougin.fr>2017-07-01 16:26:15 +0000
committerMarc Jeanmougin <marc@jeanmougin.fr>2017-07-01 16:26:15 +0000
commita943d5ab5f8f2cc43efd47f7e52d267cbca4269a (patch)
tree29d141393096a220abfc8ed204dd77b154aab4c9 /src
parentallows mac os build to fail as we have no mac runners yet (diff)
parentSPCanvas::paintSingleBuffer: Draw directly to _backing_store (diff)
downloadinkscape-a943d5ab5f8f2cc43efd47f7e52d267cbca4269a.tar.gz
inkscape-a943d5ab5f8f2cc43efd47f7e52d267cbca4269a.zip
Merge branch 'speed_up_drawing' of gitlab.com:psychon/inkscape
Diffstat (limited to 'src')
-rw-r--r--src/display/sp-canvas.cpp84
-rw-r--r--src/display/sp-canvas.h4
2 files changed, 72 insertions, 16 deletions
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index d04c81ecb..8857b8c68 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -966,6 +966,9 @@ static void sp_canvas_init(SPCanvas *canvas)
canvas->_drawing_disabled = false;
canvas->_backing_store = NULL;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ canvas->_surface_for_similar = NULL;
+#endif
canvas->_clean_region = cairo_region_create();
canvas->_background = cairo_pattern_create_rgb(1, 1, 1);
canvas->_background_is_checkerboard = false;
@@ -1003,6 +1006,12 @@ void SPCanvas::dispose(GObject *object)
cairo_surface_destroy(canvas->_backing_store);
canvas->_backing_store = NULL;
}
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ if (canvas->_surface_for_similar) {
+ cairo_surface_destroy(canvas->_surface_for_similar);
+ canvas->_surface_for_similar = NULL;
+ }
+#endif
if (canvas->_clean_region) {
cairo_region_destroy(canvas->_clean_region);
canvas->_clean_region = NULL;
@@ -1125,8 +1134,14 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation
allocation->width, allocation->height);
// resize backing store
- cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- allocation->width, allocation->height);
+ cairo_surface_t *new_backing_store = NULL;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ if (canvas->_surface_for_similar != NULL)
+ new_backing_store = cairo_surface_create_similar_image(canvas->_surface_for_similar,
+ CAIRO_FORMAT_ARGB32, allocation->width, allocation->height);
+#endif
+ if (new_backing_store == NULL)
+ new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation->width, allocation->height);
if (canvas->_backing_store) {
cairo_t *cr = cairo_create(new_backing_store);
cairo_translate(cr, -canvas->_x0, -canvas->_y0);
@@ -1510,8 +1525,23 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
buf.canvas_rect = canvas_rect;
buf.is_empty = true;
- // create temporary surface
- cairo_surface_t *imgs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, paint_rect.width(), paint_rect.height());
+ // Make sure the following code does not go outside of _backing_store's data
+ assert(cairo_image_surface_get_format(_backing_store) == CAIRO_FORMAT_ARGB32);
+ assert(paint_rect.left() - _x0 >= 0);
+ assert(paint_rect.top() - _y0 >= 0);
+ assert(paint_rect.right() - _x0 <= cairo_image_surface_get_width(_backing_store));
+ assert(paint_rect.bottom() - _y0 <= cairo_image_surface_get_height(_backing_store));
+
+ // Create a temporary surface that draws directly to _backing_store
+ cairo_surface_flush(_backing_store);
+ unsigned char *data = cairo_image_surface_get_data(_backing_store);
+ int stride = cairo_image_surface_get_stride(_backing_store);
+ // Move to the right row
+ data += stride * (paint_rect.top() - _y0);
+ // Move to the right pixel inside of that row
+ data += 4 * (paint_rect.left() - _x0);
+ cairo_surface_t *imgs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
+ paint_rect.width(), paint_rect.height(), stride);
buf.ct = cairo_create(imgs);
cairo_save(buf.ct);
@@ -1552,16 +1582,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
- //cairo_t *xct = gdk_cairo_create(gtk_widget_get_window (widget));
- cairo_t *xct = cairo_create(_backing_store);
- cairo_translate(xct, paint_rect.left() - _x0, paint_rect.top() - _y0);
- cairo_rectangle(xct, 0, 0, paint_rect.width(), paint_rect.height());
- cairo_clip(xct);
- cairo_set_source_surface(xct, imgs, 0, 0);
- cairo_set_operator(xct, CAIRO_OPERATOR_SOURCE);
- cairo_paint(xct);
- cairo_destroy(xct);
- cairo_surface_destroy(imgs);
+ cairo_surface_mark_dirty(_backing_store);
// Mark the painted rectangle clean
markRect(paint_rect, 0);
@@ -1764,6 +1785,28 @@ void SPCanvas::endForcedFullRedraws()
gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
SPCanvas *canvas = SP_CANVAS(widget);
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ if (canvas->_surface_for_similar == NULL && canvas->_backing_store != NULL) {
+ canvas->_surface_for_similar = cairo_surface_create_similar(
+ cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, 1, 1);
+
+ // Reallocate backing store so that cairo can use shared memory
+ cairo_surface_t *new_backing_store = cairo_surface_create_similar_image(
+ canvas->_surface_for_similar, CAIRO_FORMAT_ARGB32,
+ cairo_image_surface_get_width(canvas->_backing_store),
+ cairo_image_surface_get_height(canvas->_backing_store));
+
+ // Copy the old backing store contents
+ cairo_t *cr = cairo_create(new_backing_store);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface(cr, canvas->_backing_store, 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+ cairo_surface_destroy(canvas->_backing_store);
+ canvas->_backing_store = new_backing_store;
+ }
+#endif
+
// Blit from the backing store, without regard for the clean region.
// This is necessary because GTK clears the widget for us, which causes
// severe flicker while drawing if we don't blit the old contents.
@@ -1853,6 +1896,7 @@ int SPCanvas::paint()
cairo_region_get_rectangle(to_draw, i, &crect);
if (!paintRect(crect.x, crect.y, crect.x + crect.width, crect.y + crect.height)) {
// Aborted
+ cairo_region_destroy(to_draw);
return FALSE;
};
}
@@ -1862,6 +1906,8 @@ int SPCanvas::paint()
_forced_redraw_count = 0;
}
+ cairo_region_destroy(to_draw);
+
return TRUE;
}
@@ -1946,8 +1992,14 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol
// adjust backing store contents
assert(_backing_store);
- cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- allocation.width, allocation.height);
+ cairo_surface_t *new_backing_store = NULL;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ if (_surface_for_similar != NULL)
+ new_backing_store = cairo_surface_create_similar_image(
+ _surface_for_similar, CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
+#endif
+ if (new_backing_store == NULL)
+ new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
cairo_t *cr = cairo_create(new_backing_store);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
// Paint the background
diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h
index a2cbe0b27..92a50da11 100644
--- a/src/display/sp-canvas.h
+++ b/src/display/sp-canvas.h
@@ -179,6 +179,10 @@ public:
/// Image surface storing the contents of the widget
cairo_surface_t *_backing_store;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
+ /// This should be e.g. a cairo-xlib surface that is used to allocate _backing_store; might be NULL.
+ cairo_surface_t *_surface_for_similar;
+#endif
/// Area of the widget that has up-to-date content
cairo_region_t *_clean_region;
/// Widget background, defaults to white