【发布时间】:2015-10-10 05:26:59
【问题描述】:
我有一个 OpenGL 应用程序,我在 2011 MacBookPro 上的 Xcode 7.0.1 中运行。
我最近从 OS 10.10 升级到 10.11 El Capitan,现在带有 NSViews 的窗口抛出此错误(部署目标 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 上运行良好且没有错误。唯一的代码区别是NSViewdrawRect方法中的图形上下文是通过以下方式获得的:
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
这是这个特定窗口的图像:
行为不一致。例如,计算过程中的几个步骤中的每一步都应显示此状态窗口,但看起来只显示其他每个窗口(例如,步骤 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 文件如下所示:
此窗口中有一个自定义进度指示器(以两个白色方块为界),它是不可见的,但它就在那里。
显示此窗口的示例代码如下所示:
[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);,这将视图完全变成了应有的红色。
片段着色器实际上应该是从纹理中采样的,因此我将这个纹理与所有 (255, 0, 0, 255) 一起加载以通过在片段着色器末尾放置一个简单的采样语句来测试采样:
fragColor = texture(Texture, texCoord).rgba;
但没有写入任何内容,因此将纹理加载到着色器中肯定有问题。我现在正在努力。
【问题讨论】:
-
如果视图是 OpenGL 视图,您使用
CGContext做什么?您是否尝试过按照建议设置CG_CONTEXT_SHOW_BACKTRACE环境变量,如果是,回溯是什么? -
@Ken Thomases 我添加了更多细节,包括示例回溯。浏览 Apple 论坛后,我认为这实际上可能是 Xcode 7 的问题。
-
回溯表明问题出在方法
-[StatusWindowController updateStatusProgress:]中,您没有显示。显示。另外,您的视图是否有图层支持? -
@Ken Thomases 更改 [StatusWindowController updateStatusProgress] 中的一行代码似乎已经打破了日志堵塞。我还没有完全解决我所有的问题,但我现在已经够远了,我确信我可以从这里到达那里。请发布一个我可以接受的答案。
-
我很高兴您解决了部分问题,但是没有看到您的
-updateStatusProgress:方法以及修复了哪些更改,我不知道我的答案可能是什么。
标签: opengl nsview osx-elcapitan