天天看點

osg多線程_osg深入探究---第四天

再次回到viewer的realize函數中(/src/osgViewer/Viewer.cpp第525行)

通過前一個的介紹我們知道了當使用者沒有設定context的時候,osg會自動的根據系統類型建立适宜的context,是以一下代碼做了這麼兩件事情

1.如果沒有建立成功,那麼,将會因為contexts為空,realize失敗而退出。

2.再往下就是來得到DisplaySetting,并根據這個DisplaySetting來得到視窗系統的接口,(DisplaySetting以及WindowingSystemInterface我們在上幾節都有說明。)

下面一段for循環我們需要進行詳細講解

for(Contexts::iterator citr = contexts.begin();

citr != contexts.end();

++citr)

{

osg::GraphicsContext* gc = *citr;

if (ds->getSyncSwapBuffers()) gc->setSwapCallback(new osg::SyncSwapBuffersCallback);

// set the pool sizes, 0 the default will result in no GL object pools.

gc->getState()->setMaxTexturePoolSize(maxTexturePoolSize);

gc->getState()->setMaxBufferObjectPoolSize(maxBufferObjectPoolSize);

gc->realize();

if (_realizeOperation.valid() && gc->valid())

{

gc->makeCurrent();

(*_realizeOperation)(gc);

gc->releaseContext();

}

}

這段代碼做了一下幾個事情周遊所有的GraphicsContext,然後判斷是否設定了同步交換緩沖區(這一般是渲染的最後一步),這是osg提供的多機同步swapbuffer機制,他會預設調用内置的swapbuffer的回調函數(osg::SyncSwapBuffersCallback中,作用主要是等待client端的同步鎖,實作多機同步執行swapbuffer)。如果developer想幹預的話 可以調用 osg::GraphicsContext::setSwapCallback(SwapCallback* rc)來設定自定義的緩存交換回調。自定義的回調必須調用GraphicsContext::swapBuffersImplementation()函數.

定義gc中最大的紋理層數以及最大緩沖池的大小

3.進行GraphicsContext的realize動作,他其實就是調用了GraphicsContext中realizeImplementation(),它是一個被重載的函數,我們可以在GraphicsWindowX11.cpp中找到linux下的實作方法,我們可以從中看出主要就是針對linux視窗程式中gc以及event的初始化工作。結合上一日的講解我們可以總結從作業系統底層到建立出graphiccontext,以及交給camera使用的步驟

a.viewer中主從相機使用的setGraphicContext設定對應的顯示上下文其實就是對應的顯示視窗。

b.GraphicContext的建立是由平台相關的抽象類WindowingSystemInterface負責,對于linux來說。這個類是有GraphicsWindowX11.cpp中的X11WindowingSystem類具體實作的,它建立了osgViewer::GraphicsWindowX11的執行個體

c.進一步講,如果視窗特性Traits中開啟了pbuffer選項,則OSG将嘗試建立osgViewer::PixelBufferX11裝置,以實作離屏渲染、紋理烘焙等工作,否則隻建立普通的opengl視窗。

4.完成使用者指定一些在realize時執行的動作。其中_realizeOperation是通過osgViewer::ViewerBase中setRealizeOperation來設定,其主要作用是在執行 realize 函數時,順便完成使用者指定的一些工作。您自己的工作内容可以通過繼承 osg::Operation 類,并重載 operator()操作符來添加。

5.相比較而言,GraphicContext::makeCurrent以及GraphicContext::releaseContext函數也是使用相同的方法實作多态的針對不同的作業系統平台,那麼他們兩個的主要工作就是完成類似opengl的wglMakeCurrent完成的工作,即将渲染的上下文RC對應到正确的視窗繪制句柄上。在其中穿插使用者自定義的動作。

再次聚焦到realize函數上(/src/osgViewer/Viewer.cpp第567行),_incrementalCompileOperation,用于預編譯GraphicContext,主要作用是,想在程式運作開始時就加在一個資源檔案但是又不想或者沒有到顯示到界面的時機,則會用到這個預加載操作。具體的用法如下:

//從Viewer擷取 osgUtil::IncrementalCompileOperation的指針:

osgUtil::IncrementalCompileOperation* pIcompOperation = viewer.getIncrementalCompileOperation();//從Viewer擷取 osgUtil::IncrementalCompileOperation的指針:

// 建立compileSet:

osg::ref_ptr<:incrementalcompileoperation::compileset> compileSet = osgUtil::IncrementalCompileOperation::CompileSet(NODE,true);

//從CompileCompletedCallback派生新類,然後重寫Completed函數,在内部隐藏節點:

//将 派生類 綁定到 compileSet。

compileSet->compileSet->_compileCompletedCallback = newCompileCompletedCallback;

//設定 IncrementalCompileOperation 過期政策

pIcompOperation->setCompileAllTillFrameNumber(50);

再往下就是使滑鼠聚焦到osg的繪制視窗上這個一個功能。

osg::Timer::instance()->setStartTick();

setStartTick(osg::Timer::instance()->getStartTick());

setUpThreading();

首先調用 osg::Timer::setStartTick 函數,啟動 OSG 内部定時器并開始計時。

随後, Viewer::setStartTick 函數的工作是找到目前視景器和所有 GraphicsContext 裝置的

事件隊列_eventQueue,并設定它們的啟動時刻為目前時間。

下一行是調用 ViewerBase::setUpThreading 函數(這個多線程問題我們以後再深入讨論)

請回到 realize 函數,現在這個函數的執

行已經接近了尾聲,不過我們又遇到了一個問題:編譯上下文(也就是 Compile Contexts,

暫時就這樣翻譯吧)?如果要啟用它的話并不困難,隻需要在調用 realize 之前執行:

osg::DisplaySettings::instance()->setCompileContextsHint(true);

随後,正如您在 realize 函數的 491-503 行之間看到的,系統将設法周遊所有可能的

GraphicsContext 裝置,針對它們分别再各自添加一個新的 GraphicsContext 裝置(也就是說,

如果系統中已經有了數個圖形上下文,那麼現在又将新增同樣數量的圖形上下文與之對應),

所用的函數為 GraphicsContext::getOrCreateCompileContext。這之後,分别執行了建立圖形

線程,設定 CPU 依賴性,以及啟動圖形線程的工作,具體的實作内容可以暫時忽略。觀察 getOrCreateCompileContext 函數的内容,很快我們就可以發現其中的重點:這些新

增的 GraphicsContext 對象使用了 pBuffer 的特性,并與對應的已有對象共享同一個圖形上下

文(Traits::sharedContext 特性)。事實上,這是 OSG 利用 OpenGL 的像素緩存(Pixel Buffer)

技術,為圖形上下文的背景編譯提供的一種新的解決方案。這樣不僅可以提高圖形重新整理的速

度,還可以友善使用者為某一特定的 GraphicsContext 裝置添加特殊的處理動作,方法是使用

osg::GraphicsContext::getCompileContext 擷取背景圖形上下文,再使用 GraphicsContext::add

函數向其中追加 osg::Operation 對象,類似的例子可以參看 osgterrain。