Cocoa: extremely slow graphics

In my MacDraw-like application I have a palette for creating arrows types that offers a selection of arrow heads, decorations and line types in a floating window.

Under Carbon when one close the window it is instantly gone. Under Cocoa it takes 3 seconds. One can see items (canvases) in the palette being slowly erased in turn before the window closes so the problem seems to be in the framework not Cocoa.

Also when I edit an arrow type and click on “Update” to show it in the main window, under Carbon the update is instantaneous, but under Cocoa it takes 8 seconds (with no sign of any activity whilst waiting).

This is with Xojo 2014r2 under the IDE on the new Mac Pro so there is no shortage of compute power, and all drawing is in the paint event.

Drawing far more complex graphics interactively is fast, e.g. dragging nodes with several hundred lines attached being recomputed and redrawn, so it is not graphics in general that is slow, just widgets in a window.

Has anyone had similar problems with the user interface?

Well all I can say is my PaintDS program has no such problems… and while is was written originally under CARBON, I am working on the Cocoa update now, but all the animations, opening/closing of windows etc… are the same if not faster…

My SnapDragon app (similar to Visio) was written in Cocoa to start, and it too has no issues with dealing with hundreds of vector (Object2D) drawings…

Cocoa drawing is definitely slower than carbon… but I don’t see it as noticeable with widgets- just drawing I do… I would guess you are seeing differences in event handling that is causing a lot more processing…

Have you profiled your code?

  • Karen

For me not only the graphics are slower, even simple commands take longer to run, out problems in events like mouse move, mouse enter or mouse exit that sometimes just do not work, as well as the Global foating Window window that is behind other windows, is impossible for me to transfer for COCOA my projects now .

There might be something else at play here. I’ve noticed just the slightest slowdown in graphics in Cocoa (which are more than made up for how much better the apps look. Everything but listboxes, at least).

Why not first make Window.Visible = False, then close it ? It should make the window disappear right away.

Stick something debug in the Paint event and see how many times it is being called
When I first started moving to Cocoa I was inundated with pointless paint events, mainly due to controls being very close to each other.

Same here. Older RB and Xojo versions did have slow drawing but the latest are blistering fast.
Even very complex drawing stuff, event handling speed etc … is on par with Carbon.

And you can massively quicken the drawing speed up to 10 times using some declares too.

Read this.
https://forum.xojo.com/12286-speeding-up-cocoa-drawing

Also, don’t use .refresh but .invalidate for refreshing a canvas.

[quote=107936:@Jeff Tullin]Stick something debug in the Paint event and see how many times it is being called
When I first started moving to Cocoa I was inundated with pointless paint events, mainly due to controls being very close to each other.[/quote]

Optimising your code in your paint event is a must anyway. I always profile my code and look for anything which is chomping up processing time. Its very easy to end up with a lot of code in your paint event and some code which can easily be moved out of the paint event as it does not need evaluating on every call to paint. Profile your code it is a must

For this, you could use MacOSLIb or certainly a MBS plugin that gives you access to the NSWwindow class. Its AlwaysonTop property makes the window float reliably.

Cocoa is extremely slow with graphics. I’ve updated every piece of code and optimized in every possible way, to still have completely unusable HD (retina) graphics classes.

https://forum.xojo.com/12394-simdesignercanvas-1-6

Still runs smooth in Windows, Linux, and barely noticable lag with non-retina Cocoa apps. Still cannot find where (or how) a paint event can alter the window title (numbers or random jumbles of letters and numbers)… perhaps a pointer bug somewhere in the framework? Either way, would love to find a solution since graphics intensive events make Cocoa (retina) apps useless. (OpenGL is not an option and as of 2014 r2 crashes Windows apps)

Interesting… I have found Cocoa (using the right declares) to be MUCH Faster (and nicer looking) than Carbon…
You can’t just flip the Cocoa/Carbon switch… there are changes to be made to optimize things, but it is no great shakes… just a little research and a little work, and you end up with so much more.

I was able to add dotted/dashed lines to my paint program super easily… very difficult with Carbon…

[quote=108254:@Dave S]Interesting… I have found Cocoa (using the right declares) to be MUCH Faster (and nicer looking) than Carbon…
You can’t just flip the Cocoa/Carbon switch… there are changes to be made to optimize things, but it is no great shakes… just a little research and a little work, and you end up with so much more.

I was able to add dotted/dashed lines to my paint program super easily… very difficult with Carbon…[/quote]

