Clean edges

The backdrop gets redrawn. It has to otherwise you wouldn’t see it. It’s just that it’s handled internally/automatically. I doubt you’ll see much speed up.

Well, you won’t get speed up from using a Backdrop but it looks like you were creating the Pictures every time in the Paint event. Creating and drawing a Picture takes good time so this should only be done once. That’s where you will get speed up. Drawing a prebuilt picture in Paint or using Backdrop will be the same speed pretty much.

There’s a couple of things that you can do (for the MacOS), the #1 thing I would recommend is NOT caching the image and redrawing the image.

#2 Use NSGradient or CGGradient for drawing the gradient, it’s a bit more work to set-up and you need to cache the gradient object for optimal drawing speed.

#3 You can enabled layer-backed views for that control in particular, this way the OS will cache the image for you (at the right resolution) and update it automatically when it needs to be updated.

Add the following functions to a module:

[code]Sub wantsLayer(extends r as rectControl, assigns value as boolean)
NSViewSetWantsLayer( ptr( r.handle ), value )
End Sub

Sub NSViewSetWantsLayer(NSViewID as ptr, value as boolean)
#if TargetCocoa then
declare sub doThing lib “Cocoa” selector “setWantsLayer:” ( NSViewID as Ptr, value as boolean )
doThing( NSViewID, value )
#endif
End Sub
[/code]

Then in the open event of your canvas or window simply call. Replace canvas1 with the name of your control or me if called from within the control’s Open event.

canvas1.setWantsLayer = true

Will using NSGradient/CGGradient and layer-backed views make the drawing/scrolling faster?

Do you have any examples of using NSGradient/CGGradient’s in xojo? I’m a bit confused on how to go about caching the gradient object.

Yes it does.
If you have a picture in memory at double size, and it gets copied to screen in the paint event, you don’t have to waste time creating the image with the gradient or any complex math.
A simple ‘copy this picture to screen’ is instantaneous.
The paint event is only called now and then anyway, when the control has been covered by another or you force a refresh.

In a sense that is exactly what the backdrop property is doing for you, but the backdrop is held at 1x scale so would likely be grainy.
painting a pre-created 2x image during the paint event is painless and fast.

Your worry about speed is not the drawing but the creating of the picture.
Create a picture property.
In your pain event, test if it’s Nil.
If it’s Nil, create the image and store it in the property.
Draw the picture property.

Things are working well. Thank you all!
Storing the image property and drawing it in the paint event saves time.
Some notes though:
Storing a picture property and drawing it to scale is almost as slow as creating it from scratch and drawing it. So, Will, your code with salable bitmaps helped considerably to speed it up.

Sam,
I am still curious about your suggestions though. Why do you opt for not caching the image, but rather use NS/CGGradient and caching that instead?

About that backdrop thing. In HiDPI mode, when a picture is dropped into the project, then it becomes an image set, where 1x or 2x will be displayed according to Retina or not. It would be nice to be able to be able to address that in code as well. Right now all we have is backdrop at 72dpi.Would it not be possible to have backdrop, backdrop.2x, and backdrop.3x as well ?

I think that the backdrop already works although something weird is going on when in the IDE. I noticed the same yesterday with a segmented control icon and today with the Canvas backdrop. I’m on a non-retina iMac.

Open a new project. Enable Retina/HiDPI.
Drag a (72 DPI) picture in your project so it becomes an image set. Then drag a (144 DPI) picture in the 2x position of the image set.
Add a Canvas and in the inspector, select the picture as backdrop.

In the IDE, the second (2x) picture is displayed.
When I run the project, the 1x picture is displayed.
When I switch to retina, the 2x picture is displayed.

Indeed the display in the IDE is not right. However, upon run, it works perfectly.

My point was that if we can do it with pictures dragged into the project, it would be nice to do the same with pictures created in code.

Ah, yes. You’re right.

You can. Set the Vertical/HorizontalResolution to 144 OR construct an ‘Image’ Picture with it where the ‘Image’ size is expressed in Points.

dim img As new Picture(100, 100, Array(pic)) //pic is 200x200 pixels

[quote=262900:@Marco Hof]I think that the backdrop already works although something weird is going on when in the IDE. I noticed the same yesterday with a segmented control icon and today with the Canvas backdrop. I’m on a non-retina iMac.

Open a new project. Enable Retina/HiDPI.
Drag a (72 DPI) picture in your project so it becomes an image set. Then drag a (144 DPI) picture in the 2x position of the image set.
Add a Canvas and in the inspector, select the picture as backdrop.

In the IDE, the second (2x) picture is displayed.
When I run the project, the 1x picture is displayed.
When I switch to retina, the 2x picture is displayed.[/quote]

Recall the IDE is more or less just mimicking what you’ll see at run time and IF we have a bug then what you see in the IDE may not exactly match what you get at runtime
But we do our best to make sure they are as similar as possible

Sometimes, like with OS native controls, we can use actual controls so the similarity is 100%.
But things like iOS and Web do not have “native” controls in the IDE that we can use to draw the UI in the IDE since they exist on other devices / browsers. So we draw those by hand

Either will improve the rendering speed. Layer-backed views is the easiest to implement and allows you take advantage of the OS level GPU caching (which is faster than drawing an image) without updating your drawing code.

NSGradients & CGGradients are a bit more difficult to set-up, there’s various snippets on this forum. It’s important to ‘retain’ the gradientID as creating the gradient object is one of the more expensive operations.

[quote=262892:@erin jamroz]Sam,
I am still curious about your suggestions though. Why do you opt for not caching the image, but rather use NS/CGGradient and caching that instead?[/quote]
The #1 reason why I recommend against caching the drawing to a picture and then drawing the picture, is for resolution independence. The moment you start drawing to a bitmap image, you then become responsible for ensuring that bitmap image is the correct resolution at all times. By removing that layer of complexity, you reduce the amount of work you have to do and reduce the likelihood of doing it wrong or it getting broken in the future.

Both the NSGradient & CGGradient drawing speeds are quicker than drawing a picture. But I would recommend trying the layer backed solution first.

Sure transferring image data from main memory to the GPU memory to then translate and copy in to the GPU screen buffer is relatively fast. What’s faster is to already have the image data in the correct format in the GPU memory. This can be done by using CGLayers (which are broke in Yosemite +), CALayers (which suck for bitmaps) or by using a Layer-Backed View.

A couple years ago I timed the difference between drawing a Xojo picture and drawing a CGLayer, the picture took 8000 ms, while the CGLayer would take 3~5 ms. It’s how we were able to deliver smooth animation on a retina display. CALayers work, but you don’t ‘draw’ them, you append them to another layer and the OS draws them when needed. They’re awkward to setup, where as CGLayers were easy.