You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/terrain/compositemaprenderer.cpp

182 lines
5.7 KiB
C++

#include "compositemaprenderer.hpp"
#include <osg/FrameBufferObject>
#include <osg/RenderInfo>
#include <osg/Texture2D>
#include <algorithm>
namespace Terrain
{
CompositeMapRenderer::CompositeMapRenderer()
: mTargetFrameRate(120)
, mMinimumTimeAvailable(0.0025)
{
setSupportsDisplayList(false);
setCullingActive(false);
mFBO = new osg::FrameBufferObject;
getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
}
CompositeMapRenderer::~CompositeMapRenderer() {}
void CompositeMapRenderer::drawImplementation(osg::RenderInfo& renderInfo) const
{
double dt = mTimer.time_s();
dt = std::min(dt, 0.2);
mTimer.setStartTick();
double targetFrameTime = 1.0 / static_cast<double>(mTargetFrameRate);
double conservativeTimeRatio(0.75);
double availableTime = std::max((targetFrameTime - dt) * conservativeTimeRatio, mMinimumTimeAvailable);
std::lock_guard<std::mutex> lock(mMutex);
if (mImmediateCompileSet.empty() && mCompileSet.empty())
return;
while (!mImmediateCompileSet.empty())
{
osg::ref_ptr<CompositeMap> node = *mImmediateCompileSet.begin();
mImmediateCompileSet.erase(node);
mMutex.unlock();
compile(*node, renderInfo);
mMutex.lock();
}
const auto deadline = std::chrono::steady_clock::now() + std::chrono::duration<double>(availableTime);
while (!mCompileSet.empty() && std::chrono::steady_clock::now() < deadline)
{
osg::ref_ptr<CompositeMap> node = *mCompileSet.begin();
mCompileSet.erase(node);
mMutex.unlock();
compile(*node, renderInfo);
mMutex.lock();
if (node->mCompiled < node->mDrawables.size())
{
// We did not compile the map fully.
// Place it back to queue to continue work in the next time.
mCompileSet.insert(node);
}
}
mTimer.setStartTick();
}
void CompositeMapRenderer::compile(CompositeMap& compositeMap, osg::RenderInfo& renderInfo) const
{
// if there are no more external references we can assume the texture is no longer required
if (compositeMap.mTexture->referenceCount() <= 1)
{
compositeMap.mCompiled = compositeMap.mDrawables.size();
return;
}
osg::Timer timer;
osg::State& state = *renderInfo.getState();
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
if (!mFBO)
return;
if (!ext->isFrameBufferObjectSupported)
return;
osg::FrameBufferAttachment attach(compositeMap.mTexture);
mFBO->setAttachment(osg::Camera::COLOR_BUFFER, attach);
mFBO->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
GLenum status = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
OSG_ALWAYS << "Error attaching FBO" << std::endl;
return;
}
// inform State that Texture attribute has changed due to compiling of FBO texture
// should OSG be doing this on its own?
state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), osg::StateAttribute::TEXTURE);
for (unsigned int i = compositeMap.mCompiled; i < compositeMap.mDrawables.size(); ++i)
{
osg::Drawable* drw = compositeMap.mDrawables[i];
osg::StateSet* stateset = drw->getStateSet();
if (stateset)
renderInfo.getState()->pushStateSet(stateset);
renderInfo.getState()->apply();
glViewport(0, 0, compositeMap.mTexture->getTextureWidth(), compositeMap.mTexture->getTextureHeight());
drw->drawImplementation(renderInfo);
if (stateset)
renderInfo.getState()->popStateSet();
++compositeMap.mCompiled;
compositeMap.mDrawables[i] = nullptr;
}
if (compositeMap.mCompiled == compositeMap.mDrawables.size())
compositeMap.mDrawables = std::vector<osg::ref_ptr<osg::Drawable>>();
state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT);
GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
}
void CompositeMapRenderer::setMinimumTimeAvailableForCompile(double time)
{
mMinimumTimeAvailable = time;
}
void CompositeMapRenderer::setTargetFrameRate(float framerate)
{
mTargetFrameRate = framerate;
}
void CompositeMapRenderer::addCompositeMap(CompositeMap* compositeMap, bool immediate)
{
std::lock_guard<std::mutex> lock(mMutex);
if (immediate)
mImmediateCompileSet.insert(compositeMap);
else
mCompileSet.insert(compositeMap);
}
void CompositeMapRenderer::setImmediate(CompositeMap* compositeMap)
{
std::lock_guard<std::mutex> lock(mMutex);
CompileSet::iterator found = mCompileSet.find(compositeMap);
if (found == mCompileSet.end())
return;
else
{
mImmediateCompileSet.insert(compositeMap);
mCompileSet.erase(found);
}
}
unsigned int CompositeMapRenderer::getCompileSetSize() const
{
std::lock_guard<std::mutex> lock(mMutex);
return mCompileSet.size();
}
CompositeMap::CompositeMap()
: mCompiled(0)
{
}
CompositeMap::~CompositeMap() {}
}