如何从iOS上的Grand Central Dispatch Queue异步绘制到GLKit的OpenGL ES上下文

杰布

我试图将冗长的OpenGL绘制操作移至GCD队列中,以便在GPU磨削的同时完成其他工作。我会更愿意倾向于与GCD要做到这一点对增加实际线程我的应用程序。从字面上看,我想做的就是

  • 不要阻塞glDrawArrays()调用,因此当GL渲染变得非常慢时,UI的其余部分可以保持响应。
  • 当我们无论如何都没有完成它们时,请丢弃glDrawArrays()调用(不要建立只会不断增长的帧队列)

在苹果网站上,文档说:

GCD和NSOperationQueue对象可以在自己选择的线程上执行任务。他们可以创建专门用于该任务的线程,或者可以重用现有线程。但是无论哪种情况,您都不能保证哪个线程执行任务。对于OpenGL ES应用程序,这意味着:

  • 每个任务必须在执行任何OpenGL ES命令之前设置上下文。
  • 访问同一上下文的两个任务可能永远不会同时执行。
  • 每个任务在退出前都应清除线程的上下文。

听起来很简单。

为了简单起见,我首先从新的Apple模板的骨干版本开始,该版本出现在“ OpenGL ES”游戏的“新项目”对话框中。实例化,编译和运行它时,应该看到两个多维数据集在灰色的字段上旋转。

在该代码中,我添加了一个GCD队列。从以下内容的接口部分开始ViewController.m

dispatch_queue_t openGLESDrawQueue;

然后在ViewController viewDidLoad以下位置进行设置

openGLESDrawQueue = dispatch_queue_create("GLDRAWINGQUEUE", NULL);

最后,我对drawInRectCADisplayLink最终触发方法进行了非常小的更改

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
void (^glDrawBlock)(void) = ^{
    [EAGLContext setCurrentContext:self.context];
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArrayOES(_vertexArray);

    // Render the object with GLKit
    [self.effect prepareToDraw];

    glDrawArrays(GL_TRIANGLES, 0, 36);

    // Render the object again with ES2
    glUseProgram(_program);

    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);

    glDrawArrays(GL_TRIANGLES, 0, 36);
};
dispatch_async(openGLESDrawQueue, glDrawBlock);
}

这是行不通的。图纸变得疯狂。但是,使用相同的块进行绘制dispatch_sync()可以很好地工作。

让我们仔细检查一下苹果的列表:

  • 每个任务必须在执行任何OpenGL ES命令之前设置上下文。
    • 好的。我正在设置上下文。它的Objective-C对象指针的生存期比该块还要长,因此应该将其关闭。另外,我可以在调试器中检查它们,它们很好。另外,当我从dispatch_sync绘制时,它也可以工作。因此,这似乎不是问题。
  • 访问同一上下文的两个任务可能永远不会同时执行。
    • 设置GL上下文后,唯一访问该上下文的代码就是此方法中的代码,而该方法又位于此块中。由于这是一个串行队列,因此无论如何一次都只能绘制一个实例。此外,如果添加一个synchronized(self.context){}块,它不会解决任何问题。另外,在其他绘图速度很慢的代码中,我添加了一个信号量,以在前一个尚未完成并且丢弃帧的情况下跳过向队列添加块的操作(根据NSLog()消息被吐出来了),但它没有修复图形。但是,有些看不见的GLKit代码有可能以我无法从主线程理解的方式操纵上下文。这是我目前评分第二高的理论,尽管sync()并不能解决问题并且OpenGL Profiler不会显示任何线程冲突。
  • 每个任务在退出前都应清除线程的上下文。
    • 我不清楚这是什么意思。GCD线程的上下文?没关系。我们不会在队列的上下文中添加任何内容,因此没有需要清理的内容。我们要绘制的EAGLContext?我不知道我们还能做什么。当然不是真正清除它,只会删除所有内容。另外,Sunset Lake的分子有一些代码如下所示:

代码:

dispatch_async(openGLESContextQueue, ^{
    [EAGLContext setCurrentContext:context];        
    GLfloat currentModelViewMatrix[9];
    [self convert3DTransform:&currentCalculatedMatrix to3x3Matrix:currentModelViewMatrix];
    CATransform3D inverseMatrix = CATransform3DInvert(currentCalculatedMatrix);
    GLfloat inverseModelViewMatrix[9];
    [self convert3DTransform:&inverseMatrix to3x3Matrix:inverseModelViewMatrix];

    GLfloat currentTranslation[3];
    currentTranslation[0] = accumulatedModelTranslation[0];
    currentTranslation[1] = accumulatedModelTranslation[1];
    currentTranslation[2] = accumulatedModelTranslation[2];

    GLfloat currentScaleFactor = currentModelScaleFactor;

    [self precalculateAOLookupTextureForInverseMatrix:inverseModelViewMatrix];
    [self renderDepthTextureForModelViewMatrix:currentModelViewMatrix translation:currentTranslation scale:currentScaleFactor];
    [self renderRaytracedSceneForModelViewMatrix:currentModelViewMatrix inverseMatrix:inverseModelViewMatrix translation:currentTranslation scale:currentScaleFactor];

    const GLenum discards[]  = {GL_DEPTH_ATTACHMENT};
    glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discards);

    [self presentRenderBuffer];

    dispatch_semaphore_signal(frameRenderingSemaphore);
});

