8

他们建议

使用 GCD 时,使用专用的串行队列向 OpenGL ES 分发命令;这可以用来替换传统的互斥体模式。

我不明白这个建议。有一个我无法解决的冲突:

当应用的应用委托接收到-applicationWillResignActive调用时,它必须立即停止调用任何 OpenGL 函数

如果应用返回后继续调用OpenGL函数-applicationWillResignActive,应用会崩溃

如果我按照 Apple 的建议在串行后台队列中调用 OpenGL 函数,我将面临这个看似无法解决的问题:

1)收到后-applicationWillResignActive我必须立即停止调用任何进一步的 OpenGL 函数。

2)但是由于串行队列在后台处理一段代码,有时代码块执行完after -applicationWillResignActive返回,应用程序崩溃。

这是显示并发“块”的插图。主线程收到完全停止消息,并且必须阻止对 OpenGL ES 的进一步调用。但不幸的是,这些发生在后台队列中,在处理块时无法停止:

|_____main thread: "STOP calling OpenGL ES!"_____|
 _____|_____drawing queue: "Draw!"_____|_____drawing queue: "Draw!"_____|

从技术上讲,我发现无法立即停止后台队列并避免在后台进一步调用 OpenGL。提交的代码块一旦运行就会继续运行。

我找到的唯一解决方案是不在后台调用 OpenGL ES 函数。相反,在主线程上调用它们以保证在应用程序失去对 GPU 的访问权后永远不会调用它们。

因此,如果可以在后台调用 OpenGL ES 函数,那么如何确保在应用退出活动后它们永远不会被调用?

4

2 回答 2

7

只需等待applicationWillResignActive队列使用调度组或类似机制完成所有排队操作。

您可以在文档中找到一个示例:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

// Add a task to the group
dispatch_group_async(group, queue, ^{
   // Some asynchronous work
});

// Do some other work while the tasks execute.

// When you cannot make any more forward progress,
// wait on the group to block the current thread.
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

// Release the group when it is no longer needed.
dispatch_release(group);
于 2013-11-02T12:08:02.270 回答
4

除了 Sven 关于使用调度组的建议之外,我过去通过使用同步调度到您的渲染串行队列中走了一条更简单的路线-applicationWillResignActive

// Tell whatever is generating rendering operations to pause

dispatch_sync(openGLESSerialQueue, ^{
    [EAGLContext setCurrentContext:context];
    glFinish();

    // Whatever other cleanup is required
});

此处的同步调度将阻塞,直到串行队列中的所有操作都完成,然后它将在该块内运行您的代码。如果你有一个计时器或其他触发新渲染块的源,我会先暂停它,以防它把最后一个块放在队列中。

作为一项额外的安全措施,我使用glFinish()哪些阻塞直到所有渲染在 GPU 上完成(PowerVR GPU 喜欢尽可能延迟渲染)。对于运行时间极长的渲染帧,我偶尔会看到由于帧渲染而导致的崩溃,即使在所有负责任的 OpenGL ES 调用完成后仍然会发生崩溃。这可以防止这种情况。

我在几个不同的应用程序中使用它,它几乎消除了在转换到后台时由于渲染而导致的崩溃。我知道其他人使用与我的 GPUImage 库类似的东西(它也使用串行后台调度队列进行渲染),它似乎对他们很有效。

您必须小心的一件事是,使用此解决方案或任何其他在后台进程完成之前阻塞的解决方案是,如果您不小心,您就会陷入死锁。如果您在后台队列的块内有任何同步调度回主队列,您将想要删除这些或尝试使它们异步。如果他们在主队列上等待,而主队列在后台队列上等待,你会很好地冻结。通常,避免这种情况非常简单。

于 2013-11-04T20:08:42.857 回答