Возможно ли для слоя NSView
правильно выполнить рендеринг OpenGL в drawRect:
, или необходимо использовать NSOpenGLLayer
/ CAOpenGLLayer
?До недавнего времени мне не нужно было беспокоиться об этом, я просто использовал представление без слоев.Но, как указано в примечаниях к выпуску AppKit для 10.14:
Windows в приложениях, связанных с macOS 10.14 SDK, отображаются с помощью Core Animation, когда приложение работает в macOS 10.14.
Чтобы показать, как это нарушает мой рендеринг, я собрал пример приложения с кодом, показанным ниже.Если проект запускается в операционной системе до Mojave или создается с использованием SDK до 10.14, то представление отображает сплошной красный цвет, который остается таким же при изменении размера окна.Но если проект собран с использованием SDK 10.14 и запущен под macOS 10.14, то при изменении размера окна представление безумно мерцает, и когда вы прекращаете изменение размера, представление может отображать или не отображать что-либо.
Вотпапка проекта .Кроме того, вот приложение , построенное под High Sierra, но с двумя экземплярами вида, один отмечен слоистым фоном в кончике.
- AppDelegate.h -
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (strong) NSOpenGLPixelFormat* pixelFormat;
@end
- AppDelegate.m -
#import "AppDelegate.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (instancetype) init
{
self = [super init];
if (self != nil)
{
NSOpenGLPixelFormatAttribute attribs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
NSOpenGLPFAColorSize,
32,
0
};
_pixelFormat = [[NSOpenGLPixelFormat alloc]
initWithAttributes: attribs];
NSLog(@"Got pixel format %@", _pixelFormat);
}
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self.window makeKeyAndOrderFront: self];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
}
@end
- MyGLView.h -
#import <Cocoa/Cocoa.h>
@class AppDelegate;
@interface MyGLView : NSView
@property (weak) IBOutlet AppDelegate* appDelegate;
@end
- MyGLView.m -
#import "MyGLView.h"
#import "AppDelegate.h"
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
@interface MyGLView ()
@property (strong) NSOpenGLContext* openGLContext;
@end
@implementation MyGLView
- (void) awakeFromNib
{
self.openGLContext = [[NSOpenGLContext alloc]
initWithFormat: self.appDelegate.pixelFormat shareContext: nil];
self.openGLContext.view = self;
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(resized:)
name: NSViewFrameDidChangeNotification
object: self];
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
- (void) resized: (NSNotification*) note
{
[self.openGLContext update];
}
- (void) drawRect:(NSRect) dirtyRect
{
[self.openGLContext makeCurrentContext];
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
[self.openGLContext flushBuffer];
}
@end
Обновление:
Похоже, что то, что я хотел сделать, не может быть сделано.Поэтому я выбираю NSOpenGLView
, который использует закрытый класс _NSOpenGLViewBackingLayer
для своего слоя, или NSOpenGLLayer
.
. Я нахожу NSOpenGLLayer
сбивающим с толку, потому что, хотя кажется, что он рендерится на экране,это на самом деле рендеринг в FBO.И даже если вы начинаете с пиксельного формата, который поддерживает двойную буферизацию, вы действительно выполняете рендеринг с одной буферизацией.Напротив, NSOpenGLView
отображается для рендеринга в основной буфер кадров, если хотите, с двойной буферизацией.