summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza <jabier.arraiza@marker.es>2019-11-19 05:23:04 +0000
committerJabier Arraiza <jabier.arraiza@marker.es>2019-11-19 05:23:04 +0000
commit969361993806dbe679d1065d5a869fbb74163e8e (patch)
tree96d9ad847f6f5236719f06a9964d7f4fca1b72dc /src
parentMultiple fixes for the objects panel (diff)
downloadinkscape-969361993806dbe679d1065d5a869fbb74163e8e.tar.gz
inkscape-969361993806dbe679d1065d5a869fbb74163e8e.zip
Speedup filtering and panning
Diffstat (limited to 'src')
-rw-r--r--src/desktop.cpp2
-rw-r--r--src/display/drawing-item.cpp107
-rw-r--r--src/display/drawing-item.h4
-rw-r--r--src/display/drawing-surface.cpp7
-rw-r--r--src/display/drawing-surface.h4
-rw-r--r--src/display/drawing.cpp6
-rw-r--r--src/display/sp-canvas.cpp8
-rw-r--r--src/ui/tools/node-tool.cpp16
-rw-r--r--src/ui/tools/select-tool.cpp9
9 files changed, 100 insertions, 63 deletions
diff --git a/src/desktop.cpp b/src/desktop.cpp
index b055dcf7b..84c867cd6 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -963,8 +963,8 @@ SPDesktop::set_display_area( Geom::Rect const &r, double border, bool log)
} else {
zoom = w.height() / r.height();
}
+ zoom = CLAMP(zoom, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
_current_affine.setScale( Geom::Scale(zoom, yaxisdir() * zoom) );
-
// Zero offset, actual offset calculated later.
_current_affine.setOffset( Geom::Point( 0, 0 ) );
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 9bcaf36aa..999e914a6 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -75,9 +75,10 @@ DrawingItem::DrawingItem(Drawing &drawing)
, _cached_persistent(0)
, _has_cache_iterator(0)
, _propagate(0)
-// , _renders_opacity(0)
+ // , _renders_opacity(0)
, _pick_children(0)
, _antialias(2)
+ , _prev_nir(false)
, _isolation(SP_CSS_ISOLATION_AUTO)
, _mix_blend_mode(SP_CSS_BLEND_NORMAL)
{}
@@ -91,9 +92,6 @@ DrawingItem::~DrawingItem()
// remove from the set of cached items and delete cache
setCached(false, true);
- if (_has_cache_iterator) {
- _drawing._candidate_items.erase(_cache_iterator);
- }
// remove this item from parent's children list
// due to the effect of clearChildren(), this only happens for the top-level deleted item
if (_parent) {
@@ -296,6 +294,10 @@ DrawingItem::setCached(bool cached, bool persistent)
_drawing._cached_items.erase(this);
delete _cache;
_cache = nullptr;
+ if (_has_cache_iterator) {
+ _drawing._candidate_items.erase(_cache_iterator);
+ _has_cache_iterator = false;
+ }
}
}
@@ -595,15 +597,14 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne
* using more memory than the cache budget */
if (_cache) {
Geom::OptIntRect cl = _cacheRect();
- if (_visible && cl) { // never create cache for invisible items
+ if (_visible && cl && _has_cache_iterator) { // never create cache for invisible items
// this takes care of invalidation on transform
_cache->scheduleTransform(*cl, ctm_change);
} else {
// Destroy cache for this item - outside of canvas or invisible.
// The opposite transition (invisible -> visible or object
// entering the canvas) is handled during the render phase
- delete _cache;
- _cache = nullptr;
+ setCached(false, true);
}
}
}
@@ -673,18 +674,20 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
// carea is the area to paint
Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
-
- // expand render on filtered items
- Geom::OptIntRect cl = _cacheRect();
- if (_filter != nullptr && render_filters && cl) {
+ // iarea is the bounding box for intermediate rendering
+ // Note 1: Pixels inside iarea but outside carea are invalid
+ // (incomplete filter dependence region).
+ // Note 2: We only need to render carea of clip and mask, but
+ // iarea of the object.
+ Geom::OptIntRect iarea = carea;
+ // expand carea to contain the dependent area of filters.
+ if (_filter && render_filters) {
+ iarea = _cacheRect();
setCached(_cached, true);
- carea = cl;
}
-
- if (!carea) {
+ if (!iarea) {
return RENDER_OK;
}
-
// Device scale for HiDPI screens (typically 1 or 2)
int device_scale = dc.surface()->device_scale();
@@ -711,17 +714,16 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
if (_cache) {
_cache->prepare();
dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode));
- _cache->paintFromCache(dc, carea);
+ _cache->paintFromCache(dc, carea, _filter && render_filters);
if (!carea) {
+ dc.setSource(0, 0, 0, 0);
return RENDER_OK;
}
} else {
// There is no cache. This could be because caching of this item
// was just turned on after the last update phase, or because
// we were previously outside of the canvas.
- if (cl) {
- _cache = new DrawingCache(*cl, device_scale);
- }
+ _cache = new DrawingCache(*iarea, device_scale);
}
} else {
// if our caching was turned off after the last update, it was already
@@ -740,15 +742,11 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
nir |= needs_opacity; // 4. it is non-opaque
nir |= (_mix_blend_mode != SP_CSS_BLEND_NORMAL); // 5. it has blend mode
nir |= (_isolation == SP_CSS_ISOLATION_ISOLATE); // 6. it is isolated
- nir |= !parent(); // 7. is root, need isolation from background
- if (prev_nir && !needs_intermediate_rendering) {
+ nir |= !parent(); // 7. is root, need isolation from background
+ if (_prev_nir && !needs_intermediate_rendering) {
setCached(false, true);
- if (_has_cache_iterator) {
- _drawing._candidate_items.erase(_cache_iterator);
- _has_cache_iterator = false;
- }
}
- prev_nir = needs_intermediate_rendering;
+ _prev_nir = needs_intermediate_rendering;
nir |= (_cache != nullptr); // 5. it is to be cached
/* How the rendering is done.
@@ -770,20 +768,9 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) {
dc.setOperator(ink_css_blend_to_cairo_operator(SP_CSS_BLEND_NORMAL));
- return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at);
+ return _renderItem(dc, *iarea, flags & ~RENDER_FILTER_BACKGROUND, stop_at);
}
- // iarea is the bounding box for intermediate rendering
- // Note 1: Pixels inside iarea but outside carea are invalid
- // (incomplete filter dependence region).
- // Note 2: We only need to render carea of clip and mask, but
- // iarea of the object.
- Geom::OptIntRect iarea = carea;
- // expand carea to contain the dependent area of filters.
- if (_filter && render_filters) {
- _filter->area_enlarge(*iarea, this);
- iarea.intersectWith(_drawbox);
- }
DrawingSurface intermediate(*iarea, device_scale);
DrawingContext ict(intermediate);
@@ -866,11 +853,15 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
// 6. Paint the completed rendering onto the base context (or into cache)
if (_cached && _cache) {
DrawingContext cachect(*_cache);
- cachect.rectangle(*carea);
+ cachect.rectangle(*iarea);
cachect.setOperator(CAIRO_OPERATOR_SOURCE);
cachect.setSource(&intermediate);
cachect.fill();
- _cache->markClean(*carea);
+ if (_filter && render_filters) {
+ _cache->markClean(*_cacheRect(true));
+ } else {
+ _cache->markClean(*iarea);
+ }
}
dc.rectangle(*carea);
@@ -1141,10 +1132,6 @@ DrawingItem::_cacheScore()
{
Geom::OptIntRect cache_rect = _cacheRect();
if (!cache_rect) return -1.0;
- if (is_drawing_group(this) && !prev_nir) {
- return -1.0;
- }
-
// a crude first approximation:
// the basic score is the number of pixels in the drawbox
double score = cache_rect->area();
@@ -1171,10 +1158,38 @@ DrawingItem::_cacheScore()
return score;
}
-Geom::OptIntRect
-DrawingItem::_cacheRect()
+inline void expandByScale(Geom::IntRect &rect, double scale)
+{
+ double fraction = (scale - 1) / 2;
+ rect.expandBy(rect.width() * fraction, rect.height() * fraction);
+}
+
+
+Geom::OptIntRect DrawingItem::_cacheRect(bool cropped)
{
Geom::OptIntRect r = _drawbox & _drawing.cacheLimit();
+ if (_filter && _drawing.renderFilters()) {
+ // we check unfiltered item is emought inside the cache area to render properly
+ Geom::OptIntRect canvas = r;
+ expandByScale(*canvas, 0.5);
+ expandByScale(*r, 2);
+ Geom::OptIntRect valid = Geom::intersect(canvas, _bbox);
+ if (!valid) {
+ valid = _bbox;
+ // contract the item _bbox to get reduced size to render. $ seems good enought
+ expandByScale(*valid, 0.5);
+ // now we get the nearest point to cache area
+ Geom::IntPoint center = (*r).midpoint();
+ Geom::IntPoint nearest = (*valid).nearestEdgePoint(center);
+ r.expandTo(nearest);
+ }
+ valid = _drawbox & r;
+ // to reduce banding if item filtered overflow iarea area
+ if (cropped && r && _drawbox != valid) {
+ expandByScale(*r, 5. / 6.);
+ }
+ return _drawbox & r;
+ }
return r;
}
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index 8dd4fc5dc..08dbaadca 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -164,7 +164,7 @@ protected:
void _markForRendering();
void _invalidateFilterBackground(Geom::IntRect const &area);
double _cacheScore();
- Geom::OptIntRect _cacheRect();
+ Geom::OptIntRect _cacheRect(bool cropped = false);
virtual unsigned _updateItem(Geom::IntRect const &/*area*/, UpdateContext const &/*ctx*/,
unsigned /*flags*/, unsigned /*reset*/) { return 0; }
virtual unsigned _renderItem(DrawingContext &/*dc*/, Geom::IntRect const &/*area*/, unsigned /*flags*/,
@@ -209,7 +209,7 @@ protected:
Inkscape::Filters::Filter *_filter;
SPItem *_item; ///< Used to associate DrawingItems with SPItems that created them
DrawingCache *_cache;
- bool prev_nir;
+ bool _prev_nir;
CacheList::iterator _cache_iterator;
diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp
index 24fc525b1..c84e358f8 100644
--- a/src/display/drawing-surface.cpp
+++ b/src/display/drawing-surface.cpp
@@ -297,8 +297,7 @@ DrawingCache::prepare()
* Paints the clean area from cache and modifies the @a area
* parameter to the bounds of the region that must be repainted.
*/
-void
-DrawingCache::paintFromCache(DrawingContext &dc, Geom::OptIntRect &area)
+void DrawingCache::paintFromCache(DrawingContext &dc, Geom::OptIntRect &area, bool is_filter)
{
if (!area) return;
@@ -312,12 +311,16 @@ DrawingCache::paintFromCache(DrawingContext &dc, Geom::OptIntRect &area)
cairo_region_t *cache_region = cairo_region_copy(dirty_region);
cairo_region_subtract(dirty_region, _clean_region);
+ if (is_filter && !cairo_region_is_empty(dirty_region)) { // To allow fast panning on high zoom on filters
+ return;
+ }
if (cairo_region_is_empty(dirty_region)) {
area = Geom::OptIntRect();
} else {
cairo_rectangle_int_t to_repaint;
cairo_region_get_extents(dirty_region, &to_repaint);
area = _convertRect(to_repaint);
+ markDirty(*area);
cairo_region_subtract_rectangle(cache_region, &to_repaint);
}
cairo_region_destroy(dirty_region);
diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h
index f93920d7c..0522b53e6 100644
--- a/src/display/drawing-surface.h
+++ b/src/display/drawing-surface.h
@@ -72,9 +72,9 @@ public:
void markClean(Geom::IntRect const &area = Geom::IntRect::infinite());
void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans);
void prepare();
- void paintFromCache(DrawingContext &dc, Geom::OptIntRect &area);
+ void paintFromCache(DrawingContext &dc, Geom::OptIntRect &area, bool is_filter);
-protected:
+ protected:
cairo_region_t *_clean_region;
Geom::IntRect _pending_area;
Geom::Affine _pending_transform;
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index 511de780a..4ff7464a2 100644
--- a/src/display/drawing.cpp
+++ b/src/display/drawing.cpp
@@ -170,8 +170,10 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl
if (_root) {
_root->update(area, ctx, flags, reset);
}
- // process the updated cache scores
- _pickItemsForCaching();
+ if ((flags & DrawingItem::STATE_CACHE) || (flags & DrawingItem::STATE_ALL)) {
+ // process the updated cache scores
+ _pickItemsForCaching();
+ }
}
void
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 88fec767f..4bff9865a 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -2119,8 +2119,9 @@ int SPCanvas::paintRectInternal(PaintRectSetup const *setup, Geom::IntRect const
// Find the optimal buffer dimensions
int bw = this_rect.width();
int bh = this_rect.height();
+ // we dont want to stop the idle process if the area is empty
if ((bw < 1) || (bh < 1))
- return 0;
+ return 1;
if (bw * bh < setup->max_pixels) {
// We are small enough
@@ -2207,7 +2208,10 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
Geom::IntRect paint_rect(xx0, yy0, xx1, yy1);
Geom::OptIntRect area = paint_rect & canvas_rect;
- if (!area || area->hasZeroArea()) return false;
+ // we dont want to stop the idle process if the area is empty
+ if (!area || area->hasZeroArea()) {
+ return true;
+ }
paint_rect = *area;
PaintRectSetup setup;
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index 5054a83d9..ca485a706 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -470,6 +470,9 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) {
_previous_selection = _current_selection;
_current_selection = vec;
+ // Be sure unclean areas are redraw on selection change
+ desktop->getCanvas()->_forcefull = true;
+
this->_multipath->setItems(shapes);
this->update_tip(nullptr);
// This not need to be called canvas is updated on selection change on setItems
@@ -532,6 +535,11 @@ bool NodeTool::root_handler(GdkEvent* event) {
}
// create pathflash outline
if (prefs->getBool("/tools/nodes/pathflash_enabled")) {
+ // We want to reset flashed item to can highligh again previous one
+ if (!over_item && this->flashed_item) {
+ this->flashed_item = nullptr;
+ break;
+ }
if (!over_item || over_item == this->flashed_item) {
break;
}
@@ -620,9 +628,6 @@ bool NodeTool::root_handler(GdkEvent* event) {
break;
case GDK_BUTTON_RELEASE:
- if (event->button.button == 1) {
- this->desktop->canvas->_forcefull = true;
- }
if (this->_selector->doubleClicked()) {
// If the selector received the doubleclick event, then we're at some distance from
// the path; otherwise, the doubleclick event would have been received by
@@ -651,7 +656,10 @@ bool NodeTool::root_handler(GdkEvent* event) {
}
}
}
-
+ if (event->button.button == 1) {
+ // we want redraw of all dirty regions on relase
+ this->desktop->canvas->_forcefull = true;
+ }
break;
default:
diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp
index 2627f2e9a..553b021a2 100644
--- a/src/ui/tools/select-tool.cpp
+++ b/src/ui/tools/select-tool.cpp
@@ -799,8 +799,13 @@ bool SelectTool::root_handler(GdkEvent* event) {
sp_canvas_item_ungrab(this->grabbed);
this->grabbed = nullptr;
}
-
- desktop->updateNow();
+ desktop->canvas->endForcedFullRedraws(); // we want this forced redraw always with this tool
+ if (event->button.button == 1) {
+ // we want redraw of all dirty regions on relase
+ desktop->canvas->_forcefull = true;
+ }
+ // Think is not necesary now
+ // desktop->updateNow();
}
if (event->button.button == 1) {