Hi
I found out that for certain SVG files, rendering can likely be sped up a lot by directly rendering SVG elliptical arcs with Cairo instead of converting them to cubic Beziers and rendering those.
I expanded our current code in experimental to do that, and it... almost works. I'm not quite sure what I'm doing wrong at the moment, hopefully someone can help me with that! The code works well for perfect circles. It does not work well for ellipses, but doesn't seem to have any issues with rotation of ellipses.
Any optimization tips would be appreciated, as this code is called extremely often.
#line 558 "src/display/cairo-utils.cpp" else if (Geom::EllipticalArc const *a = dynamic_cast<Geom::EllipticalArc const*>(&c)) { Geom::EllipticalArc* tx = static_castGeom::EllipticalArc *(a->transformed(trans)); Geom::Affine xform = tx->unitCircleTransform();
// Normalize the ellipse into a circle Geom::EllipticalArc * ax = static_castGeom::EllipticalArc *(tx->transformed(xform));
bool sweep = /*ax->sweep(), large_arc = */ax->largeArc(); Geom::Point ce = ax->center(); Geom::Point ang(ax->initialAngle().radians(), ax->finalAngle().radians());
// Apply the transformation to the current context cairo_save(cr); cairo_matrix_t cr_trans; xform = xform.inverse() * trans; cairo_matrix_init(&cr_trans, xform[0], xform[1], xform[2], xform[3], xform[4], xform[5]); cairo_transform(cr, &cr_trans);
if (!optimize_stroke || tx->boundsFast().intersects(view)) { // Draw the circle if (sweep) { cairo_arc(cr, ce[X], ce[Y], ax->ray(X), ang[0], ang[1]); } else { cairo_arc_negative(cr, ce[X], ce[Y], ax->ray(X), ang[0], ang[1]); } } else { cairo_move_to(cr, ax->finalPoint()[X], ax->finalPoint()[Y]); } cairo_restore(cr); delete tx; delete ax; return; }
Please look at CairoPathSink which I have recently committed to lib2geom.
Regards, Krzysztof
2014-08-07 21:23 GMT+02:00 Liam White <inkscapebrony@...400...>:
Hi
I found out that for certain SVG files, rendering can likely be sped up a lot by directly rendering SVG elliptical arcs with Cairo instead of converting them to cubic Beziers and rendering those.
I expanded our current code in experimental to do that, and it... almost works. I'm not quite sure what I'm doing wrong at the moment, hopefully someone can help me with that! The code works well for perfect circles. It does not work well for ellipses, but doesn't seem to have any issues with rotation of ellipses.
Any optimization tips would be appreciated, as this code is called extremely often.
#line 558 "src/display/cairo-utils.cpp" else if (Geom::EllipticalArc const *a = dynamic_cast<Geom::EllipticalArc
const*>(&c)) { Geom::EllipticalArc* tx = static_castGeom::EllipticalArc *(a->transformed(trans)); Geom::Affine xform = tx->unitCircleTransform();
// Normalize the ellipse into a circle Geom::EllipticalArc * ax = static_cast<Geom::EllipticalArc
*>(tx->transformed(xform));
bool sweep = /*ax->sweep(), large_arc = */ax->largeArc(); Geom::Point ce = ax->center(); Geom::Point ang(ax->initialAngle().radians(),
ax->finalAngle().radians());
// Apply the transformation to the current context cairo_save(cr); cairo_matrix_t cr_trans; xform = xform.inverse() * trans; cairo_matrix_init(&cr_trans, xform[0], xform[1], xform[2], xform[3],
xform[4], xform[5]); cairo_transform(cr, &cr_trans);
if (!optimize_stroke || tx->boundsFast().intersects(view)) { // Draw the circle if (sweep) { cairo_arc(cr, ce[X], ce[Y], ax->ray(X), ang[0], ang[1]); } else { cairo_arc_negative(cr, ce[X], ce[Y], ax->ray(X), ang[0],
ang[1]); } } else { cairo_move_to(cr, ax->finalPoint()[X], ax->finalPoint()[Y]); } cairo_restore(cr); delete tx; delete ax; return; }
http://cairographics.org/manual/cairo-Paths.html#cairo-arc
Infragistics Professional Build stunning WinForms apps today! Reboot your WinForms applications with our WinForms controls. Build a bridge from your legacy apps to the future. http://pubads.g.doubleclick.net/gampad/clk?id=153845071&iu=/4140/ostg.cl... _______________________________________________ Inkscape-devel mailing list Inkscape-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/inkscape-devel
On Thu, Aug 07, 2014 at 03:23:44PM -0400, Liam White wrote:
Hi
I found out that for certain SVG files, rendering can likely be sped up a lot by directly rendering SVG elliptical arcs with Cairo instead of converting them to cubic Beziers and rendering those.
Does Inkscape use Cairo's rectangle drawing code? I understand that is optimized as well on certain backends, vs. just drawing the four lines. Which backend are you doing this testing with, the default image backend?
Ironically digging into the code it looks like Cairo's arc() routine does end up drawing the arc as a series of Beziers, although it appears to make some approximations that perhaps speed things up. This is also backend-dependent though; like for the gl backend I think it passes the drawing request directly to the opengl driver.
I expanded our current code in experimental to do that, and it... almost works. I'm not quite sure what I'm doing wrong at the moment, hopefully someone can help me with that! The code works well for perfect circles. It does not work well for ellipses, but doesn't seem to have any issues with rotation of ellipses.
Have you tried applying the transformation matrix after the cairo_arc() calls? Also, maybe do your stroking before calling cairo_restore()?
Any optimization tips would be appreciated, as this code is called extremely often.
Tried profiling it with linux-perf?
If not, I have a few notes from when I last did it: http://www.bryceharrington.org/wordpress/2013/08/measuring-cairo-performance... http://www.bryceharrington.org/wordpress/2013/08/vbo-size/
#line 558 "src/display/cairo-utils.cpp" else if (Geom::EllipticalArc const *a =
dynamic_cast<Geom::EllipticalArc const*>(&c)) { Geom::EllipticalArc* tx = static_castGeom::EllipticalArc *(a->transformed(trans)); Geom::Affine xform = tx->unitCircleTransform();
// Normalize the ellipse into a circle Geom::EllipticalArc * ax = static_cast<Geom::EllipticalArc
*>(tx->transformed(xform));
bool sweep = /*ax->sweep(), large_arc = */ax->largeArc(); Geom::Point ce = ax->center(); Geom::Point ang(ax->initialAngle().radians(),
ax->finalAngle().radians());
// Apply the transformation to the current context cairo_save(cr); cairo_matrix_t cr_trans; xform = xform.inverse() * trans; cairo_matrix_init(&cr_trans, xform[0], xform[1], xform[2],
xform[3], xform[4], xform[5]); cairo_transform(cr, &cr_trans);
if (!optimize_stroke || tx->boundsFast().intersects(view)) { // Draw the circle if (sweep) { cairo_arc(cr, ce[X], ce[Y], ax->ray(X), ang[0], ang[1]); } else { cairo_arc_negative(cr, ce[X], ce[Y], ax->ray(X), ang[0],
ang[1]); } } else { cairo_move_to(cr, ax->finalPoint()[X], ax->finalPoint()[Y]); } cairo_restore(cr); delete tx; delete ax; return; }
You mentioned this is called a lot. Do you mean in general for any drawing, or just in cases where an ellipse specifically is being drawn?
One thing I'm wondering is what if we added a true ellipse drawing functionality to cairo, and dispense with all the transformation business.
Infragistics Professional Build stunning WinForms apps today! Reboot your WinForms applications with our WinForms controls. Build a bridge from your legacy apps to the future. http://pubads.g.doubleclick.net/gampad/clk?id=153845071&iu=/4140/ostg.cl...
Inkscape-devel mailing list Inkscape-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/inkscape-devel
participants (3)
-
Bryce Harrington
-
Krzysztof Kosiński
-
Liam White