• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: lockFocusIfCanDraw behavior in layer-backed mode
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: lockFocusIfCanDraw behavior in layer-backed mode


  • Subject: Re: lockFocusIfCanDraw behavior in layer-backed mode
  • From: Tor Arne Vestbø <email@hidden>
  • Date: Sun, 23 Dec 2018 14:41:42 +0000
  • Thread-topic: lockFocusIfCanDraw behavior in layer-backed mode

Thank you Matt for a very detailed and thorough reply! This is very useful and
clarifying information.

> On 17 Dec 2018, at 20:39, Matt Jacobson <email@hidden> wrote:
>
> Even if it were, it’s still unsafe to ignore the rect passed to -drawRect:.
> That’s because the system might require you to redraw a larger area than what
> your code thinks needs to be redrawn.

Speaking of this, getRectsBeingDrawn: doesn’t seem to work outside of
drawRect:, e.g. in displayLayer:. Is there any way to get at CA/AppKit’s view
of what needs redrawn another way? Without this information we’re forced to do
full updates on every repaint, even when originating from say
setNeedsDisplayInRect:CGRectMake(50, 50, 10, 10).

>> (I know this is a bad ida, but) is there a way to achieve the same
>> synchronous flush with layer-backing?
>
> No.
>
> The imperative view drawing model you’re describing has long been
> discouraged.  Among others problems, imperative drawing disrupts the drawing
> of overlapping views (both siblings and superview–subview pairs), is
> incompatible with layer-backed views, and prevents system drawing
> optimizations.

Right. We are aware of the situation. Unfortunately Qt’s Widget module assumes
an imperative drawing model.

During AppKit driven updates the flow goes something like this:

        - [QNSView drawRect:] or [QNSView displayLayer:] (depending on whether
layer-backing is enabled or not)
                - QCocoaWindow::handleExposeEvent(dirtyRegion)
                        - QWidgetBackingStore::beginPaint()
                        - QWidgetBackingStore::endPaint()
                        - QWidgetBackingStore::flush()
                                - QCocoaBackingStore::flush()
                                        - a) non-layer-backed
                                                - [view lockFocusIfCanDraw] (if
there’s no focusView)
                                                - [backingStoreImage
drawInRect:]
                                                - [view unlockFocus] and
[view.window flushWindow] (if there was no focusView)
                                        - b) layer-backed
                                                - view.layer.contents =
CGImageFrom(backingStoreImage)

But when QtWidget drives an update, say after clicking a button, we end up with:

        - Qt’s CFRunLoopSource for posted events
                - QWidgetWindow::event(QEvent::UpdateRequest):
                        - QWidgetBackingStore::beginPaint()
                        - QWidgetBackingStore::endPaint()
                        - QWidgetBackingStore::flush()
                                - QCocoaBackingStore::flush()
                                        - a) non-layer-backed
                                                - [view lockFocusIfCanDraw] (if
there’s no focusView)
                                                - [backingStoreImage
drawInRect:]
                                                - [view unlockFocus] and
[view.window flushWindow] (if there was no focusView)
                                        - b) layer-backed
                                                - view.layer.contents =
CGImageFrom(backingStoreImage)

https://github.com/qt/qtbase/blob/5.12/src/plugins/platforms/cocoa/qcocoabackingstore.mm#L81

A similar situation happens when an animation is driven by a CVDisplayLink,
where the display-link callback coming in on the secondary thread is delivered
to the main thread via dispatch_source event handler, so we’re again drawing &
flushing outside of the display cycle.

https://github.com/qt/qtbase/blob/5.12/src/plugins/platforms/cocoa/qcocoascreen.mm#L270

If we can’t (shouldn’t) do any imperative drawing, should a CVDisplayLink
callback always just call setNeedsDisplay and let the callback be coalesced
into the main runloop's display cycle? Even for OpenGL or Metal, where you can
present a frame imperatively?

>       • using -[NSImage initWithSize:flipped:drawingHandler] to capture
> drawing code into a block; by drawing that image in -drawRect:, you’ll defer
> execution of the drawing code until then

This one looks interesting!

>
> I hope this helps!

Very much so, thanks again!! 😊

Cheers,
Tor Arne

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

References: 
 >Re: NSString drawAtPoint in Mojave (From: Tom Doan <email@hidden>)
 >Re: NSString drawAtPoint in Mojave (From: Matt Jacobson <email@hidden>)
 >lockFocusIfCanDraw behavior in layer-backed mode (From: Tor Arne Vestbø <email@hidden>)
 >Re: lockFocusIfCanDraw behavior in layer-backed mode (From: Matt Jacobson <email@hidden>)

  • Prev by Date: Re: lockFocusIfCanDraw behavior in layer-backed mode
  • Previous by thread: Re: lockFocusIfCanDraw behavior in layer-backed mode
  • Index(es):
    • Date
    • Thread