Efficient Canvas Drawing

Apologizes about the delayed response. To test this I made the performance widget I’ve always wanted. However I’m occasionally getting application hangs when using drawstring with it to display fps/ms.

I’ve been trying to figure out why, but I’m at a loss.

I also integrated this widget into my other application, and have been using it to gauge and improve performance. It’s forced me to have to look at how I’m rendering to Metal, as when I started it was running slower than OpenGL. Some of that probably is because Metal doesn’t support some of the things that OpenGL does and like to display solid black screens if pixels have values out of the range 0.0 ~ 1.0, so I have to do extra work on Metal to clamp them after each and every shader. Eurgh!

How much work was it to get a Metal surface on a view @samRowlands? Is this something you could abstract for more general use like Xojo’s OpenGLSurface? I’d pay for that. I think that’s actually how the OpenGLSurface came about - it was a plugin created by TinRocket.

First up, I’m only using Metal (and OpenGL) as a rendering context for Apple’s (soon to be retired Core Image) processing. So there’s enough to do what I need to do, in theory it could be extended enough to replace OpenGL surface.

  1. Initially, when I first worked on it almost 3 years ago, I was happy that it was much easier to configure than an OpenGL context. What I didn’t realize until last summer, was that I’d used incorrect documentation from Apple, and had created a Metal display portal that was backed by OpenGL. While it all worked perfectly on the array of hardware (with various OS version) here, it failed miserably for many customers.

Once I’d got the combination correct of a Metal display, backed by a Metal render, I realized that it had just moved the complexity from configuring to actual rendering. Sadly all the workarounds I’ve been forced to employ have pretty much obliterated any perceived performance improvement and actually broke a feature that made my app pretty powerful.

If it wasn’t for the fact that OpenGL is deprecated, I’d advise avoiding Metal entirely. That and while Metal was supported from 10.11, only 10.14 guarantees you a Metal device, so for anything lower, you need to support OpenGL and Metal.

  1. Yes it can be extracted and shared, it will take me some time to do so. My final design is pretty slick IMHO, as it uses CALayers, so from one single control at design time it can be either OpenGL or Metal at run time, I even allow the user to choose. It’s worth noting that because it’s only a rendering target for Core Image, it makes this much easier, otherwise you’ll need to have two sets of code, one for Metal and one for OpenGL.

I have several complaints with Metal (when compared with OpenGL).
A. pow( negative value ) with Metal will crash the render.
B. Negative values must be clamped after each shader, or weirdness ensures.
C. Stuttering. OpenGL frame rates are consistent, even with long renders, as they’re synchronous. Metal is asynchronous, passing control back to your application before it’s finished rendering, simulating faster performance, but in reality, it fills up it’s buffer, which is a maximum of 3 frames, and then your application freezes until all 3 buffers have been rendered. I’m still trying to find a solution for this nightmare.

Of course all my complaints with Metal could simply be because there’s very little documentation on using Core Image with Metal on the Mac.

I’m also not looking forwards to having to re-write all my core image code and kernels in pure Metal.

Ha ha ha… I decide to Google on how to make it Synchronous and implemented it, now it’s much smoother as it no longer stutters :slight_smile:

1 Like


  1. Change the CAMetalLayer to use Core Animation when presenting (eugh, normally Core Animation slows things down).
  2. When “presenting” the CAMetalDrawable, commit the commandBuffer first, then ask the command buffer to “waitUntilScheduled” and call “present” on the CAMetalDrawable.

Each pass takes longer and asking the CAMetalLayer for a drawable still takes time, but it’s more consistent, than loading up 3 frames and pausing for a second or two before anything else can happen.