diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-08-09 05:51:45 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2011-08-09 05:51:45 +0000 |
| commit | 74b91362758052e0f03bb819663a4606f08e4c69 (patch) | |
| tree | d3c1c2e8620b067383f8014b055fe81fb34b6326 /src | |
| parent | Turn off debug message spam (diff) | |
| download | inkscape-74b91362758052e0f03bb819663a4606f08e4c69.tar.gz inkscape-74b91362758052e0f03bb819663a4606f08e4c69.zip | |
Use cache even if only part of the redraw region is clean
(bzr r10347.1.28)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/drawing-context.h | 3 | ||||
| -rw-r--r-- | src/display/drawing-item.cpp | 38 | ||||
| -rw-r--r-- | src/display/drawing-surface.cpp | 71 | ||||
| -rw-r--r-- | src/display/drawing-surface.h | 4 |
4 files changed, 75 insertions, 41 deletions
diff --git a/src/display/drawing-context.h b/src/display/drawing-context.h index 8d2e7d68a..4ada79057 100644 --- a/src/display/drawing-context.h +++ b/src/display/drawing-context.h @@ -64,6 +64,9 @@ public: void rectangle(Geom::Rect const &r) { cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); } + void rectangle(Geom::IntRect const &r) { + cairo_rectangle(_ct, r.left(), r.top(), r.width(), r.height()); + } void newPath() { cairo_new_path(_ct); } void newSubpath() { cairo_new_sub_path(_ct); } void path(Geom::PathVector const &pv); diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index e86e222e2..113bf9c33 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -422,7 +422,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag return; } - // carea is the bounding box for intermediate rendering. + // carea is the area to paint Geom::OptIntRect carea = Geom::intersect(area, _drawbox); if (!carea) return; @@ -430,8 +430,8 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag if (_cached) { if (_cache) { _cache->prepare(); - if (_cache->paintFromCache(ct, *carea)) - return; + _cache->paintFromCache(ct, carea); + if (!carea) return; } else { // There is no cache. This could be because caching of this item // was just turned on after the last update phase, or because @@ -447,12 +447,6 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag // deleted in setCached() } - // expand carea to contain the dependent area of filters. - if (_filter && render_filters) { - _filter->area_enlarge(*carea, this); - carea.intersectWith(_drawbox); - } - // determine whether this shape needs intermediate rendering. bool needs_intermediate_rendering = false; bool &nir = needs_intermediate_rendering; @@ -480,7 +474,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag if (!needs_intermediate_rendering) { if (_cached && _cache) { Inkscape::DrawingContext cachect(*_cache); - cachect.rectangle(area); + cachect.rectangle(*carea); cachect.clip(); { // 1. clear the corresponding part of cache @@ -498,7 +492,7 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag ct.setSource(_cache); ct.paint(); // 4. mark as clean - _cache->markClean(area); + _cache->markClean(*carea); return; } else { _renderItem(ct, *carea, flags); @@ -506,7 +500,19 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag } } - DrawingSurface intermediate(*carea); + // iarea is the bounding box for intermediate rendering + // Note 1: pixels inside iarea but outside carea might be 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); DrawingContext ict(intermediate); // 1. Render clipping path with alpha = opacity. @@ -537,9 +543,9 @@ DrawingItem::render(DrawingContext &ct, Geom::IntRect const &area, unsigned flag ict.setOperator(CAIRO_OPERATOR_OVER); } - // 3. Render object itself. + // 3. Render object itself ict.pushGroup(); - _renderItem(ict, *carea, flags); + _renderItem(ict, *iarea, flags); // 4. Apply filter. if (_filter && render_filters) { @@ -557,12 +563,12 @@ DrawingItem::render(DrawingContext &ct, 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(area); + cachect.rectangle(*carea); cachect.clip(); cachect.setOperator(CAIRO_OPERATOR_SOURCE); cachect.setSource(&intermediate); cachect.paint(); - _cache->markClean(area); + _cache->markClean(*carea); } ct.setSource(&intermediate); ct.paint(); diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 39a622fe7..43cf50b88 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -188,16 +188,6 @@ DrawingCache::markClean(Geom::IntRect const &area) cairo_rectangle_int_t clean = _convertRect(*r); cairo_region_union_rectangle(_clean_region, &clean); } -bool -DrawingCache::isClean(Geom::IntRect const &area) const -{ - cairo_rectangle_int_t test = _convertRect(area); - if (cairo_region_contains_rectangle(_clean_region, &test) == CAIRO_REGION_OVERLAP_IN) { - return true; - } else { - return false; - } -} /// Call this during the update phase to schedule a transformation of the cache. void @@ -267,20 +257,46 @@ DrawingCache::prepare() _pending_transform.setIdentity(); } -/** @brief Paints the clean area from cache and returns the remaining part */ -bool -DrawingCache::paintFromCache(DrawingContext &ct, Geom::IntRect const &area) +/** @brief 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 &ct, Geom::OptIntRect &area) { - if (!isClean(area)) - return false; - - Inkscape::DrawingContext::Save save(ct); - ct.rectangle(area); - ct.clip(); - ct.setSource(this); - ct.paint(); - - return true; + if (!area) return; + + // We subtract the clean region from the area, then get the bounds + // of the resulting region. This is the area that needs to be repainted + // by the item. + // Then we subtract the area that needs to be repainted from the + // original area and paint the resulting region from cache. + cairo_rectangle_int_t area_c = _convertRect(*area); + cairo_region_t *dirty_region = cairo_region_create_rectangle(&area_c); + cairo_region_t *cache_region = cairo_region_copy(dirty_region); + cairo_region_subtract(dirty_region, _clean_region); + + 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); + cairo_region_subtract_rectangle(cache_region, &to_repaint); + } + cairo_region_destroy(dirty_region); + + if (!cairo_region_is_empty(cache_region)) { + Inkscape::DrawingContext::Save save(ct); + int nr = cairo_region_num_rectangles(cache_region); + cairo_rectangle_int_t tmp; + for (int i = 0; i < nr; ++i) { + cairo_region_get_rectangle(cache_region, i, &tmp); + ct.rectangle(_convertRect(tmp)); + } + ct.clip(); + ct.setSource(this); + ct.paint(); + } + cairo_region_destroy(cache_region); } cairo_rectangle_int_t @@ -294,6 +310,15 @@ DrawingCache::_convertRect(Geom::IntRect const &area) return ret; } +Geom::IntRect +DrawingCache::_convertRect(cairo_rectangle_int_t const &r) +{ + Geom::IntRect ret = Geom::IntRect::from_xywh( + r.x, r.y, + r.width, r.height); + return ret; +} + } // end namespace Inkscape /* diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h index fd46d66ba..f3af33002 100644 --- a/src/display/drawing-surface.h +++ b/src/display/drawing-surface.h @@ -63,10 +63,9 @@ public: void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite()); void markClean(Geom::IntRect const &area = Geom::IntRect::infinite()); - bool isClean(Geom::IntRect const &area) const; void scheduleTransform(Geom::IntRect const &new_area, Geom::Affine const &trans); void prepare(); - bool paintFromCache(DrawingContext &ct, Geom::IntRect const &area); + void paintFromCache(DrawingContext &ct, Geom::OptIntRect &area); protected: cairo_region_t *_clean_region; @@ -74,6 +73,7 @@ protected: Geom::Affine _pending_transform; private: static cairo_rectangle_int_t _convertRect(Geom::IntRect const &r); + static Geom::IntRect _convertRect(cairo_rectangle_int_t const &r); }; } // end namespace Inkscape |
