OS 10.11中的NSView El Capitan投掷错误

时间:2015-10-05 19:07:45

标签: opengl nsview osx-elcapitan

我有一个OpenGL应用程序,我在2011年的MacBookPro上运行Xcode 7.0.1。

我最近从OS 10.10升级到10.11 El Capitan,现在带有NSView的Windows正在抛出此错误(部署目标10.11,10.10或10.9):

invalid context 0x0. If you want to see the backtrace, please set     
CG_CONTEXT_SHOW_BACKTRACE environmental variable.

在NSView drawRect方法中,我使用以下语句获取CGContext:

CGContextRef context = [[NSGraphicsContext currentContext] CGContext];

另外,我的GLSL 4.1着色器不再向OpenGL窗口写任何东西。

在升级到El Capitan之前,这段代码没有给我任何问题,并且(几乎)完全相同的代码在2012 MacBookPro,OS 10.10,Xcode 6.4,部署目标10.9或10.10上运行良好而没有错误。唯一的代码区别是NSView drawRect方法中的图形上下文是通过以下方式获得的:

CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];

我认为我的问题可能是有问题的计算机是2011 MacBookPro,而Metal需要2012或更高版本。我没有使用Metal,但我仍然认为这可能是一个因素。

计算机是否会产生错误的问题,或者我是否应该使用其他语法来获取图形上下文?

我不知道为什么GLSL着色器不再工作了。那里有什么想法吗?

应用程序主窗口是一个OpenGL视图,但我在弹出的用户界面窗口,自定义按钮和各种其他用途中使用了许多NSView。下面是最简单的窗口之一的完整代码。在我升级到EC和Xcode 7.0.1之前,这一切都运行良好。

@implementation StatusView

// **************************** Init **********************************

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {

    }
    return self;
}

// ************************** Draw Rect ********************************

