drawRect未被NSView的图层支持图形调用



我正在尝试将我的Opengl应用程序迁移到Metal,并且我正在使用CAMetalLayer实现Metal。我在继承的NSView类对象上设置了以下属性:

self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
[self setWantsLayer:YES];

我已经检查了SO上的其他答案,比如NSView子类-drawRect:不叫

因此,我尝试按照上面答案中的建议分配代表,类似于

[self.layer setDelegate:self];

我得到以下编译错误:

Cannot initialize a parameter of type 'id<CALayerDelegate> _Nullable' with an lvalue of type 'MyNSView *'

此外,我还看到了在https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/SettingUpLayerObjects/SettingUpLayerObjects.html,声明如下:

对于具有自定义内容的层支持视图,您应该继续替代视图的绘制方法。图层背景视图自动使自己成为其层的委托并实现所需的委托方法,并且您不应该更改配置相反,您应该实现视图的drawRect:绘制内容的方法。

因此,根据这一点,我甚至不必在我的情况下设置委托,并且我已经在MyNSView中实现了drawRect函数。但它仍然没有被调用。

还有什么需要做的吗?

谢谢!

编辑:因此,我通过使我的层遵循协议CALayerDelegate来修复编译错误,但仍然没有得到任何对drawLayerdrawRect的调用。

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;
}

初始化函数

self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
[self setWantsLayer:YES];
[self.layer setDelegate:self];

绘制函数

- (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];
}

我已经实现了所有的draw函数,以检查它们中是否有任何一个被命中,但我没有收到对这些函数的调用。

为了将内容绘制到NSView,我绘制到屏幕外资源,并从NSView的CALayer获取drawable,并在commandBuffer上提交之前调用presentDrawable

由于这里没有太多可以调试的东西来找到错误的引入位置,所以我开始按照指令的执行顺序进行操作。事实证明,你调用的顺序是:

[self setWantsLayer:YES];
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;

是造成问题的原因。在交换这两条语句后,我开始接收对displayLayer函数的调用。我仍然不明白为什么drawRect没有被调用用于层支持的NSView。

发布这个只是为了以防万一这种交换也为其他人解决了这个问题。

最新更新