Reputation: 2172
I am trying to migrate my Opengl application to Metal, and I am using CAMetalLayer
for the Metal implementation.
I have set the following properties on my inherited NSView
class object:
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
[self setWantsLayer:YES];
I have checked other answers on SO, like NSView subclass - drawRect: not called
So, I tried assigning the delegate as suggested in answers above, something like this
[self.layer setDelegate:self];
and I get the following compilation error:
Cannot initialize a parameter of type 'id<CALayerDelegate> _Nullable' with an lvalue of type 'MyNSView *'
Moreover, I also see the documentation for setting up layer objects at https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/SettingUpLayerObjects/SettingUpLayerObjects.html, which states this:
For layer-backed views with custom content, you should continue to override the view’s methods to do your drawing. A layer-backed view automatically makes itself the delegate of its layer and implements the needed delegate methods, and you should not change that configuration. Instead, you should implement your view’s drawRect: method to draw your content.
So, according to this, I don't even have to set the delegate in my case and I am already implementing the drawRect
function in MyNSView
. Still it doesn't get called.
Is there anything more that needs to be done?
Thanks!
Edit:
So, I fixed the compilation error by making my layer follow the protocol CALayerDelegate
, but still I don't get any calls to drawLayer
or drawRect
.
makeBackingLayer
- (CALayer*)makeBackingLayer
{
id <MTLDevice> device = MTLCreateSystemDefaultDevice();
CAMetalLayer *backingLayer = [CAMetalLayer layer];
backingLayer.opaque = YES;
backingLayer.device = device;
backingLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
backingLayer.framebufferOnly = YES;
// [backingLayer setDelegate:self]; //Tried setting the delegate
//here as well
return backingLayer;
}
init function
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
[self setWantsLayer:YES];
[self.layer setDelegate:self];
Draw functions
- (void)displayLayer:(CALayer *)layer
{
[self drawRect:self.bounds];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
[self drawRect:self.bounds];
}
-(void) drawRect: (NSRect) dirtyRect
{
[super drawRect:dirtyRect];
}
I have implemented all the draw functions to check if any of them get hit, but I don't receive a call on any of these functions.
For drawing content to the NSView, I draw to offscreen resources and the get the drawable
from CALayer of NSView and call presentDrawable
before committing on the commandBuffer
.
Upvotes: 2
Views: 1227
Reputation: 2172
Since there wasn't much here that I could debug to find where the bug was introduced, so I started playing with the order in which the instructions were executed. And as it turns out, the order in which you call :
[self setWantsLayer:YES];
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
was causing the issue. On swapping these two statements, I started receiving call to my displayLayer
function. I still couldn't figure out why drawRect
doesn't get called for layer backed NSView.
Posting this just in case this swapping fixes the issue for someone else as well.
Upvotes: 2