- (void)drawRect:(NSRect)dirtyRect
{
    if(windowManager)
    {
        CGContextRef context = [[NSGraphicsContext currentContext] CGContext];

        // Define a color space variable
        CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();            

        // Get the bounds
        NSRect nsBounds = [self bounds];

        // Set the graphics bounds
        CGRect cgBounds = NSRectToCGRect(nsBounds);                               

        // ****** Draw the Background in Transparent Black

        CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
        CGContextFillRect(context, cgBounds);

        // Set the text matrix.
        CGContextSetTextMatrix(context, CGAffineTransformIdentity);

        // Create a color that will be added as an attribute to the attrString for normal text.
        CGFloat textColorComponents[] = { 1.0, 1.0, 1.0, 1.0 };
        CGColorRef whiteColor = CGColorCreate(rgbColorspace, textColorComponents);

        // Create a color that will be added as an attribute to the attrString for invisible text.
        CGFloat invisibleTextColorComponents[] = { 0.0, 0.0, 0.0, 0.0 };
        CGColorRef invisibleColor = CGColorCreate(rgbColorspace, invisibleTextColorComponents);

        // Create a font for normal text.
        CFStringRef stringFontName = CFSTR("AppleCasual");
        CTFontRef stringFont = CTFontCreateWithName(stringFontName, 18.0, NULL);

        CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
        CGContextFillRect(context, cgBounds);

        // ************* Box the Window in Gray ***************************

        CGContextMoveToPoint(context, 0.0,1.0);
        CGContextAddLineToPoint(context,0.0, cgBounds.size.height - 1.0);
        CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, cgBounds.size.height - 1.0);
        CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, 1.0);
        CGContextAddLineToPoint(context,0.0, 1.0);
        CGContextSetLineWidth(context, 2.0);
        CGContextSetRGBStrokeColor(context, 0.7, 0.7, 0.7, 1.0);
        CGContextStrokePath(context);

        // *********** Draw String1

        CGPoint endingTextPoint;

        if(windowManager->statusTextBox1String)
        {
            // Create a mutable attributed string with a max length of 0 for normal text.
            CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);

            // Create a path which will bound the area where you will be drawing text.
            CGMutablePathRef invisibleTextPath = CGPathCreateMutable();

            // Create a path which will bound the area where you will be drawing text.
            CGMutablePathRef string1TextPath = CGPathCreateMutable();

            // Initialize a string.
            CFStringRef textString = (__bridge CFStringRef)windowManager->statusTextBox1String;
            CFIndex textStringLength = CFStringGetLength (textString);

            // Measure the string length
            CGRect invisibleTextBounds = CGRectMake(0.0, 0.0, cgBounds.size.width, 30.0);
            CGPathAddRect(invisibleTextPath, NULL, invisibleTextBounds);

            // Copy the textString into attrString
            CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), textString);

            // Set the color and font.
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, invisibleColor);
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);

            // Create the framesetter with the attributed string.
            CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);

            CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), invisibleTextPath, NULL);

            // Draw the specified frame in the given context.
            CTFrameDraw(frame, context);

            endingTextPoint = CGContextGetTextPosition(context);

            // Draw the Text

            // Set a rectangular path.
            CGRect textBounds = CGRectMake((cgBounds.size.width / 2.0) - (endingTextPoint.x / 2.0), 140.0, cgBounds.size.width, 30.0);
            CGPathAddRect(string1TextPath, NULL, textBounds);

            // Copy the textString into attrString
            CFAttributedStringReplaceString (attrString, CFRangeMake(0, textStringLength), textString);

            // Set the color and fontof the first chars.
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, whiteColor);
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);

            // Create the framesetter with the attributed string.
        framesetter = CTFramesetterCreateWithAttributedString(attrString);

            // Create a frame.
            frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), string1TextPath, NULL);

            // Draw the specified frame in the given context.
            CTFrameDraw(frame, context);

            CFRelease(string1TextPath);
            CFRelease(invisibleTextPath);
            CFRelease(frame);
            CFRelease(framesetter);
            CFRelease(attrString);
        }

        // ****************** Draw String 2

        if(windowManager->statusTextBox2String)
        {
            CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f);
            CGContextFillRect(context, cgBounds);

            // ********** Box the Window in Gray ***********************

            CGContextMoveToPoint(context, 0.0,1.0);
            CGContextAddLineToPoint(context,0.0, cgBounds.size.height - 1.0);
            CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, cgBounds.size.height - 1.0);
            CGContextAddLineToPoint(context,cgBounds.size.width - 2.0, 1.0);
            CGContextAddLineToPoint(context,0.0, 1.0);
            CGContextSetLineWidth(context, 2.0);
            CGContextSetRGBStrokeColor(context, 0.7, 0.7, 0.7, 1.0);
            CGContextStrokePath(context);

            // Create a mutable attributed string with a max length of 0 for normal text.
            CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);

            // Create a path which will bound the area where you will be drawing text.
            CGMutablePathRef invisibleTextPath = CGPathCreateMutable();

            // Create a path which will bound the area where you will be drawing text.
            CGMutablePathRef string2TextPath = CGPathCreateMutable();

            // Initialize a string.
            CFStringRef textString = (__bridge CFStringRef)windowManager->statusTextBox2String;
            CFIndex textStringLength = CFStringGetLength (textString);

            // Measure the string length
            CGRect invisibleTextBounds = CGRectMake(0.0, 0.0, cgBounds.size.width, 130.0);
            CGPathAddRect(invisibleTextPath, NULL, invisibleTextBounds);

            // Copy the textString into attrString
            CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), textString);

            // Set the color and font
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, invisibleColor);
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);

            // Create the framesetter with the attributed string.
            CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString);

            CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), invisibleTextPath, NULL);

            // Draw the specified frame in the given context.
            CTFrameDraw(frame, context);

            endingTextPoint = CGContextGetTextPosition(context);

            // Draw the Text

            // Set a rectangular path.
            CGRect textBounds = CGRectMake((cgBounds.size.width / 2.0) - (endingTextPoint.x / 2.0), 100.0, cgBounds.size.width, 30.0);
            CGPathAddRect(string2TextPath, NULL, textBounds);

            // Copy the textString into attrString
            CFAttributedStringReplaceString (attrString, CFRangeMake(0, textStringLength), textString);

            // Set the color and fontof the first chars.
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTForegroundColorAttributeName, whiteColor);
            CFAttributedStringSetAttribute(attrString, CFRangeMake(0, textStringLength), kCTFontAttributeName, stringFont);

            // Create the framesetter with the attributed string.
            framesetter = CTFramesetterCreateWithAttributedString(attrString);

            // Create a frame.
            frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), string2TextPath, NULL);

            // Draw the specified frame in the given context.
            CTFrameDraw(frame, context);

            CFRelease(string2TextPath);
            CFRelease(invisibleTextPath);
            CFRelease(frame);
            CFRelease(framesetter);
            CFRelease(attrString);
        }

        CFRelease(stringFont);
        CFRelease(whiteColor);
        CFRelease(invisibleColor);

        CGContextFlush(context);
    }

    return;
}

@end

这是此特定窗口的图像:

enter image description here

行为不一致。例如,此状态窗口应在计算过程中的每个步骤中出现,但看起来只显示每个其他窗口(例如,步骤2,4和6,但不是1,3或5)。

生成了大量错误,但这是其中一个错误的示例回溯:

