diff options
| author | Jabier Arraiza <jabier.arraiza@marker.es> | 2019-11-19 05:23:04 +0000 |
|---|---|---|
| committer | Jabier Arraiza <jabier.arraiza@marker.es> | 2019-11-19 05:23:04 +0000 |
| commit | 969361993806dbe679d1065d5a869fbb74163e8e (patch) | |
| tree | 96d9ad847f6f5236719f06a9964d7f4fca1b72dc | |
| parent | Multiple fixes for the objects panel (diff) | |
| download | inkscape-969361993806dbe679d1065d5a869fbb74163e8e.tar.gz inkscape-969361993806dbe679d1065d5a869fbb74163e8e.zip | |
Speedup filtering and panning
| -rw-r--r-- | src/desktop.cpp | 2 | ||||
| -rw-r--r-- | src/display/drawing-item.cpp | 107 | ||||
| -rw-r--r-- | src/display/drawing-item.h | 4 | ||||
| -rw-r--r-- | src/display/drawing-surface.cpp | 7 | ||||
| -rw-r--r-- | src/display/drawing-surface.h | 4 | ||||
| -rw-r--r-- | src/display/drawing.cpp | 6 | ||||
| -rw-r--r-- | src/display/sp-canvas.cpp | 8 | ||||
| -rw-r--r-- | src/ui/tools/node-tool.cpp | 16 | ||||
| -rw-r--r-- | src/ui/tools/select-tool.cpp | 9 |
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) { |
