From cfc1695f611980b1503f0e0547d9abf57608cf3e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Date: Sun, 10 Jul 2022 05:51:49 +0200 Subject: [PATCH 1/2] Refactor drawing Item --- src/display/drawing-item.cpp | 55 ++++++++++++++------------------- src/display/drawing-surface.cpp | 5 ++- src/display/drawing.cpp | 8 +---- src/display/drawing.h | 2 +- src/object/sp-item.cpp | 13 +++++++- src/ui/widget/canvas.cpp | 2 +- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 166a84d39b..78b1341ff6 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -686,18 +686,17 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag return RENDER_OK; } - // carea is the area to paint - Geom::OptIntRect carea = Geom::intersect(area, _drawbox); - + Geom::OptIntRect carea = area & _drawbox; if (!carea) { return RENDER_OK; } - // 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. - + // TODO study chenge the next iarea funcitions to this one commented + // Nonmaly _cacheRect is not in comandline. + // If we decide do it we need to chage a test rendering + // a few chaged + //if (_filter && render_filters) { + // carea = _cacheRect(); ? _cacheRect() : _drawbox; + //} Geom::OptIntRect iarea = carea; // expand carea to contain the dependent area of filters. if (_filter && render_filters) { @@ -712,10 +711,12 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag } } - if (!iarea) { + // carea is the area to paint + carea = iarea & _drawbox; + if (!carea) { return RENDER_OK; } - + // Device scale for HiDPI screens (typically 1 or 2) int device_scale = dc.surface()->device_scale(); @@ -740,8 +741,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag } 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. - Geom::OptIntRect cl = _cacheRect(); + Geom::OptIntRect cl = _cacheRect() ? _cacheRect() : _drawbox; _cache = new DrawingCache(*cl, device_scale); } } else { @@ -766,7 +766,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag setCached(false, true); } _prev_nir = needs_intermediate_rendering; - nir |= (_cache != nullptr); // 5. it is to be cached + nir |= (_cache != nullptr); // 8. it is to be cached /* How the rendering is done. * @@ -787,11 +787,11 @@ 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, *iarea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); + return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at); } - DrawingSurface intermediate(*iarea, device_scale); + DrawingSurface intermediate(*carea, device_scale); DrawingContext ict(intermediate); // This path fails for patterns/hatches when stepping the pattern to handle overflows. @@ -840,7 +840,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag // 3. Render object itself ict.pushGroup(); - render_result = _renderItem(ict, *iarea, flags, stop_at); + render_result = _renderItem(ict, *carea, flags, stop_at); // 4. Apply filter. if (_filter && render_filters) { @@ -851,9 +851,9 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag if (bg_root->_background_new) break; } if (bg_root) { - DrawingSurface bg(*iarea, device_scale); + DrawingSurface bg(*carea, device_scale); DrawingContext bgdc(bg); - bg_root->render(bgdc, *iarea, flags | RENDER_FILTER_BACKGROUND, this); + bg_root->render(bgdc, *carea, flags | RENDER_FILTER_BACKGROUND, this); _filter->render(this, ict, &bgdc); rendered = true; } @@ -870,29 +870,20 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag ict.popGroupToSource(); ict.setOperator(CAIRO_OPERATOR_IN); ict.paint(); - + // 6. Paint the completed rendering onto the base context (or into cache) if (_cached && _cache) { DrawingContext cachect(*_cache); - Geom::OptIntRect cl = _cacheRect(); - if (_filter && render_filters && cl) { - cachect.rectangle(*cl); - } else { - cachect.rectangle(*iarea); - } + cachect.rectangle(*carea); cachect.setOperator(CAIRO_OPERATOR_SOURCE); cachect.setSource(&intermediate); cachect.fill(); - - if (_filter && render_filters && cl) { - _cache->markClean(*cl); - } else { - _cache->markClean(*iarea); - } + _cache->markClean(*carea); } dc.rectangle(*carea); dc.setSource(&intermediate); + // 7. Render blend mode dc.setOperator(ink_css_blend_to_cairo_operator(_mix_blend_mode)); dc.fill(); diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index bf8653007f..4b24cb5895 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -322,7 +322,10 @@ void DrawingCache::paintFromCache(DrawingContext &dc, Geom::OptIntRect &area, bo 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 + if (is_filter && !cairo_region_is_empty(dirty_region)) { // To allow fast panning on high zoom on filters + cairo_region_destroy(cache_region); + cairo_region_destroy(dirty_region); + markDirty(*area); return; } if (cairo_region_is_empty(dirty_region)) { diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp index 09a2d11a86..ac052404a2 100644 --- a/src/display/drawing.cpp +++ b/src/display/drawing.cpp @@ -145,15 +145,9 @@ Drawing::cacheLimit() const return _cache_limit; } void -Drawing::setCacheLimit(Geom::OptIntRect const &r, bool update_cache) +Drawing::setCacheLimit(Geom::OptIntRect const &r) { _cache_limit = r; - if (update_cache) { - for (auto _cached_item : _cached_items) - { - _cached_item->_markForUpdate(DrawingItem::STATE_CACHE, false); - } - } } void Drawing::setCacheBudget(size_t bytes) diff --git a/src/display/drawing.h b/src/display/drawing.h index 20df1b02b1..39773a773a 100644 --- a/src/display/drawing.h +++ b/src/display/drawing.h @@ -69,7 +69,7 @@ public: bool getOutlineSensitive() const { return _outline_sensitive; }; Geom::PathVector clip; Geom::OptIntRect const &cacheLimit() const; - void setCacheLimit(Geom::OptIntRect const &r, bool update_cache = true); + void setCacheLimit(Geom::OptIntRect const &r); void setCacheBudget(size_t bytes); OutlineColors const &colors() const { return _colors; } diff --git a/src/object/sp-item.cpp b/src/object/sp-item.cpp index 02dabf68bf..f40b3ca64e 100644 --- a/src/object/sp-item.cpp +++ b/src/object/sp-item.cpp @@ -1609,12 +1609,23 @@ void SPItem::doWriteTransform(Geom::Affine const &transform, Geom::Affine const if (lpeitem) { lpeitem->notifyTransform(transform); } + bool unoptimized = false; + gchar *classes = g_strdup(getAttribute("class")); + if (classes) { + Glib::ustring classdata = classes; + size_t pos = classdata.find("UnoptimicedTransforms"); + if ( pos != std::string::npos ) { + unoptimized = true; + } + } + g_free(classes); if ( // run the object's set_transform (i.e. embed transform) only if: (dynamic_cast(this) && firstChild() && dynamic_cast(firstChild())) || (!preserve && // user did not chose to preserve all transforms (!clip_ref || !clip_ref->getObject()) && // the object does not have a clippath (!mask_ref || !mask_ref->getObject()) && // the object does not have a mask - !(!transform.isTranslation() && style && style->getFilter())) + !(!transform.isTranslation() && style && style->getFilter()) && + !unoptimized) // the object does not have a filter, or the transform is translation (which is supposed to not affect filters) ) { diff --git a/src/ui/widget/canvas.cpp b/src/ui/widget/canvas.cpp index 39c0cb55d3..a2b083e397 100644 --- a/src/ui/widget/canvas.cpp +++ b/src/ui/widget/canvas.cpp @@ -3332,7 +3332,7 @@ bool CanvasPrivate::on_idle() // Recreate the store fragment at the current affine so that it covers the visible region + prerender margin. auto store = graphics->get_store(); store->rect = expandedBy(q->get_area_world(), prefs.margin + prefs.pad); - q->_drawing->setCacheLimit(store->rect, false); + q->_drawing->setCacheLimit(store->rect); store->affine = q->_affine; auto content_size = store->rect.dimensions() * device_scale; -- GitLab From a188d3282b9fc781dcec71b4da84117ca74eb014 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Date: Sun, 10 Jul 2022 05:54:37 +0200 Subject: [PATCH 2/2] Refactor drawing Item. caching only filters --- src/display/drawing-item.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index 78b1341ff6..9d7e8019c7 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -1172,9 +1172,10 @@ DrawingItem::_cacheScore() if (!cache_rect) return -1.0; // a crude first approximation: // the basic score is the number of pixels in the drawbox - double score = cache_rect->area(); + double score = 0; // this is multiplied by the filter complexity and its expansion if (_filter &&_drawing.renderFilters()) { + score = cache_rect->area(); score *= _filter->complexity(_ctm); Geom::IntRect ref_area = Geom::IntRect::from_xywh(0, 0, 16, 16); Geom::IntRect test_area = ref_area; @@ -1185,11 +1186,11 @@ DrawingItem::_cacheScore() score *= double((test_area & limit_area)->area()) / ref_area.area(); } // if the object is clipped, add 1/2 of its bbox pixels - if (_clip && _clip->_bbox) { + if (score && _clip && _clip->_bbox) { score += _clip->_bbox->area() * 0.5; } // if masked, add mask score - if (_mask) { + if (score && _mask) { score += _mask->_cacheScore(); } //g_message("caching score: %f", score); -- GitLab