Oct  9 10:23:30  WispFractals3D[746] <Error>: CGContextRestoreGState: invalid context 0x0. Backtrace:
  <-[StatusWindowController updateStatusProgress:]+228>
   <-[AppController updateStatusProgress:]+64>
    <-[AppController runTheFractal:]+804>
     <_os_activity_initiate+75>
      <-[NSApplication sendAction:to:from:]+460>
       <-[NSMenuItem _corePerformAction]+336>
        <-[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:]+114>
         <_os_activity_initiate+75>
          <-[NSMenu performActionForItemAtIndex:]+131>
           <-[NSMenu _internalPerformActionForItemAtIndex:]+35>
            <-[NSCarbonMenuImpl       _carbonCommandProcessEvent:handlerCallRef:]+107>
             <NSSLMMenuEventHandler+708>
              <_ZL23DispatchEventToHandlersP14EventTargetRecP14OpaqueEventRefP14HandlerCallRec+1231>
               <_ZL30SendEventToEventTargetInternalP14OpaqueEventRefP20OpaqueEventTargetRefP14HandlerCallRec+404>
                <SendEventToEventTarget+40>
                 <_ZL18SendHICommandEventjPK9HICommandjjhPKvP20OpaqueEventTargetRefS5_PP14OpaqueEventRef+411>
                  <SendMenuCommandWithContextAndModifiers+59>
                   <SendMenuItemSelectedEvent+188>
                    <_ZL19FinishMenuSelectionP13SelectionDataP10MenuResultS2_+96>
                     <_ZL14MenuSelectCoreP8MenuData5PointdjPP13OpaqueMenuRefPt+711>
                      <_HandleMenuSelection2+460>
                       <_NSHandleCarbonMenuEvent+277>
                        <_DPSNextEvent+1906>
                         <-[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+454>
                          <-[NSApplication run]+682>
                           <NSApplicationMain+1176>
                            <main+34>

.xib文件如下所示:

enter image description here

这个窗口中有一个自定义进度指示器(由两个白色方块限定)是不可见的,但它就在那里。

显示此窗口的示例代码如下所示:

    [self showStatusWindowWithString1:@"Calculation Complete" String2:timeMessage ButtonOn:YES AbortOn:NO ProgressOn:NO ProgressMax:100.0 Title:@"Fractal Run Time"];

并且showStatusWindow方法的代码是:

- (void)showStatusWindowWithString1:(NSString *)string1 String2:(NSString *)string2 ButtonOn:(BOOL)buttonon AbortOn:(BOOL)aborton ProgressOn:(BOOL)progresson ProgressMax:(double)progressmax Title:(NSString *)title
{
    statusWindowTitle = title;
    statusTextBox1String = string1;
    statusTextBox2String = string2;
    statusButtonOn = buttonon;
    abortOn = aborton;
    statusProgressOn = progresson;
    statusProgressMax = progressmax;

    if (!statusWindowController)
    {
        statusWindowController = [[StatusWindowController alloc] initWithWindowNibName:@"StatusWindow" Manager:self];
    }

    [[statusWindowController window] setTitle:statusWindowTitle];

    [statusWindowController showWindow:self];
    [fileStatusWindow makeKeyAndOrderFront:self];

    appDelegate->fileStatusWindowOpenFlag = YES;
    [appDelegate checkFlags];

    return;
}

Ken Thomases诊断出回溯表明在[StatusWindowController updateStatusProgress:]中生成了无效的上下文错误(这会更新自定义进度指示器)。

我改变了这个方法:

- (void) updateStatusProgress:(double)statusprogress
{
    [statusProgressIndicator setDoubleValue:statusprogress];
    [statusProgressIndicator drawRect:[statusProgressIndicator bounds]];
}

要:

- (void) updateStatusProgress:(double)statusprogress
{
    [statusProgressIndicator setDoubleValue:statusprogress];
    [statusProgressIndicator setNeedsDisplay:YES];
}

在我看来,错误消息是在多个地方生成的,但是这一个更改停止了所有错误消息。

我的下一个问题是,状态窗口(上图)每次都没有显示,有时只显示。再一次,这在Yosemite,Xcode 6.4中都运行良好。

我现在发现当状态窗口没有显示时,我可以通过模态运行来显示它。奇怪。

我正在解决的最后一个问题是GLSL着色器没有像他们应该那样写入OpenGL视图。我通过在片段着色器的末尾添加一行来测试着色器是否正在加载和运行:fragColor = vec4(1.0,0.0,0.0,1.0);,它将视图完全变为红色。< / p>

碎片着色器实际应该是从纹理中采样,所以我用全部(255,0,0,255)加载这个纹理,通过在片段着色器末尾放置一个简单的采样语句来测试采样:

fragColor = texture(Texture, texCoord).rgba;

但没有任何内容被写入,因此将纹理加载到着色器中一定存在问题。我现在正在努力。

2 个答案:

答案 0 :(得分:0)

我刚刚快速构建了一个我之前未在EC下重建过的应用程序。这一切都很好。

也许您可以发布更多细节。代码和崩溃点?

答案 1 :(得分:0)

导致“无效上下文0x0”消息的问题是您直接调用-drawRect:。这从未有效。在框架设置了适当的图形上下文之后,框架会调用-drawRect:,例如坐标转换,将图形放在窗口中的正确位置,并剪切到视图的边界。如果你在其他时间调用它,那么就没有设置任何上下文,也没有任何好处。

如果必须立即重绘,可以调用其中一种-display...方法。

但是,通常最好按照您现在的步骤进行操作:只需将视图标记为需要显示,然后让Cocoa在适当的时候重新绘制它。

您应该针对其他问题发布单独的问题。