Canvas offloading

Hi,

Out of curiosity is canvas drawing handled by the GPU, be it on Mac or Windows ?

Thanks.

Hi @Eric_R ,

I am pretty sure that canvas drawing on Windows OS uses the CPU, and the OpenGL control uses the GPU.

@Eugene_Dakin
Is OpenGL surface still useful/available?
I keep hearing that Macs don’t support it, in the same discussions as Metal and Vulkan.
If there is a faster way to get graphics on screen cross platform, I’d be interested in trying…

It certainly used to be on the Mac and I don’t think that’s changed, but there’s no guarantee with Apple PJ.

Back in 10.9 and below, it was possible to get a CGLayer, which lived on the GPU. But it got broke with 10.10 and eventually deprecated:( it was furiously fast.

Canvas drawing is all single threaded CPU. There are feedback requests going back years asking for some sort of cross platform GPU accelerated canvas control but there looks to be no interest from Xojo in this.

OpenGL is deprecated on macOS and I wouldn’t be surprised if it’s dropped in the next version of macOS.

I see.

To bad canvas isn’t GPU accelerated. Maybe someday someone will come with a solution
if Xojo wont.

Well good to know. Thanks.

For workarounds, you can use declares to draw directly to memory pictures and then in the paint event of the canvas just draw those

Plenty of advice in this forum to NOT do that and put all the drawing code into the Paint event instead.
With a complex diagram, Im not sure.
I might expect a Group2D to really perform, but the lack of discussion here about these graphic objects really make me suspect that Xojo may ‘forget they exist’ at any time, like the SpriteSurface as an example.

looks like you are confused. “All the drawing code into the Paint event” could be a simple
g.Drawpicture(BufferPic, 0, 0, g.width, g.height).

But you can draw to the BufferPic from outside the Paint event (either with declares or xojo code) then, to paint the buffer to the canvas just use a:

Canvas.Ivalidate

Also you can use declaraes inside the pait event.

But you can have multiple buffers, for example one for a background, a couple for some regions that dont change or change not so often, then in the paint event draw the background, the not changing regions and then on top of that the changing part.

This is a way to offloading the drawing event.

I do this a lot, I have for example a method “DrawBkg” that draws the Background picture (outside the paint event of the canvas), I call it at the start of the app and when the canvas is resized.

(The Background is a Picture Variable in the Window)

looks like you are confused.
No, I’m not.
Drawing to a picture object and then painting that picture is what I do now and have been doing for years.
But there has been advice to not blit big pictures to the screen, and do it in discrete drawing operations during Paint instead.
I havent spent the time trying that to compare the speeds.

Id like to think Group2d was faster, but that would be a big overhaul

There are several reasons as to why I would not recommend this at all.

  1. The Mac OS now uses view caching by default.
  2. Because the macOS is caching your canvas, the cache that you’ve created is simply occupying memory.
  3. Resizing the window, as you point out is going to be slow as the app needs to do a lot more.
  4. When drawing pictures, the macOS will create an optimized cache of that image, which can be slow for the first draw.

Below is what I would recommend.

  1. As you’ve stated you separate the background from other elements, then use that to your advantage. Have one canvas for the background, which only draws the background (in the paint event). Other canvases for the content. This should give you a huge boost in performance and it allows you to utilize Apple’s view animation system.
  2. Separate the logic from the paint. Do as much math and calculation in a ‘updateLayout’ method, so that at paint time, all it does is… paints.
  3. Only use anti-alias when needed, it makes things look smooth (especially on 1x displays) but it has an impact on rendering time.
  4. If you’re going to draw pictures, make sure that they’re drawing at one pixel of the image to one pixel on the screen, these you should cache off screen, leave anti-alias on when creating this cache, but turn it off when drawing the image.

At some point I need to experiment to see if I can gain a boost moving my drawing code over to using graphics paths, my gut tells me I will.

Hi Eric and @Jeff_Tullin

I wrote a book on Xojo and OpenGL at Program OpenGL Core 32-bit with Xojo on Windows and OSX, and just ran a few example programs on Windows 11, Ubunutu 20.04 LTS, and Raspberry Pi OS, and the examples that I tried all worked. I am not sure about Mac though, and here is a link with some information about Mac and OpenGL: Mac computers that use OpenCL and OpenGL graphics - Apple Support

I had to install the following OpenGL libraries on Raspberry Pi:

sudo apt-get install libgles2-mesa libgles2-mesa-dev xorg-dev

Edit: Added Jeff

I dont use Mac. Overlaping xojo controls on windows sucks, so… worst performance and flicker.

1 Like

I did a little looking around and on the Mac - at least in the recent past - drawing to an off-screen buffer uses the CPU while drawing to an on-screen context uses GPU acceleration. This should correspond to drawing to a Picture’s Graphics property versus responding to a Paint event.

For speed, you’re probably best served doing all of your drawing to the Paint event’s Graphics parameter, and not drawing to a Picture first. However, this is pretty general advice and you should profile both approaches to see which ones best fits your scenario.

1 Like