gpt4 book ai didi

ios - 如何重置 opengl es 上下文或重新绑定(bind)框架

转载 作者:行者123 更新时间:2023-11-29 10:38:08 25 4
gpt4 key购买 nike

目前,我有一个使用 OpenGL ES 1.0 渲染所有内容的 map View 对象。这是 View 初始化代码:

- (void)initGLES {
CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if(!context || ![EAGLContext setCurrentContext:context] || ![self createFramebuffer])
return;
}

- (BOOL)createFramebuffer {
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);

glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>)self.layer];
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);

glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);

if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
// NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}

GLuint sampleColorRenderbuffer, sampleDepthRenderbuffer;

glGenFramebuffers(1, &sampleFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, sampleFramebuffer);

glGenRenderbuffers(1, &sampleColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleColorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, backingWidth, backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, sampleColorRenderbuffer);

glGenRenderbuffers(1, &sampleDepthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, sampleDepthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, backingWidth, backingHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sampleDepthRenderbuffer);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));

return YES;
}

当我们在整个应用程序中只有一个 map View 时,这项工作很好。但是当我们创建多个 map View 时,例如:我们在主屏幕上创建第一个 map View 。然后我们导航到子屏幕。这里我们创建另一个 map View 。但是当我们导航回主屏幕时,主屏幕的 map View 不再有效。这是因为我们已经创建了另一个上下文并将所有 opengl 函数绑定(bind)到那里的新缓冲区。因此,不是将内容绘制到旧 map View ,而是将所有内容都绘制到屏幕上不再可见的最新 View 。

有些人向我们评论说我们应该:

  1. 仅创建 1 个上下文并为每个 View 重新绑定(bind)缓冲区
  2. 为每个屏幕创建多个上下文,并在每次更换屏幕时重置上下文

所以我想知道在这种情况下我应该怎么做?我应该如何更改我们在这里更改 opengl 的 init 方法的方式?

非常感谢。

============================================= ==

更新:这是我在解除分配时释放资源的代码:

glDeleteRenderbuffersOES(1, &viewRenderbuffer);
glDeleteRenderbuffersOES(1, &viewFramebuffer);
glDeleteRenderbuffersOES(1, &sampleFramebuffer);
context = nil;
[EAGLContext setCurrentContext:nil];

最佳答案

设置当前上下文对您不起作用吗?一旦切换到新 View ,您应该做的就是使用正确的上下文调用 [EAGLContext setCurrentContext:context]

例如,如果您创建了一个将绘制 openGL 内容的自定义 View ,您很可能会创建一个帧缓冲区、一个渲染缓冲区和一个上下文。如果您随后创建此 View ,您可以正常绘制它(就像您已经做的那样)。然后,如果您要创建此 View 的另一个实例并将其添加为 subview ,您需要做的就是:

  • 设置第一个上下文
  • 绘制场景
  • 出席
  • 设置第二个上下文
  • 绘制场景
  • 出席
  • ...

在你的情况下,它几乎是一样的,只是它更容易。当您想绘制到另一个 View 时,只需设置另一个上下文...

编辑:清理和上下文

所以这里似乎是个大问题。正如在问题编辑中发布的那样,一旦释放 View 对象,缓冲区也会被删除,上下文设置为 nil ([EAGLContext setCurrentContext:nil])。这将从当前线程中删除上下文,并且不再执行任何 openGL 代码。

在这种情况下,问题本身是当此方法执行时我们根本不知道当前设置的上下文是什么,它可能是在其上创建缓冲区的上下文或“其他”上下文。所以最快的解决方案是像这样修改它:

    EAGLContext *lastContext = [EAGLContext currentContext];
EAGLContext *thisContext = context; // get the context of this view
[EAGLContext setCurrentContext:thisContext];

// do the deletion and cleanup

glDeleteRenderbuffersOES(1, &viewRenderbuffer);
glDeleteRenderbuffersOES(1, &viewFramebuffer);
glDeleteRenderbuffersOES(1, &sampleFramebuffer);
context = nil;

if(lastContext == thisContext)
{
// since there was no other context set just destroy this one
[EAGLContext setCurrentContext:nil];
}
else
{
// there was another context previously set so let us just set it back
[EAGLContext setCurrentContext:lastContext];
}

试试这个代码,看看它是否解决了你的问题。

因此,对这个特定问题进行一般性评论:

如前所述,您可以同时使用多个 View ,它们包含自己的上下文,但都在同一个线程上(因为它们是可呈现的,将是主线程,所以您不能使用其他 View )。此 View 上的操作必须以一种或另一种方式序列化,但要同时使用这两种方式,您需要将当前上下文设置为您将要使用的上下文。这意味着每个执行的代码块和将使用一些与上下文相关的代码之前必须设置正确的上下文。这意味着如果您要调用一系列 3 种方法来处理单个 View ,您需要在第一次调用之前设置上下文。另一方面,如果您对它们中的每一个都使用了 performSelector: 方法,那么为了安全起见,您需要在每个被调用的方法中设置上下文:由于可能的多线程,可能会执行另一个方法在同一线程上的其他调用之间。

因此,当您能够理解上面写的所有内容时,您会问自己“如何以及何时正确清理上下文中的项目?”。你至少有两种方法,一种是上面描述的,但不是很好,它看起来像是一个 hack。另一种方法是不显式调用清理(例如在 dealloc 方法中),而是设置一个不再需要此 View 的特定标志。设置此标志后, View 仍应执行绘图、呈现和所有其他操作,但一旦进入这些刷新方法之一,您将调用清理而不是刷新 View ,然后将 View 与所有所有者(如计时器)分离,显示链接和 super View 。因此,通过这种方式,您可以保留所有其他逻辑,没有黑客攻击,甚至可以从另一个线程调用此调用。

为什么这通常不是问题以及为什么告诉您宁愿使用单个上下文是因为上下文主要用于具有多个线程。每个线程都需要自己的上下文(但在同一个线程上有多个上下文仍然可以)所以当处理每个线程的单个上下文时,您可以仅在创建上下文时(在正确的线程上)设置当前上下文,然后一旦不再需要上下文(清理),设置为 nil

我希望这是有道理的...

关于ios - 如何重置 opengl es 上下文或重新绑定(bind)框架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25882617/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com