Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Layer-backed NSView rotation and skewed siblings

I have a strange issue with layer-backed NSView and it's siblings, some of them are not rendered correctly when added into the existing view hierarchy attached to the rotated superview. Below are the details.

The problem

- NSScrollView (layer can be here)
  - NSClipView (or here)
    - Document View (or even here)
      - Some *rotated* subview
        - { Problematic sublings }

So, the hierarchy itself is rather simple and common: a scrollview with some document, document subviews represent some content. In my case it's graphics content and it can be rotated. Rotated views can have some additional subviews - various markers, control points and so on and that's where I face strange issues with skewed graphics once I use CALayer for a back-end: Issue illustration

Camera pictures are rendered separately, they are not the part of this view tree, pay attention to the markers and buttons.

As you can see on the image, I have some test views with subviews (just random buttons). Object on the right is rendered correctly, always. According to my tests, each and every NSView with frameRotation between [0, pi/2] renders OK. Object on the left is rendered blurry, it looks like caching buffer for this item is too small. It happens when frameRotation is in the [pi/2, pi] range.

The most strange thing

This issue doesn't happen in "real-time rotation". I.e. if I just change the frameRoation of the set-up hierarchy, with each subview on it's place, everything works fine. However, when subling are added to the already rotated object - it bugs and gives this blurred look.

In my application special subview appear when the user clicks on the item, that' the moment when the sibling are added into the superview.

It seems like back-end layer has some caching buffer for the subviews and some of them are computed with the wrong size when the root view is rotated.

How is it implemented and What have I tried

  1. The views are quite simple and standard, I have tried to push [view setWantsLayer:YES] to the root views of the hierarchy: scroll view, clip view, document view, each tme the result was the same. No hand-made layers, no layer hosts.
  2. Content views, siblings and actually the whole views tree (except of views mentioned above) have no layers. Although, I have tried to turn layers on for various item without any success.
  3. I have tried to force update (setNeedsDisplay) the back-end layer with no luck
  4. Re-setting the layer completely seems to be working, but lags to hard.

The solution?

That's the question, actually. Has anybody faced such issue? Of maybe someone knows the way to force the layer to drop all the caches and renew completely? So far I have only two solutions: to either drop the layers completely (works, but turns of all the eye-candy as well), or re-set the layer calling setWantsLayer:NO followed by setWantsLayer:YES. This one has terrible performance.

like image 282
Gobra Avatar asked Feb 19 '13 12:02

Gobra


1 Answers

You've written that you tried "setNeedsDisplay". Are you calling this method from the main thread? In one of my applications nothing happened if I called setNeedsDisplay from another thread. If you want to make sure the display is invalid, then use dispatch like so:

dispatch_async(dispatch_get_main_queue(), ^{

       [view setNeedsDisplay:YES];
});

Additionally have a look in your IB inspector. Sometimes layer backed views don't like being mixed with non layer backed views. Make sure, that in the "View Effects Inspector" layer support is turned on for all subviews of your root layer.

(In my program sometimes NSButtons vanished if layer support was turned off)

like image 153
JackPearse Avatar answered Nov 10 '22 04:11

JackPearse