summaryrefslogtreecommitdiffstats
path: root/src/display/drawing-item.cpp
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/display/drawing-item.cpp
parentMultiple fixes for the objects panel (diff)
downloadinkscape-969361993806dbe679d1065d5a869fbb74163e8e.tar.gz
inkscape-969361993806dbe679d1065d5a869fbb74163e8e.zip
Speedup filtering and panning
Diffstat (limited to 'src/display/drawing-item.cpp')
-rw-r--r--src/display/drawing-item.cpp107
1 files changed, 61 insertions, 46 deletions
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;
}