这段代码有效,而且我看不到任何其他清理方法。我无法弄清楚这段代码与我的代码有何不同。有所不同的是,看起来与GL上下文相关的所有事情实际上都是在同一GCD派遣队列中完成的。但是,当我这样编写代码时,它无法解决任何问题。

最后一点不同是该代码似乎未使用GLKit。上面的代码(以及我实际上感兴趣的代码)确实使用了GLKit。

在这一点上,我有关于该问题的三种理论:1.我在概念上犯了有关块,GCD和OpenGL ES之间交互的错误。2. GLKit的GLKViewControllerGLKView一些拉伸或操纵EAGLContext在调用之间drawInRect当我的drawInRect积木正在加工时,会发生这种情况,使事情变得混乱。3.我依赖该- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect方法的事实就是问题所在。我认为这种方法是:“嘿,您会自动CADisplayLink配置,并且每次它想要一个框架时,它都会命中此方法。做任何你想做的。我的意思是,在此处的普通代码中,您只需发出glDrawArrays命令即可。这不像我要传回包含要在屏幕上显示的内容的帧缓冲区对象或CGImageRef。我正在发布GL命令。但是,这可能是错误的。也许您无法以任何方式推迟使用该方法进行绘制而不会引起问题。为了验证这一理论,我将所有绘图代码移入了一个名为的方法中drawStuff,然后将drawRect方法的主体替换为

[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(drawStuff) userInfo:nil repeats:NO];

该应用程序启动,显示视图所要显示的颜色glClear十秒钟,然后像平常一样绘制。因此,该理论看起来也不是太强硬。

这里发布了一个类似的问题,有一个答案,该答案被接受并接受:

调度块中的代码将无法正常工作。到执行时,该帧的所有OpenGL状态早就被销毁了。如果您要在该代码块中调用glGetError(),我相信它会告诉您相同的信息。您需要确保所有绘画代码均在该glkView方法中完成,以使OpenGL状态有效。执行该分派时,实际上是在使该绘图代码的执行脱离该方法的范围。

我不明白为什么这应该是真的。但:

  1. 我只引用关闭到东西,在块要活得比块,和他们喜欢的东西从封闭对象范围Objective-C的指针。
  2. 我可以在调试器中检查它们,看起来不错。
  3. 我在每个GL操作后都插入了一个getGLError()调用,它只返回零。
  4. 使用dispatch_sync从块进行绘制即可。
  5. 我想了想drawInRect方法中的什么地方,将块保存到ivar中,然后将NSTimer设置为call drawStuffdrawStuff我只是调用块。画得很好。

NSTimer情况是异步绘制的,但是它不涉及从另一个线程进行绘制,因为AFAIK NSTimer调用只是在设置线程的运行循环中安排的。因此,它与线程有关。

有人可以告诉我我在这里想念的东西吗?

塔克

这是行不通的,因为正如borrrden所说,GLKitpresentRenderbuffer:- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect完成后立即调用

这在使用计时器的情况下有效,因为在drawStuff绘制周期开始时在主线程上调用了该方法。- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect实际上没有执行任何操作,只是将其安排在另外10秒内再次在主线程上发生,然后在drawInRect:方法结束时呈现了先前安排的图形调用除了将绘图延迟10秒之外,这什么都没做,所有事情仍在主线程上进行。

如果您想采用渲染主线程的方法,则GLKit并不是一个很好的选择。您将需要使用runloop设置自己的线程,将a连接CADisplayLink到该runloop,然后从此队列进行渲染。GLKViewController被配置为使用主运行循环,并且将始终在每个帧的末尾呈现渲染缓冲区,这将导致您在其他线程上所做的任何事情都陷入混乱。

根据您的GL需求,您可能会发现在主线程上执行所有GL事务并在主线程上执行“其他事务”更为简单。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何从iOS上的Grand Central Dispatch Queue异步绘制到GLKit的OpenGL ES上下文

来自分类Dev

在Swift中找出Grand Central Dispatch的语法

来自分类Dev

OpenCL与Grand Central Dispatch中的并发编程

来自分类Dev

将代码转换为Grand Central Dispatch

来自分类Dev