Even with the “right declares” Cocoa has been known to be slower than Carbon.

https://forum.xojo.com/12286-speeding-up-cocoa-drawing

The above declares increased performance “slightly” but there is nothing left to optimize (except the framework itself).

[quote=108254:@Dave S]
I was able to add dotted/dashed lines to my paint program super easily… very difficult with Carbon…[/quote]

Are the you talking about doing it with declares or pure Xojo code?

I wanted Xplatform so I do that (and more ) in Xojo code without any declares. I am updating this very old code for that to support cocoa:

Styledline Project

I see that doing it that way Cocoa is a slower than carbon, but not that much.

Interestingly the difference was more noticeable on Windows between GDI+ on and off. By coding differently I got the speed for both cocoa and GDI+ is fine.

BTW I’ve not tried it on a retina display because I don’t have one. The above was old carbon… the lines look better drawn in cocoa and GDI+ than they did on carbon and on Windows without GDI+.

PS: the StyledLine stuff on my website is very old… Will update soon.

This keeps coming up. There’s nothing wrong with Cocoa’s graphics toolbox, it uses CoreGraphics, which is what Carbon used also. Core Graphics is hardware accelerated and is blisteringly fast.

As point of reference, it possible to have full screen animations (in Retina, nearly 5mp per frame) run at 245 FPS, within Xojo.

The biggest slowdowns I’ve encountered are as follows:
#1 Overlapping controls, simply put, don’t do it! Cocoa’s smarter, but if you have EraseBackground checked, a simply refresh on one control will cause all controls overlapped to refresh.

#2 When drawing images, try to avoid drawing large images down, this takes precious time, instead cache them at the right size.

#3 When drawing text, if the text is to be drawn ‘trimmed’, consider trimming it before rather than during the drawing.

#4 Gradients, use CGGradient or NSGradient declares.

#5 Shadows, use the shadow property of the CGContext or NSShadow.

#6 Pay attention to the areas() property of the canvas, there’s no need to redraw everything if only a small portion is being updated.

#7 Consider using CGLayers (via declares) for caching as these as super fast and Retina ready.

#8 Retina is twice the resolution of a normal screen, which means that it can take 4 times as long to update each frame.

#9 Use invalidate( x, y, w, h, false ) if you only need to update a specific area, in combination with #6.

#10 actually time how long it takes to draw, work on doing as little as possible in the ‘Paint’ event. If your application spends too long in the paint event, you’ll be skipping frames.

#11 OS X uses coalescing to keep the refresh rate at 60 fps, the same as most displays, if you want higher fps, there’s a plist option for it.

#12 Understanding the difference between invalidate and refresh will make a difference. Invalidate, simply marks the NSView as dirty and needs drawing again. Most likely this will occur on the same event loop, but it may not. You can call invalidate as many times as you like in a method, it’ll only happen once. Refresh on the other hand, forces the view to update there and then, you call it ten times in a method and it’ll fire the Paint event ten times, however you’ll only see the update on the screen once, unless you also force the window to refresh.

Most of the time, use invalidate, but Refresh is useful when doing blocking animation (i.e. you want a control to animate, but don’t want the user to instigate an action while the animation is occurring).

#13 If you can, use the vector shapes drawRect, drawOval rather than images. Don’t forget you can use complex shapes also.

#14 Lastly if you have to draw a lot of images, loaded from disk, use NSImage (via MacOSLib, MBS or RetinaKIt). NSImage is highly cached and Retina ready.

For those comparing OS X graphics to Windows, it’s like Apple’s and Oranges… Apple use a form of PostScript for their display language (which is why every OS X application can output PDF), it’s double buffered, window and screen.

Windows, just erm… Lets any application do what ever it wants and AFAIK is still only Bitmap based. For gaming, it’s an advantage over a Mac.

I think it has nothing to do with Cocoa. When Retina enabled you have x4 more pixel to calculate.
For Retina you indeed need to optimise a lot. Especially refreshing. So don’t use .refresh or .invalidate but .refreshRect (read : update only content that changes).
I know this can be cumbersome but it helps when you do.

You don’t need a Retina. Apple offers tools for checking HD stuff.

But you have to take in account everything is 4-6 times slower. In many cases you will have to optimise code.

I mostly use .refreshRect(x, y, w, h, true) which is faster then Invalidate(x, y, w, h, false)

I always thought this was the same.

Didn’t know about this.
Could explain this? Any drawbacks when you do allow you app for higher FPS ?