Заставить OpenGL сосуществовать с Core Animation в macOS - PullRequest
0 голосов
/ 01 февраля 2019

Возможно ли для слоя 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 отображается для рендеринга в основной буфер кадров, если хотите, с двойной буферизацией.

...