调试最长的一帧(第29天)

GraphicsContext::createGraphicsThread()创建线程时,得到一个osg::GraphicsThread线程对象

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

 

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

而使用Camera::createCamera创建线程时,得到的是osg::OperationThread对象,它是GraphicsThread的父类。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

可见osg::OperationThread是osg::GraphicsThread的父类。

 

调试最长的一帧(第29天)

这一微小的区别使得这两类线程之间不会存在太大的差异。事实上,图形设备所用的GraphicsThread线程只是在每次运行时(即GraphicsThread::run函数)保证设备的渲染上下文RC设置正确,即,在恰当的时机使用GaphicsContext::makeCurrent和releaseContext函数操作RC设备,并在RC设备正确关联之后执行OperationThread::run函数。

调试最长的一帧(第29天)

 

接下来就是OperationThread线程的执行内容,事实上是GC线程和摄像机线程在启动以后要反复完成的工作。如下。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

接下来介绍如何象任务列表添加任务,用OperationThread::add函数。也可以向GC线程或者摄像机线程传递自定义任务。

调试最长的一帧(第29天)

 

以前介绍了数据分页线程执行中,DatabaseThread::run将DataBasePager::CompileOperation传递给对应的GC线程。执行函数operator()是执行DatabasePager::compileAllGLObjects函数对当前的GC设备中待编译的对象执行预编译(使用compileGLObjects函数)。CompileOperation的getKeep属性为false,执行完依次,将会被剔除出GC线程的任务列表。

调试最长的一帧(第29天)

。。。。。。。。。。。。。。

调试最长的一帧(第29天)

。。。。。。。。。。。。。。。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

除此之外,GC线程的主要工作任务设置都是在startThreading 这个函数中完成的。这个startThreading将在Viewer::realize()函数中执行,因此,尽量不要在执行realize之后再做多余的工作,因为此时渲染线程已经启动了。

在startThread函数中,根据线程模型的不同,以下几种任务对象将可能被添加到GC线程或者摄像机线程。

osg::BarrierOperation,也就是启动栅栏_startRenderingBarrier和结束栅栏_endRenderingDispatchBarrier,它们同时也可以作为任务对象被添加到线程中,这就使得线程的同步控制十分方便。只要任务队列执行到启动栅栏或者结束栅栏,就自动使用block阻塞线程,直到栅栏被冲开(也就是全部线程都被阻塞的那一刻),才会继续执行后面的任务。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

osg::RunOperations:这个任务将负责执行GraphicsContext::runOperations()函数,这样就会通过执行渲染器的Renderer::operator()操作,完成场景的绘制(或者筛选加上绘制,Renderer::cull_draw)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

。。。。。。

调试最长的一帧(第29天)

。。。。。。。

调试最长的一帧(第29天)

osgViewer::Renderer渲染器本身也是可以作为一个任务存在的,它将根据相应的设置直接执行场景的绘制(Renderer::draw)或者筛选加绘制(Renderer::cull_draw)操作。

调试最长的一帧(第29天)

。。。。。。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

osg::SwapBuffersOperation:这个任务将负责执行双缓存的动作,以实现场景的平滑浏览,相关的函数是GraphicsContext::swapBuffersImplementation.

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

电子书首先介绍了CullDrawThreadPerContext模式,看看在该模式下,任务的添加和处理顺序有什么要求。

调试最长的一帧(第29天)

CullDrawThreadPerContext模式的渲染开始栅栏和结束栅栏的强度都设为contexts()+1,即GC线程的数目加1.

调试最长的一帧(第29天)

任务列表中任务的顺序

1,_startRenderingBarrier任务,由于getKeep()设置为true,这个任务不会从列表中删除。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

 

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

2,osg::RunOperations任务,它将同时负责场景的筛选和绘制(即最终执行Renderer::cull_draw()函数),该任务不会从列表中删除。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

.........

调试最长的一帧(第29天)

调试最长的一帧(第29天)

..............

调试最长的一帧(第29天)

3,swapReadyBarrier任务,它实质上是一个BarrierOperation栅栏对象,强度等于GC线程的数目。它的作用是在交换双缓存前对所有GC线程执行一次同步。该任务不会从列表中删除。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

4,swapOp任务,它是一个SwapBuffersOperation对象,用于执行绘制后的双缓存交换操作。该任务不会从列表中删除。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

5,_endRenderingDispatchBarrier任务,即渲染结束栅栏的位置。该任务不会从列表中删除。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

到此时,都在队列里

调试最长的一帧(第29天)

然后就运行了。

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

调试最长的一帧(第29天)

由此可知,CullDrawThreadPerContext模式可以类比于下面图示。

调试最长的一帧(第29天)

可以看出,对上图三个GC线程分别绘制三个不同的图形设备,由于场景筛选所需时间以及渲染数据量等种种差异,三个线程完成筛选(CULL)和绘制(Draw)的时间都不享同,但是CullDrawThreadPerContext将保证它们在运行时的同步性。

原因如下:

从左到右,三个同步线程的栅栏,_startRenderingBarrier在场景筛选和绘制开始前,swapReadyBarrier在场景筛选和绘制完毕后,_endRenderingDispatchBarrier在双缓存交换完毕后,三次进行对各个GC线程进行同步。其他时候则交由各个线程*完成针对各个GC设备的场景渲染工作。

 

上一篇:OsgEarth下实现雷达波束扫描飞机动画


下一篇:python之平*立的调试工具winpdb介绍