将数据对象传递到Grand Central Dispatch Task的最佳方法

来自分类Dev

在主线程上发生到后台队列的dispatch_sync(防止在后台线程上设置后台管理对象上下文)

来自分类Dev

在主线程上发生到后台队列的dispatch_sync(防止在后台线程上设置后台托管对象上下文)

来自分类Dev

在iPad上未创建OpenGl ES 3.0上下文(在Simulator中可以运行)

来自分类Dev

与OpenGL ES共享egl上下文

来自分类Dev

在Grand Central Dispatch中使用术语“队列”,“多核”和“线程”

来自分类Dev

使用Swift进行Grand Central Dispatch时遇到问题

来自分类Dev

在Swift中使用Grand Central Dispatch并行化并加速“ for”循环?

来自分类Dev

我的Grand Central Dispatch用法:我使用正确吗?

来自分类Dev

使用Swift进行Grand Central Dispatch时遇到问题

来自分类Dev

Grand Central Dispatch替代使用NSTimer的方法-多次无效

来自分类Dev

串行 Grand Central Dispatch 中的完成处理程序

来自分类Dev

使用Grand Central Dispatch IOS Swift Xcode 6.3.1时遇到问题

来自分类Dev

迅捷:Grand-Central-Dispatch但是代码是在主线程上执行的?

来自分类Dev

如何绑定到与样式值继承的数据上下文不同的数据上下文?

来自分类Dev

Swift是否具有通过Grand Central Dispatch的dispatch_async进行并行编程的构造?

来自分类Dev

Swift是否具有通过Grand Central Dispatch的dispatch_async进行并行编程的构造?

来自分类Dev

如何将OpenGL上下文中的纹理复制到另一个上下文

来自分类Dev

如何将OpenGL上下文中的纹理复制到另一个上下文

来自分类Dev

使用设备上下文在CImage对象上绘制线

来自分类Dev

在 CAShapeLayer 上绘制 bezierPath 时上下文无效

来自分类Dev

如何创建用于绘制的子矩形设备上下文

来自分类Dev

如何获取Android的GLSurfaceView创建的OpenGL上下文?

来自分类Dev

如何从QML绑定到根上下文对象信号

来自分类Dev

如何绑定到数据上下文的设计实例

Related 相关文章

  1. 1

    如何从iOS上的Grand Central Dispatch Queue异步绘制到GLKit的OpenGL ES上下文

  2. 2

    在Swift中找出Grand Central Dispatch的语法

  3. 3

    OpenCL与Grand Central Dispatch中的并发编程

  4. 4

    将代码转换为Grand Central Dispatch

  5. 5

    将数据对象传递到Grand Central Dispatch Task的最佳方法

  6. 6

    在主线程上发生到后台队列的dispatch_sync(防止在后台线程上设置后台管理对象上下文)

  7. 7

    在主线程上发生到后台队列的dispatch_sync(防止在后台线程上设置后台托管对象上下文)

  8. 8

    在iPad上未创建OpenGl ES 3.0上下文(在Simulator中可以运行)

  9. 9

    与OpenGL ES共享egl上下文

  10. 10

    在Grand Central Dispatch中使用术语“队列”,“多核”和“线程”

  11. 11

    使用Swift进行Grand Central Dispatch时遇到问题

  12. 12

    在Swift中使用Grand Central Dispatch并行化并加速“ for”循环?

  13. 13

    我的Grand Central Dispatch用法:我使用正确吗?

  14. 14

    使用Swift进行Grand Central Dispatch时遇到问题

  15. 15

    Grand Central Dispatch替代使用NSTimer的方法-多次无效

  16. 16

    串行 Grand Central Dispatch 中的完成处理程序

  17. 17

    使用Grand Central Dispatch IOS Swift Xcode 6.3.1时遇到问题

  18. 18

    迅捷:Grand-Central-Dispatch但是代码是在主线程上执行的?

  19. 19

    如何绑定到与样式值继承的数据上下文不同的数据上下文?

  20. 20

    Swift是否具有通过Grand Central Dispatch的dispatch_async进行并行编程的构造?

  21. 21

    Swift是否具有通过Grand Central Dispatch的dispatch_async进行并行编程的构造?

  22. 22

    如何将OpenGL上下文中的纹理复制到另一个上下文

  23. 23

    如何将OpenGL上下文中的纹理复制到另一个上下文

  24. 24

    使用设备上下文在CImage对象上绘制线

  25. 25

    在 CAShapeLayer 上绘制 bezierPath 时上下文无效

  26. 26

    如何创建用于绘制的子矩形设备上下文

  27. 27

    如何获取Android的GLSurfaceView创建的OpenGL上下文?

  28. 28

    如何从QML绑定到根上下文对象信号

  29. 29

    如何绑定到数据上下文的设计实例

热门标签

归档