Note that there are some explanatory texts on larger screens.

plurals
  1. POiOS CGPath Performance
    primarykey
    data
    text
    <p><strong>UPDATE</strong></p> <p>I got around CG's limitations by drawing everything with OpenGL. Still some glitches, but so far it's working much, much faster.</p> <p>Some interesting points :</p> <ul> <li><strong><code>GLKView</code></strong> : That's an iOS-specific view, and it helps a lot in setting up the OpenGL context and rendering loop. If you're not on iOS, I'm afraid you're on your own.</li> <li><strong>Shader precision</strong> : The precision of shader variables in the current version of OpenGL ES (2.0) is <a href="https://stackoverflow.com/questions/4414041/what-is-the-precision-of-highp-floats-in-glsl-es-2-0-for-iphone-ipod-touch-ipad" title="16-bit">16-bit</a>. That was a little low for my purposes, so I emulated 32-bit arithmetics with pairs of 16-bit variables.</li> <li><strong><code>GL_LINES</code></strong> : OpenGL ES can natively draw simple lines. Not very well <em>(no joints, no caps, see the purple/grey line on the top of the screenshot below)</em>, but to improve that you'll have to write a custom shader, convert each line into a triangle strip and pray that it works! <em>(supposedly that's how browsers do that when they tell you that Canvas2D is GPU-accelerated)</em></li> </ul> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://i.stack.imgur.com/y0lAI.png" alt="Example rendering"></p> <ul> <li>Draw <strong>as little as possible</strong>. I suppose that makes sense, but you can frequently avoid rendering things that are, for instance, outside of the viewport.</li> <li>OpenGL ES has <strong><em>no</em> support for filled polygons</strong>, so you have to tesselate them yourself. Consider using <a href="http://code.google.com/p/iphone-glu/" rel="nofollow noreferrer" title="iPhone-GLU">iPhone-GLU</a> : that's a port of the MESA code and it's pretty good, although it's a little hard to use (no standard Objective-C interface).</li> </ul> <p><strong>Original Question</strong></p> <p>I'm trying to draw lots of CGPaths (typically more than 1000) in the <code>drawRect</code> method of my scroll view, which is refreshed when the user pans with his finger. I have the same application in JavaScript for the browser, and I'm trying to port it to an iOS native app.</p> <p>The iOS test code is (with 100 line operations, <code>path</code> being a pre-made <code>CGMutablePathRef</code>) :</p> <pre><code>- (void) drawRect:(CGRect)rect { // Start the timer BSInitClass(@"Renderer"); BSStartTimedOp(@"Rendering"); // Get the context CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(context, 2.0); CGContextSetFillColorWithColor(context, [[UIColor redColor] CGColor]); CGContextSetStrokeColorWithColor(context, [[UIColor blueColor] CGColor]); CGContextTranslateCTM(context, 800, 800); // Draw the points CGContextAddPath(context, path); CGContextStrokePath(context); // Display the elapsed time BSEndTimedOp(@"Rendering"); } </code></pre> <p>In JavaScript, for reference, the code is (with 10000 line operations) :</p> <pre><code>window.onload = function() { canvas = document.getElementById("test"); ctx = canvas.getContext("2d"); // Prepare the points before drawing var data = []; for (var i = 0; i &lt; 100; i++) data.push ({x: Math.random()*canvas.width, y: Math.random()*canvas.height}); // Draw those points, and write the elapsed time var __start = new Date().getTime(); for (var i = 0; i &lt; 100; i++) { for (var j = 0; j &lt; data.length; j++) { var d = data[j]; if (j == 0) ctx.moveTo (d.x, d.y); else ctx.lineTo(d.x,d.y) } } ctx.stroke(); document.write ("Finished in " + (new Date().getTime() - __start) + "ms"); }; </code></pre> <p>Now, I'm much more proficient in optimizing JavaScript than I am at iOS, but, after some profiling, it seems that CGPath's overhead is absolutely, incredibly bad compared to JavaScript. Both snippets run at about <em><strong>the same speed</strong></em> on a real iOS device, and the JavaScript code has 100x the number of line operations of the Quartz2D code!</p> <p><em>EDIT: Here is the top of the time profiler in Instruments :</em></p> <pre><code>Running Time Self Symbol Name 6487.0ms 77.8% 6487.0 aa_render 449.0ms 5.3% 449.0 aa_intersection_event 112.0ms 1.3% 112.0 CGSColorMaskCopyARGB8888 73.0ms 0.8% 73.0 objc::DenseMap&lt;objc_object*, unsigned long, true, objc::DenseMapInfo&lt;objc_object*&gt;, objc::DenseMapInfo&lt;unsigned long&gt; &gt;::LookupBucketFor(objc_object* const&amp;, std::pair&lt;objc_object*, unsigned long&gt;*&amp;) const 69.0ms 0.8% 69.0 CGSFillDRAM8by1 66.0ms 0.7% 66.0 ml_set_interrupts_enabled 46.0ms 0.5% 46.0 objc_msgSend 42.0ms 0.5% 42.0 floor 29.0ms 0.3% 29.0 aa_ael_insert </code></pre> <p>It is my understanding that this should be much faster on iOS, simply because the code is native... So, do you know :</p> <ul> <li>...what I am doing wrong here?</li> <li>...and if there's another, better solution to draw that many lines in real-time?</li> </ul> <p>Thanks a lot!</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload