-[EAGLContext renderbufferStorage:fromDrawable:] 第二次失败?
Posted
技术标签:
【中文标题】-[EAGLContext renderbufferStorage:fromDrawable:] 第二次失败?【英文标题】:-[EAGLContext renderbufferStorage:fromDrawable:] Failing the second time on? 【发布时间】:2013-08-20 03:39:54 【问题描述】:我正在开发一个 ios openGL ES 应用程序。
我正在做通常的 EAGLView / ES2Render 工作。
启动时,frambuffer 创建成功,使用以下代码:
- (BOOL) createFramebuffers
[EAGLContext setCurrentContext:_mainContext];
// [ A ] On-screen
// 1. Framebuffer
glGenFramebuffers(1, &_mainFramebuffer);
bindFramebuffer(_mainFramebuffer);
// 2. Color buffer
glGenRenderbuffers(1, &_mainColorbuffer);
bindRenderbuffer(_mainColorbuffer);
// Adjust size to view's layer:
CAEAGLLayer* layer = (CAEAGLLayer*)[_view layer];
if (![_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer])
// something went horribly wrong
NSLog(@"-[ES2Renderer createFramebuffers]: Failed to obtain renderbuffer storage from layer!");
return NO;
// Query new size:
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
// Attach to color:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _mainColorbuffer);
// 3. Depth buffer
glGenRenderbuffers(1, &_depthBuffer);
bindRenderbuffer(_depthBuffer);
if (_useStencilBuffer)
// Depth + Stencil
// Allocate storage:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
// Attach to depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
// Attach to stencil:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
else
// Depth only
// Allocate storage:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
// Attachto depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
// 4. Validate the set:
GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
// Something went wrong!
NSLog(@"-[ES2Renderer createFramebuffers]: Failed to make complete framebuffer object: %@",
[self stringFromFramebufferStauts:framebufferStatus]);
return NO;
// [ B ] Off-screen (Render-to-texture)
// 1. Framebuffer
glGenFramebuffers(1, &_transFramebuffer);
bindFramebuffer(_transFramebuffer);
// 2. Depth buffer
glGenRenderbuffers(1, &_transDepthBuffer);
bindRenderbuffer(_transDepthBuffer);
if (_useStencilBuffer)
// Allocate storage:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
// Attach to depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer);
// Attach to stencil:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer);
else
// Allocate storage
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
// Attach to depth:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _transDepthBuffer);
// 3. Textures (color buffers)
GLuint* texPtrs[2] = &_transTexture1, &_transTexture2;
for (NSUInteger i=0; i < 2; i++)
GLuint* texPtr = texPtrs[i];
// Create:
glGenTextures(1, texPtr);
// Bind:
bindTexture2D(*texPtr);
// Configure for pixel-aligned use:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Allocate storage:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// Attach:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texPtr, 0);
framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
// Validate:
if ( framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
// Something went wrong!
NSLog(@"-[ES2Renderer createFramebuffers]: Failed to make complete framebuffer object: %@",
[self stringFromFramebufferStauts:framebufferStatus]);
return NO;
// Final State:
bindFramebuffer(_mainFramebuffer);
bindRenderbuffer(_mainColorbuffer);
bindTexture2D(0);
NSLog(@"-[ES2Renderer createFramebuffers] Succeeded.");
return YES;
不久之后,UIView
的 -layoutSubviews
被调用,我依次执行 -resizeFromLayer:
:
- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
// [ A ] On screen framebuffer
bindFramebuffer(_mainFramebuffer);
// 1. Resize color buffer
bindRenderbuffer(_mainColorbuffer);
if (![_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer])
// Something went wrong
return NO; // <-- SECOND TIME ON, THIS HAPPENS
// Query new size:
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
// 2. Resize depth buffer
bindRenderbuffer(_depthBuffer);
if (_useStencilBuffer)
// (Depth & Stencil)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
else
// (Depth only)
glRenderbufferStorage(GL_FRAMEBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
// ...Validate:
GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
// Something went wrong!
NSLog(@"-[ES2Renderer resizeFromLayer:]: Failed to make complete framebuffer object: %@",
[self stringFromFramebufferStauts:glCheckFramebufferStatus(GL_FRAMEBUFFER)]);
return NO;
// [ B ] Off screen (render-to-terxture) framebuffer
bindFramebuffer(_transFramebuffer);
// 1. Resize depth buffer
bindRenderbuffer(_transDepthBuffer);
if (_useStencilBuffer)
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _backingWidth, _backingHeight);
else
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, _backingWidth, _backingHeight);
// 2. Resize textures
GLuint* texPtrs[2] = &_transTexture1, &_transTexture2;
for (NSUInteger i=0; i < 2; i++)
GLuint* texPtr = texPtrs[i];
// Bind:
bindTexture2D(*texPtr);
// Configure for pixel-aligned use:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Allocate storage:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _backingWidth, _backingHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// Attach:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *texPtr, 0);
// Validate:
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
// Something went wrong!
NSString* statusString = [self stringFromFramebufferStauts:glCheckFramebufferStatus(GL_FRAMEBUFFER)];
NSLog(@"-[ES2Renderer resizeFromLayer:]: Failed to make complete framebuffer object: %@", statusString);
return NO;
bindFramebuffer(_mainFramebuffer);
bindRenderbuffer(_mainColorbuffer);
// Pass new ortho projection to shaders
[self initializeModelViewMatrix];
[self initializeSpriteProgram];
// Set new viewport
glViewport(0, 0, _backingWidth, _backingHeight);
NSLog(@"-[ES2Renderer resizeFromLayer:]: Succeeded.");
return YES;
我所做的一切都没有什么特别之处。我有一个单独的帧缓冲区来渲染场景转换,有两个纹理可以附加到颜色和深度。
第二次调用-renderbufferStorage:fromDrawable:
(-layoutSubviews
-> resizeFromLayer:
),总是失败(返回NO
);在此之前调用glGetError()
不会导致错误,但在返回GL_INVALID_OPERATION
之后立即调用它。
如果我忽略这一点并继续,glGetRenderbufferParameteriv()
仍会为我提供正确的宽度和高度(在 iPhone 5 上分别为 640 和 1136),但glCheckFramebufferStatus()
将返回GL_FRAMEBUFFER_UNSUPPORTED
。
或者,我跳过了上面的 resizeFromLayer:
并将其替换为:
- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
[self destroyFramebuffers];
return [self createFramebuffers];
...但同样的错误仍然存在(-renderStorage:fromDrawable:
失败;这次在-createFramebuffers
内)。
现在,我只返回YES
(我的应用只支持纵向,因此实际上不会发生屏幕尺寸更改),但我真的很想修复它,因为有一天我需要支持横向等。 .
【问题讨论】:
我最近遇到了这个问题,但只是在 iOS 7 设备(不是模拟器)上运行时。不幸的是,我不知道是什么原因造成的,但重新启动设备似乎可以解决问题。虽然很烦人,但不能保证它不会再次发生...... 【参考方案1】:另一个可能的原因是图层的大小太大。此外,请确保您每次都使用新的帧缓冲区和渲染缓冲区。而且你在创造新的之前已经摧毁了你的旧的。
你可以这样删除它们
if let displayFramebuffer = self.displayFramebuffer
var temporaryFramebuffer = displayFramebuffer
glDeleteFramebuffers(1, &temporaryFramebuffer)
self.displayFramebuffer = nil
if let displayRenderbuffer = self.displayRenderbuffer
var temporaryRenderbuffer = displayRenderbuffer
glDeleteRenderbuffers(1, &temporaryRenderbuffer)
self.displayRenderbuffer = nil
【讨论】:
【参考方案2】:renderbufferStorage:fromDrawable:
失败的一个可能原因是_mainContext
不是当时的当前上下文。尽管看起来没有其他上下文可以窃取“当前”状态,但我建议在任何gl
或EAGL
代码之前调用[EAGLContext setCurrentContext:_mainContext]
操作与该上下文关联的对象(例如,在@的开头987654326@方法)。
【讨论】:
【参考方案3】:Josh Bernfeld 的回答启发了我。我检查了MyView
的大小,它的边界是CGRect.zero
。 CAEAGLLayer
也是如此。
对我来说,使用非零 CGRect
初始化 MyView
解决了这个问题。
希望它对你有用。
【讨论】:
以上是关于-[EAGLContext renderbufferStorage:fromDrawable:] 第二次失败?的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL中Framebuffer和Renderbuffer的概念和区别是啥?