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, в которой говорится следующее:

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.

Итак, в соответствии с этим мне даже не нужно устанавливать делегата в моем случае, и я уже реализую функцию drawRect в MyNSView. По-прежнему его не называют.

Есть ли что-то еще, что нужно сделать?

Спасибо!

Редактировать: Итак, я исправил ошибку компиляции, заставив свой уровень следовать протоколу CALayerDelegate, но все равно я не получаю никаких вызовов drawLayer или 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;
}

функция инициализации

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

Я реализовал все функции рисования, чтобы проверить, не сработает ли какая-либо из них, но я не получаю вызова ни одной из этих функций.

Для рисования контента в NSView я рисую закадровые ресурсы, получаю drawable из CALayer NSView и вызываю presentDrawable перед фиксацией на commandBuffer.

Почему вы не используете подкласс MTKView? Как вы организовали использование CAMetalLayer для слоя? Вы переопределили -makeBackingLayer? Если да, покажите этот метод и любое другое место, где вы пытаетесь настроить слой.

Ken Thomases 29.10.2018 13:30

@KenThomases Использование NSView только для рендеринга металла является ограничением. И да, я использую makeBackingLayer для создания слоя. Я дополню вопрос соответствующими фрагментами кода.

user007 29.10.2018 13:49

@KenThomases Обновленные детали, о которых идет речь.

user007 29.10.2018 13:59

Какие еще методы NSView вы игнорируете? Какие еще свойства вы ему задали? Например, вы отменяете -wantsUpdateLayer, чтобы он возвращал истину?

Ken Thomases 29.10.2018 16:41

@KenThomases Я попытался переопределить -wantsUpdateLayer, чтобы вернуть true, а затем переопределить UpdateLayer. Но, видимо, это не называется. Я также попытался изменить layerContentsRedrawPolicy на NSViewLayerContentsRedrawOnSetNeedsDisplay и вызвать [nsView setNeedsDisplay:YES] после вызова commit в буфере команд, но это тоже не запускает рисование.

user007 30.10.2018 05:03
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
5
824
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку здесь было не так много вещей, которые я мог бы отладить, чтобы найти, где была обнаружена ошибка, поэтому я начал играть с порядком, в котором выполнялись инструкции. И, как выясняется, порядок, в котором вы звоните:

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

вызывал проблему. При замене этих двух операторов я начал получать вызов моей функции displayLayer. Я все еще не мог понять, почему drawRect не вызывается для многоуровневого NSView.

Публикация этого сообщения на случай, если эта замена решит проблему и для кого-то еще.

Другие вопросы по теме