Я пытаюсь перенести свое приложение 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
.
@KenThomases Использование NSView только для рендеринга металла является ограничением. И да, я использую makeBackingLayer
для создания слоя. Я дополню вопрос соответствующими фрагментами кода.
@KenThomases Обновленные детали, о которых идет речь.
Какие еще методы NSView
вы игнорируете? Какие еще свойства вы ему задали? Например, вы отменяете -wantsUpdateLayer
, чтобы он возвращал истину?
@KenThomases Я попытался переопределить -wantsUpdateLayer
, чтобы вернуть true, а затем переопределить UpdateLayer
. Но, видимо, это не называется. Я также попытался изменить layerContentsRedrawPolicy
на NSViewLayerContentsRedrawOnSetNeedsDisplay
и вызвать [nsView setNeedsDisplay:YES]
после вызова commit
в буфере команд, но это тоже не запускает рисование.
Поскольку здесь было не так много вещей, которые я мог бы отладить, чтобы найти, где была обнаружена ошибка, поэтому я начал играть с порядком, в котором выполнялись инструкции. И, как выясняется, порядок, в котором вы звоните:
[self setWantsLayer:YES];
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
вызывал проблему. При замене этих двух операторов я начал получать вызов моей функции displayLayer
. Я все еще не мог понять, почему drawRect
не вызывается для многоуровневого NSView.
Публикация этого сообщения на случай, если эта замена решит проблему и для кого-то еще.
Почему вы не используете подкласс
MTKView
? Как вы организовали использованиеCAMetalLayer
для слоя? Вы переопределили-makeBackingLayer
? Если да, покажите этот метод и любое другое место, где вы пытаетесь настроить слой.