Further work on GraphicsContext/GraphicsThread
This commit is contained in:
@@ -113,25 +113,62 @@ void GraphicsContext::decrementContextIDUsageCount(unsigned int contextID)
|
||||
|
||||
|
||||
GraphicsContext::GraphicsContext():
|
||||
_closeOnDestruction(true),
|
||||
_threadOfLastMakeCurrent(0)
|
||||
{
|
||||
}
|
||||
|
||||
GraphicsContext::~GraphicsContext()
|
||||
{
|
||||
// switch off the graphics thread...
|
||||
setGraphicsThread(0);
|
||||
|
||||
if (_state.valid())
|
||||
{
|
||||
decrementContextIDUsageCount(_state->getContextID());
|
||||
}
|
||||
|
||||
if (_closeOnDestruction)
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/** Realise the GraphicsContext.*/
|
||||
bool GraphicsContext::realize()
|
||||
{
|
||||
if (realizeImplementation())
|
||||
{
|
||||
if (_graphicsThread.valid() && !_graphicsThread->isRunning())
|
||||
{
|
||||
_graphicsThread->startThread();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsContext::close()
|
||||
{
|
||||
// switch off the graphics thread...
|
||||
setGraphicsThread(0);
|
||||
|
||||
closeImplementation();
|
||||
}
|
||||
|
||||
|
||||
void GraphicsContext::makeCurrent()
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Doing GraphicsContext::makeCurrent"<<(unsigned int)OpenThreads::Thread::CurrentThread()<<std::endl;
|
||||
|
||||
ReleaseContext_Block_MakeCurrentOperation* rcbmco = 0;
|
||||
|
||||
if (_graphicsThread.valid() &&
|
||||
_threadOfLastMakeCurrent == _graphicsThread.get())
|
||||
_threadOfLastMakeCurrent == _graphicsThread.get() &&
|
||||
_threadOfLastMakeCurrent != OpenThreads::Thread::CurrentThread())
|
||||
{
|
||||
// create a relase contex, block and make current operation to stop the graphics thread while we use the graphics context for ourselves
|
||||
rcbmco = new ReleaseContext_Block_MakeCurrentOperation;
|
||||
@@ -140,6 +177,8 @@ void GraphicsContext::makeCurrent()
|
||||
|
||||
if (!isCurrent()) _mutex.lock();
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Calling GraphicsContext::makeCurrentImplementation"<<(unsigned int)OpenThreads::Thread::CurrentThread()<<std::endl;
|
||||
|
||||
makeCurrentImplementation();
|
||||
|
||||
_threadOfLastMakeCurrent = OpenThreads::Thread::CurrentThread();
|
||||
@@ -150,6 +189,8 @@ void GraphicsContext::makeCurrent()
|
||||
// contex itself with a makeCurrent(), this will then block on the GraphicsContext mutex till releaseContext() releases it.
|
||||
rcbmco->release();
|
||||
}
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Done GraphicsContext::makeCurrentImplementation"<<(unsigned int)OpenThreads::Thread::CurrentThread()<<std::endl;
|
||||
}
|
||||
|
||||
void GraphicsContext::makeContextCurrent(GraphicsContext* readContext)
|
||||
@@ -165,3 +206,59 @@ void GraphicsContext::releaseContext()
|
||||
{
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
void GraphicsContext::swapBuffers()
|
||||
{
|
||||
if (isCurrent())
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Doing GraphicsContext::swapBuffers() call to swapBuffersImplementation() "<<(unsigned int)OpenThreads::Thread::CurrentThread()<<std::endl;
|
||||
swapBuffersImplementation();
|
||||
}
|
||||
else if (_graphicsThread.valid() &&
|
||||
_threadOfLastMakeCurrent == _graphicsThread.get())
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Doing GraphicsContext::swapBuffers() registering SwapBuffersOperation"<<(unsigned int)OpenThreads::Thread::CurrentThread()<<std::endl;
|
||||
_graphicsThread->add(new SwapBuffersOperation);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Doing GraphicsContext::swapBuffers() makeCurrent;swapBuffersImplementation;releaseContext"<<(unsigned int)OpenThreads::Thread::CurrentThread()<<std::endl;
|
||||
makeCurrent();
|
||||
swapBuffersImplementation();
|
||||
releaseContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GraphicsContext::createGraphicsThread()
|
||||
{
|
||||
if (!_graphicsThread)
|
||||
{
|
||||
setGraphicsThread(new GraphicsThread);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsContext::setGraphicsThread(GraphicsThread* gt)
|
||||
{
|
||||
if (_graphicsThread==gt) return;
|
||||
|
||||
if (_graphicsThread.valid())
|
||||
{
|
||||
// need to kill the thread in some way...
|
||||
_graphicsThread->cancel();
|
||||
_graphicsThread->_graphicsContext = 0;
|
||||
}
|
||||
|
||||
_graphicsThread = gt;
|
||||
|
||||
if (_graphicsThread.valid())
|
||||
{
|
||||
_graphicsThread->_graphicsContext = this;
|
||||
|
||||
if (!_graphicsThread->isRunning() && isRealized())
|
||||
{
|
||||
_graphicsThread->startThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,70 @@
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osg;
|
||||
using namespace OpenThreads;
|
||||
|
||||
struct BlockOperation : public GraphicsThread::Operation, public Block
|
||||
{
|
||||
BlockOperation() { reset(); }
|
||||
|
||||
virtual void operator () (GraphicsContext*)
|
||||
{
|
||||
//osg::notify(osg::NOTICE)<<"BlockOperation doing release"<<(unsigned int)this<<std::endl;
|
||||
glFlush();
|
||||
release();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
GraphicsThread::GraphicsThread():
|
||||
_graphicsContext(0),
|
||||
_done(false)
|
||||
{
|
||||
_operationsBlock = new Block;
|
||||
}
|
||||
|
||||
GraphicsThread::~GraphicsThread()
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Destructing graphics thread"<<std::endl;
|
||||
|
||||
cancel();
|
||||
}
|
||||
|
||||
int GraphicsThread::cancel()
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Cancelling graphics thread"<<std::endl;
|
||||
|
||||
int result = 0;
|
||||
if( isRunning() )
|
||||
{
|
||||
|
||||
_done = true;
|
||||
|
||||
// cancel the thread..
|
||||
result = Thread::cancel();
|
||||
//join();
|
||||
|
||||
// release the frameBlock and _databasePagerThreadBlock incase its holding up thread cancelation.
|
||||
_operationsBlock->release();
|
||||
|
||||
// then wait for the the thread to stop running.
|
||||
while(isRunning())
|
||||
{
|
||||
// commenting out debug info as it was cashing crash on exit, presumable
|
||||
// due to osg::notify or std::cout destructing earlier than this destructor.
|
||||
osg::notify(osg::NOTICE)<<"Waiting for GraphicsThread to cancel"<<std::endl;
|
||||
OpenThreads::Thread::YieldCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GraphicsThread::add(Operation* operation, bool waitForCompletion)
|
||||
{
|
||||
osg::BarrierOperation* barrier = 0;
|
||||
osg::notify(osg::NOTICE)<<"Doing add"<<std::endl;
|
||||
|
||||
BlockOperation* block = 0;
|
||||
|
||||
{
|
||||
// aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
|
||||
@@ -36,29 +91,44 @@ void GraphicsThread::add(Operation* operation, bool waitForCompletion)
|
||||
|
||||
if (waitForCompletion)
|
||||
{
|
||||
barrier = new BarrierOperation(2);
|
||||
_operations.push_back(barrier);
|
||||
block = new BlockOperation;
|
||||
_operations.push_back(block);
|
||||
}
|
||||
|
||||
_operationsBlock->set(true);
|
||||
}
|
||||
|
||||
if (barrier)
|
||||
if (block)
|
||||
{
|
||||
// now we wait till the barrier is joined by the graphics thread.
|
||||
barrier->block();
|
||||
block->block();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsThread::run()
|
||||
{
|
||||
// make the graphics context current.
|
||||
if (_graphicsContext) _graphicsContext->makeCurrent();
|
||||
if (_graphicsContext)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Doing make current"<<std::endl;
|
||||
_graphicsContext->makeCurrent();
|
||||
}
|
||||
|
||||
bool firstTime = false;
|
||||
osg::notify(osg::NOTICE)<<"Doing run"<<std::endl;
|
||||
|
||||
bool _done = false;
|
||||
bool firstTime = true;
|
||||
|
||||
do
|
||||
{
|
||||
// osg::notify(osg::NOTICE)<<"In main loop"<<std::endl;
|
||||
|
||||
if (_operations.empty())
|
||||
{
|
||||
_operationsBlock->block();
|
||||
}
|
||||
|
||||
// osg::notify(osg::NOTICE)<<"get op"<<std::endl;
|
||||
|
||||
ref_ptr<Operation> operation;
|
||||
|
||||
// get the front of the file request list.
|
||||
@@ -71,12 +141,20 @@ void GraphicsThread::run()
|
||||
|
||||
// remove it from the opeations queue
|
||||
_operations.erase(_operations.begin());
|
||||
|
||||
if (_operations.empty())
|
||||
{
|
||||
_operationsBlock->set(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (operation.valid())
|
||||
{
|
||||
// osg::notify(osg::NOTICE)<<"Doing op"<<std::endl;
|
||||
|
||||
// call the graphics operation.
|
||||
(*operation)(_graphicsContext);
|
||||
}
|
||||
@@ -91,18 +169,26 @@ void GraphicsThread::run()
|
||||
|
||||
} while (!testCancel() && !_done);
|
||||
|
||||
osg::notify(osg::NOTICE)<<"exit loop"<<std::endl;
|
||||
|
||||
// release the graphics context so that others can aquire it.
|
||||
if (_graphicsContext) _graphicsContext->releaseContext();
|
||||
|
||||
}
|
||||
|
||||
void SwapBufferOperation::operator () (GraphicsContext* context)
|
||||
|
||||
void SwapBuffersOperation::operator () (GraphicsContext* context)
|
||||
{
|
||||
if (context) context->swapBuffers();
|
||||
if (context)
|
||||
{
|
||||
context->swapBuffersImplementation();
|
||||
}
|
||||
}
|
||||
|
||||
void BarrierOperation::operator () (GraphicsContext*)
|
||||
{
|
||||
if (_preBlockOp==GL_FLUSH) glFlush();
|
||||
if (_preBlockOp==GL_FINISH) glFinish();
|
||||
|
||||
block();
|
||||
}
|
||||
|
||||
|
||||
@@ -150,19 +150,20 @@ GraphicsContextImplementation::GraphicsContextImplementation(Traits* traits)
|
||||
//_rs->realize();
|
||||
}
|
||||
|
||||
_closeOnDestruction = true;
|
||||
}
|
||||
|
||||
GraphicsContextImplementation::GraphicsContextImplementation(Producer::RenderSurface* rs)
|
||||
{
|
||||
_rs = rs;
|
||||
_closeOnDestruction = false;
|
||||
}
|
||||
|
||||
GraphicsContextImplementation::~GraphicsContextImplementation()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool GraphicsContextImplementation::realize()
|
||||
bool GraphicsContextImplementation::realizeImplementation()
|
||||
{
|
||||
if (_rs.valid())
|
||||
{
|
||||
@@ -188,6 +189,8 @@ void GraphicsContextImplementation::makeCurrentImplementation()
|
||||
{
|
||||
if (!_rs) return;
|
||||
|
||||
osg::notify(osg::NOTICE)<<"GraphicsContextImplementation::makeCurrentImplementation()"<<std::endl;
|
||||
|
||||
_rs->setReadDrawable( 0 );
|
||||
|
||||
_rs->makeCurrent();
|
||||
@@ -207,14 +210,14 @@ void GraphicsContextImplementation::makeContextCurrentImplementation(GraphicsCon
|
||||
_rs->makeCurrent();
|
||||
}
|
||||
|
||||
void GraphicsContextImplementation::close()
|
||||
void GraphicsContextImplementation::closeImplementation()
|
||||
{
|
||||
if (!_rs) return;
|
||||
|
||||
// need to close render surface...
|
||||
}
|
||||
|
||||
void GraphicsContextImplementation::bindPBufferToTexture(GLenum buffer)
|
||||
void GraphicsContextImplementation::bindPBufferToTextureImplementation(GLenum buffer)
|
||||
{
|
||||
if (!_rs) return;
|
||||
|
||||
@@ -229,7 +232,7 @@ void GraphicsContextImplementation::bindPBufferToTexture(GLenum buffer)
|
||||
_rs->bindPBufferToTexture(bufferType);
|
||||
}
|
||||
|
||||
void GraphicsContextImplementation::swapBuffers()
|
||||
void GraphicsContextImplementation::swapBuffersImplementation()
|
||||
{
|
||||
_rs->swapBuffers();
|
||||
}
|
||||
|
||||
@@ -1332,8 +1332,9 @@ void CullVisitor::apply(osg::CameraNode& camera)
|
||||
|
||||
rtts->setGraphicsContext(context.get());
|
||||
|
||||
context->realize();
|
||||
context->createGraphicsThread();
|
||||
|
||||
context->realize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,32 +143,47 @@ void RenderStage::drawPreRenderStages(osg::State& state,RenderLeaf*& previous)
|
||||
//cout << "Done Drawing prerendering stages "<<this<< " "<<_viewport->x()<<","<< _viewport->y()<<","<< _viewport->width()<<","<< _viewport->height()<<std::endl;
|
||||
}
|
||||
|
||||
void RenderStage::draw(osg::State& state,RenderLeaf*& previous)
|
||||
void RenderStage::copyTexture(osg::State& state)
|
||||
{
|
||||
if (_stageDrawnThisFrame) return;
|
||||
|
||||
_stageDrawnThisFrame = true;
|
||||
|
||||
// note, SceneView does call to drawPreRenderStages explicitly
|
||||
// so there is no need to call it here.
|
||||
drawPreRenderStages(state,previous);
|
||||
|
||||
|
||||
osg::State* useState = &state;
|
||||
osg::GraphicsContext* callingContext = state.getGraphicsContext();
|
||||
osg::GraphicsContext* useContext = callingContext;
|
||||
|
||||
if (_graphicsContext.valid() && _graphicsContext != callingContext)
|
||||
if (_readBuffer != GL_NONE)
|
||||
{
|
||||
// show we release the context so that others can use it?? will do so right
|
||||
// now as an experiment.
|
||||
callingContext->releaseContext();
|
||||
|
||||
useState = _graphicsContext->getState();
|
||||
useContext = _graphicsContext.get();
|
||||
useContext->makeCurrent();
|
||||
glReadBuffer(_readBuffer);
|
||||
}
|
||||
|
||||
// need to implement texture cube map etc...
|
||||
osg::Texture1D* texture1D = 0;
|
||||
osg::Texture2D* texture2D = 0;
|
||||
osg::Texture3D* texture3D = 0;
|
||||
osg::TextureRectangle* textureRec = 0;
|
||||
osg::TextureCubeMap* textureCubeMap = 0;
|
||||
|
||||
if ((texture2D = dynamic_cast<osg::Texture2D*>(_texture.get())) != 0)
|
||||
{
|
||||
texture2D->copyTexImage2D(state,_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height());
|
||||
}
|
||||
else if ((textureRec = dynamic_cast<osg::TextureRectangle*>(_texture.get())) != 0)
|
||||
{
|
||||
textureRec->copyTexImage2D(state,_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height());
|
||||
}
|
||||
else if ((texture1D = dynamic_cast<osg::Texture1D*>(_texture.get())) != 0)
|
||||
{
|
||||
// need to implement
|
||||
texture1D->copyTexImage1D(state,_viewport->x(),_viewport->y(),_viewport->width());
|
||||
}
|
||||
else if ((texture3D = dynamic_cast<osg::Texture3D*>(_texture.get())) != 0)
|
||||
{
|
||||
// need to implement
|
||||
texture3D->copyTexSubImage3D(state, 0, 0, _face, _viewport->x(), _viewport->y(), _viewport->width(), _viewport->height());
|
||||
}
|
||||
else if ((textureCubeMap = dynamic_cast<osg::TextureCubeMap*>(_texture.get())) != 0)
|
||||
{
|
||||
// need to implement
|
||||
textureCubeMap->copyTexSubImageCubeMap(state, _face, 0, 0, _viewport->x(),_viewport->y(),_viewport->width(),_viewport->height());
|
||||
}
|
||||
}
|
||||
|
||||
void RenderStage::drawInner(osg::State& state,RenderLeaf*& previous, bool& doCopyTexture)
|
||||
{
|
||||
if (_drawBuffer != GL_NONE)
|
||||
{
|
||||
glDrawBuffer(_drawBuffer);
|
||||
@@ -184,58 +199,17 @@ void RenderStage::draw(osg::State& state,RenderLeaf*& previous)
|
||||
|
||||
if (fbo_supported)
|
||||
{
|
||||
_fbo->apply(*useState);
|
||||
_fbo->apply(state);
|
||||
}
|
||||
|
||||
|
||||
// do the drawing itself.
|
||||
RenderBin::draw(state,previous);
|
||||
|
||||
|
||||
// now copy the rendered image to attached texture.
|
||||
if (_texture.valid() && !fbo_supported)
|
||||
if (doCopyTexture)
|
||||
{
|
||||
if (callingContext && useContext!= callingContext)
|
||||
{
|
||||
// make the calling context use the pbuffer context for reading.
|
||||
callingContext->makeContextCurrent(useContext);
|
||||
|
||||
if (_readBuffer != GL_NONE)
|
||||
{
|
||||
glReadBuffer(_readBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// need to implement texture cube map etc...
|
||||
osg::Texture1D* texture1D = 0;
|
||||
osg::Texture2D* texture2D = 0;
|
||||
osg::Texture3D* texture3D = 0;
|
||||
osg::TextureRectangle* textureRec = 0;
|
||||
osg::TextureCubeMap* textureCubeMap = 0;
|
||||
|
||||
if ((texture2D = dynamic_cast<osg::Texture2D*>(_texture.get())) != 0)
|
||||
{
|
||||
texture2D->copyTexImage2D(state,_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height());
|
||||
}
|
||||
else if ((textureRec = dynamic_cast<osg::TextureRectangle*>(_texture.get())) != 0)
|
||||
{
|
||||
textureRec->copyTexImage2D(state,_viewport->x(),_viewport->y(),_viewport->width(),_viewport->height());
|
||||
}
|
||||
else if ((texture1D = dynamic_cast<osg::Texture1D*>(_texture.get())) != 0)
|
||||
{
|
||||
// need to implement
|
||||
texture1D->copyTexImage1D(state,_viewport->x(),_viewport->y(),_viewport->width());
|
||||
}
|
||||
else if ((texture3D = dynamic_cast<osg::Texture3D*>(_texture.get())) != 0)
|
||||
{
|
||||
// need to implement
|
||||
texture3D->copyTexSubImage3D(state, 0, 0, _face, _viewport->x(), _viewport->y(), _viewport->width(), _viewport->height());
|
||||
}
|
||||
else if ((textureCubeMap = dynamic_cast<osg::TextureCubeMap*>(_texture.get())) != 0)
|
||||
{
|
||||
// need to implement
|
||||
textureCubeMap->copyTexSubImageCubeMap(state, _face, 0, 0, _viewport->x(),_viewport->y(),_viewport->width(),_viewport->height());
|
||||
}
|
||||
copyTexture(state);
|
||||
}
|
||||
|
||||
if (_image.valid())
|
||||
@@ -260,6 +234,8 @@ void RenderStage::draw(osg::State& state,RenderLeaf*& previous)
|
||||
{
|
||||
// switch of the frame buffer object
|
||||
fbo_ext->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
doCopyTexture = true;
|
||||
}
|
||||
|
||||
if (fbo_supported && _camera)
|
||||
@@ -272,11 +248,100 @@ void RenderStage::draw(osg::State& state,RenderLeaf*& previous)
|
||||
{
|
||||
if (itr->second._texture.valid() && itr->second._mipMapGeneration)
|
||||
{
|
||||
itr->second._texture->apply(*useState);
|
||||
itr->second._texture->apply(state);
|
||||
// fbo_ext->glGenerateMipmapEXT(itr->second._texture->getTextureTarget());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DrawInnerOperation : public osg::GraphicsThread::Operation
|
||||
{
|
||||
DrawInnerOperation(RenderStage* stage) : _stage(stage) {}
|
||||
|
||||
virtual void operator() (osg::GraphicsContext* context)
|
||||
{
|
||||
// osg::notify(osg::NOTICE)<<"DrawInnerOperation operator"<<std::endl;
|
||||
if (_stage && context)
|
||||
{
|
||||
RenderLeaf* previous = 0;
|
||||
bool doCopyTexture = false;
|
||||
_stage->drawInner(*(context->getState()), previous, doCopyTexture);
|
||||
}
|
||||
}
|
||||
|
||||
RenderStage* _stage;
|
||||
};
|
||||
|
||||
|
||||
void RenderStage::draw(osg::State& state,RenderLeaf*& previous)
|
||||
{
|
||||
if (_stageDrawnThisFrame) return;
|
||||
|
||||
_stageDrawnThisFrame = true;
|
||||
|
||||
// note, SceneView does call to drawPreRenderStages explicitly
|
||||
// so there is no need to call it here.
|
||||
drawPreRenderStages(state,previous);
|
||||
|
||||
|
||||
osg::State* useState = &state;
|
||||
osg::GraphicsContext* callingContext = state.getGraphicsContext();
|
||||
osg::GraphicsContext* useContext = callingContext;
|
||||
osg::GraphicsThread* useThread = 0;
|
||||
|
||||
if (_graphicsContext.valid() && _graphicsContext != callingContext)
|
||||
{
|
||||
// show we release the context so that others can use it?? will do so right
|
||||
// now as an experiment.
|
||||
callingContext->releaseContext();
|
||||
|
||||
useState = _graphicsContext->getState();
|
||||
useContext = _graphicsContext.get();
|
||||
|
||||
useThread = useContext->getGraphicsThread();
|
||||
|
||||
if (!useThread) useContext->makeCurrent();
|
||||
}
|
||||
|
||||
bool doCopyTexture = _texture.valid() ?
|
||||
(callingContext != useContext) :
|
||||
false;
|
||||
|
||||
if (useThread)
|
||||
{
|
||||
useThread->add(new DrawInnerOperation( this ), true);
|
||||
|
||||
doCopyTexture = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawInner( *useState, previous, doCopyTexture);
|
||||
}
|
||||
|
||||
|
||||
// now copy the rendered image to attached texture.
|
||||
if (_texture.valid() && !doCopyTexture)
|
||||
{
|
||||
if (callingContext && useContext!= callingContext)
|
||||
{
|
||||
// make the calling context use the pbuffer context for reading.
|
||||
callingContext->makeContextCurrent(useContext);
|
||||
}
|
||||
|
||||
copyTexture(state);
|
||||
}
|
||||
|
||||
if (_camera && _camera->getPostDrawCallback())
|
||||
{
|
||||
// if we have a camera with a post draw callback invoke it.
|
||||
(*(_camera->getPostDrawCallback()))(*_camera);
|
||||
}
|
||||
|
||||
if (_graphicsContext.valid() && _graphicsContext != callingContext)
|
||||
{
|
||||
if (!useThread) useContext->releaseContext();
|
||||
}
|
||||
|
||||
if (callingContext && useContext != callingContext)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user